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