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));
100 mm_log((1,"i_t1_new: requesting afm file '%s'.\n",afm));
101 if (T1_SetAfmFileName(font_id,afm)<0) mm_log((1,"i_t1_new: afm loading of '%s' failed.\n",afm));
110 =item i_t1_destroy(font_id)
112 Frees resources for a t1 font with given font id.
114 font_id - number of the font to free
120 i_t1_destroy(int font_id) {
121 mm_log((1,"i_t1_destroy(font_id %d)\n",font_id));
125 return T1_DeleteFont(font_id);
130 =item i_t1_set_aa(st)
132 Sets the antialiasing level of the t1 library.
134 st - 0 = NONE, 1 = LOW, 2 = HIGH.
140 i_t1_set_aa(int st) {
142 unsigned long cst[17];
145 T1_AASetBitsPerPixel( 8 );
146 T1_AASetLevel( T1_AA_NONE );
147 T1_AANSetGrayValues( 0, 255 );
148 mm_log((1,"setting T1 antialias to none\n"));
151 T1_AASetBitsPerPixel( 8 );
152 T1_AASetLevel( T1_AA_LOW );
153 T1_AASetGrayValues( 0,65,127,191,255 );
154 mm_log((1,"setting T1 antialias to low\n"));
157 T1_AASetBitsPerPixel(8);
158 T1_AASetLevel(T1_AA_HIGH);
159 for(i=0;i<17;i++) cst[i]=(i*255)/16;
160 T1_AAHSetGrayValues( cst );
161 mm_log((1,"setting T1 antialias to high\n"));
167 =item i_t1_cp(im, xb, yb, channel, fontnum, points, str, len, align)
169 Interface to text rendering into a single channel in an image
171 im pointer to image structure
172 xb x coordinate of start of string
173 yb y coordinate of start of string ( see align )
174 channel - destination channel
175 fontnum - t1 library font id
176 points - number of points in fontheight
177 str - string to render
179 align - (0 - top of font glyph | 1 - baseline )
185 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) {
189 int mod_flags = t1_get_flags(flags);
191 unsigned int ch_mask_store;
193 if (im == NULL) { mm_log((1,"i_t1_cp: Null image in input\n")); return(0); }
197 char *work = t1_from_utf8(str, len, &worklen);
198 glyph=T1_AASetString( fontnum, work, worklen, 0, mod_flags, points, NULL);
202 glyph=T1_AASetString( fontnum, str, len, 0, mod_flags, points, NULL);
207 mm_log((1,"metrics: ascent: %d descent: %d\n",glyph->metrics.ascent,glyph->metrics.descent));
208 mm_log((1," leftSideBearing: %d rightSideBearing: %d\n",glyph->metrics.leftSideBearing,glyph->metrics.rightSideBearing));
209 mm_log((1," advanceX: %d advanceY: %d\n",glyph->metrics.advanceX,glyph->metrics.advanceY));
210 mm_log((1,"bpp: %d\n",glyph->bpp));
212 xsize=glyph->metrics.rightSideBearing-glyph->metrics.leftSideBearing;
213 ysize=glyph->metrics.ascent-glyph->metrics.descent;
215 mm_log((1,"width: %d height: %d\n",xsize,ysize));
217 ch_mask_store=im->ch_mask;
218 im->ch_mask=1<<channel;
220 if (align==1) { xb+=glyph->metrics.leftSideBearing; yb-=glyph->metrics.ascent; }
222 for(y=0;y<ysize;y++) for(x=0;x<xsize;x++) {
223 val.channel[channel]=glyph->bits[y*xsize+x];
224 i_ppix(im,x+xb,y+yb,&val);
227 im->ch_mask=ch_mask_store;
232 t1_fix_bbox(BBox *bbox, const char *str, size_t len, int advance,
233 int space_position) {
234 /* never called with len == 0 */
235 if (str[0] == space_position && bbox->llx > 0)
237 if (str[len-1] == space_position && bbox->urx < advance)
239 if (bbox->lly > bbox->ury)
240 bbox->lly = bbox->ury = 0;
244 =item i_t1_bbox(handle, fontnum, points, str, len, cords)
246 function to get a strings bounding box given the font id and sizes
248 handle - pointer to font handle
249 fontnum - t1 library font id
250 points - number of points in fontheight
251 str - string to measure
253 cords - the bounding box (modified in place)
259 i_t1_bbox(int fontnum, double points,const char *str,size_t len, i_img_dim cords[6], int utf8,char const *flags) {
262 int mod_flags = t1_get_flags(flags);
264 int space_position = T1_GetEncodingIndex(fontnum, "space");
266 mm_log((1,"i_t1_bbox(fontnum %d,points %.2f,str '%.*s', len %d)\n",fontnum,points,len,str,len));
267 T1_LoadFont(fontnum); /* FIXME: Here a return code is ignored - haw haw haw */
270 /* len == 0 has special meaning to T1lib, but it means there's
271 nothing to draw, so return that */
272 bbox.llx = bbox.lly = bbox.urx = bbox.ury = 0;
278 char *work = t1_from_utf8(str, len, &worklen);
279 advance = T1_GetStringWidth(fontnum, work, worklen, 0, mod_flags);
280 bbox = T1_GetStringBBox(fontnum,work,worklen,0,mod_flags);
281 t1_fix_bbox(&bbox, work, worklen, advance, space_position);
285 advance = T1_GetStringWidth(fontnum, (char *)str, len, 0, mod_flags);
286 bbox = T1_GetStringBBox(fontnum,(char *)str,len,0,mod_flags);
287 t1_fix_bbox(&bbox, str, len, advance, space_position);
290 gbbox = T1_GetFontBBox(fontnum);
292 mm_log((1,"bbox: (%d,%d,%d,%d)\n",
293 (int)(bbox.llx*points/1000),
294 (int)(gbbox.lly*points/1000),
295 (int)(bbox.urx*points/1000),
296 (int)(gbbox.ury*points/1000),
297 (int)(bbox.lly*points/1000),
298 (int)(bbox.ury*points/1000) ));
301 cords[BBOX_NEG_WIDTH]=((double)bbox.llx*points)/1000;
302 cords[BBOX_POS_WIDTH]=((double)bbox.urx*points)/1000;
304 cords[BBOX_GLOBAL_DESCENT]=((double)gbbox.lly*points)/1000;
305 cords[BBOX_GLOBAL_ASCENT]=((double)gbbox.ury*points)/1000;
307 cords[BBOX_DESCENT]=((double)bbox.lly*points)/1000;
308 cords[BBOX_ASCENT]=((double)bbox.ury*points)/1000;
310 cords[BBOX_ADVANCE_WIDTH] = ((double)advance * points)/1000;
311 cords[BBOX_RIGHT_BEARING] =
312 cords[BBOX_ADVANCE_WIDTH] - cords[BBOX_POS_WIDTH];
314 return BBOX_RIGHT_BEARING+1;
319 =item i_t1_text(im, xb, yb, cl, fontnum, points, str, len, align)
321 Interface to text rendering in a single color onto an image
323 im - pointer to image structure
324 xb - x coordinate of start of string
325 yb - y coordinate of start of string ( see align )
326 cl - color to draw the text in
327 fontnum - t1 library font id
328 points - number of points in fontheight
329 str - char pointer to string to render
331 align - (0 - top of font glyph | 1 - baseline )
337 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) {
340 int mod_flags = t1_get_flags(flags);
343 if (im == NULL) { mm_log((1,"i_t1_cp: Null image in input\n")); return(0); }
347 char *work = t1_from_utf8(str, len, &worklen);
348 glyph=T1_AASetString( fontnum, work, worklen, 0, mod_flags, points, NULL);
352 /* T1_AASetString() accepts a char * not a const char */
353 glyph=T1_AASetString( fontnum, (char *)str, len, 0, mod_flags, points, NULL);
358 mm_log((1,"metrics: ascent: %d descent: %d\n",glyph->metrics.ascent,glyph->metrics.descent));
359 mm_log((1," leftSideBearing: %d rightSideBearing: %d\n",glyph->metrics.leftSideBearing,glyph->metrics.rightSideBearing));
360 mm_log((1," advanceX: %d advanceY: %d\n",glyph->metrics.advanceX,glyph->metrics.advanceY));
361 mm_log((1,"bpp: %d\n",glyph->bpp));
363 xsize=glyph->metrics.rightSideBearing-glyph->metrics.leftSideBearing;
364 ysize=glyph->metrics.ascent-glyph->metrics.descent;
366 mm_log((1,"width: %d height: %d\n",xsize,ysize));
368 if (align==1) { xb+=glyph->metrics.leftSideBearing; yb-=glyph->metrics.ascent; }
370 r = i_render_new(im, xsize);
371 for(y=0;y<ysize;y++) {
372 i_render_color(r, xb, yb+y, xsize, (unsigned char *)glyph->bits+y*xsize, cl);
380 =item t1_get_flags(flags)
382 Processes the characters in I<flags> to create a mod_flags value used
383 by some T1Lib functions.
388 t1_get_flags(char const *flags) {
389 int mod_flags = T1_KERNING;
393 case 'u': case 'U': mod_flags |= T1_UNDERLINE; break;
394 case 'o': case 'O': mod_flags |= T1_OVERLINE; break;
395 case 's': case 'S': mod_flags |= T1_OVERSTRIKE; break;
396 /* ignore anything we don't recognize */
404 =item t1_from_utf8(char const *in, size_t len, int *outlen)
406 Produces an unencoded version of I<in> by dropping any Unicode
409 Returns a newly allocated buffer which should be freed with myfree().
410 Sets *outlen to the number of bytes used in the output string.
416 t1_from_utf8(char const *in, size_t len, int *outlen) {
417 /* at this point len is from a STRLEN which should be size_t and can't
418 be too big for mymalloc */
419 char *out = mymalloc(len+1); /* rechecked 29jul11 tonyc */
424 c = i_utf8_advance(&in, &len);
427 i_push_error(0, "invalid UTF8 character");
430 /* yeah, just drop them */
442 =item i_t1_has_chars(font_num, text, len, utf8, out)
444 Check if the given characters are defined by the font. Note that len
445 is the number of bytes, not the number of characters (when utf8 is
448 out[char index] will be true if the character exists.
450 Accepts UTF-8, but since T1 can only have 256 characters, any chars
451 with values over 255 will simply be returned as false.
453 Returns the number of characters that were checked.
459 i_t1_has_chars(int font_num, const char *text, size_t len, int utf8,
463 mm_log((1, "i_t1_has_chars(font_num %d, text %p, len %d, utf8 %d)\n",
464 font_num, text, len, utf8));
467 if (T1_LoadFont(font_num)) {
475 c = i_utf8_advance(&text, &len);
477 i_push_error(0, "invalid UTF8 character");
482 c = (unsigned char)*text++;
487 /* limit of 256 characters for T1 */
491 char const * name = T1_GetCharName(font_num, (unsigned char)c);
494 *out++ = strcmp(name, ".notdef") != 0;
497 mm_log((2, " No name found for character %lx\n", c));
508 =item i_t1_face_name(font_num, name_buf, name_buf_size)
510 Copies the face name of the given C<font_num> to C<name_buf>. Returns
511 the number of characters required to store the name (which can be
512 larger than C<name_buf_size>, including the space required to store
513 the terminating NUL).
515 If name_buf is too small (as specified by name_buf_size) then the name
516 will be truncated. name_buf will always be NUL termintaed.
522 i_t1_face_name(int font_num, char *name_buf, size_t name_buf_size) {
526 if (T1_LoadFont(font_num)) {
530 name = T1_GetFontName(font_num);
533 strncpy(name_buf, name, name_buf_size);
534 name_buf[name_buf_size-1] = '\0';
535 return strlen(name) + 1;
544 i_t1_glyph_name(int font_num, unsigned long ch, char *name_buf,
545 size_t name_buf_size) {
552 if (T1_LoadFont(font_num)) {
556 name = T1_GetCharName(font_num, (unsigned char)ch);
558 if (strcmp(name, ".notdef")) {
559 strncpy(name_buf, name, name_buf_size);
560 name_buf[name_buf_size-1] = '\0';
561 return strlen(name) + 1;
574 t1_push_error(void) {
577 i_push_error(0, "No error");
580 #ifdef T1ERR_SCAN_FONT_FORMAT
581 case T1ERR_SCAN_FONT_FORMAT:
582 i_push_error(T1ERR_SCAN_FONT_FORMAT, "SCAN_FONT_FORMAT");
586 #ifdef T1ERR_SCAN_FILE_OPEN_ERR
587 case T1ERR_SCAN_FILE_OPEN_ERR:
588 i_push_error(T1ERR_SCAN_FILE_OPEN_ERR, "SCAN_FILE_OPEN_ERR");
592 #ifdef T1ERR_SCAN_OUT_OF_MEMORY
593 case T1ERR_SCAN_OUT_OF_MEMORY:
594 i_push_error(T1ERR_SCAN_OUT_OF_MEMORY, "SCAN_OUT_OF_MEMORY");
598 #ifdef T1ERR_SCAN_ERROR
599 case T1ERR_SCAN_ERROR:
600 i_push_error(T1ERR_SCAN_ERROR, "SCAN_ERROR");
604 #ifdef T1ERR_SCAN_FILE_EOF
605 case T1ERR_SCAN_FILE_EOF:
606 i_push_error(T1ERR_SCAN_FILE_EOF, "SCAN_FILE_EOF");
610 #ifdef T1ERR_PATH_ERROR
611 case T1ERR_PATH_ERROR:
612 i_push_error(T1ERR_PATH_ERROR, "PATH_ERROR");
616 #ifdef T1ERR_PARSE_ERROR
617 case T1ERR_PARSE_ERROR:
618 i_push_error(T1ERR_PARSE_ERROR, "PARSE_ERROR");
622 #ifdef T1ERR_TYPE1_ABORT
623 case T1ERR_TYPE1_ABORT:
624 i_push_error(T1ERR_TYPE1_ABORT, "TYPE1_ABORT");
628 #ifdef T1ERR_INVALID_FONTID
629 case T1ERR_INVALID_FONTID:
630 i_push_error(T1ERR_INVALID_FONTID, "INVALID_FONTID");
634 #ifdef T1ERR_INVALID_PARAMETER
635 case T1ERR_INVALID_PARAMETER:
636 i_push_error(T1ERR_INVALID_PARAMETER, "INVALID_PARAMETER");
640 #ifdef T1ERR_OP_NOT_PERMITTED
641 case T1ERR_OP_NOT_PERMITTED:
642 i_push_error(T1ERR_OP_NOT_PERMITTED, "OP_NOT_PERMITTED");
646 #ifdef T1ERR_ALLOC_MEM
647 case T1ERR_ALLOC_MEM:
648 i_push_error(T1ERR_ALLOC_MEM, "ALLOC_MEM");
652 #ifdef T1ERR_FILE_OPEN_ERR
653 case T1ERR_FILE_OPEN_ERR:
654 i_push_error(T1ERR_FILE_OPEN_ERR, "FILE_OPEN_ERR");
658 #ifdef T1ERR_UNSPECIFIED
659 case T1ERR_UNSPECIFIED:
660 i_push_error(T1ERR_UNSPECIFIED, "UNSPECIFIED");
664 #ifdef T1ERR_NO_AFM_DATA
665 case T1ERR_NO_AFM_DATA:
666 i_push_error(T1ERR_NO_AFM_DATA, "NO_AFM_DATA");
672 i_push_error(T1ERR_X11, "X11");
676 #ifdef T1ERR_COMPOSITE_CHAR
677 case T1ERR_COMPOSITE_CHAR:
678 i_push_error(T1ERR_COMPOSITE_CHAR, "COMPOSITE_CHAR");
683 i_push_errorf(T1_errno, "unknown error %d", (int)T1_errno);