18 font.c - implements font handling functions for t1 and truetype fonts
25 fontnum = i_t1_new(path_to_pfb, path_to_afm);
26 i_t1_bbox(fontnum, points, "foo", 3, int cords[6]);
27 rc = i_t1_destroy(fontnum);
31 handle = i_tt_new(path_to_ttf);
32 rc = i_tt_bbox(handle, points, "foo", 3, int cords[6]);
39 font.c implements font creation, rendering, bounding box functions and
42 =head1 FUNCTION REFERENCE
44 Some of these functions are internal.
63 Initialize font rendering libraries if they are avaliable.
69 i_init_fonts(int t1log) {
70 mm_log((1,"Initializing fonts\n"));
85 return(1); /* FIXME: Always true - check the return values of the init_t1 and init_tt functions */
96 =item i_init_t1(t1log)
98 Initializes the t1lib font rendering engine.
104 i_init_t1(int t1log) {
105 int init_flags = IGNORE_CONFIGFILE|IGNORE_FONTDATABASE;
106 mm_log((1,"init_t1()\n"));
109 init_flags |= LOGFILE;
110 if ((T1_InitLib(init_flags) == NULL)){
111 mm_log((1,"Initialization of t1lib failed\n"));
114 T1_SetLogLevel(T1LOG_DEBUG);
115 i_t1_set_aa(1); /* Default Antialias value */
123 Shuts the t1lib font rendering engine down.
125 This it seems that this function is never used.
137 =item i_t1_new(pfb, afm)
139 Loads the fonts with the given filenames, returns its font id
141 pfb - path to pfb file for font
142 afm - path to afm file for font
148 i_t1_new(char *pfb,char *afm) {
150 mm_log((1,"i_t1_new(pfb %s,afm %s)\n",pfb,(afm?afm:"NULL")));
151 font_id = T1_AddFont(pfb);
153 mm_log((1,"i_t1_new: Failed to load pfb file '%s' - return code %d.\n",pfb,font_id));
158 mm_log((1,"i_t1_new: requesting afm file '%s'.\n",afm));
159 if (T1_SetAfmFileName(font_id,afm)<0) mm_log((1,"i_t1_new: afm loading of '%s' failed.\n",afm));
165 =item i_t1_destroy(font_id)
167 Frees resources for a t1 font with given font id.
169 font_id - number of the font to free
175 i_t1_destroy(int font_id) {
176 mm_log((1,"i_t1_destroy(font_id %d)\n",font_id));
177 return T1_DeleteFont(font_id);
182 =item i_t1_set_aa(st)
184 Sets the antialiasing level of the t1 library.
186 st - 0 = NONE, 1 = LOW, 2 = HIGH.
192 i_t1_set_aa(int st) {
194 unsigned long cst[17];
197 T1_AASetBitsPerPixel( 8 );
198 T1_AASetLevel( T1_AA_NONE );
199 T1_AANSetGrayValues( 0, 255 );
200 mm_log((1,"setting T1 antialias to none\n"));
203 T1_AASetBitsPerPixel( 8 );
204 T1_AASetLevel( T1_AA_LOW );
205 T1_AASetGrayValues( 0,65,127,191,255 );
206 mm_log((1,"setting T1 antialias to low\n"));
209 T1_AASetBitsPerPixel(8);
210 T1_AASetLevel(T1_AA_HIGH);
211 for(i=0;i<17;i++) cst[i]=(i*255)/16;
212 T1_AAHSetGrayValues( cst );
213 mm_log((1,"setting T1 antialias to high\n"));
219 =item i_t1_cp(im, xb, yb, channel, fontnum, points, str, len, align)
221 Interface to text rendering into a single channel in an image
223 im pointer to image structure
224 xb x coordinate of start of string
225 yb y coordinate of start of string ( see align )
226 channel - destination channel
227 fontnum - t1 library font id
228 points - number of points in fontheight
229 str - string to render
231 align - (0 - top of font glyph | 1 - baseline )
237 i_t1_cp(i_img *im,int xb,int yb,int channel,int fontnum,float points,char* str,int len,int align) {
242 unsigned int ch_mask_store;
244 if (im == NULL) { mm_log((1,"i_t1_cp: Null image in input\n")); return(0); }
246 glyph=T1_AASetString( fontnum, str, len, 0, T1_KERNING, points, NULL);
250 mm_log((1,"metrics: ascent: %d descent: %d\n",glyph->metrics.ascent,glyph->metrics.descent));
251 mm_log((1," leftSideBearing: %d rightSideBearing: %d\n",glyph->metrics.leftSideBearing,glyph->metrics.rightSideBearing));
252 mm_log((1," advanceX: %d advanceY: %d\n",glyph->metrics.advanceX,glyph->metrics.advanceY));
253 mm_log((1,"bpp: %d\n",glyph->bpp));
255 xsize=glyph->metrics.rightSideBearing-glyph->metrics.leftSideBearing;
256 ysize=glyph->metrics.ascent-glyph->metrics.descent;
258 mm_log((1,"width: %d height: %d\n",xsize,ysize));
260 ch_mask_store=im->ch_mask;
261 im->ch_mask=1<<channel;
263 if (align==1) { xb+=glyph->metrics.leftSideBearing; yb-=glyph->metrics.ascent; }
265 for(y=0;y<ysize;y++) for(x=0;x<xsize;x++) {
266 val.channel[channel]=glyph->bits[y*xsize+x];
267 i_ppix(im,x+xb,y+yb,&val);
270 im->ch_mask=ch_mask_store;
276 =item i_t1_bbox(handle, fontnum, points, str, len, cords)
278 function to get a strings bounding box given the font id and sizes
280 handle - pointer to font handle
281 fontnum - t1 library font id
282 points - number of points in fontheight
283 str - string to measure
285 cords - the bounding box (modified in place)
291 i_t1_bbox(int fontnum,float points,char *str,int len,int cords[6]) {
295 mm_log((1,"i_t1_bbox(fontnum %d,points %.2f,str '%.*s', len %d)\n",fontnum,points,len,str,len));
296 T1_LoadFont(fontnum); /* FIXME: Here a return code is ignored - haw haw haw */
297 bbox = T1_GetStringBBox(fontnum,str,len,0,T1_KERNING);
298 gbbox = T1_GetFontBBox(fontnum);
300 mm_log((1,"bbox: (%d,%d,%d,%d)\n",
301 (int)(bbox.llx*points/1000),
302 (int)(gbbox.lly*points/1000),
303 (int)(bbox.urx*points/1000),
304 (int)(gbbox.ury*points/1000),
305 (int)(bbox.lly*points/1000),
306 (int)(bbox.ury*points/1000) ));
309 cords[0]=((float)bbox.llx*points)/1000;
310 cords[2]=((float)bbox.urx*points)/1000;
312 cords[1]=((float)gbbox.lly*points)/1000;
313 cords[3]=((float)gbbox.ury*points)/1000;
315 cords[4]=((float)bbox.lly*points)/1000;
316 cords[5]=((float)bbox.ury*points)/1000;
321 =item i_t1_text(im, xb, yb, cl, fontnum, points, str, len, align)
323 Interface to text rendering in a single color onto an image
325 im - pointer to image structure
326 xb - x coordinate of start of string
327 yb - y coordinate of start of string ( see align )
328 cl - color to draw the text in
329 fontnum - t1 library font id
330 points - number of points in fontheight
331 str - char pointer to string to render
333 align - (0 - top of font glyph | 1 - baseline )
339 i_t1_text(i_img *im,int xb,int yb,i_color *cl,int fontnum,float points,char* str,int len,int align) {
341 int xsize,ysize,x,y,ch;
345 if (im == NULL) { mm_log((1,"i_t1_cp: Null image in input\n")); return(0); }
347 glyph=T1_AASetString( fontnum, str, len, 0, T1_KERNING, points, NULL);
351 mm_log((1,"metrics: ascent: %d descent: %d\n",glyph->metrics.ascent,glyph->metrics.descent));
352 mm_log((1," leftSideBearing: %d rightSideBearing: %d\n",glyph->metrics.leftSideBearing,glyph->metrics.rightSideBearing));
353 mm_log((1," advanceX: %d advanceY: %d\n",glyph->metrics.advanceX,glyph->metrics.advanceY));
354 mm_log((1,"bpp: %d\n",glyph->bpp));
356 xsize=glyph->metrics.rightSideBearing-glyph->metrics.leftSideBearing;
357 ysize=glyph->metrics.ascent-glyph->metrics.descent;
359 mm_log((1,"width: %d height: %d\n",xsize,ysize));
361 if (align==1) { xb+=glyph->metrics.leftSideBearing; yb-=glyph->metrics.ascent; }
363 for(y=0;y<ysize;y++) for(x=0;x<xsize;x++) {
364 c=glyph->bits[y*xsize+x];
366 i_gpix(im,x+xb,y+yb,&val);
367 for(ch=0;ch<im->channels;ch++) val.channel[ch]=(c*cl->channel[ch]+i*val.channel[ch])/255;
368 i_ppix(im,x+xb,y+yb,&val);
374 #endif /* HAVE_LIBT1 */
385 /* Truetype font support */
392 #define USTRCT(x) ((x).z)
393 #define TT_VALID( handle ) ( ( handle ).z != NULL )
398 static int i_tt_get_instance( TT_Fonthandle *handle, int points, int smooth );
399 static void i_tt_init_raster_map( TT_Raster_Map* bit, int width, int height, int smooth );
400 static void i_tt_done_raster_map( TT_Raster_Map *bit );
401 static void i_tt_clear_raster_map( TT_Raster_Map* bit );
402 static void i_tt_blit_or( TT_Raster_Map *dst, TT_Raster_Map *src,int x_off, int y_off );
403 static int i_tt_get_glyph( TT_Fonthandle *handle, int inst, unsigned char j );
404 static void i_tt_render_glyph( TT_Glyph glyph, TT_Glyph_Metrics* gmetrics, TT_Raster_Map *bit, TT_Raster_Map *small_bit, int x_off, int y_off, int smooth );
405 static void i_tt_render_all_glyphs( TT_Fonthandle *handle, int inst, TT_Raster_Map *bit, TT_Raster_Map *small_bit, int cords[6], char* txt, int len, int smooth );
406 static void i_tt_dump_raster_map2( i_img* im, TT_Raster_Map* bit, int xb, int yb, i_color *cl, int smooth );
407 static void i_tt_dump_raster_map_channel( i_img* im, TT_Raster_Map* bit, int xb, int yb, int channel, int smooth );
408 static int i_tt_rasterize( TT_Fonthandle *handle, TT_Raster_Map *bit, int cords[6], float points, char* txt, int len, int smooth );
409 static undef_int i_tt_bbox_inst( TT_Fonthandle *handle, int inst ,const char *txt, int len, int cords[6] );
412 /* static globals needed */
414 static TT_Engine engine;
415 static int LTT_dpi = 72; /* FIXME: this ought to be a part of the call interface */
416 static int LTT_hinted = 1; /* FIXME: this too */
427 Initializes the freetype font rendering engine
435 mm_log((1,"init_tt()\n"));
436 error = TT_Init_FreeType( &engine );
438 mm_log((1,"Initialization of freetype failed, code = 0x%x\n",error));
446 =item i_tt_get_instance(handle, points, smooth)
448 Finds a points+smooth instance or if one doesn't exist in the cache
449 allocates room and returns its cache entry
451 fontname - path to the font to load
452 handle - handle to the font.
453 points - points of the requested font
454 smooth - boolean (True: antialias on, False: antialias is off)
461 i_tt_get_instance( TT_Fonthandle *handle, int points, int smooth ) {
465 mm_log((1,"i_tt_get_instance(handle 0x%X, points %d, smooth %d)\n",handle,points,smooth));
467 if (smooth == -1) { /* Smooth doesn't matter for this search */
468 for(i=0;i<TT_CHC;i++) if (handle->instanceh[i].ptsize==points) {
469 mm_log((1,"i_tt_get_instance: in cache - (non selective smoothing search) returning %d\n",i));
472 smooth=1; /* We will be adding a font - add it as smooth then */
473 } else { /* Smooth doesn't matter for this search */
474 for(i=0;i<TT_CHC;i++) if (handle->instanceh[i].ptsize==points && handle->instanceh[i].smooth==smooth) {
475 mm_log((1,"i_tt_get_instance: in cache returning %d\n",i));
480 /* Found the instance in the cache - return the cache index */
482 for(idx=0;idx<TT_CHC;idx++) if (!(handle->instanceh[idx].order)) break; /* find the lru item */
484 mm_log((1,"i_tt_get_instance: lru item is %d\n",idx));
485 mm_log((1,"i_tt_get_instance: lru pointer 0x%X\n",USTRCT(handle->instanceh[idx].instance) ));
487 if ( USTRCT(handle->instanceh[idx].instance) ) {
488 mm_log((1,"i_tt_get_instance: freeing lru item from cache %d\n",idx));
489 /* Free cached glyphs */
492 if ( USTRCT(handle->instanceh[idx].glyphs[i]) )
493 TT_Done_Glyph( handle->instanceh[idx].glyphs[i] );
495 for(i=0;i<256;i++) USTRCT(handle->instanceh[idx].glyphs[i])=NULL;
496 TT_Done_Instance( handle->instanceh[idx].instance ); /* Free instance if needed */
500 /* create and initialize instance */
501 /* FIXME: probably a memory leak on fail */
503 (void) (( error = TT_New_Instance( handle->face, &handle->instanceh[idx].instance ) ) ||
504 ( error = TT_Set_Instance_Resolutions( handle->instanceh[idx].instance, LTT_dpi, LTT_dpi ) ) ||
505 ( error = TT_Set_Instance_CharSize( handle->instanceh[idx].instance, points*64 ) ) );
508 mm_log((1, "Could not create and initialize instance: error 0x%x.\n",error ));
512 /* Now that the instance should the inplace we need to lower all of the
513 ru counts and put `this' one with the highest entry */
515 for(i=0;i<TT_CHC;i++) handle->instanceh[i].order--;
517 handle->instanceh[idx].order=TT_CHC-1;
518 handle->instanceh[idx].ptsize=points;
519 handle->instanceh[idx].smooth=smooth;
520 TT_Get_Instance_Metrics( handle->instanceh[idx].instance, &(handle->instanceh[idx].imetrics) );
522 /* Zero the memory for the glyph storage so they are not thought as cached if they haven't been cached
523 since this new font was loaded */
525 for(i=0;i<256;i++) USTRCT(handle->instanceh[idx].glyphs[i])=NULL;
532 =item i_tt_new(fontname)
534 Creates a new font handle object, finds a character map and initialise the
535 the font handle's cache
537 fontname - path to the font to load
543 i_tt_new(char *fontname) {
545 TT_Fonthandle *handle;
547 unsigned short platform,encoding;
549 mm_log((1,"i_tt_new(fontname '%s')\n",fontname));
551 /* allocate memory for the structure */
553 handle = mymalloc( sizeof(TT_Fonthandle) );
555 /* load the typeface */
556 error = TT_Open_Face( engine, fontname, &handle->face );
558 if ( error == TT_Err_Could_Not_Open_File ) { mm_log((1, "Could not find/open %s.\n", fontname )) }
559 else { mm_log((1, "Error while opening %s, error code = 0x%x.\n",fontname, error )); }
563 TT_Get_Face_Properties( handle->face, &(handle->properties) );
564 /* First, look for a Unicode charmap */
566 n = handle->properties.num_CharMaps;
567 USTRCT( handle->char_map )=NULL; /* Invalidate character map */
569 for ( i = 0; i < n; i++ ) {
570 TT_Get_CharMap_ID( handle->face, i, &platform, &encoding );
571 if ( (platform == 3 && encoding == 1 ) || (platform == 0 && encoding == 0 ) ) {
572 mm_log((2,"i_tt_new - found char map platform %u encoding %u\n", platform, encoding));
573 TT_Get_CharMap( handle->face, i, &(handle->char_map) );
577 if (!USTRCT(handle->char_map) && n != 0) {
578 /* just use the first one */
579 TT_Get_CharMap( handle->face, 0, &(handle->char_map));
582 /* Zero the pointsizes - and ordering */
584 for(i=0;i<TT_CHC;i++) {
585 USTRCT(handle->instanceh[i].instance)=NULL;
586 handle->instanceh[i].order=i;
587 handle->instanceh[i].ptsize=0;
588 handle->instanceh[i].smooth=-1;
591 mm_log((1,"i_tt_new <- 0x%X\n",handle));
598 * raster map management
602 =item i_tt_init_raster_map(bit, width, height, smooth)
604 Allocates internal memory for the bitmap as needed by the parameters (internal)
606 bit - bitmap to allocate into
607 width - width of the bitmap
608 height - height of the bitmap
609 smooth - boolean (True: antialias on, False: antialias is off)
616 i_tt_init_raster_map( TT_Raster_Map* bit, int width, int height, int smooth ) {
618 mm_log((1,"i_tt_init_raster_map( bit 08x%08X, width %d, height %d, smooth %d)\n", bit, width, height, smooth));
621 bit->width = ( width + 3 ) & -4;
622 bit->flow = TT_Flow_Down;
625 bit->cols = bit->width;
626 bit->size = bit->rows * bit->width;
628 bit->cols = ( bit->width + 7 ) / 8; /* convert to # of bytes */
629 bit->size = bit->rows * bit->cols; /* number of bytes in buffer */
632 mm_log((1,"i_tt_init_raster_map: bit->width %d, bit->cols %d, bit->rows %d, bit->size %d)\n", bit->width, bit->cols, bit->rows, bit->size ));
634 bit->bitmap = (void *) mymalloc( bit->size );
635 if ( !bit->bitmap ) m_fatal(0,"Not enough memory to allocate bitmap (%d)!\n",bit->size );
640 =item i_tt_clear_raster_map(bit)
642 Frees the bitmap data and sets pointer to NULL (internal)
651 i_tt_done_raster_map( TT_Raster_Map *bit ) {
652 myfree( bit->bitmap );
658 =item i_tt_clear_raster_map(bit)
660 Clears the specified bitmap (internal)
670 i_tt_clear_raster_map( TT_Raster_Map* bit ) {
671 memset( bit->bitmap, 0, bit->size );
676 =item i_tt_blit_or(dst, src, x_off, y_off)
678 function that blits one raster map into another (internal)
680 dst - destination bitmap
682 x_off - x offset into the destination bitmap
683 y_off - y offset into the destination bitmap
690 i_tt_blit_or( TT_Raster_Map *dst, TT_Raster_Map *src,int x_off, int y_off ) {
695 x1 = x_off < 0 ? -x_off : 0;
696 y1 = y_off < 0 ? -y_off : 0;
698 x2 = (int)dst->cols - x_off;
699 if ( x2 > src->cols ) x2 = src->cols;
701 y2 = (int)dst->rows - y_off;
702 if ( y2 > src->rows ) y2 = src->rows;
704 if ( x1 >= x2 ) return;
706 /* do the real work now */
708 for ( y = y1; y < y2; ++y ) {
709 s = ( (char*)src->bitmap ) + y * src->cols + x1;
710 d = ( (char*)dst->bitmap ) + ( y + y_off ) * dst->cols + x1 + x_off;
712 for ( x = x1; x < x2; ++x ) {
721 /* useful for debugging */
724 static void dump_raster_map(FILE *out, TT_Raster_Map *bit ) {
726 fprintf(out, "cols %d rows %d flow %d\n", bit->cols, bit->rows, bit->flow);
727 for (y = 0; y < bit->rows; ++y) {
728 fprintf(out, "%2d:", y);
729 for (x = 0; x < bit->cols; ++x) {
730 if ((x & 7) == 0 && x) putc(' ', out);
731 fprintf(out, "%02x", ((unsigned char *)bit->bitmap)[y*bit->cols+x]);
740 =item i_tt_get_glyph(handle, inst, j)
742 Function to see if a glyph exists and if so cache it (internal)
744 handle - pointer to font handle
746 j - charcode of glyph
753 i_tt_get_glyph( TT_Fonthandle *handle, int inst, unsigned char j) { /* FIXME: Check if unsigned char is enough */
754 unsigned short load_flags, code;
757 mm_log((1, "i_tt_get_glyph(handle 0x%X, inst %d, j %d (%c))\n",handle,inst,j,j));
758 mm_log((1, "handle->instanceh[inst].glyphs[j]=0x%08X\n",handle->instanceh[inst].glyphs[j] ));
760 if ( TT_VALID(handle->instanceh[inst].glyphs[j]) ) {
761 mm_log((1,"i_tt_get_glyph: %d in cache\n",j));
765 /* Ok - it wasn't cached - try to get it in */
766 load_flags = TTLOAD_SCALE_GLYPH;
767 if ( LTT_hinted ) load_flags |= TTLOAD_HINT_GLYPH;
769 if ( !TT_VALID(handle->char_map) ) {
770 code = (j - ' ' + 1) < 0 ? 0 : (j - ' ' + 1);
771 if ( code >= handle->properties.num_Glyphs ) code = 0;
772 } else code = TT_Char_Index( handle->char_map, j );
774 if ( (error = TT_New_Glyph( handle->face, &handle->instanceh[inst].glyphs[j])) )
775 mm_log((1, "Cannot allocate and load glyph: error 0x%x.\n", error ));
776 if ( (error = TT_Load_Glyph( handle->instanceh[inst].instance, handle->instanceh[inst].glyphs[j], code, load_flags)) )
777 mm_log((1, "Cannot allocate and load glyph: error 0x%x.\n", error ));
779 /* At this point the glyph should be allocated and loaded */
780 /* Next get the glyph metrics */
782 error = TT_Get_Glyph_Metrics( handle->instanceh[inst].glyphs[j], &handle->instanceh[inst].gmetrics[j] );
783 mm_log((1, "TT_Get_Glyph_Metrics: error 0x%x.\n", error ));
789 =item i_tt_destroy(handle)
791 Clears the data taken by a font including all cached data such as
794 handle - pointer to font handle
800 i_tt_destroy( TT_Fonthandle *handle) {
801 TT_Close_Face( handle->face );
804 /* FIXME: Should these be freed automatically by the library?
806 TT_Done_Instance( instance );
808 i_tt_done_glyphs( void ) {
811 if ( !glyphs ) return;
813 for ( i = 0; i < 256; ++i ) TT_Done_Glyph( glyphs[i] );
823 * FreeType Rendering functions
828 =item i_tt_render_glyph(handle, gmetrics, bit, smallbit, x_off, y_off, smooth)
830 Renders a single glyph into the bit rastermap (internal)
832 handle - pointer to font handle
833 gmetrics - the metrics for the glyph to be rendered
834 bit - large bitmap that is the destination for the text
835 smallbit - small bitmap that is used only if smooth is true
836 x_off - x offset of glyph
837 y_off - y offset of glyph
838 smooth - boolean (True: antialias on, False: antialias is off)
845 i_tt_render_glyph( TT_Glyph glyph, TT_Glyph_Metrics* gmetrics, TT_Raster_Map *bit, TT_Raster_Map *small_bit, int x_off, int y_off, int smooth ) {
847 mm_log((1,"i_tt_render_glyph(glyph 0x0%X, gmetrics 0x0%X, bit 0x%X, small_bit 0x%X, x_off %d, y_off %d, smooth %d)\n",
848 USTRCT(glyph), gmetrics, bit, small_bit, x_off,y_off,smooth));
850 if ( !smooth ) TT_Get_Glyph_Bitmap( glyph, bit, x_off * 64, y_off * 64);
852 TT_F26Dot6 xmin, ymin, xmax, ymax;
854 xmin = gmetrics->bbox.xMin & -64;
855 ymin = gmetrics->bbox.yMin & -64;
856 xmax = (gmetrics->bbox.xMax + 63) & -64;
857 ymax = (gmetrics->bbox.yMax + 63) & -64;
859 i_tt_clear_raster_map( small_bit );
860 TT_Get_Glyph_Pixmap( glyph, small_bit, -xmin, -ymin );
861 i_tt_blit_or( bit, small_bit, xmin/64 + x_off, -ymin/64 - y_off );
867 =item i_tt_render_all_glyphs(handle, inst, bit, small_bit, cords, txt, len, smooth)
869 calls i_tt_render_glyph to render each glyph into the bit rastermap (internal)
871 handle - pointer to font handle
873 bit - large bitmap that is the destination for the text
874 smallbit - small bitmap that is used only if smooth is true
875 txt - string to render
876 len - length of the string to render
877 smooth - boolean (True: antialias on, False: antialias is off)
884 i_tt_render_all_glyphs( TT_Fonthandle *handle, int inst, TT_Raster_Map *bit, TT_Raster_Map *small_bit, int cords[6], char* txt, int len, int smooth ) {
889 mm_log((1,"i_tt_render_all_glyphs( handle 0x%X, inst %d, bit 0x%X, small_bit 0x%X, txt '%.*s', len %d, smooth %d)\n",
890 handle, inst, bit, small_bit, len, txt, len, smooth));
893 y=-( handle->properties.horizontal->Descender * handle->instanceh[inst].imetrics.y_ppem )/(handle->properties.header->Units_Per_EM);
896 x=-cords[0]; /* FIXME: If you font is antialiased this should be expanded by one to allow for aa expansion and the allocation too - do before passing here */
899 for ( i = 0; i < len; i++ ) {
901 if ( !i_tt_get_glyph(handle,inst,j) ) continue;
902 i_tt_render_glyph( handle->instanceh[inst].glyphs[j], &handle->instanceh[inst].gmetrics[j], bit, small_bit, x, y, smooth );
903 x += handle->instanceh[inst].gmetrics[j].advance / 64;
909 * Functions to render rasters (single channel images) onto images
913 =item i_tt_dump_raster_map2(im, bit, xb, yb, cl, smooth)
915 Function to dump a raster onto an image in color used by i_tt_text() (internal).
917 im - image to dump raster on
918 bit - bitmap that contains the text to be dumped to im
919 xb, yb - coordinates, left edge and baseline
920 cl - color to use for text
921 smooth - boolean (True: antialias on, False: antialias is off)
928 i_tt_dump_raster_map2( i_img* im, TT_Raster_Map* bit, int xb, int yb, i_color *cl, int smooth ) {
932 mm_log((1,"i_tt_dump_raster_map2(im 0x%x, bit 0x%X, xb %d, yb %d, cl 0x%X)\n",im,bit,xb,yb,cl));
934 bmap = (char *)bit->bitmap;
938 for(y=0;y<bit->rows;y++) for(x=0;x<bit->width;x++) {
939 c=(255*bmap[y*(bit->cols)+x])/4;
941 i_gpix(im,x+xb,y+yb,&val);
942 for(ch=0;ch<im->channels;ch++) val.channel[ch]=(c*cl->channel[ch]+i*val.channel[ch])/255;
943 i_ppix(im,x+xb,y+yb,&val);
948 for(y=0;y<bit->rows;y++) for(x=0;x<bit->width;x++) {
949 c=( bmap[y*bit->cols+x/8] & (128>>(x%8)) ) ? 255 : 0;
951 i_gpix(im,x+xb,y+yb,&val);
952 for(ch=0;ch<im->channels;ch++) val.channel[ch]=(c*cl->channel[ch]+i*val.channel[ch])/255;
953 i_ppix(im,x+xb,y+yb,&val);
961 =item i_tt_dump_raster_map_channel(im, bit, xb, yb, channel, smooth)
963 Function to dump a raster onto a single channel image in color (internal)
965 im - image to dump raster on
966 bit - bitmap that contains the text to be dumped to im
967 xb, yb - coordinates, left edge and baseline
968 channel - channel to copy to
969 smooth - boolean (True: antialias on, False: antialias is off)
976 i_tt_dump_raster_map_channel( i_img* im, TT_Raster_Map* bit, int xb, int yb, int channel, int smooth ) {
981 mm_log((1,"i_tt_dump_raster_channel(im 0x%x, bit 0x%X, xb %d, yb %d, channel %d)\n",im,bit,xb,yb,channel));
983 bmap = (char *)bit->bitmap;
986 for(y=0;y<bit->rows;y++) for(x=0;x<bit->width;x++) {
987 c=(255*bmap[y*(bit->cols)+x])/4;
988 i_gpix(im,x+xb,y+yb,&val);
989 val.channel[channel]=c;
990 i_ppix(im,x+xb,y+yb,&val);
993 for(y=0;y<bit->rows;y++) for(x=0;x<bit->width;x++) {
994 c=( bmap[y*bit->cols+x/8] & (128>>(x%8)) ) ? 255 : 0;
995 i_gpix(im,x+xb,y+yb,&val);
996 val.channel[channel]=c;
997 i_ppix(im,x+xb,y+yb,&val);
1004 =item i_tt_rasterize(handle, bit, cords, points, txt, len, smooth)
1006 interface for generating single channel raster of text (internal)
1008 handle - pointer to font handle
1009 bit - the bitmap that is allocated, rendered into and NOT freed
1010 cords - the bounding box (modified in place)
1011 points - font size to use
1012 txt - string to render
1013 len - length of the string to render
1014 smooth - boolean (True: antialias on, False: antialias is off)
1021 i_tt_rasterize( TT_Fonthandle *handle, TT_Raster_Map *bit, int cords[6], float points, char* txt, int len, int smooth ) {
1024 TT_Raster_Map small_bit;
1026 /* find or install an instance */
1027 if ( (inst=i_tt_get_instance(handle,points,smooth)) < 0) {
1028 mm_log((1,"i_tt_rasterize: get instance failed\n"));
1032 /* calculate bounding box */
1033 i_tt_bbox_inst( handle, inst, txt, len, cords );
1035 width = cords[2]-cords[0];
1036 height = cords[5]-cords[4];
1038 mm_log((1,"i_tt_rasterize: width=%d, height=%d\n",width, height ));
1040 i_tt_init_raster_map ( bit, width, height, smooth );
1041 i_tt_clear_raster_map( bit );
1042 if ( smooth ) i_tt_init_raster_map( &small_bit, handle->instanceh[inst].imetrics.x_ppem + 32, height, smooth );
1044 i_tt_render_all_glyphs( handle, inst, bit, &small_bit, cords, txt, len, smooth );
1046 /* ascent = ( handle->properties.horizontal->Ascender * handle->instanceh[inst].imetrics.y_ppem ) / handle->properties.header->Units_Per_EM; */
1048 if ( smooth ) i_tt_done_raster_map( &small_bit );
1055 * Exported text rendering interfaces
1060 =item i_tt_cp(handle, im, xb, yb, channel, points, txt, len, smooth)
1062 Interface to text rendering into a single channel in an image
1064 handle - pointer to font handle
1065 im - image to render text on to
1066 xb, yb - coordinates, left edge and baseline
1067 channel - channel to render into
1068 points - font size to use
1069 txt - string to render
1070 len - length of the string to render
1071 smooth - boolean (True: antialias on, False: antialias is off)
1077 i_tt_cp( TT_Fonthandle *handle, i_img *im, int xb, int yb, int channel, float points, char* txt, int len, int smooth ) {
1080 int ascent, st_offset;
1083 if (! i_tt_rasterize( handle, &bit, cords, points, txt, len, smooth ) ) return 0;
1088 i_tt_dump_raster_map_channel( im, &bit, xb-st_offset , yb-ascent, channel, smooth );
1089 i_tt_done_raster_map( &bit );
1096 =item i_tt_text(handle, im, xb, yb, cl, points, txt, len, smooth)
1098 Interface to text rendering in a single color onto an image
1100 handle - pointer to font handle
1101 im - image to render text on to
1102 xb, yb - coordinates, left edge and baseline
1103 cl - color to use for text
1104 points - font size to use
1105 txt - string to render
1106 len - length of the string to render
1107 smooth - boolean (True: antialias on, False: antialias is off)
1113 i_tt_text( TT_Fonthandle *handle, i_img *im, int xb, int yb, i_color *cl, float points, char* txt, int len, int smooth) {
1115 int ascent, st_offset;
1118 if (! i_tt_rasterize( handle, &bit, cords, points, txt, len, smooth ) ) return 0;
1123 i_tt_dump_raster_map2( im, &bit, xb+st_offset, yb-ascent, cl, smooth );
1124 i_tt_done_raster_map( &bit );
1131 =item i_tt_bbox_inst(handle, inst, txt, len, cords)
1133 Function to get texts bounding boxes given the instance of the font (internal)
1135 handle - pointer to font handle
1136 inst - font instance
1137 txt - string to measure
1138 len - length of the string to render
1139 cords - the bounding box (modified in place)
1146 i_tt_bbox_inst( TT_Fonthandle *handle, int inst ,const char *txt, int len, int cords[6] ) {
1147 int i, upm, ascent, descent, gascent, gdescent, width, casc, cdesc, first, start;
1149 unsigned char *ustr;
1150 ustr=(unsigned char*)txt;
1152 mm_log((1,"i_tt_box_inst(handle 0x%X,inst %d,txt '%.*s', len %d)\n",handle,inst,len,txt,len));
1154 upm = handle->properties.header->Units_Per_EM;
1155 gascent = ( handle->properties.horizontal->Ascender * handle->instanceh[inst].imetrics.y_ppem + upm - 1) / upm;
1156 gdescent = ( handle->properties.horizontal->Descender * handle->instanceh[inst].imetrics.y_ppem - upm + 1) / upm;
1161 mm_log((1, "i_tt_box_inst: gascent=%d gdescent=%d\n", gascent, gdescent));
1164 for ( i = 0; i < len; ++i ) {
1166 if ( i_tt_get_glyph(handle,inst,j) ) {
1167 TT_Glyph_Metrics *gm = handle->instanceh[inst].gmetrics + j;
1168 width += gm->advance / 64;
1169 casc = (gm->bbox.yMax+63) / 64;
1170 cdesc = (gm->bbox.yMin-63) / 64;
1172 mm_log((1, "i_tt_box_inst: glyph='%c' casc=%d cdesc=%d\n", j, casc, cdesc));
1175 start = gm->bbox.xMin / 64;
1176 ascent = (gm->bbox.yMax+63) / 64;
1177 descent = (gm->bbox.yMin-63) / 64;
1181 /* the right-side bearing - in case the right-side of a
1182 character goes past the right of the advance width,
1183 as is common for italic fonts
1185 int rightb = gm->advance - gm->bearingX
1186 - (gm->bbox.xMax - gm->bbox.xMin);
1187 /* fprintf(stderr, "font info last: %d %d %d %d\n",
1188 gm->bbox.xMax, gm->bbox.xMin, gm->advance, rightb); */
1193 ascent = (ascent > casc ? ascent : casc );
1194 descent = (descent < cdesc ? descent : cdesc);
1209 =item i_tt_bbox(handle, points, txt, len, cords)
1211 Interface to get a strings bounding box
1213 handle - pointer to font handle
1214 points - font size to use
1215 txt - string to render
1216 len - length of the string to render
1217 cords - the bounding box (modified in place)
1223 i_tt_bbox( TT_Fonthandle *handle, float points,char *txt,int len,int cords[6]) {
1226 mm_log((1,"i_tt_box(handle 0x%X,points %f,txt '%.*s', len %d)\n",handle,points,len,txt,len));
1228 if ( (inst=i_tt_get_instance(handle,points,-1)) < 0) {
1229 mm_log((1,"i_tt_text: get instance failed\n"));
1233 return i_tt_bbox_inst(handle, inst, txt, len, cords);
1238 #endif /* HAVE_LIBTT */
1246 Arnar M. Hrafnkelsson <addi@umich.edu>