Skip to content

Commit f53959b

Browse files
committed
switch font rendering to pangocairo
to make colour font rendering work
1 parent 8412b82 commit f53959b

File tree

4 files changed

+67
-60
lines changed

4 files changed

+67
-60
lines changed

ChangeLog

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
- add vips_image_[set|get]_array_double()
2323
- add GIF load with libnsgif
2424
- add JPEG2000 load and save
25+
- add "rgba" flag to vips_text() to enable full colour text rendering
2526

2627
22/12/20 start 8.10.6
2728
- don't seek on bad file descriptors [kleisauke]

configure.ac

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1083,25 +1083,25 @@ fi
10831083
VIPS_CFLAGS="$VIPS_CFLAGS $LIBWEBP_CFLAGS"
10841084
VIPS_LIBS="$VIPS_LIBS $LIBWEBP_LIBS"
10851085

1086-
# pangoft2
1087-
AC_ARG_WITH([pangoft2],
1088-
AS_HELP_STRING([--without-pangoft2],
1089-
[build without pangoft2 (default: test)]))
1090-
1091-
if test x"$with_pangoft2" != x"no"; then
1092-
PKG_CHECK_MODULES(PANGOFT2, pangoft2,
1093-
[AC_DEFINE(HAVE_PANGOFT2,1,[define if you have pangoft2 installed.])
1094-
with_pangoft2=yes
1095-
PACKAGES_USED="$PACKAGES_USED pangoft2"
1086+
# pangocairo for text rendering
1087+
AC_ARG_WITH([pangocairo],
1088+
AS_HELP_STRING([--without-pangocairo],
1089+
[build without pangocairo (default: test)]))
1090+
1091+
if test x"$with_pangocairo" != x"no"; then
1092+
PKG_CHECK_MODULES(PANGOCAIRO, pangocairo,
1093+
[AC_DEFINE(HAVE_PANGOCAIRO,1,[define if you have pangocairo installed.])
1094+
with_pangocairo=yes
1095+
PACKAGES_USED="$PACKAGES_USED pangocairo"
10961096
],
1097-
[AC_MSG_WARN([pangoft2 not found; disabling pangoft2 support])
1098-
with_pangoft2=no
1097+
[AC_MSG_WARN([pangocairo not found; disabling pangocairo support])
1098+
with_pangocairo=no
10991099
]
11001100
)
11011101
fi
11021102

1103-
VIPS_CFLAGS="$VIPS_CFLAGS $PANGOFT2_CFLAGS"
1104-
VIPS_LIBS="$VIPS_LIBS $PANGOFT2_LIBS"
1103+
VIPS_CFLAGS="$VIPS_CFLAGS $PANGOCAIRO_CFLAGS"
1104+
VIPS_LIBS="$VIPS_LIBS $PANGOCAIRO_LIBS"
11051105

11061106
# look for TIFF with pkg-config ... fall back to our tester
11071107
# pkgconfig support for libtiff starts with libtiff-4
@@ -1325,7 +1325,7 @@ use fftw3 for FFT: $with_fftw, \
13251325
accelerate loops with orc: $with_orc, \
13261326
ICC profile support with lcms: $with_lcms, \
13271327
zlib: $with_zlib, \
1328-
text rendering with pangoft2: $with_pangoft2, \
1328+
text rendering with pangocairo: $with_pangocairo, \
13291329
EXIF metadata support with libexif: $with_libexif, \
13301330
JPEG load/save with libjpeg: $with_jpeg, \
13311331
PNG load with libspng: $with_libspng, \
@@ -1427,7 +1427,7 @@ accelerate loops with orc: $with_orc
14271427
(requires orc-0.4.11 or later)
14281428
ICC profile support with lcms: $with_lcms
14291429
zlib: $with_zlib
1430-
text rendering with pangoft2: $with_pangoft2
1430+
text rendering with pangocairo: $with_pangocairo
14311431
EXIF metadata support with libexif: $with_libexif
14321432
14331433
## File format support

libvips/create/create.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,9 @@ vips_create_operation_init( void )
116116
extern GType vips_gaussmat_get_type( void );
117117
extern GType vips_logmat_get_type( void );
118118
extern GType vips_gaussnoise_get_type( void );
119-
#ifdef HAVE_PANGOFT2
119+
#ifdef HAVE_PANGOCAIRO
120120
extern GType vips_text_get_type( void );
121-
#endif /*HAVE_PANGOFT2*/
121+
#endif /*HAVE_PANGOCAIRO*/
122122
extern GType vips_xyz_get_type( void );
123123
extern GType vips_eye_get_type( void );
124124
extern GType vips_grey_get_type( void );
@@ -146,9 +146,9 @@ vips_create_operation_init( void )
146146
vips_gaussmat_get_type();
147147
vips_logmat_get_type();
148148
vips_gaussnoise_get_type();
149-
#ifdef HAVE_PANGOFT2
149+
#ifdef HAVE_PANGOCAIRO
150150
vips_text_get_type();
151-
#endif /*HAVE_PANGOFT2*/
151+
#endif /*HAVE_PANGOCAIRO*/
152152
vips_xyz_get_type();
153153
vips_eye_get_type();
154154
vips_grey_get_type();

libvips/create/text.c

Lines changed: 46 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232
* - fitting could occasionally terminate early [levmorozov]
3333
* 16/5/20 [keiviv]
3434
* - don't add fontfiles repeatedly
35+
* 12/4/21
36+
* - switch to cairo for text rendering
37+
* - add rgba flag
3538
*/
3639

3740
/*
@@ -74,11 +77,13 @@
7477
#include <string.h>
7578

7679
#include <vips/vips.h>
80+
#include <vips/internal.h>
7781

78-
#ifdef HAVE_PANGOFT2
82+
#ifdef HAVE_PANGOCAIRO
7983

84+
#include <cairo.h>
8085
#include <pango/pango.h>
81-
#include <pango/pangoft2.h>
86+
#include <pango/pangocairo.h>
8287

8388
#include "pcreate.h"
8489

@@ -96,7 +101,6 @@ typedef struct _VipsText {
96101
char *fontfile;
97102
gboolean rgba;
98103

99-
FT_Bitmap bitmap;
100104
PangoContext *context;
101105
PangoLayout *layout;
102106

@@ -130,7 +134,6 @@ vips_text_dispose( GObject *gobject )
130134

131135
VIPS_UNREF( text->layout );
132136
VIPS_UNREF( text->context );
133-
VIPS_FREE( text->bitmap.buffer );
134137

135138
G_OBJECT_CLASS( vips_text_parent_class )->dispose( gobject );
136139
}
@@ -187,8 +190,8 @@ vips_text_get_extents( VipsText *text, VipsRect *extents )
187190
PangoRectangle ink_rect;
188191
PangoRectangle logical_rect;
189192

190-
pango_ft2_font_map_set_resolution(
191-
PANGO_FT2_FONT_MAP( vips_text_fontmap ), text->dpi, text->dpi );
193+
pango_cairo_font_map_set_resolution(
194+
PANGO_CAIRO_FONT_MAP( vips_text_fontmap ), text->dpi );
192195

193196
VIPS_UNREF( text->layout );
194197
if( !(text->layout = text_layout_new( text->context,
@@ -345,8 +348,8 @@ vips_text_build( VipsObject *object )
345348
VipsRect extents;
346349
int bands;
347350
VipsInterpretation interpretation;
348-
FT_Pixel_Mode pixel_mode;
349-
int y;
351+
cairo_surface_t *surface;
352+
cairo_t *cr;
350353

351354
if( VIPS_OBJECT_CLASS( vips_text_parent_class )->build( object ) )
352355
return( -1 );
@@ -360,14 +363,15 @@ vips_text_build( VipsObject *object )
360363
g_mutex_lock( vips_text_lock );
361364

362365
if( !vips_text_fontmap )
363-
vips_text_fontmap = pango_ft2_font_map_new();
366+
vips_text_fontmap = pango_cairo_font_map_new();
364367
if( !vips_text_fontfiles )
365368
vips_text_fontfiles =
366369
g_hash_table_new( g_str_hash, g_str_equal );
367370

368371
text->context = pango_font_map_create_context(
369372
PANGO_FONT_MAP( vips_text_fontmap ) );
370373

374+
/*
371375
if( text->fontfile &&
372376
!g_hash_table_lookup( vips_text_fontfiles, text->fontfile ) ) {
373377
if( !FcConfigAppFontAddFile( NULL,
@@ -382,6 +386,7 @@ vips_text_build( VipsObject *object )
382386
text->fontfile,
383387
g_strdup( text->fontfile ) );
384388
}
389+
*/
385390

386391
/* If our caller set height and not dpi, we adjust dpi until
387392
* we get a fit.
@@ -406,55 +411,57 @@ vips_text_build( VipsObject *object )
406411
if( text->rgba ) {
407412
interpretation = VIPS_INTERPRETATION_sRGB;
408413
bands = 4;
409-
pixel_mode = FT_PIXEL_MODE_BGRA;
410414
}
411415
else {
412416
interpretation = VIPS_INTERPRETATION_MULTIBAND;
413417
bands = 1;
414-
pixel_mode = FT_PIXEL_MODE_GRAY;
415-
}
416-
417-
text->bitmap.width = extents.width;
418-
text->bitmap.pitch = (bands * text->bitmap.width + 3) & ~3;
419-
text->bitmap.rows = extents.height;
420-
if( !(text->bitmap.buffer =
421-
VIPS_ARRAY( NULL,
422-
text->bitmap.pitch * text->bitmap.rows, VipsPel )) ) {
423-
g_mutex_unlock( vips_text_lock );
424-
return( -1 );
425418
}
426-
text->bitmap.num_grays = 256;
427-
text->bitmap.pixel_mode = pixel_mode;
428-
memset( text->bitmap.buffer, 0x00,
429-
text->bitmap.pitch * text->bitmap.rows );
430-
431-
pango_ft2_render_layout( &text->bitmap, text->layout,
432-
-extents.left, -extents.top );
433419

434420
/* Set DPI as pixels/mm.
435421
*/
436422
vips_image_init_fields( create->out,
437-
text->bitmap.width, text->bitmap.rows, bands,
423+
extents.width, extents.height, bands,
438424
VIPS_FORMAT_UCHAR, VIPS_CODING_NONE,
439425
interpretation, text->dpi / 25.4, text->dpi / 25.4 );
440426

441-
g_mutex_unlock( vips_text_lock );
442-
443427
vips_image_pipelinev( create->out, VIPS_DEMAND_STYLE_ANY, NULL );
444428
create->out->Xoffset = extents.left;
445429
create->out->Yoffset = extents.top;
446430

431+
if( vips_image_write_prepare( create->out ) ) {
432+
g_mutex_unlock( vips_text_lock );
433+
return( -1 );
434+
}
435+
436+
surface = cairo_image_surface_create_for_data(
437+
VIPS_IMAGE_ADDR( create->out, 0, 0 ),
438+
text->rgba ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_A8,
439+
create->out->Xsize, create->out->Ysize,
440+
VIPS_IMAGE_SIZEOF_LINE( create->out ) );
441+
cr = cairo_create( surface );
442+
cairo_surface_destroy( surface );
443+
444+
cairo_translate( cr, -extents.left, -extents.top );
445+
446+
pango_cairo_show_layout( cr, text->layout );
447+
448+
cairo_destroy( cr );
449+
450+
g_mutex_unlock( vips_text_lock );
451+
447452
if( text->rgba ) {
448-
/* Convert premultiplied BGRA to RGBA.
453+
int y;
454+
455+
/* Cairo makes pre-multipled BRGA -- we must byteswap and
456+
* unpremultiply.
449457
*/
458+
for( y = 0; y < create->out->Ysize; y++ )
459+
vips__premultiplied_bgra2rgba(
460+
(guint32 *)
461+
VIPS_IMAGE_ADDR( create->out, 0, y ),
462+
create->out->Xsize );
450463
}
451464

452-
for( y = 0; y < text->bitmap.rows; y++ )
453-
if( vips_image_write_line( create->out, y,
454-
(VipsPel *) text->bitmap.buffer +
455-
y * text->bitmap.pitch ) )
456-
return( -1 );
457-
458465
return( 0 );
459466
}
460467

@@ -569,11 +576,10 @@ vips_text_init( VipsText *text )
569576
{
570577
text->align = VIPS_ALIGN_LOW;
571578
text->dpi = 72;
572-
text->bitmap.buffer = NULL;
573579
VIPS_SETSTR( text->font, "sans 12" );
574580
}
575581

576-
#endif /*HAVE_PANGOFT2*/
582+
#endif /*HAVE_PANGOCAIRO*/
577583

578584
/**
579585
* vips_text:

0 commit comments

Comments
 (0)