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);
271 FT_Done_FreeType(freetype);
278 printf("ttf2png 1.1 - True Type Font to PNG converter\n"
279 "Copyright (c) 2004-2018 Mikko Rasa, Mikkosoft Productions\n"
280 "Distributed under the GNU General Public License\n\n");
282 printf("Usage: ttf2png [options] <TTF file>\n\n");
284 printf("Accepted options (default values in [brackets])\n"
285 " -r Range of code points to convert [0,255]\n"
286 " -s Font size to use, in pixels [10]\n"
287 " -l Number of glyphs to put in one line [auto]\n"
288 " -c Glyph cell size, in pixels (grid mode only) [auto]\n"
289 " -o Output file name (or - for stdout) [font.png]\n");
290 printf(" -a Force autohinter\n"
291 " -t Render glyphs to alpha channel\n"
292 " -i Invert colors of the glyphs\n"
293 " -v Increase the level of verbosity\n"
294 " -e Use cells in sequence, without gaps (grid mode only)\n"
295 " -p Pack the glyphs tightly instead of in a grid\n"
296 " -m Margin around image edges (packed mode only) [0]\n"
297 " -n Padding between glyphs (packed mode only) [1]\n"
298 " -f Allow non-power-of-two result\n"
299 " -d File name for writing glyph definitions\n"
300 " -h Print this message\n");
303 int convert_numeric_option(char opt, int min_value)
308 value = strtol(optarg, &ptr, 0);
309 if(value<min_value || *ptr)
311 printf("Invalid option argument in -%c %s\n", opt, optarg);
318 void convert_code_point_range(char opt, Range *range)
323 if(!strcmp(optarg, "all"))
326 range->last = 0x10FFFF;
330 value = str_to_code_point(optarg, &ptr);
331 if(value>0 && *ptr==',')
333 range->first = value;
334 value = str_to_code_point(ptr+1, &ptr);
342 printf("Invalid option argument in -%c %s\n", opt, optarg);
346 unsigned str_to_code_point(const char *nptr, char **endptr)
348 if(nptr[0]=='U' && nptr[1]=='+')
349 return strtoul(nptr+2, endptr, 16);
350 else if(nptr[0]&0x80)
357 *endptr = (char *)nptr;
359 for(bytes=1; (bytes<4 && (nptr[0]&(0x80>>bytes))); ++bytes)
360 if((nptr[bytes]&0xC0)!=0x80)
365 code = nptr[0]&(0x3F>>bytes);
366 for(i=1; i<bytes; ++i)
367 code = (code<<6)|(nptr[i]&0x3F);
370 *endptr = (char *)nptr+bytes;
374 else if(isdigit(nptr[0]))
375 return strtoul(nptr, endptr, 0);
379 *endptr = (char *)nptr+1;
384 void convert_size(char opt, unsigned *width, unsigned *height)
389 if(!strcmp(optarg, "auto"))
395 else if(!strcmp(optarg, "autorect"))
402 value = strtol(optarg, &ptr, 0);
408 value = strtol(ptr+1, &ptr, 0);
422 printf("Invalid option argument in -%c %s\n", opt, optarg);
426 void sort_and_compact_ranges(Range *ranges, unsigned *n_ranges)
433 qsort(ranges, *n_ranges, sizeof(Range), &range_cmp);
434 for(i=0, j=1; j<*n_ranges; ++j)
436 if(ranges[i].last+1>=ranges[j].first)
438 if(ranges[j].last>ranges[i].last)
439 ranges[i].last = ranges[j].last;
445 ranges[i] = ranges[j];
452 int range_cmp(const void *p1, const void *p2)
454 const Range *r1 = (const Range *)p1;
455 const Range *r2 = (const Range *)p2;
456 if(r1->first!=r2->first)
457 return (r1->first<r2->first ? -1 : 1);
458 else if(r1->last!=r2->last)
459 return (r1->last<r2->last ? -1 : 1);
464 unsigned round_to_pot(unsigned n)
476 void *alloc_image_data(size_t a, size_t b)
480 /* Carry out the multiplication manually so we can check for overflow. */
489 fprintf(stderr, "Cannot allocate %lu kbytes of memory for image\n", (unsigned long)(c/1024*b));
496 fprintf(stderr, "Cannot allocate %lu kbytes of memory for image\n", (unsigned long)(a/1024*b));
500 int init_font(Font *font, FT_Face face, const Range *ranges, unsigned n_ranges, bool autohinter)
505 font->ascent = (face->size->metrics.ascender+63)/64;
506 font->descent = (face->size->metrics.descender-63)/64;
510 printf("Ascent: %d\n", font->ascent);
511 printf("Descent: %d\n", font->descent);
516 for(i=0; i<n_ranges; ++i)
517 if(init_glyphs(font, face, &ranges[i], autohinter))
521 printf("Loaded %u glyphs\n", font->n_glyphs);
524 font->kerning = NULL;
525 for(i=0; i<font->n_glyphs; ++i) for(j=0; j<font->n_glyphs; ++j)
529 FT_Get_Kerning(face, font->glyphs[i].index, font->glyphs[j].index, FT_KERNING_DEFAULT, &kerning);
531 /* FreeType documentation says that vertical kerning is practically
532 never used, so we ignore it. */
537 if(font->n_kerning>=size)
540 font->kerning = (Kerning *)realloc(font->kerning, size*sizeof(Kerning));
543 kern = &font->kerning[font->n_kerning++];
544 kern->left_code = font->glyphs[i].code;
545 kern->right_code = font->glyphs[j].code;
546 kern->distance = (kerning.x+32)/64;
551 printf("Loaded %d kerning pairs\n", font->n_kerning);
556 int init_glyphs(Font *font, FT_Face face, const Range *range, bool autohinter)
559 unsigned size = font->n_glyphs;
561 for(i=range->first; i<=range->last; ++i)
564 FT_Bitmap *bmp = &face->glyph->bitmap;
568 n = FT_Get_Char_Index(face, i);
573 flags |= FT_LOAD_FORCE_AUTOHINT;
574 FT_Load_Glyph(face, n, flags);
575 FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
579 printf(" Code point U+%04X", i);
580 if(i>=0x20 && i<0x7F)
582 else if(i>=0xA0 && i<=0x10FFFF)
587 for(bytes=2; i>>(1+bytes*5); ++bytes) ;
588 for(j=0; j<bytes; ++j)
589 utf8[j] = 0x80 | ((i>>((bytes-j-1)*6))&0x3F);
590 utf8[0] |= 0xF0<<(4-bytes);
593 printf(" (%s)", utf8);
595 printf(": glyph %u, size %dx%d\n", n, bmp->width, bmp->rows);
598 if(bmp->pixel_mode!=FT_PIXEL_MODE_GRAY && bmp->pixel_mode!=FT_PIXEL_MODE_MONO)
600 fprintf(stderr, "Warning: Glyph %u skipped, incompatible pixel mode\n", n);
604 if(font->n_glyphs>=size)
607 font->glyphs = (Glyph *)realloc(font->glyphs, size*sizeof(Glyph));
610 glyph = &font->glyphs[font->n_glyphs++];
613 glyph->offset_x = face->glyph->bitmap_left;
614 glyph->offset_y = face->glyph->bitmap_top-bmp->rows;
615 glyph->advance = (int)(face->glyph->advance.x+32)/64;
617 /* Copy the glyph image since FreeType uses a global buffer, which would
618 be overwritten by the next glyph. Negative pitch means the scanlines
619 start from the bottom. */
620 if(copy_bitmap(bmp, &glyph->image))
627 int copy_bitmap(const FT_Bitmap *bmp, Image *image)
633 image->w = bmp->width;
634 image->h = bmp->rows;
635 if(!image->w || !image->h)
641 image->data = (unsigned char *)malloc(image->w*image->h);
644 fprintf(stderr, "Cannot allocate %d bytes of memory for glyph\n", image->w*image->h);
649 src = bmp->buffer+(bmp->rows-1)*-bmp->pitch;
654 for(y=0; y<bmp->rows; ++y)
656 if(bmp->pixel_mode==FT_PIXEL_MODE_MONO)
658 for(x=0; x<bmp->width; ++x)
659 dst[x] = ((src[x/8]&(0x80>>(x%8))) ? 0xFF : 0x00);
663 for(x=0; x<bmp->width; ++x)
674 int render_grid(Font *font, unsigned cellw, unsigned cellh, unsigned cpl, bool seq, bool npot)
677 int top = 0, bot = 0;
678 unsigned first, last;
679 unsigned maxw = 0, maxh = 0;
681 /* Find extremes of the glyph images. */
682 for(i=0; i<font->n_glyphs; ++i)
686 y = font->glyphs[i].offset_y+font->glyphs[i].image.h;
689 if(font->glyphs[i].offset_y<bot)
690 bot = font->glyphs[i].offset_y;
691 if(font->glyphs[i].image.w>maxw)
692 maxw = font->glyphs[i].image.w;
693 if(font->glyphs[i].image.h>maxh)
694 maxh = font->glyphs[i].image.h;
699 /* Establish a large enough cell to hold all glyphs in the range. */
700 int square = (cellh==cellw);
714 printf("Max size: %u x %u\n", maxw, maxh);
715 printf("Y range: [%d %d]\n", bot, top);
716 printf("Cell size: %u x %u\n", cellw, cellh);
717 if(maxw>cellw || (unsigned)(top-bot)>cellh)
718 fprintf(stderr, "Warning: character size exceeds cell size\n");
723 /* Determine number of characters per line, trying to fit all the glyphs
724 in a square image. */
728 if(cpl>0 && font->n_glyphs/cpl*cellh<=cpl*cellw)
733 first = font->glyphs[0].code;
736 last = font->glyphs[font->n_glyphs-1].code;
738 font->image.w = cpl*cellw;
740 font->image.w = round_to_pot(font->image.w);
742 font->image.h = (font->n_glyphs+cpl-1)/cpl*cellh;
744 font->image.h = (last-first+cpl)/cpl*cellh;
746 font->image.h = round_to_pot(font->image.h);
748 font->image.data = (unsigned char *)alloc_image_data(font->image.w, font->image.h);
749 if(!font->image.data)
751 memset(font->image.data, 255, font->image.w*font->image.h);
753 for(i=0; i<font->n_glyphs; ++i)
759 glyph = &font->glyphs[i];
764 ci = glyph->code-first;
769 if(cellw>glyph->image.w)
770 cx += (cellw-glyph->image.w)/2;
771 cy += top-glyph->offset_y-glyph->image.h;
776 for(y=0; y<glyph->image.h; ++y) for(x=0; x<glyph->image.w; ++x)
778 if(cx+x>=font->image.w || cy+y>=font->image.h)
780 font->image.data[cx+x+(cy+y)*font->image.w] = 255-glyph->image.data[x+y*glyph->image.w];
787 int render_packed(Font *font, unsigned margin, unsigned padding, bool npot)
792 unsigned *used_pixels;
793 unsigned cx = margin, cy;
796 /* Compute the total area occupied by glyphs and padding. */
797 for(i=0; i<font->n_glyphs; ++i)
799 size_t a = area+(font->glyphs[i].image.w+padding)*(font->glyphs[i].image.h+padding);
802 fprintf(stderr, "Overflow in counting total glyph area\n");
808 /* Find an image size that's no higher than wide, allowing for some
809 imperfections in the packing. */
810 for(font->image.w=1;; font->image.w<<=1)
812 if(font->image.w<=margin*2)
814 font->image.h = (area*5/4)/(font->image.w-margin*2)+margin*2;
815 if(font->image.h<=font->image.w)
819 font->image.h = round_to_pot(font->image.h);
821 /* Allocate arrays for storing the image and keeping track of used pixels and
822 glyphs. Since glyphs are rectangular and the image is filled starting from
823 the top, it's enough to track the number of used pixels at the top of each
825 font->image.data = (unsigned char *)alloc_image_data(font->image.w, font->image.h);
826 if(!font->image.data)
828 memset(font->image.data, 255, font->image.w*font->image.h);
829 used_pixels = (unsigned *)malloc(font->image.w*sizeof(unsigned));
830 memset(used_pixels, 0, font->image.w*sizeof(unsigned));
831 used_glyphs = (char *)malloc(font->n_glyphs);
832 memset(used_glyphs, 0, font->n_glyphs);
834 for(cy=margin; cy+margin<font->image.h;)
839 unsigned best_score = 0;
840 unsigned target_h = 0;
842 /* Find the leftmost free pixel on this row. Also record the lowest
843 extent of glyphs to the left of the free position. */
844 for(; (cx+margin<font->image.w && used_pixels[cx]>cy); ++cx)
845 if(used_pixels[cx]-cy-padding>target_h)
846 target_h = used_pixels[cx]-cy-padding;
848 if(cx+margin>=font->image.w)
855 /* Count the free pixel at this position. */
856 for(w=0; (cx+w+margin<font->image.w && used_pixels[cx+w]<=cy); ++w) ;
858 /* Find a suitable glyph to put here. */
859 for(i=0; i<font->n_glyphs; ++i)
863 g = &font->glyphs[i];
864 if(!used_glyphs[i] && g->image.w<=w)
868 /* Prefer glyphs that would reach exactly as low as the ones left
869 of here. This aims to create a straight edge at the bottom for
870 lining up further glyphs. */
871 score = g->image.h+padding;
872 if(g->image.h==target_h)
891 used_glyphs[glyph-font->glyphs] = 1;
895 for(y=0; y<glyph->image.h; ++y) for(x=0; x<glyph->image.w; ++x)
897 if(cx+x>=font->image.w || cy+y>=font->image.h)
899 font->image.data[cx+x+(cy+y)*font->image.w] = 255-glyph->image.data[x+y*glyph->image.w];
901 for(x=0; x<glyph->image.w+2*padding; ++x)
903 if(cx+x<padding || cx+x>=font->image.w+padding)
905 if(used_pixels[cx+x-padding]<cy+glyph->image.h+padding)
906 used_pixels[cx+x-padding] = cy+glyph->image.h+padding;
909 if(cy+glyph->image.h+margin>used_h)
910 used_h = cy+glyph->image.h+margin;
913 /* Trim the image to the actually used size, in case the original estimate
914 was too pessimistic. */
915 font->image.h = used_h;
917 font->image.h = round_to_pot(font->image.h);
925 int save_defs(const char *fn, const Font *font)
930 out = fopen(fn, "w");
933 fprintf(stderr, "Couldn't open %s\n",fn);
937 fprintf(out, "# Image/font info:\n");
938 fprintf(out, "# width height size ascent descent\n");
939 fprintf(out, "font %d %d %d %d %d\n", font->image.w, font->image.h, font->size, font->ascent, font->descent);
940 fprintf(out, "\n# Glyph info:\n");
941 fprintf(out, "# code x y width height offset_x offset_y advance\n");
942 for(i=0; i<font->n_glyphs; ++i)
944 const Glyph *g = &font->glyphs[i];
945 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);
947 fprintf(out, "\n# Kerning info:\n");
948 fprintf(out, "# left right distance\n");
949 for(i=0; i<font->n_kerning; ++i)
951 const Kerning *k = &font->kerning[i];
952 fprintf(out, "kern %u %u %d\n", k->left_code, k->right_code, k->distance);
960 int save_png(const char *fn, const Image *image, char alpha)
974 out = fopen(fn, "wb");
977 fprintf(stderr, "Couldn't open %s\n",fn);
982 pngs = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
985 fprintf(stderr, "Error writing PNG file\n");
988 pngi = png_create_info_struct(pngs);
991 png_destroy_write_struct(&pngs, NULL);
992 fprintf(stderr, "Error writing PNG file\n");
996 png_init_io(pngs, out);
997 rows = (png_byte **)malloc(image->h*sizeof(png_byte *));
1000 data2 = (png_byte *)alloc_image_data(image->w*2, image->h);
1003 for(i=0; i<image->w*image->h; ++i)
1006 data2[i*2+1] = 255-image->data[i];
1008 for(i=0; i<image->h; ++i)
1009 rows[i] = (png_byte *)(data2+i*image->w*2);
1010 color = PNG_COLOR_TYPE_GRAY_ALPHA;
1014 for(i=0; i<image->h; ++i)
1015 rows[i] = (png_byte *)(image->data+i*image->w);
1016 color = PNG_COLOR_TYPE_GRAY;
1018 png_set_IHDR(pngs, pngi, image->w, image->h, 8, color, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
1019 png_set_rows(pngs, pngi, rows);
1020 png_write_png(pngs, pngi, PNG_TRANSFORM_IDENTITY, NULL);
1021 png_destroy_write_struct(&pngs, &pngi);
1027 printf("Saved %dx%d PNG image to %s\n", image->w, image->h, fn);