static void ttf_instance_setc(struct image_ttf_face_struct *face_s, struct image_ttf_faceinstance_struct *face_i, int towhat, char *where) { TT_Face_Properties prop; TT_Instance_Metrics metr; int res; int resol; if ((res=TT_Get_Face_Properties(face_s->face,&prop))) my_tt_error(where,"TT_Get_Face_Properties",res); resol=58; /* should be 72, but glyphs fit using this value */ /* (int)((72*(prop.horizontal->Ascender+ prop.horizontal->Descender)/ (float)prop.horizontal->Ascender)); */ if ((res=TT_Set_Instance_Resolutions(face_i->instance, (TT_UShort)resol, (TT_UShort)resol))) my_tt_error("Image.TTF.FaceInstance()", "TT_Set_Instance_Resolutions: ",res); if ((res=TT_Get_Instance_Metrics(face_i->instance,&metr))) my_tt_error(where,"TT_Get_Instance_Metrics",res); if ((res=TT_Set_Instance_CharSize(face_i->instance,towhat))) my_tt_error(where,"TT_Set_Instance_CharSize: ",res); face_i->baseline= DOUBLE_TO_INT(((double)(towhat/64.0+towhat/640.0)* prop.horizontal->Ascender)/ (prop.horizontal->Ascender - prop.horizontal->Descender)); face_i->height= (towhat/64 + towhat/640); face_i->trans = ~63 & (32 + DOUBLE_TO_INT(64*((towhat/64.0+towhat/640.0)* prop.horizontal->Ascender)/ (prop.horizontal->Ascender-prop.horizontal->Descender))); }
TTF_Font *TTF_OpenFont(const char *file, int ptsize) { TTF_Font *font; TT_Face_Properties properties; TT_Instance_Metrics imetrics; int i, n; TT_UShort platform, encoding; TT_Error error; font = (TTF_Font *)malloc(sizeof(*font)); if ( font == NULL ) { SDL_SetError("Out of memory"); return(NULL); } memset(font, 0, sizeof(*font)); /* Open the font and create ancillary data */ error = TT_Open_Face(engine, file, &font->face); if ( error ) { SDL_SetError("Couldn't load font file"); free(font); return(NULL); } error = TT_New_Glyph(font->face, &font->glyph); if ( error ) { SDL_SetError("Couldn't create glyph container"); TTF_CloseFont(font); return(NULL); } error = TT_New_Instance(font->face, &font->inst); if ( error ) { SDL_SetError("Couldn't create font instance"); TTF_CloseFont(font); return(NULL); } /* Set the display resolution */ error = TT_Set_Instance_Resolutions(font->inst, 72, 72); if ( error ) { SDL_SetError("Couldn't set font resolution"); TTF_CloseFont(font); return(NULL); } error = TT_Set_Instance_CharSize(font->inst, ptsize*64); if ( error ) { SDL_SetError("Couldn't set font size"); TTF_CloseFont(font); return(NULL); } /* Get a Unicode mapping for this font */ n = TT_Get_CharMap_Count(font->face); for ( i=0; i<n; ++i ) { TT_Get_CharMap_ID(font->face, i, &platform, &encoding); if ( ((platform == TT_PLATFORM_MICROSOFT) && (encoding == TT_MS_ID_UNICODE_CS)) || ((platform == TT_PLATFORM_APPLE_UNICODE) && (encoding == TT_APPLE_ID_DEFAULT)) ) { TT_Get_CharMap(font->face, i, &font->map); break; } } if ( i == n ) { SDL_SetError("Font doesn't have a Unicode mapping"); TTF_CloseFont(font); return(NULL); } /* Get the font metrics for this font */ TT_Get_Face_Properties(font->face, &properties ); TT_Get_Instance_Metrics(font->inst, &imetrics); font->pointsize = imetrics.y_ppem; font->ascent = (float)properties.horizontal->Ascender / properties.header->Units_Per_EM; font->ascent *= font->pointsize; font->descent = (float)properties.horizontal->Descender / properties.header->Units_Per_EM; font->descent *= font->pointsize; font->lineskip = (float)properties.horizontal->Line_Gap / properties.header->Units_Per_EM; font->lineskip *= font->pointsize; font->height = round(font->ascent - font->descent); /* Set the default font style */ font->style = TTF_STYLE_NORMAL; font->glyph_overhang = font->pointsize/10; /* x offset = cos(((90.0-12)/360)*2*M_PI), or 12 degree angle */ font->glyph_italics = 0.207; font->glyph_italics *= font->height; return(font); }
int main( int argc, char** argv ) { int i, orig_ptsize, file; char filename[128 + 4]; char alt_filename[128 + 4]; char* execname; int option; int ptsize; int num_Faces = 0; int glyph_index = 0; int load_flags = TTLOAD_DEFAULT; int force_sbit = 0; TT_Engine engine; TT_Face face; TT_Instance instance; TT_Glyph glyph; TT_Raster_Map map; TT_Big_Glyph_Metrics metrics; TT_Face_Properties properties; TT_Instance_Metrics imetrics; TT_EBLC eblc; TT_SBit_Image* bitmap = NULL; TT_Error error; int res = 72; #ifdef HAVE_LIBINTL_H setlocale( LC_ALL, "" ); bindtextdomain( "freetype", LOCALEDIR ); textdomain( "freetype" ); #endif execname = ft_basename( argv[0] ); while ( 1 ) { option = ft_getopt( argc, argv, "c:r:i:B" ); if ( option == -1 ) break; switch ( option ) { case 'r': res = atoi( ft_optarg ); if ( res < 1 ) usage( execname ); break; case 'c': num_Faces = atoi( ft_optarg ); if ( num_Faces < 0 ) usage( execname ); break; case 'i': glyph_index = atoi( ft_optarg ); if ( glyph_index < 0 ) usage( execname ); break; case 'B': force_sbit = 1; break; default: usage( execname ); break; } } argc -= ft_optind; argv += ft_optind; if ( argc <= 1 ) usage( execname ); if ( sscanf( argv[0], "%d", &orig_ptsize ) != 1 ) orig_ptsize = 64; file = 1; ptsize = orig_ptsize; i = strlen( argv[file] ); while ( i > 0 && argv[file][i] != '\\' && argv[file][i] != '/' ) { if ( argv[file][i] == '.' ) i = 0; i--; } filename[128] = '\0'; alt_filename[128] = '\0'; strncpy( filename, argv[file], 128 ); strncpy( alt_filename, argv[file], 128 ); if ( i >= 0 ) { strncpy( filename + strlen( filename ), ".ttf", 4 ); strncpy( alt_filename + strlen( alt_filename ), ".ttc", 4 ); } /* Initialize engine */ error = TT_Init_FreeType( &engine ); if ( error ) { fprintf( stderr, gettext( "Error while initializing engine.\n" ) ); goto Failure; } error = TT_Init_SBit_Extension( engine ); if ( error ) { fprintf( stderr, gettext( "Error while initializing embedded bitmap extension.\n" ) ); goto Failure; } /* Load face */ error = TT_Open_Face( engine, filename, &face ); if ( error == TT_Err_Could_Not_Open_File ) { strcpy( filename, alt_filename ); error = TT_Open_Face( engine, alt_filename, &face ); } if ( error == TT_Err_Could_Not_Open_File ) Panic( gettext( "Could not find or open %s.\n" ), filename ); if ( error ) { fprintf( stderr, gettext( "Error while opening %s.\n" ), filename ); goto Failure; } TT_Get_Face_Properties( face, &properties ); printf( gettext( "There are %d fonts in this collection.\n" ), (int)(properties.num_Faces) ); if ( num_Faces >= properties.num_Faces ) Panic( gettext( "There is no collection with index %d in this font file.\n" ), num_Faces ); TT_Close_Face( face ); error = TT_Open_Collection( engine, filename, num_Faces, &face ); /* get face properties and eblc */ TT_Get_Face_Properties( face, &properties ); if ( force_sbit ) { error = TT_Get_Face_Bitmaps( face, &eblc ); if ( error == TT_Err_Table_Missing ) Panic( gettext( "There is no embedded bitmap data in the font.\n" ) ); if ( error ) { fprintf( stderr, gettext( "Error while retrieving embedded bitmaps table.\n" ) ); goto Failure; } } /* create glyph */ error = TT_New_Glyph( face, &glyph ); if ( error ) { fprintf( stderr, gettext( "Could not create glyph container.\n" ) ); goto Failure; } /* create instance */ error = TT_New_Instance( face, &instance ); if ( error ) { fprintf( stderr, gettext( "Could not create instance.\n" ) ); goto Failure; } error = TT_Set_Instance_Resolutions( instance, res, res ); if ( error ) { fprintf( stderr, gettext( "Could not set device resolutions.\n" ) ); goto Failure; } error = TT_Set_Instance_CharSize( instance, ptsize*64 ); if ( error ) { fprintf( stderr, gettext( "Could not reset instance.\n" ) ); goto Failure; } TT_Get_Instance_Metrics( instance, &imetrics ); printf( gettext( "Instance metrics: ppemX %d, ppemY %d\n" ), imetrics.x_ppem, imetrics.y_ppem ); if ( force_sbit ) { error = TT_New_SBit_Image( &bitmap ); if ( error ) { fprintf( stderr, gettext( "Could not allocate glyph bitmap container.\n" ) ); goto Failure; } error = TT_Load_Glyph_Bitmap( face, instance, glyph_index, bitmap ); if ( error ) { fprintf( stderr, gettext( "Can't load bitmap for glyph %d.\n" ), glyph_index ); goto Failure; } Show_Metrics( bitmap->metrics, "SBit's metrics" ); printf( "SBit glyph:\n" ); Show_Single_Glyph( &bitmap->map ); } else { TT_Load_Glyph( instance, glyph, glyph_index, load_flags ); TT_Get_Glyph_Big_Metrics( glyph, &metrics ); map.width = ( metrics.bbox.xMax - metrics.bbox.xMin ) / 64; map.rows = ( metrics.bbox.yMax - metrics.bbox.yMin ) / 64; map.cols = ( map.width + 7 ) / 8; map.size = map.cols * map.rows; map.bitmap = malloc( map.size ); map.flow = TT_Flow_Down; memset( map.bitmap, 0, map.size ); error = TT_Get_Glyph_Bitmap( glyph, &map, -metrics.bbox.xMin, -metrics.bbox.yMin ); Show_Metrics( metrics, gettext( "Outline's metrics" ) ); printf( gettext( "Outline glyph\n" ) ); Show_Single_Glyph( &map ); } free( map.bitmap ); if ( bitmap ) TT_Done_SBit_Image( bitmap ); TT_Done_Instance( instance ); TT_Done_Glyph( glyph ); TT_Done_FreeType( engine ); exit( EXIT_SUCCESS ); /* for safety reasons */ return 0; /* never reached */ Failure: fprintf( stderr, " " ); fprintf( stderr, gettext( "FreeType error message: %s\n" ), TT_ErrToString18( error ) ); exit( EXIT_FAILURE ); return 0; /* never reached */ }
static void image_ttf_faceinstance_write(INT32 args) { int **sstr; int *slen; int i,res=0,base=0,a; struct image_ttf_face_struct *face_s; struct image_ttf_faceinstance_struct *face_i=THISi; TT_CharMap charMap; TT_Kerning kerning; int has_kerning = 0; char *errs=NULL; int scalefactor=0; int xmin=1000,xmax=-1000,pos=0,ypos; int width,height,mod; unsigned char* pixmap; int maxcharwidth = 0; if (!(face_s=(struct image_ttf_face_struct*) get_storage(THISi->faceobj,image_ttf_face_program))) Pike_error("Image.TTF.FaceInstance->write(): lost Face\n"); if(!TT_Get_Kerning_Directory( face_s->face, &kerning )) { TT_Instance_Metrics metrics; /* fprintf(stderr, "has kerning!\n"); */ has_kerning = 1; if(TT_Get_Instance_Metrics( face_i->instance, &metrics )) Pike_error("Nope. No way.\n"); scalefactor = metrics.x_scale; /* fprintf(stderr, "offset=%d\n", (int)metrics.x_scale); */ } if (args && sp[-1].type==T_INT) { base=sp[-1].u.integer; args--; pop_stack(); } if (!args) { push_empty_string(); args=1; } ttf_get_nice_charmap(face_s->face,&charMap, "Image.TTF.FaceInstance->write()"); sstr=alloca(args*sizeof(int*)); slen=alloca(args*sizeof(int)); /* first pass: figure out total bounding box */ for (a=0; a<args; a++) { char *errs=NULL; TT_Glyph_Metrics metrics; if (sp[a-args].type!=T_STRING) Pike_error("Image.TTF.FaceInstance->write(): illegal argument %d\n",a+1); switch(sp[a-args].u.string->size_shift) { case 0: ttf_translate_8bit(charMap,(unsigned char*)sp[a-args].u.string->str, sstr+a, DO_NOT_WARN(slen[a]=sp[a-args].u.string->len), base); break; case 1: ttf_translate_16bit(charMap,(unsigned short*)sp[a-args].u.string->str, sstr+a, DO_NOT_WARN(slen[a]=sp[a-args].u.string->len), base); break; case 2: Pike_error("Too wide string for truetype\n"); break; } pos=0; for (i=0; i<slen[a]; i++) { TT_Glyph glyph; int ind; ind=sstr[a][i]; /* fprintf(stderr,"glyph: %d\n",ind); */ if ((res=TT_New_Glyph(face_s->face,&glyph))) { errs="TT_New_Glyph: "; break; } if ((res=TT_Load_Glyph(face_i->instance, glyph, (TT_UShort)ind, (TT_UShort)face_i->load_flags))) { errs="TT_Load_Glyph: "; break; } if ((res=TT_Get_Glyph_Metrics(glyph,&metrics))) { errs="TT_Get_Glyph_Metrics: "; break; } if (pos+metrics.bbox.xMin<xmin) xmin=pos+metrics.bbox.xMin; if (pos+metrics.bbox.xMax>xmax) xmax=pos+metrics.bbox.xMax; if((metrics.bbox.xMax-(metrics.bbox.xMin<0?metrics.bbox.xMin:0)) >maxcharwidth) maxcharwidth = (metrics.bbox.xMax-(metrics.bbox.xMin<0?metrics.bbox.xMin:0)); pos+=metrics.advance; if(has_kerning && i<slen[a]-1) { int kern = find_kerning( kerning, ind, sstr[a][i+1] ); pos += DOUBLE_TO_INT(kern * (scalefactor/65535.0)); } if ((res=TT_Done_Glyph(glyph))) { errs="TT_Done_Glyph: "; break; } } pos -= metrics.advance; pos += metrics.bbox.xMax-metrics.bbox.xMin; if (pos>xmax) xmax=pos; if (errs) { for (i=0; i<a; i++) free(sstr[i]); my_tt_error("Image.TTF.FaceInstance->write()",errs,res); } } pop_n_elems(args); /* fprintf(stderr,"xmin=%f xmax=%f\n",xmin/64.0,xmax/64.0); */ xmin&=~63; width=((xmax-xmin+63)>>6)+4; height=face_i->height*args; mod=(4-(maxcharwidth&3))&3; if (width<1) width=1; if ((pixmap=malloc((maxcharwidth+mod)*face_i->height))) { /* second pass: write the stuff */ TT_Raster_Map rastermap; struct object *o; struct image *img; rgb_group *d; rastermap.rows=face_i->height; rastermap.cols=rastermap.width=maxcharwidth+mod; rastermap.flow=TT_Flow_Down; rastermap.bitmap=pixmap; rastermap.size=rastermap.cols*rastermap.rows; ypos=0; /* fprintf(stderr,"rastermap.rows=%d cols=%d width=%d\n", */ /* rastermap.rows,rastermap.cols,rastermap.width); */ push_int(width); push_int(height); o=clone_object(image_program,2); img=(struct image*)get_storage(o,image_program); d=img->img; for (a=0; a<args; a++) { pos=-xmin; for (i=0; i<slen[a]; i++) { int sw, xp; TT_Glyph glyph; TT_Glyph_Metrics metrics; int ind, x, y; ind=sstr[a][i]; /* fprintf(stderr,"glyph: %d\n",ind); */ if ((res=TT_New_Glyph(face_s->face,&glyph))) { errs="TT_New_Glyph: "; break; } if ((res=TT_Load_Glyph(face_i->instance, glyph, (TT_UShort)ind, (TT_UShort)face_i->load_flags))) { errs="TT_Load_Glyph: "; break; } if ((res=TT_Get_Glyph_Metrics(glyph,&metrics))) { errs="TT_Get_Glyph_Metrics: "; break; } MEMSET(pixmap,0,rastermap.size); if ((res=TT_Get_Glyph_Pixmap(glyph, &rastermap, -metrics.bbox.xMin /*+pos%64*/, face_i->height*64- face_i->trans))) { errs="TT_Get_Glyph_Pixmap: "; break; } sw = metrics.bbox.xMax-(metrics.bbox.xMin<0?metrics.bbox.xMin:0); /* Copy source pixmap to destination image object. */ for(y=0; y<face_i->height; y++) { unsigned int s; unsigned char * source = pixmap+rastermap.width*y; rgb_group *dt=d+(ypos+y)*width+(xp=(metrics.bbox.xMin+pos)/64); for(x=0; x<sw && xp<width; x++,xp++,source++,dt++) if(xp<0 || !(s = *source)) continue; else if((s=dt->r+s) < 256) dt->r=dt->g=dt->b=s; else dt->r=dt->g=dt->b=255; } pos+=metrics.advance; /* if(metrics.bbox.xMin < 0) */ /* pos += metrics.bbox.xMin; */ if(has_kerning && i<slen[a]-1) { int kern = find_kerning( kerning, sstr[a][i], sstr[a][i+1] ); pos += DOUBLE_TO_INT(kern * (scalefactor/65535.0)); /* fprintf(stderr, "Adjusted is %d\n", */ /* (int)(kern * (scalefactor/65535.0))); */ } if ((res=TT_Done_Glyph(glyph))) { errs="TT_Done_Glyph: "; break; } } if (errs) { for (a=0; a<args; a++) free(sstr[a]); free(pixmap); free_object(o); my_tt_error("Image.TTF.FaceInstance->write()",errs,res); } ypos+=face_i->height; } free(pixmap); push_object(o); } else { Pike_error("Image.TTF.FaceInstance->write(): out of memory\n"); } for (a=0; a<args; a++) free(sstr[a]); }
static int i_tt_get_instance( TT_Fonthandle *handle, i_img_dim points, int smooth ) { int i,idx; TT_Error error; mm_log((1,"i_tt_get_instance(handle %p, points %" i_DF ", smooth %d)\n", handle, i_DFc(points), smooth)); if (smooth == -1) { /* Smooth doesn't matter for this search */ for(i=0;i<TT_CHC;i++) { if (handle->instanceh[i].ptsize==points) { mm_log((1,"i_tt_get_instance: in cache - (non selective smoothing search) returning %d\n",i)); return i; } } smooth=1; /* We will be adding a font - add it as smooth then */ } else { /* Smooth doesn't matter for this search */ for(i=0;i<TT_CHC;i++) { if (handle->instanceh[i].ptsize == points && handle->instanceh[i].smooth == smooth) { mm_log((1,"i_tt_get_instance: in cache returning %d\n",i)); return i; } } } /* Found the instance in the cache - return the cache index */ for(idx=0;idx<TT_CHC;idx++) { if (!(handle->instanceh[idx].order)) break; /* find the lru item */ } mm_log((1,"i_tt_get_instance: lru item is %d\n",idx)); mm_log((1,"i_tt_get_instance: lru pointer %p\n", USTRCT(handle->instanceh[idx].instance) )); if ( USTRCT(handle->instanceh[idx].instance) ) { mm_log((1,"i_tt_get_instance: freeing lru item from cache %d\n",idx)); /* Free cached glyphs */ for(i=0;i<256;i++) if ( USTRCT(handle->instanceh[idx].glyphs[i].glyph) ) TT_Done_Glyph( handle->instanceh[idx].glyphs[i].glyph ); for(i=0;i<256;i++) { handle->instanceh[idx].glyphs[i].ch = TT_NOCHAR; USTRCT(handle->instanceh[idx].glyphs[i].glyph)=NULL; } /* Free instance if needed */ TT_Done_Instance( handle->instanceh[idx].instance ); } /* create and initialize instance */ /* FIXME: probably a memory leak on fail */ (void) (( error = TT_New_Instance( handle->face, &handle->instanceh[idx].instance ) ) || ( error = TT_Set_Instance_Resolutions( handle->instanceh[idx].instance, LTT_dpi, LTT_dpi ) ) || ( error = TT_Set_Instance_CharSize( handle->instanceh[idx].instance, points*64 ) ) ); if ( error ) { mm_log((1, "Could not create and initialize instance: error %x.\n", (unsigned)error )); return -1; } /* Now that the instance should the inplace we need to lower all of the ru counts and put `this' one with the highest entry */ for(i=0;i<TT_CHC;i++) handle->instanceh[i].order--; handle->instanceh[idx].order=TT_CHC-1; handle->instanceh[idx].ptsize=points; handle->instanceh[idx].smooth=smooth; TT_Get_Instance_Metrics( handle->instanceh[idx].instance, &(handle->instanceh[idx].imetrics) ); /* Zero the memory for the glyph storage so they are not thought as cached if they haven't been cached since this new font was loaded */ for(i=0;i<256;i++) { handle->instanceh[idx].glyphs[i].ch = TT_NOCHAR; USTRCT(handle->instanceh[idx].glyphs[i].glyph)=NULL; } return idx; }