2
/********************************************/
3
/* gd interface to freetype library */
5
/* John Ellson ellson@lucent.com */
6
/********************************************/
13
#include "gdhelpers.h"
21
/* number of antialised colors for indexed bitmaps */
24
#ifndef HAVE_LIBFREETYPE
26
gdImageStringFT (gdImage * im, int *brect, int fg, char *fontlist,
27
double ptsize, double angle, int x, int y, char *string)
30
return gdImageStringTTF(im,brect,fg,fontlist,ptsize,angle,x,y,string);
32
return "libgd was not built with FreeType font support\n";
38
#include "freetype/freetype.h"
39
#include "freetype/ftglyph.h"
41
/* number of fonts cached before least recently used is replaced */
42
#define FONTCACHESIZE 6
44
/* number of antialias color lookups cached */
45
#define TWEENCOLORCACHESIZE 32
48
* Line separation as a factor of font height.
49
* No space between if LINESPACE = 1.00
50
* Line separation will be rounded up to next pixel row.
52
#define LINESPACE 1.05
55
* The character (space) used to separate alternate fonts in the
56
* fontlist parameter to gdImageStringFT.
58
#define LISTSEPARATOR " "
61
* DEFAULT_FONTPATH and PATHSEPARATOR are host type dependent and
62
* are normally set by configure in gvconfig.h. These are just
63
* some last resort values that might match some Un*x system
64
* if building this version of gd separate from graphviz.
66
#ifndef DEFAULT_FONTPATH
67
#define DEFAULT_FONTPATH "/usr/share/fonts/truetype"
70
#define PATHSEPARATOR ":"
78
#define MAX(a,b) ((a)>(b)?(a):(b))
79
#define MIN(a,b) ((a)<(b)?(a):(b))
83
char *fontlist; /* key */
86
FT_Bool have_char_map_unicode, have_char_map_big5, have_char_map_sjis,
87
have_char_map_apple_roman;
88
gdCache_head_t *glyphCache;
94
char *fontlist; /* key */
102
int bgcolor; /* key */
103
int fgcolor; /* key *//* -ve means no antialias */
104
gdImagePtr im; /* key */
112
int bgcolor; /* key */
113
int fgcolor; /* key *//* -ve means no antialias */
114
gdImagePtr im; /* key */
118
/********************************************************************
119
* gdTcl_UtfToUniChar is borrowed from Tcl ...
124
* Routines for manipulating UTF-8 strings.
126
* Copyright (c) 1997-1998 Sun Microsystems, Inc.
128
* See the file "license.terms" for information on usage and redistribution
129
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
131
* SCCS: @(#) tclUtf.c 1.25 98/01/28 18:02:43
135
*---------------------------------------------------------------------------
137
* gdTcl_UtfToUniChar --
139
* Extract the Tcl_UniChar represented by the UTF-8 string. Bad
140
* UTF-8 sequences are converted to valid Tcl_UniChars and processing
141
* continues. Equivalent to Plan 9 chartorune().
143
* The caller must ensure that the source buffer is long enough that
144
* this routine does not run off the end and dereference non-existent
145
* memory looking for trail bytes. If the source buffer is known to
146
* be '\0' terminated, this cannot happen. Otherwise, the caller
147
* should call Tcl_UtfCharComplete() before calling this routine to
148
* ensure that enough bytes remain in the string.
151
* *chPtr is filled with the Tcl_UniChar, and the return value is the
152
* number of bytes from the UTF-8 string that were consumed.
157
*---------------------------------------------------------------------------
161
#include "jisx0208.h"
164
#define Tcl_UniChar int
165
#define TCL_UTF_MAX 3
167
gdTcl_UtfToUniChar (char *str, Tcl_UniChar * chPtr)
168
/* str is the UTF8 next character pointer */
169
/* chPtr is the int for the result */
173
/* HTML4.0 entities in decimal form, e.g. Å */
174
byte = *((unsigned char *) str);
179
byte = *((unsigned char *) (str + 1));
182
for (i = 2; i < 8; i++)
184
byte = *((unsigned char *) (str + i));
185
if (byte >= '0' && byte <= '9')
187
n = (n * 10) + (byte - '0');
194
*chPtr = (Tcl_UniChar) n;
201
* Unroll 1 to 3 byte UTF-8 sequences, use loop to handle longer ones.
204
byte = *((unsigned char *) str);
206
if (0xA1 <= byte && byte <= 0xFE)
210
ku = (byte & 0x7F) - 0x20;
211
ten = (str[1] & 0x7F) - 0x20;
212
if ((ku < 1 || ku > 92) || (ten < 1 || ten > 94))
214
*chPtr = (Tcl_UniChar) byte;
218
*chPtr = (Tcl_UniChar) UnicodeTbl[ku - 1][ten - 1];
222
#endif /* JISX0208 */
226
* Handles properly formed UTF-8 characters between
227
* 0x01 and 0x7F. Also treats \0 and naked trail
228
* bytes 0x80 to 0xBF as valid characters representing
232
*chPtr = (Tcl_UniChar) byte;
235
else if (byte < 0xE0)
237
if ((str[1] & 0xC0) == 0x80)
240
* Two-byte-character lead-byte followed
244
*chPtr = (Tcl_UniChar) (((byte & 0x1F) << 6)
249
* A two-byte-character lead-byte not followed by trail-byte
253
*chPtr = (Tcl_UniChar) byte;
256
else if (byte < 0xF0)
258
if (((str[1] & 0xC0) == 0x80) && ((str[2] & 0xC0) == 0x80))
261
* Three-byte-character lead byte followed by
265
*chPtr = (Tcl_UniChar) (((byte & 0x0F) << 12)
266
| ((str[1] & 0x3F) << 6) | (str[2] & 0x3F));
270
* A three-byte-character lead-byte not followed by
271
* two trail-bytes represents itself.
274
*chPtr = (Tcl_UniChar) byte;
280
int ch, total, trail;
282
total = totalBytes[byte];
286
ch = byte & (0x3F >> trail);
290
if ((*str & 0xC0) != 0x80)
306
*chPtr = (Tcl_UniChar) byte;
310
/********************************************************************/
311
/* font cache functions */
314
fontTest (void *element, void *key)
316
font_t *a = (font_t *) element;
317
fontkey_t *b = (fontkey_t *) key;
319
return (strcmp (a->fontlist, b->fontlist) == 0);
323
fontFetch (char **error, void *key)
326
fontkey_t *b = (fontkey_t *) key;
329
unsigned short platform, encoding;
330
char *fontsearchpath, *fontlist;
331
char *fullname = NULL;
332
char *name, *path, *dir;
335
FT_CharMap found = 0;
338
a = (font_t *) gdMalloc (sizeof (font_t));
339
a->fontlist = strdup (b->fontlist);
340
a->library = b->library;
343
* Search the pathlist for any of a list of font names.
345
fontsearchpath = getenv ("GDFONTPATH");
347
fontsearchpath = DEFAULT_FONTPATH;
348
fontlist = strdup (a->fontlist);
351
* Must use gd_strtok_r else pointer corrupted by strtok in nested loop.
353
for (name = gd_strtok_r (fontlist, LISTSEPARATOR, &strtok_ptr); name;
354
name = gd_strtok_r (0, LISTSEPARATOR, &strtok_ptr))
357
/* make a fresh copy each time - strtok corrupts it. */
358
path = strdup (fontsearchpath);
360
* Allocate an oversized buffer that is guaranteed to be
361
* big enough for all paths to be tested.
363
fullname = gdRealloc (fullname,
364
strlen (fontsearchpath) + strlen (name) + 6);
365
/* if name is an absolute filename then test directly */
366
if (*name == '/' || (name[0] != 0 && name[1] == ':' && (name[2] == '/' || name[2] == '\\')))
368
sprintf (fullname, "%s", name);
369
if (access (fullname, R_OK) == 0)
375
for (dir = strtok (path, PATHSEPARATOR); dir;
376
dir = strtok (0, PATHSEPARATOR))
378
sprintf (fullname, "%s/%s.ttf", dir, name);
379
if (access (fullname, R_OK) == 0)
392
*error = "Could not find/open font";
396
err = FT_New_Face (*b->library, fullname, 0, &a->face);
399
*error = "Could not read font";
404
/* FIXME - This mapping stuff is imcomplete - where is the spec? */
406
a->have_char_map_unicode = 0;
407
a->have_char_map_big5 = 0;
408
a->have_char_map_sjis = 0;
409
a->have_char_map_apple_roman = 0;
410
for (n = 0; n < a->face->num_charmaps; n++)
412
charmap = a->face->charmaps[n];
413
platform = charmap->platform_id;
414
encoding = charmap->encoding_id;
415
if ((platform == 3 && encoding == 1) /* Windows Unicode */
416
|| (platform == 3 && encoding == 0) /* Windows Symbol */
417
|| (platform == 2 && encoding == 1) /* ISO Unicode */
419
{ /* Apple Unicode */
420
a->have_char_map_unicode = 1;
423
else if (platform == 3 && encoding == 4)
425
a->have_char_map_big5 = 1;
428
else if (platform == 3 && encoding == 2)
430
a->have_char_map_sjis = 1;
433
else if ((platform == 1 && encoding == 0) /* Apple Roman */
434
|| (platform == 2 && encoding == 0))
436
a->have_char_map_apple_roman = 1;
442
*error = "Unable to find a CharMap that I can handle";
450
fontRelease (void *element)
452
font_t *a = (font_t *) element;
454
FT_Done_Face (a->face);
455
gdFree (a->fontlist);
456
gdFree ((char *) element);
459
/********************************************************************/
460
/* tweencolor cache functions */
463
tweenColorTest (void *element, void *key)
465
tweencolor_t *a = (tweencolor_t *) element;
466
tweencolorkey_t *b = (tweencolorkey_t *) key;
468
return (a->pixel == b->pixel
469
&& a->bgcolor == b->bgcolor
470
&& a->fgcolor == b->fgcolor
475
* Computes a color in im's color table that is part way between
476
* the background and foreground colors proportional to the gray
477
* pixel value in the range 0-NUMCOLORS. The fg and bg colors must already
478
* be in the color table.
481
tweenColorFetch (char **error, void *key)
484
tweencolorkey_t *b = (tweencolorkey_t *) key;
485
int pixel, npixel, bg, fg;
488
a = (tweencolor_t *) gdMalloc (sizeof (tweencolor_t));
489
pixel = a->pixel = b->pixel;
490
bg = a->bgcolor = b->bgcolor;
491
fg = a->fgcolor = b->fgcolor;
494
/* if fg is specified by a negative color idx, then don't antialias */
501
npixel = NUMCOLORS - pixel;
504
/* 2.0.1: use gdImageSetPixel to do the alpha blending work,
505
or to just store the alpha level. All we have to do here
506
is incorporate our knowledge of the percentage of this
507
pixel that is really "lit" by pushing the alpha value
508
up toward transparency in edge regions. */
509
a->tweencolor = gdTrueColorAlpha (
510
gdTrueColorGetRed (fg),
511
gdTrueColorGetGreen (fg),
512
gdTrueColorGetBlue (fg),
513
gdAlphaMax - (gdTrueColorGetAlpha (fg) * pixel / NUMCOLORS));
517
a->tweencolor = gdImageColorResolve (im,
518
(pixel * im->red[fg] + npixel * im->red[bg]) / NUMCOLORS,
519
(pixel * im->green[fg] + npixel * im->green[bg]) / NUMCOLORS,
520
(pixel * im->blue[fg] + npixel * im->blue[bg]) / NUMCOLORS);
527
tweenColorRelease (void *element)
529
gdFree ((char *) element);
532
/* draw_bitmap - transfers glyph bitmap to GD image */
534
gdft_draw_bitmap (gdCache_head_t *tc_cache, gdImage * im, int fg, FT_Bitmap bitmap, int pen_x, int pen_y)
536
unsigned char *pixel = NULL;
538
int x, y, row, col, pc;
540
tweencolor_t *tc_elem;
541
tweencolorkey_t tc_key;
543
/* copy to image, mapping colors */
546
for (row = 0; row < bitmap.rows; row++)
548
pc = row * bitmap.pitch;
549
if(bitmap.pixel_mode==ft_pixel_mode_mono)
550
pc *= 8; /* pc is measured in bits for monochrome images */
554
/* clip if out of bounds */
555
if (y >= im->sy || y < 0)
558
for (col = 0; col < bitmap.width; col++, pc++)
560
if (bitmap.pixel_mode == ft_pixel_mode_grays)
563
* Round to NUMCOLORS levels of antialiasing for
564
* index color images since only 256 colors are
567
tc_key.pixel = ((bitmap.buffer[pc] * NUMCOLORS)
568
+ bitmap.num_grays / 2)
569
/ (bitmap.num_grays - 1);
571
else if (bitmap.pixel_mode == ft_pixel_mode_mono)
573
tc_key.pixel = ((bitmap.buffer[pc / 8]
574
<< (pc % 8)) & 128) ? NUMCOLORS : 0;
578
return "Unsupported ft_pixel_mode";
581
if (tc_key.pixel > 0)
582
{ /* if not background */
585
/* clip if out of bounds */
586
if (x >= im->sx || x < 0)
588
/* get pixel location in gd buffer */
591
tpixel = &im->tpixels[y][x];
595
pixel = &im->pixels[y][x];
597
if (tc_key.pixel == NUMCOLORS)
599
/* use fg color directly */
611
/* find antialised color */
614
tc_key.bgcolor = *tpixel;
618
tc_key.bgcolor = *pixel;
620
tc_elem = (tweencolor_t *) gdCacheGet (
624
*tpixel = tc_elem->tweencolor;
628
*pixel = tc_elem->tweencolor;
634
return (char *) NULL;
638
gdroundupdown (FT_F26Dot6 v1, int updown)
641
? (v1 < 0 ? ((v1 - 63) >> 6) : v1 >> 6)
642
: (v1 > 0 ? ((v1 + 63) >> 6) : v1 >> 6);
646
extern int any2eucjp (char *, char *, unsigned int);
648
/********************************************************************/
649
/* gdImageStringFT - render a utf8 string onto a gd image */
652
gdImageStringFT (gdImage * im, int *brect, int fg, char *fontlist,
653
double ptsize, double angle, int x, int y, char *string)
655
FT_BBox bbox, glyph_bbox;
657
FT_Vector pen, delta, penf;
663
FT_UInt glyph_index, previous;
664
double sin_a = sin (angle);
665
double cos_a = cos (angle);
672
int render = (im && (im->trueColor || (fg <= 255 && fg >= -255)));
674
int render_mode = FT_LOAD_RENDER | FT_LOAD_FORCE_AUTOHINT;
677
/***** initialize font library and font cache on first call ******/
678
static gdCache_head_t *fontCache;
679
static FT_Library library;
682
* make a new tweenColorCache on every call
683
* because caching colormappings between calls
684
* is not safe. If the im-pointer points to a
685
* brand new image, the cache gives out bogus
686
* colorindexes. -- 27.06.2001 <krisku@arrak.fi>
688
gdCache_head_t *tc_cache;
690
tc_cache = gdCacheCreate( TWEENCOLORCACHESIZE,
691
tweenColorTest, tweenColorFetch, tweenColorRelease );
695
if (FT_Init_FreeType (&library))
697
gdCacheDelete( tc_cache );
698
return "Failure to initialize font library";
700
fontCache = gdCacheCreate (FONTCACHESIZE,
701
fontTest, fontFetch, fontRelease);
705
/* get the font (via font cache) */
706
fontkey.fontlist = fontlist;
707
fontkey.library = &library;
708
font = (font_t *) gdCacheGet (fontCache, &fontkey);
711
gdCacheDelete( tc_cache );
712
return fontCache->error;
714
face = font->face; /* shortcut */
715
slot = face->glyph; /* shortcut */
717
if (FT_Set_Char_Size (face, 0, (FT_F26Dot6) (ptsize * 64),
718
GD_RESOLUTION, GD_RESOLUTION))
720
gdCacheDelete( tc_cache );
721
return "Could not set character size";
724
matrix.xx = (FT_Fixed) (cos_a * (1 << 16));
725
matrix.yx = (FT_Fixed) (sin_a * (1 << 16));
726
matrix.xy = -matrix.yx;
727
matrix.yy = matrix.xx;
729
penf.x = penf.y = 0; /* running position of non-rotated string */
730
pen.x = pen.y = 0; /* running position of rotated string */
731
bbox.xMin = bbox.xMax = bbox.yMin = bbox.yMax = 0;
732
use_kerning = FT_HAS_KERNING (face);
736
render_mode |= FT_LOAD_MONOCHROME;
740
if (font->have_char_map_sjis)
743
if ((tmpstr = (char *) gdMalloc (BUFSIZ)))
745
any2eucjp (tmpstr, string, BUFSIZ);
763
/* carriage returns */
767
x1 = (penf.x * cos_a - penf.y * sin_a + 32) / 64;
768
y1 = (penf.x * sin_a + penf.y * cos_a + 32) / 64;
770
previous = 0; /* clear kerning flag */
777
penf.y -= face->size->metrics.height * LINESPACE;
778
penf.y = (penf.y - 32) & -64; /* round to next pixel row */
779
x1 = (penf.x * cos_a - penf.y * sin_a + 32) / 64;
780
y1 = (penf.x * sin_a + penf.y * cos_a + 32) / 64;
782
previous = 0; /* clear kerning flag */
787
if (font->have_char_map_unicode)
789
/* use UTF-8 mapping from ASCII */
790
len = gdTcl_UtfToUniChar (next, &ch);
793
else if (font->have_char_map_sjis)
799
if (0xA1 <= c && c <= 0xFE)
802
jiscode = 0x100 * (c & 0x7F) + ((*next) & 0x7F);
804
ch = (jiscode >> 8) & 0xFF;
808
jiscode += 0x40 - 0x21;
810
jiscode += 0x9E - 0x21;
814
ch = (ch - 0x21) / 2 + 0x81;
818
ch = (ch << 8) + jiscode;
822
ch = c & 0xFF; /* don't extend sign */
830
* use "JIS-8 half-width katakana" coding from 8-bit characters. Ref:
831
* ftp://ftp.ora.com/pub/examples/nutshell/ujip/doc/japan.inf-032092.sjs
833
ch = (*next) & 0xFF; /* don't extend sign */
835
if (ch >= 161 /* first code of JIS-8 pair */
837
{ /* don't advance past '\0' */
838
/* TBB: Fix from Kwok Wah On: & 255 needed */
839
ch = (ch * 256) + ((*next) & 255);
844
/* set rotation transform */
845
FT_Set_Transform(face, &matrix, NULL);
847
/* Convert character code to glyph index */
848
glyph_index = FT_Get_Char_Index (face, ch);
850
/* retrieve kerning distance and move pen position */
851
if (use_kerning && previous && glyph_index)
853
FT_Get_Kerning (face, previous, glyph_index,
854
ft_kerning_default, &delta);
858
/* load glyph image into the slot (erase previous one) */
859
err = FT_Load_Glyph (face, glyph_index, render_mode);
862
gdCacheDelete( tc_cache );
863
return "Problem loading glyph";
866
/* transform glyph image */
867
FT_Get_Glyph (slot, &image);
869
{ /* only if need brect */
870
FT_Glyph_Get_CBox (image, ft_glyph_bbox_gridfit, &glyph_bbox);
871
glyph_bbox.xMin += penf.x;
872
glyph_bbox.yMin += penf.y;
873
glyph_bbox.xMax += penf.x;
874
glyph_bbox.yMax += penf.y;
876
{ /* if first character, init BB corner values */
877
bbox.xMin = glyph_bbox.xMin;
878
bbox.yMin = glyph_bbox.yMin;
879
bbox.xMax = glyph_bbox.xMax;
880
bbox.yMax = glyph_bbox.yMax;
884
if (bbox.xMin > glyph_bbox.xMin)
885
bbox.xMin = glyph_bbox.xMin;
886
if (bbox.yMin > glyph_bbox.yMin)
887
bbox.yMin = glyph_bbox.yMin;
888
if (bbox.xMax < glyph_bbox.xMax)
889
bbox.xMax = glyph_bbox.xMax;
890
if (bbox.yMax < glyph_bbox.yMax)
891
bbox.yMax = glyph_bbox.yMax;
898
if (image->format != ft_glyph_format_bitmap)
900
err = FT_Glyph_To_Bitmap (&image, ft_render_mode_normal, 0, 1);
903
gdCacheDelete( tc_cache );
904
return "Problem rendering glyph";
908
/* now, draw to our target surface */
909
bm = (FT_BitmapGlyph) image;
910
gdft_draw_bitmap (tc_cache, im, fg, bm->bitmap,
911
x + x1 + ((pen.x + 31) >> 6) + bm->left,
912
y - y1 + ((pen.y + 31) >> 6) - bm->top);
915
/* record current glyph index for kerning */
916
previous = glyph_index;
918
/* increment pen position */
919
pen.x += image->advance.x >> 10;
920
pen.y -= image->advance.y >> 10;
922
penf.x += slot->metrics.horiAdvance;
924
FT_Done_Glyph (image);
928
{ /* only if need brect */
929
/* For perfect rounding, must get sin(a + pi/4) and sin(a - pi/4). */
930
double d1 = sin (angle + 0.78539816339744830962);
931
double d2 = sin (angle - 0.78539816339744830962);
933
/* rotate bounding rectangle */
934
brect[0] = (int) (bbox.xMin * cos_a - bbox.yMin * sin_a);
935
brect[1] = (int) (bbox.xMin * sin_a + bbox.yMin * cos_a);
936
brect[2] = (int) (bbox.xMax * cos_a - bbox.yMin * sin_a);
937
brect[3] = (int) (bbox.xMax * sin_a + bbox.yMin * cos_a);
938
brect[4] = (int) (bbox.xMax * cos_a - bbox.yMax * sin_a);
939
brect[5] = (int) (bbox.xMax * sin_a + bbox.yMax * cos_a);
940
brect[6] = (int) (bbox.xMin * cos_a - bbox.yMax * sin_a);
941
brect[7] = (int) (bbox.xMin * sin_a + bbox.yMax * cos_a);
943
/* scale, round and offset brect */
944
brect[0] = x + gdroundupdown (brect[0], d2 > 0);
945
brect[1] = y - gdroundupdown (brect[1], d1 < 0);
946
brect[2] = x + gdroundupdown (brect[2], d1 > 0);
947
brect[3] = y - gdroundupdown (brect[3], d2 > 0);
948
brect[4] = x + gdroundupdown (brect[4], d2 < 0);
949
brect[5] = y - gdroundupdown (brect[5], d1 > 0);
950
brect[6] = x + gdroundupdown (brect[6], d1 < 0);
951
brect[7] = y - gdroundupdown (brect[7], d2 < 0);
956
gdCacheDelete( tc_cache );
957
return (char *) NULL;
960
#endif /* HAVE_LIBFREETYPE */