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
45 typedef struct sKerning
73 int convert_numeric_option(char, int);
74 void convert_code_point_range(char, Range *);
75 unsigned str_to_code_point(const char *, char **);
76 void convert_size(char, unsigned *, unsigned *);
77 void sort_and_compact_ranges(Range *, unsigned *);
78 int range_cmp(const void *, const void *);
79 unsigned round_to_pot(unsigned);
80 void *alloc_image_data(size_t, size_t);
81 int init_font(Font *, FT_Face, const Range *, unsigned, bool, unsigned, unsigned);
82 int init_glyphs(Font *, FT_Face, const Range *, bool, unsigned, unsigned);
83 int copy_bitmap(const FT_Bitmap *, Image *);
84 unsigned sqrti(unsigned);
85 unsigned find_distance_to_edge(const Image *, int, int, unsigned);
86 int create_distance_field(const FT_Bitmap *, Image *, unsigned, unsigned);
87 int render_grid(Font *, unsigned, unsigned, unsigned, bool);
88 int render_packed(Font *, unsigned, unsigned);
89 int save_defs(const char *, const Font *);
90 int save_png(const char *, const Image *, bool, bool, bool);
94 int main(int argc, char **argv)
98 unsigned n_ranges = 0;
109 unsigned padding = 1;
111 unsigned distfield = 0;
120 char *out_fn = "font.png";
131 while((i = getopt(argc, argv, "r:s:l:c:o:atvh?ed:pim:n:gf:b:")) != -1)
136 ranges = (Range *)realloc(ranges, (++n_ranges)*sizeof(Range));
137 convert_code_point_range('r', &ranges[n_ranges-1]);
140 size = convert_numeric_option('s', 1);
143 cpl = convert_numeric_option('l', 1);
146 convert_size('c', &cellw, &cellh);
177 margin = convert_numeric_option('m', 0);
180 padding = convert_numeric_option('n', 0);
186 distfield = convert_numeric_option('f', 1);
189 border = convert_numeric_option('b', 1);
193 if(!strcmp(out_fn, "-"))
204 err = FT_Init_FreeType(&freetype);
207 fprintf(stderr, "Couldn't initialize FreeType library\n");
211 err = FT_New_Face(freetype, fn, 0, &face);
214 fprintf(stderr, "Couldn't load font file\n");
215 if(err==FT_Err_Unknown_File_Format)
216 fprintf(stderr, "Unknown file format\n");
222 const char *name = FT_Get_Postscript_Name(face);
223 printf("Font name: %s\n", name);
224 printf("Glyphs: %ld\n", face->num_glyphs);
231 border = sqrti(font.size);
235 err = FT_Set_Pixel_Sizes(face, 0, size);
238 fprintf(stderr, "Couldn't set size\n");
244 ranges = malloc(sizeof(Range));
246 ranges[0].last = 255;
250 sort_and_compact_ranges(ranges, &n_ranges);
252 err = init_font(&font, face, ranges, n_ranges, autohinter, distfield, border);
258 fprintf(stderr, "No glyphs found in the requested range\n");
263 err = render_packed(&font, margin, padding);
265 err = render_grid(&font, cellw, cellh, cpl, seq);
269 err = save_png(out_fn, &font.image, (alpha && !distfield), (invert || distfield), npot);
274 save_defs(def_fn, &font);
276 for(i=0; (unsigned)i<font.n_glyphs; ++i)
277 free(font.glyphs[i].image.data);
280 free(font.image.data);
284 FT_Done_FreeType(freetype);
291 printf("ttf2png 1.1 - True Type Font to PNG converter\n"
292 "Copyright (c) 2004-2018 Mikko Rasa, Mikkosoft Productions\n"
293 "Distributed under the GNU General Public License\n\n");
295 printf("Usage: ttf2png [options] <TTF file>\n\n");
297 printf("Accepted options (default values in [brackets])\n"
298 " -r Range of code points to convert [0,255]\n"
299 " -s Font size to use, in pixels [10]\n"
300 " -l Number of glyphs to put in one line [auto]\n"
301 " -c Glyph cell size, in pixels (grid mode only) [auto]\n"
302 " -o Output file name (or - for stdout) [font.png]\n");
303 printf(" -a Force autohinter\n"
304 " -t Render glyphs to alpha channel\n"
305 " -i Invert colors of the glyphs\n"
306 " -v Increase the level of verbosity\n"
307 " -e Use cells in sequence, without gaps (grid mode only)\n"
308 " -p Pack the glyphs tightly instead of in a grid\n"
309 " -m Margin around image edges (packed mode only) [0]\n"
310 " -n Padding between glyphs (packed mode only) [1]\n"
311 " -g Allow non-power-of-two result\n"
312 " -f Create a distance field texture\n"
313 " -d File name for writing glyph definitions\n"
314 " -h Print this message\n");
317 int convert_numeric_option(char opt, int min_value)
322 value = strtol(optarg, &ptr, 0);
323 if(value<min_value || *ptr)
325 printf("Invalid option argument in -%c %s\n", opt, optarg);
332 void convert_code_point_range(char opt, Range *range)
337 if(!strcmp(optarg, "all"))
340 range->last = 0x10FFFF;
344 value = str_to_code_point(optarg, &ptr);
345 if(value>0 && *ptr==',')
347 range->first = value;
348 value = str_to_code_point(ptr+1, &ptr);
356 printf("Invalid option argument in -%c %s\n", opt, optarg);
360 unsigned str_to_code_point(const char *nptr, char **endptr)
362 if(nptr[0]=='U' && nptr[1]=='+')
363 return strtoul(nptr+2, endptr, 16);
364 else if(nptr[0]&0x80)
371 *endptr = (char *)nptr;
373 for(bytes=1; (bytes<4 && (nptr[0]&(0x80>>bytes))); ++bytes)
374 if((nptr[bytes]&0xC0)!=0x80)
379 code = nptr[0]&(0x3F>>bytes);
380 for(i=1; i<bytes; ++i)
381 code = (code<<6)|(nptr[i]&0x3F);
384 *endptr = (char *)nptr+bytes;
388 else if(isdigit(nptr[0]))
389 return strtoul(nptr, endptr, 0);
393 *endptr = (char *)nptr+1;
398 void convert_size(char opt, unsigned *width, unsigned *height)
403 if(!strcmp(optarg, "auto"))
409 else if(!strcmp(optarg, "autorect"))
416 value = strtol(optarg, &ptr, 0);
422 value = strtol(ptr+1, &ptr, 0);
436 printf("Invalid option argument in -%c %s\n", opt, optarg);
440 void sort_and_compact_ranges(Range *ranges, unsigned *n_ranges)
447 qsort(ranges, *n_ranges, sizeof(Range), &range_cmp);
448 for(i=0, j=1; j<*n_ranges; ++j)
450 if(ranges[i].last+1>=ranges[j].first)
452 if(ranges[j].last>ranges[i].last)
453 ranges[i].last = ranges[j].last;
459 ranges[i] = ranges[j];
466 int range_cmp(const void *p1, const void *p2)
468 const Range *r1 = (const Range *)p1;
469 const Range *r2 = (const Range *)p2;
470 if(r1->first!=r2->first)
471 return (r1->first<r2->first ? -1 : 1);
472 else if(r1->last!=r2->last)
473 return (r1->last<r2->last ? -1 : 1);
478 unsigned round_to_pot(unsigned n)
490 void *alloc_image_data(size_t a, size_t b)
494 /* Carry out the multiplication manually so we can check for overflow. */
503 fprintf(stderr, "Cannot allocate %lu kbytes of memory for image\n", (unsigned long)(c/1024*b));
510 fprintf(stderr, "Cannot allocate %lu kbytes of memory for image\n", (unsigned long)(a/1024*b));
514 int init_font(Font *font, FT_Face face, const Range *ranges, unsigned n_ranges, bool autohinter, unsigned distfield, unsigned border)
518 int scale = (distfield>0 ? distfield : 1);
520 font->ascent = (face->size->metrics.ascender/scale+63)/64;
521 font->descent = (face->size->metrics.descender/scale-63)/64;
525 printf("Ascent: %d\n", font->ascent);
526 printf("Descent: %d\n", font->descent);
531 for(i=0; i<n_ranges; ++i)
532 if(init_glyphs(font, face, &ranges[i], autohinter, distfield, border))
536 printf("Loaded %u glyphs\n", font->n_glyphs);
539 font->kerning = NULL;
540 for(i=0; i<font->n_glyphs; ++i) for(j=0; j<font->n_glyphs; ++j)
544 FT_Get_Kerning(face, font->glyphs[i].index, font->glyphs[j].index, FT_KERNING_DEFAULT, &kerning);
546 /* FreeType documentation says that vertical kerning is practically
547 never used, so we ignore it. */
552 if(font->n_kerning>=size)
555 font->kerning = (Kerning *)realloc(font->kerning, size*sizeof(Kerning));
558 kern = &font->kerning[font->n_kerning++];
559 kern->left_code = font->glyphs[i].code;
560 kern->right_code = font->glyphs[j].code;
561 kern->distance = (kerning.x/scale+32)/64;
566 printf("Loaded %d kerning pairs\n", font->n_kerning);
571 int init_glyphs(Font *font, FT_Face face, const Range *range, bool autohinter, unsigned distfield, unsigned border)
574 unsigned size = font->n_glyphs;
575 int scale = (distfield>0 ? distfield : 1);
577 for(i=range->first; i<=range->last; ++i)
580 FT_Bitmap *bmp = &face->glyph->bitmap;
584 n = FT_Get_Char_Index(face, i);
589 flags |= FT_LOAD_FORCE_AUTOHINT;
590 FT_Load_Glyph(face, n, flags);
591 FT_Render_Glyph(face->glyph, (distfield ? FT_RENDER_MODE_MONO : FT_RENDER_MODE_NORMAL));
595 printf(" Code point U+%04X", i);
596 if(i>=0x20 && i<0x7F)
598 else if(i>=0xA0 && i<=0x10FFFF)
603 for(bytes=2; i>>(1+bytes*5); ++bytes) ;
604 for(j=0; j<bytes; ++j)
605 utf8[j] = 0x80 | ((i>>((bytes-j-1)*6))&0x3F);
606 utf8[0] |= 0xF0<<(4-bytes);
609 printf(" (%s)", utf8);
611 printf(": glyph %u, size %dx%d\n", n, bmp->width/scale, bmp->rows/scale);
614 if(bmp->pixel_mode!=FT_PIXEL_MODE_GRAY && bmp->pixel_mode!=FT_PIXEL_MODE_MONO)
616 fprintf(stderr, "Warning: Glyph %u skipped, incompatible pixel mode\n", n);
620 if(font->n_glyphs>=size)
623 font->glyphs = (Glyph *)realloc(font->glyphs, size*sizeof(Glyph));
626 glyph = &font->glyphs[font->n_glyphs++];
629 glyph->offset_x = (int)(face->glyph->bitmap_left+scale/2)/scale;
630 glyph->offset_y = (int)(face->glyph->bitmap_top-bmp->rows+scale/2)/scale;
631 glyph->advance = (int)(face->glyph->advance.x/scale+32)/64;
633 /* Copy the glyph image since FreeType uses a global buffer, which would
634 be overwritten by the next glyph. Negative pitch means the scanlines
635 start from the bottom. */
638 glyph->offset_x -= border;
639 glyph->offset_y -= border;
640 create_distance_field(bmp, &glyph->image, distfield, border);
644 if(copy_bitmap(bmp, &glyph->image))
652 int copy_bitmap(const FT_Bitmap *bmp, Image *image)
658 image->w = bmp->width;
659 image->h = bmp->rows;
660 if(!image->w || !image->h)
666 image->data = (unsigned char *)malloc(image->w*image->h);
669 fprintf(stderr, "Cannot allocate %d bytes of memory for glyph\n", image->w*image->h);
674 src = bmp->buffer+(bmp->rows-1)*-bmp->pitch;
679 for(y=0; y<bmp->rows; ++y)
681 if(bmp->pixel_mode==FT_PIXEL_MODE_MONO)
683 for(x=0; x<bmp->width; ++x)
684 dst[x] = ((src[x/8]&(0x80>>(x%8))) ? 0xFF : 0x00);
688 for(x=0; x<bmp->width; ++x)
699 unsigned sqrti(unsigned num)
701 unsigned result = (num>0xFFFF ? 0xFFFF : 0x100);
702 while(result && result*result>=result+num)
703 result -= (result*result+result-num)/(result*2);
708 unsigned find_distance_to_edge(const Image *image, int origin_x, int origin_y, unsigned range)
712 unsigned char origin_pixel = 0;
713 unsigned closest = range*range;
715 if(origin_x>=0 && (unsigned)origin_x<image->w && origin_y>=0 && (unsigned)origin_y<image->h)
716 origin_pixel = image->data[origin_x+origin_y*image->w];
720 for(i=1; (i<range && i*i<=closest); ++i, --x, --y) for(j=0; j<4; ++j)
723 int dx = (j==0 ? 1 : j==2 ? -1 : 0);
724 int dy = (j==1 ? 1 : j==3 ? -1 : 0);
726 for(k=0; k<i*2; ++k, x+=dx, y+=dy)
728 unsigned char pixel = 0;
729 if(x>=0 && (unsigned)x<image->w && y>=0 && (unsigned)y<image->h)
730 pixel = image->data[x+y*image->w];
732 if((pixel^origin_pixel)&0x80)
734 unsigned d = 2*i*i + k*k - 2*k*i;
741 return sqrti(closest*0x3F01)/range;
744 int create_distance_field(const FT_Bitmap *bmp, Image *image, unsigned scale, unsigned margin)
749 if(!bmp->width || !bmp->rows)
757 if(copy_bitmap(bmp, &base_image))
760 image->w = (base_image.w-1)/scale+2*margin+1;
761 image->h = (base_image.h-1)/scale+2*margin+1;
762 image->data = (unsigned char *)malloc(image->w*image->h);
765 fprintf(stderr, "Cannot allocate %d bytes of memory for glyph\n", image->w*image->h);
766 free(base_image.data);
770 for(y=0; y<image->h; ++y) for(x=0; x<image->w; ++x)
772 int bx = (x-margin)*scale+scale/2;
773 int by = (y-margin)*scale+scale/2;
774 unsigned char pixel = find_distance_to_edge(&base_image, bx, by, margin*scale);
775 if(bx>=0 && (unsigned)bx<base_image.w && by>=0 && (unsigned)by<base_image.h)
776 pixel |= base_image.data[bx+by*base_image.w]&0x80;
779 image->data[x+y*image->w] = pixel;
782 free(base_image.data);
787 int render_grid(Font *font, unsigned cellw, unsigned cellh, unsigned cpl, bool seq)
790 int top = 0, bot = 0;
791 unsigned first, last;
792 unsigned maxw = 0, maxh = 0;
794 /* Find extremes of the glyph images. */
795 for(i=0; i<font->n_glyphs; ++i)
799 y = font->glyphs[i].offset_y+font->glyphs[i].image.h;
802 if(font->glyphs[i].offset_y<bot)
803 bot = font->glyphs[i].offset_y;
804 if(font->glyphs[i].image.w>maxw)
805 maxw = font->glyphs[i].image.w;
806 if(font->glyphs[i].image.h>maxh)
807 maxh = font->glyphs[i].image.h;
812 /* Establish a large enough cell to hold all glyphs in the range. */
813 int square = (cellh==cellw);
827 printf("Max size: %u x %u\n", maxw, maxh);
828 printf("Y range: [%d %d]\n", bot, top);
829 printf("Cell size: %u x %u\n", cellw, cellh);
830 if(maxw>cellw || (unsigned)(top-bot)>cellh)
831 fprintf(stderr, "Warning: character size exceeds cell size\n");
836 /* Determine number of characters per line, trying to fit all the glyphs
837 in a square image. */
841 if(cpl>0 && font->n_glyphs/cpl*cellh<=cpl*cellw)
846 first = font->glyphs[0].code;
849 last = font->glyphs[font->n_glyphs-1].code;
851 font->image.w = cpl*cellw;
853 font->image.h = (font->n_glyphs+cpl-1)/cpl*cellh;
855 font->image.h = (last-first+cpl)/cpl*cellh;
857 font->image.data = (unsigned char *)alloc_image_data(font->image.w, font->image.h);
858 if(!font->image.data)
860 memset(font->image.data, 0, font->image.w*font->image.h);
862 for(i=0; i<font->n_glyphs; ++i)
868 glyph = &font->glyphs[i];
873 ci = glyph->code-first;
878 if(cellw>glyph->image.w)
879 cx += (cellw-glyph->image.w)/2;
880 cy += top-glyph->offset_y-glyph->image.h;
885 for(y=0; y<glyph->image.h; ++y) for(x=0; x<glyph->image.w; ++x)
887 if(cx+x>=font->image.w || cy+y>=font->image.h)
889 font->image.data[cx+x+(cy+y)*font->image.w] = glyph->image.data[x+y*glyph->image.w];
896 int render_packed(Font *font, unsigned margin, unsigned padding)
901 unsigned *used_pixels;
902 unsigned cx = margin, cy;
905 /* Compute the total area occupied by glyphs and padding. */
906 for(i=0; i<font->n_glyphs; ++i)
908 size_t a = area+(font->glyphs[i].image.w+padding)*(font->glyphs[i].image.h+padding);
911 fprintf(stderr, "Overflow in counting total glyph area\n");
917 /* Find an image size that's approximately square. */
918 for(font->image.w=1;; font->image.w<<=1)
920 if(font->image.w<=margin*2)
922 font->image.h = area/(font->image.w-margin*2)+margin*2;
923 if(font->image.h<=font->image.w)
927 /* Add some extra space to accommodate packing imperfections. */
928 font->image.h = font->image.h*3/2;
930 /* Allocate arrays for storing the image and keeping track of used pixels and
931 glyphs. Since glyphs are rectangular and the image is filled starting from
932 the top, it's enough to track the number of used pixels at the top of each
934 font->image.data = (unsigned char *)alloc_image_data(font->image.w, font->image.h);
935 if(!font->image.data)
937 memset(font->image.data, 0, font->image.w*font->image.h);
938 used_pixels = (unsigned *)malloc(font->image.w*sizeof(unsigned));
939 memset(used_pixels, 0, font->image.w*sizeof(unsigned));
940 used_glyphs = (char *)malloc(font->n_glyphs);
941 memset(used_glyphs, 0, font->n_glyphs);
943 for(cy=margin; cy+margin<font->image.h;)
948 unsigned best_score = 0;
949 unsigned target_h = 0;
951 /* Find the leftmost free pixel on this row. Also record the lowest
952 extent of glyphs to the left of the free position. */
953 for(; (cx+margin<font->image.w && used_pixels[cx]>cy); ++cx)
954 if(used_pixels[cx]-cy-padding>target_h)
955 target_h = used_pixels[cx]-cy-padding;
957 if(cx+margin>=font->image.w)
964 /* Count the free pixel at this position. */
965 for(w=0; (cx+w+margin<font->image.w && used_pixels[cx+w]<=cy); ++w) ;
967 /* Find a suitable glyph to put here. */
968 for(i=0; i<font->n_glyphs; ++i)
972 g = &font->glyphs[i];
973 if(!used_glyphs[i] && g->image.w<=w)
977 /* Prefer glyphs that would reach exactly as low as the ones left
978 of here. This aims to create a straight edge at the bottom for
979 lining up further glyphs. */
980 score = g->image.h+padding;
981 if(g->image.h==target_h)
1000 used_glyphs[glyph-font->glyphs] = 1;
1004 for(y=0; y<glyph->image.h; ++y) for(x=0; x<glyph->image.w; ++x)
1006 if(cx+x>=font->image.w || cy+y>=font->image.h)
1008 font->image.data[cx+x+(cy+y)*font->image.w] = glyph->image.data[x+y*glyph->image.w];
1010 for(x=0; x<glyph->image.w+2*padding; ++x)
1012 if(cx+x<padding || cx+x>=font->image.w+padding)
1014 if(used_pixels[cx+x-padding]<cy+glyph->image.h+padding)
1015 used_pixels[cx+x-padding] = cy+glyph->image.h+padding;
1018 if(cy+glyph->image.h+margin>used_h)
1019 used_h = cy+glyph->image.h+margin;
1022 /* Trim the image to the actually used size, in case the original estimate
1023 was too pessimistic. */
1024 font->image.h = used_h;
1032 int save_defs(const char *fn, const Font *font)
1037 out = fopen(fn, "w");
1040 fprintf(stderr, "Couldn't open %s\n",fn);
1044 fprintf(out, "# Image/font info:\n");
1045 fprintf(out, "# width height size ascent descent\n");
1046 fprintf(out, "font %d %d %d %d %d\n", font->image.w, font->image.h, font->size, font->ascent, font->descent);
1047 fprintf(out, "\n# Glyph info:\n");
1048 fprintf(out, "# code x y width height offset_x offset_y advance\n");
1049 for(i=0; i<font->n_glyphs; ++i)
1051 const Glyph *g = &font->glyphs[i];
1052 fprintf(out, "glyph %u %u %u %u %u %d %d %d\n", g->code, g->x, g->y, g->image.w, g->image.h, g->offset_x, g->offset_y, g->advance);
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_code, k->right_code, 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);