X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=ttf2png.c;h=bd8410674d8bdc67765689bed3fbc9f21aa30158;hb=8665ed42e9f40edaa902d963c933f8627a3178e6;hp=97be0f1fc6ef4934f991bfc323c5b80a02eecd93;hpb=4291a684d86dbd80880503d12e4a1f8db3a41579;p=ttf2png.git diff --git a/ttf2png.c b/ttf2png.c index 97be0f1..bd84106 100644 --- a/ttf2png.c +++ b/ttf2png.c @@ -1,6 +1,6 @@ /* ttf2png - True Type Font to PNG converter -Copyright (c) 2004 Mikkosoft Productions +Copyright (c) 2004-2006 Mikkosoft Productions This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -24,31 +24,49 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include #include FT_FREETYPE_H +typedef struct sGlyphDef +{ + int code; + int x,y; + int w,h; + int ascent; + int advance; +} GlyphDef; + +unsigned round_to_pot(unsigned); void usage(); -int save_png(char *, char *, int, int); +int save_defs(const char *, const GlyphDef *, int, int, int, int); +int save_png(const char *, const char *, int, int, char); + +char verbose=0; int main(int argc, char **argv) { - FT_Library freetype; - FT_Face face; - int err; - int o; - int begin=0; - int end=255; - char *fn; - int size=10; - int cpl=16; - int w,h; - int i; - char *data; - int ch,cw; - int cell=16; - int ascent; - char *out="font.png"; - char verbose=0; - const char *name; - char autohinter=0; - int count; + char *fn; + int begin=0; + int end=255; + int size=10; + int cpl=16; + int cell=16; + char autohinter=0; + char seq=0; + char alpha=0; + + FT_Library freetype; + FT_Face face; + int ch,cw; + int ascent; + + int err; + int i; + int count; + + int w,h; + char *data; + char *out_fn="font.png"; + + char *def_fn=NULL; + GlyphDef *defs=NULL; if(argc<2) { @@ -56,133 +74,236 @@ int main(int argc, char **argv) return 1; } - while((o=getopt(argc,argv,"r:s:l:c:o:avh?"))!=-1) + while((i=getopt(argc, argv, "r:s:l:c:o:atvh?ed:"))!=-1) { - char *ptr; - int temp; - switch(o) + char *ptr; + int temp; + switch(i) { case 'r': - if(!isdigit(optarg[0])) temp=-1; - else + if(!strcmp(optarg, "all")) { - temp=strtol(optarg,&ptr,0); - if(ptr[0]!=',' || !isdigit(ptr[1])) temp=-1; + begin=0; + end=0x110000; } - if(temp<0) - printf("Not a valid range: %s\n",optarg); else { - begin=temp; - end=strtol(ptr+1,NULL,0); + if(!isdigit(optarg[0])) + temp=-1; + else + { + temp=strtol(optarg, &ptr, 0); + if(ptr[0]!=',' || !isdigit(ptr[1])) + temp=-1; + } + if(temp<0) + { + printf("Not a valid range: %s\n", optarg); + exit(1); + } + else + { + begin=temp; + end=strtol(ptr+1, NULL, 0); + } } break; case 's': - size=strtol(optarg,NULL,0); + size=strtol(optarg, NULL, 0); break; case 'l': - cpl=strtol(optarg,NULL,0); + cpl=strtol(optarg, NULL, 0); break; case 'c': - cell=strtol(optarg,NULL,0); + cell=strtol(optarg, NULL, 0); break; case 'o': - out=optarg; + out_fn=optarg; break; case 'a': autohinter=1; break; + case 't': + alpha=1; + break; case 'v': - verbose=1; + ++verbose; break; case 'h': case '?': usage(); return 0; + case 'e': + seq=1; + break; + case 'd': + def_fn=optarg; + break; } } + if(!strcmp(out_fn, "-")) + verbose=0; - if(optind>=argc) + if(optind!=argc-1) { usage(); return 1; } + fn=argv[optind]; err=FT_Init_FreeType(&freetype); if(err) { - fprintf(stderr,"Couldn't initialize FreeType library\n"); + fprintf(stderr, "Couldn't initialize FreeType library\n"); return 1; } - err=FT_New_Face(freetype,fn,0,&face); + err=FT_New_Face(freetype, fn, 0, &face); if(err) { - fprintf(stderr,"Couldn't load font file\n"); + fprintf(stderr, "Couldn't load font file\n"); if(err==FT_Err_Unknown_File_Format) - fprintf(stderr,"Unknown file format\n"); + fprintf(stderr, "Unknown file format\n"); return 1; } - name=FT_Get_Postscript_Name(face); - if(verbose) printf("Font name: %s\n",name); + if(verbose) + { + const char *name=FT_Get_Postscript_Name(face); + printf("Font name: %s\n", name); + printf("Glyphs: %ld\n", face->num_glyphs); + } - err=FT_Set_Pixel_Sizes(face,0,size); + err=FT_Set_Pixel_Sizes(face, 0, size); if(err) { - fprintf(stderr,"Couldn't set size\n"); + fprintf(stderr, "Couldn't set size\n"); return 1; } - ascent=face->size->metrics.ascender/64; - ch=(face->size->metrics.ascender-face->size->metrics.descender)/64; - cw=face->size->metrics.max_advance/64; + ascent=(face->bbox.yMax*face->size->metrics.x_scale)>>16; + ascent=(ascent+63)/64; + ch=((face->bbox.yMax-face->bbox.yMin)*face->size->metrics.y_scale)>>16; + ch=(ch+63)/64; + cw=((face->bbox.xMax-face->bbox.xMin)*face->size->metrics.x_scale)>>16; + cw=(cw+63)/64; if(verbose) { printf("Ascent %d\n",ascent); - printf("Descent %ld\n",face->size->metrics.descender/64); - printf("Height %d\n",ch); - printf("Width %d\n",cw); + printf("Descent %ld\n",(((face->bbox.yMin*face->size->metrics.y_scale)>>16)+63)/64); + printf("Max height %d\n",ch); + printf("Max width %d\n",cw); } - if(ch>cell || cw>cell) fprintf(stderr,"ttf2png: Warning: character size exceeds cell size\n"); + if(verbose>=1 && (ch>cell || cw>cell)) fprintf(stderr,"Warning: character size exceeds cell size\n"); - w=cpl*cell; - h=(end-begin+cpl-1)/cpl*cell; + w=round_to_pot(cpl*cell); + if(seq && face->num_glyphsnum_glyphs+cpl-1)/cpl*cell; + else + h=(end-begin+cpl-1)/cpl*cell; + h=round_to_pot(h); + data=(char *)malloc(w*h); - memset(data,255,w*h); + memset(data, 255, w*h); + + if(def_fn) + { + if(face->num_glyphsnum_glyphs; + else + count=end-begin; + + defs=(GlyphDef *)malloc(count*sizeof(GlyphDef)); + } count=0; - for(i=begin;i<=end;++i) - { - int glyph=FT_Get_Char_Index(face,i); - FT_Bitmap *bmp=&face->glyph->bitmap; - int x,y; - int cx=(i%cpl)*cell+(cell-cw)/2; - int cy=(i/cpl)*cell; - int flags=0; + for(i=begin; i<=end; ++i) + { + int glyph=FT_Get_Char_Index(face,i); + FT_Bitmap *bmp=&face->glyph->bitmap; + int x,y; + int cx,cy; + int flags=0; + int dy; + if(!glyph) continue; - fflush(stdout); - if(autohinter) flags|=FT_LOAD_FORCE_AUTOHINT; - FT_Load_Glyph(face,glyph,flags); - FT_Render_Glyph(face->glyph,FT_RENDER_MODE_NORMAL); - cx+=face->glyph->bitmap_left; - cy+=ascent-face->glyph->bitmap_top; - for(y=0;yrows;++y) for(x=0;xwidth;++x) + + if(seq) + { + cx=(count%cpl)*cell; + cy=(count/cpl)*cell; + } + else + { + cx=(i%cpl)*cell; + cy=(i/cpl)*cell; + } + + if(autohinter) + flags|=FT_LOAD_FORCE_AUTOHINT; + FT_Load_Glyph(face, glyph, flags); + FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL); + if(cell>bmp->width) + cx+=(cell-bmp->width)/2; + dy=ascent-face->glyph->bitmap_top; + cy+=dy; + + if(verbose>=2) + { + printf(" Char %d: glyph %d, size %dx%d\n", i, glyph, bmp->width, bmp->rows); + if(bmp->width>cell || dy+bmp->rows>cell || dy<0) printf(" Warning: Character %d does not fit in cell\n", i); + } + + if(bmp->pitch<0) + { + fprintf(stderr, "Warning: Character %d not rendered (can't handle reversed bitmaps)\n", i); + continue; + } + + for(y=0; yrows; ++y) for(x=0; xwidth; ++x) { if(cx+x<0 || cx+x>=w || cy+y<0 || cy+y>=h) continue; - if(bmp->pitch>0) - data[cx+x+(cy+y)*w]=255-bmp->buffer[x+y*bmp->pitch]; + data[cx+x+(cy+y)*w]=255-bmp->buffer[x+y*bmp->pitch]; } + + if(def_fn) + { + defs[count].code=i; + defs[count].x=cx; + defs[count].y=cy; + defs[count].w=bmp->width; + defs[count].h=bmp->rows; + defs[count].ascent=face->glyph->bitmap_top-bmp->rows; + defs[count].advance=(int)(face->glyph->advance.x+32)/64; + } + ++count; } - save_png(out,data,w,h); + while(seq && h/2>=(count+cpl-1)/cpl*cell) + h/=2; + + if(def_fn) + save_defs(def_fn, defs, count, w, h, size); + save_png(out_fn, data, w, h, alpha); - if(verbose) printf("Converted %d glyphs\n",count); + if(verbose) printf("Converted %d glyphs\n", count); return 0; } +unsigned round_to_pot(unsigned n) +{ + n-=1; + n|=n>>1; + n|=n>>2; + n|=n>>4; + n|=n>>8; + n|=n>>16; + + return n+1; +} + void usage() { printf("ttf2png - True Type Font to PNG converter\n" @@ -194,48 +315,101 @@ void usage() " -s Font size to use, in pixels [10]\n" " -l Number of characters to put in one line [16]\n" " -c Character cell size, in pixels [16]\n" - " -o Output file name [font.png]\n" + " -o Output file name (or - for stdout) [font.png]\n" " -a Force autohinter\n" - " -v Enable verbose mode\n" + " -t Render font to alpha channel\n" + " -v Increase the level of verbosity\n" + " -e Use cells in sequence, rather than by code\n" + " -d Write a definition to the given file\n" " -h Print this message\n"); } -int save_png(char *fn, char *data, int w, int h) +int save_defs(const char *fn, const GlyphDef *defs, int count, int w, int h, int size) { - FILE *out; - png_struct *pngs; - png_info *pngi; - png_byte *rows[h]; - int i; + FILE *out; + int i; - out=fopen(fn,"wb"); + out=fopen(fn, "w"); if(!out) { - fprintf(stderr,"Couldn't open output file\n"); + fprintf(stderr, "Couldn't open %s\n",fn); return -1; } - pngs=png_create_write_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL); + fprintf(out, "%d %d %d\n", w, h, size); + for(i=0; icode, d->x, d->y, d->w, d->h, d->ascent, d->advance); + } + + fclose(out); + + return 0; +} + +int save_png(const char *fn, const char *data, int w, int h, char alpha) +{ + FILE *out; + png_struct *pngs; + png_info *pngi; + png_byte *rows[h]; + int i; + png_byte *data2; + int color; + + if(!strcmp(fn, "-")) + out=stdout; + else + { + out=fopen(fn, "wb"); + if(!out) + { + fprintf(stderr, "Couldn't open %s\n",fn); + return -1; + } + } + + pngs=png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if(!pngs) { - fprintf(stderr,"Error writing PNG file\n"); + fprintf(stderr, "Error writing PNG file\n"); return -1; } pngi=png_create_info_struct(pngs); if(!pngi) { - png_destroy_write_struct(&pngs,NULL); - fprintf(stderr,"Error writing PNG file\n"); + png_destroy_write_struct(&pngs, NULL); + fprintf(stderr, "Error writing PNG file\n"); return -1; } - png_init_io(pngs,out); - png_set_IHDR(pngs,pngi,w,h,8,PNG_COLOR_TYPE_GRAY,PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT); - for(i=0;i