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