Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

pngio.cpp

Go to the documentation of this file.
00001 
00005 /*
00006  * Author: Steven Ludtke, 04/10/2003 (sludtke@bcm.edu)
00007  * Copyright (c) 2000-2006 Baylor College of Medicine
00008  *
00009  * This software is issued under a joint BSD/GNU license. You may use the
00010  * source code in this file under either license. However, note that the
00011  * complete EMAN2 and SPARX software packages have some GPL dependencies,
00012  * so you are responsible for compliance with the licenses of these packages
00013  * if you opt to use BSD licensing. The warranty disclaimer below holds
00014  * in either instance.
00015  *
00016  * This complete copyright notice must be included in any revised version of the
00017  * source code. Additional authorship citations may be added, but existing
00018  * author citations must be preserved.
00019  *
00020  * This program is free software; you can redistribute it and/or modify
00021  * it under the terms of the GNU General Public License as published by
00022  * the Free Software Foundation; either version 2 of the License, or
00023  * (at your option) any later version.
00024  *
00025  * This program is distributed in the hope that it will be useful,
00026  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00027  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00028  * GNU General Public License for more details.
00029  *
00030  * You should have received a copy of the GNU General Public License
00031  * along with this program; if not, write to the Free Software
00032  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00033  *
00034  * */
00035 
00036 #ifdef EM_PNG
00037 
00038 #include <climits>
00039 #include "pngio.h"
00040 #include "geometry.h"
00041 #include "util.h"
00042 
00043 
00044 using namespace EMAN;
00045 
00046 PngIO::PngIO(const string & file, IOMode rw)
00047 :       filename(file), rw_mode(rw), png_file(0), initialized(false),
00048         png_ptr(0), info_ptr(0), end_info(0), nx(0), ny(0),
00049         depth_type(PNG_INVALID_DEPTH), number_passes(0), rendermin(0), rendermax(0)
00050 {}
00051 
00052 PngIO::~PngIO()
00053 {
00054         if (png_file) {
00055                 fclose(png_file);
00056                 png_file = 0;
00057         }
00058 
00059         png_ptr = 0;
00060         info_ptr = 0;
00061         end_info = 0;
00062 }
00063 
00064 void PngIO::init()
00065 {
00066         ENTERFUNC;
00067         if (initialized) {
00068                 return;
00069         }
00070 
00071         initialized = true;
00072 
00073         bool is_new_file = false;
00074         png_file = sfopen(filename, rw_mode, &is_new_file, true);
00075 
00076         if (!is_new_file) {
00077                 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
00078         }
00079         else {
00080                 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
00081         }
00082 
00083         if (!png_ptr) {
00084                 throw ImageReadException(filename, "cannot initialize libpng data structure");
00085         }
00086 
00087         info_ptr = png_create_info_struct(png_ptr);
00088         if (!info_ptr) {
00089                 throw ImageReadException(filename, "cannot create png info data structure");
00090         }
00091 
00092         end_info = png_create_info_struct(png_ptr);
00093         if (!end_info) {
00094                 throw ImageReadException(filename, "cannot create png end info structure");
00095         }
00096 
00097         if (setjmp (png_jmpbuf (png_ptr))) {
00098                 throw ImageReadException(filename, "an error occurs within png");
00099         }
00100 
00101         png_init_io(png_ptr, png_file);
00102 
00103         if (!is_new_file) {
00104                 unsigned char header[PNG_BYTES_TO_CHECK];
00105                 fread(header, sizeof(unsigned char), PNG_BYTES_TO_CHECK, png_file);
00106                 if (!is_valid(header)) {
00107                         throw ImageReadException(filename, "invalid PNG format");
00108                 }
00109 
00110                 png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK);
00111 
00112                 png_read_info(png_ptr, info_ptr);
00113 
00114                 nx = png_get_image_width(png_ptr, info_ptr);
00115                 ny = png_get_image_height(png_ptr, info_ptr);
00116                 int bit_depth = png_get_bit_depth(png_ptr, info_ptr);
00117                 int color_type = png_get_color_type(png_ptr, info_ptr);
00118 
00119                 if (nx == 0 || ny == 0) {
00120                         throw ImageReadException(filename, "PNG file size = 0");
00121                 }
00122 
00123                 if (bit_depth == CHAR_BIT) {
00124                         depth_type = PNG_CHAR_DEPTH;
00125                 }
00126                 else if (bit_depth == CHAR_BIT * sizeof(short)) {
00127                         depth_type = PNG_SHORT_DEPTH;
00128                 }
00129                 else {
00130                         depth_type = PNG_INVALID_DEPTH;
00131                         char desc[256];
00132                         sprintf(desc, "not support png with depth = %d bit", bit_depth);
00133                         throw ImageReadException(filename, desc);
00134                 }
00135 
00136                 png_set_packing(png_ptr);
00137 
00138                 if ((color_type == PNG_COLOR_TYPE_GRAY) && (bit_depth < CHAR_BIT)) {
00139                         png_set_expand(png_ptr);
00140                 }
00141 
00142                 number_passes = png_set_interlace_handling(png_ptr);
00143 
00144                 if (bit_depth > CHAR_BIT) {
00145                         png_set_swap(png_ptr);
00146                 }
00147 
00148                 png_read_update_info(png_ptr, info_ptr);
00149         }
00150         EXITFUNC;
00151 }
00152 
00153 bool PngIO::is_valid(const void *first_block)
00154 {
00155         ENTERFUNC;
00156         bool result = false;
00157 
00158         if (!first_block) {
00159                 result = false;
00160         }
00161         else {
00162                 if (png_sig_cmp((png_byte *) first_block, (png_size_t) 0, PNG_BYTES_TO_CHECK) == 0) {
00163                         result = true;
00164                 }
00165         }
00166         EXITFUNC;
00167         return result;
00168 }
00169 
00170 int PngIO::read_header(Dict & dict, int image_index, const Region * area, bool)
00171 {
00172         ENTERFUNC;
00173 
00174         //single image format, index can only be zero
00175         if(image_index == -1) {
00176                 image_index = 0;
00177         }
00178 
00179         if(image_index != 0) {
00180                 throw ImageReadException(filename, "no stack allowed for MRC image. For take 2D slice out of 3D image, read the 3D image first, then use get_clip().");
00181         }
00182 
00183         init();
00184 
00185         int nx1 = static_cast < int >(nx);
00186         int ny1 = static_cast < int >(ny);
00187         check_region(area, IntSize(nx1, ny1));
00188         int xlen = 0, ylen = 0;
00189         EMUtil::get_region_dims(area, nx1, &xlen, ny1, &ylen);
00190 
00191         dict["nx"] = xlen;
00192         dict["ny"] = ylen;
00193         dict["nz"] = 1;
00194 
00195         if (depth_type == PNG_CHAR_DEPTH) {
00196                 dict["datatype"] = EMUtil::EM_UCHAR;
00197         }
00198         else if (depth_type == PNG_SHORT_DEPTH) {
00199                 dict["datatype"] = EMUtil::EM_USHORT;
00200         }
00201         else {
00202                 throw ImageReadException(filename, "unsupported PNG bit depth");
00203         }
00204 
00205         EXITFUNC;
00206         return 0;
00207 }
00208 
00209 int PngIO::write_header(const Dict & dict, int image_index, const Region*,
00210                                                 EMUtil::EMDataType, bool)
00211 {
00212         ENTERFUNC;
00213 
00214         //single image format, index can only be zero
00215         if(image_index == -1) {
00216                 image_index = 0;
00217         }
00218         if(image_index != 0) {
00219                 throw ImageWriteException(filename, "PNG file does not support stack.");
00220         }
00221         check_write_access(rw_mode, image_index);
00222 
00223         nx = (png_uint_32) (int) dict["nx"];
00224         ny = (png_uint_32) (int) dict["ny"];
00225         int nz = dict["nz"];
00226         if (nz != 1) {
00227                 LOGERR("Only support 2D PNG file write");
00228                 return 1;
00229         }
00230 
00231         int bit_depth = 0;
00232         EMUtil::EMDataType datatype = (EMUtil::EMDataType) (int) dict["datatype"];
00233 
00234         if (datatype == EMUtil::EM_UCHAR) {
00235                 depth_type = PNG_CHAR_DEPTH;
00236                 bit_depth = CHAR_BIT;
00237         }
00238         else {
00239                 if (datatype != EMUtil::EM_USHORT) {
00240                         LOGWARN("Don't support data type '%s' in PNG. Convert to '%s'.",
00241                                         EMUtil::get_datatype_string(datatype),
00242                                         EMUtil::get_datatype_string(EMUtil::EM_USHORT));
00243                 }
00244                 depth_type = PNG_SHORT_DEPTH;
00245                 bit_depth = sizeof(unsigned short) * CHAR_BIT;
00246         }
00247 
00248         png_set_IHDR(png_ptr, info_ptr, nx, ny, bit_depth, PNG_COLOR_TYPE_GRAY,
00249                                  PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
00250 
00251         png_write_info(png_ptr, info_ptr);
00252 
00253         if (depth_type == PNG_SHORT_DEPTH) {
00254                 png_set_swap(png_ptr);
00255         }
00256 
00257         if(dict.has_key("render_min")) rendermin=(float)dict["render_min"];
00258         else rendermin=0;
00259         if(dict.has_key("render_max")) rendermax=(float)dict["render_max"];
00260         else rendermax=0;
00261         EXITFUNC;
00262         return 0;
00263 }
00264 
00265 int PngIO::read_data(float *data, int image_index, const Region * area, bool)
00266 {
00267         ENTERFUNC;
00268 
00269         //single image format, index can only be zero
00270         image_index = 0;
00271         check_read_access(image_index, data);
00272 
00273         int nx1 = static_cast < int >(nx);
00274         int ny1 = static_cast < int >(ny);
00275 
00276         check_region(area, IntSize(nx1, ny1));
00277 
00278         png_init_io(png_ptr, png_file);
00279         png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK);
00280 
00281         int xlen = 0, ylen = 0, x0 = 0, y0 = 0;
00282         EMUtil::get_region_dims(area, nx1, &xlen, ny1, &ylen);
00283         EMUtil::get_region_origins(area, &x0, &y0);
00284 
00285         png_uint_32 rowbytes = png_get_rowbytes(png_ptr, info_ptr);
00286         unsigned char *cdata = new unsigned char[rowbytes];
00287         unsigned short *sdata = (unsigned short *) cdata;
00288 
00289         int k = 0;
00290         for (int i = y0; i < y0 + ylen; i++) {
00291                 for (int pass = 0; pass < number_passes; pass++) {
00292                         png_read_rows(png_ptr, (png_byte **) & cdata, 0, 1);
00293                 }
00294 
00295                 if (depth_type == PNG_CHAR_DEPTH) {
00296                         for (int x = x0; x < x0 + xlen; x++) {
00297                                 data[k] = static_cast < float >(cdata[x]);
00298                                 k++;
00299                         }
00300                 }
00301                 else if (depth_type == PNG_SHORT_DEPTH) {
00302                         for (int x = x0; x < x0 + xlen; x++) {
00303                                 data[k] = static_cast < float >(sdata[x]);
00304                                 k++;
00305                         }
00306                 }
00307         }
00308 
00311         Util::flip_image(data, nx, ny);
00312 
00313         if( cdata )
00314         {
00315                 delete[]cdata;
00316                 cdata = 0;
00317         }
00318 
00319         png_read_end(png_ptr, end_info);
00320         png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
00321         EXITFUNC;
00322         return 0;
00323 }
00324 
00325 int PngIO::write_data(float *data, int image_index, const Region*,
00326                                           EMUtil::EMDataType, bool)
00327 {
00328         ENTERFUNC;
00329 
00330         //single image format, index can only be zero
00331         image_index = 0;
00332         check_write_access(rw_mode, image_index, 1, data);
00333 
00334         // If we didn't get any parameters in 'render_min' or 'render_max', we need to find some good ones
00335         if (!rendermin && !rendermax) EMUtil::getRenderMinMax(data, nx, ny, rendermin, rendermax);
00336 
00339         if (depth_type == PNG_CHAR_DEPTH) {
00340                 unsigned char *cdata = new unsigned char[nx];
00341 
00342                 for (int y = (int)ny-1; y >= 0; y--) {
00343                         for (int x = 0; x < (int)nx; x++) {
00344                                 if(data[y * nx + x] <= rendermin){
00345                                         cdata[x] = 0;
00346                                 }
00347                                 else if(data[y * nx + x] >= rendermax) {
00348                                         cdata[x] = UCHAR_MAX;
00349                                 }
00350                                 else {
00351                                         cdata[x] = (unsigned char)((data[y * nx + x] - rendermin) / (rendermax - rendermin) * 256);
00352                                 }
00353                         }
00354                         png_write_row(png_ptr, (png_byte *) cdata);
00355                 }
00356 
00357                 if( cdata )
00358                 {
00359                         delete[]cdata;
00360                         cdata = 0;
00361                 }
00362         }
00363         else if (depth_type == PNG_SHORT_DEPTH) {
00364                 unsigned short *sdata = new unsigned short[nx];
00365 
00366                 for (int y = (int)ny-1; y >= 0 ; y--) {
00367                         for (int x = 0; x < (int)nx; x++) {
00368                                 if(data[y * nx + x] <= rendermin){
00369                                         sdata[x] = 0;
00370                                 }
00371                                 else if(data[y * nx + x] >= rendermax) {
00372                                         sdata[x] = USHRT_MAX;
00373                                 }
00374                                 else {
00375                                         sdata[x] = (unsigned short)((data[y * nx + x] - rendermin) / (rendermax - rendermin) * 65536);
00376                                 }
00377                         }
00378 
00379                         png_write_row(png_ptr, (png_byte *) sdata);
00380                 }
00381 
00382                 if( sdata )
00383                 {
00384                         delete[]sdata;
00385                         sdata = 0;
00386                 }
00387         }
00388 
00389         png_write_end(png_ptr, info_ptr);
00390         png_destroy_write_struct(&png_ptr, &info_ptr);
00391 
00392         EXITFUNC;
00393         return 0;
00394 }
00395 
00396 void PngIO::flush()
00397 {
00398         png_write_flush(png_ptr);
00399 }
00400 
00401 bool PngIO::is_complex_mode()
00402 {
00403         return false;
00404 }
00405 
00406 bool PngIO::is_image_big_endian()
00407 {
00408         return true;
00409 }
00410 
00411 
00412 #endif  //EM_PNG

Generated on Tue Jun 11 13:46:16 2013 for EMAN2 by  doxygen 1.3.9.1