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