#include <ft2build.h>
#include FT_FREETYPE_H
+unsigned round_to_pot(unsigned);
void usage();
int save_png(char *, char *, int, int);
-char verbose=0;
-char alpha=0;
+char verbose=0;
+char alpha=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";
- const char *name;
- char autohinter=0;
- int count;
+ 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 autohinter=0;
+ int count;
+ char *def_fn=NULL;
+ char seq=0;
+ FILE *def=NULL;
if(argc<2)
{
return 1;
}
- while((o=getopt(argc,argv,"r:s:l:c:o:atvh?"))!=-1)
+ while((o=getopt(argc, argv, "r:s:l:c:o:atvh?ed:"))!=-1)
{
- char *ptr;
- int temp;
+ char *ptr;
+ int temp;
switch(o)
{
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);
+ 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;
case '?':
usage();
return 0;
+ case 'e':
+ seq=1;
+ break;
+ case 'd':
+ def_fn=optarg;
+ break;
}
}
+ if(!strcmp(out,"-"))
+ 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);
- printf("Glyphs: %ld\n",face->num_glyphs);
+ 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->bbox.yMax*face->size->metrics.x_scale)>>16;
}
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)
+ h=(face->num_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)
+ def=fopen(def_fn, "w");
+
+ if(def)
+ fprintf(def, "%d %d %d\n", w, h, size);
count=0;
- for(i=begin;i<=end;++i)
+ 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;
- int cy=(i/cpl)*cell;
- int flags=0;
- int dy;
+ 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);
- if(cell>bmp->width) cx+=(cell-bmp->width)/2;
+
+ 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);
+ 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);
+ fprintf(stderr, "Warning: Character %d not rendered (can't handle reversed bitmaps)\n", i);
continue;
}
- for(y=0;y<bmp->rows;++y) for(x=0;x<bmp->width;++x)
+
+ for(y=0; y<bmp->rows; ++y) for(x=0; x<bmp->width; ++x)
{
if(cx+x<0 || cx+x>=w || cy+y<0 || cy+y>=h) continue;
data[cx+x+(cy+y)*w]=255-bmp->buffer[x+y*bmp->pitch];
}
+
+ if(def)
+ fprintf(def, "%d %d %d %d %d %d %d\n",i, cx, cy, bmp->width, bmp->rows, face->glyph->bitmap_top-bmp->rows, (int)(face->glyph->advance.x+32)/64);
+
++count;
}
- save_png(out,data,w,h);
+ if(def)
+ fclose(def);
+
+ save_png(out, data, w, h);
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"
" -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"
" -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)
{
- FILE *out;
- png_struct *pngs;
- png_info *pngi;
- png_byte *rows[h];
- int i;
- png_byte *data2;
- int color;
-
- out=fopen(fn,"wb");
- if(!out)
+ 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
{
- fprintf(stderr,"Couldn't open output file\n");
- return -1;
+ out=fopen(fn, "wb");
+ if(!out)
+ {
+ fprintf(stderr, "Couldn't open output file\n");
+ return -1;
+ }
}
- pngs=png_create_write_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
+ 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_init_io(pngs, out);
if(alpha)
{
data2=(png_byte *)malloc(w*h*2);
- for(i=0;i<w*h;++i)
+ for(i=0; i<w*h; ++i)
{
data2[i*2]=255;
data2[i*2+1]=255-data[i];
}
- for(i=0;i<h;++i)
+ for(i=0; i<h; ++i)
rows[i]=(png_byte *)(data2+i*w*2);
color=PNG_COLOR_TYPE_GRAY_ALPHA;
}
else
{
- for(i=0;i<h;++i)
+ for(i=0; i<h; ++i)
rows[i]=(png_byte *)(data+i*w);
color=PNG_COLOR_TYPE_GRAY;
}
- png_set_IHDR(pngs,pngi,w,h,8,color,PNG_INTERLACE_NONE,PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT);
- png_set_rows(pngs,pngi,rows);
- png_write_png(pngs,pngi,PNG_TRANSFORM_IDENTITY,NULL);
- png_destroy_write_struct(&pngs,&pngi);
+ png_set_IHDR(pngs, pngi, w, h, 8, color, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+ png_set_rows(pngs, pngi, rows);
+ png_write_png(pngs, pngi, PNG_TRANSFORM_IDENTITY, NULL);
+ png_destroy_write_struct(&pngs, &pngi);
if(alpha) free(data2);
- if(verbose) printf("Saved %dx%d PNG image to %s\n",w,h,fn);
+ if(verbose) printf("Saved %dx%d PNG image to %s\n", w, h, fn);
return 0;
}