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);
82 int init_glyphs(Font *, FT_Face, const Range *, bool);
83 int copy_bitmap(const FT_Bitmap *, Image *);
84 int render_grid(Font *, unsigned, unsigned, unsigned, bool, bool);
85 int render_packed(Font *, unsigned, unsigned, bool);
86 int save_defs(const char *, const Font *);
87 int save_png(const char *, const Image *, char);
91 int main(int argc, char **argv)
95 unsigned n_ranges = 0;
106 unsigned padding = 1;
115 char *out_fn = "font.png";
126 while((i = getopt(argc, argv, "r:s:l:c:o:atvh?ed:pim:n:f")) != -1)
131 ranges = (Range *)realloc(ranges, (++n_ranges)*sizeof(Range));
132 convert_code_point_range('r', &ranges[n_ranges-1]);
135 size = convert_numeric_option('s', 1);
138 cpl = convert_numeric_option('l', 1);
141 convert_size('c', &cellw, &cellh);
172 margin = convert_numeric_option('m', 0);
175 padding = convert_numeric_option('n', 0);
182 if(!strcmp(out_fn, "-"))
193 err = FT_Init_FreeType(&freetype);
196 fprintf(stderr, "Couldn't initialize FreeType library\n");
200 err = FT_New_Face(freetype, fn, 0, &face);
203 fprintf(stderr, "Couldn't load font file\n");
204 if(err==FT_Err_Unknown_File_Format)
205 fprintf(stderr, "Unknown file format\n");
211 const char *name = FT_Get_Postscript_Name(face);
212 printf("Font name: %s\n", name);
213 printf("Glyphs: %ld\n", face->num_glyphs);
216 err = FT_Set_Pixel_Sizes(face, 0, size);
219 fprintf(stderr, "Couldn't set size\n");
225 ranges = malloc(sizeof(Range));
227 ranges[0].last = 255;
231 sort_and_compact_ranges(ranges, &n_ranges);
234 err = init_font(&font, face, ranges, n_ranges, autohinter);
240 fprintf(stderr, "No glyphs found in the requested range\n");
245 err = render_packed(&font, margin, padding, npot);
247 err = render_grid(&font, cellw, cellh, cpl, seq, npot);
253 for(i=0; (unsigned)i<font.image.w*font.image.h; ++i)
254 font.image.data[i] = 255-font.image.data[i];
256 err = save_png(out_fn, &font.image, alpha);
261 save_defs(def_fn, &font);
263 for(i=0; (unsigned)i<font.n_glyphs; ++i)
264 free(font.glyphs[i].image.data);
267 free(font.image.data);
270 FT_Done_FreeType(freetype);
277 printf("ttf2png 1.1 - True Type Font to PNG converter\n"
278 "Copyright (c) 2004-2018 Mikko Rasa, Mikkosoft Productions\n"
279 "Distributed under the GNU General Public License\n\n");
281 printf("Usage: ttf2png [options] <TTF file>\n\n");
283 printf("Accepted options (default values in [brackets])\n"
284 " -r Range of code points to convert [0,255]\n"
285 " -s Font size to use, in pixels [10]\n"
286 " -l Number of glyphs to put in one line [auto]\n"
287 " -c Glyph cell size, in pixels (grid mode only) [auto]\n"
288 " -o Output file name (or - for stdout) [font.png]\n");
289 printf(" -a Force autohinter\n"
290 " -t Render glyphs to alpha channel\n"
291 " -i Invert colors of the glyphs\n"
292 " -v Increase the level of verbosity\n"
293 " -e Use cells in sequence, without gaps (grid mode only)\n"
294 " -p Pack the glyphs tightly instead of in a grid\n"
295 " -m Margin around image edges (packed mode only) [0]\n"
296 " -n Padding between glyphs (packed mode only) [1]\n"
297 " -f Allow non-power-of-two result\n"
298 " -d File name for writing glyph definitions\n"
299 " -h Print this message\n");
302 int convert_numeric_option(char opt, int min_value)
307 value = strtol(optarg, &ptr, 0);
308 if(value<min_value || *ptr)
310 printf("Invalid option argument in -%c %s\n", opt, optarg);
317 void convert_code_point_range(char opt, Range *range)
322 if(!strcmp(optarg, "all"))
325 range->last = 0x10FFFF;
329 value = str_to_code_point(optarg, &ptr);
330 if(value>0 && *ptr==',')
332 range->first = value;
333 value = str_to_code_point(ptr+1, &ptr);
341 printf("Invalid option argument in -%c %s\n", opt, optarg);
345 unsigned str_to_code_point(const char *nptr, char **endptr)
347 if(nptr[0]=='U' && nptr[1]=='+')
348 return strtoul(nptr+2, endptr, 16);
349 else if(nptr[0]&0x80)
356 *endptr = (char *)nptr;
358 for(bytes=1; (bytes<4 && (nptr[0]&(0x80>>bytes))); ++bytes)
359 if((nptr[bytes]&0xC0)!=0x80)
364 code = nptr[0]&(0x3F>>bytes);
365 for(i=1; i<bytes; ++i)
366 code = (code<<6)|(nptr[i]&0x3F);
369 *endptr = (char *)nptr+bytes;
373 else if(isdigit(nptr[0]))
374 return strtoul(nptr, endptr, 0);
378 *endptr = (char *)nptr+1;
383 void convert_size(char opt, unsigned *width, unsigned *height)
388 if(!strcmp(optarg, "auto"))
394 else if(!strcmp(optarg, "autorect"))
401 value = strtol(optarg, &ptr, 0);
407 value = strtol(ptr+1, &ptr, 0);
421 printf("Invalid option argument in -%c %s\n", opt, optarg);
425 void sort_and_compact_ranges(Range *ranges, unsigned *n_ranges)
432 qsort(ranges, *n_ranges, sizeof(Range), &range_cmp);
433 for(i=0, j=1; j<*n_ranges; ++j)
435 if(ranges[i].last+1>=ranges[j].first)
437 if(ranges[j].last>ranges[i].last)
438 ranges[i].last = ranges[j].last;
444 ranges[i] = ranges[j];
451 int range_cmp(const void *p1, const void *p2)
453 const Range *r1 = (const Range *)p1;
454 const Range *r2 = (const Range *)p2;
455 if(r1->first!=r2->first)
456 return (r1->first<r2->first ? -1 : 1);
457 else if(r1->last!=r2->last)
458 return (r1->last<r2->last ? -1 : 1);
463 unsigned round_to_pot(unsigned n)
475 void *alloc_image_data(size_t a, size_t b)
479 /* Carry out the multiplication manually so we can check for overflow. */
488 fprintf(stderr, "Cannot allocate %lu kbytes of memory for image\n", (unsigned long)(c/1024*b));
495 fprintf(stderr, "Cannot allocate %lu kbytes of memory for image\n", (unsigned long)(a/1024*b));
499 int init_font(Font *font, FT_Face face, const Range *ranges, unsigned n_ranges, bool autohinter)
504 font->ascent = (face->size->metrics.ascender+63)>>6;
505 font->descent = (face->size->metrics.descender+63)>>6;
509 printf("Ascent: %d\n", font->ascent);
510 printf("Descent: %d\n", font->descent);
515 for(i=0; i<n_ranges; ++i)
516 if(init_glyphs(font, face, &ranges[i], autohinter))
520 printf("Loaded %u glyphs\n", font->n_glyphs);
523 font->kerning = NULL;
524 for(i=0; i<font->n_glyphs; ++i) for(j=0; j<font->n_glyphs; ++j)
528 FT_Get_Kerning(face, font->glyphs[i].index, font->glyphs[j].index, FT_KERNING_DEFAULT, &kerning);
530 /* FreeType documentation says that vertical kerning is practically
531 never used, so we ignore it. */
536 if(font->n_kerning>=size)
539 font->kerning = (Kerning *)realloc(font->kerning, size*sizeof(Kerning));
542 kern = &font->kerning[font->n_kerning++];
543 kern->left_code = font->glyphs[i].code;
544 kern->right_code = font->glyphs[j].code;
545 kern->distance = kerning.x/64;
550 printf("Loaded %d kerning pairs\n", font->n_kerning);
555 int init_glyphs(Font *font, FT_Face face, const Range *range, bool autohinter)
558 unsigned size = font->n_glyphs;
560 for(i=range->first; i<=range->last; ++i)
563 FT_Bitmap *bmp = &face->glyph->bitmap;
567 n = FT_Get_Char_Index(face, i);
572 flags |= FT_LOAD_FORCE_AUTOHINT;
573 FT_Load_Glyph(face, n, flags);
574 FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
578 printf(" Code point U+%04X", i);
579 if(i>=0x20 && i<0x7F)
581 else if(i>=0xA0 && i<=0x10FFFF)
586 for(bytes=2; i>>(1+bytes*5); ++bytes) ;
587 for(j=0; j<bytes; ++j)
588 utf8[j] = 0x80 | ((i>>((bytes-j-1)*6))&0x3F);
589 utf8[0] |= 0xF0<<(4-bytes);
592 printf(" (%s)", utf8);
594 printf(": glyph %u, size %dx%d\n", n, bmp->width, bmp->rows);
597 if(bmp->pixel_mode!=FT_PIXEL_MODE_GRAY)
599 fprintf(stderr, "Warning: Glyph %u skipped, not grayscale\n", n);
603 if(font->n_glyphs>=size)
606 font->glyphs = (Glyph *)realloc(font->glyphs, size*sizeof(Glyph));
609 glyph = &font->glyphs[font->n_glyphs++];
612 glyph->offset_x = face->glyph->bitmap_left;
613 glyph->offset_y = face->glyph->bitmap_top-bmp->rows;
614 glyph->advance = (int)(face->glyph->advance.x+32)/64;
616 /* Copy the glyph image since FreeType uses a global buffer, which would
617 be overwritten by the next glyph. Negative pitch means the scanlines
618 start from the bottom. */
619 if(copy_bitmap(bmp, &glyph->image))
626 int copy_bitmap(const FT_Bitmap *bmp, Image *image)
632 image->w = bmp->width;
633 image->h = bmp->rows;
634 if(!image->w || !image->h)
640 image->data = (char *)malloc(image->w*image->h);
643 fprintf(stderr, "Cannot allocate %d bytes of memory for glyph\n", image->w*image->h);
648 src = bmp->buffer+(bmp->rows-1)*-bmp->pitch;
653 for(y=0; y<bmp->rows; ++y)
655 for(x=0; x<bmp->width; ++x)
665 int render_grid(Font *font, unsigned cellw, unsigned cellh, unsigned cpl, bool seq, bool npot)
668 int top = 0, bot = 0;
669 unsigned first, last;
670 unsigned maxw = 0, maxh = 0;
672 /* Find extremes of the glyph images. */
673 for(i=0; i<font->n_glyphs; ++i)
677 y = font->glyphs[i].offset_y+font->glyphs[i].image.h;
680 if(font->glyphs[i].offset_y<bot)
681 bot = font->glyphs[i].offset_y;
682 if(font->glyphs[i].image.w>maxw)
683 maxw = font->glyphs[i].image.w;
684 if(font->glyphs[i].image.h>maxh)
685 maxh = font->glyphs[i].image.h;
690 /* Establish a large enough cell to hold all glyphs in the range. */
691 int square = (cellh==cellw);
705 printf("Max size: %u x %u\n", maxw, maxh);
706 printf("Y range: [%d %d]\n", bot, top);
707 printf("Cell size: %u x %u\n", cellw, cellh);
708 if(maxw>cellw || (unsigned)(top-bot)>cellh)
709 fprintf(stderr, "Warning: character size exceeds cell size\n");
714 /* Determine number of characters per line, trying to fit all the glyphs
715 in a square image. */
719 if(cpl>0 && font->n_glyphs/cpl*cellh<=cpl*cellw)
724 first = font->glyphs[0].code;
727 last = font->glyphs[font->n_glyphs-1].code;
729 font->image.w = cpl*cellw;
731 font->image.w = round_to_pot(font->image.w);
733 font->image.h = (font->n_glyphs+cpl-1)/cpl*cellh;
735 font->image.h = (last-first+cpl)/cpl*cellh;
737 font->image.h = round_to_pot(font->image.h);
739 font->image.data = (char *)alloc_image_data(font->image.w, font->image.h);
740 if(!font->image.data)
742 memset(font->image.data, 255, font->image.w*font->image.h);
744 for(i=0; i<font->n_glyphs; ++i)
750 glyph = &font->glyphs[i];
755 ci = glyph->code-first;
760 if(cellw>glyph->image.w)
761 cx += (cellw-glyph->image.w)/2;
762 cy += top-glyph->offset_y-glyph->image.h;
767 for(y=0; y<glyph->image.h; ++y) for(x=0; x<glyph->image.w; ++x)
769 if(cx+x>=font->image.w || cy+y>=font->image.h)
771 font->image.data[cx+x+(cy+y)*font->image.w] = 255-glyph->image.data[x+y*glyph->image.w];
778 int render_packed(Font *font, unsigned margin, unsigned padding, bool npot)
783 unsigned *used_pixels;
784 unsigned cx = margin, cy;
787 /* Compute the total area occupied by glyphs and padding. */
788 for(i=0; i<font->n_glyphs; ++i)
790 size_t a = area+(font->glyphs[i].image.w+padding)*(font->glyphs[i].image.h+padding);
793 fprintf(stderr, "Overflow in counting total glyph area\n");
799 /* Find an image size that's no higher than wide, allowing for some
800 imperfections in the packing. */
801 for(font->image.w=1;; font->image.w<<=1)
803 if(font->image.w<=margin*2)
805 font->image.h = (area*5/4)/(font->image.w-margin*2)+margin*2;
806 if(font->image.h<=font->image.w)
810 font->image.h = round_to_pot(font->image.h);
812 /* Allocate arrays for storing the image and keeping track of used pixels and
813 glyphs. Since glyphs are rectangular and the image is filled starting from
814 the top, it's enough to track the number of used pixels at the top of each
816 font->image.data = (char *)alloc_image_data(font->image.w, font->image.h);
817 if(!font->image.data)
819 memset(font->image.data, 255, font->image.w*font->image.h);
820 used_pixels = (unsigned *)malloc(font->image.w*sizeof(unsigned));
821 memset(used_pixels, 0, font->image.w*sizeof(unsigned));
822 used_glyphs = (char *)malloc(font->n_glyphs);
823 memset(used_glyphs, 0, font->n_glyphs);
825 for(cy=margin; cy+margin<font->image.h;)
830 unsigned best_score = 0;
831 unsigned target_h = 0;
833 /* Find the leftmost free pixel on this row. Also record the lowest
834 extent of glyphs to the left of the free position. */
835 for(; (cx+margin<font->image.w && used_pixels[cx]>cy); ++cx)
836 if(used_pixels[cx]-cy-padding>target_h)
837 target_h = used_pixels[cx]-cy-padding;
839 if(cx+margin>=font->image.w)
846 /* Count the free pixel at this position. */
847 for(w=0; (cx+w+margin<font->image.w && used_pixels[cx+w]<=cy); ++w) ;
849 /* Find a suitable glyph to put here. */
850 for(i=0; i<font->n_glyphs; ++i)
854 g = &font->glyphs[i];
855 if(!used_glyphs[i] && g->image.w<=w)
859 /* Prefer glyphs that would reach exactly as low as the ones left
860 of here. This aims to create a straight edge at the bottom for
861 lining up further glyphs. */
862 score = g->image.h+padding;
863 if(g->image.h==target_h)
882 used_glyphs[glyph-font->glyphs] = 1;
886 for(y=0; y<glyph->image.h; ++y) for(x=0; x<glyph->image.w; ++x)
888 if(cx+x>=font->image.w || cy+y>=font->image.h)
890 font->image.data[cx+x+(cy+y)*font->image.w] = 255-glyph->image.data[x+y*glyph->image.w];
892 for(x=0; x<glyph->image.w+2*padding; ++x)
894 if(cx+x<padding || cx+x>=font->image.w+padding)
896 if(used_pixels[cx+x-padding]<cy+glyph->image.h+padding)
897 used_pixels[cx+x-padding] = cy+glyph->image.h+padding;
900 if(cy+glyph->image.h+margin>used_h)
901 used_h = cy+glyph->image.h+margin;
904 /* Trim the image to the actually used size, in case the original estimate
905 was too pessimistic. */
906 font->image.h = used_h;
908 font->image.h = round_to_pot(font->image.h);
916 int save_defs(const char *fn, const Font *font)
921 out = fopen(fn, "w");
924 fprintf(stderr, "Couldn't open %s\n",fn);
928 fprintf(out, "# Image/font info:\n");
929 fprintf(out, "# width height size ascent descent\n");
930 fprintf(out, "font %d %d %d %d %d\n", font->image.w, font->image.h, font->size, font->ascent, font->descent);
931 fprintf(out, "\n# Glyph info:\n");
932 fprintf(out, "# code x y width height offset_x offset_y advance\n");
933 for(i=0; i<font->n_glyphs; ++i)
935 const Glyph *g = &font->glyphs[i];
936 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);
938 fprintf(out, "\n# Kerning info:\n");
939 fprintf(out, "# left right distance\n");
940 for(i=0; i<font->n_kerning; ++i)
942 const Kerning *k = &font->kerning[i];
943 fprintf(out, "kern %u %u %d\n", k->left_code, k->right_code, k->distance);
951 int save_png(const char *fn, const Image *image, char alpha)
965 out = fopen(fn, "wb");
968 fprintf(stderr, "Couldn't open %s\n",fn);
973 pngs = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
976 fprintf(stderr, "Error writing PNG file\n");
979 pngi = png_create_info_struct(pngs);
982 png_destroy_write_struct(&pngs, NULL);
983 fprintf(stderr, "Error writing PNG file\n");
987 png_init_io(pngs, out);
988 rows = (png_byte **)malloc(image->h*sizeof(png_byte *));
991 data2 = (png_byte *)alloc_image_data(image->w*2, image->h);
994 for(i=0; i<image->w*image->h; ++i)
997 data2[i*2+1] = 255-image->data[i];
999 for(i=0; i<image->h; ++i)
1000 rows[i] = (png_byte *)(data2+i*image->w*2);
1001 color = PNG_COLOR_TYPE_GRAY_ALPHA;
1005 for(i=0; i<image->h; ++i)
1006 rows[i] = (png_byte *)(image->data+i*image->w);
1007 color = PNG_COLOR_TYPE_GRAY;
1009 png_set_IHDR(pngs, pngi, image->w, image->h, 8, color, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
1010 png_set_rows(pngs, pngi, rows);
1011 png_write_png(pngs, pngi, PNG_TRANSFORM_IDENTITY, NULL);
1012 png_destroy_write_struct(&pngs, &pngi);
1018 printf("Saved %dx%d PNG image to %s\n", image->w, image->h, fn);