]> git.tdb.fi Git - ttf2png.git/blob - ttf2png.c
Perform color inversion and npot rounding in save_png
[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 } 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, unsigned);
82 int init_glyphs(Font *, FT_Face, const Range *, bool, unsigned, 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);
88 int render_packed(Font *, unsigned, unsigned);
89 int save_defs(const char *, const Font *);
90 int save_png(const char *, const Image *, bool, bool, bool);
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         unsigned border = 0;
113
114         FT_Library freetype;
115         FT_Face face;
116
117         int err;
118         int i;
119
120         char *out_fn = "font.png";
121         char *def_fn = NULL;
122
123         Font font;
124
125         if(argc<2)
126         {
127                 usage();
128                 return 1;
129         }
130
131         while((i = getopt(argc, argv, "r:s:l:c:o:atvh?ed:pim:n:gf:b:")) != -1)
132         {
133                 switch(i)
134                 {
135                 case 'r':
136                         ranges = (Range *)realloc(ranges, (++n_ranges)*sizeof(Range));
137                         convert_code_point_range('r', &ranges[n_ranges-1]);
138                         break;
139                 case 's':
140                         size = convert_numeric_option('s', 1);
141                         break;
142                 case 'l':
143                         cpl = convert_numeric_option('l', 1);
144                         break;
145                 case 'c':
146                         convert_size('c', &cellw, &cellh);
147                         break;
148                 case 'o':
149                         out_fn = optarg;
150                         break;
151                 case 'a':
152                         autohinter = 1;
153                         break;
154                 case 't':
155                         alpha = 1;
156                         break;
157                 case 'v':
158                         ++verbose;
159                         break;
160                 case 'h':
161                 case '?':
162                         usage();
163                         return 0;
164                 case 'e':
165                         seq = 1;
166                         break;
167                 case 'd':
168                         def_fn = optarg;
169                         break;
170                 case 'p':
171                         pack = 1;
172                         break;
173                 case 'i':
174                         invert = 1;
175                         break;
176                 case 'm':
177                         margin = convert_numeric_option('m', 0);
178                         break;
179                 case 'n':
180                         padding = convert_numeric_option('n', 0);
181                         break;
182                 case 'g':
183                         npot = 1;
184                         break;
185                 case 'f':
186                         distfield = convert_numeric_option('f', 1);
187                         break;
188                 case 'b':
189                         border = convert_numeric_option('b', 1);
190                         break;
191                 }
192         }
193         if(!strcmp(out_fn, "-"))
194                 verbose = 0;
195
196         if(optind!=argc-1)
197         {
198                 usage();
199                 return 1;
200         }
201
202         fn = argv[optind];
203
204         err = FT_Init_FreeType(&freetype);
205         if(err)
206         {
207                 fprintf(stderr, "Couldn't initialize FreeType library\n");
208                 return 1;
209         }
210
211         err = FT_New_Face(freetype, fn, 0, &face);
212         if(err)
213         {
214                 fprintf(stderr, "Couldn't load font file\n");
215                 if(err==FT_Err_Unknown_File_Format)
216                         fprintf(stderr, "Unknown file format\n");
217                 return 1;
218         }
219
220         if(verbose)
221         {
222                 const char *name = FT_Get_Postscript_Name(face);
223                 printf("Font name: %s\n", name);
224                 printf("Glyphs:    %ld\n", face->num_glyphs);
225         }
226
227         font.size = size;
228         if(distfield)
229         {
230                 if(!border)
231                         border = sqrti(font.size);
232                 size *= distfield;
233         }
234
235         err = FT_Set_Pixel_Sizes(face, 0, size);
236         if(err)
237         {
238                 fprintf(stderr, "Couldn't set size\n");
239                 return 1;
240         }
241
242         if(!n_ranges)
243         {
244                 ranges = malloc(sizeof(Range));
245                 ranges[0].first = 0;
246                 ranges[0].last = 255;
247                 n_ranges = 1;
248         }
249         else
250                 sort_and_compact_ranges(ranges, &n_ranges);
251
252         err = init_font(&font, face, ranges, n_ranges, autohinter, distfield, border);
253         if(err)
254                 return 1;
255
256         if(!font.n_glyphs)
257         {
258                 fprintf(stderr, "No glyphs found in the requested range\n");
259                 return 1;
260         }
261
262         if(pack)
263                 err = render_packed(&font, margin, padding);
264         else
265                 err = render_grid(&font, cellw, cellh, cpl, seq);
266         if(err)
267                 return 1;
268
269         err = save_png(out_fn, &font.image, (alpha && !distfield), (invert || distfield), npot);
270         if(err)
271                 return 1;
272
273         if(def_fn)
274                 save_defs(def_fn, &font);
275
276         for(i=0; (unsigned)i<font.n_glyphs; ++i)
277                 free(font.glyphs[i].image.data);
278         free(font.glyphs);
279         free(font.kerning);
280         free(font.image.data);
281         free(ranges);
282
283         FT_Done_Face(face);
284         FT_Done_FreeType(freetype);
285
286         return 0;
287 }
288
289 void usage(void)
290 {
291         printf("ttf2png 1.1 - True Type Font to PNG converter\n"
292                 "Copyright (c) 2004-2018  Mikko Rasa, Mikkosoft Productions\n"
293                 "Distributed under the GNU General Public License\n\n");
294
295         printf("Usage: ttf2png [options] <TTF file>\n\n");
296
297         printf("Accepted options (default values in [brackets])\n"
298                 "  -r  Range of code points to convert [0,255]\n"
299                 "  -s  Font size to use, in pixels [10]\n"
300                 "  -l  Number of glyphs to put in one line [auto]\n"
301                 "  -c  Glyph cell size, in pixels (grid mode only) [auto]\n"
302                 "  -o  Output file name (or - for stdout) [font.png]\n");
303         printf("  -a  Force autohinter\n"
304                 "  -t  Render glyphs to alpha channel\n"
305                 "  -i  Invert colors of the glyphs\n"
306                 "  -v  Increase the level of verbosity\n"
307                 "  -e  Use cells in sequence, without gaps (grid mode only)\n"
308                 "  -p  Pack the glyphs tightly instead of in a grid\n"
309                 "  -m  Margin around image edges (packed mode only) [0]\n"
310                 "  -n  Padding between glyphs (packed mode only) [1]\n"
311                 "  -g  Allow non-power-of-two result\n"
312                 "  -f  Create a distance field texture\n"
313                 "  -d  File name for writing glyph definitions\n"
314                 "  -h  Print this message\n");
315 }
316
317 int convert_numeric_option(char opt, int min_value)
318 {
319         int value;
320         char *ptr;
321
322         value = strtol(optarg, &ptr, 0);
323         if(value<min_value || *ptr)
324         {
325                 printf("Invalid option argument in -%c %s\n", opt, optarg);
326                 exit(1);
327         }
328
329         return value;
330 }
331
332 void convert_code_point_range(char opt, Range *range)
333 {
334         int value;
335         char *ptr;
336
337         if(!strcmp(optarg, "all"))
338         {
339                 range->first = 0;
340                 range->last = 0x10FFFF;
341                 return;
342         }
343
344         value = str_to_code_point(optarg, &ptr);
345         if(value>0 && *ptr==',')
346         {
347                 range->first = value;
348                 value = str_to_code_point(ptr+1, &ptr);
349                 if(value>0 && !*ptr)
350                 {
351                         range->last = value;
352                         return;
353                 }
354         }
355
356         printf("Invalid option argument in -%c %s\n", opt, optarg);
357         exit(1);
358 }
359
360 unsigned str_to_code_point(const char *nptr, char **endptr)
361 {
362         if(nptr[0]=='U' && nptr[1]=='+')
363                 return strtoul(nptr+2, endptr, 16);
364         else if(nptr[0]&0x80)
365         {
366                 unsigned bytes;
367                 unsigned code;
368                 unsigned i;
369
370                 if(endptr)
371                         *endptr = (char *)nptr;
372
373                 for(bytes=1; (bytes<4 && (nptr[0]&(0x80>>bytes))); ++bytes)
374                         if((nptr[bytes]&0xC0)!=0x80)
375                                 return 0;
376                 if(bytes<2)
377                         return 0;
378
379                 code = nptr[0]&(0x3F>>bytes);
380                 for(i=1; i<bytes; ++i)
381                         code = (code<<6)|(nptr[i]&0x3F);
382
383                 if(endptr)
384                         *endptr = (char *)nptr+bytes;
385
386                 return code;
387         }
388         else if(isdigit(nptr[0]))
389                 return strtoul(nptr, endptr, 0);
390         else
391         {
392                 if(endptr)
393                         *endptr = (char *)nptr+1;
394                 return *nptr;
395         }
396 }
397
398 void convert_size(char opt, unsigned *width, unsigned *height)
399 {
400         int value;
401         char *ptr;
402
403         if(!strcmp(optarg, "auto"))
404         {
405                 *width = 0;
406                 *height = 0;
407                 return;
408         }
409         else if(!strcmp(optarg, "autorect"))
410         {
411                 *width = 0;
412                 *height = 1;
413                 return;
414         }
415
416         value = strtol(optarg, &ptr, 0);
417         if(value>0)
418         {
419                 *width = value;
420                 if(*ptr=='x')
421                 {
422                         value = strtol(ptr+1, &ptr, 0);
423                         if(value>0 && !*ptr)
424                         {
425                                 *height = value;
426                                 return;
427                         }
428                 }
429                 else if(!*ptr)
430                 {
431                         *height = *width;
432                         return;
433                 }
434         }
435
436         printf("Invalid option argument in -%c %s\n", opt, optarg);
437         exit(1);
438 }
439
440 void sort_and_compact_ranges(Range *ranges, unsigned *n_ranges)
441 {
442         unsigned i, j;
443
444         if(!*n_ranges)
445                 return;
446
447         qsort(ranges, *n_ranges, sizeof(Range), &range_cmp);
448         for(i=0, j=1; j<*n_ranges; ++j)
449         {
450                 if(ranges[i].last+1>=ranges[j].first)
451                 {
452                         if(ranges[j].last>ranges[i].last)
453                                 ranges[i].last = ranges[j].last;
454                 }
455                 else
456                 {
457                         ++i;
458                         if(i!=j)
459                                 ranges[i] = ranges[j];
460                 }
461         }
462
463         *n_ranges = i+1;
464 }
465
466 int range_cmp(const void *p1, const void *p2)
467 {
468         const Range *r1 = (const Range *)p1;
469         const Range *r2 = (const Range *)p2;
470         if(r1->first!=r2->first)
471                 return (r1->first<r2->first ? -1 : 1);
472         else if(r1->last!=r2->last)
473                 return (r1->last<r2->last ? -1 : 1);
474         else
475                 return 0;
476 }
477
478 unsigned round_to_pot(unsigned n)
479 {
480         n -= 1;
481         n |= n>>1;
482         n |= n>>2;
483         n |= n>>4;
484         n |= n>>8;
485         n |= n>>16;
486
487         return n+1;
488 }
489
490 void *alloc_image_data(size_t a, size_t b)
491 {
492         void *ptr;
493
494         /* Carry out the multiplication manually so we can check for overflow. */
495         while(b>1)
496         {
497                 size_t c = a;
498                 a *= 2;
499                 if(b&1)
500                         a += c;
501                 if(a<c)
502                 {
503                         fprintf(stderr, "Cannot allocate %lu kbytes of memory for image\n", (unsigned long)(c/1024*b));
504                         return NULL;
505                 }
506                 b /= 2;
507         }
508         ptr = malloc(a);
509         if(!ptr)
510                 fprintf(stderr, "Cannot allocate %lu kbytes of memory for image\n", (unsigned long)(a/1024*b));
511         return ptr;
512 }
513
514 int init_font(Font *font, FT_Face face, const Range *ranges, unsigned n_ranges, bool autohinter, unsigned distfield, unsigned border)
515 {
516         unsigned i, j;
517         unsigned size = 0;
518         int scale = (distfield>0 ? distfield : 1);
519
520         font->ascent = (face->size->metrics.ascender/scale+63)/64;
521         font->descent = (face->size->metrics.descender/scale-63)/64;
522
523         if(verbose>=1)
524         {
525                 printf("Ascent:    %d\n", font->ascent);
526                 printf("Descent:   %d\n", font->descent);
527         }
528
529         font->n_glyphs = 0;
530         font->glyphs = NULL;
531         for(i=0; i<n_ranges; ++i)
532                 if(init_glyphs(font, face, &ranges[i], autohinter, distfield, border))
533                         return -1;
534
535         if(verbose>=1)
536                 printf("Loaded %u glyphs\n", font->n_glyphs);
537
538         font->n_kerning = 0;
539         font->kerning = NULL;
540         for(i=0; i<font->n_glyphs; ++i) for(j=0; j<font->n_glyphs; ++j)
541                 if(j!=i)
542                 {
543                         FT_Vector kerning;
544                         FT_Get_Kerning(face, font->glyphs[i].index, font->glyphs[j].index, FT_KERNING_DEFAULT, &kerning);
545
546                         /* FreeType documentation says that vertical kerning is practically
547                         never used, so we ignore it. */
548                         if(kerning.x)
549                         {
550                                 Kerning *kern;
551
552                                 if(font->n_kerning>=size)
553                                 {
554                                         size += 16;
555                                         font->kerning = (Kerning *)realloc(font->kerning, size*sizeof(Kerning));
556                                 }
557
558                                 kern = &font->kerning[font->n_kerning++];
559                                 kern->left_code = font->glyphs[i].code;
560                                 kern->right_code = font->glyphs[j].code;
561                                 kern->distance = (kerning.x/scale+32)/64;
562                         }
563                 }
564
565         if(verbose>=1)
566                 printf("Loaded %d kerning pairs\n", font->n_kerning);
567
568         return 0;
569 }
570
571 int init_glyphs(Font *font, FT_Face face, const Range *range, bool autohinter, unsigned distfield, unsigned border)
572 {
573         unsigned i, j;
574         unsigned size = font->n_glyphs;
575         int scale = (distfield>0 ? distfield : 1);
576
577         for(i=range->first; i<=range->last; ++i)
578         {
579                 unsigned n;
580                 FT_Bitmap *bmp = &face->glyph->bitmap;
581                 int flags = 0;
582                 Glyph *glyph;
583
584                 n = FT_Get_Char_Index(face, i);
585                 if(!n)
586                         continue;
587
588                 if(autohinter)
589                         flags |= FT_LOAD_FORCE_AUTOHINT;
590                 FT_Load_Glyph(face, n, flags);
591                 FT_Render_Glyph(face->glyph, (distfield ? FT_RENDER_MODE_MONO : FT_RENDER_MODE_NORMAL));
592
593                 if(verbose>=2)
594                 {
595                         printf("  Code point U+%04X", i);
596                         if(i>=0x20 && i<0x7F)
597                                 printf(" (%c)", i);
598                         else if(i>=0xA0 && i<=0x10FFFF)
599                         {
600                                 char utf8[5];
601                                 unsigned bytes;
602
603                                 for(bytes=2; i>>(1+bytes*5); ++bytes) ;
604                                 for(j=0; j<bytes; ++j)
605                                         utf8[j] = 0x80 | ((i>>((bytes-j-1)*6))&0x3F);
606                                 utf8[0] |= 0xF0<<(4-bytes);
607                                 utf8[j] = 0;
608
609                                 printf(" (%s)", utf8);
610                         }
611                         printf(": glyph %u, size %dx%d\n", n, bmp->width/scale, bmp->rows/scale);
612                 }
613
614                 if(bmp->pixel_mode!=FT_PIXEL_MODE_GRAY && bmp->pixel_mode!=FT_PIXEL_MODE_MONO)
615                 {
616                         fprintf(stderr, "Warning: Glyph %u skipped, incompatible pixel mode\n", n);
617                         continue;
618                 }
619
620                 if(font->n_glyphs>=size)
621                 {
622                         size += 16;
623                         font->glyphs = (Glyph *)realloc(font->glyphs, size*sizeof(Glyph));
624                 }
625
626                 glyph = &font->glyphs[font->n_glyphs++];
627                 glyph->index = n;
628                 glyph->code = i;
629                 glyph->offset_x = (int)(face->glyph->bitmap_left+scale/2)/scale;
630                 glyph->offset_y = (int)(face->glyph->bitmap_top-bmp->rows+scale/2)/scale;
631                 glyph->advance = (int)(face->glyph->advance.x/scale+32)/64;
632
633                 /* Copy the glyph image since FreeType uses a global buffer, which would
634                 be overwritten by the next glyph.  Negative pitch means the scanlines
635                 start from the bottom. */
636                 if(distfield)
637                 {
638                         glyph->offset_x -= border;
639                         glyph->offset_y -= border;
640                         create_distance_field(bmp, &glyph->image, distfield, border);
641                 }
642                 else
643                 {
644                         if(copy_bitmap(bmp, &glyph->image))
645                                 return -1;
646                 }
647         }
648
649         return 0;
650 }
651
652 int copy_bitmap(const FT_Bitmap *bmp, Image *image)
653 {
654         unsigned x, y;
655         unsigned char *src;
656         unsigned char *dst;
657
658         image->w = bmp->width;
659         image->h = bmp->rows;
660         if(!image->w || !image->h)
661         {
662                 image->data = NULL;
663                 return 0;
664         }
665
666         image->data = (unsigned char *)malloc(image->w*image->h);
667         if(!image->data)
668         {
669                 fprintf(stderr, "Cannot allocate %d bytes of memory for glyph\n", image->w*image->h);
670                 return -1;
671         }
672
673         if(bmp->pitch<0)
674                 src = bmp->buffer+(bmp->rows-1)*-bmp->pitch;
675         else
676                 src = bmp->buffer;
677         dst = image->data;
678
679         for(y=0; y<bmp->rows; ++y)
680         {
681                 if(bmp->pixel_mode==FT_PIXEL_MODE_MONO)
682                 {
683                         for(x=0; x<bmp->width; ++x)
684                                 dst[x] = ((src[x/8]&(0x80>>(x%8))) ? 0xFF : 0x00);
685                 }
686                 else
687                 {
688                         for(x=0; x<bmp->width; ++x)
689                                 dst[x] = src[x];
690                 }
691
692                 src += bmp->pitch;
693                 dst += image->w;
694         }
695
696         return 0;
697 }
698
699 unsigned sqrti(unsigned num)
700 {
701         unsigned result = (num>0xFFFF ? 0xFFFF : 0x100);
702         while(result && result*result>=result+num)
703                 result -= (result*result+result-num)/(result*2);
704
705         return result;
706 }
707
708 unsigned find_distance_to_edge(const Image *image, int origin_x, int origin_y, unsigned range)
709 {
710         unsigned i, j;
711         int x, y;
712         unsigned char origin_pixel = 0;
713         unsigned closest = range*range;
714
715         if(origin_x>=0 && (unsigned)origin_x<image->w && origin_y>=0 && (unsigned)origin_y<image->h)
716                 origin_pixel = image->data[origin_x+origin_y*image->w];
717
718         x = origin_x-1;
719         y = origin_y-1;
720         for(i=1; (i<range && i*i<=closest); ++i, --x, --y) for(j=0; j<4; ++j)
721         {
722                 unsigned k;
723                 int dx = (j==0 ? 1 : j==2 ? -1 : 0);
724                 int dy = (j==1 ? 1 : j==3 ? -1 : 0);
725
726                 for(k=0; k<i*2; ++k, x+=dx, y+=dy)
727                 {
728                         unsigned char pixel = 0;
729                         if(x>=0 && (unsigned)x<image->w && y>=0 && (unsigned)y<image->h)
730                                 pixel = image->data[x+y*image->w];
731                                 
732                         if((pixel^origin_pixel)&0x80)
733                         {
734                                 unsigned d = 2*i*i + k*k - 2*k*i;
735                                 if(d<closest)
736                                         closest = d;
737                         }
738                 }
739         }
740
741         return sqrti(closest*0x3F01)/range;
742 }
743
744 int create_distance_field(const FT_Bitmap *bmp, Image *image, unsigned scale, unsigned margin)
745 {
746         unsigned x, y;
747         Image base_image;
748
749         if(!bmp->width || !bmp->rows)
750         {
751                 image->w = 0;
752                 image->h = 0;
753                 image->data = NULL;
754                 return 0;
755         }
756
757         if(copy_bitmap(bmp, &base_image))
758                 return -1;
759
760         image->w = (base_image.w-1)/scale+2*margin+1;
761         image->h = (base_image.h-1)/scale+2*margin+1;
762         image->data = (unsigned char *)malloc(image->w*image->h);
763         if(!image->data)
764         {
765                 fprintf(stderr, "Cannot allocate %d bytes of memory for glyph\n", image->w*image->h);
766                 free(base_image.data);
767                 return -1;
768         }
769
770         for(y=0; y<image->h; ++y) for(x=0; x<image->w; ++x)
771         {
772                 int bx = (x-margin)*scale+scale/2;
773                 int by = (y-margin)*scale+scale/2;
774                 unsigned char pixel = find_distance_to_edge(&base_image, bx, by, margin*scale);
775                 if(bx>=0 && (unsigned)bx<base_image.w && by>=0 && (unsigned)by<base_image.h)
776                         pixel |= base_image.data[bx+by*base_image.w]&0x80;
777                 if(!(pixel&0x80))
778                         pixel = 0x80-pixel;
779                 image->data[x+y*image->w] = pixel;
780         }
781
782         free(base_image.data);
783
784         return 0;
785 }
786
787 int render_grid(Font *font, unsigned cellw, unsigned cellh, unsigned cpl, bool seq)
788 {
789         unsigned i;
790         int top = 0, bot = 0;
791         unsigned first, last;
792         unsigned maxw = 0, maxh = 0;
793
794         /* Find extremes of the glyph images. */
795         for(i=0; i<font->n_glyphs; ++i)
796         {
797                 int y;
798
799                 y = font->glyphs[i].offset_y+font->glyphs[i].image.h;
800                 if(y>top)
801                         top = y;
802                 if(font->glyphs[i].offset_y<bot)
803                         bot = font->glyphs[i].offset_y;
804                 if(font->glyphs[i].image.w>maxw)
805                         maxw = font->glyphs[i].image.w;
806                 if(font->glyphs[i].image.h>maxh)
807                         maxh = font->glyphs[i].image.h;
808         }
809
810         if(cellw==0)
811         {
812                 /* Establish a large enough cell to hold all glyphs in the range. */
813                 int square = (cellh==cellw);
814                 cellw = maxw;
815                 cellh = top-bot;
816                 if(square)
817                 {
818                         if(cellh>cellw)
819                                 cellw = cellh;
820                         else
821                                 cellh = cellw;
822                 }
823         }
824
825         if(verbose>=1)
826         {
827                 printf("Max size:  %u x %u\n", maxw, maxh);
828                 printf("Y range:   [%d %d]\n", bot, top);
829                 printf("Cell size: %u x %u\n", cellw, cellh);
830                 if(maxw>cellw || (unsigned)(top-bot)>cellh)
831                         fprintf(stderr, "Warning: character size exceeds cell size\n");
832         }
833
834         if(cpl==0)
835         {
836                 /* Determine number of characters per line, trying to fit all the glyphs
837                 in a square image. */
838                 for(i=1;; i<<=1)
839                 {
840                         cpl = i/cellw;
841                         if(cpl>0 && font->n_glyphs/cpl*cellh<=cpl*cellw)
842                                 break;
843                 }
844         }
845
846         first = font->glyphs[0].code;
847         if(!seq)
848                 first -= first%cpl;
849         last = font->glyphs[font->n_glyphs-1].code;
850
851         font->image.w = cpl*cellw;
852         if(seq)
853                 font->image.h = (font->n_glyphs+cpl-1)/cpl*cellh;
854         else
855                 font->image.h = (last-first+cpl)/cpl*cellh;
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, 0, 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] = 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)
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, 0, 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] = 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
1026         free(used_glyphs);
1027         free(used_pixels);
1028
1029         return 0;
1030 }
1031
1032 int save_defs(const char *fn, const Font *font)
1033 {
1034         FILE *out;
1035         unsigned i;
1036
1037         out = fopen(fn, "w");
1038         if(!out)
1039         {
1040                 fprintf(stderr, "Couldn't open %s\n",fn);
1041                 return -1;
1042         }
1043
1044         fprintf(out, "# Image/font info:\n");
1045         fprintf(out, "# width height size ascent descent\n");
1046         fprintf(out, "font %d %d %d %d %d\n", font->image.w, font->image.h, font->size, font->ascent, font->descent);
1047         fprintf(out, "\n# Glyph info:\n");
1048         fprintf(out, "# code x y width height offset_x offset_y advance\n");
1049         for(i=0; i<font->n_glyphs; ++i)
1050         {
1051                 const Glyph *g = &font->glyphs[i];
1052                 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);
1053         }
1054         fprintf(out, "\n# Kerning info:\n");
1055         fprintf(out, "# left right distance\n");
1056         for(i=0; i<font->n_kerning; ++i)
1057         {
1058                 const Kerning *k = &font->kerning[i];
1059                 fprintf(out, "kern %u %u %d\n", k->left_code, k->right_code, k->distance);
1060         }
1061
1062         fclose(out);
1063
1064         return 0;
1065 }
1066
1067 int save_png(const char *fn, const Image *image, bool alpha, bool invert, bool npot)
1068 {
1069         FILE *out;
1070         png_struct *pngs;
1071         png_info *pngi;
1072         unsigned w, h;
1073         png_byte *row;
1074         unsigned x, y;
1075         int color;
1076         unsigned flip_bits = (invert==alpha ? 0xFF : 0x00);
1077         unsigned char *src = image->data;
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         w = (npot ? image->w : round_to_pot(image->w));
1106         h = (npot ? image->h : round_to_pot(image->h));
1107         color = (alpha ? PNG_COLOR_TYPE_GRAY_ALPHA : PNG_COLOR_TYPE_GRAY);
1108         png_set_IHDR(pngs, pngi, w, h, 8, color, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
1109
1110         png_init_io(pngs, out);
1111         png_write_info(pngs, pngi);
1112         row = (png_byte *)malloc(w*(1+alpha));
1113         if(alpha)
1114         {
1115                 for(x=0; x<w; ++x)
1116                 {
1117                         row[x*2] = 255;
1118                         row[x*2+1] = flip_bits;
1119                 }
1120                 for(y=0; y<image->h; ++y)
1121                 {
1122                         for(x=0; x<image->w; ++x)
1123                                 row[x*2+1] = *src++^flip_bits;
1124                         png_write_row(pngs, row);
1125                 }
1126
1127                 for(x=0; x<w; ++x)
1128                         row[x*2+1] = 0;
1129         }
1130         else
1131         {
1132                 memset(row+image->w, flip_bits, w-image->w);
1133                 for(y=0; y<image->h; ++y)
1134                 {
1135                         for(x=0; x<image->w; ++x)
1136                                 row[x] = *src++^flip_bits;
1137                         png_write_row(pngs, row);
1138                 }
1139
1140                 memset(row, flip_bits, w);
1141         }
1142
1143         for(; y<h; ++y)
1144                 png_write_row(pngs, row);
1145
1146         png_write_end(pngs, pngi);
1147         png_destroy_write_struct(&pngs, &pngi);
1148         free(row);
1149
1150         if(verbose)
1151                 printf("Saved %dx%d PNG image to %s\n", w, h, fn);
1152
1153         fclose(out);
1154
1155         return 0;
1156 }