2 ttf2png - True Type Font to PNG converter
3 Copyright (c) 2004-2008 Mikko Rasa
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);
82 int init_glyphs(Font *, FT_Face, const Range *, bool, 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, bool);
88 int render_packed(Font *, unsigned, unsigned, bool);
89 int save_defs(const char *, const Font *);
90 int save_png(const char *, const Image *, char);
94 int main(int argc, char **argv)
98 unsigned n_ranges = 0;
109 unsigned padding = 1;
111 unsigned distfield = 0;
119 char *out_fn = "font.png";
130 while((i = getopt(argc, argv, "r:s:l:c:o:atvh?ed:pim:n:gf:")) != -1)
135 ranges = (Range *)realloc(ranges, (++n_ranges)*sizeof(Range));
136 convert_code_point_range('r', &ranges[n_ranges-1]);
139 size = convert_numeric_option('s', 1);
142 cpl = convert_numeric_option('l', 1);
145 convert_size('c', &cellw, &cellh);
176 margin = convert_numeric_option('m', 0);
179 padding = convert_numeric_option('n', 0);
185 distfield = convert_numeric_option('f', 1);
189 if(!strcmp(out_fn, "-"))
200 err = FT_Init_FreeType(&freetype);
203 fprintf(stderr, "Couldn't initialize FreeType library\n");
207 err = FT_New_Face(freetype, fn, 0, &face);
210 fprintf(stderr, "Couldn't load font file\n");
211 if(err==FT_Err_Unknown_File_Format)
212 fprintf(stderr, "Unknown file format\n");
218 const char *name = FT_Get_Postscript_Name(face);
219 printf("Font name: %s\n", name);
220 printf("Glyphs: %ld\n", face->num_glyphs);
223 err = FT_Set_Pixel_Sizes(face, 0, (distfield ? size*distfield : size));
226 fprintf(stderr, "Couldn't set size\n");
232 ranges = malloc(sizeof(Range));
234 ranges[0].last = 255;
238 sort_and_compact_ranges(ranges, &n_ranges);
241 err = init_font(&font, face, ranges, n_ranges, autohinter, distfield);
247 fprintf(stderr, "No glyphs found in the requested range\n");
252 err = render_packed(&font, margin, padding, npot);
254 err = render_grid(&font, cellw, cellh, cpl, seq, npot);
258 if(invert || distfield)
260 for(i=0; (unsigned)i<font.image.w*font.image.h; ++i)
261 font.image.data[i] = 255-font.image.data[i];
263 err = save_png(out_fn, &font.image, (alpha && !distfield));
268 save_defs(def_fn, &font);
270 for(i=0; (unsigned)i<font.n_glyphs; ++i)
271 free(font.glyphs[i].image.data);
274 free(font.image.data);
278 FT_Done_FreeType(freetype);
285 printf("ttf2png 1.1 - True Type Font to PNG converter\n"
286 "Copyright (c) 2004-2018 Mikko Rasa, Mikkosoft Productions\n"
287 "Distributed under the GNU General Public License\n\n");
289 printf("Usage: ttf2png [options] <TTF file>\n\n");
291 printf("Accepted options (default values in [brackets])\n"
292 " -r Range of code points to convert [0,255]\n"
293 " -s Font size to use, in pixels [10]\n"
294 " -l Number of glyphs to put in one line [auto]\n"
295 " -c Glyph cell size, in pixels (grid mode only) [auto]\n"
296 " -o Output file name (or - for stdout) [font.png]\n");
297 printf(" -a Force autohinter\n"
298 " -t Render glyphs to alpha channel\n"
299 " -i Invert colors of the glyphs\n"
300 " -v Increase the level of verbosity\n"
301 " -e Use cells in sequence, without gaps (grid mode only)\n"
302 " -p Pack the glyphs tightly instead of in a grid\n"
303 " -m Margin around image edges (packed mode only) [0]\n"
304 " -n Padding between glyphs (packed mode only) [1]\n"
305 " -g Allow non-power-of-two result\n"
306 " -f Create a distance field texture\n"
307 " -d File name for writing glyph definitions\n"
308 " -h Print this message\n");
311 int convert_numeric_option(char opt, int min_value)
316 value = strtol(optarg, &ptr, 0);
317 if(value<min_value || *ptr)
319 printf("Invalid option argument in -%c %s\n", opt, optarg);
326 void convert_code_point_range(char opt, Range *range)
331 if(!strcmp(optarg, "all"))
334 range->last = 0x10FFFF;
338 value = str_to_code_point(optarg, &ptr);
339 if(value>0 && *ptr==',')
341 range->first = value;
342 value = str_to_code_point(ptr+1, &ptr);
350 printf("Invalid option argument in -%c %s\n", opt, optarg);
354 unsigned str_to_code_point(const char *nptr, char **endptr)
356 if(nptr[0]=='U' && nptr[1]=='+')
357 return strtoul(nptr+2, endptr, 16);
358 else if(nptr[0]&0x80)
365 *endptr = (char *)nptr;
367 for(bytes=1; (bytes<4 && (nptr[0]&(0x80>>bytes))); ++bytes)
368 if((nptr[bytes]&0xC0)!=0x80)
373 code = nptr[0]&(0x3F>>bytes);
374 for(i=1; i<bytes; ++i)
375 code = (code<<6)|(nptr[i]&0x3F);
378 *endptr = (char *)nptr+bytes;
382 else if(isdigit(nptr[0]))
383 return strtoul(nptr, endptr, 0);
387 *endptr = (char *)nptr+1;
392 void convert_size(char opt, unsigned *width, unsigned *height)
397 if(!strcmp(optarg, "auto"))
403 else if(!strcmp(optarg, "autorect"))
410 value = strtol(optarg, &ptr, 0);
416 value = strtol(ptr+1, &ptr, 0);
430 printf("Invalid option argument in -%c %s\n", opt, optarg);
434 void sort_and_compact_ranges(Range *ranges, unsigned *n_ranges)
441 qsort(ranges, *n_ranges, sizeof(Range), &range_cmp);
442 for(i=0, j=1; j<*n_ranges; ++j)
444 if(ranges[i].last+1>=ranges[j].first)
446 if(ranges[j].last>ranges[i].last)
447 ranges[i].last = ranges[j].last;
453 ranges[i] = ranges[j];
460 int range_cmp(const void *p1, const void *p2)
462 const Range *r1 = (const Range *)p1;
463 const Range *r2 = (const Range *)p2;
464 if(r1->first!=r2->first)
465 return (r1->first<r2->first ? -1 : 1);
466 else if(r1->last!=r2->last)
467 return (r1->last<r2->last ? -1 : 1);
472 unsigned round_to_pot(unsigned n)
484 void *alloc_image_data(size_t a, size_t b)
488 /* Carry out the multiplication manually so we can check for overflow. */
497 fprintf(stderr, "Cannot allocate %lu kbytes of memory for image\n", (unsigned long)(c/1024*b));
504 fprintf(stderr, "Cannot allocate %lu kbytes of memory for image\n", (unsigned long)(a/1024*b));
508 int init_font(Font *font, FT_Face face, const Range *ranges, unsigned n_ranges, bool autohinter, unsigned distfield)
512 int scale = (distfield>0 ? distfield : 1);
514 font->ascent = (face->size->metrics.ascender/scale+63)/64;
515 font->descent = (face->size->metrics.descender/scale-63)/64;
519 printf("Ascent: %d\n", font->ascent);
520 printf("Descent: %d\n", font->descent);
525 for(i=0; i<n_ranges; ++i)
526 if(init_glyphs(font, face, &ranges[i], autohinter, distfield))
530 printf("Loaded %u glyphs\n", font->n_glyphs);
533 font->kerning = NULL;
534 for(i=0; i<font->n_glyphs; ++i) for(j=0; j<font->n_glyphs; ++j)
538 FT_Get_Kerning(face, font->glyphs[i].index, font->glyphs[j].index, FT_KERNING_DEFAULT, &kerning);
540 /* FreeType documentation says that vertical kerning is practically
541 never used, so we ignore it. */
546 if(font->n_kerning>=size)
549 font->kerning = (Kerning *)realloc(font->kerning, size*sizeof(Kerning));
552 kern = &font->kerning[font->n_kerning++];
553 kern->left_code = font->glyphs[i].code;
554 kern->right_code = font->glyphs[j].code;
555 kern->distance = (kerning.x/scale+32)/64;
560 printf("Loaded %d kerning pairs\n", font->n_kerning);
565 int init_glyphs(Font *font, FT_Face face, const Range *range, bool autohinter, unsigned distfield)
568 unsigned size = font->n_glyphs;
569 int scale = (distfield>0 ? distfield : 1);
571 for(i=range->first; i<=range->last; ++i)
574 FT_Bitmap *bmp = &face->glyph->bitmap;
578 n = FT_Get_Char_Index(face, i);
583 flags |= FT_LOAD_FORCE_AUTOHINT;
584 FT_Load_Glyph(face, n, flags);
585 FT_Render_Glyph(face->glyph, (distfield ? FT_RENDER_MODE_MONO : FT_RENDER_MODE_NORMAL));
589 printf(" Code point U+%04X", i);
590 if(i>=0x20 && i<0x7F)
592 else if(i>=0xA0 && i<=0x10FFFF)
597 for(bytes=2; i>>(1+bytes*5); ++bytes) ;
598 for(j=0; j<bytes; ++j)
599 utf8[j] = 0x80 | ((i>>((bytes-j-1)*6))&0x3F);
600 utf8[0] |= 0xF0<<(4-bytes);
603 printf(" (%s)", utf8);
605 printf(": glyph %u, size %dx%d\n", n, bmp->width/scale, bmp->rows/scale);
608 if(bmp->pixel_mode!=FT_PIXEL_MODE_GRAY && bmp->pixel_mode!=FT_PIXEL_MODE_MONO)
610 fprintf(stderr, "Warning: Glyph %u skipped, incompatible pixel mode\n", n);
614 if(font->n_glyphs>=size)
617 font->glyphs = (Glyph *)realloc(font->glyphs, size*sizeof(Glyph));
620 glyph = &font->glyphs[font->n_glyphs++];
623 glyph->offset_x = (int)(face->glyph->bitmap_left+scale/2)/scale;
624 glyph->offset_y = (int)(face->glyph->bitmap_top-bmp->rows+scale/2)/scale;
625 glyph->advance = (int)(face->glyph->advance.x/scale+32)/64;
627 /* Copy the glyph image since FreeType uses a global buffer, which would
628 be overwritten by the next glyph. Negative pitch means the scanlines
629 start from the bottom. */
634 glyph->offset_x -= margin;
635 glyph->offset_y -= margin;
636 create_distance_field(bmp, &glyph->image, distfield, margin);
640 if(copy_bitmap(bmp, &glyph->image))
648 int copy_bitmap(const FT_Bitmap *bmp, Image *image)
654 image->w = bmp->width;
655 image->h = bmp->rows;
656 if(!image->w || !image->h)
662 image->data = (unsigned char *)malloc(image->w*image->h);
665 fprintf(stderr, "Cannot allocate %d bytes of memory for glyph\n", 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(!bmp->width || !bmp->rows)
753 if(copy_bitmap(bmp, &base_image))
756 image->w = (base_image.w-1)/scale+2*margin+1;
757 image->h = (base_image.h-1)/scale+2*margin+1;
758 image->data = (unsigned char *)malloc(image->w*image->h);
761 fprintf(stderr, "Cannot allocate %d bytes of memory for glyph\n", image->w*image->h);
762 free(base_image.data);
766 for(y=0; y<image->h; ++y) for(x=0; x<image->w; ++x)
768 int bx = (x-margin)*scale+scale/2;
769 int by = (y-margin)*scale+scale/2;
770 unsigned char pixel = find_distance_to_edge(&base_image, bx, by, margin*scale);
771 if(bx>=0 && (unsigned)bx<base_image.w && by>=0 && (unsigned)by<base_image.h)
772 pixel |= base_image.data[bx+by*base_image.w]&0x80;
775 image->data[x+y*image->w] = pixel;
778 free(base_image.data);
783 int render_grid(Font *font, unsigned cellw, unsigned cellh, unsigned cpl, bool seq, bool npot)
786 int top = 0, bot = 0;
787 unsigned first, last;
788 unsigned maxw = 0, maxh = 0;
790 /* Find extremes of the glyph images. */
791 for(i=0; i<font->n_glyphs; ++i)
795 y = font->glyphs[i].offset_y+font->glyphs[i].image.h;
798 if(font->glyphs[i].offset_y<bot)
799 bot = font->glyphs[i].offset_y;
800 if(font->glyphs[i].image.w>maxw)
801 maxw = font->glyphs[i].image.w;
802 if(font->glyphs[i].image.h>maxh)
803 maxh = font->glyphs[i].image.h;
808 /* Establish a large enough cell to hold all glyphs in the range. */
809 int square = (cellh==cellw);
823 printf("Max size: %u x %u\n", maxw, maxh);
824 printf("Y range: [%d %d]\n", bot, top);
825 printf("Cell size: %u x %u\n", cellw, cellh);
826 if(maxw>cellw || (unsigned)(top-bot)>cellh)
827 fprintf(stderr, "Warning: character size exceeds cell size\n");
832 /* Determine number of characters per line, trying to fit all the glyphs
833 in a square image. */
837 if(cpl>0 && font->n_glyphs/cpl*cellh<=cpl*cellw)
842 first = font->glyphs[0].code;
845 last = font->glyphs[font->n_glyphs-1].code;
847 font->image.w = cpl*cellw;
849 font->image.w = round_to_pot(font->image.w);
851 font->image.h = (font->n_glyphs+cpl-1)/cpl*cellh;
853 font->image.h = (last-first+cpl)/cpl*cellh;
855 font->image.h = round_to_pot(font->image.h);
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, 255, 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] = 255-glyph->image.data[x+y*glyph->image.w];
896 int render_packed(Font *font, unsigned margin, unsigned padding, bool npot)
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, 255, 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] = 255-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;
1026 font->image.h = round_to_pot(font->image.h);
1034 int save_defs(const char *fn, const Font *font)
1039 out = fopen(fn, "w");
1042 fprintf(stderr, "Couldn't open %s\n",fn);
1046 fprintf(out, "# Image/font info:\n");
1047 fprintf(out, "# width height size ascent descent\n");
1048 fprintf(out, "font %d %d %d %d %d\n", font->image.w, font->image.h, font->size, font->ascent, font->descent);
1049 fprintf(out, "\n# Glyph info:\n");
1050 fprintf(out, "# code x y width height offset_x offset_y advance\n");
1051 for(i=0; i<font->n_glyphs; ++i)
1053 const Glyph *g = &font->glyphs[i];
1054 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);
1056 fprintf(out, "\n# Kerning info:\n");
1057 fprintf(out, "# left right distance\n");
1058 for(i=0; i<font->n_kerning; ++i)
1060 const Kerning *k = &font->kerning[i];
1061 fprintf(out, "kern %u %u %d\n", k->left_code, k->right_code, k->distance);
1069 int save_png(const char *fn, const Image *image, char alpha)
1076 png_byte *data2 = 0;
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 png_init_io(pngs, out);
1106 rows = (png_byte **)malloc(image->h*sizeof(png_byte *));
1109 data2 = (png_byte *)alloc_image_data(image->w*2, image->h);
1112 for(i=0; i<image->w*image->h; ++i)
1115 data2[i*2+1] = 255-image->data[i];
1117 for(i=0; i<image->h; ++i)
1118 rows[i] = (png_byte *)(data2+i*image->w*2);
1119 color = PNG_COLOR_TYPE_GRAY_ALPHA;
1123 for(i=0; i<image->h; ++i)
1124 rows[i] = (png_byte *)(image->data+i*image->w);
1125 color = PNG_COLOR_TYPE_GRAY;
1127 png_set_IHDR(pngs, pngi, image->w, image->h, 8, color, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
1128 png_set_rows(pngs, pngi, rows);
1129 png_write_png(pngs, pngi, PNG_TRANSFORM_IDENTITY, NULL);
1130 png_destroy_write_struct(&pngs, &pngi);
1136 printf("Saved %dx%d PNG image to %s\n", image->w, image->h, fn);