2019-07-04 23:49:20 +02:00
|
|
|
/* GIMP - The GNU Image Manipulation Program
|
|
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
|
|
*
|
|
|
|
* GimpLinkLayer
|
|
|
|
* Copyright (C) 2019 Jehan
|
|
|
|
*
|
|
|
|
* 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 <string.h>
|
|
|
|
|
|
|
|
#include <cairo.h>
|
|
|
|
#include <gegl.h>
|
|
|
|
#include <gdk-pixbuf/gdk-pixbuf.h>
|
|
|
|
|
|
|
|
#include "libgimpbase/gimpbase.h"
|
|
|
|
#include "libgimpcolor/gimpcolor.h"
|
|
|
|
#include "libgimpconfig/gimpconfig.h"
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 14:49:12 +02:00
|
|
|
#include "libgimpmath/gimpmath.h"
|
2019-07-04 23:49:20 +02:00
|
|
|
|
|
|
|
#include "core-types.h"
|
|
|
|
|
|
|
|
#include "gegl/gimp-gegl-loops.h"
|
|
|
|
#include "gegl/gimp-gegl-utils.h"
|
|
|
|
|
|
|
|
#include "gimp.h"
|
|
|
|
#include "gimpcontext.h"
|
|
|
|
#include "gimpimage.h"
|
|
|
|
#include "gimpimage-color-profile.h"
|
|
|
|
#include "gimpimage-undo.h"
|
|
|
|
#include "gimpimage-undo-push.h"
|
|
|
|
#include "gimpitemtree.h"
|
2020-07-29 19:17:04 +02:00
|
|
|
#include "gimpobjectqueue.h"
|
|
|
|
#include "gimpprogress.h"
|
2019-07-04 23:49:20 +02:00
|
|
|
|
|
|
|
#include "gimplink.h"
|
|
|
|
#include "gimplinklayer.h"
|
|
|
|
|
|
|
|
#include "gimp-intl.h"
|
|
|
|
|
2025-08-27 19:21:54 +02:00
|
|
|
#define EPSILON 1e-10
|
|
|
|
|
2019-07-04 23:49:20 +02:00
|
|
|
|
2019-07-08 16:48:56 +02:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
LINK_LAYER_XCF_NONE = 0,
|
|
|
|
LINK_LAYER_XCF_DONT_AUTO_RENAME = 1 << 0,
|
|
|
|
LINK_LAYER_XCF_MODIFIED = 1 << 1
|
|
|
|
};
|
|
|
|
|
2019-07-04 23:49:20 +02:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
PROP_0,
|
|
|
|
PROP_LINK,
|
|
|
|
PROP_AUTO_RENAME,
|
2025-08-09 23:26:13 +02:00
|
|
|
PROP_SCALED_ONLY,
|
|
|
|
N_PROPS
|
2019-07-04 23:49:20 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
struct _GimpLinkLayerPrivate
|
|
|
|
{
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 14:49:12 +02:00
|
|
|
GimpLink *link;
|
|
|
|
gboolean scaled_only;
|
|
|
|
gboolean auto_rename;
|
|
|
|
|
|
|
|
GimpMatrix3 matrix;
|
|
|
|
gint offset_x;
|
|
|
|
gint offset_y;
|
|
|
|
GimpInterpolationType interpolation;
|
|
|
|
|
|
|
|
/* A transient value only useful to know when to drop monitoring after
|
|
|
|
* a buffer update.
|
|
|
|
*/
|
|
|
|
gboolean keep_monitoring;
|
2019-07-04 23:49:20 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
static void gimp_link_layer_finalize (GObject *object);
|
|
|
|
static void gimp_link_layer_get_property (GObject *object,
|
|
|
|
guint property_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec);
|
|
|
|
static void gimp_link_layer_set_property (GObject *object,
|
|
|
|
guint property_id,
|
|
|
|
const GValue *value,
|
|
|
|
GParamSpec *pspec);
|
|
|
|
|
|
|
|
static gint64 gimp_link_layer_get_memsize (GimpObject *object,
|
|
|
|
gint64 *gui_size);
|
|
|
|
|
|
|
|
static GimpItem * gimp_link_layer_duplicate (GimpItem *item,
|
|
|
|
GType new_type);
|
|
|
|
static gboolean gimp_link_layer_rename (GimpItem *item,
|
|
|
|
const gchar *new_name,
|
|
|
|
const gchar *undo_desc,
|
|
|
|
GError **error);
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 14:49:12 +02:00
|
|
|
|
|
|
|
static void gimp_link_layer_translate (GimpItem *item,
|
|
|
|
gdouble offset_x,
|
|
|
|
gdouble offset_y,
|
|
|
|
gboolean push_undo);
|
2020-07-29 19:17:04 +02:00
|
|
|
static void gimp_link_layer_scale (GimpItem *item,
|
|
|
|
gint new_width,
|
|
|
|
gint new_height,
|
|
|
|
gint new_offset_x,
|
|
|
|
gint new_offset_y,
|
|
|
|
GimpInterpolationType interpolation_type,
|
|
|
|
GimpProgress *progress);
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 14:49:12 +02:00
|
|
|
static void gimp_link_layer_transform (GimpItem *item,
|
|
|
|
GimpContext *context,
|
|
|
|
const GimpMatrix3 *matrix,
|
|
|
|
GimpTransformDirection direction,
|
|
|
|
GimpInterpolationType interpolation_type,
|
|
|
|
GimpTransformResize clip_result,
|
|
|
|
GimpProgress *progress,
|
|
|
|
gboolean push_undo);
|
2019-07-04 23:49:20 +02:00
|
|
|
|
|
|
|
static void gimp_link_layer_set_buffer (GimpDrawable *drawable,
|
|
|
|
gboolean push_undo,
|
|
|
|
const gchar *undo_desc,
|
|
|
|
GeglBuffer *buffer,
|
|
|
|
const GeglRectangle *bounds);
|
|
|
|
static void gimp_link_layer_push_undo (GimpDrawable *drawable,
|
|
|
|
const gchar *undo_desc,
|
|
|
|
GeglBuffer *buffer,
|
|
|
|
gint x,
|
|
|
|
gint y,
|
|
|
|
gint width,
|
|
|
|
gint height);
|
|
|
|
|
|
|
|
static void gimp_link_layer_convert_type (GimpLayer *layer,
|
|
|
|
GimpImage *dest_image,
|
|
|
|
const Babl *new_format,
|
|
|
|
GimpColorProfile *src_profile,
|
|
|
|
GimpColorProfile *dest_profile,
|
|
|
|
GeglDitherMethod layer_dither_type,
|
|
|
|
GeglDitherMethod mask_dither_type,
|
|
|
|
gboolean push_undo,
|
|
|
|
GimpProgress *progress);
|
|
|
|
|
2025-08-13 16:08:09 +02:00
|
|
|
static void gimp_link_layer_render_full (GimpLinkLayer *layer);
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 14:49:12 +02:00
|
|
|
static gboolean gimp_link_layer_render_link (GimpLinkLayer *layer);
|
2019-07-04 23:49:20 +02:00
|
|
|
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 14:49:12 +02:00
|
|
|
static gboolean
|
|
|
|
gimp_link_layer_is_scaling_matrix (GimpLinkLayer *layer,
|
|
|
|
const GimpMatrix3 *matrix,
|
|
|
|
gint *new_width,
|
|
|
|
gint *new_height,
|
|
|
|
gint *new_offset_x,
|
|
|
|
gint *new_offset_y);
|
|
|
|
|
2019-07-04 23:49:20 +02:00
|
|
|
|
|
|
|
G_DEFINE_TYPE_WITH_PRIVATE (GimpLinkLayer, gimp_link_layer, GIMP_TYPE_LAYER)
|
|
|
|
|
|
|
|
#define parent_class gimp_link_layer_parent_class
|
|
|
|
|
2025-08-09 23:26:13 +02:00
|
|
|
static GParamSpec *link_layer_props[N_PROPS] = { NULL, };
|
|
|
|
|
2019-07-04 23:49:20 +02:00
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_link_layer_class_init (GimpLinkLayerClass *klass)
|
|
|
|
{
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass);
|
|
|
|
GimpViewableClass *viewable_class = GIMP_VIEWABLE_CLASS (klass);
|
|
|
|
GimpItemClass *item_class = GIMP_ITEM_CLASS (klass);
|
|
|
|
GimpDrawableClass *drawable_class = GIMP_DRAWABLE_CLASS (klass);
|
|
|
|
GimpLayerClass *layer_class = GIMP_LAYER_CLASS (klass);
|
|
|
|
|
|
|
|
object_class->finalize = gimp_link_layer_finalize;
|
|
|
|
object_class->get_property = gimp_link_layer_get_property;
|
|
|
|
object_class->set_property = gimp_link_layer_set_property;
|
|
|
|
|
|
|
|
gimp_object_class->get_memsize = gimp_link_layer_get_memsize;
|
|
|
|
|
|
|
|
viewable_class->default_icon_name = "emblem-symbolic-link";
|
|
|
|
viewable_class->default_name = _("Link Layer");
|
|
|
|
|
|
|
|
item_class->duplicate = gimp_link_layer_duplicate;
|
|
|
|
item_class->rename = gimp_link_layer_rename;
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 14:49:12 +02:00
|
|
|
item_class->translate = gimp_link_layer_translate;
|
2020-07-29 19:17:04 +02:00
|
|
|
item_class->scale = gimp_link_layer_scale;
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 14:49:12 +02:00
|
|
|
item_class->transform = gimp_link_layer_transform;
|
2019-07-04 23:49:20 +02:00
|
|
|
|
|
|
|
item_class->rename_desc = _("Rename Link Layer");
|
|
|
|
item_class->translate_desc = _("Move Link Layer");
|
|
|
|
item_class->scale_desc = _("Scale Link Layer");
|
|
|
|
item_class->resize_desc = _("Resize Link Layer");
|
|
|
|
item_class->flip_desc = _("Flip Link Layer");
|
|
|
|
item_class->rotate_desc = _("Rotate Link Layer");
|
|
|
|
item_class->transform_desc = _("Transform Link Layer");
|
|
|
|
|
|
|
|
drawable_class->set_buffer = gimp_link_layer_set_buffer;
|
|
|
|
drawable_class->push_undo = gimp_link_layer_push_undo;
|
|
|
|
|
|
|
|
layer_class->convert_type = gimp_link_layer_convert_type;
|
|
|
|
|
2025-08-09 23:26:13 +02:00
|
|
|
link_layer_props[PROP_LINK] = g_param_spec_object ("link",
|
|
|
|
NULL, NULL,
|
|
|
|
GIMP_TYPE_LINK,
|
|
|
|
GIMP_PARAM_READWRITE |
|
|
|
|
GIMP_PARAM_STATIC_STRINGS);
|
|
|
|
|
|
|
|
link_layer_props[PROP_AUTO_RENAME] = g_param_spec_boolean ("auto-rename",
|
|
|
|
NULL, NULL,
|
|
|
|
TRUE,
|
|
|
|
GIMP_PARAM_READWRITE |
|
|
|
|
GIMP_PARAM_STATIC_STRINGS);
|
|
|
|
|
|
|
|
link_layer_props[PROP_SCALED_ONLY] = g_param_spec_boolean ("scaled-only",
|
|
|
|
NULL, NULL,
|
|
|
|
FALSE,
|
|
|
|
GIMP_PARAM_READWRITE |
|
|
|
|
GIMP_PARAM_STATIC_STRINGS);
|
|
|
|
|
|
|
|
g_object_class_install_properties (object_class, N_PROPS, link_layer_props);
|
2019-07-04 23:49:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_link_layer_init (GimpLinkLayer *layer)
|
|
|
|
{
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 14:49:12 +02:00
|
|
|
layer->p = gimp_link_layer_get_instance_private (layer);
|
|
|
|
layer->p->link = NULL;
|
|
|
|
gimp_matrix3_identity (&layer->p->matrix);
|
|
|
|
|
|
|
|
layer->p->scaled_only = FALSE;
|
|
|
|
layer->p->auto_rename = FALSE;
|
|
|
|
layer->p->offset_x = 0;
|
|
|
|
layer->p->offset_y = 0;
|
|
|
|
layer->p->interpolation = GIMP_INTERPOLATION_NONE;
|
|
|
|
|
|
|
|
layer->p->keep_monitoring = FALSE;
|
2019-07-04 23:49:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_link_layer_finalize (GObject *object)
|
|
|
|
{
|
|
|
|
GimpLinkLayer *layer = GIMP_LINK_LAYER (object);
|
|
|
|
|
|
|
|
g_clear_object (&layer->p->link);
|
|
|
|
|
|
|
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_link_layer_get_property (GObject *object,
|
|
|
|
guint property_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
GimpLinkLayer *layer = GIMP_LINK_LAYER (object);
|
|
|
|
|
|
|
|
switch (property_id)
|
|
|
|
{
|
|
|
|
case PROP_LINK:
|
|
|
|
g_value_set_object (value, layer->p->link);
|
|
|
|
break;
|
|
|
|
case PROP_AUTO_RENAME:
|
|
|
|
g_value_set_boolean (value, layer->p->auto_rename);
|
|
|
|
break;
|
2025-03-31 22:36:34 +02:00
|
|
|
case PROP_SCALED_ONLY:
|
|
|
|
g_value_set_boolean (value, layer->p->scaled_only);
|
|
|
|
break;
|
2019-07-04 23:49:20 +02:00
|
|
|
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_link_layer_set_property (GObject *object,
|
|
|
|
guint property_id,
|
|
|
|
const GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
GimpLinkLayer *layer = GIMP_LINK_LAYER (object);
|
|
|
|
|
|
|
|
switch (property_id)
|
|
|
|
{
|
|
|
|
case PROP_LINK:
|
2025-08-07 16:53:22 +02:00
|
|
|
gimp_link_layer_set_link (layer, g_value_get_object (value), FALSE);
|
2019-07-04 23:49:20 +02:00
|
|
|
break;
|
|
|
|
case PROP_AUTO_RENAME:
|
|
|
|
layer->p->auto_rename = g_value_get_boolean (value);
|
|
|
|
break;
|
2025-03-31 22:36:34 +02:00
|
|
|
case PROP_SCALED_ONLY:
|
|
|
|
layer->p->scaled_only = g_value_get_boolean (value);
|
|
|
|
break;
|
2019-07-04 23:49:20 +02:00
|
|
|
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static gint64
|
|
|
|
gimp_link_layer_get_memsize (GimpObject *object,
|
|
|
|
gint64 *gui_size)
|
|
|
|
{
|
|
|
|
GimpLinkLayer *layer = GIMP_LINK_LAYER (object);
|
|
|
|
gint64 memsize = 0;
|
|
|
|
|
|
|
|
memsize += gimp_object_get_memsize (GIMP_OBJECT (layer->p->link),
|
|
|
|
gui_size);
|
|
|
|
|
|
|
|
return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object,
|
|
|
|
gui_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
static GimpItem *
|
|
|
|
gimp_link_layer_duplicate (GimpItem *item,
|
|
|
|
GType new_type)
|
|
|
|
{
|
|
|
|
GimpItem *new_item;
|
|
|
|
|
|
|
|
g_return_val_if_fail (g_type_is_a (new_type, GIMP_TYPE_DRAWABLE), NULL);
|
|
|
|
|
|
|
|
new_item = GIMP_ITEM_CLASS (parent_class)->duplicate (item, new_type);
|
|
|
|
|
|
|
|
if (GIMP_IS_LINK_LAYER (new_item))
|
|
|
|
{
|
|
|
|
GimpLinkLayer *layer = GIMP_LINK_LAYER (item);
|
|
|
|
GimpLinkLayer *new_layer = GIMP_LINK_LAYER (new_item);
|
2025-08-09 23:26:13 +02:00
|
|
|
GimpLink *link = NULL;
|
2025-08-13 16:08:09 +02:00
|
|
|
GeglBuffer *buffer;
|
|
|
|
gint width;
|
|
|
|
gint height;
|
2019-07-04 23:49:20 +02:00
|
|
|
|
|
|
|
if (layer->p->link)
|
|
|
|
{
|
2025-08-09 23:26:13 +02:00
|
|
|
link = gimp_link_duplicate (layer->p->link);
|
2019-07-04 23:49:20 +02:00
|
|
|
gimp_link_layer_set_link (new_layer, link, FALSE);
|
|
|
|
}
|
2025-04-01 00:03:36 +02:00
|
|
|
|
|
|
|
gimp_config_sync (G_OBJECT (layer), G_OBJECT (new_layer), 0);
|
|
|
|
|
2025-08-13 16:08:09 +02:00
|
|
|
buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (layer));
|
|
|
|
width = gegl_buffer_get_width (buffer);
|
|
|
|
height = gegl_buffer_get_height (buffer);
|
2025-04-01 00:03:36 +02:00
|
|
|
|
2025-08-13 16:08:09 +02:00
|
|
|
if (width != gimp_item_get_width (GIMP_ITEM (new_layer)) ||
|
|
|
|
height != gimp_item_get_height (GIMP_ITEM (new_layer)))
|
|
|
|
{
|
|
|
|
GeglBuffer *new_buffer;
|
|
|
|
GeglRectangle bounds;
|
|
|
|
|
|
|
|
gimp_item_get_offset (GIMP_ITEM (new_layer), &bounds.x, &bounds.y);
|
|
|
|
bounds.width = 0;
|
|
|
|
bounds.height = 0;
|
|
|
|
|
|
|
|
new_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, width, height),
|
|
|
|
gimp_drawable_get_format (GIMP_DRAWABLE (new_layer)));
|
|
|
|
GIMP_DRAWABLE_CLASS (parent_class)->set_buffer (GIMP_DRAWABLE (new_layer),
|
|
|
|
FALSE, NULL,
|
|
|
|
new_buffer, &bounds);
|
|
|
|
g_object_unref (new_buffer);
|
2025-04-01 00:03:36 +02:00
|
|
|
}
|
|
|
|
|
2025-08-13 16:08:09 +02:00
|
|
|
gimp_gegl_buffer_copy (buffer, NULL, GEGL_ABYSS_NONE,
|
|
|
|
gimp_drawable_get_buffer (GIMP_DRAWABLE (new_layer)), NULL);
|
|
|
|
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 14:49:12 +02:00
|
|
|
new_layer->p->scaled_only = layer->p->scaled_only;
|
|
|
|
new_layer->p->auto_rename = layer->p->auto_rename;
|
|
|
|
new_layer->p->matrix = layer->p->matrix;
|
|
|
|
new_layer->p->offset_x = layer->p->offset_x;
|
|
|
|
new_layer->p->offset_y = layer->p->offset_y;
|
|
|
|
new_layer->p->interpolation = layer->p->interpolation;
|
|
|
|
|
|
|
|
new_layer->p->keep_monitoring = FALSE;
|
2025-08-09 23:26:13 +02:00
|
|
|
|
|
|
|
g_clear_object (&link);
|
2019-07-04 23:49:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return new_item;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
gimp_link_layer_rename (GimpItem *item,
|
|
|
|
const gchar *new_name,
|
|
|
|
const gchar *undo_desc,
|
|
|
|
GError **error)
|
|
|
|
{
|
|
|
|
if (GIMP_ITEM_CLASS (parent_class)->rename (item, new_name, undo_desc, error))
|
|
|
|
{
|
|
|
|
g_object_set (item, "auto-rename", FALSE, NULL);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 14:49:12 +02:00
|
|
|
static void
|
|
|
|
gimp_link_layer_translate (GimpItem *item,
|
|
|
|
gdouble offset_x,
|
|
|
|
gdouble offset_y,
|
|
|
|
gboolean push_undo)
|
|
|
|
{
|
|
|
|
GimpLinkLayer *layer = GIMP_LINK_LAYER (item);
|
|
|
|
|
|
|
|
if (! gimp_matrix3_is_identity (&layer->p->matrix))
|
|
|
|
gimp_matrix3_translate (&layer->p->matrix, offset_x, offset_y);
|
|
|
|
|
|
|
|
GIMP_ITEM_CLASS (parent_class)->translate (item, offset_x, offset_y, push_undo);
|
|
|
|
}
|
|
|
|
|
2020-07-29 19:17:04 +02:00
|
|
|
static void
|
|
|
|
gimp_link_layer_scale (GimpItem *item,
|
|
|
|
gint new_width,
|
|
|
|
gint new_height,
|
|
|
|
gint new_offset_x,
|
|
|
|
gint new_offset_y,
|
|
|
|
GimpInterpolationType interpolation_type,
|
|
|
|
GimpProgress *progress)
|
|
|
|
{
|
|
|
|
GimpLinkLayer *link_layer = GIMP_LINK_LAYER (item);
|
|
|
|
GimpLayer *layer = GIMP_LAYER (item);
|
|
|
|
GimpObjectQueue *queue = NULL;
|
|
|
|
|
|
|
|
if (progress && layer->mask)
|
|
|
|
{
|
|
|
|
GimpLayerMask *mask;
|
|
|
|
|
|
|
|
queue = gimp_object_queue_new (progress);
|
|
|
|
progress = GIMP_PROGRESS (queue);
|
|
|
|
|
|
|
|
/* temporarily set layer->mask to NULL, so that its size won't be counted
|
|
|
|
* when pushing the layer to the queue.
|
|
|
|
*/
|
|
|
|
mask = layer->mask;
|
|
|
|
layer->mask = NULL;
|
|
|
|
|
|
|
|
gimp_object_queue_push (queue, layer);
|
|
|
|
gimp_object_queue_push (queue, mask);
|
|
|
|
|
|
|
|
layer->mask = mask;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (queue)
|
|
|
|
gimp_object_queue_pop (queue);
|
|
|
|
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 14:49:12 +02:00
|
|
|
if (gimp_link_is_vector (link_layer->p->link) &&
|
|
|
|
gimp_link_is_monitored (link_layer->p->link) &&
|
|
|
|
gimp_matrix3_is_identity (&link_layer->p->matrix))
|
2020-07-29 19:17:04 +02:00
|
|
|
{
|
2025-03-31 22:36:34 +02:00
|
|
|
/* Non-modified vector images are always recomputed from the
|
|
|
|
* source file and therefore are always sharp.
|
|
|
|
*/
|
2025-08-28 23:06:11 +02:00
|
|
|
gimp_link_set_size (link_layer->p->link, new_width, new_height, FALSE);
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 14:49:12 +02:00
|
|
|
gimp_item_set_offset (item, new_offset_x, new_offset_y);
|
|
|
|
gimp_link_layer_render_link (link_layer);
|
2025-03-31 22:36:34 +02:00
|
|
|
}
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 14:49:12 +02:00
|
|
|
else if (! gimp_matrix3_is_identity (&link_layer->p->matrix))
|
2025-03-31 22:36:34 +02:00
|
|
|
{
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 14:49:12 +02:00
|
|
|
GimpMatrix3 matrix = link_layer->p->matrix;
|
|
|
|
gdouble x_scale_factor;
|
|
|
|
gdouble y_scale_factor;
|
|
|
|
gint offset_x;
|
|
|
|
gint offset_y;
|
2025-03-31 22:36:34 +02:00
|
|
|
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 14:49:12 +02:00
|
|
|
x_scale_factor = (gdouble) new_width / gimp_item_get_width (item);
|
|
|
|
y_scale_factor = (gdouble) new_height / gimp_item_get_height (item);
|
2025-03-31 22:36:34 +02:00
|
|
|
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 14:49:12 +02:00
|
|
|
gimp_matrix3_scale (&matrix, x_scale_factor, y_scale_factor);
|
|
|
|
|
|
|
|
gimp_link_layer_set_transform (link_layer, &matrix, interpolation_type, TRUE);
|
|
|
|
|
|
|
|
/* Unfortunately we can't know the proper translation offset to
|
|
|
|
* set before we replay the full matrix (the offsets may have been
|
|
|
|
* changed in previous transformations).
|
|
|
|
* To avoid re-loading the source image twice though, I don't call
|
|
|
|
* gimp_link_layer_set_transform() again but directly edit the
|
|
|
|
* matrix and set the offset.
|
|
|
|
*/
|
|
|
|
gimp_item_get_offset (item, &offset_x, &offset_y);
|
|
|
|
gimp_matrix3_translate (&link_layer->p->matrix,
|
|
|
|
new_offset_x - offset_x,
|
|
|
|
new_offset_y - offset_y);
|
|
|
|
gimp_item_set_offset (item, new_offset_x, new_offset_y);
|
|
|
|
gimp_drawable_update_all (GIMP_DRAWABLE (layer));
|
|
|
|
}
|
|
|
|
else if (gimp_link_is_monitored (link_layer->p->link))
|
|
|
|
{
|
|
|
|
GimpMatrix3 matrix = link_layer->p->matrix;
|
|
|
|
gdouble x_scale_factor;
|
|
|
|
gdouble y_scale_factor;
|
|
|
|
gint offset_x;
|
|
|
|
gint offset_y;
|
|
|
|
|
|
|
|
x_scale_factor = (gdouble) new_width / gimp_item_get_width (item);
|
|
|
|
y_scale_factor = (gdouble) new_height / gimp_item_get_height (item);
|
|
|
|
|
|
|
|
gimp_matrix3_scale (&matrix, x_scale_factor, y_scale_factor);
|
|
|
|
gimp_item_get_offset (item, &offset_x, &offset_y);
|
|
|
|
gimp_matrix3_translate (&matrix,
|
|
|
|
new_offset_x - offset_x,
|
|
|
|
new_offset_y - offset_y);
|
|
|
|
gimp_link_layer_set_transform (link_layer, &matrix, interpolation_type, TRUE);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-07-29 19:17:04 +02:00
|
|
|
GIMP_ITEM_CLASS (parent_class)->scale (GIMP_ITEM (layer),
|
|
|
|
new_width, new_height,
|
|
|
|
new_offset_x, new_offset_y,
|
|
|
|
interpolation_type, progress);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (layer->mask)
|
|
|
|
{
|
|
|
|
if (queue)
|
|
|
|
gimp_object_queue_pop (queue);
|
|
|
|
|
|
|
|
gimp_item_scale (GIMP_ITEM (layer->mask),
|
|
|
|
new_width, new_height,
|
|
|
|
new_offset_x, new_offset_y,
|
|
|
|
interpolation_type, progress);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_clear_object (&queue);
|
|
|
|
}
|
|
|
|
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 14:49:12 +02:00
|
|
|
static void
|
|
|
|
gimp_link_layer_transform (GimpItem *item,
|
|
|
|
GimpContext *context,
|
|
|
|
const GimpMatrix3 *matrix,
|
|
|
|
GimpTransformDirection direction,
|
|
|
|
GimpInterpolationType interpolation_type,
|
|
|
|
GimpTransformResize clip_result,
|
|
|
|
GimpProgress *progress,
|
|
|
|
gboolean push_undo)
|
|
|
|
{
|
|
|
|
GimpLinkLayer *layer = GIMP_LINK_LAYER (item);
|
|
|
|
gboolean keep_monitoring;
|
|
|
|
|
|
|
|
if (gimp_matrix3_is_identity (matrix))
|
|
|
|
return;
|
|
|
|
|
2025-08-27 19:35:12 +02:00
|
|
|
if (push_undo)
|
|
|
|
gimp_image_undo_push_link_layer (gimp_item_get_image (GIMP_ITEM (layer)),
|
|
|
|
_("Transform Link Layer"), layer);
|
|
|
|
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 14:49:12 +02:00
|
|
|
if (gimp_link_is_vector (layer->p->link) &&
|
|
|
|
gimp_link_is_monitored (layer->p->link) &&
|
|
|
|
gimp_matrix3_is_identity (&layer->p->matrix))
|
|
|
|
{
|
|
|
|
gint new_width;
|
|
|
|
gint new_height;
|
|
|
|
gint new_offset_x;
|
|
|
|
gint new_offset_y;
|
|
|
|
|
|
|
|
if (gimp_link_layer_is_scaling_matrix (layer, matrix,
|
|
|
|
&new_width, &new_height,
|
|
|
|
&new_offset_x, &new_offset_y))
|
|
|
|
{
|
|
|
|
/* Scaling when no other transformation has happened yet is
|
|
|
|
* special-case for vector links, because we can do even
|
|
|
|
* better by reloading from source.
|
|
|
|
*/
|
|
|
|
gimp_link_layer_scale (item, new_width, new_height,
|
|
|
|
new_offset_x, new_offset_y,
|
|
|
|
interpolation_type, progress);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Clipping would produce different results when applied on a single
|
|
|
|
* step of multiple transformations. So only "adjust" transformations
|
|
|
|
* are stored non-destructively. Any clip/crop transformation triggers
|
|
|
|
* a destructive transform.
|
|
|
|
*
|
|
|
|
* Note: we could also store non-destructively a single clipped
|
|
|
|
* transformation, but that would be harder to document and explain.
|
|
|
|
*/
|
|
|
|
keep_monitoring = (gimp_link_is_monitored (layer->p->link) &&
|
|
|
|
clip_result == GIMP_TRANSFORM_RESIZE_ADJUST);
|
|
|
|
|
|
|
|
if (keep_monitoring)
|
|
|
|
{
|
|
|
|
GimpMatrix3 left = *matrix;
|
|
|
|
GimpMatrix3 right = layer->p->matrix;
|
|
|
|
|
|
|
|
if (direction == GIMP_TRANSFORM_BACKWARD)
|
|
|
|
gimp_matrix3_invert (&left);
|
|
|
|
|
|
|
|
gimp_matrix3_mult (&left, &right);
|
|
|
|
gimp_link_layer_set_transform (layer, &right, interpolation_type, TRUE);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Reset the transformation matrix. */
|
|
|
|
gimp_matrix3_identity (&layer->p->matrix);
|
|
|
|
|
|
|
|
GIMP_ITEM_CLASS (parent_class)->transform (item, context,
|
|
|
|
matrix, direction,
|
|
|
|
interpolation_type,
|
|
|
|
clip_result, progress,
|
|
|
|
push_undo);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-04 23:49:20 +02:00
|
|
|
static void
|
|
|
|
gimp_link_layer_set_buffer (GimpDrawable *drawable,
|
|
|
|
gboolean push_undo,
|
|
|
|
const gchar *undo_desc,
|
|
|
|
GeglBuffer *buffer,
|
|
|
|
const GeglRectangle *bounds)
|
|
|
|
{
|
|
|
|
GimpLinkLayer *layer = GIMP_LINK_LAYER (drawable);
|
|
|
|
GimpImage *image = gimp_item_get_image (GIMP_ITEM (layer));
|
|
|
|
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 14:49:12 +02:00
|
|
|
if (push_undo)
|
|
|
|
{
|
|
|
|
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_DRAWABLE_MOD, undo_desc);
|
|
|
|
gimp_image_undo_push_link_layer (image, NULL, layer);
|
|
|
|
}
|
2019-07-04 23:49:20 +02:00
|
|
|
|
|
|
|
GIMP_DRAWABLE_CLASS (parent_class)->set_buffer (drawable,
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 14:49:12 +02:00
|
|
|
FALSE, undo_desc,
|
2019-07-04 23:49:20 +02:00
|
|
|
buffer,
|
|
|
|
bounds);
|
|
|
|
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 14:49:12 +02:00
|
|
|
if (push_undo)
|
2019-07-04 23:49:20 +02:00
|
|
|
{
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 14:49:12 +02:00
|
|
|
if (layer->p->link &&
|
|
|
|
gimp_link_is_monitored (layer->p->link) &&
|
|
|
|
! layer->p->keep_monitoring)
|
|
|
|
gimp_link_freeze (layer->p->link);
|
2019-07-04 23:49:20 +02:00
|
|
|
|
|
|
|
gimp_image_undo_group_end (image);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_link_layer_push_undo (GimpDrawable *drawable,
|
|
|
|
const gchar *undo_desc,
|
|
|
|
GeglBuffer *buffer,
|
|
|
|
gint x,
|
|
|
|
gint y,
|
|
|
|
gint width,
|
|
|
|
gint height)
|
|
|
|
{
|
|
|
|
GimpLinkLayer *layer = GIMP_LINK_LAYER (drawable);
|
|
|
|
GimpImage *image = gimp_item_get_image (GIMP_ITEM (layer));
|
2025-08-09 23:26:13 +02:00
|
|
|
gboolean monitored;
|
2019-07-04 23:49:20 +02:00
|
|
|
|
2025-08-09 23:26:13 +02:00
|
|
|
monitored = gimp_link_is_monitored (layer->p->link);
|
|
|
|
|
|
|
|
if (monitored)
|
|
|
|
{
|
|
|
|
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_DRAWABLE, undo_desc);
|
|
|
|
|
|
|
|
gimp_image_undo_push_link_layer (image, NULL, layer);
|
|
|
|
gimp_link_freeze (layer->p->link);
|
|
|
|
}
|
2019-07-04 23:49:20 +02:00
|
|
|
|
|
|
|
GIMP_DRAWABLE_CLASS (parent_class)->push_undo (drawable, undo_desc,
|
|
|
|
buffer,
|
|
|
|
x, y, width, height);
|
|
|
|
|
2025-08-09 23:26:13 +02:00
|
|
|
if (monitored)
|
2019-07-04 23:49:20 +02:00
|
|
|
{
|
|
|
|
gimp_image_undo_group_end (image);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_link_layer_convert_type (GimpLayer *layer,
|
|
|
|
GimpImage *dest_image,
|
|
|
|
const Babl *new_format,
|
|
|
|
GimpColorProfile *src_profile,
|
|
|
|
GimpColorProfile *dest_profile,
|
|
|
|
GeglDitherMethod layer_dither_type,
|
|
|
|
GeglDitherMethod mask_dither_type,
|
|
|
|
gboolean push_undo,
|
|
|
|
GimpProgress *progress)
|
|
|
|
{
|
|
|
|
GimpLinkLayer *link_layer = GIMP_LINK_LAYER (layer);
|
|
|
|
GimpImage *image = gimp_item_get_image (GIMP_ITEM (link_layer));
|
|
|
|
|
2025-08-26 19:23:30 +02:00
|
|
|
GIMP_LAYER_CLASS (parent_class)->convert_type (layer, dest_image,
|
|
|
|
new_format,
|
|
|
|
src_profile,
|
|
|
|
dest_profile,
|
|
|
|
layer_dither_type,
|
|
|
|
mask_dither_type,
|
|
|
|
push_undo,
|
|
|
|
progress);
|
|
|
|
|
|
|
|
if (link_layer->p->link && gimp_link_is_monitored (link_layer->p->link))
|
2019-07-04 23:49:20 +02:00
|
|
|
{
|
|
|
|
if (push_undo)
|
|
|
|
gimp_image_undo_push_link_layer (image, NULL, link_layer);
|
|
|
|
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 14:49:12 +02:00
|
|
|
gimp_link_layer_render_link (link_layer);
|
2019-07-04 23:49:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* public functions */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gimp_link_layer_new:
|
|
|
|
* @image: the #GimpImage the layer should belong to
|
|
|
|
* @text: a #GimpText object
|
|
|
|
*
|
|
|
|
* Creates a new link layer.
|
|
|
|
*
|
|
|
|
* Return value: a new #GimpLinkLayer or %NULL in case of a problem
|
|
|
|
**/
|
|
|
|
GimpLayer *
|
|
|
|
gimp_link_layer_new (GimpImage *image,
|
|
|
|
GimpLink *link)
|
|
|
|
{
|
|
|
|
GimpLinkLayer *layer;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
|
|
|
|
|
|
|
|
layer =
|
|
|
|
GIMP_LINK_LAYER (gimp_drawable_new (GIMP_TYPE_LINK_LAYER,
|
|
|
|
image, NULL,
|
|
|
|
0, 0, 1, 1,
|
|
|
|
gimp_image_get_layer_format (image,
|
|
|
|
TRUE)));
|
|
|
|
gimp_layer_set_mode (GIMP_LAYER (layer),
|
|
|
|
gimp_image_get_default_new_layer_mode (image),
|
|
|
|
FALSE);
|
2025-08-07 16:53:22 +02:00
|
|
|
|
2019-07-04 23:49:20 +02:00
|
|
|
if (! gimp_link_layer_set_link (layer, link, FALSE))
|
2025-08-07 16:53:22 +02:00
|
|
|
g_clear_object (&layer);
|
2019-07-04 23:49:20 +02:00
|
|
|
|
|
|
|
return GIMP_LAYER (layer);
|
|
|
|
}
|
|
|
|
|
|
|
|
GimpLink *
|
|
|
|
gimp_link_layer_get_link (GimpLinkLayer *layer)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_LINK_LAYER (layer), NULL);
|
|
|
|
|
|
|
|
return layer->p->link;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
gimp_link_layer_set_link (GimpLinkLayer *layer,
|
|
|
|
GimpLink *link,
|
|
|
|
gboolean push_undo)
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 14:49:12 +02:00
|
|
|
{
|
|
|
|
return gimp_link_layer_set_link_with_matrix (layer, link, NULL,
|
|
|
|
GIMP_INTERPOLATION_NONE,
|
|
|
|
0, 0, push_undo);
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
gimp_link_layer_set_link_with_matrix (GimpLinkLayer *layer,
|
|
|
|
GimpLink *link,
|
|
|
|
GimpMatrix3 *matrix,
|
|
|
|
GimpInterpolationType interpolation_type,
|
|
|
|
gint offset_x,
|
|
|
|
gint offset_y,
|
|
|
|
gboolean push_undo)
|
2019-07-04 23:49:20 +02:00
|
|
|
{
|
|
|
|
gboolean rendered = FALSE;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_LINK_LAYER (layer), FALSE);
|
|
|
|
g_return_val_if_fail (GIMP_IS_LINK (link), FALSE);
|
|
|
|
|
|
|
|
if (gimp_item_is_attached (GIMP_ITEM (layer)) && push_undo)
|
|
|
|
gimp_image_undo_push_link_layer (gimp_item_get_image (GIMP_ITEM (layer)),
|
|
|
|
_("Set layer link"), layer);
|
|
|
|
|
|
|
|
if (layer->p->link)
|
|
|
|
{
|
|
|
|
g_signal_handlers_disconnect_by_func (layer->p->link,
|
2025-08-13 16:08:09 +02:00
|
|
|
G_CALLBACK (gimp_link_layer_render_full),
|
2019-07-04 23:49:20 +02:00
|
|
|
layer);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2025-08-07 16:53:22 +02:00
|
|
|
g_set_object (&layer->p->link, link);
|
|
|
|
|
2019-07-04 23:49:20 +02:00
|
|
|
if (link)
|
|
|
|
{
|
|
|
|
g_signal_connect_object (link, "changed",
|
2025-08-13 16:08:09 +02:00
|
|
|
G_CALLBACK (gimp_link_layer_render_full),
|
2019-07-04 23:49:20 +02:00
|
|
|
layer, G_CONNECT_SWAPPED);
|
|
|
|
|
2025-08-09 23:26:13 +02:00
|
|
|
if (gimp_link_is_monitored (link))
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 14:49:12 +02:00
|
|
|
{
|
|
|
|
if (matrix == NULL)
|
|
|
|
{
|
2025-08-13 16:08:09 +02:00
|
|
|
gimp_matrix3_identity (&layer->p->matrix);
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 14:49:12 +02:00
|
|
|
rendered = gimp_link_layer_render_link (layer);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (! gimp_matrix3_is_identity (matrix))
|
|
|
|
{
|
|
|
|
layer->p->offset_x = offset_x;
|
|
|
|
layer->p->offset_y = offset_y;
|
|
|
|
}
|
|
|
|
rendered = gimp_link_layer_set_transform (layer, matrix, interpolation_type, push_undo);
|
|
|
|
}
|
|
|
|
}
|
2019-07-04 23:49:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
g_object_notify (G_OBJECT (layer), "link");
|
|
|
|
gimp_viewable_invalidate_preview (GIMP_VIEWABLE (layer));
|
|
|
|
|
|
|
|
return rendered;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gimp_link_layer_discard:
|
|
|
|
* @layer: a #GimpLinkLayer
|
|
|
|
*
|
|
|
|
* Discards the link. This makes @layer behave like a
|
|
|
|
* normal layer.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
gimp_link_layer_discard (GimpLinkLayer *layer)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_LINK_LAYER (layer));
|
|
|
|
g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (layer)));
|
|
|
|
|
|
|
|
gimp_image_undo_push_link_layer (gimp_item_get_image (GIMP_ITEM (layer)),
|
|
|
|
_("Discard Link"), layer);
|
|
|
|
|
2025-08-09 23:26:13 +02:00
|
|
|
gimp_link_freeze (layer->p->link);
|
2025-08-06 11:47:33 +02:00
|
|
|
|
2025-08-09 23:26:13 +02:00
|
|
|
/* Triggers thumbnail update. */
|
2025-08-06 11:47:33 +02:00
|
|
|
gimp_drawable_update_all (GIMP_DRAWABLE (layer));
|
2025-08-09 23:26:13 +02:00
|
|
|
/* Triggers contextual menu update. */
|
|
|
|
gimp_image_flush (gimp_item_get_image (GIMP_ITEM (layer)));
|
2019-07-04 23:49:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_link_layer_monitor (GimpLinkLayer *layer)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_LINK_LAYER (layer));
|
|
|
|
g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (layer)));
|
|
|
|
|
|
|
|
gimp_image_undo_push_link_layer (gimp_item_get_image (GIMP_ITEM (layer)),
|
|
|
|
_("Monitor Link"), layer);
|
|
|
|
|
2025-08-09 23:26:13 +02:00
|
|
|
gimp_link_thaw (layer->p->link);
|
2025-08-13 16:08:09 +02:00
|
|
|
gimp_matrix3_identity (&layer->p->matrix);
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 14:49:12 +02:00
|
|
|
gimp_link_layer_render_link (layer);
|
2019-07-04 23:49:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
2025-08-09 23:26:13 +02:00
|
|
|
gimp_link_layer_is_monitored (GimpLinkLayer *layer)
|
2019-07-04 23:49:20 +02:00
|
|
|
{
|
2025-08-09 23:26:13 +02:00
|
|
|
g_return_val_if_fail (GIMP_IS_LINK_LAYER (layer), FALSE);
|
|
|
|
|
|
|
|
return (GIMP_LINK_LAYER (layer)->p->link &&
|
|
|
|
gimp_link_is_monitored (GIMP_LINK_LAYER (layer)->p->link));
|
2019-07-04 23:49:20 +02:00
|
|
|
}
|
|
|
|
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 14:49:12 +02:00
|
|
|
gboolean
|
|
|
|
gimp_link_layer_get_transform (GimpLinkLayer *layer,
|
|
|
|
GimpMatrix3 *matrix,
|
|
|
|
gint *offset_x,
|
|
|
|
gint *offset_y,
|
|
|
|
GimpInterpolationType *interpolation)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_LINK_LAYER (layer), FALSE);
|
|
|
|
|
|
|
|
*matrix = layer->p->matrix;
|
|
|
|
*offset_x = layer->p->offset_x;
|
|
|
|
*offset_y = layer->p->offset_y;
|
|
|
|
*interpolation = layer->p->interpolation;
|
|
|
|
|
|
|
|
return ! gimp_matrix3_is_identity (matrix);
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
gimp_link_layer_set_transform (GimpLinkLayer *layer,
|
|
|
|
GimpMatrix3 *matrix,
|
|
|
|
GimpInterpolationType interpolation_type,
|
|
|
|
gboolean push_undo)
|
|
|
|
{
|
|
|
|
Gimp *gimp;
|
|
|
|
gboolean rendered;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_LINK_LAYER (layer), FALSE);
|
|
|
|
g_return_val_if_fail (gimp_link_is_monitored (layer->p->link), FALSE);
|
|
|
|
|
|
|
|
gimp = (gimp_item_get_image (GIMP_ITEM (layer)))->gimp;
|
|
|
|
|
|
|
|
if (gimp_matrix3_is_identity (&layer->p->matrix))
|
|
|
|
/* First transformation: store the initial offset. */
|
|
|
|
gimp_item_get_offset (GIMP_ITEM (layer), &layer->p->offset_x, &layer->p->offset_y);
|
|
|
|
|
|
|
|
gimp_item_set_offset (GIMP_ITEM (layer), layer->p->offset_x, layer->p->offset_y);
|
|
|
|
|
|
|
|
rendered = gimp_link_layer_render_link (layer);
|
|
|
|
if (! gimp_matrix3_is_identity (matrix))
|
|
|
|
{
|
|
|
|
layer->p->keep_monitoring = TRUE;
|
|
|
|
GIMP_ITEM_CLASS (parent_class)->transform (GIMP_ITEM (layer),
|
|
|
|
gimp_get_user_context (gimp),
|
|
|
|
matrix,
|
|
|
|
GIMP_TRANSFORM_FORWARD,
|
|
|
|
interpolation_type,
|
|
|
|
GIMP_TRANSFORM_RESIZE_ADJUST,
|
|
|
|
NULL, push_undo);
|
|
|
|
layer->p->keep_monitoring = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
layer->p->matrix = *matrix;
|
|
|
|
|
|
|
|
/* Interpolations are used to obtain reasonable quality. Considering
|
|
|
|
* that doing a single transform will always be better than several
|
|
|
|
* transforms in a row, it's OK to just drop the interpolation
|
|
|
|
* algorithm of previous transforms. We just store the last one.
|
|
|
|
*/
|
|
|
|
layer->p->interpolation = interpolation_type;
|
|
|
|
|
|
|
|
return rendered;
|
|
|
|
}
|
|
|
|
|
2025-08-30 09:54:10 +02:00
|
|
|
gboolean
|
|
|
|
gimp_item_is_link_layer (GimpItem *item)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_ITEM (item), FALSE);
|
|
|
|
|
|
|
|
return (GIMP_IS_LINK_LAYER (item) &&
|
|
|
|
gimp_link_layer_is_monitored (GIMP_LINK_LAYER (item)));
|
|
|
|
}
|
|
|
|
|
2025-08-26 22:51:36 +02:00
|
|
|
void
|
|
|
|
gimp_link_layer_set_xcf_flags (GimpLinkLayer *layer,
|
|
|
|
guint32 flags)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_LINK_LAYER (layer));
|
|
|
|
|
|
|
|
g_object_set (layer,
|
|
|
|
"auto-rename", (flags & LINK_LAYER_XCF_DONT_AUTO_RENAME) == 0,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
if ((flags & LINK_LAYER_XCF_MODIFIED) != 0)
|
|
|
|
gimp_link_freeze (layer->p->link);
|
|
|
|
}
|
|
|
|
|
2019-07-08 16:48:56 +02:00
|
|
|
guint32
|
|
|
|
gimp_link_layer_get_xcf_flags (GimpLinkLayer *link_layer)
|
|
|
|
{
|
|
|
|
guint flags = 0;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_LINK_LAYER (link_layer), 0);
|
|
|
|
|
|
|
|
if (! link_layer->p->auto_rename)
|
|
|
|
flags |= LINK_LAYER_XCF_DONT_AUTO_RENAME;
|
|
|
|
|
2025-08-09 23:26:13 +02:00
|
|
|
if (! gimp_link_is_monitored (link_layer->p->link))
|
2019-07-08 16:48:56 +02:00
|
|
|
flags |= LINK_LAYER_XCF_MODIFIED;
|
|
|
|
|
|
|
|
return flags;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-07-04 23:49:20 +02:00
|
|
|
/* private functions */
|
|
|
|
|
2025-08-13 16:08:09 +02:00
|
|
|
static void
|
|
|
|
gimp_link_layer_render_full (GimpLinkLayer *layer)
|
|
|
|
{
|
|
|
|
gimp_link_layer_render_link (layer);
|
|
|
|
if (! gimp_matrix3_is_identity (&layer->p->matrix))
|
|
|
|
{
|
|
|
|
Gimp *gimp = (gimp_item_get_image (GIMP_ITEM (layer)))->gimp;
|
|
|
|
|
|
|
|
gimp_item_set_offset (GIMP_ITEM (layer), layer->p->offset_x, layer->p->offset_y);
|
|
|
|
|
|
|
|
layer->p->keep_monitoring = TRUE;
|
|
|
|
GIMP_ITEM_CLASS (parent_class)->transform (GIMP_ITEM (layer),
|
|
|
|
gimp_get_user_context (gimp),
|
|
|
|
&layer->p->matrix,
|
|
|
|
GIMP_TRANSFORM_FORWARD,
|
|
|
|
layer->p->interpolation,
|
|
|
|
GIMP_TRANSFORM_RESIZE_ADJUST,
|
|
|
|
NULL, FALSE);
|
|
|
|
layer->p->keep_monitoring = FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-04 23:49:20 +02:00
|
|
|
static gboolean
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 14:49:12 +02:00
|
|
|
gimp_link_layer_render_link (GimpLinkLayer *layer)
|
2019-07-04 23:49:20 +02:00
|
|
|
{
|
|
|
|
GimpDrawable *drawable;
|
|
|
|
GimpItem *item;
|
|
|
|
GimpImage *image;
|
|
|
|
GeglBuffer *buffer;
|
|
|
|
gdouble xres;
|
|
|
|
gdouble yres;
|
|
|
|
gint width;
|
|
|
|
gint height;
|
|
|
|
|
|
|
|
if (! layer->p->link)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
drawable = GIMP_DRAWABLE (layer);
|
|
|
|
item = GIMP_ITEM (layer);
|
|
|
|
image = gimp_item_get_image (item);
|
|
|
|
|
|
|
|
gimp_image_get_resolution (image, &xres, &yres);
|
|
|
|
/* TODO: I could imagine a GimpBusyBox (to be made as GimpProgress) in
|
|
|
|
* the later list showing layer update.
|
|
|
|
*/
|
2025-08-07 16:53:22 +02:00
|
|
|
buffer = gimp_link_get_buffer (layer->p->link);
|
2019-07-04 23:49:20 +02:00
|
|
|
|
|
|
|
if (! buffer)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
width = gegl_buffer_get_width (buffer);
|
|
|
|
height = gegl_buffer_get_height (buffer);
|
|
|
|
|
|
|
|
g_object_freeze_notify (G_OBJECT (drawable));
|
|
|
|
|
|
|
|
if ((width != gimp_item_get_width (item) ||
|
|
|
|
height != gimp_item_get_height (item)))
|
|
|
|
{
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 14:49:12 +02:00
|
|
|
GeglBuffer *new_buffer;
|
|
|
|
GeglRectangle bounds;
|
|
|
|
|
|
|
|
gimp_item_get_offset (GIMP_ITEM (drawable),
|
|
|
|
&bounds.x, &bounds.y);
|
|
|
|
bounds.width = 0;
|
|
|
|
bounds.height = 0;
|
2019-07-04 23:49:20 +02:00
|
|
|
|
|
|
|
new_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, width, height),
|
|
|
|
gimp_drawable_get_format (drawable));
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 14:49:12 +02:00
|
|
|
GIMP_DRAWABLE_CLASS (parent_class)->set_buffer (drawable,
|
|
|
|
FALSE, NULL,
|
|
|
|
new_buffer, &bounds);
|
2019-07-04 23:49:20 +02:00
|
|
|
g_object_unref (new_buffer);
|
|
|
|
|
|
|
|
if (gimp_layer_get_mask (GIMP_LAYER (layer)))
|
|
|
|
{
|
|
|
|
GimpLayerMask *mask = gimp_layer_get_mask (GIMP_LAYER (layer));
|
|
|
|
|
|
|
|
static GimpContext *unused_eek = NULL;
|
|
|
|
|
|
|
|
if (! unused_eek)
|
|
|
|
unused_eek = gimp_context_new (image->gimp, "eek", NULL);
|
|
|
|
|
|
|
|
gimp_item_resize (GIMP_ITEM (mask),
|
|
|
|
unused_eek, GIMP_FILL_TRANSPARENT,
|
|
|
|
width, height, 0, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (layer->p->auto_rename)
|
|
|
|
{
|
|
|
|
GimpItem *item = GIMP_ITEM (layer);
|
|
|
|
gchar *name = NULL;
|
|
|
|
|
|
|
|
if (layer->p->link)
|
|
|
|
{
|
|
|
|
name = g_strdup (gimp_object_get_name (layer->p->link));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (! name || ! name[0])
|
|
|
|
{
|
|
|
|
g_free (name);
|
|
|
|
name = g_strdup (_("Link Layer"));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gimp_item_is_attached (item))
|
|
|
|
{
|
|
|
|
gimp_item_tree_rename_item (gimp_item_get_tree (item), item,
|
|
|
|
name, FALSE, NULL);
|
|
|
|
g_free (name);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gimp_object_take_name (GIMP_OBJECT (layer), name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-03-31 18:41:09 +02:00
|
|
|
gimp_gegl_buffer_copy (buffer, NULL, GEGL_ABYSS_NONE,
|
|
|
|
gimp_drawable_get_buffer (drawable), NULL);
|
2019-07-04 23:49:20 +02:00
|
|
|
|
|
|
|
g_object_thaw_notify (G_OBJECT (drawable));
|
|
|
|
|
|
|
|
gimp_drawable_update (drawable, 0, 0, width, height);
|
|
|
|
gimp_image_flush (image);
|
|
|
|
|
|
|
|
return (width > 0 && height > 0);
|
|
|
|
}
|
|
|
|
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 14:49:12 +02:00
|
|
|
static gboolean
|
|
|
|
gimp_link_layer_is_scaling_matrix (GimpLinkLayer *layer,
|
|
|
|
const GimpMatrix3 *matrix,
|
|
|
|
gint *new_width,
|
|
|
|
gint *new_height,
|
|
|
|
gint *new_offset_x,
|
|
|
|
gint *new_offset_y)
|
|
|
|
{
|
|
|
|
gboolean is_scaling;
|
|
|
|
|
|
|
|
/* Scaling 3x3 matrix on a 2D plane (with optional translation). */
|
|
|
|
is_scaling = (matrix->coeff[0][0] > 0.0 && matrix->coeff[0][1] == 0.0 &&
|
2025-08-27 19:21:54 +02:00
|
|
|
matrix->coeff[1][0] < EPSILON && matrix->coeff[1][1] > 0.0 &&
|
|
|
|
matrix->coeff[2][0] < EPSILON && matrix->coeff[2][1] < EPSILON && matrix->coeff[2][2] == 1.0);
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 14:49:12 +02:00
|
|
|
|
|
|
|
if (is_scaling)
|
|
|
|
{
|
|
|
|
gint width;
|
|
|
|
gint height;
|
|
|
|
gint offset_x;
|
|
|
|
gint offset_y;
|
|
|
|
|
|
|
|
width = gimp_item_get_width (GIMP_ITEM (layer));
|
|
|
|
height = gimp_item_get_height (GIMP_ITEM (layer));
|
|
|
|
gimp_item_get_offset (GIMP_ITEM (layer), &offset_x, &offset_y);
|
|
|
|
|
|
|
|
*new_width = (gint) (width * matrix->coeff[0][0]);
|
2025-08-27 19:21:54 +02:00
|
|
|
*new_height = (gint) (height * matrix->coeff[1][1]);
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 14:49:12 +02:00
|
|
|
|
2025-08-27 19:21:54 +02:00
|
|
|
*new_offset_x = (gint) (offset_x * matrix->coeff[0][0] + matrix->coeff[0][2]);
|
|
|
|
*new_offset_y = (gint) (offset_y * matrix->coeff[1][1] + matrix->coeff[1][2]);
|
app: add generic support for less destructive transform tools.
This commit will make all transform tools run on a link layer cumulate
their transform matrix on top of the previous transform steps. It means
that as long as you don't edit the pixels another way (e.g. with a paint
tool), all your transformations will apply as a single transformation.
For instance it means that applying several transform tool steps on a
monitored link layer will be less destructive than applying the exact
same transformations on the exact same "normal" layer contents.
Even scaling an image to 1x1 then back to a big size will work very
fine!
Note nevertheless the following limitations in current implementation:
* The link layer with transformations will still show as a standard link
layer. Nothing says it has transformation applied on it right now.
* To drop transformations applied on a link layer, you have to discard
the link info, then monitor the link again. A specific action in the
contextual menu could be worth it.
* This should work with all transform tools (scale, rotation, unified,
perspective, 3D, even Warp…) but it won't work for the Flip tool, nor
will it work for the Transform actions. I will need to implement
GimpItem's rotate(), flip() and resize() methods next.
* The layer mask would still be destructively transformed (I have not
made any tests with layer masks yet, but this should be done next
too).
* I think that the "scaled-only" property is now meaningless. It is now
being replaced by the presence of the GimpMatrix3. Nevertheless I have
still not removed this property.
* The load/save code has not been redone yet to include all these
changes.
The kind of caveats we'd have to know about (and which are not planned
for change, because it's just how it is):
* Any intermediate interpolation methods are dropped when cumulating
transform steps. Only the last interpolation is stored. This is
because anyway the interpolation is only there as the best algorithm
where we visually see the less quality loss. Applying several
transformations as a single matrix will always be visually better than
applying several matrices (whatever the intermediate interpolation
methods chosen).
* This only works with the "Adjust" clipping method (basically no
clipping) because 2 transform steps with clipping won't produce the
same result as the multiplied matrix with clipping. It means that
applying a transform with clipping will downgrade your link layer to
being a normal layer.
The only issue I have with this is how to best convey that clipping is
a major setting setting here, which disables our less-destructive
abilities. Right now, people will just have to "know" it.
* Vector link layers in particular will have 2 levels of
non/less-destructivity transforms. In particular any scaling (both
through "Scale Image", "Scale Layers" and transform tools — since I
added code to detect a matrix doing only scaling and optionally
translation) done **first** will be completely non-destructive since
we will simply reload the original vector source at the right
dimensions. Any other kind of transforms will be appended through the
cumulative matrix, as raster link layers. This also includes scaling
done **after** other transforms, since we cannot easily move the
scaling first (matrix multiplication is not commutative). This second
level of scaling will therefore be *less* destructive, but still
destructive.
It is possible eventually to improve the whole thing if we add some
day the ability to request loading a vector image with a transform
matrix (it will then be up to each vector format plug-in to support
this feature or not).
Note: it could be argued that this whole implementation could in fact be
moved over to base layers, since it would allow also less-destructivity
when applying multiple transformations in a row. We would only merge
results once we edit pixels more directly.
But I think that it's not a bad idea to experiment with this new code in
the link layer. Eventually I may likely move this to the parent
GimpLayer if no blocking issues are found.
2025-08-13 14:49:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return is_scaling;
|
|
|
|
}
|