]> git.tdb.fi Git - ttf2png.git/blob - ttf2png.c
Avoid warning about signed/unsigend mismatch
[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         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 void usage();
65 unsigned round_to_pot(unsigned);
66 void *alloc_image_data(size_t, size_t);
67 int init_font(Font *, FT_Face, unsigned, unsigned, int);
68 int render_grid(Font *, unsigned, unsigned, unsigned, int);
69 int render_packed(Font *);
70 int save_defs(const char *, const Font *);
71 int save_png(const char *, const Image *, char);
72
73 char verbose = 0;
74
75 int main(int argc, char **argv)
76 {
77         char *fn;
78         int  begin = 0;
79         int  end = 255;
80         int  size = 10;
81         int  cpl = 0;
82         int  cellw = 0;
83         int  cellh = 0;
84         char autohinter = 0;
85         char seq = 0;
86         char alpha = 0;
87         char invert = 0;
88         char pack = 0;
89
90         FT_Library freetype;
91         FT_Face    face;
92
93         int  err;
94         int  i;
95
96         char *out_fn = "font.png";
97         char *def_fn = NULL;
98
99         Font font;
100
101         if(argc<2)
102         {
103                 usage();
104                 return 1;
105         }
106
107         while((i = getopt(argc, argv, "r:s:l:c:o:atvh?ed:pi")) != -1)
108         {
109                 char *ptr;
110                 int  temp;
111                 switch(i)
112                 {
113                 case 'r':
114                         if(!strcmp(optarg, "all"))
115                         {
116                                 begin = 0;
117                                 end = 0x110000;
118                         }
119                         else
120                         {
121                                 if(!isdigit(optarg[0]))
122                                         temp = -1;
123                                 else
124                                 {
125                                         temp = strtol(optarg, &ptr, 0);
126                                         if(ptr[0]!=',' || !isdigit(ptr[1]))
127                                                 temp = -1;
128                                 }
129                                 if(temp<0)
130                                 {
131                                         printf("Not a valid range: %s\n", optarg);
132                                         exit(1);
133                                 }
134                                 else
135                                 {
136                                         begin = temp;
137                                         end = strtol(ptr+1, NULL, 0);
138                                 }
139                         }
140                         break;
141                 case 's':
142                         size = strtol(optarg, NULL, 0);
143                         break;
144                 case 'l':
145                         cpl = strtol(optarg, NULL, 0);
146                         break;
147                 case 'c':
148                         if(!strcmp(optarg, "auto"))
149                         {
150                                 cellw = 0;
151                                 cellh = 0;
152                         }
153                         else if(!strcmp(optarg, "autorect"))
154                         {
155                                 cellw = 0;
156                                 cellh = 1;
157                         }
158                         else
159                         {
160                                 cellw = strtol(optarg, &ptr, 0);
161                                 if(ptr[0]=='x' && isdigit(ptr[1]))
162                                         cellh = strtol(ptr+1, NULL, 0);
163                                 else
164                                         cellh = cellw;
165                         }
166                         break;
167                 case 'o':
168                         out_fn = optarg;
169                         break;
170                 case 'a':
171                         autohinter = 1;
172                         break;
173                 case 't':
174                         alpha = 1;
175                         break;
176                 case 'v':
177                         ++verbose;
178                         break;
179                 case 'h':
180                 case '?':
181                         usage();
182                         return 0;
183                 case 'e':
184                         seq = 1;
185                         break;
186                 case 'd':
187                         def_fn = optarg;
188                         break;
189                 case 'p':
190                         pack = 1;
191                         break;
192                 case 'i':
193                         invert = 1;
194                         break;
195                 }
196         }
197         if(!strcmp(out_fn, "-"))
198                 verbose = 0;
199
200         if(optind!=argc-1)
201         {
202                 usage();
203                 return 1;
204         }
205
206         fn = argv[optind];
207
208         err = FT_Init_FreeType(&freetype);
209         if(err)
210         {
211                 fprintf(stderr, "Couldn't initialize FreeType library\n");
212                 return 1;
213         }
214
215         err = FT_New_Face(freetype, fn, 0, &face);
216         if(err)
217         {
218                 fprintf(stderr, "Couldn't load font file\n");
219                 if(err==FT_Err_Unknown_File_Format)
220                         fprintf(stderr, "Unknown file format\n");
221                 return 1;
222         }
223
224         if(verbose)
225         {
226                 const char *name = FT_Get_Postscript_Name(face);
227                 printf("Font name: %s\n", name);
228                 printf("Glyphs:    %ld\n", face->num_glyphs);
229         }
230
231         err = FT_Set_Pixel_Sizes(face, 0, size);
232         if(err)
233         {
234                 fprintf(stderr, "Couldn't set size\n");
235                 return 1;
236         }
237
238         font.size = size;
239         err = init_font(&font, face, begin, end, autohinter);
240         if(err)
241                 return 1;
242
243         if(pack)
244                 err = render_packed(&font);
245         else
246                 err = render_grid(&font, cellw, cellh, cpl, seq);
247         if(err)
248                 return 1;
249
250         if(invert)
251         {
252                 for(i=0; (unsigned)i<font.image.w*font.image.h; ++i)
253                         font.image.data[i] = 255-font.image.data[i];
254         }
255         err = save_png(out_fn, &font.image, alpha);
256         if(err)
257                 return 1;
258
259         if(def_fn)
260                 save_defs(def_fn, &font);
261
262         for(i=0; (unsigned)i<font.n_glyphs; ++i)
263                 free(font.glyphs[i].image.data);
264         free(font.glyphs);
265         free(font.kerning);
266         free(font.image.data);
267
268         FT_Done_Face(face);
269         FT_Done_FreeType(freetype);
270
271         return 0;
272 }
273
274 void usage()
275 {
276         printf("ttf2png 1.0 - True Type Font to PNG converter\n"
277                 "Copyright (c) 2004-2008  Mikko Rasa, Mikkosoft Productions\n"
278                 "Distributed under the GNU General Public License\n\n");
279
280         printf("Usage: ttf2png [options] <TTF file>\n\n");
281
282         printf("Accepted options (default values in [brackets])\n"
283                 "  -r  Range of characters to convert [0,255]\n"
284                 "  -s  Font size to use, in pixels [10]\n"
285                 "  -l  Number of characters to put in one line [auto]\n"
286                 "  -c  Character cell size, in pixels [auto]\n"
287                 "  -o  Output file name (or - for stdout) [font.png]\n");
288         printf("  -a  Force autohinter\n"
289                 "  -t  Render glyphs to alpha channel\n"
290                 "  -i  Invert colors of the glyphs\n"
291                 "  -v  Increase the level of verbosity\n"
292                 "  -e  Use cells in sequence, without gaps\n"
293                 "  -p  Pack the glyphs tightly instead of in a grid\n"
294                 "  -d  File name for writing glyph definitions\n"
295                 "  -h  Print this message\n");
296 }
297
298 unsigned round_to_pot(unsigned n)
299 {
300         n -= 1;
301         n |= n>>1;
302         n |= n>>2;
303         n |= n>>4;
304         n |= n>>8;
305         n |= n>>16;
306
307         return n+1;
308 }
309
310 void *alloc_image_data(size_t a, size_t b)
311 {
312         void *ptr;
313
314         /* Carry out the multiplication manually so we can check for overflow. */
315         while(b>1)
316         {
317                 size_t c = a;
318                 a *= 2;
319                 if(b&1)
320                         a += c;
321                 if(a<c)
322                 {
323                         fprintf(stderr, "Cannot allocate %lu kbytes of memory for image\n", (unsigned long)(c/1024*b));
324                         return NULL;
325                 }
326                 b /= 2;
327         }
328         ptr = malloc(a);
329         if(!ptr)
330                 fprintf(stderr, "Cannot allocate %lu kbytes of memory for image\n", (unsigned long)(a/1024*b));
331         return ptr;
332 }
333
334 int init_font(Font *font, FT_Face face, unsigned first, unsigned last, int autohinter)
335 {
336         unsigned i, j;
337         unsigned size = 0;
338
339         font->ascent = (face->size->metrics.ascender+63)>>6;
340         font->descent = (face->size->metrics.descender+63)>>6;
341
342         if(verbose>=1)
343         {
344                 printf("Ascent:    %d\n", font->ascent);
345                 printf("Descent:   %d\n", font->descent);
346         }
347
348         font->n_glyphs = 0;
349         font->glyphs = NULL;
350         for(i=first; i<=last; ++i)
351         {
352                 unsigned  n;
353                 FT_Bitmap *bmp = &face->glyph->bitmap;
354                 unsigned  x, y;
355                 int       flags = 0;
356                 Glyph     *glyph;
357
358                 n = FT_Get_Char_Index(face, i);
359                 if(!n)
360                         continue;
361
362                 if(autohinter)
363                         flags |= FT_LOAD_FORCE_AUTOHINT;
364                 FT_Load_Glyph(face, n, flags);
365                 FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
366
367                 if(verbose>=2)
368                         printf("  Char %u: glyph %u, size %dx%d\n", i, n, bmp->width, bmp->rows);
369
370                 if(bmp->pixel_mode!=FT_PIXEL_MODE_GRAY)
371                 {
372                         fprintf(stderr, "Warning: Glyph %u skipped, not grayscale\n", n);
373                         continue;
374                 }
375
376                 if(font->n_glyphs>=size)
377                 {
378                         size += 16;
379                         font->glyphs = (Glyph *)realloc(font->glyphs, size*sizeof(Glyph));
380                 }
381
382                 glyph = &font->glyphs[font->n_glyphs++];
383                 glyph->index = n;
384                 glyph->code = i;
385                 glyph->image.w = bmp->width;
386                 glyph->image.h = bmp->rows;
387                 glyph->image.data = (char *)malloc(bmp->width*bmp->rows);
388                 if(!glyph->image.data)
389                 {
390                         fprintf(stderr, "Cannot allocate %d bytes of memory for glyph\n", bmp->width*bmp->rows);
391                         return -1;
392                 }
393                 glyph->offset_x = face->glyph->bitmap_left;
394                 glyph->offset_y = face->glyph->bitmap_top-bmp->rows;
395                 glyph->advance = (int)(face->glyph->advance.x+32)/64;
396
397                 /* Copy the glyph image since FreeType uses a global buffer, which would
398                 be overwritten by the next glyph.  Negative pitch means the scanlines
399                 start from the bottom. */
400                 if(bmp->pitch<0)
401                 {
402                         for(y=0; y<bmp->rows; ++y) for(x=0; x<bmp->width; ++x)
403                                 glyph->image.data[x+(glyph->image.h-1-y)*glyph->image.w] = bmp->buffer[x-y*bmp->pitch];
404                 }
405                 else
406                 {
407                         for(y=0; y<bmp->rows; ++y) for(x=0; x<bmp->width; ++x)
408                                 glyph->image.data[x+y*glyph->image.w] = bmp->buffer[x+y*bmp->pitch];
409                 }
410         }
411
412         if(verbose>=1)
413                 printf("Loaded %u glyphs\n", font->n_glyphs);
414
415         size = 0;
416         font->n_kerning = 0;
417         font->kerning = NULL;
418         for(i=0; i<font->n_glyphs; ++i) for(j=0; j<font->n_glyphs; ++j)
419                 if(j!=i)
420                 {
421                         FT_Vector kerning;
422                         FT_Get_Kerning(face, font->glyphs[i].index, font->glyphs[j].index, FT_KERNING_DEFAULT, &kerning);
423
424                         /* FreeType documentation says that vertical kerning is practically
425                         never used, so we ignore it. */
426                         if(kerning.x)
427                         {
428                                 Kerning *kern;
429
430                                 if(font->n_kerning>=size)
431                                 {
432                                         size += 16;
433                                         font->kerning = (Kerning *)realloc(font->kerning, size*sizeof(Kerning));
434                                 }
435
436                                 kern = &font->kerning[font->n_kerning++];
437                                 kern->left_code = font->glyphs[i].code;
438                                 kern->right_code = font->glyphs[j].code;
439                                 kern->distance = kerning.x/64;
440                         }
441                 }
442
443         if(verbose>=1)
444                 printf("Loaded %d kerning pairs\n", font->n_kerning);
445
446         return 0;
447 }
448
449 int render_grid(Font *font, unsigned cellw, unsigned cellh, unsigned cpl, int seq)
450 {
451         unsigned i;
452         int      top = 0, bot = 0;
453         unsigned first, last;
454         unsigned maxw = 0, maxh = 0;
455
456         /* Find extremes of the glyph images. */
457         for(i=0; i<font->n_glyphs; ++i)
458         {
459                 int y;
460
461                 y = font->glyphs[i].offset_y+font->glyphs[i].image.h;
462                 if(y>top)
463                         top = y;
464                 if(font->glyphs[i].offset_y<bot)
465                         bot = font->glyphs[i].offset_y;
466                 if(font->glyphs[i].image.w>maxw)
467                         maxw = font->glyphs[i].image.w;
468                 if(font->glyphs[i].image.h>maxh)
469                         maxh = font->glyphs[i].image.h;
470         }
471
472         if(cellw==0)
473         {
474                 /* Establish a large enough cell to hold all glyphs in the range. */
475                 int square = (cellh==cellw);
476                 cellw = maxw;
477                 cellh = top-bot;
478                 if(square)
479                 {
480                         if(cellh>cellw)
481                                 cellw = cellh;
482                         else
483                                 cellh = cellw;
484                 }
485         }
486
487         if(verbose>=1)
488         {
489                 printf("Max size:  %u x %u\n", maxw, maxh);
490                 printf("Y range:   [%d %d]\n", bot, top);
491                 printf("Cell size: %u x %u\n", cellw, cellh);
492                 if(maxw>cellw || (unsigned)(top-bot)>cellh)
493                         fprintf(stderr, "Warning: character size exceeds cell size\n");
494         }
495
496         if(cpl==0)
497         {
498                 /* Determine number of characters per line, trying to fit all the glyphs
499                 in a square image. */
500                 for(i=1;; i<<=1)
501                 {
502                         cpl = i/cellw;
503                         if(cpl>0 && font->n_glyphs/cpl*cellh<=cpl*cellw)
504                                 break;
505                 }
506         }
507
508         first = font->glyphs[0].code;
509         if(!seq)
510                 first -= first%cpl;
511         last = font->glyphs[font->n_glyphs-1].code;
512
513         font->image.w = round_to_pot(cpl*cellw);
514         if(seq)
515                 font->image.h = round_to_pot((font->n_glyphs+cpl-1)/cpl*cellh);
516         else
517                 font->image.h = round_to_pot((last-first+cpl)/cpl*cellh);
518
519         font->image.data = (char *)alloc_image_data(font->image.w, font->image.h);
520         if(!font->image.data)
521                 return -1;
522         memset(font->image.data, 255, font->image.w*font->image.h);
523
524         for(i=0; i<font->n_glyphs; ++i)
525         {
526                 Glyph    *glyph;
527                 unsigned ci, cx, cy;
528                 unsigned x, y;
529
530                 glyph = &font->glyphs[i];
531
532                 if(seq)
533                         ci = i;
534                 else
535                         ci = glyph->code-first;
536
537                 cx = (ci%cpl)*cellw;
538                 cy = (ci/cpl)*cellh;
539
540                 if(cellw>glyph->image.w)
541                         cx += (cellw-glyph->image.w)/2;
542                 cy += top-glyph->offset_y-glyph->image.h;
543
544                 glyph->x = cx;
545                 glyph->y = cy;
546
547                 for(y=0; y<glyph->image.h; ++y) for(x=0; x<glyph->image.w; ++x)
548                 {
549                         if(cx+x>=font->image.w || cy+y>=font->image.h)
550                                 continue;
551                         font->image.data[cx+x+(cy+y)*font->image.w] = 255-glyph->image.data[x+y*glyph->image.w];
552                 }
553         }
554
555         return 0;
556 }
557
558 int render_packed(Font *font)
559 {
560         unsigned i;
561         size_t   area = 0;
562         char     *used_glyphs;
563         unsigned *used_pixels;
564         unsigned cx = 0, cy;
565         unsigned used_h = 0;
566
567         /* Compute the total area occupied by glyphs and padding. */
568         for(i=0; i<font->n_glyphs; ++i)
569         {
570                 size_t a = area+(font->glyphs[i].image.w+1)*(font->glyphs[i].image.h+1);
571                 if(a<area)
572                 {
573                         fprintf(stderr, "Overflow in counting total glyph area\n");
574                         return -1;
575                 }
576                 area = a;
577         }
578
579         /* Find an image size that's no higher than wide, allowing for some
580         imperfections in the packing. */
581         for(font->image.w=1;; font->image.w<<=1)
582         {
583                 font->image.h = (area*5/4)/font->image.w;
584                 if(font->image.h<=font->image.w)
585                         break;
586         }
587         font->image.h = round_to_pot(font->image.h);
588
589         /* Allocate arrays for storing the image and keeping track of used pixels and
590         glyphs.  Since glyphs are rectangular and the image is filled starting from
591         the top, it's enough to track the number of used pixels at the top of each
592         column. */
593         font->image.data = (char *)alloc_image_data(font->image.w, font->image.h);
594         if(!font->image.data)
595                 return -1;
596         memset(font->image.data, 255, font->image.w*font->image.h);
597         used_pixels = (unsigned *)malloc(font->image.w*sizeof(unsigned));
598         memset(used_pixels, 0, font->image.w*sizeof(unsigned));
599         used_glyphs = (char *)malloc(font->n_glyphs);
600         memset(used_glyphs, 0, font->n_glyphs);
601
602         for(cy=0; cy<font->image.h;)
603         {
604                 unsigned w;
605                 unsigned x, y;
606                 Glyph    *glyph = NULL;
607                 unsigned best_score = 0;
608                 unsigned target_h = 0;
609
610                 /* Find the leftmost free pixel on this row.    Also record the lowest extent of glyphs
611                 to the left of the free position. */
612                 for(; (cx<font->image.w && used_pixels[cx]>cy); ++cx)
613                         if(used_pixels[cx]-cy-1>target_h)
614                                 target_h = used_pixels[cx]-cy-1;
615
616                 if(cx>=font->image.w)
617                 {
618                         cx = 0;
619                         ++cy;
620                         continue;
621                 }
622
623                 /* Count the free pixel at this position. */
624                 for(w=0; (cx+w<font->image.w && used_pixels[cx+w]<=cy); ++w) ;
625
626                 /* Find a suitable glyph to put here. */
627                 for(i=0; i<font->n_glyphs; ++i)
628                 {
629                         Glyph *g;
630
631                         g = &font->glyphs[i];
632                         if(!used_glyphs[i] && g->image.w<=w)
633                         {
634                                 unsigned score;
635
636                                 /* Prefer glyphs that would reach exactly as low as the ones left
637                                 of here.  This aims to create a straight edge at the bottom for
638                                 lining up further glyphs. */
639                                 score = g->image.h+1;
640                                 if(g->image.h==target_h)
641                                         score *= g->image.w;
642                                 else
643                                         score += g->image.w;
644
645                                 if(score>best_score)
646                                 {
647                                         glyph = g;
648                                         best_score = score;
649                                 }
650                         }
651                 }
652
653                 if(!glyph)
654                 {
655                         cx += w;
656                         continue;
657                 }
658
659                 used_glyphs[glyph-font->glyphs] = 1;
660                 glyph->x = cx;
661                 glyph->y = cy;
662
663                 for(y=0; y<glyph->image.h; ++y) for(x=0; x<glyph->image.w; ++x)
664                 {
665                         if(cx+x>=font->image.w || cy+y>=font->image.h)
666                                 continue;
667                         font->image.data[cx+x+(cy+y)*font->image.w] = 255-glyph->image.data[x+y*glyph->image.w];
668                 }
669                 for(x=0; x<glyph->image.w+2; ++x)
670                 {
671                         if(cx+x<1 || cx+x>font->image.w)
672                                 continue;
673                         if(used_pixels[cx+x-1]<cy+glyph->image.h+1)
674                                 used_pixels[cx+x-1] = cy+glyph->image.h+1;
675                 }
676
677                 if(cy+glyph->image.h>used_h)
678                         used_h = cy+glyph->image.h;
679         }
680
681         /* Trim the image to the actually used size, in case the original estimate
682         was too pessimistic. */
683         font->image.h = round_to_pot(used_h);
684
685         free(used_glyphs);
686         free(used_pixels);
687
688         return 0;
689 }
690
691 int save_defs(const char *fn, const Font *font)
692 {
693         FILE     *out;
694         unsigned i;
695
696         out = fopen(fn, "w");
697         if(!out)
698         {
699                 fprintf(stderr, "Couldn't open %s\n",fn);
700                 return -1;
701         }
702
703         fprintf(out, "# Image/font info:\n");
704         fprintf(out, "# width height size ascent descent\n");
705         fprintf(out, "font %d %d %d %d %d\n", font->image.w, font->image.h, font->size, font->ascent, font->descent);
706         fprintf(out, "\n# Glyph info:\n");
707         fprintf(out, "# code x y width height offset_x offset_y advance\n");
708         for(i=0; i<font->n_glyphs; ++i)
709         {
710                 const Glyph *g = &font->glyphs[i];
711                 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);
712         }
713         fprintf(out, "\n# Kerning info:\n");
714         fprintf(out, "# left right distance\n");
715         for(i=0; i<font->n_kerning; ++i)
716         {
717                 const Kerning *k = &font->kerning[i];
718                 fprintf(out, "kern %u %u %d\n", k->left_code, k->right_code, k->distance);
719         }
720
721         fclose(out);
722
723         return 0;
724 }
725
726 int save_png(const char *fn, const Image *image, char alpha)
727 {
728         FILE       *out;
729         png_struct *pngs;
730         png_info   *pngi;
731         png_byte   **rows;
732         unsigned   i;
733         png_byte   *data2 = 0;
734         int        color;
735
736         if(!strcmp(fn, "-"))
737                 out = stdout;
738         else
739         {
740                 out = fopen(fn, "wb");
741                 if(!out)
742                 {
743                         fprintf(stderr, "Couldn't open %s\n",fn);
744                         return -1;
745                 }
746         }
747
748         pngs = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
749         if(!pngs)
750         {
751                 fprintf(stderr, "Error writing PNG file\n");
752                 return -1;
753         }
754         pngi = png_create_info_struct(pngs);
755         if(!pngi)
756         {
757                 png_destroy_write_struct(&pngs, NULL);
758                 fprintf(stderr, "Error writing PNG file\n");
759                 return -1;
760         }
761
762         png_init_io(pngs, out);
763         rows = (png_byte **)malloc(image->h*sizeof(png_byte *));
764         if(alpha)
765         {
766                 data2 = (png_byte *)alloc_image_data(image->w*2, image->h);
767                 if(!data2)
768                         return -1;
769                 for(i=0; i<image->w*image->h; ++i)
770                 {
771                         data2[i*2] = 255;
772                         data2[i*2+1] = 255-image->data[i];
773                 }
774                 for(i=0; i<image->h; ++i)
775                         rows[i] = (png_byte *)(data2+i*image->w*2);
776                 color = PNG_COLOR_TYPE_GRAY_ALPHA;
777         }
778         else
779         {
780                 for(i=0; i<image->h; ++i)
781                         rows[i] = (png_byte *)(image->data+i*image->w);
782                 color = PNG_COLOR_TYPE_GRAY;
783         }
784         png_set_IHDR(pngs, pngi, image->w, image->h, 8, color, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
785         png_set_rows(pngs, pngi, rows);
786         png_write_png(pngs, pngi, PNG_TRANSFORM_IDENTITY, NULL);
787         png_destroy_write_struct(&pngs, &pngi);
788         free(rows);
789         if(alpha)
790                 free(data2);
791
792         if(verbose)
793                 printf("Saved %dx%d PNG image to %s\n", image->w, image->h, fn);
794
795         fclose(out);
796
797         return 0;
798 }