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 void propagate_distance(unsigned short *, int);
85 int create_distance_field(const FT_Bitmap *, Image *, unsigned, unsigned);
86 int render_grid(Font *, unsigned, unsigned, unsigned, bool, bool);
87 int render_packed(Font *, unsigned, unsigned, bool);
88 int save_defs(const char *, const Font *);
89 int save_png(const char *, const Image *, char);
93 int main(int argc, char **argv)
97 unsigned n_ranges = 0;
108 unsigned padding = 1;
110 unsigned distfield = 0;
118 char *out_fn = "font.png";
129 while((i = getopt(argc, argv, "r:s:l:c:o:atvh?ed:pim:n:gf:")) != -1)
134 ranges = (Range *)realloc(ranges, (++n_ranges)*sizeof(Range));
135 convert_code_point_range('r', &ranges[n_ranges-1]);
138 size = convert_numeric_option('s', 1);
141 cpl = convert_numeric_option('l', 1);
144 convert_size('c', &cellw, &cellh);
175 margin = convert_numeric_option('m', 0);
178 padding = convert_numeric_option('n', 0);
184 distfield = convert_numeric_option('f', 1);
188 if(!strcmp(out_fn, "-"))
199 err = FT_Init_FreeType(&freetype);
202 fprintf(stderr, "Couldn't initialize FreeType library\n");
206 err = FT_New_Face(freetype, fn, 0, &face);
209 fprintf(stderr, "Couldn't load font file\n");
210 if(err==FT_Err_Unknown_File_Format)
211 fprintf(stderr, "Unknown file format\n");
217 const char *name = FT_Get_Postscript_Name(face);
218 printf("Font name: %s\n", name);
219 printf("Glyphs: %ld\n", face->num_glyphs);
222 err = FT_Set_Pixel_Sizes(face, 0, (distfield ? size*distfield : size));
225 fprintf(stderr, "Couldn't set size\n");
231 ranges = malloc(sizeof(Range));
233 ranges[0].last = 255;
237 sort_and_compact_ranges(ranges, &n_ranges);
240 err = init_font(&font, face, ranges, n_ranges, autohinter, distfield);
246 fprintf(stderr, "No glyphs found in the requested range\n");
251 err = render_packed(&font, margin, padding, npot);
253 err = render_grid(&font, cellw, cellh, cpl, seq, npot);
257 if(invert || distfield)
259 for(i=0; (unsigned)i<font.image.w*font.image.h; ++i)
260 font.image.data[i] = 255-font.image.data[i];
262 err = save_png(out_fn, &font.image, (alpha && !distfield));
267 save_defs(def_fn, &font);
269 for(i=0; (unsigned)i<font.n_glyphs; ++i)
270 free(font.glyphs[i].image.data);
273 free(font.image.data);
277 FT_Done_FreeType(freetype);
284 printf("ttf2png 1.1 - True Type Font to PNG converter\n"
285 "Copyright (c) 2004-2018 Mikko Rasa, Mikkosoft Productions\n"
286 "Distributed under the GNU General Public License\n\n");
288 printf("Usage: ttf2png [options] <TTF file>\n\n");
290 printf("Accepted options (default values in [brackets])\n"
291 " -r Range of code points to convert [0,255]\n"
292 " -s Font size to use, in pixels [10]\n"
293 " -l Number of glyphs to put in one line [auto]\n"
294 " -c Glyph cell size, in pixels (grid mode only) [auto]\n"
295 " -o Output file name (or - for stdout) [font.png]\n");
296 printf(" -a Force autohinter\n"
297 " -t Render glyphs to alpha channel\n"
298 " -i Invert colors of the glyphs\n"
299 " -v Increase the level of verbosity\n"
300 " -e Use cells in sequence, without gaps (grid mode only)\n"
301 " -p Pack the glyphs tightly instead of in a grid\n"
302 " -m Margin around image edges (packed mode only) [0]\n"
303 " -n Padding between glyphs (packed mode only) [1]\n"
304 " -g Allow non-power-of-two result\n"
305 " -f Create a distance field texture\n"
306 " -d File name for writing glyph definitions\n"
307 " -h Print this message\n");
310 int convert_numeric_option(char opt, int min_value)
315 value = strtol(optarg, &ptr, 0);
316 if(value<min_value || *ptr)
318 printf("Invalid option argument in -%c %s\n", opt, optarg);
325 void convert_code_point_range(char opt, Range *range)
330 if(!strcmp(optarg, "all"))
333 range->last = 0x10FFFF;
337 value = str_to_code_point(optarg, &ptr);
338 if(value>0 && *ptr==',')
340 range->first = value;
341 value = str_to_code_point(ptr+1, &ptr);
349 printf("Invalid option argument in -%c %s\n", opt, optarg);
353 unsigned str_to_code_point(const char *nptr, char **endptr)
355 if(nptr[0]=='U' && nptr[1]=='+')
356 return strtoul(nptr+2, endptr, 16);
357 else if(nptr[0]&0x80)
364 *endptr = (char *)nptr;
366 for(bytes=1; (bytes<4 && (nptr[0]&(0x80>>bytes))); ++bytes)
367 if((nptr[bytes]&0xC0)!=0x80)
372 code = nptr[0]&(0x3F>>bytes);
373 for(i=1; i<bytes; ++i)
374 code = (code<<6)|(nptr[i]&0x3F);
377 *endptr = (char *)nptr+bytes;
381 else if(isdigit(nptr[0]))
382 return strtoul(nptr, endptr, 0);
386 *endptr = (char *)nptr+1;
391 void convert_size(char opt, unsigned *width, unsigned *height)
396 if(!strcmp(optarg, "auto"))
402 else if(!strcmp(optarg, "autorect"))
409 value = strtol(optarg, &ptr, 0);
415 value = strtol(ptr+1, &ptr, 0);
429 printf("Invalid option argument in -%c %s\n", opt, optarg);
433 void sort_and_compact_ranges(Range *ranges, unsigned *n_ranges)
440 qsort(ranges, *n_ranges, sizeof(Range), &range_cmp);
441 for(i=0, j=1; j<*n_ranges; ++j)
443 if(ranges[i].last+1>=ranges[j].first)
445 if(ranges[j].last>ranges[i].last)
446 ranges[i].last = ranges[j].last;
452 ranges[i] = ranges[j];
459 int range_cmp(const void *p1, const void *p2)
461 const Range *r1 = (const Range *)p1;
462 const Range *r2 = (const Range *)p2;
463 if(r1->first!=r2->first)
464 return (r1->first<r2->first ? -1 : 1);
465 else if(r1->last!=r2->last)
466 return (r1->last<r2->last ? -1 : 1);
471 unsigned round_to_pot(unsigned n)
483 void *alloc_image_data(size_t a, size_t b)
487 /* Carry out the multiplication manually so we can check for overflow. */
496 fprintf(stderr, "Cannot allocate %lu kbytes of memory for image\n", (unsigned long)(c/1024*b));
503 fprintf(stderr, "Cannot allocate %lu kbytes of memory for image\n", (unsigned long)(a/1024*b));
507 int init_font(Font *font, FT_Face face, const Range *ranges, unsigned n_ranges, bool autohinter, unsigned distfield)
511 int scale = (distfield>0 ? distfield : 1);
513 font->ascent = (face->size->metrics.ascender/scale+63)/64;
514 font->descent = (face->size->metrics.descender/scale-63)/64;
518 printf("Ascent: %d\n", font->ascent);
519 printf("Descent: %d\n", font->descent);
524 for(i=0; i<n_ranges; ++i)
525 if(init_glyphs(font, face, &ranges[i], autohinter, distfield))
529 printf("Loaded %u glyphs\n", font->n_glyphs);
532 font->kerning = NULL;
533 for(i=0; i<font->n_glyphs; ++i) for(j=0; j<font->n_glyphs; ++j)
537 FT_Get_Kerning(face, font->glyphs[i].index, font->glyphs[j].index, FT_KERNING_DEFAULT, &kerning);
539 /* FreeType documentation says that vertical kerning is practically
540 never used, so we ignore it. */
545 if(font->n_kerning>=size)
548 font->kerning = (Kerning *)realloc(font->kerning, size*sizeof(Kerning));
551 kern = &font->kerning[font->n_kerning++];
552 kern->left_code = font->glyphs[i].code;
553 kern->right_code = font->glyphs[j].code;
554 kern->distance = (kerning.x/scale+32)/64;
559 printf("Loaded %d kerning pairs\n", font->n_kerning);
564 int init_glyphs(Font *font, FT_Face face, const Range *range, bool autohinter, unsigned distfield)
567 unsigned size = font->n_glyphs;
568 int scale = (distfield>0 ? distfield : 1);
570 for(i=range->first; i<=range->last; ++i)
573 FT_Bitmap *bmp = &face->glyph->bitmap;
577 n = FT_Get_Char_Index(face, i);
582 flags |= FT_LOAD_FORCE_AUTOHINT;
583 FT_Load_Glyph(face, n, flags);
584 FT_Render_Glyph(face->glyph, (distfield ? FT_RENDER_MODE_MONO : FT_RENDER_MODE_NORMAL));
588 printf(" Code point U+%04X", i);
589 if(i>=0x20 && i<0x7F)
591 else if(i>=0xA0 && i<=0x10FFFF)
596 for(bytes=2; i>>(1+bytes*5); ++bytes) ;
597 for(j=0; j<bytes; ++j)
598 utf8[j] = 0x80 | ((i>>((bytes-j-1)*6))&0x3F);
599 utf8[0] |= 0xF0<<(4-bytes);
602 printf(" (%s)", utf8);
604 printf(": glyph %u, size %dx%d\n", n, bmp->width/scale, bmp->rows/scale);
607 if(bmp->pixel_mode!=FT_PIXEL_MODE_GRAY && bmp->pixel_mode!=FT_PIXEL_MODE_MONO)
609 fprintf(stderr, "Warning: Glyph %u skipped, incompatible pixel mode\n", n);
613 if(font->n_glyphs>=size)
616 font->glyphs = (Glyph *)realloc(font->glyphs, size*sizeof(Glyph));
619 glyph = &font->glyphs[font->n_glyphs++];
622 glyph->offset_x = (int)(face->glyph->bitmap_left+scale/2)/scale;
623 glyph->offset_y = (int)(face->glyph->bitmap_top-bmp->rows+scale/2)/scale;
624 glyph->advance = (int)(face->glyph->advance.x/scale+32)/64;
626 /* Copy the glyph image since FreeType uses a global buffer, which would
627 be overwritten by the next glyph. Negative pitch means the scanlines
628 start from the bottom. */
633 glyph->offset_x -= margin;
634 glyph->offset_y -= margin;
635 create_distance_field(bmp, &glyph->image, distfield, margin);
639 if(copy_bitmap(bmp, &glyph->image))
647 int copy_bitmap(const FT_Bitmap *bmp, Image *image)
653 image->w = bmp->width;
654 image->h = bmp->rows;
655 if(!image->w || !image->h)
661 image->data = (unsigned char *)malloc(image->w*image->h);
664 fprintf(stderr, "Cannot allocate %d bytes of memory for glyph\n", image->w*image->h);
669 src = bmp->buffer+(bmp->rows-1)*-bmp->pitch;
674 for(y=0; y<bmp->rows; ++y)
676 if(bmp->pixel_mode==FT_PIXEL_MODE_MONO)
678 for(x=0; x<bmp->width; ++x)
679 dst[x] = ((src[x/8]&(0x80>>(x%8))) ? 0xFF : 0x00);
683 for(x=0; x<bmp->width; ++x)
694 void propagate_distance(unsigned short *pixel, int offset)
696 unsigned short *neighbor = pixel+offset;
697 if((*neighbor^*pixel)&0x8000)
698 *neighbor = (*neighbor&0x8000)+1;
699 else if((*neighbor&0x7FFF)>(*pixel&0x7FFF))
700 *neighbor = *pixel+2;
703 int create_distance_field(const FT_Bitmap *bmp, Image *image, unsigned scale, unsigned margin)
707 unsigned short *distance_map;
712 if(!bmp->width || !bmp->rows)
720 if(copy_bitmap(bmp, &base_image))
723 map_w = base_image.w+2*margin*scale+scale-1;
724 map_w -= map_w%scale;
725 map_h = base_image.h+2*margin*scale+scale-1;
726 map_h -= map_h%scale;
727 distance_map = (unsigned short *)malloc(map_w*map_h*sizeof(unsigned short));
730 fprintf(stderr, "Cannot allocate %d bytes of memory for distance map\n", map_w*map_h);
731 free(base_image.data);
735 image->w = map_w/scale;
736 image->h = map_h/scale;
737 image->data = (unsigned char *)malloc(image->w*image->h);
740 fprintf(stderr, "Cannot allocate %d bytes of memory for glyph\n", image->w*image->h);
741 free(base_image.data);
746 for(x=0; x<map_w*map_h; ++x)
747 distance_map[x] = 0x7FFF;
749 offset = margin*scale*(map_w+1);
750 for(y=0; y<base_image.h; ++y) for(x=0; x<base_image.w; ++x)
751 distance_map[offset+x+y*map_w] |= (base_image.data[x+y*base_image.w]&0x80)<<8;
753 for(y=0; y<map_h; ++y)
755 for(x=0; x+1<map_w; ++x)
756 propagate_distance(distance_map+x+y*map_w, 1);
757 for(x=map_w-1; x>0; --x)
758 propagate_distance(distance_map+x+y*map_w, -1);
761 for(x=0; x<map_w; ++x)
763 for(y=0; y+1<map_h; ++y)
764 propagate_distance(distance_map+x+y*map_w, map_w);
765 for(y=map_h-1; y>0; --y)
766 propagate_distance(distance_map+x+y*map_w, -map_w);
769 offset = scale/2*(map_w+1);
770 for(y=0; y<image->h; ++y) for(x=0; x<image->w; ++x)
772 unsigned short pixel = distance_map[offset+(x+y*map_w)*scale];
773 unsigned short dist = (pixel&0x7FFF)*0x7F/(margin*scale*2+1);
777 image->data[x+y*image->w] = 0x80+dist;
779 image->data[x+y*image->w] = 0x7F-dist;
783 free(base_image.data);
788 int render_grid(Font *font, unsigned cellw, unsigned cellh, unsigned cpl, bool seq, bool npot)
791 int top = 0, bot = 0;
792 unsigned first, last;
793 unsigned maxw = 0, maxh = 0;
795 /* Find extremes of the glyph images. */
796 for(i=0; i<font->n_glyphs; ++i)
800 y = font->glyphs[i].offset_y+font->glyphs[i].image.h;
803 if(font->glyphs[i].offset_y<bot)
804 bot = font->glyphs[i].offset_y;
805 if(font->glyphs[i].image.w>maxw)
806 maxw = font->glyphs[i].image.w;
807 if(font->glyphs[i].image.h>maxh)
808 maxh = font->glyphs[i].image.h;
813 /* Establish a large enough cell to hold all glyphs in the range. */
814 int square = (cellh==cellw);
828 printf("Max size: %u x %u\n", maxw, maxh);
829 printf("Y range: [%d %d]\n", bot, top);
830 printf("Cell size: %u x %u\n", cellw, cellh);
831 if(maxw>cellw || (unsigned)(top-bot)>cellh)
832 fprintf(stderr, "Warning: character size exceeds cell size\n");
837 /* Determine number of characters per line, trying to fit all the glyphs
838 in a square image. */
842 if(cpl>0 && font->n_glyphs/cpl*cellh<=cpl*cellw)
847 first = font->glyphs[0].code;
850 last = font->glyphs[font->n_glyphs-1].code;
852 font->image.w = cpl*cellw;
854 font->image.w = round_to_pot(font->image.w);
856 font->image.h = (font->n_glyphs+cpl-1)/cpl*cellh;
858 font->image.h = (last-first+cpl)/cpl*cellh;
860 font->image.h = round_to_pot(font->image.h);
862 font->image.data = (unsigned char *)alloc_image_data(font->image.w, font->image.h);
863 if(!font->image.data)
865 memset(font->image.data, 255, font->image.w*font->image.h);
867 for(i=0; i<font->n_glyphs; ++i)
873 glyph = &font->glyphs[i];
878 ci = glyph->code-first;
883 if(cellw>glyph->image.w)
884 cx += (cellw-glyph->image.w)/2;
885 cy += top-glyph->offset_y-glyph->image.h;
890 for(y=0; y<glyph->image.h; ++y) for(x=0; x<glyph->image.w; ++x)
892 if(cx+x>=font->image.w || cy+y>=font->image.h)
894 font->image.data[cx+x+(cy+y)*font->image.w] = 255-glyph->image.data[x+y*glyph->image.w];
901 int render_packed(Font *font, unsigned margin, unsigned padding, bool npot)
906 unsigned *used_pixels;
907 unsigned cx = margin, cy;
910 /* Compute the total area occupied by glyphs and padding. */
911 for(i=0; i<font->n_glyphs; ++i)
913 size_t a = area+(font->glyphs[i].image.w+padding)*(font->glyphs[i].image.h+padding);
916 fprintf(stderr, "Overflow in counting total glyph area\n");
922 /* Find an image size that's approximately square. */
923 for(font->image.w=1;; font->image.w<<=1)
925 if(font->image.w<=margin*2)
927 font->image.h = area/(font->image.w-margin*2)+margin*2;
928 if(font->image.h<=font->image.w)
932 /* Add some extra space to accommodate packing imperfections. */
933 font->image.h = font->image.h*3/2;
935 /* Allocate arrays for storing the image and keeping track of used pixels and
936 glyphs. Since glyphs are rectangular and the image is filled starting from
937 the top, it's enough to track the number of used pixels at the top of each
939 font->image.data = (unsigned char *)alloc_image_data(font->image.w, font->image.h);
940 if(!font->image.data)
942 memset(font->image.data, 255, font->image.w*font->image.h);
943 used_pixels = (unsigned *)malloc(font->image.w*sizeof(unsigned));
944 memset(used_pixels, 0, font->image.w*sizeof(unsigned));
945 used_glyphs = (char *)malloc(font->n_glyphs);
946 memset(used_glyphs, 0, font->n_glyphs);
948 for(cy=margin; cy+margin<font->image.h;)
953 unsigned best_score = 0;
954 unsigned target_h = 0;
956 /* Find the leftmost free pixel on this row. Also record the lowest
957 extent of glyphs to the left of the free position. */
958 for(; (cx+margin<font->image.w && used_pixels[cx]>cy); ++cx)
959 if(used_pixels[cx]-cy-padding>target_h)
960 target_h = used_pixels[cx]-cy-padding;
962 if(cx+margin>=font->image.w)
969 /* Count the free pixel at this position. */
970 for(w=0; (cx+w+margin<font->image.w && used_pixels[cx+w]<=cy); ++w) ;
972 /* Find a suitable glyph to put here. */
973 for(i=0; i<font->n_glyphs; ++i)
977 g = &font->glyphs[i];
978 if(!used_glyphs[i] && g->image.w<=w)
982 /* Prefer glyphs that would reach exactly as low as the ones left
983 of here. This aims to create a straight edge at the bottom for
984 lining up further glyphs. */
985 score = g->image.h+padding;
986 if(g->image.h==target_h)
1005 used_glyphs[glyph-font->glyphs] = 1;
1009 for(y=0; y<glyph->image.h; ++y) for(x=0; x<glyph->image.w; ++x)
1011 if(cx+x>=font->image.w || cy+y>=font->image.h)
1013 font->image.data[cx+x+(cy+y)*font->image.w] = 255-glyph->image.data[x+y*glyph->image.w];
1015 for(x=0; x<glyph->image.w+2*padding; ++x)
1017 if(cx+x<padding || cx+x>=font->image.w+padding)
1019 if(used_pixels[cx+x-padding]<cy+glyph->image.h+padding)
1020 used_pixels[cx+x-padding] = cy+glyph->image.h+padding;
1023 if(cy+glyph->image.h+margin>used_h)
1024 used_h = cy+glyph->image.h+margin;
1027 /* Trim the image to the actually used size, in case the original estimate
1028 was too pessimistic. */
1029 font->image.h = used_h;
1031 font->image.h = round_to_pot(font->image.h);
1039 int save_defs(const char *fn, const Font *font)
1044 out = fopen(fn, "w");
1047 fprintf(stderr, "Couldn't open %s\n",fn);
1051 fprintf(out, "# Image/font info:\n");
1052 fprintf(out, "# width height size ascent descent\n");
1053 fprintf(out, "font %d %d %d %d %d\n", font->image.w, font->image.h, font->size, font->ascent, font->descent);
1054 fprintf(out, "\n# Glyph info:\n");
1055 fprintf(out, "# code x y width height offset_x offset_y advance\n");
1056 for(i=0; i<font->n_glyphs; ++i)
1058 const Glyph *g = &font->glyphs[i];
1059 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);
1061 fprintf(out, "\n# Kerning info:\n");
1062 fprintf(out, "# left right distance\n");
1063 for(i=0; i<font->n_kerning; ++i)
1065 const Kerning *k = &font->kerning[i];
1066 fprintf(out, "kern %u %u %d\n", k->left_code, k->right_code, k->distance);
1074 int save_png(const char *fn, const Image *image, char alpha)
1081 png_byte *data2 = 0;
1084 if(!strcmp(fn, "-"))
1088 out = fopen(fn, "wb");
1091 fprintf(stderr, "Couldn't open %s\n",fn);
1096 pngs = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
1099 fprintf(stderr, "Error writing PNG file\n");
1102 pngi = png_create_info_struct(pngs);
1105 png_destroy_write_struct(&pngs, NULL);
1106 fprintf(stderr, "Error writing PNG file\n");
1110 png_init_io(pngs, out);
1111 rows = (png_byte **)malloc(image->h*sizeof(png_byte *));
1114 data2 = (png_byte *)alloc_image_data(image->w*2, image->h);
1117 for(i=0; i<image->w*image->h; ++i)
1120 data2[i*2+1] = 255-image->data[i];
1122 for(i=0; i<image->h; ++i)
1123 rows[i] = (png_byte *)(data2+i*image->w*2);
1124 color = PNG_COLOR_TYPE_GRAY_ALPHA;
1128 for(i=0; i<image->h; ++i)
1129 rows[i] = (png_byte *)(image->data+i*image->w);
1130 color = PNG_COLOR_TYPE_GRAY;
1132 png_set_IHDR(pngs, pngi, image->w, image->h, 8, color, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
1133 png_set_rows(pngs, pngi, rows);
1134 png_write_png(pngs, pngi, PNG_TRANSFORM_IDENTITY, NULL);
1135 png_destroy_write_struct(&pngs, &pngi);
1141 printf("Saved %dx%d PNG image to %s\n", image->w, image->h, fn);