| Bsoft 2.0.5 Bernard's software package

rwPNG.cpp
Go to the documentation of this file.
1
9 #include "rwPNG.h"
10 #include "utilities.h"
11
12 #ifdef HAVE_PNG
13
14 #include "png.h"
15 #include "zlib.h"
16
17 // Declaration of global variables
18 extern int verbose; // Level of output to the screen
19
37 int readPNG(Bimage* p, int readdata)
38 {
39 FILE* infile; /* source file */
40 unsigned char sig[8];
41
42 if ((infile = fopen(p->file_name().c_str(), "rb")) == NULL) return -1;
43
44 // Signature check
45 size_t nr = fread(sig, 1, 8, infile);
46 if ( !nr ) return -1;
47 if ( png_sig_cmp(sig, 0, 8) ) return -1; /* bad signature */
48
49 /* could pass pointers to user-defined error handlers instead of NULLs: */
50 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
51 if ( !png_ptr ) return -4; /* out of memory */
52
53 png_infop info_ptr = png_create_info_struct(png_ptr);
54 if ( !info_ptr ) {
55 png_destroy_read_struct(&png_ptr, NULL, NULL);
56 return -4; /* out of memory */
57 }
58
59 /* setjmp() must be called in every function that calls a PNG-reading
60 * libpng function */
61 if ( setjmp(png_jmpbuf(png_ptr)) ) {
62 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
63 return -2;
64 }
65
66 png_init_io(png_ptr, infile);
67 png_set_sig_bytes(png_ptr, 8); /* we already read the 8 signature bytes */
68
69 png_read_info(png_ptr, info_ptr); /* read all PNG info up to image data */
70
71 /* expand palette images to RGB, low-bit-depth grayscale images to 8 bits,
72 * transparency chunks to full alpha channel; strip 16-bit-per-sample
73 * images to 8 bits per sample; and convert grayscale to RGB[A] */
74
75 int bit_depth = png_get_bit_depth(png_ptr, info_ptr);
76 int color_type = png_get_color_type(png_ptr, info_ptr);
77
78 if ( verbose & VERB_DEBUG )
79 cout << "DEBUG readPNG: color_type=" << color_type << " bit_depth=" << bit_depth << endl;
80
81 if ( color_type == PNG_COLOR_TYPE_PALETTE )
82 png_set_palette_to_rgb(png_ptr);
83 if ( color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8 )
84 png_set_expand_gray_1_2_4_to_8(png_ptr);
85 if ( png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) )
86 png_set_tRNS_to_alpha(png_ptr);
87 // if ( bit_depth == 16 )
88 // png_set_strip_16(png_ptr);
89 // if ( color_type == PNG_COLOR_TYPE_GRAY ||
90 // color_type == PNG_COLOR_TYPE_GRAY_ALPHA )
91 // png_set_gray_to_rgb(png_ptr);
92
93 png_set_interlace_handling(png_ptr);
94
95 png_read_update_info(png_ptr, info_ptr);
96
97 color_type = png_get_color_type(png_ptr, info_ptr);
98
99 int rowbytes = png_get_rowbytes(png_ptr, info_ptr);
100
101 // Transferring the information
102 p->size(png_get_image_width(png_ptr, info_ptr), png_get_image_height(png_ptr, info_ptr), 1);
103 p->channels(png_get_channels(png_ptr, info_ptr));
104 p->images(1);
105
106 switch ( bit_depth) {
107 case 1: p->data_type(Bit); break;
108 case 8: p->data_type(UCharacter); break;
109 case 16: p->data_type(UShort); break;
110 default: p->data_type(UCharacter); break;
111 }
112
113 switch ( color_type ) {
114 case PNG_COLOR_TYPE_GRAY: p->compound_type(TSimple); break;
115 case PNG_COLOR_TYPE_RGB: p->compound_type(TRGB); break;
116 case PNG_COLOR_TYPE_RGB_ALPHA: p->compound_type(TRGBA); break;
117 default: break;
118 }
119
120 p->sampling(png_get_x_pixels_per_meter(png_ptr, info_ptr),
121 png_get_y_pixels_per_meter(png_ptr, info_ptr), 1);
122 // p->image->origin(png_get_x_offset_pixels(png_ptr, info_ptr),
123 // png_get_y_offset_pixels(png_ptr, info_ptr), 0);
124 p->origin(png_get_x_offset_pixels(png_ptr, info_ptr),
125 png_get_y_offset_pixels(png_ptr, info_ptr), 0.0);
126
127 tm* t = p->get_localtime();
128 png_time* modtime;
129 png_get_tIME(png_ptr, info_ptr, &modtime);
130 // t->tm_year = modtime->year - 1900;
131 // t->tm_mon = modtime->month - 1;
132 // t->tm_mday = modtime->day;
133 // t->tm_hour = modtime->hour;
134 // t->tm_min = modtime->minute;
135 // t->tm_sec = modtime->second;puts("***");
136 p->set_time(t);
137
138 if ( readdata ) {
139 unsigned char* data = p->data_alloc();
140
141 png_bytep* row_pointers = new png_bytep[p->sizeY()];
142
143 // Row pointers are inverted with respect to y
144 int i, j;
145 for ( i=0, j=p->sizeY()-1; i<p->sizeY(); i++, j--, data += rowbytes )
146 row_pointers[j] = (png_bytep) data;
147
148 /* if ( verbose & VERB_DEBUG )
149 for ( i=0; i<p->sizeY(); i++ )
150 cout << "DEBUG readPNG: row_pointers[" << i << "]=" << static_cast<void*>(row_pointers[i]) << endl;
151 */
152 png_read_image(png_ptr, row_pointers);
153
154 // png_read_end(png_ptr, NULL);
155
156 delete[] row_pointers;
157 }
158
159 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
160
161 fclose(infile);
162
163 return 0;
164 }
165
173 int writePNG(Bimage* p)
174 {
175 if ( p->data_type() == SCharacter ) p->change_type(UCharacter);
176 if ( p->data_type() > UShort ) p->change_type(UShort);
177
178 /* could also replace libpng warning-handler (final NULL), but no need: */
179
180 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
181 if (!png_ptr) return -4; /* out of memory */
182
183 png_infop info_ptr = png_create_info_struct(png_ptr);
184 if ( !info_ptr ) {
185 png_destroy_write_struct(&png_ptr, NULL);
186 return -4; /* out of memory */
187 }
188
189 if ( setjmp(png_jmpbuf(png_ptr)) ) {
190 png_destroy_write_struct(&png_ptr, &info_ptr);
191 return -2;
192 }
193
194 FILE* outfile;
195 if ((outfile = fopen(p->file_name().c_str(), "wb")) == NULL) return -1;
196
197 /* make sure outfile is (re)opened in BINARY mode */
198 png_init_io(png_ptr, outfile);
199
200 /* set the compression levels--in general, always want to leave filtering
201 * turned on (except for palette images) and allow all of the filters,
202 * which is the default; want 32K zlib window, unless entire image buffer
203 * is 16K or smaller (unknown here)--also the default; usually want max
204 * compression (NOT the default); and remaining compression flags should
205 * be left alone */
206
207 png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
208 /*
209 >> this is default for no filtering; Z_FILTERED is default otherwise:
210 png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY);
211 >> these are all defaults:
212 png_set_compression_mem_level(png_ptr, 8);
213 png_set_compression_window_bits(png_ptr, 15);
214 png_set_compression_method(png_ptr, 8);
215 */
216
217
218 /* set the image parameters appropriately */
219 int color_type = PNG_COLOR_TYPE_GRAY;
220 switch ( p->compound_type() ) {
221 case TSimple: color_type = PNG_COLOR_TYPE_GRAY; break;
222 case TRGB: color_type = PNG_COLOR_TYPE_RGB; break;
223 case TRGBA: color_type = PNG_COLOR_TYPE_RGB_ALPHA; break;
224 default: color_type = PNG_COLOR_TYPE_GRAY; break;
225 }
226
227 int bit_depth = 8*p->data_type_size();
228
229 // interlace_type = mainprog_ptr->interlaced? PNG_INTERLACE_ADAM7 :
230 // PNG_INTERLACE_NONE;
231 int interlace_type = PNG_INTERLACE_NONE;
232
233 png_set_IHDR(png_ptr, info_ptr, p->sizeX(), p->sizeY(),
234 bit_depth, color_type, interlace_type,
235 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
236
237 tm* t = p->get_localtime();
238 png_time modtime;
239 png_convert_from_struct_tm(&modtime, t);
240 // png_convert_from_time_t(&modtime, p->time); // Converts to GM time
241 png_set_tIME(png_ptr, info_ptr, &modtime);
242 if ( verbose & VERB_DEBUG )
243 cout << "DEBUG writePNG: time=" << mktime(t) << endl;
244
245 /*
246 // if (mainprog_ptr->have_time) {
247 // png_time modtime;
248 //
249 // png_convert_from_time_t(&modtime, mainprog_ptr->modtime);
250 // png_set_tIME(png_ptr, info_ptr, &modtime);
251 // }
252
253 if (mainprog_ptr->have_text) {
254 png_text text[6];
255 int num_text = 0;
256
257 if (mainprog_ptr->have_text & TEXT_TITLE) {
258 text[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
259 text[num_text].key = "Title";
260 text[num_text].text = mainprog_ptr->title;
261 ++num_text;
262 }
263 if (mainprog_ptr->have_text & TEXT_AUTHOR) {
264 text[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
265 text[num_text].key = "Author";
266 text[num_text].text = mainprog_ptr->author;
267 ++num_text;
268 }
269 if (mainprog_ptr->have_text & TEXT_DESC) {
270 text[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
271 text[num_text].key = "Description";
272 text[num_text].text = mainprog_ptr->desc;
273 ++num_text;
274 }
275 if (mainprog_ptr->have_text & TEXT_COPY) {
276 text[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
277 text[num_text].key = "Copyright";
278 text[num_text].text = mainprog_ptr->copyright;
279 ++num_text;
280 }
281 if (mainprog_ptr->have_text & TEXT_EMAIL) {
282 text[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
283 text[num_text].key = "E-mail";
284 text[num_text].text = mainprog_ptr->email;
285 ++num_text;
286 }
287 if (mainprog_ptr->have_text & TEXT_URL) {
288 text[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
289 text[num_text].key = "URL";
290 text[num_text].text = mainprog_ptr->url;
291 ++num_text;
292 }
293 png_set_text(png_ptr, info_ptr, text, num_text);
294 }
295 */
296
297 /* if we wanted to write any more text info *after* the image data, we
298 * would set up text struct(s) here and call png_set_text() again, with
299 * just the new data; png_set_tIME() could also go here, but it would
300 * have no effect since we already called it above (only one tIME chunk
301 * allowed) */
302
303
304 // Optional significant bit (sBIT) chunk
305 /* png_color_8 sig_bit;
306
307 // If we are dealing with a grayscale image then
308 sig_bit.gray = bit_depth;
309
310 png_set_sBIT(png_ptr, info_ptr, &sig_bit);
311
312 png_set_shift(png_ptr, &sig_bit); // to scale low-bit-depth values
313 */
314
315 /* set up the transformations: for now, just pack low-bit-depth pixels
316 * into bytes (one, two or four pixels per byte) */
317 png_set_packing(png_ptr);
318
319 /* Optionally write comments into the image */
320 /* {
321 // png_infop write_info_ptr;
322 png_text text_ptr[1];
323
324 char key0[]="Title";
325 char text0[]=p->label();
326 text_ptr[0].key = key0;
327 text_ptr[0].text = text0;
328 text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
329 text_ptr[0].itxt_length = 0;
330 text_ptr[0].lang = NULL;
331 text_ptr[0].lang_key = NULL;
332
333 png_set_text(write_ptr, write_info_ptr, text_ptr, 1);
334 }*/
335
336 /* write all chunks up to (but not including) first IDAT */
337 png_write_info(png_ptr, info_ptr);
338
339 // Row pointers are inverted with respect to y
340 png_bytep* row_pointers = new png_bytep[p->sizeY()];
341
342 int i, j;
343 int rowbytes = p->sizeX()*p->channels()*p->data_type_size();
344 if ( verbose & VERB_DEBUG )
345 cout << "DEBUG writePNG: rowbytes=" << rowbytes << endl;
346
347 unsigned char* data = p->data_pointer();
348 if ( verbose & VERB_DEBUG )
349 cout << "DEBUG writePNG: data=" << static_cast<void*>(data) << endl;
350
351 for ( i=0, j=p->sizeY()-1; i<p->sizeY(); i++, j--, data += rowbytes )
352 row_pointers[j] = (png_bytep) data;
353
354 /* if ( verbose & VERB_DEBUG )
355 for ( i=0; i<p->sizeY(); i++ )
356 cout << "DEBUG writePNG: row_pointers[" << i << "]=" << static_cast<void*>(row_pointers[i]) << endl;
357 */
358 png_write_image(png_ptr, row_pointers);
359
360 png_write_end(png_ptr, NULL);
361
362 png_destroy_write_struct(&png_ptr, &info_ptr);
363
364 fclose(outfile);
365
366 delete[] row_pointers;
367
368 return 0;
369 }
370
371 #else
372
373 int readPNG(Bimage* p, int readdata)
374 {
375 cerr << "Error: PNG files are not supported!" << endl;
376
377 return -1;
378 }
379
380 int writePNG(Bimage* p)
381 {
382 cerr << "Error: PNG files are not supported!" << endl;
383
384 return -1;
385 }
386
387 #endif
Bimage::change_type
void change_type(char letter)
Get the data type indicated by a single letter code.
Definition: Bimage.cpp:1743
Bimage::sampling
Vector3< double > sampling()
Definition: Bimage.h:505
Bimage::data_type_size
long data_type_size() const
Returns the size of the datatype in bytes.
Definition: Bimage.cpp:1585
utilities.h
Header file for general utilities.
VERB_DEBUG
#define VERB_DEBUG
Definition: utilities.h:112
Bimage::compound_type
CompoundType compound_type()
Definition: Bimage.h:351
SCharacter
Definition: utilities.h:150
Bimage::file_name
void file_name(string s)
Definition: Bimage.h:230
rwPNG.h
Header file for reading and writing PNG files.
TSimple
Definition: Bimage.h:58
Bimage
General image parameter class.
Definition: Bimage.h:163
Bimage::data_alloc
unsigned char * data_alloc()
Definition: Bimage.h:256
Bimage::set_time
void set_time(time_t t)
Definition: Bimage.h:249
verbose
int verbose
Bimage::size
Vector3< long > size() const
Definition: Bimage.h:373
Bimage::get_localtime
tm * get_localtime()
Definition: Bimage.h:245
Bimage::channels
long channels()
Definition: Bimage.h:371
TRGB
Definition: Bimage.h:62
Bimage::data_pointer
unsigned char * data_pointer()
Definition: Bimage.h:261
UCharacter
Definition: utilities.h:149
Bimage::sizeX
void sizeX(long nx)
Definition: Bimage.h:377
Bit
Definition: utilities.h:148
readPNG
int readPNG(Bimage *p, int readdata)
Definition: rwPNG.cpp:373
TRGBA
Definition: Bimage.h:63
writePNG
int writePNG(Bimage *p)
Definition: rwPNG.cpp:380
UShort
Definition: utilities.h:151
Bimage::images
long images()
Definition: Bimage.h:491
Bimage::sizeY
void sizeY(long ny)
Definition: Bimage.h:378
Bimage::data_type
DataType data_type()
Definition: Bimage.h:349
Bimage::origin
void origin(double ox, double oy, double oz)
Definition: Bimage.h:563