]> git.tdb.fi Git - ttf2png.git/blob - ttf2png.c
Don't crash if no glyphs were found
[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                         printf("  Char %u: glyph %u, size %dx%d\n", i, n, bmp->width, bmp->rows);
470
471                 if(bmp->pixel_mode!=FT_PIXEL_MODE_GRAY)
472                 {
473                         fprintf(stderr, "Warning: Glyph %u skipped, not grayscale\n", n);
474                         continue;
475                 }
476
477                 if(font->n_glyphs>=size)
478                 {
479                         size += 16;
480                         font->glyphs = (Glyph *)realloc(font->glyphs, size*sizeof(Glyph));
481                 }
482
483                 glyph = &font->glyphs[font->n_glyphs++];
484                 glyph->index = n;
485                 glyph->code = i;
486                 glyph->image.w = bmp->width;
487                 glyph->image.h = bmp->rows;
488                 glyph->image.data = (char *)malloc(bmp->width*bmp->rows);
489                 if(!glyph->image.data)
490                 {
491                         fprintf(stderr, "Cannot allocate %d bytes of memory for glyph\n", bmp->width*bmp->rows);
492                         return -1;
493                 }
494                 glyph->offset_x = face->glyph->bitmap_left;
495                 glyph->offset_y = face->glyph->bitmap_top-bmp->rows;
496                 glyph->advance = (int)(face->glyph->advance.x+32)/64;
497
498                 /* Copy the glyph image since FreeType uses a global buffer, which would
499                 be overwritten by the next glyph.  Negative pitch means the scanlines
500                 start from the bottom. */
501                 if(bmp->pitch<0)
502                 {
503                         for(y=0; y<bmp->rows; ++y) for(x=0; x<bmp->width; ++x)
504                                 glyph->image.data[x+(glyph->image.h-1-y)*glyph->image.w] = bmp->buffer[x-y*bmp->pitch];
505                 }
506                 else
507                 {
508                         for(y=0; y<bmp->rows; ++y) for(x=0; x<bmp->width; ++x)
509                                 glyph->image.data[x+y*glyph->image.w] = bmp->buffer[x+y*bmp->pitch];
510                 }
511         }
512
513         if(verbose>=1)
514                 printf("Loaded %u glyphs\n", font->n_glyphs);
515
516         size = 0;
517         font->n_kerning = 0;
518         font->kerning = NULL;
519         for(i=0; i<font->n_glyphs; ++i) for(j=0; j<font->n_glyphs; ++j)
520                 if(j!=i)
521                 {
522                         FT_Vector kerning;
523                         FT_Get_Kerning(face, font->glyphs[i].index, font->glyphs[j].index, FT_KERNING_DEFAULT, &kerning);
524
525                         /* FreeType documentation says that vertical kerning is practically
526                         never used, so we ignore it. */
527                         if(kerning.x)
528                         {
529                                 Kerning *kern;
530
531                                 if(font->n_kerning>=size)
532                                 {
533                                         size += 16;
534                                         font->kerning = (Kerning *)realloc(font->kerning, size*sizeof(Kerning));
535                                 }
536
537                                 kern = &font->kerning[font->n_kerning++];
538                                 kern->left_code = font->glyphs[i].code;
539                                 kern->right_code = font->glyphs[j].code;
540                                 kern->distance = kerning.x/64;
541                         }
542                 }
543
544         if(verbose>=1)
545                 printf("Loaded %d kerning pairs\n", font->n_kerning);
546
547         return 0;
548 }
549
550 int render_grid(Font *font, unsigned cellw, unsigned cellh, unsigned cpl, bool seq)
551 {
552         unsigned i;
553         int top = 0, bot = 0;
554         unsigned first, last;
555         unsigned maxw = 0, maxh = 0;
556
557         /* Find extremes of the glyph images. */
558         for(i=0; i<font->n_glyphs; ++i)
559         {
560                 int y;
561
562                 y = font->glyphs[i].offset_y+font->glyphs[i].image.h;
563                 if(y>top)
564                         top = y;
565                 if(font->glyphs[i].offset_y<bot)
566                         bot = font->glyphs[i].offset_y;
567                 if(font->glyphs[i].image.w>maxw)
568                         maxw = font->glyphs[i].image.w;
569                 if(font->glyphs[i].image.h>maxh)
570                         maxh = font->glyphs[i].image.h;
571         }
572
573         if(cellw==0)
574         {
575                 /* Establish a large enough cell to hold all glyphs in the range. */
576                 int square = (cellh==cellw);
577                 cellw = maxw;
578                 cellh = top-bot;
579                 if(square)
580                 {
581                         if(cellh>cellw)
582                                 cellw = cellh;
583                         else
584                                 cellh = cellw;
585                 }
586         }
587
588         if(verbose>=1)
589         {
590                 printf("Max size:  %u x %u\n", maxw, maxh);
591                 printf("Y range:   [%d %d]\n", bot, top);
592                 printf("Cell size: %u x %u\n", cellw, cellh);
593                 if(maxw>cellw || (unsigned)(top-bot)>cellh)
594                         fprintf(stderr, "Warning: character size exceeds cell size\n");
595         }
596
597         if(cpl==0)
598         {
599                 /* Determine number of characters per line, trying to fit all the glyphs
600                 in a square image. */
601                 for(i=1;; i<<=1)
602                 {
603                         cpl = i/cellw;
604                         if(cpl>0 && font->n_glyphs/cpl*cellh<=cpl*cellw)
605                                 break;
606                 }
607         }
608
609         first = font->glyphs[0].code;
610         if(!seq)
611                 first -= first%cpl;
612         last = font->glyphs[font->n_glyphs-1].code;
613
614         font->image.w = round_to_pot(cpl*cellw);
615         if(seq)
616                 font->image.h = round_to_pot((font->n_glyphs+cpl-1)/cpl*cellh);
617         else
618                 font->image.h = round_to_pot((last-first+cpl)/cpl*cellh);
619
620         font->image.data = (char *)alloc_image_data(font->image.w, font->image.h);
621         if(!font->image.data)
622                 return -1;
623         memset(font->image.data, 255, font->image.w*font->image.h);
624
625         for(i=0; i<font->n_glyphs; ++i)
626         {
627                 Glyph *glyph;
628                 unsigned ci, cx, cy;
629                 unsigned x, y;
630
631                 glyph = &font->glyphs[i];
632
633                 if(seq)
634                         ci = i;
635                 else
636                         ci = glyph->code-first;
637
638                 cx = (ci%cpl)*cellw;
639                 cy = (ci/cpl)*cellh;
640
641                 if(cellw>glyph->image.w)
642                         cx += (cellw-glyph->image.w)/2;
643                 cy += top-glyph->offset_y-glyph->image.h;
644
645                 glyph->x = cx;
646                 glyph->y = cy;
647
648                 for(y=0; y<glyph->image.h; ++y) for(x=0; x<glyph->image.w; ++x)
649                 {
650                         if(cx+x>=font->image.w || cy+y>=font->image.h)
651                                 continue;
652                         font->image.data[cx+x+(cy+y)*font->image.w] = 255-glyph->image.data[x+y*glyph->image.w];
653                 }
654         }
655
656         return 0;
657 }
658
659 int render_packed(Font *font, unsigned margin, unsigned padding)
660 {
661         unsigned i;
662         size_t area = 0;
663         char *used_glyphs;
664         unsigned *used_pixels;
665         unsigned cx = margin, cy;
666         unsigned used_h = 0;
667
668         /* Compute the total area occupied by glyphs and padding. */
669         for(i=0; i<font->n_glyphs; ++i)
670         {
671                 size_t a = area+(font->glyphs[i].image.w+padding)*(font->glyphs[i].image.h+padding);
672                 if(a<area)
673                 {
674                         fprintf(stderr, "Overflow in counting total glyph area\n");
675                         return -1;
676                 }
677                 area = a;
678         }
679
680         /* Find an image size that's no higher than wide, allowing for some
681         imperfections in the packing. */
682         for(font->image.w=1;; font->image.w<<=1)
683         {
684                 if(font->image.w<=margin*2)
685                         continue;
686                 font->image.h = (area*5/4)/(font->image.w-margin*2)+margin*2;
687                 if(font->image.h<=font->image.w)
688                         break;
689         }
690         font->image.h = round_to_pot(font->image.h);
691
692         /* Allocate arrays for storing the image and keeping track of used pixels and
693         glyphs.  Since glyphs are rectangular and the image is filled starting from
694         the top, it's enough to track the number of used pixels at the top of each
695         column. */
696         font->image.data = (char *)alloc_image_data(font->image.w, font->image.h);
697         if(!font->image.data)
698                 return -1;
699         memset(font->image.data, 255, font->image.w*font->image.h);
700         used_pixels = (unsigned *)malloc(font->image.w*sizeof(unsigned));
701         memset(used_pixels, 0, font->image.w*sizeof(unsigned));
702         used_glyphs = (char *)malloc(font->n_glyphs);
703         memset(used_glyphs, 0, font->n_glyphs);
704
705         for(cy=margin; cy+margin<font->image.h;)
706         {
707                 unsigned w;
708                 unsigned x, y;
709                 Glyph *glyph = NULL;
710                 unsigned best_score = 0;
711                 unsigned target_h = 0;
712
713                 /* Find the leftmost free pixel on this row.  Also record the lowest
714                 extent of glyphs to the left of the free position. */
715                 for(; (cx+margin<font->image.w && used_pixels[cx]>cy); ++cx)
716                         if(used_pixels[cx]-cy-padding>target_h)
717                                 target_h = used_pixels[cx]-cy-padding;
718
719                 if(cx+margin>=font->image.w)
720                 {
721                         cx = margin;
722                         ++cy;
723                         continue;
724                 }
725
726                 /* Count the free pixel at this position. */
727                 for(w=0; (cx+w+margin<font->image.w && used_pixels[cx+w]<=cy); ++w) ;
728
729                 /* Find a suitable glyph to put here. */
730                 for(i=0; i<font->n_glyphs; ++i)
731                 {
732                         Glyph *g;
733
734                         g = &font->glyphs[i];
735                         if(!used_glyphs[i] && g->image.w<=w)
736                         {
737                                 unsigned score;
738
739                                 /* Prefer glyphs that would reach exactly as low as the ones left
740                                 of here.  This aims to create a straight edge at the bottom for
741                                 lining up further glyphs. */
742                                 score = g->image.h+padding;
743                                 if(g->image.h==target_h)
744                                         score *= g->image.w;
745                                 else
746                                         score += g->image.w;
747
748                                 if(score>best_score)
749                                 {
750                                         glyph = g;
751                                         best_score = score;
752                                 }
753                         }
754                 }
755
756                 if(!glyph)
757                 {
758                         cx += w;
759                         continue;
760                 }
761
762                 used_glyphs[glyph-font->glyphs] = 1;
763                 glyph->x = cx;
764                 glyph->y = cy;
765
766                 for(y=0; y<glyph->image.h; ++y) for(x=0; x<glyph->image.w; ++x)
767                 {
768                         if(cx+x>=font->image.w || cy+y>=font->image.h)
769                                 continue;
770                         font->image.data[cx+x+(cy+y)*font->image.w] = 255-glyph->image.data[x+y*glyph->image.w];
771                 }
772                 for(x=0; x<glyph->image.w+2*padding; ++x)
773                 {
774                         if(cx+x<padding || cx+x>=font->image.w+padding)
775                                 continue;
776                         if(used_pixels[cx+x-padding]<cy+glyph->image.h+padding)
777                                 used_pixels[cx+x-padding] = cy+glyph->image.h+padding;
778                 }
779
780                 if(cy+glyph->image.h+margin>used_h)
781                         used_h = cy+glyph->image.h+margin;
782         }
783
784         /* Trim the image to the actually used size, in case the original estimate
785         was too pessimistic. */
786         font->image.h = round_to_pot(used_h);
787
788         free(used_glyphs);
789         free(used_pixels);
790
791         return 0;
792 }
793
794 int save_defs(const char *fn, const Font *font)
795 {
796         FILE *out;
797         unsigned i;
798
799         out = fopen(fn, "w");
800         if(!out)
801         {
802                 fprintf(stderr, "Couldn't open %s\n",fn);
803                 return -1;
804         }
805
806         fprintf(out, "# Image/font info:\n");
807         fprintf(out, "# width height size ascent descent\n");
808         fprintf(out, "font %d %d %d %d %d\n", font->image.w, font->image.h, font->size, font->ascent, font->descent);
809         fprintf(out, "\n# Glyph info:\n");
810         fprintf(out, "# code x y width height offset_x offset_y advance\n");
811         for(i=0; i<font->n_glyphs; ++i)
812         {
813                 const Glyph *g = &font->glyphs[i];
814                 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);
815         }
816         fprintf(out, "\n# Kerning info:\n");
817         fprintf(out, "# left right distance\n");
818         for(i=0; i<font->n_kerning; ++i)
819         {
820                 const Kerning *k = &font->kerning[i];
821                 fprintf(out, "kern %u %u %d\n", k->left_code, k->right_code, k->distance);
822         }
823
824         fclose(out);
825
826         return 0;
827 }
828
829 int save_png(const char *fn, const Image *image, char alpha)
830 {
831         FILE *out;
832         png_struct *pngs;
833         png_info *pngi;
834         png_byte **rows;
835         unsigned i;
836         png_byte *data2 = 0;
837         int color;
838
839         if(!strcmp(fn, "-"))
840                 out = stdout;
841         else
842         {
843                 out = fopen(fn, "wb");
844                 if(!out)
845                 {
846                         fprintf(stderr, "Couldn't open %s\n",fn);
847                         return -1;
848                 }
849         }
850
851         pngs = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
852         if(!pngs)
853         {
854                 fprintf(stderr, "Error writing PNG file\n");
855                 return -1;
856         }
857         pngi = png_create_info_struct(pngs);
858         if(!pngi)
859         {
860                 png_destroy_write_struct(&pngs, NULL);
861                 fprintf(stderr, "Error writing PNG file\n");
862                 return -1;
863         }
864
865         png_init_io(pngs, out);
866         rows = (png_byte **)malloc(image->h*sizeof(png_byte *));
867         if(alpha)
868         {
869                 data2 = (png_byte *)alloc_image_data(image->w*2, image->h);
870                 if(!data2)
871                         return -1;
872                 for(i=0; i<image->w*image->h; ++i)
873                 {
874                         data2[i*2] = 255;
875                         data2[i*2+1] = 255-image->data[i];
876                 }
877                 for(i=0; i<image->h; ++i)
878                         rows[i] = (png_byte *)(data2+i*image->w*2);
879                 color = PNG_COLOR_TYPE_GRAY_ALPHA;
880         }
881         else
882         {
883                 for(i=0; i<image->h; ++i)
884                         rows[i] = (png_byte *)(image->data+i*image->w);
885                 color = PNG_COLOR_TYPE_GRAY;
886         }
887         png_set_IHDR(pngs, pngi, image->w, image->h, 8, color, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
888         png_set_rows(pngs, pngi, rows);
889         png_write_png(pngs, pngi, PNG_TRANSFORM_IDENTITY, NULL);
890         png_destroy_write_struct(&pngs, &pngi);
891         free(rows);
892         if(alpha)
893                 free(data2);
894
895         if(verbose)
896                 printf("Saved %dx%d PNG image to %s\n", image->w, image->h, fn);
897
898         fclose(out);
899
900         return 0;
901 }