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
67 int convert_numeric_option(char, int);
68 void convert_code_point_range(char, unsigned *, unsigned *);
69 unsigned str_to_code_point(const char *, char **);
70 void convert_size(char, unsigned *, unsigned *);
71 unsigned round_to_pot(unsigned);
72 void *alloc_image_data(size_t, size_t);
73 int init_font(Font *, FT_Face, unsigned, unsigned, bool);
74 int render_grid(Font *, unsigned, unsigned, unsigned, bool);
75 int render_packed(Font *, unsigned, unsigned);
76 int save_defs(const char *, const Font *);
77 int save_png(const char *, const Image *, char);
81 int main(int argc, char **argv)
104 char *out_fn = "font.png";
115 while((i = getopt(argc, argv, "r:s:l:c:o:atvh?ed:pim:n:")) != -1)
120 convert_code_point_range('r', &begin, &end);
123 size = convert_numeric_option('s', 1);
126 cpl = convert_numeric_option('l', 1);
129 convert_size('c', &cellw, &cellh);
160 margin = convert_numeric_option('m', 0);
163 padding = convert_numeric_option('n', 0);
167 if(!strcmp(out_fn, "-"))
178 err = FT_Init_FreeType(&freetype);
181 fprintf(stderr, "Couldn't initialize FreeType library\n");
185 err = FT_New_Face(freetype, fn, 0, &face);
188 fprintf(stderr, "Couldn't load font file\n");
189 if(err==FT_Err_Unknown_File_Format)
190 fprintf(stderr, "Unknown file format\n");
196 const char *name = FT_Get_Postscript_Name(face);
197 printf("Font name: %s\n", name);
198 printf("Glyphs: %ld\n", face->num_glyphs);
201 err = FT_Set_Pixel_Sizes(face, 0, size);
204 fprintf(stderr, "Couldn't set size\n");
209 err = init_font(&font, face, begin, end, autohinter);
215 fprintf(stderr, "No glyphs found in the requested range\n");
220 err = render_packed(&font, margin, padding);
222 err = render_grid(&font, cellw, cellh, cpl, seq);
228 for(i=0; (unsigned)i<font.image.w*font.image.h; ++i)
229 font.image.data[i] = 255-font.image.data[i];
231 err = save_png(out_fn, &font.image, alpha);
236 save_defs(def_fn, &font);
238 for(i=0; (unsigned)i<font.n_glyphs; ++i)
239 free(font.glyphs[i].image.data);
242 free(font.image.data);
245 FT_Done_FreeType(freetype);
252 printf("ttf2png 1.1 - True Type Font to PNG converter\n"
253 "Copyright (c) 2004-2018 Mikko Rasa, Mikkosoft Productions\n"
254 "Distributed under the GNU General Public License\n\n");
256 printf("Usage: ttf2png [options] <TTF file>\n\n");
258 printf("Accepted options (default values in [brackets])\n"
259 " -r Range of code points to convert [0,255]\n"
260 " -s Font size to use, in pixels [10]\n"
261 " -l Number of glyphs to put in one line [auto]\n"
262 " -c Glyph cell size, in pixels (grid mode only) [auto]\n"
263 " -o Output file name (or - for stdout) [font.png]\n");
264 printf(" -a Force autohinter\n"
265 " -t Render glyphs to alpha channel\n"
266 " -i Invert colors of the glyphs\n"
267 " -v Increase the level of verbosity\n"
268 " -e Use cells in sequence, without gaps (grid mode only)\n"
269 " -p Pack the glyphs tightly instead of in a grid\n"
270 " -m Margin around image edges (packed mode only) [0]\n"
271 " -n Padding between glyphs (packed mode only) [1]\n"
272 " -d File name for writing glyph definitions\n"
273 " -h Print this message\n");
276 int convert_numeric_option(char opt, int min_value)
281 value = strtol(optarg, &ptr, 0);
282 if(value<min_value || *ptr)
284 printf("Invalid option argument in -%c %s\n", opt, optarg);
291 void convert_code_point_range(char opt, unsigned *begin, unsigned *end)
296 if(!strcmp(optarg, "all"))
303 value = str_to_code_point(optarg, &ptr);
304 if(value>0 && *ptr==',')
307 value = str_to_code_point(ptr+1, &ptr);
315 printf("Invalid option argument in -%c %s\n", opt, optarg);
319 unsigned str_to_code_point(const char *nptr, char **endptr)
321 if(nptr[0]=='U' && nptr[1]=='+')
322 return strtoul(nptr+2, endptr, 16);
323 else if(nptr[0]&0x80)
330 *endptr = (char *)nptr;
332 for(bytes=1; (bytes<4 && (nptr[0]&(0x80>>bytes))); ++bytes)
333 if((nptr[bytes]&0xC0)!=0x80)
338 code = nptr[0]&(0x3F>>bytes);
339 for(i=1; i<bytes; ++i)
340 code = (code<<6)|(nptr[i]&0x3F);
343 *endptr = (char *)nptr+bytes;
347 else if(isdigit(nptr[0]))
348 return strtoul(nptr, endptr, 0);
352 *endptr = (char *)nptr+1;
357 void convert_size(char opt, unsigned *width, unsigned *height)
362 if(!strcmp(optarg, "auto"))
368 else if(!strcmp(optarg, "autorect"))
375 value = strtol(optarg, &ptr, 0);
381 value = strtol(ptr+1, &ptr, 0);
395 printf("Invalid option argument in -%c %s\n", opt, optarg);
399 unsigned round_to_pot(unsigned n)
411 void *alloc_image_data(size_t a, size_t b)
415 /* Carry out the multiplication manually so we can check for overflow. */
424 fprintf(stderr, "Cannot allocate %lu kbytes of memory for image\n", (unsigned long)(c/1024*b));
431 fprintf(stderr, "Cannot allocate %lu kbytes of memory for image\n", (unsigned long)(a/1024*b));
435 int init_font(Font *font, FT_Face face, unsigned first, unsigned last, bool autohinter)
440 font->ascent = (face->size->metrics.ascender+63)>>6;
441 font->descent = (face->size->metrics.descender+63)>>6;
445 printf("Ascent: %d\n", font->ascent);
446 printf("Descent: %d\n", font->descent);
451 for(i=first; i<=last; ++i)
454 FT_Bitmap *bmp = &face->glyph->bitmap;
459 n = FT_Get_Char_Index(face, i);
464 flags |= FT_LOAD_FORCE_AUTOHINT;
465 FT_Load_Glyph(face, n, flags);
466 FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
470 printf(" Code point U+%04X", i);
471 if(i>=0x20 && i<0x7F)
473 else if(i>=0xA0 && i<=0x10FFFF)
478 for(bytes=2; i>>(1+bytes*5); ++bytes) ;
479 for(j=0; j<bytes; ++j)
480 utf8[j] = 0x80 | ((i>>((bytes-j-1)*6))&0x3F);
481 utf8[0] |= 0xF0<<(4-bytes);
484 printf(" (%s)", utf8);
486 printf(": glyph %u, size %dx%d\n", n, bmp->width, bmp->rows);
489 if(bmp->pixel_mode!=FT_PIXEL_MODE_GRAY)
491 fprintf(stderr, "Warning: Glyph %u skipped, not grayscale\n", n);
495 if(font->n_glyphs>=size)
498 font->glyphs = (Glyph *)realloc(font->glyphs, size*sizeof(Glyph));
501 glyph = &font->glyphs[font->n_glyphs++];
504 glyph->image.w = bmp->width;
505 glyph->image.h = bmp->rows;
506 glyph->image.data = (char *)malloc(bmp->width*bmp->rows);
507 if(!glyph->image.data)
509 fprintf(stderr, "Cannot allocate %d bytes of memory for glyph\n", bmp->width*bmp->rows);
512 glyph->offset_x = face->glyph->bitmap_left;
513 glyph->offset_y = face->glyph->bitmap_top-bmp->rows;
514 glyph->advance = (int)(face->glyph->advance.x+32)/64;
516 /* Copy the glyph image since FreeType uses a global buffer, which would
517 be overwritten by the next glyph. Negative pitch means the scanlines
518 start from the bottom. */
521 for(y=0; y<bmp->rows; ++y) for(x=0; x<bmp->width; ++x)
522 glyph->image.data[x+(glyph->image.h-1-y)*glyph->image.w] = bmp->buffer[x-y*bmp->pitch];
526 for(y=0; y<bmp->rows; ++y) for(x=0; x<bmp->width; ++x)
527 glyph->image.data[x+y*glyph->image.w] = bmp->buffer[x+y*bmp->pitch];
532 printf("Loaded %u glyphs\n", font->n_glyphs);
536 font->kerning = NULL;
537 for(i=0; i<font->n_glyphs; ++i) for(j=0; j<font->n_glyphs; ++j)
541 FT_Get_Kerning(face, font->glyphs[i].index, font->glyphs[j].index, FT_KERNING_DEFAULT, &kerning);
543 /* FreeType documentation says that vertical kerning is practically
544 never used, so we ignore it. */
549 if(font->n_kerning>=size)
552 font->kerning = (Kerning *)realloc(font->kerning, size*sizeof(Kerning));
555 kern = &font->kerning[font->n_kerning++];
556 kern->left_code = font->glyphs[i].code;
557 kern->right_code = font->glyphs[j].code;
558 kern->distance = kerning.x/64;
563 printf("Loaded %d kerning pairs\n", font->n_kerning);
568 int render_grid(Font *font, unsigned cellw, unsigned cellh, unsigned cpl, bool seq)
571 int top = 0, bot = 0;
572 unsigned first, last;
573 unsigned maxw = 0, maxh = 0;
575 /* Find extremes of the glyph images. */
576 for(i=0; i<font->n_glyphs; ++i)
580 y = font->glyphs[i].offset_y+font->glyphs[i].image.h;
583 if(font->glyphs[i].offset_y<bot)
584 bot = font->glyphs[i].offset_y;
585 if(font->glyphs[i].image.w>maxw)
586 maxw = font->glyphs[i].image.w;
587 if(font->glyphs[i].image.h>maxh)
588 maxh = font->glyphs[i].image.h;
593 /* Establish a large enough cell to hold all glyphs in the range. */
594 int square = (cellh==cellw);
608 printf("Max size: %u x %u\n", maxw, maxh);
609 printf("Y range: [%d %d]\n", bot, top);
610 printf("Cell size: %u x %u\n", cellw, cellh);
611 if(maxw>cellw || (unsigned)(top-bot)>cellh)
612 fprintf(stderr, "Warning: character size exceeds cell size\n");
617 /* Determine number of characters per line, trying to fit all the glyphs
618 in a square image. */
622 if(cpl>0 && font->n_glyphs/cpl*cellh<=cpl*cellw)
627 first = font->glyphs[0].code;
630 last = font->glyphs[font->n_glyphs-1].code;
632 font->image.w = round_to_pot(cpl*cellw);
634 font->image.h = round_to_pot((font->n_glyphs+cpl-1)/cpl*cellh);
636 font->image.h = round_to_pot((last-first+cpl)/cpl*cellh);
638 font->image.data = (char *)alloc_image_data(font->image.w, font->image.h);
639 if(!font->image.data)
641 memset(font->image.data, 255, font->image.w*font->image.h);
643 for(i=0; i<font->n_glyphs; ++i)
649 glyph = &font->glyphs[i];
654 ci = glyph->code-first;
659 if(cellw>glyph->image.w)
660 cx += (cellw-glyph->image.w)/2;
661 cy += top-glyph->offset_y-glyph->image.h;
666 for(y=0; y<glyph->image.h; ++y) for(x=0; x<glyph->image.w; ++x)
668 if(cx+x>=font->image.w || cy+y>=font->image.h)
670 font->image.data[cx+x+(cy+y)*font->image.w] = 255-glyph->image.data[x+y*glyph->image.w];
677 int render_packed(Font *font, unsigned margin, unsigned padding)
682 unsigned *used_pixels;
683 unsigned cx = margin, cy;
686 /* Compute the total area occupied by glyphs and padding. */
687 for(i=0; i<font->n_glyphs; ++i)
689 size_t a = area+(font->glyphs[i].image.w+padding)*(font->glyphs[i].image.h+padding);
692 fprintf(stderr, "Overflow in counting total glyph area\n");
698 /* Find an image size that's no higher than wide, allowing for some
699 imperfections in the packing. */
700 for(font->image.w=1;; font->image.w<<=1)
702 if(font->image.w<=margin*2)
704 font->image.h = (area*5/4)/(font->image.w-margin*2)+margin*2;
705 if(font->image.h<=font->image.w)
708 font->image.h = round_to_pot(font->image.h);
710 /* Allocate arrays for storing the image and keeping track of used pixels and
711 glyphs. Since glyphs are rectangular and the image is filled starting from
712 the top, it's enough to track the number of used pixels at the top of each
714 font->image.data = (char *)alloc_image_data(font->image.w, font->image.h);
715 if(!font->image.data)
717 memset(font->image.data, 255, font->image.w*font->image.h);
718 used_pixels = (unsigned *)malloc(font->image.w*sizeof(unsigned));
719 memset(used_pixels, 0, font->image.w*sizeof(unsigned));
720 used_glyphs = (char *)malloc(font->n_glyphs);
721 memset(used_glyphs, 0, font->n_glyphs);
723 for(cy=margin; cy+margin<font->image.h;)
728 unsigned best_score = 0;
729 unsigned target_h = 0;
731 /* Find the leftmost free pixel on this row. Also record the lowest
732 extent of glyphs to the left of the free position. */
733 for(; (cx+margin<font->image.w && used_pixels[cx]>cy); ++cx)
734 if(used_pixels[cx]-cy-padding>target_h)
735 target_h = used_pixels[cx]-cy-padding;
737 if(cx+margin>=font->image.w)
744 /* Count the free pixel at this position. */
745 for(w=0; (cx+w+margin<font->image.w && used_pixels[cx+w]<=cy); ++w) ;
747 /* Find a suitable glyph to put here. */
748 for(i=0; i<font->n_glyphs; ++i)
752 g = &font->glyphs[i];
753 if(!used_glyphs[i] && g->image.w<=w)
757 /* Prefer glyphs that would reach exactly as low as the ones left
758 of here. This aims to create a straight edge at the bottom for
759 lining up further glyphs. */
760 score = g->image.h+padding;
761 if(g->image.h==target_h)
780 used_glyphs[glyph-font->glyphs] = 1;
784 for(y=0; y<glyph->image.h; ++y) for(x=0; x<glyph->image.w; ++x)
786 if(cx+x>=font->image.w || cy+y>=font->image.h)
788 font->image.data[cx+x+(cy+y)*font->image.w] = 255-glyph->image.data[x+y*glyph->image.w];
790 for(x=0; x<glyph->image.w+2*padding; ++x)
792 if(cx+x<padding || cx+x>=font->image.w+padding)
794 if(used_pixels[cx+x-padding]<cy+glyph->image.h+padding)
795 used_pixels[cx+x-padding] = cy+glyph->image.h+padding;
798 if(cy+glyph->image.h+margin>used_h)
799 used_h = cy+glyph->image.h+margin;
802 /* Trim the image to the actually used size, in case the original estimate
803 was too pessimistic. */
804 font->image.h = round_to_pot(used_h);
812 int save_defs(const char *fn, const Font *font)
817 out = fopen(fn, "w");
820 fprintf(stderr, "Couldn't open %s\n",fn);
824 fprintf(out, "# Image/font info:\n");
825 fprintf(out, "# width height size ascent descent\n");
826 fprintf(out, "font %d %d %d %d %d\n", font->image.w, font->image.h, font->size, font->ascent, font->descent);
827 fprintf(out, "\n# Glyph info:\n");
828 fprintf(out, "# code x y width height offset_x offset_y advance\n");
829 for(i=0; i<font->n_glyphs; ++i)
831 const Glyph *g = &font->glyphs[i];
832 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);
834 fprintf(out, "\n# Kerning info:\n");
835 fprintf(out, "# left right distance\n");
836 for(i=0; i<font->n_kerning; ++i)
838 const Kerning *k = &font->kerning[i];
839 fprintf(out, "kern %u %u %d\n", k->left_code, k->right_code, k->distance);
847 int save_png(const char *fn, const Image *image, char alpha)
861 out = fopen(fn, "wb");
864 fprintf(stderr, "Couldn't open %s\n",fn);
869 pngs = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
872 fprintf(stderr, "Error writing PNG file\n");
875 pngi = png_create_info_struct(pngs);
878 png_destroy_write_struct(&pngs, NULL);
879 fprintf(stderr, "Error writing PNG file\n");
883 png_init_io(pngs, out);
884 rows = (png_byte **)malloc(image->h*sizeof(png_byte *));
887 data2 = (png_byte *)alloc_image_data(image->w*2, image->h);
890 for(i=0; i<image->w*image->h; ++i)
893 data2[i*2+1] = 255-image->data[i];
895 for(i=0; i<image->h; ++i)
896 rows[i] = (png_byte *)(data2+i*image->w*2);
897 color = PNG_COLOR_TYPE_GRAY_ALPHA;
901 for(i=0; i<image->h; ++i)
902 rows[i] = (png_byte *)(image->data+i*image->w);
903 color = PNG_COLOR_TYPE_GRAY;
905 png_set_IHDR(pngs, pngi, image->w, image->h, 8, color, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
906 png_set_rows(pngs, pngi, rows);
907 png_write_png(pngs, pngi, PNG_TRANSFORM_IDENTITY, NULL);
908 png_destroy_write_struct(&pngs, &pngi);
914 printf("Saved %dx%d PNG image to %s\n", image->w, image->h, fn);