]> git.tdb.fi Git - ttf2png.git/blob - ttf2png.c
Improve glyph details output with -vv
[ttf2png.git] / ttf2png.c
1 /*
2 ttf2png - True Type Font to PNG converter
3 Copyright (c) 2004-2008 Mikko Rasa
4
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.
9
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.
14
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
18 */
19
20 #include <stdio.h>
21 #include <ctype.h>
22 #include <unistd.h>
23 #include <getopt.h>
24 #include <png.h>
25 #include <ft2build.h>
26 #include FT_FREETYPE_H
27
28 typedef struct sImage
29 {
30         unsigned w, h;
31         char *data;
32 } Image;
33
34 typedef struct sGlyph
35 {
36         unsigned index;
37         unsigned code;
38         Image image;
39         unsigned x, y;
40         int offset_x;
41         int offset_y;
42         int advance;
43 } Glyph;
44
45 typedef struct sKerning
46 {
47         unsigned left_code;
48         unsigned right_code;
49         int distance;
50 } Kerning;
51
52 typedef struct sFont
53 {
54         unsigned size;
55         int ascent;
56         int descent;
57         unsigned n_glyphs;
58         Glyph *glyphs;
59         unsigned n_kerning;
60         Kerning *kerning;
61         Image image;
62 } Font;
63
64 typedef int bool;
65
66 void usage(void);
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);
78
79 char verbose = 0;
80
81 int main(int argc, char **argv)
82 {
83         char *fn;
84         unsigned begin = 0;
85         unsigned end = 255;
86         unsigned size = 10;
87         unsigned cpl = 0;
88         unsigned cellw = 0;
89         unsigned cellh = 0;
90         bool autohinter = 0;
91         bool seq = 0;
92         bool alpha = 0;
93         bool invert = 0;
94         bool pack = 0;
95         unsigned margin = 0;
96         unsigned padding = 1;
97
98         FT_Library freetype;
99         FT_Face face;
100
101         int err;
102         int i;
103
104         char *out_fn = "font.png";
105         char *def_fn = NULL;
106
107         Font font;
108
109         if(argc<2)
110         {
111                 usage();
112                 return 1;
113         }
114
115         while((i = getopt(argc, argv, "r:s:l:c:o:atvh?ed:pim:n:")) != -1)
116         {
117                 switch(i)
118                 {
119                 case 'r':
120                         convert_code_point_range('r', &begin, &end);
121                         break;
122                 case 's':
123                         size = convert_numeric_option('s', 1);
124                         break;
125                 case 'l':
126                         cpl = convert_numeric_option('l', 1);
127                         break;
128                 case 'c':
129                         convert_size('c', &cellw, &cellh);
130                         break;
131                 case 'o':
132                         out_fn = optarg;
133                         break;
134                 case 'a':
135                         autohinter = 1;
136                         break;
137                 case 't':
138                         alpha = 1;
139                         break;
140                 case 'v':
141                         ++verbose;
142                         break;
143                 case 'h':
144                 case '?':
145                         usage();
146                         return 0;
147                 case 'e':
148                         seq = 1;
149                         break;
150                 case 'd':
151                         def_fn = optarg;
152                         break;
153                 case 'p':
154                         pack = 1;
155                         break;
156                 case 'i':
157                         invert = 1;
158                         break;
159                 case 'm':
160                         margin = convert_numeric_option('m', 0);
161                         break;
162                 case 'n':
163                         padding = convert_numeric_option('n', 0);
164                         break;
165                 }
166         }
167         if(!strcmp(out_fn, "-"))
168                 verbose = 0;
169
170         if(optind!=argc-1)
171         {
172                 usage();
173                 return 1;
174         }
175
176         fn = argv[optind];
177
178         err = FT_Init_FreeType(&freetype);
179         if(err)
180         {
181                 fprintf(stderr, "Couldn't initialize FreeType library\n");
182                 return 1;
183         }
184
185         err = FT_New_Face(freetype, fn, 0, &face);
186         if(err)
187         {
188                 fprintf(stderr, "Couldn't load font file\n");
189                 if(err==FT_Err_Unknown_File_Format)
190                         fprintf(stderr, "Unknown file format\n");
191                 return 1;
192         }
193
194         if(verbose)
195         {
196                 const char *name = FT_Get_Postscript_Name(face);
197                 printf("Font name: %s\n", name);
198                 printf("Glyphs:    %ld\n", face->num_glyphs);
199         }
200
201         err = FT_Set_Pixel_Sizes(face, 0, size);
202         if(err)
203         {
204                 fprintf(stderr, "Couldn't set size\n");
205                 return 1;
206         }
207
208         font.size = size;
209         err = init_font(&font, face, begin, end, autohinter);
210         if(err)
211                 return 1;
212
213         if(!font.n_glyphs)
214         {
215                 fprintf(stderr, "No glyphs found in the requested range\n");
216                 return 1;
217         }
218
219         if(pack)
220                 err = render_packed(&font, margin, padding);
221         else
222                 err = render_grid(&font, cellw, cellh, cpl, seq);
223         if(err)
224                 return 1;
225
226         if(invert)
227         {
228                 for(i=0; (unsigned)i<font.image.w*font.image.h; ++i)
229                         font.image.data[i] = 255-font.image.data[i];
230         }
231         err = save_png(out_fn, &font.image, alpha);
232         if(err)
233                 return 1;
234
235         if(def_fn)
236                 save_defs(def_fn, &font);
237
238         for(i=0; (unsigned)i<font.n_glyphs; ++i)
239                 free(font.glyphs[i].image.data);
240         free(font.glyphs);
241         free(font.kerning);
242         free(font.image.data);
243
244         FT_Done_Face(face);
245         FT_Done_FreeType(freetype);
246
247         return 0;
248 }
249
250 void usage(void)
251 {
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");
255
256         printf("Usage: ttf2png [options] <TTF file>\n\n");
257
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");
274 }
275
276 int convert_numeric_option(char opt, int min_value)
277 {
278         int value;
279         char *ptr;
280
281         value = strtol(optarg, &ptr, 0);
282         if(value<min_value || *ptr)
283         {
284                 printf("Invalid option argument in -%c %s\n", opt, optarg);
285                 exit(1);
286         }
287
288         return value;
289 }
290
291 void convert_code_point_range(char opt, unsigned *begin, unsigned *end)
292 {
293         int value;
294         char *ptr;
295
296         if(!strcmp(optarg, "all"))
297         {
298                 *begin = 0;
299                 *end = 0x10FFFF;
300                 return;
301         }
302
303         value = str_to_code_point(optarg, &ptr);
304         if(value>0 && *ptr==',')
305         {
306                 *begin = value;
307                 value = str_to_code_point(ptr+1, &ptr);
308                 if(value>0 && !*ptr)
309                 {
310                         *end = value;
311                         return;
312                 }
313         }
314
315         printf("Invalid option argument in -%c %s\n", opt, optarg);
316         exit(1);
317 }
318
319 unsigned str_to_code_point(const char *nptr, char **endptr)
320 {
321         if(nptr[0]=='U' && nptr[1]=='+')
322                 return strtoul(nptr+2, endptr, 16);
323         else if(nptr[0]&0x80)
324         {
325                 unsigned bytes;
326                 unsigned code;
327                 unsigned i;
328
329                 if(endptr)
330                         *endptr = (char *)nptr;
331
332                 for(bytes=1; (bytes<4 && (nptr[0]&(0x80>>bytes))); ++bytes)
333                         if((nptr[bytes]&0xC0)!=0x80)
334                                 return 0;
335                 if(bytes<2)
336                         return 0;
337
338                 code = nptr[0]&(0x3F>>bytes);
339                 for(i=1; i<bytes; ++i)
340                         code = (code<<6)|(nptr[i]&0x3F);
341
342                 if(endptr)
343                         *endptr = (char *)nptr+bytes;
344
345                 return code;
346         }
347         else if(isdigit(nptr[0]))
348                 return strtoul(nptr, endptr, 0);
349         else
350         {
351                 if(endptr)
352                         *endptr = (char *)nptr+1;
353                 return *nptr;
354         }
355 }
356
357 void convert_size(char opt, unsigned *width, unsigned *height)
358 {
359         int value;
360         char *ptr;
361
362         if(!strcmp(optarg, "auto"))
363         {
364                 *width = 0;
365                 *height = 0;
366                 return;
367         }
368         else if(!strcmp(optarg, "autorect"))
369         {
370                 *width = 0;
371                 *height = 1;
372                 return;
373         }
374
375         value = strtol(optarg, &ptr, 0);
376         if(value>0)
377         {
378                 *width = value;
379                 if(*ptr=='x')
380                 {
381                         value = strtol(ptr+1, &ptr, 0);
382                         if(value>0 && !*ptr)
383                         {
384                                 *height = value;
385                                 return;
386                         }
387                 }
388                 else if(!*ptr)
389                 {
390                         *height = *width;
391                         return;
392                 }
393         }
394
395         printf("Invalid option argument in -%c %s\n", opt, optarg);
396         exit(1);
397 }
398
399 unsigned round_to_pot(unsigned n)
400 {
401         n -= 1;
402         n |= n>>1;
403         n |= n>>2;
404         n |= n>>4;
405         n |= n>>8;
406         n |= n>>16;
407
408         return n+1;
409 }
410
411 void *alloc_image_data(size_t a, size_t b)
412 {
413         void *ptr;
414
415         /* Carry out the multiplication manually so we can check for overflow. */
416         while(b>1)
417         {
418                 size_t c = a;
419                 a *= 2;
420                 if(b&1)
421                         a += c;
422                 if(a<c)
423                 {
424                         fprintf(stderr, "Cannot allocate %lu kbytes of memory for image\n", (unsigned long)(c/1024*b));
425                         return NULL;
426                 }
427                 b /= 2;
428         }
429         ptr = malloc(a);
430         if(!ptr)
431                 fprintf(stderr, "Cannot allocate %lu kbytes of memory for image\n", (unsigned long)(a/1024*b));
432         return ptr;
433 }
434
435 int init_font(Font *font, FT_Face face, unsigned first, unsigned last, bool autohinter)
436 {
437         unsigned i, j;
438         unsigned size = 0;
439
440         font->ascent = (face->size->metrics.ascender+63)>>6;
441         font->descent = (face->size->metrics.descender+63)>>6;
442
443         if(verbose>=1)
444         {
445                 printf("Ascent:    %d\n", font->ascent);
446                 printf("Descent:   %d\n", font->descent);
447         }
448
449         font->n_glyphs = 0;
450         font->glyphs = NULL;
451         for(i=first; i<=last; ++i)
452         {
453                 unsigned n;
454                 FT_Bitmap *bmp = &face->glyph->bitmap;
455                 unsigned x, y;
456                 int flags = 0;
457                 Glyph *glyph;
458
459                 n = FT_Get_Char_Index(face, i);
460                 if(!n)
461                         continue;
462
463                 if(autohinter)
464                         flags |= FT_LOAD_FORCE_AUTOHINT;
465                 FT_Load_Glyph(face, n, flags);
466                 FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
467
468                 if(verbose>=2)
469                 {
470                         printf("  Code point U+%04X", i);
471                         if(i>=0x20 && i<0x7F)
472                                 printf(" (%c)", i);
473                         else if(i>=0xA0 && i<=0x10FFFF)
474                         {
475                                 char utf8[5];
476                                 unsigned bytes;
477
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);
482                                 utf8[j] = 0;
483
484                                 printf(" (%s)", utf8);
485                         }
486                         printf(": glyph %u, size %dx%d\n", n, bmp->width, bmp->rows);
487                 }
488
489                 if(bmp->pixel_mode!=FT_PIXEL_MODE_GRAY)
490                 {
491                         fprintf(stderr, "Warning: Glyph %u skipped, not grayscale\n", n);
492                         continue;
493                 }
494
495                 if(font->n_glyphs>=size)
496                 {
497                         size += 16;
498                         font->glyphs = (Glyph *)realloc(font->glyphs, size*sizeof(Glyph));
499                 }
500
501                 glyph = &font->glyphs[font->n_glyphs++];
502                 glyph->index = n;
503                 glyph->code = i;
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)
508                 {
509                         fprintf(stderr, "Cannot allocate %d bytes of memory for glyph\n", bmp->width*bmp->rows);
510                         return -1;
511                 }
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;
515
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. */
519                 if(bmp->pitch<0)
520                 {
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];
523                 }
524                 else
525                 {
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];
528                 }
529         }
530
531         if(verbose>=1)
532                 printf("Loaded %u glyphs\n", font->n_glyphs);
533
534         size = 0;
535         font->n_kerning = 0;
536         font->kerning = NULL;
537         for(i=0; i<font->n_glyphs; ++i) for(j=0; j<font->n_glyphs; ++j)
538                 if(j!=i)
539                 {
540                         FT_Vector kerning;
541                         FT_Get_Kerning(face, font->glyphs[i].index, font->glyphs[j].index, FT_KERNING_DEFAULT, &kerning);
542
543                         /* FreeType documentation says that vertical kerning is practically
544                         never used, so we ignore it. */
545                         if(kerning.x)
546                         {
547                                 Kerning *kern;
548
549                                 if(font->n_kerning>=size)
550                                 {
551                                         size += 16;
552                                         font->kerning = (Kerning *)realloc(font->kerning, size*sizeof(Kerning));
553                                 }
554
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;
559                         }
560                 }
561
562         if(verbose>=1)
563                 printf("Loaded %d kerning pairs\n", font->n_kerning);
564
565         return 0;
566 }
567
568 int render_grid(Font *font, unsigned cellw, unsigned cellh, unsigned cpl, bool seq)
569 {
570         unsigned i;
571         int top = 0, bot = 0;
572         unsigned first, last;
573         unsigned maxw = 0, maxh = 0;
574
575         /* Find extremes of the glyph images. */
576         for(i=0; i<font->n_glyphs; ++i)
577         {
578                 int y;
579
580                 y = font->glyphs[i].offset_y+font->glyphs[i].image.h;
581                 if(y>top)
582                         top = y;
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;
589         }
590
591         if(cellw==0)
592         {
593                 /* Establish a large enough cell to hold all glyphs in the range. */
594                 int square = (cellh==cellw);
595                 cellw = maxw;
596                 cellh = top-bot;
597                 if(square)
598                 {
599                         if(cellh>cellw)
600                                 cellw = cellh;
601                         else
602                                 cellh = cellw;
603                 }
604         }
605
606         if(verbose>=1)
607         {
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");
613         }
614
615         if(cpl==0)
616         {
617                 /* Determine number of characters per line, trying to fit all the glyphs
618                 in a square image. */
619                 for(i=1;; i<<=1)
620                 {
621                         cpl = i/cellw;
622                         if(cpl>0 && font->n_glyphs/cpl*cellh<=cpl*cellw)
623                                 break;
624                 }
625         }
626
627         first = font->glyphs[0].code;
628         if(!seq)
629                 first -= first%cpl;
630         last = font->glyphs[font->n_glyphs-1].code;
631
632         font->image.w = round_to_pot(cpl*cellw);
633         if(seq)
634                 font->image.h = round_to_pot((font->n_glyphs+cpl-1)/cpl*cellh);
635         else
636                 font->image.h = round_to_pot((last-first+cpl)/cpl*cellh);
637
638         font->image.data = (char *)alloc_image_data(font->image.w, font->image.h);
639         if(!font->image.data)
640                 return -1;
641         memset(font->image.data, 255, font->image.w*font->image.h);
642
643         for(i=0; i<font->n_glyphs; ++i)
644         {
645                 Glyph *glyph;
646                 unsigned ci, cx, cy;
647                 unsigned x, y;
648
649                 glyph = &font->glyphs[i];
650
651                 if(seq)
652                         ci = i;
653                 else
654                         ci = glyph->code-first;
655
656                 cx = (ci%cpl)*cellw;
657                 cy = (ci/cpl)*cellh;
658
659                 if(cellw>glyph->image.w)
660                         cx += (cellw-glyph->image.w)/2;
661                 cy += top-glyph->offset_y-glyph->image.h;
662
663                 glyph->x = cx;
664                 glyph->y = cy;
665
666                 for(y=0; y<glyph->image.h; ++y) for(x=0; x<glyph->image.w; ++x)
667                 {
668                         if(cx+x>=font->image.w || cy+y>=font->image.h)
669                                 continue;
670                         font->image.data[cx+x+(cy+y)*font->image.w] = 255-glyph->image.data[x+y*glyph->image.w];
671                 }
672         }
673
674         return 0;
675 }
676
677 int render_packed(Font *font, unsigned margin, unsigned padding)
678 {
679         unsigned i;
680         size_t area = 0;
681         char *used_glyphs;
682         unsigned *used_pixels;
683         unsigned cx = margin, cy;
684         unsigned used_h = 0;
685
686         /* Compute the total area occupied by glyphs and padding. */
687         for(i=0; i<font->n_glyphs; ++i)
688         {
689                 size_t a = area+(font->glyphs[i].image.w+padding)*(font->glyphs[i].image.h+padding);
690                 if(a<area)
691                 {
692                         fprintf(stderr, "Overflow in counting total glyph area\n");
693                         return -1;
694                 }
695                 area = a;
696         }
697
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)
701         {
702                 if(font->image.w<=margin*2)
703                         continue;
704                 font->image.h = (area*5/4)/(font->image.w-margin*2)+margin*2;
705                 if(font->image.h<=font->image.w)
706                         break;
707         }
708         font->image.h = round_to_pot(font->image.h);
709
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
713         column. */
714         font->image.data = (char *)alloc_image_data(font->image.w, font->image.h);
715         if(!font->image.data)
716                 return -1;
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);
722
723         for(cy=margin; cy+margin<font->image.h;)
724         {
725                 unsigned w;
726                 unsigned x, y;
727                 Glyph *glyph = NULL;
728                 unsigned best_score = 0;
729                 unsigned target_h = 0;
730
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;
736
737                 if(cx+margin>=font->image.w)
738                 {
739                         cx = margin;
740                         ++cy;
741                         continue;
742                 }
743
744                 /* Count the free pixel at this position. */
745                 for(w=0; (cx+w+margin<font->image.w && used_pixels[cx+w]<=cy); ++w) ;
746
747                 /* Find a suitable glyph to put here. */
748                 for(i=0; i<font->n_glyphs; ++i)
749                 {
750                         Glyph *g;
751
752                         g = &font->glyphs[i];
753                         if(!used_glyphs[i] && g->image.w<=w)
754                         {
755                                 unsigned score;
756
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)
762                                         score *= g->image.w;
763                                 else
764                                         score += g->image.w;
765
766                                 if(score>best_score)
767                                 {
768                                         glyph = g;
769                                         best_score = score;
770                                 }
771                         }
772                 }
773
774                 if(!glyph)
775                 {
776                         cx += w;
777                         continue;
778                 }
779
780                 used_glyphs[glyph-font->glyphs] = 1;
781                 glyph->x = cx;
782                 glyph->y = cy;
783
784                 for(y=0; y<glyph->image.h; ++y) for(x=0; x<glyph->image.w; ++x)
785                 {
786                         if(cx+x>=font->image.w || cy+y>=font->image.h)
787                                 continue;
788                         font->image.data[cx+x+(cy+y)*font->image.w] = 255-glyph->image.data[x+y*glyph->image.w];
789                 }
790                 for(x=0; x<glyph->image.w+2*padding; ++x)
791                 {
792                         if(cx+x<padding || cx+x>=font->image.w+padding)
793                                 continue;
794                         if(used_pixels[cx+x-padding]<cy+glyph->image.h+padding)
795                                 used_pixels[cx+x-padding] = cy+glyph->image.h+padding;
796                 }
797
798                 if(cy+glyph->image.h+margin>used_h)
799                         used_h = cy+glyph->image.h+margin;
800         }
801
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);
805
806         free(used_glyphs);
807         free(used_pixels);
808
809         return 0;
810 }
811
812 int save_defs(const char *fn, const Font *font)
813 {
814         FILE *out;
815         unsigned i;
816
817         out = fopen(fn, "w");
818         if(!out)
819         {
820                 fprintf(stderr, "Couldn't open %s\n",fn);
821                 return -1;
822         }
823
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)
830         {
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);
833         }
834         fprintf(out, "\n# Kerning info:\n");
835         fprintf(out, "# left right distance\n");
836         for(i=0; i<font->n_kerning; ++i)
837         {
838                 const Kerning *k = &font->kerning[i];
839                 fprintf(out, "kern %u %u %d\n", k->left_code, k->right_code, k->distance);
840         }
841
842         fclose(out);
843
844         return 0;
845 }
846
847 int save_png(const char *fn, const Image *image, char alpha)
848 {
849         FILE *out;
850         png_struct *pngs;
851         png_info *pngi;
852         png_byte **rows;
853         unsigned i;
854         png_byte *data2 = 0;
855         int color;
856
857         if(!strcmp(fn, "-"))
858                 out = stdout;
859         else
860         {
861                 out = fopen(fn, "wb");
862                 if(!out)
863                 {
864                         fprintf(stderr, "Couldn't open %s\n",fn);
865                         return -1;
866                 }
867         }
868
869         pngs = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
870         if(!pngs)
871         {
872                 fprintf(stderr, "Error writing PNG file\n");
873                 return -1;
874         }
875         pngi = png_create_info_struct(pngs);
876         if(!pngi)
877         {
878                 png_destroy_write_struct(&pngs, NULL);
879                 fprintf(stderr, "Error writing PNG file\n");
880                 return -1;
881         }
882
883         png_init_io(pngs, out);
884         rows = (png_byte **)malloc(image->h*sizeof(png_byte *));
885         if(alpha)
886         {
887                 data2 = (png_byte *)alloc_image_data(image->w*2, image->h);
888                 if(!data2)
889                         return -1;
890                 for(i=0; i<image->w*image->h; ++i)
891                 {
892                         data2[i*2] = 255;
893                         data2[i*2+1] = 255-image->data[i];
894                 }
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;
898         }
899         else
900         {
901                 for(i=0; i<image->h; ++i)
902                         rows[i] = (png_byte *)(image->data+i*image->w);
903                 color = PNG_COLOR_TYPE_GRAY;
904         }
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);
909         free(rows);
910         if(alpha)
911                 free(data2);
912
913         if(verbose)
914                 printf("Saved %dx%d PNG image to %s\n", image->w, image->h, fn);
915
916         fclose(out);
917
918         return 0;
919 }