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
65 unsigned round_to_pot(unsigned);
66 void *alloc_image_data(size_t, size_t);
67 int init_font(Font *, FT_Face, unsigned, unsigned, int);
68 int render_grid(Font *, unsigned, unsigned, unsigned, int);
69 int render_packed(Font *, unsigned, unsigned);
70 int save_defs(const char *, const Font *);
71 int save_png(const char *, const Image *, char);
75 int main(int argc, char **argv)
98 char *out_fn = "font.png";
109 while((i = getopt(argc, argv, "r:s:l:c:o:atvh?ed:pim:n:")) != -1)
116 if(!strcmp(optarg, "all"))
123 if(!isdigit(optarg[0]))
127 temp = strtol(optarg, &ptr, 0);
128 if(ptr[0]!=',' || !isdigit(ptr[1]))
133 printf("Not a valid range: %s\n", optarg);
139 end = strtol(ptr+1, NULL, 0);
144 size = strtol(optarg, NULL, 0);
147 cpl = strtol(optarg, NULL, 0);
150 if(!strcmp(optarg, "auto"))
155 else if(!strcmp(optarg, "autorect"))
162 cellw = strtol(optarg, &ptr, 0);
163 if(ptr[0]=='x' && isdigit(ptr[1]))
164 cellh = strtol(ptr+1, NULL, 0);
198 margin = strtol(optarg, NULL, 0);
201 padding = strtol(optarg, NULL, 0);
205 if(!strcmp(out_fn, "-"))
216 err = FT_Init_FreeType(&freetype);
219 fprintf(stderr, "Couldn't initialize FreeType library\n");
223 err = FT_New_Face(freetype, fn, 0, &face);
226 fprintf(stderr, "Couldn't load font file\n");
227 if(err==FT_Err_Unknown_File_Format)
228 fprintf(stderr, "Unknown file format\n");
234 const char *name = FT_Get_Postscript_Name(face);
235 printf("Font name: %s\n", name);
236 printf("Glyphs: %ld\n", face->num_glyphs);
239 err = FT_Set_Pixel_Sizes(face, 0, size);
242 fprintf(stderr, "Couldn't set size\n");
247 err = init_font(&font, face, begin, end, autohinter);
252 err = render_packed(&font, margin, padding);
254 err = render_grid(&font, cellw, cellh, cpl, seq);
260 for(i=0; (unsigned)i<font.image.w*font.image.h; ++i)
261 font.image.data[i] = 255-font.image.data[i];
263 err = save_png(out_fn, &font.image, alpha);
268 save_defs(def_fn, &font);
270 for(i=0; (unsigned)i<font.n_glyphs; ++i)
271 free(font.glyphs[i].image.data);
274 free(font.image.data);
277 FT_Done_FreeType(freetype);
284 printf("ttf2png 1.0 - True Type Font to PNG converter\n"
285 "Copyright (c) 2004-2008 Mikko Rasa, Mikkosoft Productions\n"
286 "Distributed under the GNU General Public License\n\n");
288 printf("Usage: ttf2png [options] <TTF file>\n\n");
290 printf("Accepted options (default values in [brackets])\n"
291 " -r Range of characters to convert [0,255]\n"
292 " -s Font size to use, in pixels [10]\n"
293 " -l Number of characters to put in one line [auto]\n"
294 " -c Character cell size, in pixels [auto]\n"
295 " -o Output file name (or - for stdout) [font.png]\n");
296 printf(" -a Force autohinter\n"
297 " -t Render glyphs to alpha channel\n"
298 " -i Invert colors of the glyphs\n"
299 " -v Increase the level of verbosity\n"
300 " -e Use cells in sequence, without gaps\n"
301 " -p Pack the glyphs tightly instead of in a grid\n"
302 " -m Margin around image edges in packed mode [0]\n"
303 " -n Padding between packed glyphs [1]\n"
304 " -d File name for writing glyph definitions\n"
305 " -h Print this message\n");
308 unsigned round_to_pot(unsigned n)
320 void *alloc_image_data(size_t a, size_t b)
324 /* Carry out the multiplication manually so we can check for overflow. */
333 fprintf(stderr, "Cannot allocate %lu kbytes of memory for image\n", (unsigned long)(c/1024*b));
340 fprintf(stderr, "Cannot allocate %lu kbytes of memory for image\n", (unsigned long)(a/1024*b));
344 int init_font(Font *font, FT_Face face, unsigned first, unsigned last, int autohinter)
349 font->ascent = (face->size->metrics.ascender+63)>>6;
350 font->descent = (face->size->metrics.descender+63)>>6;
354 printf("Ascent: %d\n", font->ascent);
355 printf("Descent: %d\n", font->descent);
360 for(i=first; i<=last; ++i)
363 FT_Bitmap *bmp = &face->glyph->bitmap;
368 n = FT_Get_Char_Index(face, i);
373 flags |= FT_LOAD_FORCE_AUTOHINT;
374 FT_Load_Glyph(face, n, flags);
375 FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
378 printf(" Char %u: glyph %u, size %dx%d\n", i, n, bmp->width, bmp->rows);
380 if(bmp->pixel_mode!=FT_PIXEL_MODE_GRAY)
382 fprintf(stderr, "Warning: Glyph %u skipped, not grayscale\n", n);
386 if(font->n_glyphs>=size)
389 font->glyphs = (Glyph *)realloc(font->glyphs, size*sizeof(Glyph));
392 glyph = &font->glyphs[font->n_glyphs++];
395 glyph->image.w = bmp->width;
396 glyph->image.h = bmp->rows;
397 glyph->image.data = (char *)malloc(bmp->width*bmp->rows);
398 if(!glyph->image.data)
400 fprintf(stderr, "Cannot allocate %d bytes of memory for glyph\n", bmp->width*bmp->rows);
403 glyph->offset_x = face->glyph->bitmap_left;
404 glyph->offset_y = face->glyph->bitmap_top-bmp->rows;
405 glyph->advance = (int)(face->glyph->advance.x+32)/64;
407 /* Copy the glyph image since FreeType uses a global buffer, which would
408 be overwritten by the next glyph. Negative pitch means the scanlines
409 start from the bottom. */
412 for(y=0; y<bmp->rows; ++y) for(x=0; x<bmp->width; ++x)
413 glyph->image.data[x+(glyph->image.h-1-y)*glyph->image.w] = bmp->buffer[x-y*bmp->pitch];
417 for(y=0; y<bmp->rows; ++y) for(x=0; x<bmp->width; ++x)
418 glyph->image.data[x+y*glyph->image.w] = bmp->buffer[x+y*bmp->pitch];
423 printf("Loaded %u glyphs\n", font->n_glyphs);
427 font->kerning = NULL;
428 for(i=0; i<font->n_glyphs; ++i) for(j=0; j<font->n_glyphs; ++j)
432 FT_Get_Kerning(face, font->glyphs[i].index, font->glyphs[j].index, FT_KERNING_DEFAULT, &kerning);
434 /* FreeType documentation says that vertical kerning is practically
435 never used, so we ignore it. */
440 if(font->n_kerning>=size)
443 font->kerning = (Kerning *)realloc(font->kerning, size*sizeof(Kerning));
446 kern = &font->kerning[font->n_kerning++];
447 kern->left_code = font->glyphs[i].code;
448 kern->right_code = font->glyphs[j].code;
449 kern->distance = kerning.x/64;
454 printf("Loaded %d kerning pairs\n", font->n_kerning);
459 int render_grid(Font *font, unsigned cellw, unsigned cellh, unsigned cpl, int seq)
462 int top = 0, bot = 0;
463 unsigned first, last;
464 unsigned maxw = 0, maxh = 0;
466 /* Find extremes of the glyph images. */
467 for(i=0; i<font->n_glyphs; ++i)
471 y = font->glyphs[i].offset_y+font->glyphs[i].image.h;
474 if(font->glyphs[i].offset_y<bot)
475 bot = font->glyphs[i].offset_y;
476 if(font->glyphs[i].image.w>maxw)
477 maxw = font->glyphs[i].image.w;
478 if(font->glyphs[i].image.h>maxh)
479 maxh = font->glyphs[i].image.h;
484 /* Establish a large enough cell to hold all glyphs in the range. */
485 int square = (cellh==cellw);
499 printf("Max size: %u x %u\n", maxw, maxh);
500 printf("Y range: [%d %d]\n", bot, top);
501 printf("Cell size: %u x %u\n", cellw, cellh);
502 if(maxw>cellw || (unsigned)(top-bot)>cellh)
503 fprintf(stderr, "Warning: character size exceeds cell size\n");
508 /* Determine number of characters per line, trying to fit all the glyphs
509 in a square image. */
513 if(cpl>0 && font->n_glyphs/cpl*cellh<=cpl*cellw)
518 first = font->glyphs[0].code;
521 last = font->glyphs[font->n_glyphs-1].code;
523 font->image.w = round_to_pot(cpl*cellw);
525 font->image.h = round_to_pot((font->n_glyphs+cpl-1)/cpl*cellh);
527 font->image.h = round_to_pot((last-first+cpl)/cpl*cellh);
529 font->image.data = (char *)alloc_image_data(font->image.w, font->image.h);
530 if(!font->image.data)
532 memset(font->image.data, 255, font->image.w*font->image.h);
534 for(i=0; i<font->n_glyphs; ++i)
540 glyph = &font->glyphs[i];
545 ci = glyph->code-first;
550 if(cellw>glyph->image.w)
551 cx += (cellw-glyph->image.w)/2;
552 cy += top-glyph->offset_y-glyph->image.h;
557 for(y=0; y<glyph->image.h; ++y) for(x=0; x<glyph->image.w; ++x)
559 if(cx+x>=font->image.w || cy+y>=font->image.h)
561 font->image.data[cx+x+(cy+y)*font->image.w] = 255-glyph->image.data[x+y*glyph->image.w];
568 int render_packed(Font *font, unsigned margin, unsigned padding)
573 unsigned *used_pixels;
574 unsigned cx = margin, cy;
577 /* Compute the total area occupied by glyphs and padding. */
578 for(i=0; i<font->n_glyphs; ++i)
580 size_t a = area+(font->glyphs[i].image.w+padding)*(font->glyphs[i].image.h+padding);
583 fprintf(stderr, "Overflow in counting total glyph area\n");
589 /* Find an image size that's no higher than wide, allowing for some
590 imperfections in the packing. */
591 for(font->image.w=1;; font->image.w<<=1)
593 if(font->image.w<=margin*2)
595 font->image.h = (area*5/4)/(font->image.w-margin*2)+margin*2;
596 if(font->image.h<=font->image.w)
599 font->image.h = round_to_pot(font->image.h);
601 /* Allocate arrays for storing the image and keeping track of used pixels and
602 glyphs. Since glyphs are rectangular and the image is filled starting from
603 the top, it's enough to track the number of used pixels at the top of each
605 font->image.data = (char *)alloc_image_data(font->image.w, font->image.h);
606 if(!font->image.data)
608 memset(font->image.data, 255, font->image.w*font->image.h);
609 used_pixels = (unsigned *)malloc(font->image.w*sizeof(unsigned));
610 memset(used_pixels, 0, font->image.w*sizeof(unsigned));
611 used_glyphs = (char *)malloc(font->n_glyphs);
612 memset(used_glyphs, 0, font->n_glyphs);
614 for(cy=margin; cy+margin<font->image.h;)
619 unsigned best_score = 0;
620 unsigned target_h = 0;
622 /* Find the leftmost free pixel on this row. Also record the lowest extent of glyphs
623 to the left of the free position. */
624 for(; (cx+margin<font->image.w && used_pixels[cx]>cy); ++cx)
625 if(used_pixels[cx]-cy-padding>target_h)
626 target_h = used_pixels[cx]-cy-padding;
628 if(cx+margin>=font->image.w)
635 /* Count the free pixel at this position. */
636 for(w=0; (cx+w+margin<font->image.w && used_pixels[cx+w]<=cy); ++w) ;
638 /* Find a suitable glyph to put here. */
639 for(i=0; i<font->n_glyphs; ++i)
643 g = &font->glyphs[i];
644 if(!used_glyphs[i] && g->image.w<=w)
648 /* Prefer glyphs that would reach exactly as low as the ones left
649 of here. This aims to create a straight edge at the bottom for
650 lining up further glyphs. */
651 score = g->image.h+padding;
652 if(g->image.h==target_h)
671 used_glyphs[glyph-font->glyphs] = 1;
675 for(y=0; y<glyph->image.h; ++y) for(x=0; x<glyph->image.w; ++x)
677 if(cx+x>=font->image.w || cy+y>=font->image.h)
679 font->image.data[cx+x+(cy+y)*font->image.w] = 255-glyph->image.data[x+y*glyph->image.w];
681 for(x=0; x<glyph->image.w+2*padding; ++x)
683 if(cx+x<padding || cx+x>=font->image.w+padding)
685 if(used_pixels[cx+x-padding]<cy+glyph->image.h+padding)
686 used_pixels[cx+x-padding] = cy+glyph->image.h+padding;
689 if(cy+glyph->image.h+margin>used_h)
690 used_h = cy+glyph->image.h+margin;
693 /* Trim the image to the actually used size, in case the original estimate
694 was too pessimistic. */
695 font->image.h = round_to_pot(used_h);
703 int save_defs(const char *fn, const Font *font)
708 out = fopen(fn, "w");
711 fprintf(stderr, "Couldn't open %s\n",fn);
715 fprintf(out, "# Image/font info:\n");
716 fprintf(out, "# width height size ascent descent\n");
717 fprintf(out, "font %d %d %d %d %d\n", font->image.w, font->image.h, font->size, font->ascent, font->descent);
718 fprintf(out, "\n# Glyph info:\n");
719 fprintf(out, "# code x y width height offset_x offset_y advance\n");
720 for(i=0; i<font->n_glyphs; ++i)
722 const Glyph *g = &font->glyphs[i];
723 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);
725 fprintf(out, "\n# Kerning info:\n");
726 fprintf(out, "# left right distance\n");
727 for(i=0; i<font->n_kerning; ++i)
729 const Kerning *k = &font->kerning[i];
730 fprintf(out, "kern %u %u %d\n", k->left_code, k->right_code, k->distance);
738 int save_png(const char *fn, const Image *image, char alpha)
752 out = fopen(fn, "wb");
755 fprintf(stderr, "Couldn't open %s\n",fn);
760 pngs = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
763 fprintf(stderr, "Error writing PNG file\n");
766 pngi = png_create_info_struct(pngs);
769 png_destroy_write_struct(&pngs, NULL);
770 fprintf(stderr, "Error writing PNG file\n");
774 png_init_io(pngs, out);
775 rows = (png_byte **)malloc(image->h*sizeof(png_byte *));
778 data2 = (png_byte *)alloc_image_data(image->w*2, image->h);
781 for(i=0; i<image->w*image->h; ++i)
784 data2[i*2+1] = 255-image->data[i];
786 for(i=0; i<image->h; ++i)
787 rows[i] = (png_byte *)(data2+i*image->w*2);
788 color = PNG_COLOR_TYPE_GRAY_ALPHA;
792 for(i=0; i<image->h; ++i)
793 rows[i] = (png_byte *)(image->data+i*image->w);
794 color = PNG_COLOR_TYPE_GRAY;
796 png_set_IHDR(pngs, pngi, image->w, image->h, 8, color, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
797 png_set_rows(pngs, pngi, rows);
798 png_write_png(pngs, pngi, PNG_TRANSFORM_IDENTITY, NULL);
799 png_destroy_write_struct(&pngs, &pngi);
805 printf("Saved %dx%d PNG image to %s\n", image->w, image->h, fn);