int ExportImage(char *filename,SplineChar *sc, int layer, int format, int pixelsize, int bitsperpixel) { /* 0=*.xbm, 1=*.bmp, 2=*.png, 3=*.xpm, 4=*.c(fontforge-internal) */ struct _GImage base; GImage gi; GClut clut; BDFChar *bdfc; int ret; int tot, i; uint8 *pt, *end; int scale; void *freetypecontext; double emsize = sc->parent->ascent+sc->parent->descent; if ( autohint_before_generate && sc->changedsincelasthinted && !sc->manualhints ) SplineCharAutoHint(sc,layer,NULL); memset(&gi,'\0', sizeof(gi)); memset(&base,'\0', sizeof(base)); memset(&clut,'\0', sizeof(clut)); gi.u.image = &base; if ( bitsperpixel==1 ) { if ( (freetypecontext = FreeTypeFontContext(sc->parent,sc,NULL,layer))==NULL ) bdfc = SplineCharRasterize(sc,layer,pixelsize); else { bdfc = SplineCharFreeTypeRasterize(freetypecontext,sc->orig_pos,pixelsize,72,1); FreeTypeFreeContext(freetypecontext); } BCRegularizeBitmap(bdfc); /* People don't seem to like having a minimal bounding box for their */ /* images. */ BCExpandBitmapToEmBox(bdfc, 0, (int) rint(sc->parent->ascent*pixelsize/emsize)-pixelsize, (int) rint(sc->width*pixelsize/emsize), (int) rint(sc->parent->ascent*pixelsize/emsize)); /* Sigh. Bitmaps use a different defn of set than images do. make it consistant */ tot = bdfc->bytes_per_line*(bdfc->ymax-bdfc->ymin+1); for ( pt = bdfc->bitmap, end = pt+tot; pt<end; *pt++ ^= 0xff ); base.image_type = it_mono; base.data = bdfc->bitmap; base.bytes_per_line = bdfc->bytes_per_line; base.width = bdfc->xmax-bdfc->xmin+1; base.height = bdfc->ymax-bdfc->ymin+1; base.trans = -1; if ( format==0 ) ret = !GImageWriteXbm(&gi,filename); #ifndef _NO_LIBPNG else if ( format==2 ) ret = GImageWritePng(&gi,filename,false); #endif else if ( format==3 ) ret = !GImageWriteXpm(&gi,filename); else if ( format==4 ) ret = !GImageWriteGImage(&gi,filename); else ret = GImageWriteBmp(&gi,filename); BDFCharFree(bdfc); } else { if ( (freetypecontext = FreeTypeFontContext(sc->parent,sc,NULL,layer))==NULL ) bdfc = SplineCharAntiAlias(sc,pixelsize,layer,(1<<(bitsperpixel/2))); else { bdfc = SplineCharFreeTypeRasterize(freetypecontext,sc->orig_pos,pixelsize,72,bitsperpixel); FreeTypeFreeContext(freetypecontext); } BCRegularizeGreymap(bdfc); BCExpandBitmapToEmBox(bdfc, 0, (int) rint(sc->parent->ascent*pixelsize/emsize) - pixelsize, (int) rint(sc->width*pixelsize/emsize), (int) rint(sc->parent->ascent*pixelsize/emsize)); base.image_type = it_index; base.data = bdfc->bitmap; base.bytes_per_line = bdfc->bytes_per_line; base.width = bdfc->xmax-bdfc->xmin+1; base.height = bdfc->ymax-bdfc->ymin+1; base.clut = &clut; base.trans = -1; clut.clut_len = 1<<bitsperpixel; clut.is_grey = true; clut.trans_index = -1; scale = 255/((1<<bitsperpixel)-1); scale = COLOR_CREATE(scale,scale,scale); for ( i=0; i< 1<<bitsperpixel; ++i ) clut.clut[(1<<bitsperpixel)-1 - i] = i*scale; #ifndef _NO_LIBPNG if ( format==2 ) ret = GImageWritePng(&gi,filename,false); else #endif ret = GImageWriteBmp(&gi,filename); BDFCharFree(bdfc); } return( ret ); }
void AW_FindFontParameters(WidthInfo *wi) { DBounds bb; SplineFont *sf=wi->sf; unsigned i, j; int si=-1; real caph, ds, xh, serifsize, angle, ca, seriflength = 0; int cnt; static unichar_t caps[] = { 'A', 'Z', 0x391, 0x3a9, 0x40f, 0x418, 0x41a, 0x42f, 0 }; static unichar_t descent[] = { 'p','q','g','y','j', 0x3c8, 0x3b7, 0x3b3, 0x3b2, 0x3b6, 0x3bc, 0x3be, 0x3c1, 0x3c6, 0x444, 0x443, 0x458, 0x434, 0 }; static unichar_t xheight[] = { 'x','u','v','w','y','z', 0x3b3, 0x3b9, 0x3ba, 0x3bc, 0x3bd, 0x3c0, 0x3c4, 0x3c5, 0x3c7, 0x3c8, 0x432, 0x433, 0x436, 0x438, 0x43a, 0x43d, 0x43f, 0x442, 0x443, 0x445, 0x446, 0x447, 0x448, 0x449, 0 }; static unichar_t easyserif[] = { 'I','B','D','E','F','H','K','L','N','P','R', 0x399, 0x406, 0x392, 0x393, 0x395, 0x397, 0x39a, 0x3a0, 0x3a1, 0x40a, 0x412, 0x413, 0x415, 0x41a, 0x41d, 0x41f, 0x420, 0x428, 0 }; real stemx, testx, y, ytop, ybottom, yorig, topx, bottomx; caph = 0; cnt = 0; for ( i=0; caps[i]!='\0' && cnt<5; i+=2 ) for ( j=caps[i]; j<=caps[i+1] && cnt<5; ++j ) if ( (si=SFFindExistingSlot(sf,j,NULL))!=-1 && sf->glyphs[si]!=NULL ) { SplineCharQuickBounds(sf->glyphs[si],&bb); caph += bb.maxy; ++cnt; } if ( cnt!=0 ) caph /= cnt; else caph = sf->ascent; for ( i=0; descent[i]!='\0'; ++i ) if ( (si=SFFindExistingSlot(sf,descent[i],NULL))!=-1 && sf->glyphs[si]!=NULL ) break; if ( descent[i]!='\0' ) { SplineCharQuickBounds(sf->glyphs[si],&bb); ds = bb.miny; } else ds = -sf->descent; cnt = 0; xh = 0; for ( i=0; xheight[i]!='\0' && cnt<5; ++i ) if ( (si=SFFindExistingSlot(sf,xheight[i],NULL))!=-1 && sf->glyphs[si]!=NULL ) { SplineCharQuickBounds(sf->glyphs[si],&bb); xh += bb.maxy; ++cnt; } if ( cnt!=0 ) xh /= cnt; else xh = 3*caph/4; for ( i=0; easyserif[i]!='\0'; ++i ) if ( (si=SFFindExistingSlot(sf,easyserif[i],NULL))!=-1 && sf->glyphs[si]!=NULL ) break; if ( si!=-1 ) { topx = SCFindMinXAtY(sf->glyphs[si],wi->layer,2*caph/3); bottomx = SCFindMinXAtY(sf->glyphs[si],wi->layer,caph/3); /* Some fonts don't sit on the baseline... */ SplineCharQuickBounds(sf->glyphs[si],&bb); /* beware of slanted (italic, oblique) fonts */ ytop = caph/2; ybottom=bb.miny; stemx = SCFindMinXAtY(sf->glyphs[si],wi->layer,ytop); if ( topx==bottomx ) { ca = 0; yorig = 0; /* Irrelevant because we will multiply it by 0, but makes gcc happy */ while ( ytop-ybottom>=.5 ) { y = (ytop+ybottom)/2; testx = SCFindMinXAtY(sf->glyphs[si],wi->layer,y); if ( testx+1>=stemx ) ytop = y; else ybottom = y; } } else { angle = atan2(caph/3,topx-bottomx); ca = cos(angle); yorig = ytop; while ( ytop-ybottom>=.5 ) { y = (ytop+ybottom)/2; testx = SCFindMinXAtY(sf->glyphs[si],wi->layer,y)+ (yorig-y)*ca; if ( testx+4>=stemx ) /* the +4 is to counteract rounding */ ytop = y; else ybottom = y; } } /* If "I" has a curved stem then it's probably in a script style and */ /* serifs don't really make sense (or not the simplistic ones I deal with) */ if ( ytop<=bb.miny+.5 || SCIsMinXAtYCurved(sf->glyphs[si],wi->layer,caph/2) ) serifsize = 0; else if ( ytop>caph/4 ) serifsize = /*.06*(sf->ascent+sf->descent)*/ 0; else serifsize = ytop-bb.miny; if ( serifsize!=0 ) { y = serifsize/4 + bb.miny; testx = SCFindMinXAtY(sf->glyphs[si],wi->layer,y); if ( testx==NOTREACHED ) serifsize=0; else { testx += (yorig-y)*ca; seriflength = stemx-testx; if ( seriflength < (sf->ascent+sf->descent)/200 ) serifsize = 0; } } } else serifsize = .06*(sf->ascent+sf->descent); serifsize = rint(serifsize); if ( seriflength>.1*(sf->ascent+sf->descent) || serifsize<0 ) { seriflength = 0; /* that's an unreasonable value, we must be wrong */ serifsize = 0; } if ( (si=SFFindExistingSlot(sf,'n',"n"))!=-1 && sf->glyphs[si]!=NULL ) { SplineChar *sc = sf->glyphs[si]; if ( sc->changedsincelasthinted && !sc->manualhints ) SplineCharAutoHint(sc,wi->layer,NULL); SplineCharQuickBounds(sc,&bb); if ( sc->vstem!=NULL && sc->vstem->next!=NULL ) { wi->n_stem_exterior_width = sc->vstem->next->start+sc->vstem->next->width- sc->vstem->start; wi->n_stem_interior_width = sc->vstem->next->start- (sc->vstem->start+sc->vstem->width); } if ( wi->n_stem_exterior_width<bb.maxx-bb.minx-3*seriflength || wi->n_stem_exterior_width>bb.maxx-bb.minx+seriflength || wi->n_stem_interior_width <= 0 ) { wi->n_stem_exterior_width = bb.maxx-bb.minx - 2*seriflength; /* guess that the stem width is somewhere around the seriflength and */ /* one quarter of the character width */ wi->n_stem_interior_width = wi->n_stem_exterior_width - seriflength - wi->n_stem_exterior_width/4; } } if ( ((si=SFFindExistingSlot(sf,'I',"I"))!=-1 && sf->glyphs[si]!=NULL ) || ((si=SFFindExistingSlot(sf,0x399,"Iota"))!=-1 && sf->glyphs[si]!=NULL ) || ((si=SFFindExistingSlot(sf,0x406,"afii10055"))!=-1 && sf->glyphs[si]!=NULL ) ) { SplineChar *sc = sf->glyphs[si]; SplineCharQuickBounds(sc,&bb); wi->current_I_spacing = sc->width - (bb.maxx-bb.minx); } wi->caph = caph; wi->descent = ds; wi->xheight = xh; wi->serifsize = serifsize; wi->seriflength = seriflength; wi->decimation = caph<=1?10:caph/60; if ( serifsize==0 ) { wi->serifs[0][0] = wi->serifs[0][1] = wi->serifs[1][0] = wi->serifs[1][1] = NOTREACHED; wi->serifs[2][0] = wi->serifs[2][1] = wi->serifs[3][0] = wi->serifs[3][1] = NOTREACHED; } else { wi->serifs[0][0] = rint(ds/wi->decimation); wi->serifs[0][1] = rint((ds+serifsize)/wi->decimation); wi->serifs[1][0] = 0; wi->serifs[1][1] = rint(serifsize/wi->decimation); wi->serifs[2][0] = rint((xh-serifsize)/wi->decimation); wi->serifs[2][1] = rint(xh/wi->decimation); wi->serifs[3][0] = rint((caph-serifsize)/wi->decimation); wi->serifs[3][1] = rint(caph/wi->decimation); } if ( wi->sf==aw_old_sf ) wi->space_guess = aw_old_spaceguess; else if ( wi->autokern && wi->current_I_spacing ) wi->space_guess = rint(wi->current_I_spacing); else if ( wi->n_stem_interior_width>0 ) wi->space_guess = rint(wi->n_stem_interior_width); else if ( caph!=sf->ascent && ds!=-sf->descent ) wi->space_guess = rint(.205*(caph-ds)); else wi->space_guess = rint(.184*(sf->ascent+sf->descent)); }