1 module kodachrome.png;
2 import std.stdio;
3 import std.algorithm.mutation;
4 import std.string;
5 import x11.X;
6 import x11.Xlib;
7 import kodachrome.x;
8 
9 /+
10  + This part needs to be spun off into its own library.
11  +/
12 extern(C):
13 alias png_byte = char;
14 alias png_bytep = png_byte*;
15 alias png_const_bytep = const(png_byte)*;
16 
17 alias png_charp = char*;
18 alias png_const_charp = const(char)*;
19 alias png_voidp = void*;
20 
21 struct png_struct;
22 alias png_structp = png_struct*;
23 alias png_structpp = png_struct**;
24 alias png_structrp = png_structp;
25 alias png_const_structp = const(png_struct)*;
26 alias png_const_structrp = png_const_structp;
27 
28 struct png_info;
29 alias png_infop = png_info*;
30 alias png_infopp = png_info**;
31 alias png_inforp = png_infop;
32 alias png_const_infop = const(png_info)*;
33 alias png_const_inforp = png_const_infop;
34 
35 png_infop png_create_info_struct(png_const_structrp);
36 
37 alias png_error_ptr = void function(png_structp, png_const_charp);
38 
39 void png_destroy_write_struct(png_structpp, png_infopp);
40 
41 enum PNG_LIBPNG_VER_STRING = "1.6.37";
42 
43 png_structp png_create_write_struct(png_const_charp, png_voidp,
44     png_error_ptr, png_error_ptr);
45 
46 alias png_FILE_p = FILE*;
47 
48 void png_init_io(png_structrp, png_FILE_p);
49 
50 void png_set_IHDR(png_const_structrp, png_inforp, png_uint_32, png_uint_32,
51     int, int, int, int, int);
52 
53 alias png_uint_32 = uint;
54 
55 struct png_text
56 {
57     int compression;
58     png_charp key;
59     png_charp text;
60     size_t text_length;
61     size_t itxt_length;
62     png_charp lang;
63     png_charp lang_key;
64 }
65 
66 alias png_const_textp = const(png_text)*;
67 
68 void png_set_text(png_const_structrp, png_inforp, png_const_textp, int);
69 
70 void png_write_info(png_structrp, png_const_inforp);
71 
72 void png_write_row(png_structrp, png_const_bytep);
73 
74 void png_write_end(png_structrp, png_inforp);
75 
76 void png_free_data(png_const_structrp, png_inforp, png_uint_32, int);
77 
78 enum PNG_COLOR_MASK_COLOR = 2;
79 enum PNG_COLOR_MASK_ALPHA = 4;
80 enum PNG_COLOR_TYPE_RGB_ALPHA = PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_ALPHA;
81 
82 enum PNG_INTERLACE_NONE = 0;
83 
84 enum PNG_COMPRESSION_TYPE_BASE = 0;
85 
86 enum PNG_FILTER_TYPE_BASE = 0;
87 
88 enum PNG_TEXT_COMPRESSION_NONE = -1;
89 
90 enum PNG_FREE_ALL = 0xffffU;
91 
92 /+
93  + This stays.
94  +/
95 extern(D):
96 bool createPNG(string name, XImage* ximg)
97 {
98     png_text title_text;
99 
100     png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
101         null, null, null);
102     if (png_ptr == null) {
103         stderr.writeln("kodachrome: Could not create PNG write struct");
104         return false;
105     }
106 
107     png_infop info_ptr = png_create_info_struct(png_ptr);
108     if (info_ptr == null) {
109         stderr.writeln("kodachrome: Could not create PNG info struct");
110         png_destroy_write_struct(&png_ptr, null);
111         return false;
112     }
113 
114     string nameWithExt = name ~ ".png";
115     File f = File(nameWithExt, "w");
116 
117     png_init_io(png_ptr, f.getFP());
118 
119     png_set_IHDR(png_ptr, info_ptr, ximg.width, ximg.height, 8,
120         PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
121         PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
122 
123     title_text.compression = PNG_TEXT_COMPRESSION_NONE;
124     title_text.key = cast(char*)toStringz("Title");
125     title_text.text = cast(char*)toStringz(name);
126     png_set_text(png_ptr, info_ptr, &title_text, 1);
127 
128     png_write_info(png_ptr, info_ptr);
129 
130     char* row = ximg.data;
131     for (int i = 0; i < ximg.height; i++) {
132         if (ximg.bitmap_bit_order == LSBFirst) {
133             for (int idx = 0; idx < ximg.chars_per_line; idx += 4) {
134                 swap(row[idx], row[idx + 2]);
135                 row[idx + 3] = 255;
136             }
137         } else {
138             for (int idx = 0; idx < ximg.chars_per_line; idx += 4) {
139                 ubyte t1 = row[idx + 1];
140                 ubyte t2 = row[idx + 2];
141                 ubyte t3 = row[idx + 3];
142 
143                 row[idx] = t1;
144                 row[idx + 1] = t2;
145                 row[idx + 2] = t3;
146                 row[idx + 3] = 255;
147             }
148         }
149 
150         png_write_row(png_ptr, row);
151         row += ximg.chars_per_line;
152     }
153     png_write_end(png_ptr, null);
154 
155     f.close();
156 
157     png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
158     png_destroy_write_struct(&png_ptr, null);
159 
160     return true;
161 }