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