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 render_grid(Font *, unsigned, unsigned, unsigned, bool, bool);
84 int render_packed(Font *, unsigned, unsigned, bool);
85 int save_defs(const char *, const Font *);
86 int save_png(const char *, const Image *, char);
90 int main(int argc, char **argv)
94 unsigned n_ranges = 0;
105 unsigned padding = 1;
114 char *out_fn = "font.png";
125 while((i = getopt(argc, argv, "r:s:l:c:o:atvh?ed:pim:n:f")) != -1)
130 ranges = (Range *)realloc(ranges, (++n_ranges)*sizeof(Range));
131 convert_code_point_range('r', &ranges[n_ranges-1]);
134 size = convert_numeric_option('s', 1);
137 cpl = convert_numeric_option('l', 1);
140 convert_size('c', &cellw, &cellh);
171 margin = convert_numeric_option('m', 0);
174 padding = convert_numeric_option('n', 0);
181 if(!strcmp(out_fn, "-"))
192 err = FT_Init_FreeType(&freetype);
195 fprintf(stderr, "Couldn't initialize FreeType library\n");
199 err = FT_New_Face(freetype, fn, 0, &face);
202 fprintf(stderr, "Couldn't load font file\n");
203 if(err==FT_Err_Unknown_File_Format)
204 fprintf(stderr, "Unknown file format\n");
210 const char *name = FT_Get_Postscript_Name(face);
211 printf("Font name: %s\n", name);
212 printf("Glyphs: %ld\n", face->num_glyphs);
215 err = FT_Set_Pixel_Sizes(face, 0, size);
218 fprintf(stderr, "Couldn't set size\n");
224 ranges = malloc(sizeof(Range));
226 ranges[0].last = 255;
230 sort_and_compact_ranges(ranges, &n_ranges);
233 err = init_font(&font, face, ranges, n_ranges, autohinter);
239 fprintf(stderr, "No glyphs found in the requested range\n");
244 err = render_packed(&font, margin, padding, npot);
246 err = render_grid(&font, cellw, cellh, cpl, seq, npot);
252 for(i=0; (unsigned)i<font.image.w*font.image.h; ++i)
253 font.image.data[i] = 255-font.image.data[i];
255 err = save_png(out_fn, &font.image, alpha);
260 save_defs(def_fn, &font);
262 for(i=0; (unsigned)i<font.n_glyphs; ++i)
263 free(font.glyphs[i].image.data);
266 free(font.image.data);
269 FT_Done_FreeType(freetype);
276 printf("ttf2png 1.1 - True Type Font to PNG converter\n"
277 "Copyright (c) 2004-2018 Mikko Rasa, Mikkosoft Productions\n"
278 "Distributed under the GNU General Public License\n\n");
280 printf("Usage: ttf2png [options] <TTF file>\n\n");
282 printf("Accepted options (default values in [brackets])\n"
283 " -r Range of code points to convert [0,255]\n"
284 " -s Font size to use, in pixels [10]\n"
285 " -l Number of glyphs to put in one line [auto]\n"
286 " -c Glyph cell size, in pixels (grid mode only) [auto]\n"
287 " -o Output file name (or - for stdout) [font.png]\n");
288 printf(" -a Force autohinter\n"
289 " -t Render glyphs to alpha channel\n"
290 " -i Invert colors of the glyphs\n"
291 " -v Increase the level of verbosity\n"
292 " -e Use cells in sequence, without gaps (grid mode only)\n"
293 " -p Pack the glyphs tightly instead of in a grid\n"
294 " -m Margin around image edges (packed mode only) [0]\n"
295 " -n Padding between glyphs (packed mode only) [1]\n"
296 " -f Allow non-power-of-two result\n"
297 " -d File name for writing glyph definitions\n"
298 " -h Print this message\n");
301 int convert_numeric_option(char opt, int min_value)
306 value = strtol(optarg, &ptr, 0);
307 if(value<min_value || *ptr)
309 printf("Invalid option argument in -%c %s\n", opt, optarg);
316 void convert_code_point_range(char opt, Range *range)
321 if(!strcmp(optarg, "all"))
324 range->last = 0x10FFFF;
328 value = str_to_code_point(optarg, &ptr);
329 if(value>0 && *ptr==',')
331 range->first = value;
332 value = str_to_code_point(ptr+1, &ptr);
340 printf("Invalid option argument in -%c %s\n", opt, optarg);
344 unsigned str_to_code_point(const char *nptr, char **endptr)
346 if(nptr[0]=='U' && nptr[1]=='+')
347 return strtoul(nptr+2, endptr, 16);
348 else if(nptr[0]&0x80)
355 *endptr = (char *)nptr;
357 for(bytes=1; (bytes<4 && (nptr[0]&(0x80>>bytes))); ++bytes)
358 if((nptr[bytes]&0xC0)!=0x80)
363 code = nptr[0]&(0x3F>>bytes);
364 for(i=1; i<bytes; ++i)
365 code = (code<<6)|(nptr[i]&0x3F);
368 *endptr = (char *)nptr+bytes;
372 else if(isdigit(nptr[0]))
373 return strtoul(nptr, endptr, 0);
377 *endptr = (char *)nptr+1;
382 void convert_size(char opt, unsigned *width, unsigned *height)
387 if(!strcmp(optarg, "auto"))
393 else if(!strcmp(optarg, "autorect"))
400 value = strtol(optarg, &ptr, 0);
406 value = strtol(ptr+1, &ptr, 0);
420 printf("Invalid option argument in -%c %s\n", opt, optarg);
424 void sort_and_compact_ranges(Range *ranges, unsigned *n_ranges)
431 qsort(ranges, *n_ranges, sizeof(Range), &range_cmp);
432 for(i=0, j=1; j<*n_ranges; ++j)
434 if(ranges[i].last+1>=ranges[j].first)
436 if(ranges[j].last>ranges[i].last)
437 ranges[i].last = ranges[j].last;
443 ranges[i] = ranges[j];
450 int range_cmp(const void *p1, const void *p2)
452 const Range *r1 = (const Range *)p1;
453 const Range *r2 = (const Range *)p2;
454 if(r1->first!=r2->first)
455 return (r1->first<r2->first ? -1 : 1);
456 else if(r1->last!=r2->last)
457 return (r1->last<r2->last ? -1 : 1);
462 unsigned round_to_pot(unsigned n)
474 void *alloc_image_data(size_t a, size_t b)
478 /* Carry out the multiplication manually so we can check for overflow. */
487 fprintf(stderr, "Cannot allocate %lu kbytes of memory for image\n", (unsigned long)(c/1024*b));
494 fprintf(stderr, "Cannot allocate %lu kbytes of memory for image\n", (unsigned long)(a/1024*b));
498 int init_font(Font *font, FT_Face face, const Range *ranges, unsigned n_ranges, bool autohinter)
503 font->ascent = (face->size->metrics.ascender+63)>>6;
504 font->descent = (face->size->metrics.descender+63)>>6;
508 printf("Ascent: %d\n", font->ascent);
509 printf("Descent: %d\n", font->descent);
514 for(i=0; i<n_ranges; ++i)
515 if(init_glyphs(font, face, &ranges[i], autohinter))
519 printf("Loaded %u glyphs\n", font->n_glyphs);
522 font->kerning = NULL;
523 for(i=0; i<font->n_glyphs; ++i) for(j=0; j<font->n_glyphs; ++j)
527 FT_Get_Kerning(face, font->glyphs[i].index, font->glyphs[j].index, FT_KERNING_DEFAULT, &kerning);
529 /* FreeType documentation says that vertical kerning is practically
530 never used, so we ignore it. */
535 if(font->n_kerning>=size)
538 font->kerning = (Kerning *)realloc(font->kerning, size*sizeof(Kerning));
541 kern = &font->kerning[font->n_kerning++];
542 kern->left_code = font->glyphs[i].code;
543 kern->right_code = font->glyphs[j].code;
544 kern->distance = kerning.x/64;
549 printf("Loaded %d kerning pairs\n", font->n_kerning);
554 int init_glyphs(Font *font, FT_Face face, const Range *range, bool autohinter)
557 unsigned size = font->n_glyphs;
559 for(i=range->first; i<=range->last; ++i)
562 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->image.w = bmp->width;
613 glyph->image.h = bmp->rows;
614 glyph->image.data = (char *)malloc(bmp->width*bmp->rows);
615 if(!glyph->image.data)
617 fprintf(stderr, "Cannot allocate %d bytes of memory for glyph\n", bmp->width*bmp->rows);
620 glyph->offset_x = face->glyph->bitmap_left;
621 glyph->offset_y = face->glyph->bitmap_top-bmp->rows;
622 glyph->advance = (int)(face->glyph->advance.x+32)/64;
624 /* Copy the glyph image since FreeType uses a global buffer, which would
625 be overwritten by the next glyph. Negative pitch means the scanlines
626 start from the bottom. */
629 for(y=0; y<bmp->rows; ++y) for(x=0; x<bmp->width; ++x)
630 glyph->image.data[x+(glyph->image.h-1-y)*glyph->image.w] = bmp->buffer[x-y*bmp->pitch];
634 for(y=0; y<bmp->rows; ++y) for(x=0; x<bmp->width; ++x)
635 glyph->image.data[x+y*glyph->image.w] = bmp->buffer[x+y*bmp->pitch];
642 int render_grid(Font *font, unsigned cellw, unsigned cellh, unsigned cpl, bool seq, bool npot)
645 int top = 0, bot = 0;
646 unsigned first, last;
647 unsigned maxw = 0, maxh = 0;
649 /* Find extremes of the glyph images. */
650 for(i=0; i<font->n_glyphs; ++i)
654 y = font->glyphs[i].offset_y+font->glyphs[i].image.h;
657 if(font->glyphs[i].offset_y<bot)
658 bot = font->glyphs[i].offset_y;
659 if(font->glyphs[i].image.w>maxw)
660 maxw = font->glyphs[i].image.w;
661 if(font->glyphs[i].image.h>maxh)
662 maxh = font->glyphs[i].image.h;
667 /* Establish a large enough cell to hold all glyphs in the range. */
668 int square = (cellh==cellw);
682 printf("Max size: %u x %u\n", maxw, maxh);
683 printf("Y range: [%d %d]\n", bot, top);
684 printf("Cell size: %u x %u\n", cellw, cellh);
685 if(maxw>cellw || (unsigned)(top-bot)>cellh)
686 fprintf(stderr, "Warning: character size exceeds cell size\n");
691 /* Determine number of characters per line, trying to fit all the glyphs
692 in a square image. */
696 if(cpl>0 && font->n_glyphs/cpl*cellh<=cpl*cellw)
701 first = font->glyphs[0].code;
704 last = font->glyphs[font->n_glyphs-1].code;
706 font->image.w = cpl*cellw;
708 font->image.w = round_to_pot(font->image.w);
710 font->image.h = (font->n_glyphs+cpl-1)/cpl*cellh;
712 font->image.h = (last-first+cpl)/cpl*cellh;
714 font->image.h = round_to_pot(font->image.h);
716 font->image.data = (char *)alloc_image_data(font->image.w, font->image.h);
717 if(!font->image.data)
719 memset(font->image.data, 255, font->image.w*font->image.h);
721 for(i=0; i<font->n_glyphs; ++i)
727 glyph = &font->glyphs[i];
732 ci = glyph->code-first;
737 if(cellw>glyph->image.w)
738 cx += (cellw-glyph->image.w)/2;
739 cy += top-glyph->offset_y-glyph->image.h;
744 for(y=0; y<glyph->image.h; ++y) for(x=0; x<glyph->image.w; ++x)
746 if(cx+x>=font->image.w || cy+y>=font->image.h)
748 font->image.data[cx+x+(cy+y)*font->image.w] = 255-glyph->image.data[x+y*glyph->image.w];
755 int render_packed(Font *font, unsigned margin, unsigned padding, bool npot)
760 unsigned *used_pixels;
761 unsigned cx = margin, cy;
764 /* Compute the total area occupied by glyphs and padding. */
765 for(i=0; i<font->n_glyphs; ++i)
767 size_t a = area+(font->glyphs[i].image.w+padding)*(font->glyphs[i].image.h+padding);
770 fprintf(stderr, "Overflow in counting total glyph area\n");
776 /* Find an image size that's no higher than wide, allowing for some
777 imperfections in the packing. */
778 for(font->image.w=1;; font->image.w<<=1)
780 if(font->image.w<=margin*2)
782 font->image.h = (area*5/4)/(font->image.w-margin*2)+margin*2;
783 if(font->image.h<=font->image.w)
787 font->image.h = round_to_pot(font->image.h);
789 /* Allocate arrays for storing the image and keeping track of used pixels and
790 glyphs. Since glyphs are rectangular and the image is filled starting from
791 the top, it's enough to track the number of used pixels at the top of each
793 font->image.data = (char *)alloc_image_data(font->image.w, font->image.h);
794 if(!font->image.data)
796 memset(font->image.data, 255, font->image.w*font->image.h);
797 used_pixels = (unsigned *)malloc(font->image.w*sizeof(unsigned));
798 memset(used_pixels, 0, font->image.w*sizeof(unsigned));
799 used_glyphs = (char *)malloc(font->n_glyphs);
800 memset(used_glyphs, 0, font->n_glyphs);
802 for(cy=margin; cy+margin<font->image.h;)
807 unsigned best_score = 0;
808 unsigned target_h = 0;
810 /* Find the leftmost free pixel on this row. Also record the lowest
811 extent of glyphs to the left of the free position. */
812 for(; (cx+margin<font->image.w && used_pixels[cx]>cy); ++cx)
813 if(used_pixels[cx]-cy-padding>target_h)
814 target_h = used_pixels[cx]-cy-padding;
816 if(cx+margin>=font->image.w)
823 /* Count the free pixel at this position. */
824 for(w=0; (cx+w+margin<font->image.w && used_pixels[cx+w]<=cy); ++w) ;
826 /* Find a suitable glyph to put here. */
827 for(i=0; i<font->n_glyphs; ++i)
831 g = &font->glyphs[i];
832 if(!used_glyphs[i] && g->image.w<=w)
836 /* Prefer glyphs that would reach exactly as low as the ones left
837 of here. This aims to create a straight edge at the bottom for
838 lining up further glyphs. */
839 score = g->image.h+padding;
840 if(g->image.h==target_h)
859 used_glyphs[glyph-font->glyphs] = 1;
863 for(y=0; y<glyph->image.h; ++y) for(x=0; x<glyph->image.w; ++x)
865 if(cx+x>=font->image.w || cy+y>=font->image.h)
867 font->image.data[cx+x+(cy+y)*font->image.w] = 255-glyph->image.data[x+y*glyph->image.w];
869 for(x=0; x<glyph->image.w+2*padding; ++x)
871 if(cx+x<padding || cx+x>=font->image.w+padding)
873 if(used_pixels[cx+x-padding]<cy+glyph->image.h+padding)
874 used_pixels[cx+x-padding] = cy+glyph->image.h+padding;
877 if(cy+glyph->image.h+margin>used_h)
878 used_h = cy+glyph->image.h+margin;
881 /* Trim the image to the actually used size, in case the original estimate
882 was too pessimistic. */
883 font->image.h = used_h;
885 font->image.h = round_to_pot(font->image.h);
893 int save_defs(const char *fn, const Font *font)
898 out = fopen(fn, "w");
901 fprintf(stderr, "Couldn't open %s\n",fn);
905 fprintf(out, "# Image/font info:\n");
906 fprintf(out, "# width height size ascent descent\n");
907 fprintf(out, "font %d %d %d %d %d\n", font->image.w, font->image.h, font->size, font->ascent, font->descent);
908 fprintf(out, "\n# Glyph info:\n");
909 fprintf(out, "# code x y width height offset_x offset_y advance\n");
910 for(i=0; i<font->n_glyphs; ++i)
912 const Glyph *g = &font->glyphs[i];
913 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);
915 fprintf(out, "\n# Kerning info:\n");
916 fprintf(out, "# left right distance\n");
917 for(i=0; i<font->n_kerning; ++i)
919 const Kerning *k = &font->kerning[i];
920 fprintf(out, "kern %u %u %d\n", k->left_code, k->right_code, k->distance);
928 int save_png(const char *fn, const Image *image, char alpha)
942 out = fopen(fn, "wb");
945 fprintf(stderr, "Couldn't open %s\n",fn);
950 pngs = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
953 fprintf(stderr, "Error writing PNG file\n");
956 pngi = png_create_info_struct(pngs);
959 png_destroy_write_struct(&pngs, NULL);
960 fprintf(stderr, "Error writing PNG file\n");
964 png_init_io(pngs, out);
965 rows = (png_byte **)malloc(image->h*sizeof(png_byte *));
968 data2 = (png_byte *)alloc_image_data(image->w*2, image->h);
971 for(i=0; i<image->w*image->h; ++i)
974 data2[i*2+1] = 255-image->data[i];
976 for(i=0; i<image->h; ++i)
977 rows[i] = (png_byte *)(data2+i*image->w*2);
978 color = PNG_COLOR_TYPE_GRAY_ALPHA;
982 for(i=0; i<image->h; ++i)
983 rows[i] = (png_byte *)(image->data+i*image->w);
984 color = PNG_COLOR_TYPE_GRAY;
986 png_set_IHDR(pngs, pngi, image->w, image->h, 8, color, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
987 png_set_rows(pngs, pngi, rows);
988 png_write_png(pngs, pngi, PNG_TRANSFORM_IDENTITY, NULL);
989 png_destroy_write_struct(&pngs, &pngi);
995 printf("Saved %dx%d PNG image to %s\n", image->w, image->h, fn);