]> git.tdb.fi Git - ttf2png.git/blob - ttf2png.c
Allocate slightly larger image when creating packed texture
[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         unsigned 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 struct sRange
65 {
66         unsigned first;
67         unsigned last;
68 } Range;
69
70 typedef int bool;
71
72 void usage(void);
73 int convert_numeric_option(char, int);
74 void convert_code_point_range(char, Range *);
75 unsigned str_to_code_point(const char *, char **);
76 void convert_size(char, unsigned *, unsigned *);
77 void sort_and_compact_ranges(Range *, unsigned *);
78 int range_cmp(const void *, const void *);
79 unsigned round_to_pot(unsigned);
80 void *alloc_image_data(size_t, size_t);
81 int init_font(Font *, FT_Face, const Range *, unsigned, bool, unsigned);
82 int init_glyphs(Font *, FT_Face, const Range *, bool, unsigned);
83 int copy_bitmap(const FT_Bitmap *, Image *);
84 void propagate_distance(unsigned short *, int);
85 int create_distance_field(const FT_Bitmap *, Image *, unsigned, unsigned);
86 int render_grid(Font *, unsigned, unsigned, unsigned, bool, bool);
87 int render_packed(Font *, unsigned, unsigned, bool);
88 int save_defs(const char *, const Font *);
89 int save_png(const char *, const Image *, char);
90
91 char verbose = 0;
92
93 int main(int argc, char **argv)
94 {
95         char *fn;
96         Range *ranges = NULL;
97         unsigned n_ranges = 0;
98         unsigned size = 10;
99         unsigned cpl = 0;
100         unsigned cellw = 0;
101         unsigned cellh = 0;
102         bool autohinter = 0;
103         bool seq = 0;
104         bool alpha = 0;
105         bool invert = 0;
106         bool pack = 0;
107         unsigned margin = 0;
108         unsigned padding = 1;
109         bool npot = 0;
110         unsigned distfield = 0;
111
112         FT_Library freetype;
113         FT_Face face;
114
115         int err;
116         int i;
117
118         char *out_fn = "font.png";
119         char *def_fn = NULL;
120
121         Font font;
122
123         if(argc<2)
124         {
125                 usage();
126                 return 1;
127         }
128
129         while((i = getopt(argc, argv, "r:s:l:c:o:atvh?ed:pim:n:gf:")) != -1)
130         {
131                 switch(i)
132                 {
133                 case 'r':
134                         ranges = (Range *)realloc(ranges, (++n_ranges)*sizeof(Range));
135                         convert_code_point_range('r', &ranges[n_ranges-1]);
136                         break;
137                 case 's':
138                         size = convert_numeric_option('s', 1);
139                         break;
140                 case 'l':
141                         cpl = convert_numeric_option('l', 1);
142                         break;
143                 case 'c':
144                         convert_size('c', &cellw, &cellh);
145                         break;
146                 case 'o':
147                         out_fn = optarg;
148                         break;
149                 case 'a':
150                         autohinter = 1;
151                         break;
152                 case 't':
153                         alpha = 1;
154                         break;
155                 case 'v':
156                         ++verbose;
157                         break;
158                 case 'h':
159                 case '?':
160                         usage();
161                         return 0;
162                 case 'e':
163                         seq = 1;
164                         break;
165                 case 'd':
166                         def_fn = optarg;
167                         break;
168                 case 'p':
169                         pack = 1;
170                         break;
171                 case 'i':
172                         invert = 1;
173                         break;
174                 case 'm':
175                         margin = convert_numeric_option('m', 0);
176                         break;
177                 case 'n':
178                         padding = convert_numeric_option('n', 0);
179                         break;
180                 case 'g':
181                         npot = 1;
182                         break;
183                 case 'f':
184                         distfield = convert_numeric_option('f', 1);
185                         break;
186                 }
187         }
188         if(!strcmp(out_fn, "-"))
189                 verbose = 0;
190
191         if(optind!=argc-1)
192         {
193                 usage();
194                 return 1;
195         }
196
197         fn = argv[optind];
198
199         err = FT_Init_FreeType(&freetype);
200         if(err)
201         {
202                 fprintf(stderr, "Couldn't initialize FreeType library\n");
203                 return 1;
204         }
205
206         err = FT_New_Face(freetype, fn, 0, &face);
207         if(err)
208         {
209                 fprintf(stderr, "Couldn't load font file\n");
210                 if(err==FT_Err_Unknown_File_Format)
211                         fprintf(stderr, "Unknown file format\n");
212                 return 1;
213         }
214
215         if(verbose)
216         {
217                 const char *name = FT_Get_Postscript_Name(face);
218                 printf("Font name: %s\n", name);
219                 printf("Glyphs:    %ld\n", face->num_glyphs);
220         }
221
222         err = FT_Set_Pixel_Sizes(face, 0, (distfield ? size*distfield : size));
223         if(err)
224         {
225                 fprintf(stderr, "Couldn't set size\n");
226                 return 1;
227         }
228
229         if(!n_ranges)
230         {
231                 ranges = malloc(sizeof(Range));
232                 ranges[0].first = 0;
233                 ranges[0].last = 255;
234                 n_ranges = 1;
235         }
236         else
237                 sort_and_compact_ranges(ranges, &n_ranges);
238
239         font.size = size;
240         err = init_font(&font, face, ranges, n_ranges, autohinter, distfield);
241         if(err)
242                 return 1;
243
244         if(!font.n_glyphs)
245         {
246                 fprintf(stderr, "No glyphs found in the requested range\n");
247                 return 1;
248         }
249
250         if(pack)
251                 err = render_packed(&font, margin, padding, npot);
252         else
253                 err = render_grid(&font, cellw, cellh, cpl, seq, npot);
254         if(err)
255                 return 1;
256
257         if(invert || distfield)
258         {
259                 for(i=0; (unsigned)i<font.image.w*font.image.h; ++i)
260                         font.image.data[i] = 255-font.image.data[i];
261         }
262         err = save_png(out_fn, &font.image, (alpha && !distfield));
263         if(err)
264                 return 1;
265
266         if(def_fn)
267                 save_defs(def_fn, &font);
268
269         for(i=0; (unsigned)i<font.n_glyphs; ++i)
270                 free(font.glyphs[i].image.data);
271         free(font.glyphs);
272         free(font.kerning);
273         free(font.image.data);
274         free(ranges);
275
276         FT_Done_Face(face);
277         FT_Done_FreeType(freetype);
278
279         return 0;
280 }
281
282 void usage(void)
283 {
284         printf("ttf2png 1.1 - True Type Font to PNG converter\n"
285                 "Copyright (c) 2004-2018  Mikko Rasa, Mikkosoft Productions\n"
286                 "Distributed under the GNU General Public License\n\n");
287
288         printf("Usage: ttf2png [options] <TTF file>\n\n");
289
290         printf("Accepted options (default values in [brackets])\n"
291                 "  -r  Range of code points to convert [0,255]\n"
292                 "  -s  Font size to use, in pixels [10]\n"
293                 "  -l  Number of glyphs to put in one line [auto]\n"
294                 "  -c  Glyph cell size, in pixels (grid mode only) [auto]\n"
295                 "  -o  Output file name (or - for stdout) [font.png]\n");
296         printf("  -a  Force autohinter\n"
297                 "  -t  Render glyphs to alpha channel\n"
298                 "  -i  Invert colors of the glyphs\n"
299                 "  -v  Increase the level of verbosity\n"
300                 "  -e  Use cells in sequence, without gaps (grid mode only)\n"
301                 "  -p  Pack the glyphs tightly instead of in a grid\n"
302                 "  -m  Margin around image edges (packed mode only) [0]\n"
303                 "  -n  Padding between glyphs (packed mode only) [1]\n"
304                 "  -g  Allow non-power-of-two result\n"
305                 "  -f  Create a distance field texture\n"
306                 "  -d  File name for writing glyph definitions\n"
307                 "  -h  Print this message\n");
308 }
309
310 int convert_numeric_option(char opt, int min_value)
311 {
312         int value;
313         char *ptr;
314
315         value = strtol(optarg, &ptr, 0);
316         if(value<min_value || *ptr)
317         {
318                 printf("Invalid option argument in -%c %s\n", opt, optarg);
319                 exit(1);
320         }
321
322         return value;
323 }
324
325 void convert_code_point_range(char opt, Range *range)
326 {
327         int value;
328         char *ptr;
329
330         if(!strcmp(optarg, "all"))
331         {
332                 range->first = 0;
333                 range->last = 0x10FFFF;
334                 return;
335         }
336
337         value = str_to_code_point(optarg, &ptr);
338         if(value>0 && *ptr==',')
339         {
340                 range->first = value;
341                 value = str_to_code_point(ptr+1, &ptr);
342                 if(value>0 && !*ptr)
343                 {
344                         range->last = value;
345                         return;
346                 }
347         }
348
349         printf("Invalid option argument in -%c %s\n", opt, optarg);
350         exit(1);
351 }
352
353 unsigned str_to_code_point(const char *nptr, char **endptr)
354 {
355         if(nptr[0]=='U' && nptr[1]=='+')
356                 return strtoul(nptr+2, endptr, 16);
357         else if(nptr[0]&0x80)
358         {
359                 unsigned bytes;
360                 unsigned code;
361                 unsigned i;
362
363                 if(endptr)
364                         *endptr = (char *)nptr;
365
366                 for(bytes=1; (bytes<4 && (nptr[0]&(0x80>>bytes))); ++bytes)
367                         if((nptr[bytes]&0xC0)!=0x80)
368                                 return 0;
369                 if(bytes<2)
370                         return 0;
371
372                 code = nptr[0]&(0x3F>>bytes);
373                 for(i=1; i<bytes; ++i)
374                         code = (code<<6)|(nptr[i]&0x3F);
375
376                 if(endptr)
377                         *endptr = (char *)nptr+bytes;
378
379                 return code;
380         }
381         else if(isdigit(nptr[0]))
382                 return strtoul(nptr, endptr, 0);
383         else
384         {
385                 if(endptr)
386                         *endptr = (char *)nptr+1;
387                 return *nptr;
388         }
389 }
390
391 void convert_size(char opt, unsigned *width, unsigned *height)
392 {
393         int value;
394         char *ptr;
395
396         if(!strcmp(optarg, "auto"))
397         {
398                 *width = 0;
399                 *height = 0;
400                 return;
401         }
402         else if(!strcmp(optarg, "autorect"))
403         {
404                 *width = 0;
405                 *height = 1;
406                 return;
407         }
408
409         value = strtol(optarg, &ptr, 0);
410         if(value>0)
411         {
412                 *width = value;
413                 if(*ptr=='x')
414                 {
415                         value = strtol(ptr+1, &ptr, 0);
416                         if(value>0 && !*ptr)
417                         {
418                                 *height = value;
419                                 return;
420                         }
421                 }
422                 else if(!*ptr)
423                 {
424                         *height = *width;
425                         return;
426                 }
427         }
428
429         printf("Invalid option argument in -%c %s\n", opt, optarg);
430         exit(1);
431 }
432
433 void sort_and_compact_ranges(Range *ranges, unsigned *n_ranges)
434 {
435         unsigned i, j;
436
437         if(!*n_ranges)
438                 return;
439
440         qsort(ranges, *n_ranges, sizeof(Range), &range_cmp);
441         for(i=0, j=1; j<*n_ranges; ++j)
442         {
443                 if(ranges[i].last+1>=ranges[j].first)
444                 {
445                         if(ranges[j].last>ranges[i].last)
446                                 ranges[i].last = ranges[j].last;
447                 }
448                 else
449                 {
450                         ++i;
451                         if(i!=j)
452                                 ranges[i] = ranges[j];
453                 }
454         }
455
456         *n_ranges = i+1;
457 }
458
459 int range_cmp(const void *p1, const void *p2)
460 {
461         const Range *r1 = (const Range *)p1;
462         const Range *r2 = (const Range *)p2;
463         if(r1->first!=r2->first)
464                 return (r1->first<r2->first ? -1 : 1);
465         else if(r1->last!=r2->last)
466                 return (r1->last<r2->last ? -1 : 1);
467         else
468                 return 0;
469 }
470
471 unsigned round_to_pot(unsigned n)
472 {
473         n -= 1;
474         n |= n>>1;
475         n |= n>>2;
476         n |= n>>4;
477         n |= n>>8;
478         n |= n>>16;
479
480         return n+1;
481 }
482
483 void *alloc_image_data(size_t a, size_t b)
484 {
485         void *ptr;
486
487         /* Carry out the multiplication manually so we can check for overflow. */
488         while(b>1)
489         {
490                 size_t c = a;
491                 a *= 2;
492                 if(b&1)
493                         a += c;
494                 if(a<c)
495                 {
496                         fprintf(stderr, "Cannot allocate %lu kbytes of memory for image\n", (unsigned long)(c/1024*b));
497                         return NULL;
498                 }
499                 b /= 2;
500         }
501         ptr = malloc(a);
502         if(!ptr)
503                 fprintf(stderr, "Cannot allocate %lu kbytes of memory for image\n", (unsigned long)(a/1024*b));
504         return ptr;
505 }
506
507 int init_font(Font *font, FT_Face face, const Range *ranges, unsigned n_ranges, bool autohinter, unsigned distfield)
508 {
509         unsigned i, j;
510         unsigned size = 0;
511         int scale = (distfield>0 ? distfield : 1);
512
513         font->ascent = (face->size->metrics.ascender/scale+63)/64;
514         font->descent = (face->size->metrics.descender/scale-63)/64;
515
516         if(verbose>=1)
517         {
518                 printf("Ascent:    %d\n", font->ascent);
519                 printf("Descent:   %d\n", font->descent);
520         }
521
522         font->n_glyphs = 0;
523         font->glyphs = NULL;
524         for(i=0; i<n_ranges; ++i)
525                 if(init_glyphs(font, face, &ranges[i], autohinter, distfield))
526                         return -1;
527
528         if(verbose>=1)
529                 printf("Loaded %u glyphs\n", font->n_glyphs);
530
531         font->n_kerning = 0;
532         font->kerning = NULL;
533         for(i=0; i<font->n_glyphs; ++i) for(j=0; j<font->n_glyphs; ++j)
534                 if(j!=i)
535                 {
536                         FT_Vector kerning;
537                         FT_Get_Kerning(face, font->glyphs[i].index, font->glyphs[j].index, FT_KERNING_DEFAULT, &kerning);
538
539                         /* FreeType documentation says that vertical kerning is practically
540                         never used, so we ignore it. */
541                         if(kerning.x)
542                         {
543                                 Kerning *kern;
544
545                                 if(font->n_kerning>=size)
546                                 {
547                                         size += 16;
548                                         font->kerning = (Kerning *)realloc(font->kerning, size*sizeof(Kerning));
549                                 }
550
551                                 kern = &font->kerning[font->n_kerning++];
552                                 kern->left_code = font->glyphs[i].code;
553                                 kern->right_code = font->glyphs[j].code;
554                                 kern->distance = (kerning.x/scale+32)/64;
555                         }
556                 }
557
558         if(verbose>=1)
559                 printf("Loaded %d kerning pairs\n", font->n_kerning);
560
561         return 0;
562 }
563
564 int init_glyphs(Font *font, FT_Face face, const Range *range, bool autohinter, unsigned distfield)
565 {
566         unsigned i, j;
567         unsigned size = font->n_glyphs;
568         int scale = (distfield>0 ? distfield : 1);
569
570         for(i=range->first; i<=range->last; ++i)
571         {
572                 unsigned n;
573                 FT_Bitmap *bmp = &face->glyph->bitmap;
574                 int flags = 0;
575                 Glyph *glyph;
576
577                 n = FT_Get_Char_Index(face, i);
578                 if(!n)
579                         continue;
580
581                 if(autohinter)
582                         flags |= FT_LOAD_FORCE_AUTOHINT;
583                 FT_Load_Glyph(face, n, flags);
584                 FT_Render_Glyph(face->glyph, (distfield ? FT_RENDER_MODE_MONO : FT_RENDER_MODE_NORMAL));
585
586                 if(verbose>=2)
587                 {
588                         printf("  Code point U+%04X", i);
589                         if(i>=0x20 && i<0x7F)
590                                 printf(" (%c)", i);
591                         else if(i>=0xA0 && i<=0x10FFFF)
592                         {
593                                 char utf8[5];
594                                 unsigned bytes;
595
596                                 for(bytes=2; i>>(1+bytes*5); ++bytes) ;
597                                 for(j=0; j<bytes; ++j)
598                                         utf8[j] = 0x80 | ((i>>((bytes-j-1)*6))&0x3F);
599                                 utf8[0] |= 0xF0<<(4-bytes);
600                                 utf8[j] = 0;
601
602                                 printf(" (%s)", utf8);
603                         }
604                         printf(": glyph %u, size %dx%d\n", n, bmp->width/scale, bmp->rows/scale);
605                 }
606
607                 if(bmp->pixel_mode!=FT_PIXEL_MODE_GRAY && bmp->pixel_mode!=FT_PIXEL_MODE_MONO)
608                 {
609                         fprintf(stderr, "Warning: Glyph %u skipped, incompatible pixel mode\n", n);
610                         continue;
611                 }
612
613                 if(font->n_glyphs>=size)
614                 {
615                         size += 16;
616                         font->glyphs = (Glyph *)realloc(font->glyphs, size*sizeof(Glyph));
617                 }
618
619                 glyph = &font->glyphs[font->n_glyphs++];
620                 glyph->index = n;
621                 glyph->code = i;
622                 glyph->offset_x = (int)(face->glyph->bitmap_left+scale/2)/scale;
623                 glyph->offset_y = (int)(face->glyph->bitmap_top-bmp->rows+scale/2)/scale;
624                 glyph->advance = (int)(face->glyph->advance.x/scale+32)/64;
625
626                 /* Copy the glyph image since FreeType uses a global buffer, which would
627                 be overwritten by the next glyph.  Negative pitch means the scanlines
628                 start from the bottom. */
629                 if(distfield)
630                 {
631                         unsigned margin = 3;
632
633                         glyph->offset_x -= margin;
634                         glyph->offset_y -= margin;
635                         create_distance_field(bmp, &glyph->image, distfield, margin);
636                 }
637                 else
638                 {
639                         if(copy_bitmap(bmp, &glyph->image))
640                                 return -1;
641                 }
642         }
643
644         return 0;
645 }
646
647 int copy_bitmap(const FT_Bitmap *bmp, Image *image)
648 {
649         unsigned x, y;
650         unsigned char *src;
651         unsigned char *dst;
652
653         image->w = bmp->width;
654         image->h = bmp->rows;
655         if(!image->w || !image->h)
656         {
657                 image->data = NULL;
658                 return 0;
659         }
660
661         image->data = (unsigned char *)malloc(image->w*image->h);
662         if(!image->data)
663         {
664                 fprintf(stderr, "Cannot allocate %d bytes of memory for glyph\n", image->w*image->h);
665                 return -1;
666         }
667
668         if(bmp->pitch<0)
669                 src = bmp->buffer+(bmp->rows-1)*-bmp->pitch;
670         else
671                 src = bmp->buffer;
672         dst = image->data;
673
674         for(y=0; y<bmp->rows; ++y)
675         {
676                 if(bmp->pixel_mode==FT_PIXEL_MODE_MONO)
677                 {
678                         for(x=0; x<bmp->width; ++x)
679                                 dst[x] = ((src[x/8]&(0x80>>(x%8))) ? 0xFF : 0x00);
680                 }
681                 else
682                 {
683                         for(x=0; x<bmp->width; ++x)
684                                 dst[x] = src[x];
685                 }
686
687                 src += bmp->pitch;
688                 dst += image->w;
689         }
690
691         return 0;
692 }
693
694 void propagate_distance(unsigned short *pixel, int offset)
695 {
696         unsigned short *neighbor = pixel+offset;
697         if((*neighbor^*pixel)&0x8000)
698                 *neighbor = (*neighbor&0x8000)+1;
699         else if((*neighbor&0x7FFF)>(*pixel&0x7FFF))
700                 *neighbor = *pixel+2;
701 }
702
703 int create_distance_field(const FT_Bitmap *bmp, Image *image, unsigned scale, unsigned margin)
704 {
705         unsigned x, y;
706         Image base_image;
707         unsigned short *distance_map;
708         unsigned map_w;
709         unsigned map_h;
710         unsigned offset;
711
712         if(!bmp->width || !bmp->rows)
713         {
714                 image->w = 0;
715                 image->h = 0;
716                 image->data = NULL;
717                 return 0;
718         }
719
720         if(copy_bitmap(bmp, &base_image))
721                 return -1;
722
723         map_w = base_image.w+2*margin*scale+scale-1;
724         map_w -= map_w%scale;
725         map_h = base_image.h+2*margin*scale+scale-1;
726         map_h -= map_h%scale;
727         distance_map = (unsigned short *)malloc(map_w*map_h*sizeof(unsigned short));
728         if(!distance_map)
729         {
730                 fprintf(stderr, "Cannot allocate %d bytes of memory for distance map\n", map_w*map_h);
731                 free(base_image.data);
732                 return -1;
733         }
734
735         image->w = map_w/scale;
736         image->h = map_h/scale;
737         image->data = (unsigned char *)malloc(image->w*image->h);
738         if(!image->data)
739         {
740                 fprintf(stderr, "Cannot allocate %d bytes of memory for glyph\n", image->w*image->h);
741                 free(base_image.data);
742                 free(distance_map);
743                 return -1;
744         }
745
746         for(x=0; x<map_w*map_h; ++x)
747                 distance_map[x] = 0x7FFF;
748
749         offset = margin*scale*(map_w+1);
750         for(y=0; y<base_image.h; ++y) for(x=0; x<base_image.w; ++x)
751                 distance_map[offset+x+y*map_w] |= (base_image.data[x+y*base_image.w]&0x80)<<8;
752
753         for(y=0; y<map_h; ++y)
754         {
755                 for(x=0; x+1<map_w; ++x)
756                         propagate_distance(distance_map+x+y*map_w, 1);
757                 for(x=map_w-1; x>0; --x)
758                         propagate_distance(distance_map+x+y*map_w, -1);
759         }
760
761         for(x=0; x<map_w; ++x)
762         {
763                 for(y=0; y+1<map_h; ++y)
764                         propagate_distance(distance_map+x+y*map_w, map_w);
765                 for(y=map_h-1; y>0; --y)
766                         propagate_distance(distance_map+x+y*map_w, -map_w);
767         }
768
769         offset = scale/2*(map_w+1);
770         for(y=0; y<image->h; ++y) for(x=0; x<image->w; ++x)
771         {
772                 unsigned short pixel = distance_map[offset+(x+y*map_w)*scale];
773                 unsigned short dist = (pixel&0x7FFF)*0x7F/(margin*scale*2+1);
774                 if(dist>0x7F)
775                         dist = 0x7F;
776                 if(pixel&0x8000)
777                         image->data[x+y*image->w] = 0x80+dist;
778                 else
779                         image->data[x+y*image->w] = 0x7F-dist;
780         }
781
782         free(distance_map);
783         free(base_image.data);
784
785         return 0;
786 }
787
788 int render_grid(Font *font, unsigned cellw, unsigned cellh, unsigned cpl, bool seq, bool npot)
789 {
790         unsigned i;
791         int top = 0, bot = 0;
792         unsigned first, last;
793         unsigned maxw = 0, maxh = 0;
794
795         /* Find extremes of the glyph images. */
796         for(i=0; i<font->n_glyphs; ++i)
797         {
798                 int y;
799
800                 y = font->glyphs[i].offset_y+font->glyphs[i].image.h;
801                 if(y>top)
802                         top = y;
803                 if(font->glyphs[i].offset_y<bot)
804                         bot = font->glyphs[i].offset_y;
805                 if(font->glyphs[i].image.w>maxw)
806                         maxw = font->glyphs[i].image.w;
807                 if(font->glyphs[i].image.h>maxh)
808                         maxh = font->glyphs[i].image.h;
809         }
810
811         if(cellw==0)
812         {
813                 /* Establish a large enough cell to hold all glyphs in the range. */
814                 int square = (cellh==cellw);
815                 cellw = maxw;
816                 cellh = top-bot;
817                 if(square)
818                 {
819                         if(cellh>cellw)
820                                 cellw = cellh;
821                         else
822                                 cellh = cellw;
823                 }
824         }
825
826         if(verbose>=1)
827         {
828                 printf("Max size:  %u x %u\n", maxw, maxh);
829                 printf("Y range:   [%d %d]\n", bot, top);
830                 printf("Cell size: %u x %u\n", cellw, cellh);
831                 if(maxw>cellw || (unsigned)(top-bot)>cellh)
832                         fprintf(stderr, "Warning: character size exceeds cell size\n");
833         }
834
835         if(cpl==0)
836         {
837                 /* Determine number of characters per line, trying to fit all the glyphs
838                 in a square image. */
839                 for(i=1;; i<<=1)
840                 {
841                         cpl = i/cellw;
842                         if(cpl>0 && font->n_glyphs/cpl*cellh<=cpl*cellw)
843                                 break;
844                 }
845         }
846
847         first = font->glyphs[0].code;
848         if(!seq)
849                 first -= first%cpl;
850         last = font->glyphs[font->n_glyphs-1].code;
851
852         font->image.w = cpl*cellw;
853         if(!npot)
854                 font->image.w = round_to_pot(font->image.w);
855         if(seq)
856                 font->image.h = (font->n_glyphs+cpl-1)/cpl*cellh;
857         else
858                 font->image.h = (last-first+cpl)/cpl*cellh;
859         if(!npot)
860                 font->image.h = round_to_pot(font->image.h);
861
862         font->image.data = (unsigned char *)alloc_image_data(font->image.w, font->image.h);
863         if(!font->image.data)
864                 return -1;
865         memset(font->image.data, 255, font->image.w*font->image.h);
866
867         for(i=0; i<font->n_glyphs; ++i)
868         {
869                 Glyph *glyph;
870                 unsigned ci, cx, cy;
871                 unsigned x, y;
872
873                 glyph = &font->glyphs[i];
874
875                 if(seq)
876                         ci = i;
877                 else
878                         ci = glyph->code-first;
879
880                 cx = (ci%cpl)*cellw;
881                 cy = (ci/cpl)*cellh;
882
883                 if(cellw>glyph->image.w)
884                         cx += (cellw-glyph->image.w)/2;
885                 cy += top-glyph->offset_y-glyph->image.h;
886
887                 glyph->x = cx;
888                 glyph->y = cy;
889
890                 for(y=0; y<glyph->image.h; ++y) for(x=0; x<glyph->image.w; ++x)
891                 {
892                         if(cx+x>=font->image.w || cy+y>=font->image.h)
893                                 continue;
894                         font->image.data[cx+x+(cy+y)*font->image.w] = 255-glyph->image.data[x+y*glyph->image.w];
895                 }
896         }
897
898         return 0;
899 }
900
901 int render_packed(Font *font, unsigned margin, unsigned padding, bool npot)
902 {
903         unsigned i;
904         size_t area = 0;
905         char *used_glyphs;
906         unsigned *used_pixels;
907         unsigned cx = margin, cy;
908         unsigned used_h = 0;
909
910         /* Compute the total area occupied by glyphs and padding. */
911         for(i=0; i<font->n_glyphs; ++i)
912         {
913                 size_t a = area+(font->glyphs[i].image.w+padding)*(font->glyphs[i].image.h+padding);
914                 if(a<area)
915                 {
916                         fprintf(stderr, "Overflow in counting total glyph area\n");
917                         return -1;
918                 }
919                 area = a;
920         }
921
922         /* Find an image size that's approximately square. */
923         for(font->image.w=1;; font->image.w<<=1)
924         {
925                 if(font->image.w<=margin*2)
926                         continue;
927                 font->image.h = area/(font->image.w-margin*2)+margin*2;
928                 if(font->image.h<=font->image.w)
929                         break;
930         }
931
932         /* Add some extra space to accommodate packing imperfections. */
933         font->image.h = font->image.h*3/2;
934
935         /* Allocate arrays for storing the image and keeping track of used pixels and
936         glyphs.  Since glyphs are rectangular and the image is filled starting from
937         the top, it's enough to track the number of used pixels at the top of each
938         column. */
939         font->image.data = (unsigned char *)alloc_image_data(font->image.w, font->image.h);
940         if(!font->image.data)
941                 return -1;
942         memset(font->image.data, 255, font->image.w*font->image.h);
943         used_pixels = (unsigned *)malloc(font->image.w*sizeof(unsigned));
944         memset(used_pixels, 0, font->image.w*sizeof(unsigned));
945         used_glyphs = (char *)malloc(font->n_glyphs);
946         memset(used_glyphs, 0, font->n_glyphs);
947
948         for(cy=margin; cy+margin<font->image.h;)
949         {
950                 unsigned w;
951                 unsigned x, y;
952                 Glyph *glyph = NULL;
953                 unsigned best_score = 0;
954                 unsigned target_h = 0;
955
956                 /* Find the leftmost free pixel on this row.  Also record the lowest
957                 extent of glyphs to the left of the free position. */
958                 for(; (cx+margin<font->image.w && used_pixels[cx]>cy); ++cx)
959                         if(used_pixels[cx]-cy-padding>target_h)
960                                 target_h = used_pixels[cx]-cy-padding;
961
962                 if(cx+margin>=font->image.w)
963                 {
964                         cx = margin;
965                         ++cy;
966                         continue;
967                 }
968
969                 /* Count the free pixel at this position. */
970                 for(w=0; (cx+w+margin<font->image.w && used_pixels[cx+w]<=cy); ++w) ;
971
972                 /* Find a suitable glyph to put here. */
973                 for(i=0; i<font->n_glyphs; ++i)
974                 {
975                         Glyph *g;
976
977                         g = &font->glyphs[i];
978                         if(!used_glyphs[i] && g->image.w<=w)
979                         {
980                                 unsigned score;
981
982                                 /* Prefer glyphs that would reach exactly as low as the ones left
983                                 of here.  This aims to create a straight edge at the bottom for
984                                 lining up further glyphs. */
985                                 score = g->image.h+padding;
986                                 if(g->image.h==target_h)
987                                         score *= g->image.w;
988                                 else
989                                         score += g->image.w;
990
991                                 if(score>best_score)
992                                 {
993                                         glyph = g;
994                                         best_score = score;
995                                 }
996                         }
997                 }
998
999                 if(!glyph)
1000                 {
1001                         cx += w;
1002                         continue;
1003                 }
1004
1005                 used_glyphs[glyph-font->glyphs] = 1;
1006                 glyph->x = cx;
1007                 glyph->y = cy;
1008
1009                 for(y=0; y<glyph->image.h; ++y) for(x=0; x<glyph->image.w; ++x)
1010                 {
1011                         if(cx+x>=font->image.w || cy+y>=font->image.h)
1012                                 continue;
1013                         font->image.data[cx+x+(cy+y)*font->image.w] = 255-glyph->image.data[x+y*glyph->image.w];
1014                 }
1015                 for(x=0; x<glyph->image.w+2*padding; ++x)
1016                 {
1017                         if(cx+x<padding || cx+x>=font->image.w+padding)
1018                                 continue;
1019                         if(used_pixels[cx+x-padding]<cy+glyph->image.h+padding)
1020                                 used_pixels[cx+x-padding] = cy+glyph->image.h+padding;
1021                 }
1022
1023                 if(cy+glyph->image.h+margin>used_h)
1024                         used_h = cy+glyph->image.h+margin;
1025         }
1026
1027         /* Trim the image to the actually used size, in case the original estimate
1028         was too pessimistic. */
1029         font->image.h = used_h;
1030         if(!npot)
1031                 font->image.h = round_to_pot(font->image.h);
1032
1033         free(used_glyphs);
1034         free(used_pixels);
1035
1036         return 0;
1037 }
1038
1039 int save_defs(const char *fn, const Font *font)
1040 {
1041         FILE *out;
1042         unsigned i;
1043
1044         out = fopen(fn, "w");
1045         if(!out)
1046         {
1047                 fprintf(stderr, "Couldn't open %s\n",fn);
1048                 return -1;
1049         }
1050
1051         fprintf(out, "# Image/font info:\n");
1052         fprintf(out, "# width height size ascent descent\n");
1053         fprintf(out, "font %d %d %d %d %d\n", font->image.w, font->image.h, font->size, font->ascent, font->descent);
1054         fprintf(out, "\n# Glyph info:\n");
1055         fprintf(out, "# code x y width height offset_x offset_y advance\n");
1056         for(i=0; i<font->n_glyphs; ++i)
1057         {
1058                 const Glyph *g = &font->glyphs[i];
1059                 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);
1060         }
1061         fprintf(out, "\n# Kerning info:\n");
1062         fprintf(out, "# left right distance\n");
1063         for(i=0; i<font->n_kerning; ++i)
1064         {
1065                 const Kerning *k = &font->kerning[i];
1066                 fprintf(out, "kern %u %u %d\n", k->left_code, k->right_code, k->distance);
1067         }
1068
1069         fclose(out);
1070
1071         return 0;
1072 }
1073
1074 int save_png(const char *fn, const Image *image, char alpha)
1075 {
1076         FILE *out;
1077         png_struct *pngs;
1078         png_info *pngi;
1079         png_byte **rows;
1080         unsigned i;
1081         png_byte *data2 = 0;
1082         int color;
1083
1084         if(!strcmp(fn, "-"))
1085                 out = stdout;
1086         else
1087         {
1088                 out = fopen(fn, "wb");
1089                 if(!out)
1090                 {
1091                         fprintf(stderr, "Couldn't open %s\n",fn);
1092                         return -1;
1093                 }
1094         }
1095
1096         pngs = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
1097         if(!pngs)
1098         {
1099                 fprintf(stderr, "Error writing PNG file\n");
1100                 return -1;
1101         }
1102         pngi = png_create_info_struct(pngs);
1103         if(!pngi)
1104         {
1105                 png_destroy_write_struct(&pngs, NULL);
1106                 fprintf(stderr, "Error writing PNG file\n");
1107                 return -1;
1108         }
1109
1110         png_init_io(pngs, out);
1111         rows = (png_byte **)malloc(image->h*sizeof(png_byte *));
1112         if(alpha)
1113         {
1114                 data2 = (png_byte *)alloc_image_data(image->w*2, image->h);
1115                 if(!data2)
1116                         return -1;
1117                 for(i=0; i<image->w*image->h; ++i)
1118                 {
1119                         data2[i*2] = 255;
1120                         data2[i*2+1] = 255-image->data[i];
1121                 }
1122                 for(i=0; i<image->h; ++i)
1123                         rows[i] = (png_byte *)(data2+i*image->w*2);
1124                 color = PNG_COLOR_TYPE_GRAY_ALPHA;
1125         }
1126         else
1127         {
1128                 for(i=0; i<image->h; ++i)
1129                         rows[i] = (png_byte *)(image->data+i*image->w);
1130                 color = PNG_COLOR_TYPE_GRAY;
1131         }
1132         png_set_IHDR(pngs, pngi, image->w, image->h, 8, color, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
1133         png_set_rows(pngs, pngi, rows);
1134         png_write_png(pngs, pngi, PNG_TRANSFORM_IDENTITY, NULL);
1135         png_destroy_write_struct(&pngs, &pngi);
1136         free(rows);
1137         if(alpha)
1138                 free(data2);
1139
1140         if(verbose)
1141                 printf("Saved %dx%d PNG image to %s\n", image->w, image->h, fn);
1142
1143         fclose(out);
1144
1145         return 0;
1146 }