|
Packit |
bc1512 |
/* This file is an image processing operation for GEGL
|
|
Packit |
bc1512 |
*
|
|
Packit |
bc1512 |
* GEGL is free software; you can redistribute it and/or
|
|
Packit |
bc1512 |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit |
bc1512 |
* License as published by the Free Software Foundation; either
|
|
Packit |
bc1512 |
* version 3 of the License, or (at your option) any later version.
|
|
Packit |
bc1512 |
*
|
|
Packit |
bc1512 |
* GEGL is distributed in the hope that it will be useful,
|
|
Packit |
bc1512 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
bc1512 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
bc1512 |
* Lesser General Public License for more details.
|
|
Packit |
bc1512 |
*
|
|
Packit |
bc1512 |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit |
bc1512 |
* License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
bc1512 |
*
|
|
Packit |
bc1512 |
* Copyright 2006 Øyvind Kolås <pippin@gimp.org>
|
|
Packit |
bc1512 |
*/
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#include "config.h"
|
|
Packit |
bc1512 |
#include <glib/gi18n-lib.h>
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#ifdef GEGL_CHANT_PROPERTIES
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
gegl_chant_multiline (string, _("Text"), "Hello",
|
|
Packit |
bc1512 |
_("String to display (utf8)"))
|
|
Packit |
bc1512 |
gegl_chant_string (font, _("Font family"), "Sans",
|
|
Packit |
bc1512 |
_("Font family (utf8)"))
|
|
Packit |
bc1512 |
gegl_chant_double (size, _("Size"), 1.0, 2048.0, 10.0,
|
|
Packit |
bc1512 |
_("Approximate height of text in pixels."))
|
|
Packit |
bc1512 |
gegl_chant_color (color, _("Color"), "black",
|
|
Packit |
bc1512 |
_("Color for the text (defaults to 'white')"))
|
|
Packit |
bc1512 |
gegl_chant_int (wrap, _("Wrap width"), -1, 1000000, -1,
|
|
Packit |
bc1512 |
_("Sets the width in pixels at which long lines will wrap. "
|
|
Packit |
bc1512 |
"Use -1 for no wrapping."))
|
|
Packit |
bc1512 |
gegl_chant_int (alignment, _("Justification"), 0, 2, 0,
|
|
Packit |
bc1512 |
_("Alignment for multi-line text (0=Left, 1=Center, 2=Right)"))
|
|
Packit |
bc1512 |
gegl_chant_int (width, _("Width"), 0, 1000000, 0,
|
|
Packit |
bc1512 |
_("Rendered width in pixels. (read only)"))
|
|
Packit |
bc1512 |
gegl_chant_int (height, _("Height"), 0, 1000000, 0,
|
|
Packit |
bc1512 |
_("Rendered height in pixels. (read only)"))
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#else
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#include <gegl-plugin.h>
|
|
Packit |
bc1512 |
#include <cairo.h>
|
|
Packit |
bc1512 |
#include <pango/pango-attributes.h>
|
|
Packit |
bc1512 |
#include <pango/pangocairo.h>
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/* XXX: this struct is unneeded and could be folded directly into
|
|
Packit |
bc1512 |
* struct _GeglChant
|
|
Packit |
bc1512 |
*/
|
|
Packit |
bc1512 |
typedef struct {
|
|
Packit |
bc1512 |
gchar *string;
|
|
Packit |
bc1512 |
gchar *font;
|
|
Packit |
bc1512 |
gdouble size;
|
|
Packit |
bc1512 |
gint wrap;
|
|
Packit |
bc1512 |
gint alignment;
|
|
Packit |
bc1512 |
GeglRectangle defined;
|
|
Packit |
bc1512 |
} CachedExtent;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
struct _GeglChant
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
GeglOperationSource parent_instance;
|
|
Packit |
bc1512 |
gpointer properties;
|
|
Packit |
bc1512 |
CachedExtent cex;
|
|
Packit |
bc1512 |
};
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
typedef struct
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
GeglOperationSourceClass parent_class;
|
|
Packit |
bc1512 |
} GeglChantClass;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#define GEGL_CHANT_C_FILE "text.c"
|
|
Packit |
bc1512 |
#include "gegl-chant.h"
|
|
Packit |
bc1512 |
GEGL_DEFINE_DYNAMIC_OPERATION (GEGL_TYPE_OPERATION_SOURCE)
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
static void text_layout_text (GeglChant *self,
|
|
Packit |
bc1512 |
cairo_t *cr,
|
|
Packit |
bc1512 |
gdouble rowstride,
|
|
Packit |
bc1512 |
gdouble *width,
|
|
Packit |
bc1512 |
gdouble *height)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
GeglChantO *o = GEGL_CHANT_PROPERTIES (self);
|
|
Packit |
bc1512 |
PangoFontDescription *desc;
|
|
Packit |
bc1512 |
PangoLayout *layout;
|
|
Packit |
bc1512 |
PangoAttrList *attrs;
|
|
Packit |
bc1512 |
PangoAttribute *attr = NULL;
|
|
Packit |
bc1512 |
gchar *string;
|
|
Packit |
bc1512 |
gfloat color[4];
|
|
Packit |
bc1512 |
gint alignment = 0;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/* Create a PangoLayout, set the font and text */
|
|
Packit |
bc1512 |
layout = pango_cairo_create_layout (cr);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
string = g_strcompress (o->string);
|
|
Packit |
bc1512 |
pango_layout_set_text (layout, string, -1);
|
|
Packit |
bc1512 |
g_free (string);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
desc = pango_font_description_from_string (o->font);
|
|
Packit |
bc1512 |
pango_font_description_set_absolute_size (desc, o->size * PANGO_SCALE);
|
|
Packit |
bc1512 |
pango_layout_set_font_description (layout, desc);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
switch (o->alignment)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
case 0:
|
|
Packit |
bc1512 |
alignment = PANGO_ALIGN_LEFT;
|
|
Packit |
bc1512 |
break;
|
|
Packit |
bc1512 |
case 1:
|
|
Packit |
bc1512 |
alignment = PANGO_ALIGN_CENTER;
|
|
Packit |
bc1512 |
break;
|
|
Packit |
bc1512 |
case 2:
|
|
Packit |
bc1512 |
alignment = PANGO_ALIGN_RIGHT;
|
|
Packit |
bc1512 |
break;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
pango_layout_set_alignment (layout, alignment);
|
|
Packit |
bc1512 |
pango_layout_set_width (layout, o->wrap * PANGO_SCALE);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
attrs = pango_attr_list_new ();
|
|
Packit |
bc1512 |
if (attrs)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
gegl_color_get_pixel (o->color, babl_format ("RGBA float"), color);
|
|
Packit |
bc1512 |
attr = pango_attr_foreground_new ((guint16) (color[0] * 65535),
|
|
Packit |
bc1512 |
(guint16) (color[1] * 65535),
|
|
Packit |
bc1512 |
(guint16) (color[2] * 65535));
|
|
Packit |
bc1512 |
if (attr)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
attr->start_index = 0;
|
|
Packit |
bc1512 |
attr->end_index = -1;
|
|
Packit |
bc1512 |
pango_attr_list_insert (attrs, attr);
|
|
Packit |
bc1512 |
pango_layout_set_attributes (layout, attrs);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/* Inform Pango to re-layout the text with the new transformation */
|
|
Packit |
bc1512 |
pango_cairo_update_layout (cr, layout);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (width && height)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
int w, h;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
pango_layout_get_pixel_size (layout, &w, &h);
|
|
Packit |
bc1512 |
*width = (gdouble)w;
|
|
Packit |
bc1512 |
*height = (gdouble)h;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
else
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
/* FIXME: This feels like a hack but it stops the rendered text */
|
|
Packit |
bc1512 |
/* from shifting position depending on the value of 'alignment'. */
|
|
Packit |
bc1512 |
if (o->alignment == 1)
|
|
Packit |
bc1512 |
cairo_move_to (cr, o->width / 2, 0);
|
|
Packit |
bc1512 |
else
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
if (o->alignment == 2)
|
|
Packit |
bc1512 |
cairo_move_to (cr, o->width, 0);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
pango_cairo_show_layout (cr, layout);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
pango_font_description_free (desc);
|
|
Packit |
bc1512 |
pango_attr_list_unref (attrs);
|
|
Packit |
bc1512 |
g_object_unref (layout);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
static gboolean
|
|
Packit |
bc1512 |
process (GeglOperation *operation,
|
|
Packit |
bc1512 |
GeglBuffer *output,
|
|
Packit |
bc1512 |
const GeglRectangle *result,
|
|
Packit |
bc1512 |
gint level)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
GeglChant *self = GEGL_CHANT (operation);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
guchar *data = g_new0 (guchar, result->width * result->height * 4);
|
|
Packit |
bc1512 |
cairo_t *cr;
|
|
Packit |
bc1512 |
cairo_surface_t *surface;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
surface = cairo_image_surface_create_for_data (data,
|
|
Packit |
bc1512 |
CAIRO_FORMAT_ARGB32,
|
|
Packit |
bc1512 |
result->width,
|
|
Packit |
bc1512 |
result->height,
|
|
Packit |
bc1512 |
result->width * 4);
|
|
Packit |
bc1512 |
cr = cairo_create (surface);
|
|
Packit |
bc1512 |
cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 1.0);
|
|
Packit |
bc1512 |
cairo_translate (cr, -result->x, -result->y);
|
|
Packit |
bc1512 |
text_layout_text (self, cr, 0, NULL, NULL);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
gegl_buffer_set (output, result, 0, babl_format ("B'aG'aR'aA u8"), data,
|
|
Packit |
bc1512 |
GEGL_AUTO_ROWSTRIDE);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
cairo_destroy (cr);
|
|
Packit |
bc1512 |
cairo_surface_destroy (surface);
|
|
Packit |
bc1512 |
g_free (data);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
return TRUE;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
static GeglRectangle
|
|
Packit |
bc1512 |
get_bounding_box (GeglOperation *operation)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
GeglChant *self = GEGL_CHANT (operation);
|
|
Packit |
bc1512 |
GeglChantO *o = GEGL_CHANT_PROPERTIES (self);
|
|
Packit |
bc1512 |
CachedExtent *extent;
|
|
Packit |
bc1512 |
gint status = FALSE;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
extent = (CachedExtent*)&self->cex;
|
|
Packit |
bc1512 |
/*if (!self->priv)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
self->priv = g_malloc0 (sizeof (CachedExtent));
|
|
Packit |
bc1512 |
extent = (CachedExtent*)self->priv;
|
|
Packit |
bc1512 |
extent->string = g_strdup ("");
|
|
Packit |
bc1512 |
extent->font = g_strdup ("");
|
|
Packit |
bc1512 |
}*/
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if ((extent->string && strcmp (extent->string, o->string)) ||
|
|
Packit |
bc1512 |
(extent->font && strcmp (extent->font, o->font)) ||
|
|
Packit |
bc1512 |
extent->size != o->size ||
|
|
Packit |
bc1512 |
extent->wrap != o->wrap ||
|
|
Packit |
bc1512 |
extent->alignment != o->alignment)
|
|
Packit |
bc1512 |
{ /* get extents */
|
|
Packit |
bc1512 |
cairo_t *cr;
|
|
Packit |
bc1512 |
gdouble width, height;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
|
|
Packit |
bc1512 |
1, 1);
|
|
Packit |
bc1512 |
cr = cairo_create (surface);
|
|
Packit |
bc1512 |
text_layout_text (self, cr, 0, &width, &height);
|
|
Packit |
bc1512 |
cairo_destroy (cr);
|
|
Packit |
bc1512 |
cairo_surface_destroy (surface);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
extent->defined.width = width;
|
|
Packit |
bc1512 |
extent->defined.height = height;
|
|
Packit |
bc1512 |
if (extent->string)
|
|
Packit |
bc1512 |
g_free (extent->string);
|
|
Packit |
bc1512 |
extent->string = g_strdup (o->string);
|
|
Packit |
bc1512 |
if (extent->font)
|
|
Packit |
bc1512 |
g_free (extent->font);
|
|
Packit |
bc1512 |
extent->font = g_strdup (o->font);
|
|
Packit |
bc1512 |
extent->size = o->size;
|
|
Packit |
bc1512 |
extent->wrap = o->wrap;
|
|
Packit |
bc1512 |
extent->alignment = o->alignment;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
/* store the measured size for later use */
|
|
Packit |
bc1512 |
o->width = width;
|
|
Packit |
bc1512 |
o->height = height;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
gegl_operation_invalidate (operation, NULL, TRUE);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (status)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
g_warning ("get defined region for text '%s' failed", o->string);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
return extent->defined;
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
static void
|
|
Packit |
bc1512 |
finalize (GObject *object)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
GeglChant *self = GEGL_CHANT (object);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
if (self->cex.string)
|
|
Packit |
bc1512 |
g_free (self->cex.string);
|
|
Packit |
bc1512 |
if (self->cex.font)
|
|
Packit |
bc1512 |
g_free (self->cex.font);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
G_OBJECT_CLASS (gegl_chant_parent_class)->finalize (object);
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
static void
|
|
Packit |
bc1512 |
prepare (GeglOperation *operation)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
gegl_operation_set_format (operation, "output", babl_format ("RaGaBaA float"));
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
static void
|
|
Packit |
bc1512 |
gegl_chant_class_init (GeglChantClass *klass)
|
|
Packit |
bc1512 |
{
|
|
Packit |
bc1512 |
GObjectClass *object_class;
|
|
Packit |
bc1512 |
GeglOperationClass *operation_class;
|
|
Packit |
bc1512 |
GeglOperationSourceClass *operation_source_class;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
object_class = G_OBJECT_CLASS (klass);
|
|
Packit |
bc1512 |
operation_class = GEGL_OPERATION_CLASS (klass);
|
|
Packit |
bc1512 |
operation_source_class = GEGL_OPERATION_SOURCE_CLASS (klass);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
object_class->finalize = finalize;
|
|
Packit |
bc1512 |
operation_class->prepare = prepare;
|
|
Packit |
bc1512 |
operation_class->get_bounding_box = get_bounding_box;
|
|
Packit |
bc1512 |
operation_source_class->process = process;
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
gegl_operation_class_set_keys (operation_class,
|
|
Packit |
bc1512 |
"name" , "gegl:text",
|
|
Packit |
bc1512 |
"categories" , "render",
|
|
Packit |
bc1512 |
"description" , _("Display a string of text using pango and cairo."),
|
|
Packit |
bc1512 |
NULL);
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
}
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
|
|
Packit |
bc1512 |
#endif
|