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 printf(" -f Create a distance field texture\n"
314 " -b Specify distance field border zone width\n"
315 " -d File name for writing glyph definitions\n"
316 " -h Print this message\n");
319 int convert_numeric_option(char opt, int min_value)
324 value = strtol(optarg, &ptr, 0);
325 if(value<min_value || *ptr)
327 printf("Invalid option argument in -%c %s\n", opt, optarg);
334 void convert_code_point_range(char opt, Range *range)
339 if(!strcmp(optarg, "all"))
342 range->last = 0x10FFFF;
346 value = str_to_code_point(optarg, &ptr);
347 if(value>0 && *ptr==',')
349 range->first = value;
350 value = str_to_code_point(ptr+1, &ptr);
358 printf("Invalid option argument in -%c %s\n", opt, optarg);
362 unsigned str_to_code_point(const char *nptr, char **endptr)
364 if(nptr[0]=='U' && nptr[1]=='+')
365 return strtoul(nptr+2, endptr, 16);
366 else if(nptr[0]&0x80)
373 *endptr = (char *)nptr;
375 for(bytes=1; (bytes<4 && (nptr[0]&(0x80>>bytes))); ++bytes)
376 if((nptr[bytes]&0xC0)!=0x80)
381 code = nptr[0]&(0x3F>>bytes);
382 for(i=1; i<bytes; ++i)
383 code = (code<<6)|(nptr[i]&0x3F);
386 *endptr = (char *)nptr+bytes;
390 else if(isdigit(nptr[0]))
391 return strtoul(nptr, endptr, 0);
395 *endptr = (char *)nptr+1;
400 void convert_size(char opt, unsigned *width, unsigned *height)
405 if(!strcmp(optarg, "auto"))
411 else if(!strcmp(optarg, "autorect"))
418 value = strtol(optarg, &ptr, 0);
424 value = strtol(ptr+1, &ptr, 0);
438 printf("Invalid option argument in -%c %s\n", opt, optarg);
442 void sort_and_compact_ranges(Range *ranges, unsigned *n_ranges)
449 qsort(ranges, *n_ranges, sizeof(Range), &range_cmp);
450 for(i=0, j=1; j<*n_ranges; ++j)
452 if(ranges[i].last+1>=ranges[j].first)
454 if(ranges[j].last>ranges[i].last)
455 ranges[i].last = ranges[j].last;
461 ranges[i] = ranges[j];
468 int range_cmp(const void *p1, const void *p2)
470 const Range *r1 = (const Range *)p1;
471 const Range *r2 = (const Range *)p2;
472 if(r1->first!=r2->first)
473 return (r1->first<r2->first ? -1 : 1);
474 else if(r1->last!=r2->last)
475 return (r1->last<r2->last ? -1 : 1);
480 unsigned round_to_pot(unsigned n)
492 int init_image(Image *image, size_t w, size_t h)
501 if(!image->w || !image->h)
507 fprintf(stderr, "Cannot allocate memory for a %dx%d image\n", image->w, image->h);
511 image->data = malloc(s);
514 fprintf(stderr, "Cannot allocate memory for a %dx%d image\n", image->w, image->h);
521 int init_font(Font *font, FT_Face face, const Range *ranges, unsigned n_ranges, bool autohinter, unsigned distfield, unsigned border)
525 int scale = (distfield>0 ? distfield : 1);
527 font->ascent = (face->size->metrics.ascender/scale+63)/64;
528 font->descent = (face->size->metrics.descender/scale-63)/64;
532 printf("Ascent: %d\n", font->ascent);
533 printf("Descent: %d\n", font->descent);
538 for(i=0; i<n_ranges; ++i)
539 if(init_glyphs(font, face, &ranges[i], autohinter, distfield, border))
543 printf("Loaded %u glyphs\n", font->n_glyphs);
546 font->kerning = NULL;
547 for(i=0; i<font->n_glyphs; ++i) for(j=0; j<font->n_glyphs; ++j)
551 FT_Get_Kerning(face, font->glyphs[i].index, font->glyphs[j].index, FT_KERNING_DEFAULT, &kerning);
553 /* FreeType documentation says that vertical kerning is practically
554 never used, so we ignore it. */
559 if(font->n_kerning>=size)
562 font->kerning = (Kerning *)realloc(font->kerning, size*sizeof(Kerning));
565 kern = &font->kerning[font->n_kerning++];
566 kern->left_glyph = &font->glyphs[i];
567 kern->right_glyph = &font->glyphs[j];
568 kern->distance = (kerning.x/scale+32)/64;
573 printf("Loaded %d kerning pairs\n", font->n_kerning);
578 int init_glyphs(Font *font, FT_Face face, const Range *range, bool autohinter, unsigned distfield, unsigned border)
581 unsigned size = font->n_glyphs;
582 int scale = (distfield>0 ? distfield : 1);
584 for(i=range->first; i<=range->last; ++i)
587 FT_Bitmap *bmp = &face->glyph->bitmap;
591 n = FT_Get_Char_Index(face, i);
596 flags |= FT_LOAD_FORCE_AUTOHINT;
597 FT_Load_Glyph(face, n, flags);
598 FT_Render_Glyph(face->glyph, (distfield ? FT_RENDER_MODE_MONO : FT_RENDER_MODE_NORMAL));
602 printf(" Code point U+%04X", i);
603 if(i>=0x20 && i<0x7F)
605 else if(i>=0xA0 && i<=0x10FFFF)
610 for(bytes=2; i>>(1+bytes*5); ++bytes) ;
611 for(j=0; j<bytes; ++j)
612 utf8[j] = 0x80 | ((i>>((bytes-j-1)*6))&0x3F);
613 utf8[0] |= 0xF0<<(4-bytes);
616 printf(" (%s)", utf8);
618 printf(": glyph %u, size %dx%d\n", n, bmp->width/scale, bmp->rows/scale);
621 if(bmp->pixel_mode!=FT_PIXEL_MODE_GRAY && bmp->pixel_mode!=FT_PIXEL_MODE_MONO)
623 fprintf(stderr, "Warning: Glyph %u skipped, incompatible pixel mode\n", n);
627 if(font->n_glyphs>=size)
630 font->glyphs = (Glyph *)realloc(font->glyphs, size*sizeof(Glyph));
633 glyph = &font->glyphs[font->n_glyphs++];
636 glyph->offset_x = (int)(face->glyph->bitmap_left+scale/2)/scale;
637 glyph->offset_y = (int)(face->glyph->bitmap_top-bmp->rows+scale/2)/scale;
638 glyph->advance = (int)(face->glyph->advance.x/scale+32)/64;
640 /* Copy the glyph image since FreeType uses a global buffer, which would
641 be overwritten by the next glyph. Negative pitch means the scanlines
642 start from the bottom. */
645 glyph->offset_x -= border;
646 glyph->offset_y -= border;
647 create_distance_field(bmp, &glyph->image, distfield, border);
651 if(copy_bitmap(bmp, &glyph->image))
659 int copy_bitmap(const FT_Bitmap *bmp, Image *image)
665 if(init_image(image, bmp->width, bmp->rows))
667 if(!image->w || !image->h)
671 src = bmp->buffer+(bmp->rows-1)*-bmp->pitch;
676 for(y=0; y<bmp->rows; ++y)
678 if(bmp->pixel_mode==FT_PIXEL_MODE_MONO)
680 for(x=0; x<bmp->width; ++x)
681 dst[x] = ((src[x/8]&(0x80>>(x%8))) ? 0xFF : 0x00);
685 for(x=0; x<bmp->width; ++x)
696 unsigned sqrti(unsigned num)
698 unsigned result = (num>0xFFFF ? 0xFFFF : 0x100);
699 while(result && result*result>=result+num)
700 result -= (result*result+result-num)/(result*2);
705 unsigned find_distance_to_edge(const Image *image, int origin_x, int origin_y, unsigned range)
709 unsigned char origin_pixel = 0;
710 unsigned closest = range*range;
712 if(origin_x>=0 && (unsigned)origin_x<image->w && origin_y>=0 && (unsigned)origin_y<image->h)
713 origin_pixel = image->data[origin_x+origin_y*image->w];
717 for(i=1; (i<range && i*i<=closest); ++i, --x, --y) for(j=0; j<4; ++j)
720 int dx = (j==0 ? 1 : j==2 ? -1 : 0);
721 int dy = (j==1 ? 1 : j==3 ? -1 : 0);
723 for(k=0; k<i*2; ++k, x+=dx, y+=dy)
725 unsigned char pixel = 0;
726 if(x>=0 && (unsigned)x<image->w && y>=0 && (unsigned)y<image->h)
727 pixel = image->data[x+y*image->w];
729 if((pixel^origin_pixel)&0x80)
731 unsigned d = 2*i*i + k*k - 2*k*i;
738 return sqrti(closest*0x3F01)/range;
741 int create_distance_field(const FT_Bitmap *bmp, Image *image, unsigned scale, unsigned margin)
746 if(init_image(image, (bmp->width+scale-1)/scale+2*margin, (bmp->rows+scale-1)/scale+2*margin))
748 if(!image->w || !image->h)
751 if(copy_bitmap(bmp, &base_image))
754 image->border = margin;
755 for(y=0; y<image->h; ++y) for(x=0; x<image->w; ++x)
757 int bx = (x-margin)*scale+scale/2;
758 int by = (y-margin)*scale+scale/2;
759 unsigned char pixel = find_distance_to_edge(&base_image, bx, by, margin*scale);
760 if(bx>=0 && (unsigned)bx<base_image.w && by>=0 && (unsigned)by<base_image.h)
761 pixel |= base_image.data[bx+by*base_image.w]&0x80;
764 image->data[x+y*image->w] = pixel;
767 free(base_image.data);
772 int render_grid(Font *font, unsigned cellw, unsigned cellh, unsigned cpl, bool seq)
775 int top = 0, bot = 0;
776 unsigned first, n_cells;
777 unsigned maxw = 0, maxh = 0;
779 /* Find extremes of the glyph images. */
780 for(i=0; i<font->n_glyphs; ++i)
784 y = font->glyphs[i].offset_y+font->glyphs[i].image.h;
787 if(font->glyphs[i].offset_y<bot)
788 bot = font->glyphs[i].offset_y;
789 if(font->glyphs[i].image.w>maxw)
790 maxw = font->glyphs[i].image.w;
791 if(font->glyphs[i].image.h>maxh)
792 maxh = font->glyphs[i].image.h;
797 /* Establish a large enough cell to hold all glyphs in the range. */
798 int square = (cellh==cellw);
812 printf("Max size: %u x %u\n", maxw, maxh);
813 printf("Y range: [%d %d]\n", bot, top);
814 printf("Cell size: %u x %u\n", cellw, cellh);
815 if(maxw>cellw || (unsigned)(top-bot)>cellh)
816 fprintf(stderr, "Warning: character size exceeds cell size\n");
821 /* Determine number of characters per line, trying to fit all the glyphs
822 in a square image. */
826 if(cpl>0 && font->n_glyphs/cpl*cellh<=cpl*cellw)
831 first = font->glyphs[0].code;
833 n_cells = font->n_glyphs;
837 n_cells = font->glyphs[font->n_glyphs-1].code+1-first;
840 if(init_image(&font->image, cpl*cellw, (n_cells+cpl-1)/cpl*cellh))
842 memset(font->image.data, 0, font->image.w*font->image.h);
844 for(i=0; i<font->n_glyphs; ++i)
850 glyph = &font->glyphs[i];
855 ci = glyph->code-first;
860 if(cellw>glyph->image.w)
861 cx += (cellw-glyph->image.w)/2;
862 cy += top-glyph->offset_y-glyph->image.h;
867 for(y=0; y<glyph->image.h; ++y) for(x=0; x<glyph->image.w; ++x)
869 if(cx+x>=font->image.w || cy+y>=font->image.h)
871 font->image.data[cx+x+(cy+y)*font->image.w] = glyph->image.data[x+y*glyph->image.w];
878 int render_packed(Font *font, unsigned margin, unsigned padding)
883 unsigned *used_pixels;
884 unsigned cx = margin, cy;
887 /* Compute the total area occupied by glyphs and padding. */
888 for(i=0; i<font->n_glyphs; ++i)
890 size_t a = area+(font->glyphs[i].image.w+padding)*(font->glyphs[i].image.h+padding);
893 fprintf(stderr, "Overflow in counting total glyph area\n");
899 /* Find an image size that's approximately square. */
900 for(font->image.w=1;; font->image.w<<=1)
902 if(font->image.w<=margin*2)
904 font->image.h = area/(font->image.w-margin*2)+margin*2;
905 if(font->image.h<=font->image.w)
909 /* Add some extra space to accommodate packing imperfections. */
910 font->image.h = font->image.h*3/2;
912 /* Allocate arrays for storing the image and keeping track of used pixels and
913 glyphs. Since glyphs are rectangular and the image is filled starting from
914 the top, it's enough to track the number of used pixels at the top of each
916 if(init_image(&font->image, font->image.w, font->image.h))
918 memset(font->image.data, 0, font->image.w*font->image.h);
919 used_pixels = (unsigned *)malloc(font->image.w*sizeof(unsigned));
920 memset(used_pixels, 0, font->image.w*sizeof(unsigned));
921 used_glyphs = (bool *)malloc(font->n_glyphs);
922 memset(used_glyphs, 0, font->n_glyphs);
924 for(cy=margin; cy+margin<font->image.h;)
929 unsigned best_score = 0;
930 unsigned target_h = 0;
932 /* Find the leftmost free pixel on this row. Also record the lowest
933 extent of glyphs to the left of the free position. */
934 for(; (cx+margin<font->image.w && used_pixels[cx]>cy); ++cx)
935 if(used_pixels[cx]-cy-padding>target_h)
936 target_h = used_pixels[cx]-cy-padding;
938 if(cx+margin>=font->image.w)
945 /* Count the free pixel at this position. */
946 for(w=0; (cx+w+margin<font->image.w && used_pixels[cx+w]<=cy); ++w) ;
948 /* Find a suitable glyph to put here. */
949 for(i=0; i<font->n_glyphs; ++i)
953 g = &font->glyphs[i];
954 if(!used_glyphs[i] && g->image.w<=w)
958 /* Prefer glyphs that would reach exactly as low as the ones left
959 of here. This aims to create a straight edge at the bottom for
960 lining up further glyphs. */
961 score = g->image.h+padding;
962 if(g->image.h==target_h)
981 used_glyphs[glyph-font->glyphs] = 1;
985 for(y=0; y<glyph->image.h; ++y) for(x=0; x<glyph->image.w; ++x)
987 if(cx+x>=font->image.w || cy+y>=font->image.h)
989 font->image.data[cx+x+(cy+y)*font->image.w] = glyph->image.data[x+y*glyph->image.w];
991 for(x=0; x<glyph->image.w+2*padding; ++x)
993 if(cx+x<padding || cx+x>=font->image.w+padding)
995 if(used_pixels[cx+x-padding]<cy+glyph->image.h+padding)
996 used_pixels[cx+x-padding] = cy+glyph->image.h+padding;
999 if(cy+glyph->image.h+margin>used_h)
1000 used_h = cy+glyph->image.h+margin;
1003 /* Trim the image to the actually used size, in case the original estimate
1004 was too pessimistic. */
1005 font->image.h = used_h;
1013 int save_defs(const char *fn, const Font *font)
1018 out = fopen(fn, "w");
1021 fprintf(stderr, "Couldn't open %s\n",fn);
1025 fprintf(out, "# Image/font info:\n");
1026 fprintf(out, "# width height size ascent descent\n");
1027 fprintf(out, "font %d %d %d %d %d\n", font->image.w, font->image.h, font->size, font->ascent, font->descent);
1029 fprintf(out, "\n# Code point mapping:\n");
1030 fprintf(out, "# code index\n");
1031 for(i=0; i<font->n_glyphs; ++i)
1033 const Glyph *g = &font->glyphs[i];
1034 fprintf(out, "code %u %u\n", g->code, g->index);
1037 fprintf(out, "\n# Metrics info:\n");
1038 fprintf(out, "# index width height offset_x offset_y advance\n");
1039 for(i=0; i<font->n_glyphs; ++i)
1041 const Glyph *g = &font->glyphs[i];
1042 int b = g->image.border;
1043 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);
1046 fprintf(out, "\n# Glyph info:\n");
1047 fprintf(out, "# index x y width height border\n");
1048 for(i=0; i<font->n_glyphs; ++i)
1050 const Glyph *g = &font->glyphs[i];
1051 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);
1054 fprintf(out, "\n# Kerning info:\n");
1055 fprintf(out, "# left right distance\n");
1056 for(i=0; i<font->n_kerning; ++i)
1058 const Kerning *k = &font->kerning[i];
1059 fprintf(out, "kern %u %u %d\n", k->left_glyph->index, k->right_glyph->index, k->distance);
1067 int save_png(const char *fn, const Image *image, bool alpha, bool invert, bool npot)
1076 unsigned flip_bits = (invert==alpha ? 0xFF : 0x00);
1077 unsigned char *src = image->data;
1079 if(!strcmp(fn, "-"))
1083 out = fopen(fn, "wb");
1086 fprintf(stderr, "Couldn't open %s\n",fn);
1091 pngs = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
1094 fprintf(stderr, "Error writing PNG file\n");
1097 pngi = png_create_info_struct(pngs);
1100 png_destroy_write_struct(&pngs, NULL);
1101 fprintf(stderr, "Error writing PNG file\n");
1105 w = (npot ? image->w : round_to_pot(image->w));
1106 h = (npot ? image->h : round_to_pot(image->h));
1107 color = (alpha ? PNG_COLOR_TYPE_GRAY_ALPHA : PNG_COLOR_TYPE_GRAY);
1108 png_set_IHDR(pngs, pngi, w, h, 8, color, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
1110 png_init_io(pngs, out);
1111 png_write_info(pngs, pngi);
1112 row = (png_byte *)malloc(w*(1+alpha));
1118 row[x*2+1] = flip_bits;
1120 for(y=0; y<image->h; ++y)
1122 for(x=0; x<image->w; ++x)
1123 row[x*2+1] = *src++^flip_bits;
1124 png_write_row(pngs, row);
1132 memset(row+image->w, flip_bits, w-image->w);
1133 for(y=0; y<image->h; ++y)
1135 for(x=0; x<image->w; ++x)
1136 row[x] = *src++^flip_bits;
1137 png_write_row(pngs, row);
1140 memset(row, flip_bits, w);
1144 png_write_row(pngs, row);
1146 png_write_end(pngs, pngi);
1147 png_destroy_write_struct(&pngs, &pngi);
1151 printf("Saved %dx%d PNG image to %s\n", w, h, fn);