32
32
* - fitting could occasionally terminate early [levmorozov]
33
33
* 16/5/20 [keiviv]
34
34
* - don't add fontfiles repeatedly
35
+ * 12/4/21
36
+ * - switch to cairo for text rendering
37
+ * - add rgba flag
35
38
*/
36
39
37
40
/*
74
77
#include <string.h>
75
78
76
79
#include <vips/vips.h>
80
+ #include <vips/internal.h>
77
81
78
- #ifdef HAVE_PANGOFT2
82
+ #ifdef HAVE_PANGOCAIRO
79
83
84
+ #include <cairo.h>
80
85
#include <pango/pango.h>
81
- #include <pango/pangoft2 .h>
86
+ #include <pango/pangocairo .h>
82
87
83
88
#include "pcreate.h"
84
89
@@ -96,7 +101,6 @@ typedef struct _VipsText {
96
101
char * fontfile ;
97
102
gboolean rgba ;
98
103
99
- FT_Bitmap bitmap ;
100
104
PangoContext * context ;
101
105
PangoLayout * layout ;
102
106
@@ -130,7 +134,6 @@ vips_text_dispose( GObject *gobject )
130
134
131
135
VIPS_UNREF ( text -> layout );
132
136
VIPS_UNREF ( text -> context );
133
- VIPS_FREE ( text -> bitmap .buffer );
134
137
135
138
G_OBJECT_CLASS ( vips_text_parent_class )-> dispose ( gobject );
136
139
}
@@ -187,8 +190,8 @@ vips_text_get_extents( VipsText *text, VipsRect *extents )
187
190
PangoRectangle ink_rect ;
188
191
PangoRectangle logical_rect ;
189
192
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 );
192
195
193
196
VIPS_UNREF ( text -> layout );
194
197
if ( !(text -> layout = text_layout_new ( text -> context ,
@@ -345,8 +348,8 @@ vips_text_build( VipsObject *object )
345
348
VipsRect extents ;
346
349
int bands ;
347
350
VipsInterpretation interpretation ;
348
- FT_Pixel_Mode pixel_mode ;
349
- int y ;
351
+ cairo_surface_t * surface ;
352
+ cairo_t * cr ;
350
353
351
354
if ( VIPS_OBJECT_CLASS ( vips_text_parent_class )-> build ( object ) )
352
355
return ( -1 );
@@ -360,14 +363,15 @@ vips_text_build( VipsObject *object )
360
363
g_mutex_lock ( vips_text_lock );
361
364
362
365
if ( !vips_text_fontmap )
363
- vips_text_fontmap = pango_ft2_font_map_new ();
366
+ vips_text_fontmap = pango_cairo_font_map_new ();
364
367
if ( !vips_text_fontfiles )
365
368
vips_text_fontfiles =
366
369
g_hash_table_new ( g_str_hash , g_str_equal );
367
370
368
371
text -> context = pango_font_map_create_context (
369
372
PANGO_FONT_MAP ( vips_text_fontmap ) );
370
373
374
+ /*
371
375
if( text->fontfile &&
372
376
!g_hash_table_lookup( vips_text_fontfiles, text->fontfile ) ) {
373
377
if( !FcConfigAppFontAddFile( NULL,
@@ -382,6 +386,7 @@ vips_text_build( VipsObject *object )
382
386
text->fontfile,
383
387
g_strdup( text->fontfile ) );
384
388
}
389
+ */
385
390
386
391
/* If our caller set height and not dpi, we adjust dpi until
387
392
* we get a fit.
@@ -406,55 +411,57 @@ vips_text_build( VipsObject *object )
406
411
if ( text -> rgba ) {
407
412
interpretation = VIPS_INTERPRETATION_sRGB ;
408
413
bands = 4 ;
409
- pixel_mode = FT_PIXEL_MODE_BGRA ;
410
414
}
411
415
else {
412
416
interpretation = VIPS_INTERPRETATION_MULTIBAND ;
413
417
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 );
425
418
}
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 );
433
419
434
420
/* Set DPI as pixels/mm.
435
421
*/
436
422
vips_image_init_fields ( create -> out ,
437
- text -> bitmap .width , text -> bitmap . rows , bands ,
423
+ extents .width , extents . height , bands ,
438
424
VIPS_FORMAT_UCHAR , VIPS_CODING_NONE ,
439
425
interpretation , text -> dpi / 25.4 , text -> dpi / 25.4 );
440
426
441
- g_mutex_unlock ( vips_text_lock );
442
-
443
427
vips_image_pipelinev ( create -> out , VIPS_DEMAND_STYLE_ANY , NULL );
444
428
create -> out -> Xoffset = extents .left ;
445
429
create -> out -> Yoffset = extents .top ;
446
430
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
+
447
452
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.
449
457
*/
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 );
450
463
}
451
464
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
-
458
465
return ( 0 );
459
466
}
460
467
@@ -569,11 +576,10 @@ vips_text_init( VipsText *text )
569
576
{
570
577
text -> align = VIPS_ALIGN_LOW ;
571
578
text -> dpi = 72 ;
572
- text -> bitmap .buffer = NULL ;
573
579
VIPS_SETSTR ( text -> font , "sans 12" );
574
580
}
575
581
576
- #endif /*HAVE_PANGOFT2 */
582
+ #endif /*HAVE_PANGOCAIRO */
577
583
578
584
/**
579
585
* vips_text:
0 commit comments