static void i_tt_render_glyph( TT_Glyph glyph, TT_Glyph_Metrics* gmetrics, TT_Raster_Map *bit, TT_Raster_Map *small_bit, i_img_dim x_off, i_img_dim y_off, int smooth ) { mm_log((1,"i_tt_render_glyph(glyph %p, gmetrics %p, bit %p, small_bit %p, x_off %" i_DF ", y_off %" i_DF ", smooth %d)\n", USTRCT(glyph), gmetrics, bit, small_bit, i_DFc(x_off), i_DFc(y_off), smooth)); if ( !smooth ) TT_Get_Glyph_Bitmap( glyph, bit, x_off * 64, y_off * 64); else { TT_F26Dot6 xmin, ymin; xmin = gmetrics->bbox.xMin & -64; ymin = gmetrics->bbox.yMin & -64; i_tt_clear_raster_map( small_bit ); TT_Get_Glyph_Pixmap( glyph, small_bit, -xmin, -ymin ); i_tt_blit_or( bit, small_bit, xmin/64 + x_off, -ymin/64 - y_off ); } }
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]); }