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);
214 err = render_packed(&font, margin, padding);
216 err = render_grid(&font, cellw, cellh, cpl, seq);
222 for(i=0; (unsigned)i<font.image.w*font.image.h; ++i)
223 font.image.data[i] = 255-font.image.data[i];
225 err = save_png(out_fn, &font.image, alpha);
230 save_defs(def_fn, &font);
232 for(i=0; (unsigned)i<font.n_glyphs; ++i)
233 free(font.glyphs[i].image.data);
236 free(font.image.data);
239 FT_Done_FreeType(freetype);
246 printf("ttf2png 1.1 - True Type Font to PNG converter\n"
247 "Copyright (c) 2004-2018 Mikko Rasa, Mikkosoft Productions\n"
248 "Distributed under the GNU General Public License\n\n");
250 printf("Usage: ttf2png [options] <TTF file>\n\n");
252 printf("Accepted options (default values in [brackets])\n"
253 " -r Range of code points to convert [0,255]\n"
254 " -s Font size to use, in pixels [10]\n"
255 " -l Number of glyphs to put in one line [auto]\n"
256 " -c Glyph cell size, in pixels (grid mode only) [auto]\n"
257 " -o Output file name (or - for stdout) [font.png]\n");
258 printf(" -a Force autohinter\n"
259 " -t Render glyphs to alpha channel\n"
260 " -i Invert colors of the glyphs\n"
261 " -v Increase the level of verbosity\n"
262 " -e Use cells in sequence, without gaps (grid mode only)\n"
263 " -p Pack the glyphs tightly instead of in a grid\n"
264 " -m Margin around image edges (packed mode only) [0]\n"
265 " -n Padding between glyphs (packed mode only) [1]\n"
266 " -d File name for writing glyph definitions\n"
267 " -h Print this message\n");
270 int convert_numeric_option(char opt, int min_value)
275 value = strtol(optarg, &ptr, 0);
276 if(value<min_value || *ptr)
278 printf("Invalid option argument in -%c %s\n", opt, optarg);
285 void convert_code_point_range(char opt, unsigned *begin, unsigned *end)
290 if(!strcmp(optarg, "all"))
297 value = str_to_code_point(optarg, &ptr);
298 if(value>0 && *ptr==',')
301 value = str_to_code_point(ptr+1, &ptr);
309 printf("Invalid option argument in -%c %s\n", opt, optarg);
313 unsigned str_to_code_point(const char *nptr, char **endptr)
315 if(nptr[0]=='U' && nptr[1]=='+')
316 return strtoul(nptr+2, endptr, 16);
317 else if(nptr[0]&0x80)
324 *endptr = (char *)nptr;
326 for(bytes=1; (bytes<4 && (nptr[0]&(0x80>>bytes))); ++bytes)
327 if((nptr[bytes]&0xC0)!=0x80)
332 code = nptr[0]&(0x3F>>bytes);
333 for(i=1; i<bytes; ++i)
334 code = (code<<6)|(nptr[i]&0x3F);
337 *endptr = (char *)nptr+bytes;
341 else if(isdigit(nptr[0]))
342 return strtoul(nptr, endptr, 0);
346 *endptr = (char *)nptr+1;
351 void convert_size(char opt, unsigned *width, unsigned *height)
356 if(!strcmp(optarg, "auto"))
362 else if(!strcmp(optarg, "autorect"))
369 value = strtol(optarg, &ptr, 0);
375 value = strtol(ptr+1, &ptr, 0);
389 printf("Invalid option argument in -%c %s\n", opt, optarg);
393 unsigned round_to_pot(unsigned n)
405 void *alloc_image_data(size_t a, size_t b)
409 /* Carry out the multiplication manually so we can check for overflow. */
418 fprintf(stderr, "Cannot allocate %lu kbytes of memory for image\n", (unsigned long)(c/1024*b));
425 fprintf(stderr, "Cannot allocate %lu kbytes of memory for image\n", (unsigned long)(a/1024*b));
429 int init_font(Font *font, FT_Face face, unsigned first, unsigned last, bool autohinter)
434 font->ascent = (face->size->metrics.ascender+63)>>6;
435 font->descent = (face->size->metrics.descender+63)>>6;
439 printf("Ascent: %d\n", font->ascent);
440 printf("Descent: %d\n", font->descent);
445 for(i=first; i<=last; ++i)
448 FT_Bitmap *bmp = &face->glyph->bitmap;
453 n = FT_Get_Char_Index(face, i);
458 flags |= FT_LOAD_FORCE_AUTOHINT;
459 FT_Load_Glyph(face, n, flags);
460 FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
463 printf(" Char %u: glyph %u, size %dx%d\n", i, n, bmp->width, bmp->rows);
465 if(bmp->pixel_mode!=FT_PIXEL_MODE_GRAY)
467 fprintf(stderr, "Warning: Glyph %u skipped, not grayscale\n", n);
471 if(font->n_glyphs>=size)
474 font->glyphs = (Glyph *)realloc(font->glyphs, size*sizeof(Glyph));
477 glyph = &font->glyphs[font->n_glyphs++];
480 glyph->image.w = bmp->width;
481 glyph->image.h = bmp->rows;
482 glyph->image.data = (char *)malloc(bmp->width*bmp->rows);
483 if(!glyph->image.data)
485 fprintf(stderr, "Cannot allocate %d bytes of memory for glyph\n", bmp->width*bmp->rows);
488 glyph->offset_x = face->glyph->bitmap_left;
489 glyph->offset_y = face->glyph->bitmap_top-bmp->rows;
490 glyph->advance = (int)(face->glyph->advance.x+32)/64;
492 /* Copy the glyph image since FreeType uses a global buffer, which would
493 be overwritten by the next glyph. Negative pitch means the scanlines
494 start from the bottom. */
497 for(y=0; y<bmp->rows; ++y) for(x=0; x<bmp->width; ++x)
498 glyph->image.data[x+(glyph->image.h-1-y)*glyph->image.w] = bmp->buffer[x-y*bmp->pitch];
502 for(y=0; y<bmp->rows; ++y) for(x=0; x<bmp->width; ++x)
503 glyph->image.data[x+y*glyph->image.w] = bmp->buffer[x+y*bmp->pitch];
508 printf("Loaded %u glyphs\n", font->n_glyphs);
512 font->kerning = NULL;
513 for(i=0; i<font->n_glyphs; ++i) for(j=0; j<font->n_glyphs; ++j)
517 FT_Get_Kerning(face, font->glyphs[i].index, font->glyphs[j].index, FT_KERNING_DEFAULT, &kerning);
519 /* FreeType documentation says that vertical kerning is practically
520 never used, so we ignore it. */
525 if(font->n_kerning>=size)
528 font->kerning = (Kerning *)realloc(font->kerning, size*sizeof(Kerning));
531 kern = &font->kerning[font->n_kerning++];
532 kern->left_code = font->glyphs[i].code;
533 kern->right_code = font->glyphs[j].code;
534 kern->distance = kerning.x/64;
539 printf("Loaded %d kerning pairs\n", font->n_kerning);
544 int render_grid(Font *font, unsigned cellw, unsigned cellh, unsigned cpl, bool seq)
547 int top = 0, bot = 0;
548 unsigned first, last;
549 unsigned maxw = 0, maxh = 0;
551 /* Find extremes of the glyph images. */
552 for(i=0; i<font->n_glyphs; ++i)
556 y = font->glyphs[i].offset_y+font->glyphs[i].image.h;
559 if(font->glyphs[i].offset_y<bot)
560 bot = font->glyphs[i].offset_y;
561 if(font->glyphs[i].image.w>maxw)
562 maxw = font->glyphs[i].image.w;
563 if(font->glyphs[i].image.h>maxh)
564 maxh = font->glyphs[i].image.h;
569 /* Establish a large enough cell to hold all glyphs in the range. */
570 int square = (cellh==cellw);
584 printf("Max size: %u x %u\n", maxw, maxh);
585 printf("Y range: [%d %d]\n", bot, top);
586 printf("Cell size: %u x %u\n", cellw, cellh);
587 if(maxw>cellw || (unsigned)(top-bot)>cellh)
588 fprintf(stderr, "Warning: character size exceeds cell size\n");
593 /* Determine number of characters per line, trying to fit all the glyphs
594 in a square image. */
598 if(cpl>0 && font->n_glyphs/cpl*cellh<=cpl*cellw)
603 first = font->glyphs[0].code;
606 last = font->glyphs[font->n_glyphs-1].code;
608 font->image.w = round_to_pot(cpl*cellw);
610 font->image.h = round_to_pot((font->n_glyphs+cpl-1)/cpl*cellh);
612 font->image.h = round_to_pot((last-first+cpl)/cpl*cellh);
614 font->image.data = (char *)alloc_image_data(font->image.w, font->image.h);
615 if(!font->image.data)
617 memset(font->image.data, 255, font->image.w*font->image.h);
619 for(i=0; i<font->n_glyphs; ++i)
625 glyph = &font->glyphs[i];
630 ci = glyph->code-first;
635 if(cellw>glyph->image.w)
636 cx += (cellw-glyph->image.w)/2;
637 cy += top-glyph->offset_y-glyph->image.h;
642 for(y=0; y<glyph->image.h; ++y) for(x=0; x<glyph->image.w; ++x)
644 if(cx+x>=font->image.w || cy+y>=font->image.h)
646 font->image.data[cx+x+(cy+y)*font->image.w] = 255-glyph->image.data[x+y*glyph->image.w];
653 int render_packed(Font *font, unsigned margin, unsigned padding)
658 unsigned *used_pixels;
659 unsigned cx = margin, cy;
662 /* Compute the total area occupied by glyphs and padding. */
663 for(i=0; i<font->n_glyphs; ++i)
665 size_t a = area+(font->glyphs[i].image.w+padding)*(font->glyphs[i].image.h+padding);
668 fprintf(stderr, "Overflow in counting total glyph area\n");
674 /* Find an image size that's no higher than wide, allowing for some
675 imperfections in the packing. */
676 for(font->image.w=1;; font->image.w<<=1)
678 if(font->image.w<=margin*2)
680 font->image.h = (area*5/4)/(font->image.w-margin*2)+margin*2;
681 if(font->image.h<=font->image.w)
684 font->image.h = round_to_pot(font->image.h);
686 /* Allocate arrays for storing the image and keeping track of used pixels and
687 glyphs. Since glyphs are rectangular and the image is filled starting from
688 the top, it's enough to track the number of used pixels at the top of each
690 font->image.data = (char *)alloc_image_data(font->image.w, font->image.h);
691 if(!font->image.data)
693 memset(font->image.data, 255, font->image.w*font->image.h);
694 used_pixels = (unsigned *)malloc(font->image.w*sizeof(unsigned));
695 memset(used_pixels, 0, font->image.w*sizeof(unsigned));
696 used_glyphs = (char *)malloc(font->n_glyphs);
697 memset(used_glyphs, 0, font->n_glyphs);
699 for(cy=margin; cy+margin<font->image.h;)
704 unsigned best_score = 0;
705 unsigned target_h = 0;
707 /* Find the leftmost free pixel on this row. Also record the lowest
708 extent of glyphs to the left of the free position. */
709 for(; (cx+margin<font->image.w && used_pixels[cx]>cy); ++cx)
710 if(used_pixels[cx]-cy-padding>target_h)
711 target_h = used_pixels[cx]-cy-padding;
713 if(cx+margin>=font->image.w)
720 /* Count the free pixel at this position. */
721 for(w=0; (cx+w+margin<font->image.w && used_pixels[cx+w]<=cy); ++w) ;
723 /* Find a suitable glyph to put here. */
724 for(i=0; i<font->n_glyphs; ++i)
728 g = &font->glyphs[i];
729 if(!used_glyphs[i] && g->image.w<=w)
733 /* Prefer glyphs that would reach exactly as low as the ones left
734 of here. This aims to create a straight edge at the bottom for
735 lining up further glyphs. */
736 score = g->image.h+padding;
737 if(g->image.h==target_h)
756 used_glyphs[glyph-font->glyphs] = 1;
760 for(y=0; y<glyph->image.h; ++y) for(x=0; x<glyph->image.w; ++x)
762 if(cx+x>=font->image.w || cy+y>=font->image.h)
764 font->image.data[cx+x+(cy+y)*font->image.w] = 255-glyph->image.data[x+y*glyph->image.w];
766 for(x=0; x<glyph->image.w+2*padding; ++x)
768 if(cx+x<padding || cx+x>=font->image.w+padding)
770 if(used_pixels[cx+x-padding]<cy+glyph->image.h+padding)
771 used_pixels[cx+x-padding] = cy+glyph->image.h+padding;
774 if(cy+glyph->image.h+margin>used_h)
775 used_h = cy+glyph->image.h+margin;
778 /* Trim the image to the actually used size, in case the original estimate
779 was too pessimistic. */
780 font->image.h = round_to_pot(used_h);
788 int save_defs(const char *fn, const Font *font)
793 out = fopen(fn, "w");
796 fprintf(stderr, "Couldn't open %s\n",fn);
800 fprintf(out, "# Image/font info:\n");
801 fprintf(out, "# width height size ascent descent\n");
802 fprintf(out, "font %d %d %d %d %d\n", font->image.w, font->image.h, font->size, font->ascent, font->descent);
803 fprintf(out, "\n# Glyph info:\n");
804 fprintf(out, "# code x y width height offset_x offset_y advance\n");
805 for(i=0; i<font->n_glyphs; ++i)
807 const Glyph *g = &font->glyphs[i];
808 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);
810 fprintf(out, "\n# Kerning info:\n");
811 fprintf(out, "# left right distance\n");
812 for(i=0; i<font->n_kerning; ++i)
814 const Kerning *k = &font->kerning[i];
815 fprintf(out, "kern %u %u %d\n", k->left_code, k->right_code, k->distance);
823 int save_png(const char *fn, const Image *image, char alpha)
837 out = fopen(fn, "wb");
840 fprintf(stderr, "Couldn't open %s\n",fn);
845 pngs = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
848 fprintf(stderr, "Error writing PNG file\n");
851 pngi = png_create_info_struct(pngs);
854 png_destroy_write_struct(&pngs, NULL);
855 fprintf(stderr, "Error writing PNG file\n");
859 png_init_io(pngs, out);
860 rows = (png_byte **)malloc(image->h*sizeof(png_byte *));
863 data2 = (png_byte *)alloc_image_data(image->w*2, image->h);
866 for(i=0; i<image->w*image->h; ++i)
869 data2[i*2+1] = 255-image->data[i];
871 for(i=0; i<image->h; ++i)
872 rows[i] = (png_byte *)(data2+i*image->w*2);
873 color = PNG_COLOR_TYPE_GRAY_ALPHA;
877 for(i=0; i<image->h; ++i)
878 rows[i] = (png_byte *)(image->data+i*image->w);
879 color = PNG_COLOR_TYPE_GRAY;
881 png_set_IHDR(pngs, pngi, image->w, image->h, 8, color, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
882 png_set_rows(pngs, pngi, rows);
883 png_write_png(pngs, pngi, PNG_TRANSFORM_IDENTITY, NULL);
884 png_destroy_write_struct(&pngs, &pngi);
890 printf("Saved %dx%d PNG image to %s\n", image->w, image->h, fn);