]> git.tdb.fi Git - ttf2png.git/blob - ttf2png.c
Support more ways of specifying code point ranges
[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(pack)
214                 err = render_packed(&font, margin, padding);
215         else
216                 err = render_grid(&font, cellw, cellh, cpl, seq);
217         if(err)
218                 return 1;
219
220         if(invert)
221         {
222                 for(i=0; (unsigned)i<font.image.w*font.image.h; ++i)
223                         font.image.data[i] = 255-font.image.data[i];
224         }
225         err = save_png(out_fn, &font.image, alpha);
226         if(err)
227                 return 1;
228
229         if(def_fn)
230                 save_defs(def_fn, &font);
231
232         for(i=0; (unsigned)i<font.n_glyphs; ++i)
233                 free(font.glyphs[i].image.data);
234         free(font.glyphs);
235         free(font.kerning);
236         free(font.image.data);
237
238         FT_Done_Face(face);
239         FT_Done_FreeType(freetype);
240
241         return 0;
242 }
243
244 void usage(void)
245 {
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");
249
250         printf("Usage: ttf2png [options] <TTF file>\n\n");
251
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");
268 }
269
270 int convert_numeric_option(char opt, int min_value)
271 {
272         int value;
273         char *ptr;
274
275         value = strtol(optarg, &ptr, 0);
276         if(value<min_value || *ptr)
277         {
278                 printf("Invalid option argument in -%c %s\n", opt, optarg);
279                 exit(1);
280         }
281
282         return value;
283 }
284
285 void convert_code_point_range(char opt, unsigned *begin, unsigned *end)
286 {
287         int value;
288         char *ptr;
289
290         if(!strcmp(optarg, "all"))
291         {
292                 *begin = 0;
293                 *end = 0x10FFFF;
294                 return;
295         }
296
297         value = str_to_code_point(optarg, &ptr);
298         if(value>0 && *ptr==',')
299         {
300                 *begin = value;
301                 value = str_to_code_point(ptr+1, &ptr);
302                 if(value>0 && !*ptr)
303                 {
304                         *end = value;
305                         return;
306                 }
307         }
308
309         printf("Invalid option argument in -%c %s\n", opt, optarg);
310         exit(1);
311 }
312
313 unsigned str_to_code_point(const char *nptr, char **endptr)
314 {
315         if(nptr[0]=='U' && nptr[1]=='+')
316                 return strtoul(nptr+2, endptr, 16);
317         else if(nptr[0]&0x80)
318         {
319                 unsigned bytes;
320                 unsigned code;
321                 unsigned i;
322
323                 if(endptr)
324                         *endptr = (char *)nptr;
325
326                 for(bytes=1; (bytes<4 && (nptr[0]&(0x80>>bytes))); ++bytes)
327                         if((nptr[bytes]&0xC0)!=0x80)
328                                 return 0;
329                 if(bytes<2)
330                         return 0;
331
332                 code = nptr[0]&(0x3F>>bytes);
333                 for(i=1; i<bytes; ++i)
334                         code = (code<<6)|(nptr[i]&0x3F);
335
336                 if(endptr)
337                         *endptr = (char *)nptr+bytes;
338
339                 return code;
340         }
341         else if(isdigit(nptr[0]))
342                 return strtoul(nptr, endptr, 0);
343         else
344         {
345                 if(endptr)
346                         *endptr = (char *)nptr+1;
347                 return *nptr;
348         }
349 }
350
351 void convert_size(char opt, unsigned *width, unsigned *height)
352 {
353         int value;
354         char *ptr;
355
356         if(!strcmp(optarg, "auto"))
357         {
358                 *width = 0;
359                 *height = 0;
360                 return;
361         }
362         else if(!strcmp(optarg, "autorect"))
363         {
364                 *width = 0;
365                 *height = 1;
366                 return;
367         }
368
369         value = strtol(optarg, &ptr, 0);
370         if(value>0)
371         {
372                 *width = value;
373                 if(*ptr=='x')
374                 {
375                         value = strtol(ptr+1, &ptr, 0);
376                         if(value>0 && !*ptr)
377                         {
378                                 *height = value;
379                                 return;
380                         }
381                 }
382                 else if(!*ptr)
383                 {
384                         *height = *width;
385                         return;
386                 }
387         }
388
389         printf("Invalid option argument in -%c %s\n", opt, optarg);
390         exit(1);
391 }
392
393 unsigned round_to_pot(unsigned n)
394 {
395         n -= 1;
396         n |= n>>1;
397         n |= n>>2;
398         n |= n>>4;
399         n |= n>>8;
400         n |= n>>16;
401
402         return n+1;
403 }
404
405 void *alloc_image_data(size_t a, size_t b)
406 {
407         void *ptr;
408
409         /* Carry out the multiplication manually so we can check for overflow. */
410         while(b>1)
411         {
412                 size_t c = a;
413                 a *= 2;
414                 if(b&1)
415                         a += c;
416                 if(a<c)
417                 {
418                         fprintf(stderr, "Cannot allocate %lu kbytes of memory for image\n", (unsigned long)(c/1024*b));
419                         return NULL;
420                 }
421                 b /= 2;
422         }
423         ptr = malloc(a);
424         if(!ptr)
425                 fprintf(stderr, "Cannot allocate %lu kbytes of memory for image\n", (unsigned long)(a/1024*b));
426         return ptr;
427 }
428
429 int init_font(Font *font, FT_Face face, unsigned first, unsigned last, bool autohinter)
430 {
431         unsigned i, j;
432         unsigned size = 0;
433
434         font->ascent = (face->size->metrics.ascender+63)>>6;
435         font->descent = (face->size->metrics.descender+63)>>6;
436
437         if(verbose>=1)
438         {
439                 printf("Ascent:    %d\n", font->ascent);
440                 printf("Descent:   %d\n", font->descent);
441         }
442
443         font->n_glyphs = 0;
444         font->glyphs = NULL;
445         for(i=first; i<=last; ++i)
446         {
447                 unsigned n;
448                 FT_Bitmap *bmp = &face->glyph->bitmap;
449                 unsigned x, y;
450                 int flags = 0;
451                 Glyph *glyph;
452
453                 n = FT_Get_Char_Index(face, i);
454                 if(!n)
455                         continue;
456
457                 if(autohinter)
458                         flags |= FT_LOAD_FORCE_AUTOHINT;
459                 FT_Load_Glyph(face, n, flags);
460                 FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
461
462                 if(verbose>=2)
463                         printf("  Char %u: glyph %u, size %dx%d\n", i, n, bmp->width, bmp->rows);
464
465                 if(bmp->pixel_mode!=FT_PIXEL_MODE_GRAY)
466                 {
467                         fprintf(stderr, "Warning: Glyph %u skipped, not grayscale\n", n);
468                         continue;
469                 }
470
471                 if(font->n_glyphs>=size)
472                 {
473                         size += 16;
474                         font->glyphs = (Glyph *)realloc(font->glyphs, size*sizeof(Glyph));
475                 }
476
477                 glyph = &font->glyphs[font->n_glyphs++];
478                 glyph->index = n;
479                 glyph->code = i;
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)
484                 {
485                         fprintf(stderr, "Cannot allocate %d bytes of memory for glyph\n", bmp->width*bmp->rows);
486                         return -1;
487                 }
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;
491
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. */
495                 if(bmp->pitch<0)
496                 {
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];
499                 }
500                 else
501                 {
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];
504                 }
505         }
506
507         if(verbose>=1)
508                 printf("Loaded %u glyphs\n", font->n_glyphs);
509
510         size = 0;
511         font->n_kerning = 0;
512         font->kerning = NULL;
513         for(i=0; i<font->n_glyphs; ++i) for(j=0; j<font->n_glyphs; ++j)
514                 if(j!=i)
515                 {
516                         FT_Vector kerning;
517                         FT_Get_Kerning(face, font->glyphs[i].index, font->glyphs[j].index, FT_KERNING_DEFAULT, &kerning);
518
519                         /* FreeType documentation says that vertical kerning is practically
520                         never used, so we ignore it. */
521                         if(kerning.x)
522                         {
523                                 Kerning *kern;
524
525                                 if(font->n_kerning>=size)
526                                 {
527                                         size += 16;
528                                         font->kerning = (Kerning *)realloc(font->kerning, size*sizeof(Kerning));
529                                 }
530
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;
535                         }
536                 }
537
538         if(verbose>=1)
539                 printf("Loaded %d kerning pairs\n", font->n_kerning);
540
541         return 0;
542 }
543
544 int render_grid(Font *font, unsigned cellw, unsigned cellh, unsigned cpl, bool seq)
545 {
546         unsigned i;
547         int top = 0, bot = 0;
548         unsigned first, last;
549         unsigned maxw = 0, maxh = 0;
550
551         /* Find extremes of the glyph images. */
552         for(i=0; i<font->n_glyphs; ++i)
553         {
554                 int y;
555
556                 y = font->glyphs[i].offset_y+font->glyphs[i].image.h;
557                 if(y>top)
558                         top = y;
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;
565         }
566
567         if(cellw==0)
568         {
569                 /* Establish a large enough cell to hold all glyphs in the range. */
570                 int square = (cellh==cellw);
571                 cellw = maxw;
572                 cellh = top-bot;
573                 if(square)
574                 {
575                         if(cellh>cellw)
576                                 cellw = cellh;
577                         else
578                                 cellh = cellw;
579                 }
580         }
581
582         if(verbose>=1)
583         {
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");
589         }
590
591         if(cpl==0)
592         {
593                 /* Determine number of characters per line, trying to fit all the glyphs
594                 in a square image. */
595                 for(i=1;; i<<=1)
596                 {
597                         cpl = i/cellw;
598                         if(cpl>0 && font->n_glyphs/cpl*cellh<=cpl*cellw)
599                                 break;
600                 }
601         }
602
603         first = font->glyphs[0].code;
604         if(!seq)
605                 first -= first%cpl;
606         last = font->glyphs[font->n_glyphs-1].code;
607
608         font->image.w = round_to_pot(cpl*cellw);
609         if(seq)
610                 font->image.h = round_to_pot((font->n_glyphs+cpl-1)/cpl*cellh);
611         else
612                 font->image.h = round_to_pot((last-first+cpl)/cpl*cellh);
613
614         font->image.data = (char *)alloc_image_data(font->image.w, font->image.h);
615         if(!font->image.data)
616                 return -1;
617         memset(font->image.data, 255, font->image.w*font->image.h);
618
619         for(i=0; i<font->n_glyphs; ++i)
620         {
621                 Glyph *glyph;
622                 unsigned ci, cx, cy;
623                 unsigned x, y;
624
625                 glyph = &font->glyphs[i];
626
627                 if(seq)
628                         ci = i;
629                 else
630                         ci = glyph->code-first;
631
632                 cx = (ci%cpl)*cellw;
633                 cy = (ci/cpl)*cellh;
634
635                 if(cellw>glyph->image.w)
636                         cx += (cellw-glyph->image.w)/2;
637                 cy += top-glyph->offset_y-glyph->image.h;
638
639                 glyph->x = cx;
640                 glyph->y = cy;
641
642                 for(y=0; y<glyph->image.h; ++y) for(x=0; x<glyph->image.w; ++x)
643                 {
644                         if(cx+x>=font->image.w || cy+y>=font->image.h)
645                                 continue;
646                         font->image.data[cx+x+(cy+y)*font->image.w] = 255-glyph->image.data[x+y*glyph->image.w];
647                 }
648         }
649
650         return 0;
651 }
652
653 int render_packed(Font *font, unsigned margin, unsigned padding)
654 {
655         unsigned i;
656         size_t area = 0;
657         char *used_glyphs;
658         unsigned *used_pixels;
659         unsigned cx = margin, cy;
660         unsigned used_h = 0;
661
662         /* Compute the total area occupied by glyphs and padding. */
663         for(i=0; i<font->n_glyphs; ++i)
664         {
665                 size_t a = area+(font->glyphs[i].image.w+padding)*(font->glyphs[i].image.h+padding);
666                 if(a<area)
667                 {
668                         fprintf(stderr, "Overflow in counting total glyph area\n");
669                         return -1;
670                 }
671                 area = a;
672         }
673
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)
677         {
678                 if(font->image.w<=margin*2)
679                         continue;
680                 font->image.h = (area*5/4)/(font->image.w-margin*2)+margin*2;
681                 if(font->image.h<=font->image.w)
682                         break;
683         }
684         font->image.h = round_to_pot(font->image.h);
685
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
689         column. */
690         font->image.data = (char *)alloc_image_data(font->image.w, font->image.h);
691         if(!font->image.data)
692                 return -1;
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);
698
699         for(cy=margin; cy+margin<font->image.h;)
700         {
701                 unsigned w;
702                 unsigned x, y;
703                 Glyph *glyph = NULL;
704                 unsigned best_score = 0;
705                 unsigned target_h = 0;
706
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;
712
713                 if(cx+margin>=font->image.w)
714                 {
715                         cx = margin;
716                         ++cy;
717                         continue;
718                 }
719
720                 /* Count the free pixel at this position. */
721                 for(w=0; (cx+w+margin<font->image.w && used_pixels[cx+w]<=cy); ++w) ;
722
723                 /* Find a suitable glyph to put here. */
724                 for(i=0; i<font->n_glyphs; ++i)
725                 {
726                         Glyph *g;
727
728                         g = &font->glyphs[i];
729                         if(!used_glyphs[i] && g->image.w<=w)
730                         {
731                                 unsigned score;
732
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)
738                                         score *= g->image.w;
739                                 else
740                                         score += g->image.w;
741
742                                 if(score>best_score)
743                                 {
744                                         glyph = g;
745                                         best_score = score;
746                                 }
747                         }
748                 }
749
750                 if(!glyph)
751                 {
752                         cx += w;
753                         continue;
754                 }
755
756                 used_glyphs[glyph-font->glyphs] = 1;
757                 glyph->x = cx;
758                 glyph->y = cy;
759
760                 for(y=0; y<glyph->image.h; ++y) for(x=0; x<glyph->image.w; ++x)
761                 {
762                         if(cx+x>=font->image.w || cy+y>=font->image.h)
763                                 continue;
764                         font->image.data[cx+x+(cy+y)*font->image.w] = 255-glyph->image.data[x+y*glyph->image.w];
765                 }
766                 for(x=0; x<glyph->image.w+2*padding; ++x)
767                 {
768                         if(cx+x<padding || cx+x>=font->image.w+padding)
769                                 continue;
770                         if(used_pixels[cx+x-padding]<cy+glyph->image.h+padding)
771                                 used_pixels[cx+x-padding] = cy+glyph->image.h+padding;
772                 }
773
774                 if(cy+glyph->image.h+margin>used_h)
775                         used_h = cy+glyph->image.h+margin;
776         }
777
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);
781
782         free(used_glyphs);
783         free(used_pixels);
784
785         return 0;
786 }
787
788 int save_defs(const char *fn, const Font *font)
789 {
790         FILE *out;
791         unsigned i;
792
793         out = fopen(fn, "w");
794         if(!out)
795         {
796                 fprintf(stderr, "Couldn't open %s\n",fn);
797                 return -1;
798         }
799
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)
806         {
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);
809         }
810         fprintf(out, "\n# Kerning info:\n");
811         fprintf(out, "# left right distance\n");
812         for(i=0; i<font->n_kerning; ++i)
813         {
814                 const Kerning *k = &font->kerning[i];
815                 fprintf(out, "kern %u %u %d\n", k->left_code, k->right_code, k->distance);
816         }
817
818         fclose(out);
819
820         return 0;
821 }
822
823 int save_png(const char *fn, const Image *image, char alpha)
824 {
825         FILE *out;
826         png_struct *pngs;
827         png_info *pngi;
828         png_byte **rows;
829         unsigned i;
830         png_byte *data2 = 0;
831         int color;
832
833         if(!strcmp(fn, "-"))
834                 out = stdout;
835         else
836         {
837                 out = fopen(fn, "wb");
838                 if(!out)
839                 {
840                         fprintf(stderr, "Couldn't open %s\n",fn);
841                         return -1;
842                 }
843         }
844
845         pngs = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
846         if(!pngs)
847         {
848                 fprintf(stderr, "Error writing PNG file\n");
849                 return -1;
850         }
851         pngi = png_create_info_struct(pngs);
852         if(!pngi)
853         {
854                 png_destroy_write_struct(&pngs, NULL);
855                 fprintf(stderr, "Error writing PNG file\n");
856                 return -1;
857         }
858
859         png_init_io(pngs, out);
860         rows = (png_byte **)malloc(image->h*sizeof(png_byte *));
861         if(alpha)
862         {
863                 data2 = (png_byte *)alloc_image_data(image->w*2, image->h);
864                 if(!data2)
865                         return -1;
866                 for(i=0; i<image->w*image->h; ++i)
867                 {
868                         data2[i*2] = 255;
869                         data2[i*2+1] = 255-image->data[i];
870                 }
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;
874         }
875         else
876         {
877                 for(i=0; i<image->h; ++i)
878                         rows[i] = (png_byte *)(image->data+i*image->w);
879                 color = PNG_COLOR_TYPE_GRAY;
880         }
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);
885         free(rows);
886         if(alpha)
887                 free(data2);
888
889         if(verbose)
890                 printf("Saved %dx%d PNG image to %s\n", image->w, image->h, fn);
891
892         fclose(out);
893
894         return 0;
895 }