SWFFont loadSWFFontfromTTF(char *filename) { int i; TT_Engine *engine; TT_Face face; TT_Instance instance; TT_Glyph glyph; TT_Glyph_Metrics metrics; TT_Outline outline; TT_CharMap charmap; TT_Face_Properties properties; TT_UShort pid, eid; TT_Init_FreeType(engine); error = TT_Open_Face(engine, filename, &face); if(error) fprintf(stderr, "Could not open face.\n"); TT_Get_Face_Properties(face, &properties); for(i=0; i<properties->num_CharMaps; ++i) TT_Get_CharMap_ID(face, i, &pid, &eid); TT_Get_CharMap(face, charmapIndex, &charmap); TT_New_Instance(face, &instance); TT_New_Glyph(face, &glyph); for(i=0; i<whatever; ++i) { TT_Load_Glyph(instance, glyph, TT_Char_Index(charmap, i), loadFlags); TT_Get_Glyph_Outline(glyph, &outline); TT_Get_Glyph_Metrics(glyph, &metrics); } TT_Done_FreeType(engine); }
static TT_Error Load_Glyph(TTF_Font *font, Uint16 ch, struct glyph *glyph) { TT_UShort index; TT_Glyph_Metrics metrics; TT_Outline outline; int x_offset; int y_offset; TT_Error error; /* Load the glyph */ index = TT_Char_Index(font->map, UNICODE(ch)); error = TT_Load_Glyph(font->inst, font->glyph, index, TTLOAD_DEFAULT); if ( error ) return error; /* Get the bounding box */ TT_Get_Glyph_Metrics(font->glyph, &metrics); glyph->minx = (metrics.bbox.xMin & -64) / 64; glyph->maxx = ((metrics.bbox.xMax + 63) & -64) / 64; glyph->miny = (metrics.bbox.yMin & -64) / 64; glyph->maxy = ((metrics.bbox.yMax + 63) & -64) / 64; glyph->advance = (metrics.advance & -64) / 64; /* Adjust for bold and italic text */ if ( font->style & TTF_STYLE_BOLD ) { glyph->maxx += font->glyph_overhang; } if ( font->style & TTF_STYLE_ITALIC ) { glyph->maxx += round(font->glyph_italics); } /* Get the bitmap memory */ glyph->bitmap.width = ((glyph->maxx - glyph->minx) + 7) & ~7; glyph->bitmap.rows = font->height; glyph->bitmap.cols = glyph->bitmap.width/8; glyph->bitmap.flow = TT_Flow_Down; glyph->bitmap.size = (glyph->bitmap.rows * glyph->bitmap.cols); if ( glyph->bitmap.size ) { glyph->bitmap.bitmap = malloc(glyph->bitmap.size); if ( ! glyph->bitmap.bitmap ) { error = TT_Err_Out_Of_Memory; goto was_error; } memset(glyph->bitmap.bitmap, 0, glyph->bitmap.size); } else { glyph->bitmap.bitmap = 0; } /* Get the pixmap memory */ glyph->pixmap.width = ((glyph->maxx - glyph->minx) + 3) & ~3; glyph->pixmap.rows = font->height; glyph->pixmap.cols = glyph->pixmap.width; glyph->pixmap.flow = TT_Flow_Down; glyph->pixmap.size = (glyph->pixmap.rows * glyph->pixmap.cols); if ( glyph->pixmap.size ) { glyph->pixmap.bitmap = malloc(glyph->pixmap.size); if ( ! glyph->pixmap.bitmap ) { error = TT_Err_Out_Of_Memory; goto was_error; } memset(glyph->pixmap.bitmap, 0, glyph->pixmap.size); } else { glyph->pixmap.bitmap = 0; } /* Render the glyph into the bitmap and pixmap */ error = TT_Get_Glyph_Outline(font->glyph, &outline); /* Handle the italic style */ if ( font->style & TTF_STYLE_ITALIC ) { TT_Matrix shear; shear.xx = 1<<16; shear.xy = (int)(font->glyph_italics*(1<<16))/font->height; shear.yx = 0; shear.yy = 1<<16; TT_Transform_Outline(&outline, &shear); } x_offset = -glyph->minx * 64; y_offset = -round(font->descent) * 64; TT_Translate_Outline(&outline, x_offset, y_offset); error += TT_Get_Outline_Bitmap(engine, &outline, &glyph->bitmap); error += TT_Get_Outline_Pixmap(engine, &outline, &glyph->pixmap); /* Handle the bold style */ if ( font->style & TTF_STYLE_BOLD ) { int row, col; int offset; int pixel; Uint8 *pixmap; /* The bitmap is easy, just render another copy */ for ( offset=0; offset < font->glyph_overhang; ++offset ) { TT_Translate_Outline(&outline, 64, 0); error += TT_Get_Outline_Bitmap(engine, &outline,&glyph->bitmap); } x_offset += font->glyph_overhang*64; /* The pixmap is a little harder, we have to add and clamp */ for ( row=glyph->pixmap.rows-1; row >= 0; --row ) { pixmap = (Uint8 *)glyph->pixmap.bitmap + row*glyph->pixmap.cols; for (offset=1; offset<=font->glyph_overhang; ++offset) { for (col=glyph->pixmap.cols-1; col > 0; --col) { pixel=(pixmap[col]+pixmap[col-1]); if ( pixel > 4 ) { pixel = 4; } pixmap[col] = (Uint8)pixel; } } } } TT_Translate_Outline(&outline, -x_offset, -y_offset); was_error: if ( error ) { if ( glyph->bitmap.bitmap ) { free(glyph->bitmap.bitmap); glyph->bitmap.bitmap = 0; } if ( glyph->pixmap.bitmap ) { free(glyph->pixmap.bitmap); glyph->pixmap.bitmap = 0; } return error; } /* We're done, mark this glyph cached */ glyph->cached = ch; return TT_Err_Ok; }
static void image_ttf_faceinstance_ponder(INT32 args) { int *sstr; int len,i,res,base=0; struct image_ttf_face_struct *face_s; struct image_ttf_faceinstance_struct *face_i=THISi; int xmin=1000,xmax=-1000,pos=0; if (!(face_s=(struct image_ttf_face_struct*) get_storage(THISi->faceobj,image_ttf_face_program))) Pike_error("Image.TTF.FaceInstance->ponder(): lost Face\n"); if (args && sp[-1].type==T_INT) { base=sp[-1].u.integer; args--; pop_stack(); } if (sp[-args].type!=T_STRING) Pike_error("Image.TTF.FaceInstance->ponder(): illegal argument 1\n"); switch( sp[-args].u.string->size_shift ) { case 0: ttf_please_translate_8bit(face_s->face, sp[-args].u.string,&sstr,&len,base, "Image.TTF.FaceInstance->ponder()"); break; case 1: ttf_please_translate_16bit(face_s->face, sp[-args].u.string,&sstr,&len,base, "Image.TTF.FaceInstance->ponder()"); break; default: Pike_error("Too wide string for truetype\n"); } pop_n_elems(args); for (i=0; i<len; i++) { TT_Glyph glyph; TT_Glyph_Metrics metrics; int ind; ind=sstr[i]; /* fprintf(stderr,"glyph: %d\n",ind); */ if ((res=TT_New_Glyph(face_s->face,&glyph))) my_tt_error("Image.TTF.FaceInstance->ponder()","TT_New_Glyph: ",res); if ((res=TT_Load_Glyph(face_i->instance, glyph, (TT_UShort)ind, (TT_UShort)face_i->load_flags))) my_tt_error("Image.TTF.FaceInstance->ponder()","TT_Load_Glyph: ",res); if ((res=TT_Get_Glyph_Metrics(glyph,&metrics))) my_tt_error("Image.TTF.FaceInstance->ponder()", "TT_Get_Glyph_Metrics: ",res); if (pos+metrics.bbox.xMin<xmin) xmin=pos+metrics.bbox.xMin; if (pos+metrics.bbox.xMax>xmax) xmax=pos+metrics.bbox.xMax; pos+=metrics.advance; /* insert kerning stuff here */ /* fprintf(stderr,"bbox: (%f,%f)-(%f,%f)\n", */ /* metrics.bbox.xMin/64.0, */ /* metrics.bbox.yMin/64.0, */ /* metrics.bbox.xMax/64.0, */ /* metrics.bbox.yMax/64.0); */ /* fprintf(stderr,"BearingX: %f\n",metrics.bearingX/64.0); */ /* fprintf(stderr,"BearingY: %f\n",metrics.bearingY/64.0); */ /* fprintf(stderr,"advance: %f\n",metrics.advance/64.0); */ /* fprintf(stderr,"\n"); */ } free(sstr); /* fprintf(stderr,"xmin: %f\n",xmin/64.0); */ /* fprintf(stderr,"xmax: %f\n",xmax/64.0); */ ref_push_object(THISOBJ); }
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_glyph( TT_Fonthandle *handle, int inst, unsigned long j) { unsigned short load_flags, code; TT_Error error; mm_log((1, "i_tt_get_glyph(handle %p, inst %d, j %lu (%c))\n", handle,inst,j, (int)((j >= ' ' && j <= '~') ? j : '.'))); /*mm_log((1, "handle->instanceh[inst].glyphs[j]=0x%08X\n",handle->instanceh[inst].glyphs[j] ));*/ if ( TT_VALID(handle->instanceh[inst].glyphs[TT_HASH(j)].glyph) && handle->instanceh[inst].glyphs[TT_HASH(j)].ch == j) { mm_log((1,"i_tt_get_glyph: %lu in cache\n",j)); return 1; } if ( TT_VALID(handle->instanceh[inst].glyphs[TT_HASH(j)].glyph) ) { /* clean up the entry */ TT_Done_Glyph( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph ); USTRCT( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph ) = NULL; handle->instanceh[inst].glyphs[TT_HASH(j)].ch = TT_NOCHAR; } /* Ok - it wasn't cached - try to get it in */ load_flags = TTLOAD_SCALE_GLYPH; if ( LTT_hinted ) load_flags |= TTLOAD_HINT_GLYPH; if ( !TT_VALID(handle->char_map) ) { code = (j - ' ' + 1) < 0 ? 0 : (j - ' ' + 1); if ( code >= handle->properties.num_Glyphs ) code = 0; } else code = TT_Char_Index( handle->char_map, j ); if ( (error = TT_New_Glyph( handle->face, &handle->instanceh[inst].glyphs[TT_HASH(j)].glyph)) ) { mm_log((1, "Cannot allocate and load glyph: error %#x.\n", (unsigned)error )); i_push_error(error, "TT_New_Glyph()"); return 0; } if ( (error = TT_Load_Glyph( handle->instanceh[inst].instance, handle->instanceh[inst].glyphs[TT_HASH(j)].glyph, code, load_flags)) ) { mm_log((1, "Cannot allocate and load glyph: error %#x.\n", (unsigned)error )); /* Don't leak */ TT_Done_Glyph( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph ); USTRCT( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph ) = NULL; i_push_error(error, "TT_Load_Glyph()"); return 0; } /* At this point the glyph should be allocated and loaded */ handle->instanceh[inst].glyphs[TT_HASH(j)].ch = j; /* Next get the glyph metrics */ error = TT_Get_Glyph_Metrics( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph, &handle->instanceh[inst].gmetrics[TT_HASH(j)] ); if (error) { mm_log((1, "TT_Get_Glyph_Metrics: error %#x.\n", (unsigned)error )); TT_Done_Glyph( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph ); USTRCT( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph ) = NULL; handle->instanceh[inst].glyphs[TT_HASH(j)].ch = TT_NOCHAR; i_push_error(error, "TT_Get_Glyph_Metrics()"); return 0; } return 1; }