EMAN2
pngio.cpp
Go to the documentation of this file.
1/*
2 * Author: Steven Ludtke, 04/10/2003 (sludtke@bcm.edu)
3 * Copyright (c) 2000-2006 Baylor College of Medicine
4 *
5 * This software is issued under a joint BSD/GNU license. You may use the
6 * source code in this file under either license. However, note that the
7 * complete EMAN2 and SPARX software packages have some GPL dependencies,
8 * so you are responsible for compliance with the licenses of these packages
9 * if you opt to use BSD licensing. The warranty disclaimer below holds
10 * in either instance.
11 *
12 * This complete copyright notice must be included in any revised version of the
13 * source code. Additional authorship citations may be added, but existing
14 * author citations must be preserved.
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 *
30 * */
31
32#ifdef USE_PNG
33
34#include <climits>
35#include "pngio.h"
36#include "geometry.h"
37#include "util.h"
38
39using namespace EMAN;
40
41PngIO::PngIO(const string & fname, IOMode rw)
42: ImageIO(fname, rw),
43 png_ptr(0), info_ptr(0), end_info(0), nx(0), ny(0),
44 depth_type(PNG_INVALID_DEPTH), number_passes(0),
45 rendermin(0.0), rendermax(0.0), renderbits(16)
46{}
47
48PngIO::~PngIO()
49{
50 if (file) {
51 fclose(file);
52 file = 0;
53 }
54
55 png_ptr = 0;
56 info_ptr = 0;
57 end_info = 0;
58}
59
60void PngIO::init()
61{
63 if (initialized) {
64 return;
65 }
66
67 initialized = true;
68
69 bool is_new_file = false;
70 file = sfopen(filename, rw_mode, &is_new_file, true);
71
72 if (!is_new_file) {
73 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
74 }
75 else {
76 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
77 }
78
79 if (!png_ptr) {
80 throw ImageReadException(filename, "cannot initialize libpng data structure");
81 }
82
83 info_ptr = png_create_info_struct(png_ptr);
84 if (!info_ptr) {
85 throw ImageReadException(filename, "cannot create png info data structure");
86 }
87
88 end_info = png_create_info_struct(png_ptr);
89 if (!end_info) {
90 throw ImageReadException(filename, "cannot create png end info structure");
91 }
92
93 if (setjmp (png_jmpbuf (png_ptr))) {
94 throw ImageReadException(filename, "an error occurs within png");
95 }
96
97 png_init_io(png_ptr, file);
98
99 if (!is_new_file) {
100 unsigned char header[PNG_BYTES_TO_CHECK];
101 fread(header, sizeof(unsigned char), PNG_BYTES_TO_CHECK, file);
102 if (!is_valid(header)) {
103 throw ImageReadException(filename, "invalid PNG format");
104 }
105
106 png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK);
107
108 png_read_info(png_ptr, info_ptr);
109
110 nx = png_get_image_width(png_ptr, info_ptr);
111 ny = png_get_image_height(png_ptr, info_ptr);
112 int bit_depth = png_get_bit_depth(png_ptr, info_ptr);
113 int color_type = png_get_color_type(png_ptr, info_ptr);
114
115 if (nx == 0 || ny == 0) {
116 throw ImageReadException(filename, "PNG file size = 0");
117 }
118
119 if (bit_depth == CHAR_BIT) {
120 depth_type = PNG_CHAR_DEPTH;
121 }
122 else if (bit_depth == CHAR_BIT * sizeof(short)) {
123 depth_type = PNG_SHORT_DEPTH;
124 }
125 else {
126 depth_type = PNG_INVALID_DEPTH;
127 char desc[256];
128 sprintf(desc, "not support png with depth = %d bit", bit_depth);
129 throw ImageReadException(filename, desc);
130 }
131
132 png_set_packing(png_ptr);
133
134 if ((color_type == PNG_COLOR_TYPE_GRAY) && (bit_depth < CHAR_BIT)) {
135 png_set_expand(png_ptr);
136 }
137
138 number_passes = png_set_interlace_handling(png_ptr);
139
140 if (bit_depth > CHAR_BIT) {
141 png_set_swap(png_ptr);
142 }
143
144 png_read_update_info(png_ptr, info_ptr);
145 }
146 EXITFUNC;
147}
148
149bool PngIO::is_valid(const void *first_block)
150{
151 ENTERFUNC;
152 bool result = false;
153
154 if (!first_block) {
155 result = false;
156 }
157 else {
158 if (png_sig_cmp((png_byte *) first_block, (png_size_t) 0, PNG_BYTES_TO_CHECK) == 0) {
159 result = true;
160 }
161 }
162 EXITFUNC;
163 return result;
164}
165
166int PngIO::read_header(Dict & dict, int image_index, const Region * area, bool)
167{
168 ENTERFUNC;
169
170 // single image format, index can only be zero
171 if (image_index == -1) {
172 image_index = 0;
173 }
174
175 if (image_index != 0) {
176 throw ImageReadException(filename,
177 "no stack allowed for MRC image. For take 2D slice out of 3D image, read the 3D image first, then use get_clip().");
178 }
179
180 init();
181
182 int nx1 = static_cast < int >(nx);
183 int ny1 = static_cast < int >(ny);
184 check_region(area, IntSize(nx1, ny1));
185 int xlen = 0, ylen = 0;
186
187 EMUtil::get_region_dims(area, nx1, &xlen, ny1, &ylen);
188
189 dict["nx"] = xlen;
190 dict["ny"] = ylen;
191 dict["nz"] = 1;
192
193 if (depth_type == PNG_CHAR_DEPTH) {
194 dict["datatype"] = EMUtil::EM_UCHAR;
195 }
196 else if (depth_type == PNG_SHORT_DEPTH) {
197 dict["datatype"] = EMUtil::EM_USHORT;
198 }
199 else {
200 throw ImageReadException(filename, "unsupported PNG bit depth");
201 }
202
203 EXITFUNC;
204 return 0;
205}
206
207int PngIO::write_header(const Dict & dict, int image_index, const Region*,
208 EMUtil::EMDataType, bool)
209{
210 ENTERFUNC;
211
212 //single image format, index can only be zero
213 if(image_index == -1) {
214 image_index = 0;
215 }
216 if(image_index != 0) {
217 throw ImageWriteException(filename, "PNG file does not support stack.");
218 }
219 check_write_access(rw_mode, image_index);
220
221 nx = (png_uint_32) (int) dict["nx"];
222 ny = (png_uint_32) (int) dict["ny"];
223 int nz = dict["nz"];
224 if (nz != 1) {
225 LOGERR("Only support 2D PNG file write");
226 return 1;
227 }
228
229 int bit_depth = 0;
230 EMUtil::EMDataType datatype = (EMUtil::EMDataType) (int) dict["datatype"];
231
232 if (datatype == EMUtil::EM_UCHAR) {
233 depth_type = PNG_CHAR_DEPTH;
234 bit_depth = CHAR_BIT;
235 }
236 else {
237 if (datatype != EMUtil::EM_USHORT) {
238 LOGWARN("Don't support data type '%s' in PNG. Convert to '%s'.",
239 EMUtil::get_datatype_string(datatype),
240 EMUtil::get_datatype_string(EMUtil::EM_USHORT));
241 }
242 depth_type = PNG_SHORT_DEPTH;
243 bit_depth = sizeof(unsigned short) * CHAR_BIT;
244 }
245
246 png_set_IHDR(png_ptr, info_ptr, nx, ny, bit_depth, PNG_COLOR_TYPE_GRAY,
247 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
248
249 png_write_info(png_ptr, info_ptr);
250
251 if (depth_type == PNG_SHORT_DEPTH) {
252 png_set_swap(png_ptr);
253 }
254
255 EMUtil::getRenderLimits(dict, rendermin, rendermax, renderbits);
256
257 EXITFUNC;
258 return 0;
259}
260
261int PngIO::read_data(float *data, int image_index, const Region * area, bool)
262{
263 ENTERFUNC;
264
265 //single image format, index can only be zero
266 image_index = 0;
267 check_read_access(image_index, data);
268
269
270
271 int nx1 = static_cast < int >(nx);
272 int ny1 = static_cast < int >(ny);
273
274 check_region(area, IntSize(nx1, ny1));
275
276 png_init_io(png_ptr, file);
277 png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK);
278
279 int xlen = 0, ylen = 0, x0 = 0, y0 = 0;
280 EMUtil::get_region_dims(area, nx1, &xlen, ny1, &ylen);
281 EMUtil::get_region_origins(area, &x0, &y0);
282
283 // Deal with RGB image reading...
284 int color_type = png_get_color_type(png_ptr, info_ptr);
285 //printf("color type: %d, %d\n", color_type, depth_type);
286 int clrmlt=1;
287 if (color_type!=PNG_COLOR_TYPE_GRAY){
288 printf("Reading RGB image as gray scale image...\n");
289 if (color_type==PNG_COLOR_TYPE_RGB) clrmlt=3;
290 else if (color_type==PNG_COLOR_TYPE_RGB_ALPHA) clrmlt=4;
291 else printf("Unrecognized PNG color type %d\n",color_type);
292
293 }
294
295 png_uint_32 rowbytes = png_get_rowbytes(png_ptr, info_ptr);
296 unsigned char *cdata = new unsigned char[rowbytes];
297 unsigned short *sdata = (unsigned short *) cdata;
298
299 int k = 0;
300 for (int i = y0; i < y0 + ylen; i++) {
301 for (int pass = 0; pass < number_passes; pass++) {
302 png_read_rows(png_ptr, (png_byte **) & cdata, 0, 1);
303 }
304
305 if (depth_type == PNG_CHAR_DEPTH) {
306 if (clrmlt>1){
307 for (int x = x0*clrmlt; x < x0*clrmlt + xlen*clrmlt; x+=clrmlt) {
308 float d=0;
309 for (int ri=0; ri<3; ri++) d+=static_cast < float >(cdata[x+ri]);
310 data[k] = d/3.;
311 k++;
312 }
313 }
314 else{
315 for (int x = x0; x < x0 + xlen; x++) {
316 data[k] = static_cast < float >(cdata[x]);
317 k++;
318 }
319 }
320 }
321 else if (depth_type == PNG_SHORT_DEPTH) {
322
323 if (clrmlt>1){
324 for (int x = x0*clrmlt; x < x0*clrmlt + xlen*clrmlt; x+=clrmlt) {
325 float d=0;
326 for (int ri=0; ri<3; ri++) d+=static_cast < float >(sdata[x+ri]);
327 data[k] = d/3.;
328 k++;
329 }
330 }
331 else{
332 for (int x = x0; x < x0 + xlen; x++) {
333 data[k] = static_cast < float >(sdata[x]);
334 k++;
335 }
336 }
337 }
338 }
339
342 Util::flip_image(data, nx, ny);
343
344 if( cdata )
345 {
346 delete[]cdata;
347 cdata = 0;
348 }
349
350 png_read_end(png_ptr, end_info);
351 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
352 EXITFUNC;
353 return 0;
354}
355
356int PngIO::write_data(float *data, int image_index, const Region*,
357 EMUtil::EMDataType, bool)
358{
359 ENTERFUNC;
360
361 //single image format, index can only be zero
362 image_index = 0;
363 check_write_access(rw_mode, image_index, 1, data);
364
365 // If we didn't get any parameters in 'render_min' or 'render_max',
366 // we need to find some good ones
367 int truebits=0;
368 if (depth_type==PNG_CHAR_DEPTH) truebits=8;
369 else if (depth_type=PNG_SHORT_DEPTH) truebits=16;
370 if (renderbits==0 || renderbits>truebits) renderbits=truebits;
371
372 EMUtil::getRenderMinMax(data, nx, ny, rendermin, rendermax, renderbits);
373
374// printf("render %f %f \n",rendermin,rendermax);
375
378 if (depth_type == PNG_CHAR_DEPTH) {
379 unsigned char *cdata = new unsigned char[nx];
380
381 for (int y = (int)ny-1; y >= 0; y--) {
382 for (int x = 0; x < (int)nx; x++) {
383 if(data[y * nx + x] <= rendermin){
384 cdata[x] = 0;
385 }
386 else if(data[y * nx + x] >= rendermax) {
387 cdata[x] = UCHAR_MAX;
388 }
389 else {
390 cdata[x] = (unsigned char)((data[y * nx + x] - rendermin) /
391 (rendermax - rendermin) * 256);
392 }
393 }
394 png_write_row(png_ptr, (png_byte *) cdata);
395 }
396
397 if( cdata )
398 {
399 delete[]cdata;
400 cdata = 0;
401 }
402 }
403 else if (depth_type == PNG_SHORT_DEPTH) {
404 unsigned short *sdata = new unsigned short[nx];
405
406 for (int y = (int)ny-1; y >= 0 ; y--) {
407 for (int x = 0; x < (int)nx; x++) {
408 if(data[y * nx + x] <= rendermin){
409 sdata[x] = 0;
410 }
411 else if(data[y * nx + x] >= rendermax) {
412 sdata[x] = USHRT_MAX;
413 }
414 else {
415 sdata[x] = (unsigned short)((data[y * nx + x] - rendermin) /
416 (rendermax - rendermin) * 65536);
417 }
418 }
419
420 png_write_row(png_ptr, (png_byte *) sdata);
421 }
422
423 if( sdata )
424 {
425 delete[]sdata;
426 sdata = 0;
427 }
428 }
429
430 png_write_end(png_ptr, info_ptr);
431 png_destroy_write_struct(&png_ptr, &info_ptr);
432
433 EXITFUNC;
434 return 0;
435}
436
437void PngIO::flush()
438{
439 png_write_flush(png_ptr);
440}
441
442bool PngIO::is_complex_mode()
443{
444 return false;
445}
446
447bool PngIO::is_image_big_endian()
448{
449 return true;
450}
451
452#endif //USE_PNG
Dict is a dictionary to store <string, EMObject> pair.
Definition: emobject.h:385
EMDataType
Image pixel data type used in EMAN.
Definition: emutil.h:92
ImageIO classes are designed for reading/writing various electron micrography image formats,...
Definition: imageio.h:127
IntSize is used to describe a 1D, 2D or 3D rectangular size in integers.
Definition: geometry.h:49
Region defines a 2D or 3D rectangular region specified by its origin coordinates and all edges' sizes...
Definition: geometry.h:497
void read_data(string fsp, size_t loc, const Region *area=0, const int file_nx=0, const int file_ny=0, const int file_nz=0)
Read the image pixel data in native byte order from a disk file.
void write_data(string fsp, size_t loc, const Region *const area=0, const int file_nx=0, const int file_ny=0, const int file_nz=0)
Dump the image pixel data in native byte order to a disk file.
#define ImageReadException(filename, desc)
Definition: exception.h:204
#define ImageWriteException(imagename, desc)
Definition: exception.h:223
#define LOGWARN
Definition: log.h:53
#define LOGERR
Definition: log.h:51
#define ENTERFUNC
Definition: log.h:48
#define EXITFUNC
Definition: log.h:49
E2Exception class.
Definition: aligner.h:40
#define y(i, j)
Definition: projector.cpp:1516
#define x(i)
Definition: projector.cpp:1517