41PngIO::PngIO(
const string & fname, IOMode 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)
69 bool is_new_file =
false;
70 file = sfopen(filename, rw_mode, &is_new_file,
true);
73 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
76 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
83 info_ptr = png_create_info_struct(png_ptr);
88 end_info = png_create_info_struct(png_ptr);
93 if (setjmp (png_jmpbuf (png_ptr))) {
97 png_init_io(png_ptr, 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)) {
106 png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK);
108 png_read_info(png_ptr, info_ptr);
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);
115 if (nx == 0 || ny == 0) {
119 if (bit_depth == CHAR_BIT) {
120 depth_type = PNG_CHAR_DEPTH;
122 else if (bit_depth == CHAR_BIT *
sizeof(
short)) {
123 depth_type = PNG_SHORT_DEPTH;
126 depth_type = PNG_INVALID_DEPTH;
128 sprintf(desc,
"not support png with depth = %d bit", bit_depth);
132 png_set_packing(png_ptr);
134 if ((color_type == PNG_COLOR_TYPE_GRAY) && (bit_depth < CHAR_BIT)) {
135 png_set_expand(png_ptr);
138 number_passes = png_set_interlace_handling(png_ptr);
140 if (bit_depth > CHAR_BIT) {
141 png_set_swap(png_ptr);
144 png_read_update_info(png_ptr, info_ptr);
149bool PngIO::is_valid(
const void *first_block)
158 if (png_sig_cmp((png_byte *) first_block, (png_size_t) 0, PNG_BYTES_TO_CHECK) == 0) {
166int PngIO::read_header(
Dict & dict,
int image_index,
const Region * area,
bool)
171 if (image_index == -1) {
175 if (image_index != 0) {
177 "no stack allowed for MRC image. For take 2D slice out of 3D image, read the 3D image first, then use get_clip().");
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;
187 EMUtil::get_region_dims(area, nx1, &xlen, ny1, &ylen);
193 if (depth_type == PNG_CHAR_DEPTH) {
194 dict[
"datatype"] = EMUtil::EM_UCHAR;
196 else if (depth_type == PNG_SHORT_DEPTH) {
197 dict[
"datatype"] = EMUtil::EM_USHORT;
207int PngIO::write_header(
const Dict & dict,
int image_index,
const Region*,
213 if(image_index == -1) {
216 if(image_index != 0) {
219 check_write_access(rw_mode, image_index);
221 nx = (png_uint_32) (
int) dict[
"nx"];
222 ny = (png_uint_32) (
int) dict[
"ny"];
225 LOGERR(
"Only support 2D PNG file write");
232 if (datatype == EMUtil::EM_UCHAR) {
233 depth_type = PNG_CHAR_DEPTH;
234 bit_depth = CHAR_BIT;
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));
242 depth_type = PNG_SHORT_DEPTH;
243 bit_depth =
sizeof(
unsigned short) * CHAR_BIT;
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);
249 png_write_info(png_ptr, info_ptr);
251 if (depth_type == PNG_SHORT_DEPTH) {
252 png_set_swap(png_ptr);
255 EMUtil::getRenderLimits(dict, rendermin, rendermax, renderbits);
267 check_read_access(image_index, data);
271 int nx1 =
static_cast < int >(nx);
272 int ny1 =
static_cast < int >(ny);
274 check_region(area,
IntSize(nx1, ny1));
276 png_init_io(png_ptr, file);
277 png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK);
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);
284 int color_type = png_get_color_type(png_ptr, info_ptr);
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);
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;
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);
305 if (depth_type == PNG_CHAR_DEPTH) {
307 for (
int x = x0*clrmlt;
x < x0*clrmlt + xlen*clrmlt;
x+=clrmlt) {
309 for (
int ri=0; ri<3; ri++) d+=static_cast < float >(cdata[
x+ri]);
315 for (
int x = x0;
x < x0 + xlen;
x++) {
316 data[k] =
static_cast < float >(cdata[
x]);
321 else if (depth_type == PNG_SHORT_DEPTH) {
324 for (
int x = x0*clrmlt;
x < x0*clrmlt + xlen*clrmlt;
x+=clrmlt) {
326 for (
int ri=0; ri<3; ri++) d+=static_cast < float >(sdata[
x+ri]);
332 for (
int x = x0;
x < x0 + xlen;
x++) {
333 data[k] =
static_cast < float >(sdata[
x]);
342 Util::flip_image(data, nx, ny);
350 png_read_end(png_ptr, end_info);
351 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
363 check_write_access(rw_mode, image_index, 1, data);
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;
372 EMUtil::getRenderMinMax(data, nx, ny, rendermin, rendermax, renderbits);
378 if (depth_type == PNG_CHAR_DEPTH) {
379 unsigned char *cdata =
new unsigned char[nx];
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){
386 else if(data[
y * nx +
x] >= rendermax) {
387 cdata[
x] = UCHAR_MAX;
390 cdata[
x] = (
unsigned char)((data[
y * nx +
x] - rendermin) /
391 (rendermax - rendermin) * 256);
394 png_write_row(png_ptr, (png_byte *) cdata);
403 else if (depth_type == PNG_SHORT_DEPTH) {
404 unsigned short *sdata =
new unsigned short[nx];
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){
411 else if(data[
y * nx +
x] >= rendermax) {
412 sdata[
x] = USHRT_MAX;
415 sdata[
x] = (
unsigned short)((data[
y * nx +
x] - rendermin) /
416 (rendermax - rendermin) * 65536);
420 png_write_row(png_ptr, (png_byte *) sdata);
430 png_write_end(png_ptr, info_ptr);
431 png_destroy_write_struct(&png_ptr, &info_ptr);
439 png_write_flush(png_ptr);
442bool PngIO::is_complex_mode()
447bool PngIO::is_image_big_endian()
Dict is a dictionary to store <string, EMObject> pair.
EMDataType
Image pixel data type used in EMAN.
ImageIO classes are designed for reading/writing various electron micrography image formats,...
IntSize is used to describe a 1D, 2D or 3D rectangular size in integers.
Region defines a 2D or 3D rectangular region specified by its origin coordinates and all edges' sizes...
#define ImageReadException(filename, desc)
#define ImageWriteException(imagename, desc)