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");
40 init_flags |= LOGFILE;
41 if ((T1_InitLib(init_flags) == NULL)){
42 mm_log((1,"Initialization of t1lib failed\n"));
43 i_push_error(0, "T1_InitLib failed");
46 T1_SetLogLevel(T1LOG_DEBUG);
47 i_t1_set_aa(1); /* Default Antialias value */
57 Shuts the t1lib font rendering engine down.
59 This it seems that this function is never used.
72 =item i_t1_new(pfb, afm)
74 Loads the fonts with the given filenames, returns its font id
76 pfb - path to pfb file for font
77 afm - path to afm file for font
83 i_t1_new(char *pfb,char *afm) {
88 if (!t1_initialized && i_init_t1(0))
91 mm_log((1,"i_t1_new(pfb %s,afm %s)\n",pfb,(afm?afm:"NULL")));
92 font_id = T1_AddFont(pfb);
94 mm_log((1,"i_t1_new: Failed to load pfb file '%s' - return code %d.\n",pfb,font_id));
99 mm_log((1,"i_t1_new: requesting afm file '%s'.\n",afm));
100 if (T1_SetAfmFileName(font_id,afm)<0) mm_log((1,"i_t1_new: afm loading of '%s' failed.\n",afm));
109 =item i_t1_destroy(font_id)
111 Frees resources for a t1 font with given font id.
113 font_id - number of the font to free
119 i_t1_destroy(int font_id) {
120 mm_log((1,"i_t1_destroy(font_id %d)\n",font_id));
124 return T1_DeleteFont(font_id);
129 =item i_t1_set_aa(st)
131 Sets the antialiasing level of the t1 library.
133 st - 0 = NONE, 1 = LOW, 2 = HIGH.
139 i_t1_set_aa(int st) {
141 unsigned long cst[17];
144 T1_AASetBitsPerPixel( 8 );
145 T1_AASetLevel( T1_AA_NONE );
146 T1_AANSetGrayValues( 0, 255 );
147 mm_log((1,"setting T1 antialias to none\n"));
150 T1_AASetBitsPerPixel( 8 );
151 T1_AASetLevel( T1_AA_LOW );
152 T1_AASetGrayValues( 0,65,127,191,255 );
153 mm_log((1,"setting T1 antialias to low\n"));
156 T1_AASetBitsPerPixel(8);
157 T1_AASetLevel(T1_AA_HIGH);
158 for(i=0;i<17;i++) cst[i]=(i*255)/16;
159 T1_AAHSetGrayValues( cst );
160 mm_log((1,"setting T1 antialias to high\n"));
166 =item i_t1_cp(im, xb, yb, channel, fontnum, points, str, len, align)
168 Interface to text rendering into a single channel in an image
170 im pointer to image structure
171 xb x coordinate of start of string
172 yb y coordinate of start of string ( see align )
173 channel - destination channel
174 fontnum - t1 library font id
175 points - number of points in fontheight
176 str - string to render
178 align - (0 - top of font glyph | 1 - baseline )
184 i_t1_cp(i_img *im,int xb,int yb,int channel,int fontnum,float points,char* str,size_t len,int align, int utf8, char const *flags) {
188 int mod_flags = t1_get_flags(flags);
190 unsigned int ch_mask_store;
192 if (im == NULL) { mm_log((1,"i_t1_cp: Null image in input\n")); return(0); }
196 char *work = t1_from_utf8(str, len, &worklen);
197 glyph=T1_AASetString( fontnum, work, worklen, 0, mod_flags, points, NULL);
201 glyph=T1_AASetString( fontnum, str, len, 0, mod_flags, points, NULL);
206 mm_log((1,"metrics: ascent: %d descent: %d\n",glyph->metrics.ascent,glyph->metrics.descent));
207 mm_log((1," leftSideBearing: %d rightSideBearing: %d\n",glyph->metrics.leftSideBearing,glyph->metrics.rightSideBearing));
208 mm_log((1," advanceX: %d advanceY: %d\n",glyph->metrics.advanceX,glyph->metrics.advanceY));
209 mm_log((1,"bpp: %d\n",glyph->bpp));
211 xsize=glyph->metrics.rightSideBearing-glyph->metrics.leftSideBearing;
212 ysize=glyph->metrics.ascent-glyph->metrics.descent;
214 mm_log((1,"width: %d height: %d\n",xsize,ysize));
216 ch_mask_store=im->ch_mask;
217 im->ch_mask=1<<channel;
219 if (align==1) { xb+=glyph->metrics.leftSideBearing; yb-=glyph->metrics.ascent; }
221 for(y=0;y<ysize;y++) for(x=0;x<xsize;x++) {
222 val.channel[channel]=glyph->bits[y*xsize+x];
223 i_ppix(im,x+xb,y+yb,&val);
226 im->ch_mask=ch_mask_store;
231 t1_fix_bbox(BBox *bbox, const char *str, size_t len, int advance,
232 int space_position) {
233 /* never called with len == 0 */
234 if (str[0] == space_position && bbox->llx > 0)
236 if (str[len-1] == space_position && bbox->urx < advance)
238 if (bbox->lly > bbox->ury)
239 bbox->lly = bbox->ury = 0;
243 =item i_t1_bbox(handle, fontnum, points, str, len, cords)
245 function to get a strings bounding box given the font id and sizes
247 handle - pointer to font handle
248 fontnum - t1 library font id
249 points - number of points in fontheight
250 str - string to measure
252 cords - the bounding box (modified in place)
258 i_t1_bbox(int fontnum,float points,const char *str,size_t len,int cords[6], int utf8,char const *flags) {
261 int mod_flags = t1_get_flags(flags);
263 int space_position = T1_GetEncodingIndex(fontnum, "space");
265 mm_log((1,"i_t1_bbox(fontnum %d,points %.2f,str '%.*s', len %d)\n",fontnum,points,len,str,len));
266 T1_LoadFont(fontnum); /* FIXME: Here a return code is ignored - haw haw haw */
269 /* len == 0 has special meaning to T1lib, but it means there's
270 nothing to draw, so return that */
271 bbox.llx = bbox.lly = bbox.urx = bbox.ury = 0;
277 char *work = t1_from_utf8(str, len, &worklen);
278 advance = T1_GetStringWidth(fontnum, work, worklen, 0, mod_flags);
279 bbox = T1_GetStringBBox(fontnum,work,worklen,0,mod_flags);
280 t1_fix_bbox(&bbox, work, worklen, advance, space_position);
284 advance = T1_GetStringWidth(fontnum, (char *)str, len, 0, mod_flags);
285 bbox = T1_GetStringBBox(fontnum,(char *)str,len,0,mod_flags);
286 t1_fix_bbox(&bbox, str, len, advance, space_position);
289 gbbox = T1_GetFontBBox(fontnum);
291 mm_log((1,"bbox: (%d,%d,%d,%d)\n",
292 (int)(bbox.llx*points/1000),
293 (int)(gbbox.lly*points/1000),
294 (int)(bbox.urx*points/1000),
295 (int)(gbbox.ury*points/1000),
296 (int)(bbox.lly*points/1000),
297 (int)(bbox.ury*points/1000) ));
300 cords[BBOX_NEG_WIDTH]=((float)bbox.llx*points)/1000;
301 cords[BBOX_POS_WIDTH]=((float)bbox.urx*points)/1000;
303 cords[BBOX_GLOBAL_DESCENT]=((float)gbbox.lly*points)/1000;
304 cords[BBOX_GLOBAL_ASCENT]=((float)gbbox.ury*points)/1000;
306 cords[BBOX_DESCENT]=((float)bbox.lly*points)/1000;
307 cords[BBOX_ASCENT]=((float)bbox.ury*points)/1000;
309 cords[BBOX_ADVANCE_WIDTH] = ((float)advance * points)/1000;
310 cords[BBOX_RIGHT_BEARING] =
311 cords[BBOX_ADVANCE_WIDTH] - cords[BBOX_POS_WIDTH];
313 return BBOX_RIGHT_BEARING+1;
318 =item i_t1_text(im, xb, yb, cl, fontnum, points, str, len, align)
320 Interface to text rendering in a single color onto an image
322 im - pointer to image structure
323 xb - x coordinate of start of string
324 yb - y coordinate of start of string ( see align )
325 cl - color to draw the text in
326 fontnum - t1 library font id
327 points - number of points in fontheight
328 str - char pointer to string to render
330 align - (0 - top of font glyph | 1 - baseline )
336 i_t1_text(i_img *im,int xb,int yb,const i_color *cl,int fontnum,float points,const char* str,size_t len,int align, int utf8, char const *flags) {
339 int mod_flags = t1_get_flags(flags);
342 if (im == NULL) { mm_log((1,"i_t1_cp: Null image in input\n")); return(0); }
346 char *work = t1_from_utf8(str, len, &worklen);
347 glyph=T1_AASetString( fontnum, work, worklen, 0, mod_flags, points, NULL);
351 /* T1_AASetString() accepts a char * not a const char */
352 glyph=T1_AASetString( fontnum, (char *)str, len, 0, mod_flags, points, NULL);
357 mm_log((1,"metrics: ascent: %d descent: %d\n",glyph->metrics.ascent,glyph->metrics.descent));
358 mm_log((1," leftSideBearing: %d rightSideBearing: %d\n",glyph->metrics.leftSideBearing,glyph->metrics.rightSideBearing));
359 mm_log((1," advanceX: %d advanceY: %d\n",glyph->metrics.advanceX,glyph->metrics.advanceY));
360 mm_log((1,"bpp: %d\n",glyph->bpp));
362 xsize=glyph->metrics.rightSideBearing-glyph->metrics.leftSideBearing;
363 ysize=glyph->metrics.ascent-glyph->metrics.descent;
365 mm_log((1,"width: %d height: %d\n",xsize,ysize));
367 if (align==1) { xb+=glyph->metrics.leftSideBearing; yb-=glyph->metrics.ascent; }
369 r = i_render_new(im, xsize);
370 for(y=0;y<ysize;y++) {
371 i_render_color(r, xb, yb+y, xsize, (unsigned char *)glyph->bits+y*xsize, cl);
379 =item t1_get_flags(flags)
381 Processes the characters in I<flags> to create a mod_flags value used
382 by some T1Lib functions.
387 t1_get_flags(char const *flags) {
388 int mod_flags = T1_KERNING;
392 case 'u': case 'U': mod_flags |= T1_UNDERLINE; break;
393 case 'o': case 'O': mod_flags |= T1_OVERLINE; break;
394 case 's': case 'S': mod_flags |= T1_OVERSTRIKE; break;
395 /* ignore anything we don't recognize */
403 =item t1_from_utf8(char const *in, size_t len, int *outlen)
405 Produces an unencoded version of I<in> by dropping any Unicode
408 Returns a newly allocated buffer which should be freed with myfree().
409 Sets *outlen to the number of bytes used in the output string.
415 t1_from_utf8(char const *in, size_t len, int *outlen) {
416 /* at this point len is from a perl SV, so can't approach MAXINT */
417 char *out = mymalloc(len+1); /* checked 5Nov05 tonyc */
422 c = i_utf8_advance(&in, &len);
425 i_push_error(0, "invalid UTF8 character");
428 /* yeah, just drop them */
440 =item i_t1_has_chars(font_num, text, len, utf8, out)
442 Check if the given characters are defined by the font. Note that len
443 is the number of bytes, not the number of characters (when utf8 is
446 out[char index] will be true if the character exists.
448 Accepts UTF-8, but since T1 can only have 256 characters, any chars
449 with values over 255 will simply be returned as false.
451 Returns the number of characters that were checked.
457 i_t1_has_chars(int font_num, const char *text, size_t len, int utf8,
461 mm_log((1, "i_t1_has_chars(font_num %d, text %p, len %d, utf8 %d)\n",
462 font_num, text, len, utf8));
465 if (T1_LoadFont(font_num)) {
473 c = i_utf8_advance(&text, &len);
475 i_push_error(0, "invalid UTF8 character");
480 c = (unsigned char)*text++;
485 /* limit of 256 characters for T1 */
489 char const * name = T1_GetCharName(font_num, (unsigned char)c);
492 *out++ = strcmp(name, ".notdef") != 0;
495 mm_log((2, " No name found for character %lx\n", c));
506 =item i_t1_face_name(font_num, name_buf, name_buf_size)
508 Copies the face name of the given C<font_num> to C<name_buf>. Returns
509 the number of characters required to store the name (which can be
510 larger than C<name_buf_size>, including the space required to store
511 the terminating NUL).
513 If name_buf is too small (as specified by name_buf_size) then the name
514 will be truncated. name_buf will always be NUL termintaed.
520 i_t1_face_name(int font_num, char *name_buf, size_t name_buf_size) {
524 if (T1_LoadFont(font_num)) {
528 name = T1_GetFontName(font_num);
531 strncpy(name_buf, name, name_buf_size);
532 name_buf[name_buf_size-1] = '\0';
533 return strlen(name) + 1;
542 i_t1_glyph_name(int font_num, unsigned long ch, char *name_buf,
543 size_t name_buf_size) {
550 if (T1_LoadFont(font_num)) {
554 name = T1_GetCharName(font_num, (unsigned char)ch);
556 if (strcmp(name, ".notdef")) {
557 strncpy(name_buf, name, name_buf_size);
558 name_buf[name_buf_size-1] = '\0';
559 return strlen(name) + 1;
572 t1_push_error(void) {
575 i_push_error(0, "No error");
578 #ifdef T1ERR_SCAN_FONT_FORMAT
579 case T1ERR_SCAN_FONT_FORMAT:
580 i_push_error(T1ERR_SCAN_FONT_FORMAT, "SCAN_FONT_FORMAT");
584 #ifdef T1ERR_SCAN_FILE_OPEN_ERR
585 case T1ERR_SCAN_FILE_OPEN_ERR:
586 i_push_error(T1ERR_SCAN_FILE_OPEN_ERR, "SCAN_FILE_OPEN_ERR");
590 #ifdef T1ERR_SCAN_OUT_OF_MEMORY
591 case T1ERR_SCAN_OUT_OF_MEMORY:
592 i_push_error(T1ERR_SCAN_OUT_OF_MEMORY, "SCAN_OUT_OF_MEMORY");
596 #ifdef T1ERR_SCAN_ERROR
597 case T1ERR_SCAN_ERROR:
598 i_push_error(T1ERR_SCAN_ERROR, "SCAN_ERROR");
602 #ifdef T1ERR_SCAN_FILE_EOF
603 case T1ERR_SCAN_FILE_EOF:
604 i_push_error(T1ERR_SCAN_FILE_EOF, "SCAN_FILE_EOF");
608 #ifdef T1ERR_PATH_ERROR
609 case T1ERR_PATH_ERROR:
610 i_push_error(T1ERR_PATH_ERROR, "PATH_ERROR");
614 #ifdef T1ERR_PARSE_ERROR
615 case T1ERR_PARSE_ERROR:
616 i_push_error(T1ERR_PARSE_ERROR, "PARSE_ERROR");
620 #ifdef T1ERR_TYPE1_ABORT
621 case T1ERR_TYPE1_ABORT:
622 i_push_error(T1ERR_TYPE1_ABORT, "TYPE1_ABORT");
626 #ifdef T1ERR_INVALID_FONTID
627 case T1ERR_INVALID_FONTID:
628 i_push_error(T1ERR_INVALID_FONTID, "INVALID_FONTID");
632 #ifdef T1ERR_INVALID_PARAMETER
633 case T1ERR_INVALID_PARAMETER:
634 i_push_error(T1ERR_INVALID_PARAMETER, "INVALID_PARAMETER");
638 #ifdef T1ERR_OP_NOT_PERMITTED
639 case T1ERR_OP_NOT_PERMITTED:
640 i_push_error(T1ERR_OP_NOT_PERMITTED, "OP_NOT_PERMITTED");
644 #ifdef T1ERR_ALLOC_MEM
645 case T1ERR_ALLOC_MEM:
646 i_push_error(T1ERR_ALLOC_MEM, "ALLOC_MEM");
650 #ifdef T1ERR_FILE_OPEN_ERR
651 case T1ERR_FILE_OPEN_ERR:
652 i_push_error(T1ERR_FILE_OPEN_ERR, "FILE_OPEN_ERR");
656 #ifdef T1ERR_UNSPECIFIED
657 case T1ERR_UNSPECIFIED:
658 i_push_error(T1ERR_UNSPECIFIED, "UNSPECIFIED");
662 #ifdef T1ERR_NO_AFM_DATA
663 case T1ERR_NO_AFM_DATA:
664 i_push_error(T1ERR_NO_AFM_DATA, "NO_AFM_DATA");
670 i_push_error(T1ERR_X11, "X11");
674 #ifdef T1ERR_COMPOSITE_CHAR
675 case T1ERR_COMPOSITE_CHAR:
676 i_push_error(T1ERR_COMPOSITE_CHAR, "COMPOSITE_CHAR");
681 i_push_errorf(T1_errno, "unknown error %d", (int)T1_errno);