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