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);
84 int render_packed(Font *, unsigned, unsigned);
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;
113 char *out_fn = "font.png";
124 while((i = getopt(argc, argv, "r:s:l:c:o:atvh?ed:pim:n:")) != -1)
129 ranges = (Range *)realloc(ranges, (++n_ranges)*sizeof(Range));
130 convert_code_point_range('r', &ranges[n_ranges-1]);
133 size = convert_numeric_option('s', 1);
136 cpl = convert_numeric_option('l', 1);
139 convert_size('c', &cellw, &cellh);
170 margin = convert_numeric_option('m', 0);
173 padding = convert_numeric_option('n', 0);
177 if(!strcmp(out_fn, "-"))
188 err = FT_Init_FreeType(&freetype);
191 fprintf(stderr, "Couldn't initialize FreeType library\n");
195 err = FT_New_Face(freetype, fn, 0, &face);
198 fprintf(stderr, "Couldn't load font file\n");
199 if(err==FT_Err_Unknown_File_Format)
200 fprintf(stderr, "Unknown file format\n");
206 const char *name = FT_Get_Postscript_Name(face);
207 printf("Font name: %s\n", name);
208 printf("Glyphs: %ld\n", face->num_glyphs);
211 err = FT_Set_Pixel_Sizes(face, 0, size);
214 fprintf(stderr, "Couldn't set size\n");
220 ranges = malloc(sizeof(Range));
222 ranges[0].last = 255;
226 sort_and_compact_ranges(ranges, &n_ranges);
229 err = init_font(&font, face, ranges, n_ranges, autohinter);
235 fprintf(stderr, "No glyphs found in the requested range\n");
240 err = render_packed(&font, margin, padding);
242 err = render_grid(&font, cellw, cellh, cpl, seq);
248 for(i=0; (unsigned)i<font.image.w*font.image.h; ++i)
249 font.image.data[i] = 255-font.image.data[i];
251 err = save_png(out_fn, &font.image, alpha);
256 save_defs(def_fn, &font);
258 for(i=0; (unsigned)i<font.n_glyphs; ++i)
259 free(font.glyphs[i].image.data);
262 free(font.image.data);
265 FT_Done_FreeType(freetype);
272 printf("ttf2png 1.1 - True Type Font to PNG converter\n"
273 "Copyright (c) 2004-2018 Mikko Rasa, Mikkosoft Productions\n"
274 "Distributed under the GNU General Public License\n\n");
276 printf("Usage: ttf2png [options] <TTF file>\n\n");
278 printf("Accepted options (default values in [brackets])\n"
279 " -r Range of code points to convert [0,255]\n"
280 " -s Font size to use, in pixels [10]\n"
281 " -l Number of glyphs to put in one line [auto]\n"
282 " -c Glyph cell size, in pixels (grid mode only) [auto]\n"
283 " -o Output file name (or - for stdout) [font.png]\n");
284 printf(" -a Force autohinter\n"
285 " -t Render glyphs to alpha channel\n"
286 " -i Invert colors of the glyphs\n"
287 " -v Increase the level of verbosity\n"
288 " -e Use cells in sequence, without gaps (grid mode only)\n"
289 " -p Pack the glyphs tightly instead of in a grid\n"
290 " -m Margin around image edges (packed mode only) [0]\n"
291 " -n Padding between glyphs (packed mode only) [1]\n"
292 " -d File name for writing glyph definitions\n"
293 " -h Print this message\n");
296 int convert_numeric_option(char opt, int min_value)
301 value = strtol(optarg, &ptr, 0);
302 if(value<min_value || *ptr)
304 printf("Invalid option argument in -%c %s\n", opt, optarg);
311 void convert_code_point_range(char opt, Range *range)
316 if(!strcmp(optarg, "all"))
319 range->last = 0x10FFFF;
323 value = str_to_code_point(optarg, &ptr);
324 if(value>0 && *ptr==',')
326 range->first = value;
327 value = str_to_code_point(ptr+1, &ptr);
335 printf("Invalid option argument in -%c %s\n", opt, optarg);
339 unsigned str_to_code_point(const char *nptr, char **endptr)
341 if(nptr[0]=='U' && nptr[1]=='+')
342 return strtoul(nptr+2, endptr, 16);
343 else if(nptr[0]&0x80)
350 *endptr = (char *)nptr;
352 for(bytes=1; (bytes<4 && (nptr[0]&(0x80>>bytes))); ++bytes)
353 if((nptr[bytes]&0xC0)!=0x80)
358 code = nptr[0]&(0x3F>>bytes);
359 for(i=1; i<bytes; ++i)
360 code = (code<<6)|(nptr[i]&0x3F);
363 *endptr = (char *)nptr+bytes;
367 else if(isdigit(nptr[0]))
368 return strtoul(nptr, endptr, 0);
372 *endptr = (char *)nptr+1;
377 void convert_size(char opt, unsigned *width, unsigned *height)
382 if(!strcmp(optarg, "auto"))
388 else if(!strcmp(optarg, "autorect"))
395 value = strtol(optarg, &ptr, 0);
401 value = strtol(ptr+1, &ptr, 0);
415 printf("Invalid option argument in -%c %s\n", opt, optarg);
419 void sort_and_compact_ranges(Range *ranges, unsigned *n_ranges)
426 qsort(ranges, *n_ranges, sizeof(Range), &range_cmp);
427 for(i=0, j=1; j<*n_ranges; ++j)
429 if(ranges[i].last+1>=ranges[j].first)
431 if(ranges[j].last>ranges[i].last)
432 ranges[i].last = ranges[j].last;
438 ranges[i] = ranges[j];
445 int range_cmp(const void *p1, const void *p2)
447 const Range *r1 = (const Range *)p1;
448 const Range *r2 = (const Range *)p2;
449 if(r1->first!=r2->first)
450 return (r1->first<r2->first ? -1 : 1);
451 else if(r1->last!=r2->last)
452 return (r1->last<r2->last ? -1 : 1);
457 unsigned round_to_pot(unsigned n)
469 void *alloc_image_data(size_t a, size_t b)
473 /* Carry out the multiplication manually so we can check for overflow. */
482 fprintf(stderr, "Cannot allocate %lu kbytes of memory for image\n", (unsigned long)(c/1024*b));
489 fprintf(stderr, "Cannot allocate %lu kbytes of memory for image\n", (unsigned long)(a/1024*b));
493 int init_font(Font *font, FT_Face face, const Range *ranges, unsigned n_ranges, bool autohinter)
498 font->ascent = (face->size->metrics.ascender+63)>>6;
499 font->descent = (face->size->metrics.descender+63)>>6;
503 printf("Ascent: %d\n", font->ascent);
504 printf("Descent: %d\n", font->descent);
509 for(i=0; i<n_ranges; ++i)
510 if(init_glyphs(font, face, &ranges[i], autohinter))
514 printf("Loaded %u glyphs\n", font->n_glyphs);
517 font->kerning = NULL;
518 for(i=0; i<font->n_glyphs; ++i) for(j=0; j<font->n_glyphs; ++j)
522 FT_Get_Kerning(face, font->glyphs[i].index, font->glyphs[j].index, FT_KERNING_DEFAULT, &kerning);
524 /* FreeType documentation says that vertical kerning is practically
525 never used, so we ignore it. */
530 if(font->n_kerning>=size)
533 font->kerning = (Kerning *)realloc(font->kerning, size*sizeof(Kerning));
536 kern = &font->kerning[font->n_kerning++];
537 kern->left_code = font->glyphs[i].code;
538 kern->right_code = font->glyphs[j].code;
539 kern->distance = kerning.x/64;
544 printf("Loaded %d kerning pairs\n", font->n_kerning);
549 int init_glyphs(Font *font, FT_Face face, const Range *range, bool autohinter)
552 unsigned size = font->n_glyphs;
554 for(i=range->first; i<=range->last; ++i)
557 FT_Bitmap *bmp = &face->glyph->bitmap;
562 n = FT_Get_Char_Index(face, i);
567 flags |= FT_LOAD_FORCE_AUTOHINT;
568 FT_Load_Glyph(face, n, flags);
569 FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
573 printf(" Code point U+%04X", i);
574 if(i>=0x20 && i<0x7F)
576 else if(i>=0xA0 && i<=0x10FFFF)
581 for(bytes=2; i>>(1+bytes*5); ++bytes) ;
582 for(j=0; j<bytes; ++j)
583 utf8[j] = 0x80 | ((i>>((bytes-j-1)*6))&0x3F);
584 utf8[0] |= 0xF0<<(4-bytes);
587 printf(" (%s)", utf8);
589 printf(": glyph %u, size %dx%d\n", n, bmp->width, bmp->rows);
592 if(bmp->pixel_mode!=FT_PIXEL_MODE_GRAY)
594 fprintf(stderr, "Warning: Glyph %u skipped, not grayscale\n", n);
598 if(font->n_glyphs>=size)
601 font->glyphs = (Glyph *)realloc(font->glyphs, size*sizeof(Glyph));
604 glyph = &font->glyphs[font->n_glyphs++];
607 glyph->image.w = bmp->width;
608 glyph->image.h = bmp->rows;
609 glyph->image.data = (char *)malloc(bmp->width*bmp->rows);
610 if(!glyph->image.data)
612 fprintf(stderr, "Cannot allocate %d bytes of memory for glyph\n", bmp->width*bmp->rows);
615 glyph->offset_x = face->glyph->bitmap_left;
616 glyph->offset_y = face->glyph->bitmap_top-bmp->rows;
617 glyph->advance = (int)(face->glyph->advance.x+32)/64;
619 /* Copy the glyph image since FreeType uses a global buffer, which would
620 be overwritten by the next glyph. Negative pitch means the scanlines
621 start from the bottom. */
624 for(y=0; y<bmp->rows; ++y) for(x=0; x<bmp->width; ++x)
625 glyph->image.data[x+(glyph->image.h-1-y)*glyph->image.w] = bmp->buffer[x-y*bmp->pitch];
629 for(y=0; y<bmp->rows; ++y) for(x=0; x<bmp->width; ++x)
630 glyph->image.data[x+y*glyph->image.w] = bmp->buffer[x+y*bmp->pitch];
637 int render_grid(Font *font, unsigned cellw, unsigned cellh, unsigned cpl, bool seq)
640 int top = 0, bot = 0;
641 unsigned first, last;
642 unsigned maxw = 0, maxh = 0;
644 /* Find extremes of the glyph images. */
645 for(i=0; i<font->n_glyphs; ++i)
649 y = font->glyphs[i].offset_y+font->glyphs[i].image.h;
652 if(font->glyphs[i].offset_y<bot)
653 bot = font->glyphs[i].offset_y;
654 if(font->glyphs[i].image.w>maxw)
655 maxw = font->glyphs[i].image.w;
656 if(font->glyphs[i].image.h>maxh)
657 maxh = font->glyphs[i].image.h;
662 /* Establish a large enough cell to hold all glyphs in the range. */
663 int square = (cellh==cellw);
677 printf("Max size: %u x %u\n", maxw, maxh);
678 printf("Y range: [%d %d]\n", bot, top);
679 printf("Cell size: %u x %u\n", cellw, cellh);
680 if(maxw>cellw || (unsigned)(top-bot)>cellh)
681 fprintf(stderr, "Warning: character size exceeds cell size\n");
686 /* Determine number of characters per line, trying to fit all the glyphs
687 in a square image. */
691 if(cpl>0 && font->n_glyphs/cpl*cellh<=cpl*cellw)
696 first = font->glyphs[0].code;
699 last = font->glyphs[font->n_glyphs-1].code;
701 font->image.w = round_to_pot(cpl*cellw);
703 font->image.h = round_to_pot((font->n_glyphs+cpl-1)/cpl*cellh);
705 font->image.h = round_to_pot((last-first+cpl)/cpl*cellh);
707 font->image.data = (char *)alloc_image_data(font->image.w, font->image.h);
708 if(!font->image.data)
710 memset(font->image.data, 255, font->image.w*font->image.h);
712 for(i=0; i<font->n_glyphs; ++i)
718 glyph = &font->glyphs[i];
723 ci = glyph->code-first;
728 if(cellw>glyph->image.w)
729 cx += (cellw-glyph->image.w)/2;
730 cy += top-glyph->offset_y-glyph->image.h;
735 for(y=0; y<glyph->image.h; ++y) for(x=0; x<glyph->image.w; ++x)
737 if(cx+x>=font->image.w || cy+y>=font->image.h)
739 font->image.data[cx+x+(cy+y)*font->image.w] = 255-glyph->image.data[x+y*glyph->image.w];
746 int render_packed(Font *font, unsigned margin, unsigned padding)
751 unsigned *used_pixels;
752 unsigned cx = margin, cy;
755 /* Compute the total area occupied by glyphs and padding. */
756 for(i=0; i<font->n_glyphs; ++i)
758 size_t a = area+(font->glyphs[i].image.w+padding)*(font->glyphs[i].image.h+padding);
761 fprintf(stderr, "Overflow in counting total glyph area\n");
767 /* Find an image size that's no higher than wide, allowing for some
768 imperfections in the packing. */
769 for(font->image.w=1;; font->image.w<<=1)
771 if(font->image.w<=margin*2)
773 font->image.h = (area*5/4)/(font->image.w-margin*2)+margin*2;
774 if(font->image.h<=font->image.w)
777 font->image.h = round_to_pot(font->image.h);
779 /* Allocate arrays for storing the image and keeping track of used pixels and
780 glyphs. Since glyphs are rectangular and the image is filled starting from
781 the top, it's enough to track the number of used pixels at the top of each
783 font->image.data = (char *)alloc_image_data(font->image.w, font->image.h);
784 if(!font->image.data)
786 memset(font->image.data, 255, font->image.w*font->image.h);
787 used_pixels = (unsigned *)malloc(font->image.w*sizeof(unsigned));
788 memset(used_pixels, 0, font->image.w*sizeof(unsigned));
789 used_glyphs = (char *)malloc(font->n_glyphs);
790 memset(used_glyphs, 0, font->n_glyphs);
792 for(cy=margin; cy+margin<font->image.h;)
797 unsigned best_score = 0;
798 unsigned target_h = 0;
800 /* Find the leftmost free pixel on this row. Also record the lowest
801 extent of glyphs to the left of the free position. */
802 for(; (cx+margin<font->image.w && used_pixels[cx]>cy); ++cx)
803 if(used_pixels[cx]-cy-padding>target_h)
804 target_h = used_pixels[cx]-cy-padding;
806 if(cx+margin>=font->image.w)
813 /* Count the free pixel at this position. */
814 for(w=0; (cx+w+margin<font->image.w && used_pixels[cx+w]<=cy); ++w) ;
816 /* Find a suitable glyph to put here. */
817 for(i=0; i<font->n_glyphs; ++i)
821 g = &font->glyphs[i];
822 if(!used_glyphs[i] && g->image.w<=w)
826 /* Prefer glyphs that would reach exactly as low as the ones left
827 of here. This aims to create a straight edge at the bottom for
828 lining up further glyphs. */
829 score = g->image.h+padding;
830 if(g->image.h==target_h)
849 used_glyphs[glyph-font->glyphs] = 1;
853 for(y=0; y<glyph->image.h; ++y) for(x=0; x<glyph->image.w; ++x)
855 if(cx+x>=font->image.w || cy+y>=font->image.h)
857 font->image.data[cx+x+(cy+y)*font->image.w] = 255-glyph->image.data[x+y*glyph->image.w];
859 for(x=0; x<glyph->image.w+2*padding; ++x)
861 if(cx+x<padding || cx+x>=font->image.w+padding)
863 if(used_pixels[cx+x-padding]<cy+glyph->image.h+padding)
864 used_pixels[cx+x-padding] = cy+glyph->image.h+padding;
867 if(cy+glyph->image.h+margin>used_h)
868 used_h = cy+glyph->image.h+margin;
871 /* Trim the image to the actually used size, in case the original estimate
872 was too pessimistic. */
873 font->image.h = round_to_pot(used_h);
881 int save_defs(const char *fn, const Font *font)
886 out = fopen(fn, "w");
889 fprintf(stderr, "Couldn't open %s\n",fn);
893 fprintf(out, "# Image/font info:\n");
894 fprintf(out, "# width height size ascent descent\n");
895 fprintf(out, "font %d %d %d %d %d\n", font->image.w, font->image.h, font->size, font->ascent, font->descent);
896 fprintf(out, "\n# Glyph info:\n");
897 fprintf(out, "# code x y width height offset_x offset_y advance\n");
898 for(i=0; i<font->n_glyphs; ++i)
900 const Glyph *g = &font->glyphs[i];
901 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);
903 fprintf(out, "\n# Kerning info:\n");
904 fprintf(out, "# left right distance\n");
905 for(i=0; i<font->n_kerning; ++i)
907 const Kerning *k = &font->kerning[i];
908 fprintf(out, "kern %u %u %d\n", k->left_code, k->right_code, k->distance);
916 int save_png(const char *fn, const Image *image, char alpha)
930 out = fopen(fn, "wb");
933 fprintf(stderr, "Couldn't open %s\n",fn);
938 pngs = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
941 fprintf(stderr, "Error writing PNG file\n");
944 pngi = png_create_info_struct(pngs);
947 png_destroy_write_struct(&pngs, NULL);
948 fprintf(stderr, "Error writing PNG file\n");
952 png_init_io(pngs, out);
953 rows = (png_byte **)malloc(image->h*sizeof(png_byte *));
956 data2 = (png_byte *)alloc_image_data(image->w*2, image->h);
959 for(i=0; i<image->w*image->h; ++i)
962 data2[i*2+1] = 255-image->data[i];
964 for(i=0; i<image->h; ++i)
965 rows[i] = (png_byte *)(data2+i*image->w*2);
966 color = PNG_COLOR_TYPE_GRAY_ALPHA;
970 for(i=0; i<image->h; ++i)
971 rows[i] = (png_byte *)(image->data+i*image->w);
972 color = PNG_COLOR_TYPE_GRAY;
974 png_set_IHDR(pngs, pngi, image->w, image->h, 8, color, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
975 png_set_rows(pngs, pngi, rows);
976 png_write_png(pngs, pngi, PNG_TRANSFORM_IDENTITY, NULL);
977 png_destroy_write_struct(&pngs, &pngi);
983 printf("Saved %dx%d PNG image to %s\n", image->w, image->h, fn);