1
1
mirror of https://gitlab.gnome.org/GNOME/gimp.git synced 2025-10-06 05:22:40 +02:00

Compare commits

...

1 Commits

Author SHA1 Message Date
Massimo Valentini
fd5715e6d7 text, tools, pdb: NDE text rotation
Initial implementation of non-destructive transforms of text layers.
Applies to scale, rotate, flip, and shear tools (as well as Unified
Transform Tools' version of those operations).
2025-05-14 09:22:35 -03:00
10 changed files with 261 additions and 91 deletions

View File

@@ -39,6 +39,7 @@
#include "core/gimpitem.h"
#include "core/gimpparamspecs.h"
#include "core/gimpprogress.h"
#include "text/gimptextlayer.h"
#include "gimppdb.h"
#include "gimppdb-utils.h"
@@ -130,6 +131,7 @@ item_transform_flip_simple_invoker (GimpProcedure *procedure,
if (GIMP_IS_DRAWABLE (item) &&
item != GIMP_ITEM (mask) &&
! GIMP_IS_TEXT_LAYER (item) &&
! gimp_viewable_get_children (GIMP_VIEWABLE (item)) &&
! gimp_channel_is_empty (mask))
{
@@ -215,6 +217,7 @@ item_transform_flip_invoker (GimpProcedure *procedure,
if (GIMP_IS_DRAWABLE (item) &&
item != GIMP_ITEM (mask) &&
! GIMP_IS_TEXT_LAYER (item) &&
! gimp_viewable_get_children (GIMP_VIEWABLE (item)) &&
! gimp_channel_is_empty (mask))
{
@@ -319,6 +322,7 @@ item_transform_perspective_invoker (GimpProcedure *procedure,
if (GIMP_IS_DRAWABLE (item) &&
item != GIMP_ITEM (mask) &&
! GIMP_IS_TEXT_LAYER (item) &&
! gimp_viewable_get_children (GIMP_VIEWABLE (item)) &&
! gimp_channel_is_empty (mask))
{
@@ -407,6 +411,7 @@ item_transform_rotate_simple_invoker (GimpProcedure *procedure,
if (GIMP_IS_DRAWABLE (item) &&
item != GIMP_ITEM (mask) &&
! GIMP_IS_TEXT_LAYER (item) &&
! gimp_viewable_get_children (GIMP_VIEWABLE (item)) &&
! gimp_channel_is_empty (mask))
{
@@ -500,6 +505,7 @@ item_transform_rotate_invoker (GimpProcedure *procedure,
if (GIMP_IS_DRAWABLE (item) &&
item != GIMP_ITEM (mask) &&
! GIMP_IS_TEXT_LAYER (item) &&
! gimp_viewable_get_children (GIMP_VIEWABLE (item)) &&
! gimp_channel_is_empty (mask))
{
@@ -596,6 +602,7 @@ item_transform_scale_invoker (GimpProcedure *procedure,
if (GIMP_IS_DRAWABLE (item) &&
item != GIMP_ITEM (mask) &&
! GIMP_IS_TEXT_LAYER (item) &&
! gimp_viewable_get_children (GIMP_VIEWABLE (item)) &&
! gimp_channel_is_empty (mask))
{
@@ -687,6 +694,7 @@ item_transform_shear_invoker (GimpProcedure *procedure,
if (GIMP_IS_DRAWABLE (item) &&
item != GIMP_ITEM (mask) &&
! GIMP_IS_TEXT_LAYER (item) &&
! gimp_viewable_get_children (GIMP_VIEWABLE (item)) &&
! gimp_channel_is_empty (mask))
{
@@ -789,6 +797,7 @@ item_transform_2d_invoker (GimpProcedure *procedure,
if (GIMP_IS_DRAWABLE (item) &&
item != GIMP_ITEM (mask) &&
! GIMP_IS_TEXT_LAYER (item) &&
! gimp_viewable_get_children (GIMP_VIEWABLE (item)) &&
! gimp_channel_is_empty (mask))
{
@@ -899,6 +908,7 @@ item_transform_matrix_invoker (GimpProcedure *procedure,
if (GIMP_IS_DRAWABLE (item) &&
item != GIMP_ITEM (mask) &&
! GIMP_IS_TEXT_LAYER (item) &&
! gimp_viewable_get_children (GIMP_VIEWABLE (item)) &&
! gimp_channel_is_empty (mask))
{

View File

@@ -27,6 +27,7 @@
#include "text-types.h"
#include "core/gimp-transform-resize.h"
#include "core/gimp-transform-utils.h"
#include "core/gimpimage-undo.h"
@@ -43,6 +44,33 @@ static gboolean gimp_text_layer_set_transformation (GimpTextLayer *layer,
GimpMatrix3 *matrix);
static gboolean
gimp_text_layer_transform_scale (GimpTextLayer *layer,
gint new_width,
gint new_height,
gint new_offset_x,
gint new_offset_y)
{
GimpItem *item = GIMP_ITEM (layer);
GimpMatrix3 matrix;
GimpMatrix3 scale;
if (! gimp_text_layer_get_transformation (layer, &matrix))
return FALSE;
gimp_transform_matrix_scale (&scale,
gimp_item_get_offset_x (item),
gimp_item_get_offset_y (item),
gimp_item_get_width (item),
gimp_item_get_height (item),
new_offset_x, new_offset_y,
new_width, new_height);
gimp_matrix3_mult (&scale, &matrix);
return gimp_text_layer_set_transformation (layer, &matrix);
}
void
gimp_text_layer_scale (GimpItem *item,
gint new_width,
@@ -52,7 +80,25 @@ gimp_text_layer_scale (GimpItem *item,
GimpInterpolationType interpolation_type,
GimpProgress *progress)
{
/* TODO */
GimpTextLayer *layer = GIMP_TEXT_LAYER (item);
if (gimp_text_layer_transform_scale (layer, new_width, new_height,
new_offset_x, new_offset_y))
{
GimpLayerMask *mask = gimp_layer_get_mask (GIMP_LAYER (layer));
if (mask)
gimp_item_scale (GIMP_ITEM (mask),
new_width, new_height,
new_offset_x, new_offset_y,
interpolation_type, progress);
}
else
{
gimp_text_layer_parent_class ()->scale (item, new_width, new_height,
new_offset_x, new_offset_y,
interpolation_type, progress);
}
}
static gboolean
@@ -120,8 +166,8 @@ gimp_text_layer_rotate (GimpItem *item,
{
GimpTextLayer *layer = GIMP_TEXT_LAYER (item);
if (! gimp_text_layer_transform_rotate (layer,
rotate_type, center_x, center_y))
if (gimp_text_layer_transform_rotate (layer,
rotate_type, center_x, center_y))
{
GimpLayerMask *mask = gimp_layer_get_mask (GIMP_LAYER (layer));
@@ -137,17 +183,52 @@ gimp_text_layer_rotate (GimpItem *item,
}
}
static gboolean
gimp_text_layer_transform_matrix (GimpTextLayer *layer,
const GimpMatrix3 *matrix,
GimpTransformDirection direction)
{
GimpMatrix3 left = *matrix;
GimpMatrix3 right;
if (! gimp_text_layer_get_transformation (layer, &right))
return FALSE;
if (direction == GIMP_TRANSFORM_BACKWARD)
gimp_matrix3_invert (&left);
gimp_matrix3_mult (&left, &right);
return gimp_text_layer_set_transformation (layer, &right);
}
void
gimp_text_layer_transform (GimpItem *item,
GimpContext *context,
const GimpMatrix3 *matrix,
GimpTransformDirection direction,
GimpInterpolationType interpolation_type,
gboolean supersample,
GimpTransformResize clip_result,
GimpProgress *progress)
{
/* TODO */
GimpTextLayer *layer = GIMP_TEXT_LAYER (item);
if (gimp_text_layer_transform_matrix (layer, matrix, direction))
{
GimpLayerMask *mask = gimp_layer_get_mask (GIMP_LAYER (layer));
if (mask)
gimp_item_transform (GIMP_ITEM (mask), context,
matrix, direction, interpolation_type,
clip_result, progress);
}
else
{
gimp_text_layer_parent_class ()->transform (item, context,
matrix, direction,
interpolation_type,
clip_result, progress);
}
}
static GimpItemClass *
@@ -174,6 +255,11 @@ gimp_text_layer_get_transformation (GimpTextLayer *layer,
gimp_text_get_transformation (layer->text, matrix);
gimp_matrix3_translate (matrix,
gimp_item_get_offset_x (GIMP_ITEM (layer)),
gimp_item_get_offset_y (GIMP_ITEM (layer)));
return TRUE;
}
@@ -181,17 +267,36 @@ static gboolean
gimp_text_layer_set_transformation (GimpTextLayer *layer,
GimpMatrix3 *matrix)
{
GimpMatrix2 trafo;
GimpMatrix2 trafo;
gint x;
gint y;
gint unused;
if (! gimp_matrix3_is_affine (matrix))
return FALSE;
gimp_transform_resize_boundary (matrix,
GIMP_TRANSFORM_RESIZE_ADJUST,
0, 0, layer->layout_width,
layer->layout_height, &x, &y,
&unused, &unused);
gimp_item_translate (GIMP_ITEM (layer),
x - gimp_item_get_offset_x (GIMP_ITEM (layer)),
y - gimp_item_get_offset_y (GIMP_ITEM (layer)),
FALSE);
gimp_matrix3_translate (matrix,
- gimp_item_get_offset_x (GIMP_ITEM (layer)),
- gimp_item_get_offset_y (GIMP_ITEM (layer)));
trafo.coeff[0][0] = matrix->coeff[0][0];
trafo.coeff[0][1] = matrix->coeff[0][1];
trafo.coeff[1][0] = matrix->coeff[1][0];
trafo.coeff[1][1] = matrix->coeff[1][1];
gimp_text_layer_set (GIMP_TEXT_LAYER (layer), NULL,
gimp_text_layer_set (layer, NULL,
"transformation", &trafo,
"offset-x", matrix->coeff[0][2],
"offset-y", matrix->coeff[1][2],

View File

@@ -45,7 +45,6 @@ void gimp_text_layer_transform (GimpItem *item,
const GimpMatrix3 *matrix,
GimpTransformDirection direction,
GimpInterpolationType interpolation_type,
gboolean supersample,
GimpTransformResize clip_result,
GimpProgress *progress);

View File

@@ -30,6 +30,7 @@
#include "libgimpbase/gimpbase.h"
#include "libgimpcolor/gimpcolor.h"
#include "libgimpconfig/gimpconfig.h"
#include "libgimpmath/gimpmath.h"
#include "text-types.h"
@@ -38,6 +39,7 @@
#include "gegl/gimp-gegl-utils.h"
#include "core/gimp.h"
#include "core/gimp-transform-resize.h"
#include "core/gimp-utils.h"
#include "core/gimpcontainer.h"
#include "core/gimpcontext.h"
@@ -53,6 +55,7 @@
#include "gimptext.h"
#include "gimptextlayer.h"
#include "gimptextlayer-transform.h"
#include "gimptextlayout.h"
#include "gimptextlayout-render.h"
@@ -146,14 +149,10 @@ gimp_text_layer_class_init (GimpTextLayerClass *klass)
item_class->duplicate = gimp_text_layer_duplicate;
item_class->rename = gimp_text_layer_rename;
#if 0
item_class->scale = gimp_text_layer_scale;
item_class->flip = gimp_text_layer_flip;
item_class->rotate = gimp_text_layer_rotate;
item_class->transform = gimp_text_layer_transform;
#endif
item_class->default_name = _("Text Layer");
item_class->rename_desc = _("Rename Text Layer");
item_class->translate_desc = _("Move Text Layer");
@@ -690,6 +689,81 @@ gimp_text_layer_text_changed (GimpTextLayer *layer)
layer->private->base_dir = layer->text->base_dir;
}
static gboolean
gimp_text_layer_resize_buffer (GimpTextLayer *layer,
GimpTextLayout *layout)
{
GimpItem *item = GIMP_ITEM (layer);
GimpDrawable *drawable = GIMP_DRAWABLE (layer);
gint x;
gint y;
gint X;
gint Y;
gint width = 0;
gint height = 0;
if (gimp_text_layout_get_size (layout, &width, &height))
{
GimpMatrix3 matrix;
gimp_text_get_transformation (layer->text, &matrix);
gimp_transform_resize_boundary (&matrix, GIMP_TRANSFORM_RESIZE_ADJUST,
0, 0, width, height,
&x, &y, &X, &Y);
if (x != 0 || y != 0)
{
gimp_matrix3_translate (&matrix, -x, -y);
g_object_set (layer->text,
"offset-x", matrix.coeff[0][2],
"offset-y", matrix.coeff[1][2],
NULL);
}
if (x != 0 || y != 0 ||
! gimp_drawable_has_alpha (drawable) ||
(X - x) != gimp_item_get_width (item) ||
(Y - y) != gimp_item_get_height (item))
{
const gint new_x = x + gimp_item_get_offset_x (item);
const gint new_y = y + gimp_item_get_offset_y (item);
const gint new_width = X - x;
const gint new_height = Y - y;
GeglBuffer *new_buffer;
new_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, width, height),
gimp_text_layer_get_format (layer));
gimp_drawable_set_buffer (drawable, FALSE, NULL, new_buffer);
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)
{
GimpImage *image = gimp_item_get_image(item);
unused_eek = gimp_context_new (image->gimp,
"eek", NULL);
}
gimp_item_resize (GIMP_ITEM (mask), unused_eek,
GIMP_FILL_TRANSPARENT, new_width, new_height,
new_x, new_y);
}
}
layer->layout_width = width;
layer->layout_height = height;
}
return width > 0 && height > 0;
}
static gboolean
gimp_text_layer_render (GimpTextLayer *layer)
{
@@ -700,8 +774,7 @@ gimp_text_layer_render (GimpTextLayer *layer)
GimpTextLayout *layout;
gdouble xres;
gdouble yres;
gint width;
gint height;
gboolean result;
GError *error = NULL;
if (! layer->text)
@@ -733,33 +806,7 @@ gimp_text_layer_render (GimpTextLayer *layer)
g_object_freeze_notify (G_OBJECT (drawable));
if (gimp_text_layout_get_size (layout, &width, &height) &&
(width != gimp_item_get_width (item) ||
height != gimp_item_get_height (item) ||
gimp_text_layer_get_format (layer) !=
gimp_drawable_get_format (drawable)))
{
GeglBuffer *new_buffer;
new_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, width, height),
gimp_text_layer_get_format (layer));
gimp_drawable_set_buffer (drawable, FALSE, NULL, new_buffer);
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);
}
}
result = gimp_text_layer_resize_buffer (layer, layout);
if (layer->auto_rename)
{
@@ -795,14 +842,14 @@ gimp_text_layer_render (GimpTextLayer *layer)
}
}
if (width > 0 && height > 0)
if (result)
gimp_text_layer_render_layout (layer, layout);
g_object_unref (layout);
g_object_thaw_notify (G_OBJECT (drawable));
return (width > 0 && height > 0);
return result;
}
static void

View File

@@ -48,6 +48,8 @@ struct _GimpTextLayer
gboolean text_parasite_is_old; /* Format before XCF 19. */
gboolean auto_rename;
gboolean modified;
gint layout_width;
gint layout_height;
const Babl *convert_format;

View File

@@ -67,6 +67,7 @@ gimp_text_layout_render (GimpTextLayout *layout,
}
pango_layout = gimp_text_layout_get_pango_layout (layout);
pango_cairo_update_layout (cr, pango_layout);
if (path)
pango_cairo_layout_path (cr, pango_layout);

View File

@@ -394,8 +394,8 @@ gimp_text_layout_get_transform (GimpTextLayout *layout,
matrix->xy = text->transformation.coeff[0][1] * 1.0;
matrix->yx = text->transformation.coeff[1][0] * norm;
matrix->yy = text->transformation.coeff[1][1] * 1.0;
matrix->x0 = 0;
matrix->y0 = 0;
matrix->x0 = text->offset_x;
matrix->y0 = text->offset_y;
}
void

View File

@@ -650,53 +650,52 @@ gimp_text_tool_editor_get_cursor_rect (GimpTextTool *text_tool,
cursor_rect->width == 0)
pango_layout_get_cursor_pos (layout, cursor_index, cursor_rect, NULL);
}
else
pango_layout_get_cursor_pos (layout, cursor_index, cursor_rect, NULL);
else
pango_layout_get_cursor_pos (layout, cursor_index, cursor_rect, NULL);
switch (gimp_text_tool_get_direction (text_tool))
{
case GIMP_TEXT_DIRECTION_LTR:
case GIMP_TEXT_DIRECTION_RTL:
cursor_rect->x = PANGO_PIXELS (cursor_rect->x) + offset_x;
cursor_rect->y = PANGO_PIXELS (cursor_rect->y) + offset_y;
cursor_rect->width = PANGO_PIXELS (cursor_rect->width);
cursor_rect->height = PANGO_PIXELS (cursor_rect->height);
break;
case GIMP_TEXT_DIRECTION_TTB_RTL:
case GIMP_TEXT_DIRECTION_TTB_RTL_UPRIGHT:
{
gint temp, width, height;
gimp_text_layout_get_size (text_tool->layout, &width, &height);
temp = cursor_rect->x;
cursor_rect->x = width - PANGO_PIXELS (cursor_rect->y) + offset_x;
cursor_rect->y = PANGO_PIXELS (temp) + offset_y;
temp = cursor_rect->width;
cursor_rect->width = PANGO_PIXELS (cursor_rect->height);
cursor_rect->height = PANGO_PIXELS (temp);
}
break;
case GIMP_TEXT_DIRECTION_TTB_LTR:
case GIMP_TEXT_DIRECTION_TTB_LTR_UPRIGHT:
{
gint temp, width, height;
gimp_text_layout_get_size (text_tool->layout, &width, &height);
temp = cursor_rect->x;
cursor_rect->x = PANGO_PIXELS (cursor_rect->y) + offset_x;
cursor_rect->y = height - PANGO_PIXELS (temp) + offset_y;
temp = cursor_rect->width;
cursor_rect->width = PANGO_PIXELS (cursor_rect->height);
cursor_rect->height = PANGO_PIXELS (temp);
}
break;
}
gimp_text_layout_transform_rect (text_tool->layout, cursor_rect);
switch (gimp_text_tool_get_direction (text_tool))
{
case GIMP_TEXT_DIRECTION_LTR:
case GIMP_TEXT_DIRECTION_RTL:
cursor_rect->x = PANGO_PIXELS (cursor_rect->x) + offset_x;
cursor_rect->y = PANGO_PIXELS (cursor_rect->y) + offset_y;
cursor_rect->width = PANGO_PIXELS (cursor_rect->width);
cursor_rect->height = PANGO_PIXELS (cursor_rect->height);
break;
case GIMP_TEXT_DIRECTION_TTB_RTL:
case GIMP_TEXT_DIRECTION_TTB_RTL_UPRIGHT:
{
gint temp, width, height;
gimp_text_layout_get_size (text_tool->layout, &width, &height);
temp = cursor_rect->x;
cursor_rect->x = width - PANGO_PIXELS (cursor_rect->y) + offset_x;
cursor_rect->y = PANGO_PIXELS (temp) + offset_y;
temp = cursor_rect->width;
cursor_rect->width = PANGO_PIXELS (cursor_rect->height);
cursor_rect->height = PANGO_PIXELS (temp);
}
break;
case GIMP_TEXT_DIRECTION_TTB_LTR:
case GIMP_TEXT_DIRECTION_TTB_LTR_UPRIGHT:
{
gint temp, width, height;
gimp_text_layout_get_size (text_tool->layout, &width, &height);
temp = cursor_rect->x;
cursor_rect->x = PANGO_PIXELS (cursor_rect->y) + offset_x;
cursor_rect->y = height - PANGO_PIXELS (temp) + offset_y;
temp = cursor_rect->width;
cursor_rect->width = PANGO_PIXELS (cursor_rect->height);
cursor_rect->height = PANGO_PIXELS (temp);
}
break;
}
}
void

View File

@@ -39,6 +39,8 @@
#include "core/gimpprogress.h"
#include "core/gimp-transform-resize.h"
#include "text/gimptextlayer.h"
#include "vectors/gimppath.h"
#include "display/gimpdisplay.h"
@@ -856,7 +858,8 @@ gimp_transform_tool_transform (GimpTransformTool *tr_tool,
switch (options->type)
{
case GIMP_TRANSFORM_TYPE_LAYER:
if (! gimp_channel_is_empty (gimp_image_get_mask (image)))
if (! GIMP_IS_TEXT_LAYER (selected_objects->data) &&
! gimp_channel_is_empty (gimp_image_get_mask (image)))
{
orig_buffer = gimp_drawable_transform_cut (
selected_objects,

View File

@@ -65,6 +65,7 @@ $assemble_matrix
if (GIMP_IS_DRAWABLE (item) &&
item != GIMP_ITEM (mask) &&
! GIMP_IS_TEXT_LAYER (item) &&
! gimp_viewable_get_children (GIMP_VIEWABLE (item)) &&
! gimp_channel_is_empty (mask))
{
@@ -213,6 +214,7 @@ HELP
if (GIMP_IS_DRAWABLE (item) &&
item != GIMP_ITEM (mask) &&
! GIMP_IS_TEXT_LAYER (item) &&
! gimp_viewable_get_children (GIMP_VIEWABLE (item)) &&
! gimp_channel_is_empty (mask))
{
@@ -451,6 +453,7 @@ HELP
if (GIMP_IS_DRAWABLE (item) &&
item != GIMP_ITEM (mask) &&
! GIMP_IS_TEXT_LAYER (item) &&
! gimp_viewable_get_children (GIMP_VIEWABLE (item)) &&
! gimp_channel_is_empty (mask))
{
@@ -808,6 +811,7 @@ CODE
"core/gimpdrawable-transform.h"
"core/gimpimage.h"
"core/gimpprogress.h"
"text/gimptextlayer.h"
"gimppdb-utils.h"
"gimppdbcontext.h"
"gimp-intl.h");