2 ttf2png - True Type Font to PNG converter
3 Copyright (c) 2004-2018 Mikko Rasa, Mikkosoft Productions
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include FT_FREETYPE_H
46 typedef struct sKerning
71 typedef unsigned char bool;
74 int convert_numeric_option(char, int);
75 void convert_code_point_range(char, Range *);
76 unsigned str_to_code_point(const char *, char **);
77 void convert_size(char, unsigned *, unsigned *);
78 void sort_and_compact_ranges(Range *, unsigned *);
79 int range_cmp(const void *, const void *);
80 unsigned round_to_pot(unsigned);
81 int init_image(Image *, size_t, size_t);
82 int init_font(Font *, FT_Face, const Range *, unsigned, bool, unsigned, unsigned);
83 int init_glyphs(Font *, FT_Face, const Range *, bool, unsigned, unsigned);
84 int copy_bitmap(const FT_Bitmap *, Image *);
85 unsigned sqrti(unsigned);
86 unsigned find_distance_to_edge(const Image *, int, int, unsigned);
87 int create_distance_field(const FT_Bitmap *, Image *, unsigned, unsigned);
88 int render_grid(Font *, unsigned, unsigned, unsigned, bool);
89 int render_packed(Font *, unsigned, unsigned);
90 int save_defs(const char *, const Font *);
91 int save_png(const char *, const Image *, bool, bool, bool);
95 int main(int argc, char **argv)
99 unsigned n_ranges = 0;
110 unsigned padding = 1;
112 unsigned distfield = 0;
121 char *out_fn = "font.png";
132 while((i = getopt(argc, argv, "r:s:l:c:o:atvh?ed:pim:n:gf:b:")) != -1)
137 ranges = (Range *)realloc(ranges, (++n_ranges)*sizeof(Range));
138 convert_code_point_range('r', &ranges[n_ranges-1]);
141 size = convert_numeric_option('s', 1);
144 cpl = convert_numeric_option('l', 1);
147 convert_size('c', &cellw, &cellh);
178 margin = convert_numeric_option('m', 0);
181 padding = convert_numeric_option('n', 0);
187 distfield = convert_numeric_option('f', 1);
190 border = convert_numeric_option('b', 1);
194 if(!strcmp(out_fn, "-"))
205 err = FT_Init_FreeType(&freetype);
208 fprintf(stderr, "Couldn't initialize FreeType library\n");
212 err = FT_New_Face(freetype, fn, 0, &face);
215 fprintf(stderr, "Couldn't load font file\n");
216 if(err==FT_Err_Unknown_File_Format)
217 fprintf(stderr, "Unknown file format\n");
223 const char *name = FT_Get_Postscript_Name(face);
224 printf("Font name: %s\n", name);
225 printf("Glyphs: %ld\n", face->num_glyphs);
232 border = sqrti(font.size);
236 err = FT_Set_Pixel_Sizes(face, 0, size);
239 fprintf(stderr, "Couldn't set size\n");
245 ranges = malloc(sizeof(Range));
247 ranges[0].last = 255;
251 sort_and_compact_ranges(ranges, &n_ranges);
253 err = init_font(&font, face, ranges, n_ranges, autohinter, distfield, border);
259 fprintf(stderr, "No glyphs found in the requested range\n");
264 err = render_packed(&font, margin, padding);
266 err = render_grid(&font, cellw, cellh, cpl, seq);
270 err = save_png(out_fn, &font.image, (alpha && !distfield), (invert || distfield), npot);
275 save_defs(def_fn, &font);
277 for(i=0; (unsigned)i<font.n_glyphs; ++i)
278 free(font.glyphs[i].image.data);
281 free(font.image.data);
285 FT_Done_FreeType(freetype);
292 printf("ttf2png 1.1 - True Type Font to PNG converter\n"
293 "Copyright (c) 2004-2018 Mikko Rasa, Mikkosoft Productions\n"
294 "Distributed under the GNU General Public License\n\n");
296 printf("Usage: ttf2png [options] <TTF file>\n\n");
298 printf("Accepted options (default values in [brackets])\n"
299 " -r Range of code points to convert [0,255]\n"
300 " -s Font size to use, in pixels [10]\n"
301 " -l Number of glyphs to put in one line [auto]\n"
302 " -c Glyph cell size, in pixels (grid mode only) [auto]\n"
303 " -o Output file name (or - for stdout) [font.png]\n");
304 printf(" -a Force autohinter\n"
305 " -t Render glyphs to alpha channel\n"
306 " -i Invert colors of the glyphs\n"
307 " -v Increase the level of verbosity\n"
308 " -e Use cells in sequence, without gaps (grid mode only)\n"
309 " -p Pack the glyphs tightly instead of in a grid\n"
310 " -m Margin around image edges (packed mode only) [0]\n"
311 " -n Padding between glyphs (packed mode only) [1]\n"
312 " -g Allow non-power-of-two result\n"
313 " -f Create a distance field texture\n"
314 " -d File name for writing glyph definitions\n"
315 " -h Print this message\n");
318 int convert_numeric_option(char opt, int min_value)
323 value = strtol(optarg, &ptr, 0);
324 if(value<min_value || *ptr)
326 printf("Invalid option argument in -%c %s\n", opt, optarg);
333 void convert_code_point_range(char opt, Range *range)
338 if(!strcmp(optarg, "all"))
341 range->last = 0x10FFFF;
345 value = str_to_code_point(optarg, &ptr);
346 if(value>0 && *ptr==',')
348 range->first = value;
349 value = str_to_code_point(ptr+1, &ptr);
357 printf("Invalid option argument in -%c %s\n", opt, optarg);
361 unsigned str_to_code_point(const char *nptr, char **endptr)
363 if(nptr[0]=='U' && nptr[1]=='+')
364 return strtoul(nptr+2, endptr, 16);
365 else if(nptr[0]&0x80)
372 *endptr = (char *)nptr;
374 for(bytes=1; (bytes<4 && (nptr[0]&(0x80>>bytes))); ++bytes)
375 if((nptr[bytes]&0xC0)!=0x80)
380 code = nptr[0]&(0x3F>>bytes);
381 for(i=1; i<bytes; ++i)
382 code = (code<<6)|(nptr[i]&0x3F);
385 *endptr = (char *)nptr+bytes;
389 else if(isdigit(nptr[0]))
390 return strtoul(nptr, endptr, 0);
394 *endptr = (char *)nptr+1;
399 void convert_size(char opt, unsigned *width, unsigned *height)
404 if(!strcmp(optarg, "auto"))
410 else if(!strcmp(optarg, "autorect"))
417 value = strtol(optarg, &ptr, 0);
423 value = strtol(ptr+1, &ptr, 0);
437 printf("Invalid option argument in -%c %s\n", opt, optarg);
441 void sort_and_compact_ranges(Range *ranges, unsigned *n_ranges)
448 qsort(ranges, *n_ranges, sizeof(Range), &range_cmp);
449 for(i=0, j=1; j<*n_ranges; ++j)
451 if(ranges[i].last+1>=ranges[j].first)
453 if(ranges[j].last>ranges[i].last)
454 ranges[i].last = ranges[j].last;
460 ranges[i] = ranges[j];
467 int range_cmp(const void *p1, const void *p2)
469 const Range *r1 = (const Range *)p1;
470 const Range *r2 = (const Range *)p2;
471 if(r1->first!=r2->first)
472 return (r1->first<r2->first ? -1 : 1);
473 else if(r1->last!=r2->last)
474 return (r1->last<r2->last ? -1 : 1);
479 unsigned round_to_pot(unsigned n)
491 int init_image(Image *image, size_t w, size_t h)
500 if(!image->w || !image->h)
506 fprintf(stderr, "Cannot allocate memory for a %dx%d image\n", image->w, image->h);
510 image->data = malloc(s);
513 fprintf(stderr, "Cannot allocate memory for a %dx%d image\n", image->w, image->h);
520 int init_font(Font *font, FT_Face face, const Range *ranges, unsigned n_ranges, bool autohinter, unsigned distfield, unsigned border)
524 int scale = (distfield>0 ? distfield : 1);
526 font->ascent = (face->size->metrics.ascender/scale+63)/64;
527 font->descent = (face->size->metrics.descender/scale-63)/64;
531 printf("Ascent: %d\n", font->ascent);
532 printf("Descent: %d\n", font->descent);
537 for(i=0; i<n_ranges; ++i)
538 if(init_glyphs(font, face, &ranges[i], autohinter, distfield, border))
542 printf("Loaded %u glyphs\n", font->n_glyphs);
545 font->kerning = NULL;
546 for(i=0; i<font->n_glyphs; ++i) for(j=0; j<font->n_glyphs; ++j)
550 FT_Get_Kerning(face, font->glyphs[i].index, font->glyphs[j].index, FT_KERNING_DEFAULT, &kerning);
552 /* FreeType documentation says that vertical kerning is practically
553 never used, so we ignore it. */
558 if(font->n_kerning>=size)
561 font->kerning = (Kerning *)realloc(font->kerning, size*sizeof(Kerning));
564 kern = &font->kerning[font->n_kerning++];
565 kern->left_glyph = &font->glyphs[i];
566 kern->right_glyph = &font->glyphs[j];
567 kern->distance = (kerning.x/scale+32)/64;
572 printf("Loaded %d kerning pairs\n", font->n_kerning);
577 int init_glyphs(Font *font, FT_Face face, const Range *range, bool autohinter, unsigned distfield, unsigned border)
580 unsigned size = font->n_glyphs;
581 int scale = (distfield>0 ? distfield : 1);
583 for(i=range->first; i<=range->last; ++i)
586 FT_Bitmap *bmp = &face->glyph->bitmap;
590 n = FT_Get_Char_Index(face, i);
595 flags |= FT_LOAD_FORCE_AUTOHINT;
596 FT_Load_Glyph(face, n, flags);
597 FT_Render_Glyph(face->glyph, (distfield ? FT_RENDER_MODE_MONO : FT_RENDER_MODE_NORMAL));
601 printf(" Code point U+%04X", i);
602 if(i>=0x20 && i<0x7F)
604 else if(i>=0xA0 && i<=0x10FFFF)
609 for(bytes=2; i>>(1+bytes*5); ++bytes) ;
610 for(j=0; j<bytes; ++j)
611 utf8[j] = 0x80 | ((i>>((bytes-j-1)*6))&0x3F);
612 utf8[0] |= 0xF0<<(4-bytes);
615 printf(" (%s)", utf8);
617 printf(": glyph %u, size %dx%d\n", n, bmp->width/scale, bmp->rows/scale);
620 if(bmp->pixel_mode!=FT_PIXEL_MODE_GRAY && bmp->pixel_mode!=FT_PIXEL_MODE_MONO)
622 fprintf(stderr, "Warning: Glyph %u skipped, incompatible pixel mode\n", n);
626 if(font->n_glyphs>=size)
629 font->glyphs = (Glyph *)realloc(font->glyphs, size*sizeof(Glyph));
632 glyph = &font->glyphs[font->n_glyphs++];
635 glyph->offset_x = (int)(face->glyph->bitmap_left+scale/2)/scale;
636 glyph->offset_y = (int)(face->glyph->bitmap_top-bmp->rows+scale/2)/scale;
637 glyph->advance = (int)(face->glyph->advance.x/scale+32)/64;
639 /* Copy the glyph image since FreeType uses a global buffer, which would
640 be overwritten by the next glyph. Negative pitch means the scanlines
641 start from the bottom. */
644 glyph->offset_x -= border;
645 glyph->offset_y -= border;
646 create_distance_field(bmp, &glyph->image, distfield, border);
650 if(copy_bitmap(bmp, &glyph->image))
658 int copy_bitmap(const FT_Bitmap *bmp, Image *image)
664 if(init_image(image, bmp->width, bmp->rows))
666 if(!image->w || !image->h)
670 src = bmp->buffer+(bmp->rows-1)*-bmp->pitch;
675 for(y=0; y<bmp->rows; ++y)
677 if(bmp->pixel_mode==FT_PIXEL_MODE_MONO)
679 for(x=0; x<bmp->width; ++x)
680 dst[x] = ((src[x/8]&(0x80>>(x%8))) ? 0xFF : 0x00);
684 for(x=0; x<bmp->width; ++x)
695 unsigned sqrti(unsigned num)
697 unsigned result = (num>0xFFFF ? 0xFFFF : 0x100);
698 while(result && result*result>=result+num)
699 result -= (result*result+result-num)/(result*2);
704 unsigned find_distance_to_edge(const Image *image, int origin_x, int origin_y, unsigned range)
708 unsigned char origin_pixel = 0;
709 unsigned closest = range*range;
711 if(origin_x>=0 && (unsigned)origin_x<image->w && origin_y>=0 && (unsigned)origin_y<image->h)
712 origin_pixel = image->data[origin_x+origin_y*image->w];
716 for(i=1; (i<range && i*i<=closest); ++i, --x, --y) for(j=0; j<4; ++j)
719 int dx = (j==0 ? 1 : j==2 ? -1 : 0);
720 int dy = (j==1 ? 1 : j==3 ? -1 : 0);
722 for(k=0; k<i*2; ++k, x+=dx, y+=dy)
724 unsigned char pixel = 0;
725 if(x>=0 && (unsigned)x<image->w && y>=0 && (unsigned)y<image->h)
726 pixel = image->data[x+y*image->w];
728 if((pixel^origin_pixel)&0x80)
730 unsigned d = 2*i*i + k*k - 2*k*i;
737 return sqrti(closest*0x3F01)/range;
740 int create_distance_field(const FT_Bitmap *bmp, Image *image, unsigned scale, unsigned margin)
745 if(init_image(image, (bmp->width+scale-1)/scale+2*margin, (bmp->rows+scale-1)/scale+2*margin))
747 if(!image->w || !image->h)
750 if(copy_bitmap(bmp, &base_image))
753 image->border = margin;
754 for(y=0; y<image->h; ++y) for(x=0; x<image->w; ++x)
756 int bx = (x-margin)*scale+scale/2;
757 int by = (y-margin)*scale+scale/2;
758 unsigned char pixel = find_distance_to_edge(&base_image, bx, by, margin*scale);
759 if(bx>=0 && (unsigned)bx<base_image.w && by>=0 && (unsigned)by<base_image.h)
760 pixel |= base_image.data[bx+by*base_image.w]&0x80;
763 image->data[x+y*image->w] = pixel;
766 free(base_image.data);
771 int render_grid(Font *font, unsigned cellw, unsigned cellh, unsigned cpl, bool seq)
774 int top = 0, bot = 0;
775 unsigned first, n_cells;
776 unsigned maxw = 0, maxh = 0;
778 /* Find extremes of the glyph images. */
779 for(i=0; i<font->n_glyphs; ++i)
783 y = font->glyphs[i].offset_y+font->glyphs[i].image.h;
786 if(font->glyphs[i].offset_y<bot)
787 bot = font->glyphs[i].offset_y;
788 if(font->glyphs[i].image.w>maxw)
789 maxw = font->glyphs[i].image.w;
790 if(font->glyphs[i].image.h>maxh)
791 maxh = font->glyphs[i].image.h;
796 /* Establish a large enough cell to hold all glyphs in the range. */
797 int square = (cellh==cellw);
811 printf("Max size: %u x %u\n", maxw, maxh);
812 printf("Y range: [%d %d]\n", bot, top);
813 printf("Cell size: %u x %u\n", cellw, cellh);
814 if(maxw>cellw || (unsigned)(top-bot)>cellh)
815 fprintf(stderr, "Warning: character size exceeds cell size\n");
820 /* Determine number of characters per line, trying to fit all the glyphs
821 in a square image. */
825 if(cpl>0 && font->n_glyphs/cpl*cellh<=cpl*cellw)
830 first = font->glyphs[0].code;
832 n_cells = font->n_glyphs;
836 n_cells = font->glyphs[font->n_glyphs-1].code+1-first;
839 if(init_image(&font->image, cpl*cellw, (n_cells+cpl-1)/cpl*cellh))
841 memset(font->image.data, 0, font->image.w*font->image.h);
843 for(i=0; i<font->n_glyphs; ++i)
849 glyph = &font->glyphs[i];
854 ci = glyph->code-first;
859 if(cellw>glyph->image.w)
860 cx += (cellw-glyph->image.w)/2;
861 cy += top-glyph->offset_y-glyph->image.h;
866 for(y=0; y<glyph->image.h; ++y) for(x=0; x<glyph->image.w; ++x)
868 if(cx+x>=font->image.w || cy+y>=font->image.h)
870 font->image.data[cx+x+(cy+y)*font->image.w] = glyph->image.data[x+y*glyph->image.w];
877 int render_packed(Font *font, unsigned margin, unsigned padding)
882 unsigned *used_pixels;
883 unsigned cx = margin, cy;
886 /* Compute the total area occupied by glyphs and padding. */
887 for(i=0; i<font->n_glyphs; ++i)
889 size_t a = area+(font->glyphs[i].image.w+padding)*(font->glyphs[i].image.h+padding);
892 fprintf(stderr, "Overflow in counting total glyph area\n");
898 /* Find an image size that's approximately square. */
899 for(font->image.w=1;; font->image.w<<=1)
901 if(font->image.w<=margin*2)
903 font->image.h = area/(font->image.w-margin*2)+margin*2;
904 if(font->image.h<=font->image.w)
908 /* Add some extra space to accommodate packing imperfections. */
909 font->image.h = font->image.h*3/2;
911 /* Allocate arrays for storing the image and keeping track of used pixels and
912 glyphs. Since glyphs are rectangular and the image is filled starting from
913 the top, it's enough to track the number of used pixels at the top of each
915 if(init_image(&font->image, font->image.w, font->image.h))
917 memset(font->image.data, 0, font->image.w*font->image.h);
918 used_pixels = (unsigned *)malloc(font->image.w*sizeof(unsigned));
919 memset(used_pixels, 0, font->image.w*sizeof(unsigned));
920 used_glyphs = (bool *)malloc(font->n_glyphs);
921 memset(used_glyphs, 0, font->n_glyphs);
923 for(cy=margin; cy+margin<font->image.h;)
928 unsigned best_score = 0;
929 unsigned target_h = 0;
931 /* Find the leftmost free pixel on this row. Also record the lowest
932 extent of glyphs to the left of the free position. */
933 for(; (cx+margin<font->image.w && used_pixels[cx]>cy); ++cx)
934 if(used_pixels[cx]-cy-padding>target_h)
935 target_h = used_pixels[cx]-cy-padding;
937 if(cx+margin>=font->image.w)
944 /* Count the free pixel at this position. */
945 for(w=0; (cx+w+margin<font->image.w && used_pixels[cx+w]<=cy); ++w) ;
947 /* Find a suitable glyph to put here. */
948 for(i=0; i<font->n_glyphs; ++i)
952 g = &font->glyphs[i];
953 if(!used_glyphs[i] && g->image.w<=w)
957 /* Prefer glyphs that would reach exactly as low as the ones left
958 of here. This aims to create a straight edge at the bottom for
959 lining up further glyphs. */
960 score = g->image.h+padding;
961 if(g->image.h==target_h)
980 used_glyphs[glyph-font->glyphs] = 1;
984 for(y=0; y<glyph->image.h; ++y) for(x=0; x<glyph->image.w; ++x)
986 if(cx+x>=font->image.w || cy+y>=font->image.h)
988 font->image.data[cx+x+(cy+y)*font->image.w] = glyph->image.data[x+y*glyph->image.w];
990 for(x=0; x<glyph->image.w+2*padding; ++x)
992 if(cx+x<padding || cx+x>=font->image.w+padding)
994 if(used_pixels[cx+x-padding]<cy+glyph->image.h+padding)
995 used_pixels[cx+x-padding] = cy+glyph->image.h+padding;
998 if(cy+glyph->image.h+margin>used_h)
999 used_h = cy+glyph->image.h+margin;
1002 /* Trim the image to the actually used size, in case the original estimate
1003 was too pessimistic. */
1004 font->image.h = used_h;
1012 int save_defs(const char *fn, const Font *font)
1017 out = fopen(fn, "w");
1020 fprintf(stderr, "Couldn't open %s\n",fn);
1024 fprintf(out, "# Image/font info:\n");
1025 fprintf(out, "# width height size ascent descent\n");
1026 fprintf(out, "font %d %d %d %d %d\n", font->image.w, font->image.h, font->size, font->ascent, font->descent);
1028 fprintf(out, "\n# Code point mapping:\n");
1029 fprintf(out, "# code index\n");
1030 for(i=0; i<font->n_glyphs; ++i)
1032 const Glyph *g = &font->glyphs[i];
1033 fprintf(out, "code %u %u\n", g->code, g->index);
1036 fprintf(out, "\n# Metrics info:\n");
1037 fprintf(out, "# index width height offset_x offset_y advance\n");
1038 for(i=0; i<font->n_glyphs; ++i)
1040 const Glyph *g = &font->glyphs[i];
1041 int b = g->image.border;
1042 fprintf(out, "metrics %u %u %u %d %d %d\n", g->index, g->image.w-2*b, g->image.h-2*b, g->offset_x+b, g->offset_y+b, g->advance);
1045 fprintf(out, "\n# Glyph info:\n");
1046 fprintf(out, "# index x y width height border\n");
1047 for(i=0; i<font->n_glyphs; ++i)
1049 const Glyph *g = &font->glyphs[i];
1050 fprintf(out, "glyph %u %u %u %u %u %u\n", g->index, g->x, g->y, g->image.w, g->image.h, g->image.border);
1053 fprintf(out, "\n# Kerning info:\n");
1054 fprintf(out, "# left right distance\n");
1055 for(i=0; i<font->n_kerning; ++i)
1057 const Kerning *k = &font->kerning[i];
1058 fprintf(out, "kern %u %u %d\n", k->left_glyph->index, k->right_glyph->index, k->distance);
1066 int save_png(const char *fn, const Image *image, bool alpha, bool invert, bool npot)
1075 unsigned flip_bits = (invert==alpha ? 0xFF : 0x00);
1076 unsigned char *src = image->data;
1078 if(!strcmp(fn, "-"))
1082 out = fopen(fn, "wb");
1085 fprintf(stderr, "Couldn't open %s\n",fn);
1090 pngs = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
1093 fprintf(stderr, "Error writing PNG file\n");
1096 pngi = png_create_info_struct(pngs);
1099 png_destroy_write_struct(&pngs, NULL);
1100 fprintf(stderr, "Error writing PNG file\n");
1104 w = (npot ? image->w : round_to_pot(image->w));
1105 h = (npot ? image->h : round_to_pot(image->h));
1106 color = (alpha ? PNG_COLOR_TYPE_GRAY_ALPHA : PNG_COLOR_TYPE_GRAY);
1107 png_set_IHDR(pngs, pngi, w, h, 8, color, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
1109 png_init_io(pngs, out);
1110 png_write_info(pngs, pngi);
1111 row = (png_byte *)malloc(w*(1+alpha));
1117 row[x*2+1] = flip_bits;
1119 for(y=0; y<image->h; ++y)
1121 for(x=0; x<image->w; ++x)
1122 row[x*2+1] = *src++^flip_bits;
1123 png_write_row(pngs, row);
1131 memset(row+image->w, flip_bits, w-image->w);
1132 for(y=0; y<image->h; ++y)
1134 for(x=0; x<image->w; ++x)
1135 row[x] = *src++^flip_bits;
1136 png_write_row(pngs, row);
1139 memset(row, flip_bits, w);
1143 png_write_row(pngs, row);
1145 png_write_end(pngs, pngi);
1146 png_destroy_write_struct(&pngs, &pngi);
1150 printf("Saved %dx%d PNG image to %s\n", w, h, fn);