6 static int t1_get_flags(char const *flags);
7 static char *t1_from_utf8(char const *in, size_t len, int *outlen);
9 static void t1_push_error(void);
11 static int t1_active_fonts = 0;
12 static int t1_initialized = 0;
15 =item i_init_t1(t1log)
17 Initializes the t1lib font rendering engine.
23 i_init_t1(int t1log) {
24 int init_flags = IGNORE_CONFIGFILE|IGNORE_FONTDATABASE;
25 mm_log((1,"init_t1()\n"));
29 if (t1_active_fonts) {
30 mm_log((1, "Cannot re-initialize T1 - active fonts\n"));
31 i_push_error(0, "Cannot re-initialize T1 - active fonts");
41 init_flags |= LOGFILE;
42 if ((T1_InitLib(init_flags) == NULL)){
43 mm_log((1,"Initialization of t1lib failed\n"));
44 i_push_error(0, "T1_InitLib failed");
47 T1_SetLogLevel(T1LOG_DEBUG);
48 i_t1_set_aa(1); /* Default Antialias value */
58 Shuts the t1lib font rendering engine down.
60 This it seems that this function is never used.
73 =item i_t1_new(pfb, afm)
75 Loads the fonts with the given filenames, returns its font id
77 pfb - path to pfb file for font
78 afm - path to afm file for font
84 i_t1_new(char *pfb,char *afm) {
89 if (!t1_initialized && i_init_t1(0))
92 mm_log((1,"i_t1_new(pfb %s,afm %s)\n",pfb,(afm?afm:"NULL")));
93 font_id = T1_AddFont(pfb);
95 mm_log((1,"i_t1_new: Failed to load pfb file '%s' - return code %d.\n",pfb,font_id));
101 mm_log((1,"i_t1_new: requesting afm file '%s'.\n",afm));
102 if (T1_SetAfmFileName(font_id,afm)<0) mm_log((1,"i_t1_new: afm loading of '%s' failed.\n",afm));
105 if (T1_LoadFont(font_id)) {
106 mm_log((1, "i_t1_new() -> -1 - T1_LoadFont failed (%d)\n", T1_errno));
108 i_push_error(0, "loading font");
109 T1_DeleteFont(font_id);
115 mm_log((1, "i_t1_new() -> %d\n", font_id));
121 =item i_t1_destroy(font_id)
123 Frees resources for a t1 font with given font id.
125 font_id - number of the font to free
131 i_t1_destroy(int font_id) {
132 mm_log((1,"i_t1_destroy(font_id %d)\n",font_id));
136 return T1_DeleteFont(font_id);
141 =item i_t1_set_aa(st)
143 Sets the antialiasing level of the t1 library.
145 st - 0 = NONE, 1 = LOW, 2 = HIGH.
151 i_t1_set_aa(int st) {
153 unsigned long cst[17];
156 T1_AASetBitsPerPixel( 8 );
157 T1_AASetLevel( T1_AA_NONE );
158 T1_AANSetGrayValues( 0, 255 );
159 mm_log((1,"setting T1 antialias to none\n"));
162 T1_AASetBitsPerPixel( 8 );
163 T1_AASetLevel( T1_AA_LOW );
164 T1_AASetGrayValues( 0,65,127,191,255 );
165 mm_log((1,"setting T1 antialias to low\n"));
168 T1_AASetBitsPerPixel(8);
169 T1_AASetLevel(T1_AA_HIGH);
170 for(i=0;i<17;i++) cst[i]=(i*255)/16;
171 T1_AAHSetGrayValues( cst );
172 mm_log((1,"setting T1 antialias to high\n"));
178 =item i_t1_cp(im, xb, yb, channel, fontnum, points, str, len, align)
180 Interface to text rendering into a single channel in an image
182 im pointer to image structure
183 xb x coordinate of start of string
184 yb y coordinate of start of string ( see align )
185 channel - destination channel
186 fontnum - t1 library font id
187 points - number of points in fontheight
188 str - string to render
190 align - (0 - top of font glyph | 1 - baseline )
196 i_t1_cp(i_img *im,i_img_dim xb,i_img_dim yb,int channel,int fontnum,double points,char* str,size_t len,int align, int utf8, char const *flags) {
200 int mod_flags = t1_get_flags(flags);
202 unsigned int ch_mask_store;
204 if (im == NULL) { mm_log((1,"i_t1_cp: Null image in input\n")); return(0); }
208 char *work = t1_from_utf8(str, len, &worklen);
209 glyph=T1_AASetString( fontnum, work, worklen, 0, mod_flags, points, NULL);
213 glyph=T1_AASetString( fontnum, str, len, 0, mod_flags, points, NULL);
218 mm_log((1,"metrics: ascent: %d descent: %d\n",glyph->metrics.ascent,glyph->metrics.descent));
219 mm_log((1," leftSideBearing: %d rightSideBearing: %d\n",glyph->metrics.leftSideBearing,glyph->metrics.rightSideBearing));
220 mm_log((1," advanceX: %d advanceY: %d\n",glyph->metrics.advanceX,glyph->metrics.advanceY));
221 mm_log((1,"bpp: %d\n",glyph->bpp));
223 xsize=glyph->metrics.rightSideBearing-glyph->metrics.leftSideBearing;
224 ysize=glyph->metrics.ascent-glyph->metrics.descent;
226 mm_log((1,"width: %d height: %d\n",xsize,ysize));
228 ch_mask_store=im->ch_mask;
229 im->ch_mask=1<<channel;
231 if (align==1) { xb+=glyph->metrics.leftSideBearing; yb-=glyph->metrics.ascent; }
233 for(y=0;y<ysize;y++) for(x=0;x<xsize;x++) {
234 val.channel[channel]=glyph->bits[y*xsize+x];
235 i_ppix(im,x+xb,y+yb,&val);
238 im->ch_mask=ch_mask_store;
243 t1_fix_bbox(BBox *bbox, const char *str, size_t len, int advance,
244 int space_position) {
245 /* never called with len == 0 */
246 if (str[0] == space_position && bbox->llx > 0)
248 if (str[len-1] == space_position && bbox->urx < advance)
250 if (bbox->lly > bbox->ury)
251 bbox->lly = bbox->ury = 0;
255 =item i_t1_bbox(handle, fontnum, points, str, len, cords)
257 function to get a strings bounding box given the font id and sizes
259 handle - pointer to font handle
260 fontnum - t1 library font id
261 points - number of points in fontheight
262 str - string to measure
264 cords - the bounding box (modified in place)
270 i_t1_bbox(int fontnum, double points,const char *str,size_t len, i_img_dim cords[6], int utf8,char const *flags) {
273 int mod_flags = t1_get_flags(flags);
275 int space_position = T1_GetEncodingIndex(fontnum, "space");
277 mm_log((1,"i_t1_bbox(fontnum %d,points %.2f,str '%.*s', len %d)\n",fontnum,points,len,str,len));
278 T1_LoadFont(fontnum); /* FIXME: Here a return code is ignored - haw haw haw */
281 /* len == 0 has special meaning to T1lib, but it means there's
282 nothing to draw, so return that */
283 bbox.llx = bbox.lly = bbox.urx = bbox.ury = 0;
289 char *work = t1_from_utf8(str, len, &worklen);
290 advance = T1_GetStringWidth(fontnum, work, worklen, 0, mod_flags);
291 bbox = T1_GetStringBBox(fontnum,work,worklen,0,mod_flags);
292 t1_fix_bbox(&bbox, work, worklen, advance, space_position);
296 advance = T1_GetStringWidth(fontnum, (char *)str, len, 0, mod_flags);
297 bbox = T1_GetStringBBox(fontnum,(char *)str,len,0,mod_flags);
298 t1_fix_bbox(&bbox, str, len, advance, space_position);
301 gbbox = T1_GetFontBBox(fontnum);
303 mm_log((1,"bbox: (%d,%d,%d,%d)\n",
304 (int)(bbox.llx*points/1000),
305 (int)(gbbox.lly*points/1000),
306 (int)(bbox.urx*points/1000),
307 (int)(gbbox.ury*points/1000),
308 (int)(bbox.lly*points/1000),
309 (int)(bbox.ury*points/1000) ));
312 cords[BBOX_NEG_WIDTH]=((double)bbox.llx*points)/1000;
313 cords[BBOX_POS_WIDTH]=((double)bbox.urx*points)/1000;
315 cords[BBOX_GLOBAL_DESCENT]=((double)gbbox.lly*points)/1000;
316 cords[BBOX_GLOBAL_ASCENT]=((double)gbbox.ury*points)/1000;
318 cords[BBOX_DESCENT]=((double)bbox.lly*points)/1000;
319 cords[BBOX_ASCENT]=((double)bbox.ury*points)/1000;
321 cords[BBOX_ADVANCE_WIDTH] = ((double)advance * points)/1000;
322 cords[BBOX_RIGHT_BEARING] =
323 cords[BBOX_ADVANCE_WIDTH] - cords[BBOX_POS_WIDTH];
325 return BBOX_RIGHT_BEARING+1;
330 =item i_t1_text(im, xb, yb, cl, fontnum, points, str, len, align)
332 Interface to text rendering in a single color onto an image
334 im - pointer to image structure
335 xb - x coordinate of start of string
336 yb - y coordinate of start of string ( see align )
337 cl - color to draw the text in
338 fontnum - t1 library font id
339 points - number of points in fontheight
340 str - char pointer to string to render
342 align - (0 - top of font glyph | 1 - baseline )
348 i_t1_text(i_img *im, i_img_dim xb, i_img_dim yb,const i_color *cl,int fontnum, double points,const char* str,size_t len,int align, int utf8, char const *flags) {
351 int mod_flags = t1_get_flags(flags);
354 if (im == NULL) { mm_log((1,"i_t1_cp: Null image in input\n")); return(0); }
358 char *work = t1_from_utf8(str, len, &worklen);
359 glyph=T1_AASetString( fontnum, work, worklen, 0, mod_flags, points, NULL);
363 /* T1_AASetString() accepts a char * not a const char */
364 glyph=T1_AASetString( fontnum, (char *)str, len, 0, mod_flags, points, NULL);
369 mm_log((1,"metrics: ascent: %d descent: %d\n",glyph->metrics.ascent,glyph->metrics.descent));
370 mm_log((1," leftSideBearing: %d rightSideBearing: %d\n",glyph->metrics.leftSideBearing,glyph->metrics.rightSideBearing));
371 mm_log((1," advanceX: %d advanceY: %d\n",glyph->metrics.advanceX,glyph->metrics.advanceY));
372 mm_log((1,"bpp: %d\n",glyph->bpp));
374 xsize=glyph->metrics.rightSideBearing-glyph->metrics.leftSideBearing;
375 ysize=glyph->metrics.ascent-glyph->metrics.descent;
377 mm_log((1,"width: %d height: %d\n",xsize,ysize));
379 if (align==1) { xb+=glyph->metrics.leftSideBearing; yb-=glyph->metrics.ascent; }
381 r = i_render_new(im, xsize);
382 for(y=0;y<ysize;y++) {
383 i_render_color(r, xb, yb+y, xsize, (unsigned char *)glyph->bits+y*xsize, cl);
391 =item t1_get_flags(flags)
393 Processes the characters in I<flags> to create a mod_flags value used
394 by some T1Lib functions.
399 t1_get_flags(char const *flags) {
400 int mod_flags = T1_KERNING;
404 case 'u': case 'U': mod_flags |= T1_UNDERLINE; break;
405 case 'o': case 'O': mod_flags |= T1_OVERLINE; break;
406 case 's': case 'S': mod_flags |= T1_OVERSTRIKE; break;
407 /* ignore anything we don't recognize */
415 =item t1_from_utf8(char const *in, size_t len, int *outlen)
417 Produces an unencoded version of I<in> by dropping any Unicode
420 Returns a newly allocated buffer which should be freed with myfree().
421 Sets *outlen to the number of bytes used in the output string.
427 t1_from_utf8(char const *in, size_t len, int *outlen) {
428 /* at this point len is from a STRLEN which should be size_t and can't
429 be too big for mymalloc */
430 char *out = mymalloc(len+1); /* rechecked 29jul11 tonyc */
435 c = i_utf8_advance(&in, &len);
438 i_push_error(0, "invalid UTF8 character");
441 /* yeah, just drop them */
453 =item i_t1_has_chars(font_num, text, len, utf8, out)
455 Check if the given characters are defined by the font. Note that len
456 is the number of bytes, not the number of characters (when utf8 is
459 out[char index] will be true if the character exists.
461 Accepts UTF-8, but since T1 can only have 256 characters, any chars
462 with values over 255 will simply be returned as false.
464 Returns the number of characters that were checked.
470 i_t1_has_chars(int font_num, const char *text, size_t len, int utf8,
474 mm_log((1, "i_t1_has_chars(font_num %d, text %p, len %d, utf8 %d)\n",
475 font_num, text, len, utf8));
478 if (T1_LoadFont(font_num)) {
486 c = i_utf8_advance(&text, &len);
488 i_push_error(0, "invalid UTF8 character");
493 c = (unsigned char)*text++;
498 /* limit of 256 characters for T1 */
502 char const * name = T1_GetCharName(font_num, (unsigned char)c);
505 *out++ = strcmp(name, ".notdef") != 0;
508 mm_log((2, " No name found for character %lx\n", c));
519 =item i_t1_face_name(font_num, name_buf, name_buf_size)
521 Copies the face name of the given C<font_num> to C<name_buf>. Returns
522 the number of characters required to store the name (which can be
523 larger than C<name_buf_size>, including the space required to store
524 the terminating NUL).
526 If name_buf is too small (as specified by name_buf_size) then the name
527 will be truncated. name_buf will always be NUL termintaed.
533 i_t1_face_name(int font_num, char *name_buf, size_t name_buf_size) {
537 if (T1_LoadFont(font_num)) {
541 name = T1_GetFontName(font_num);
544 strncpy(name_buf, name, name_buf_size);
545 name_buf[name_buf_size-1] = '\0';
546 return strlen(name) + 1;
555 i_t1_glyph_name(int font_num, unsigned long ch, char *name_buf,
556 size_t name_buf_size) {
563 if (T1_LoadFont(font_num)) {
567 name = T1_GetCharName(font_num, (unsigned char)ch);
569 if (strcmp(name, ".notdef")) {
570 strncpy(name_buf, name, name_buf_size);
571 name_buf[name_buf_size-1] = '\0';
572 return strlen(name) + 1;
585 t1_push_error(void) {
586 #if T1LIB_VERSION > 5 || T1LIB_VERSION == 5 && T1LIB_VERSION >= 1
587 /* I don't know when T1_StrError() was introduced, be conservative */
588 i_push_error(T1_errno, T1_StrError(T1_errno));
592 i_push_error(0, "No error");
595 #ifdef T1ERR_SCAN_FONT_FORMAT
596 case T1ERR_SCAN_FONT_FORMAT:
597 i_push_error(T1ERR_SCAN_FONT_FORMAT, "SCAN_FONT_FORMAT");
601 #ifdef T1ERR_SCAN_FILE_OPEN_ERR
602 case T1ERR_SCAN_FILE_OPEN_ERR:
603 i_push_error(T1ERR_SCAN_FILE_OPEN_ERR, "SCAN_FILE_OPEN_ERR");
607 #ifdef T1ERR_SCAN_OUT_OF_MEMORY
608 case T1ERR_SCAN_OUT_OF_MEMORY:
609 i_push_error(T1ERR_SCAN_OUT_OF_MEMORY, "SCAN_OUT_OF_MEMORY");
613 #ifdef T1ERR_SCAN_ERROR
614 case T1ERR_SCAN_ERROR:
615 i_push_error(T1ERR_SCAN_ERROR, "SCAN_ERROR");
619 #ifdef T1ERR_SCAN_FILE_EOF
620 case T1ERR_SCAN_FILE_EOF:
621 i_push_error(T1ERR_SCAN_FILE_EOF, "SCAN_FILE_EOF");
625 #ifdef T1ERR_PATH_ERROR
626 case T1ERR_PATH_ERROR:
627 i_push_error(T1ERR_PATH_ERROR, "PATH_ERROR");
631 #ifdef T1ERR_PARSE_ERROR
632 case T1ERR_PARSE_ERROR:
633 i_push_error(T1ERR_PARSE_ERROR, "PARSE_ERROR");
637 #ifdef T1ERR_TYPE1_ABORT
638 case T1ERR_TYPE1_ABORT:
639 i_push_error(T1ERR_TYPE1_ABORT, "TYPE1_ABORT");
643 #ifdef T1ERR_INVALID_FONTID
644 case T1ERR_INVALID_FONTID:
645 i_push_error(T1ERR_INVALID_FONTID, "INVALID_FONTID");
649 #ifdef T1ERR_INVALID_PARAMETER
650 case T1ERR_INVALID_PARAMETER:
651 i_push_error(T1ERR_INVALID_PARAMETER, "INVALID_PARAMETER");
655 #ifdef T1ERR_OP_NOT_PERMITTED
656 case T1ERR_OP_NOT_PERMITTED:
657 i_push_error(T1ERR_OP_NOT_PERMITTED, "OP_NOT_PERMITTED");
661 #ifdef T1ERR_ALLOC_MEM
662 case T1ERR_ALLOC_MEM:
663 i_push_error(T1ERR_ALLOC_MEM, "ALLOC_MEM");
667 #ifdef T1ERR_FILE_OPEN_ERR
668 case T1ERR_FILE_OPEN_ERR:
669 i_push_error(T1ERR_FILE_OPEN_ERR, "FILE_OPEN_ERR");
673 #ifdef T1ERR_UNSPECIFIED
674 case T1ERR_UNSPECIFIED:
675 i_push_error(T1ERR_UNSPECIFIED, "UNSPECIFIED");
679 #ifdef T1ERR_NO_AFM_DATA
680 case T1ERR_NO_AFM_DATA:
681 i_push_error(T1ERR_NO_AFM_DATA, "NO_AFM_DATA");
687 i_push_error(T1ERR_X11, "X11");
691 #ifdef T1ERR_COMPOSITE_CHAR
692 case T1ERR_COMPOSITE_CHAR:
693 i_push_error(T1ERR_COMPOSITE_CHAR, "COMPOSITE_CHAR");
698 i_push_errorf(T1_errno, "unknown error %d", (int)T1_errno);