00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include "pgmio.h"
00037 #include "geometry.h"
00038 #include "util.h"
00039 #include "portable_fileio.h"
00040
00041 #ifdef _WIN32
00042
00043
00044 #include <cfloat>
00045 #endif
00046
00047 using namespace EMAN;
00048
00049 const char *PgmIO::MAGIC_BINARY = "P5";
00050 const char *PgmIO::MAGIC_ASCII = "P2";
00051
00052 PgmIO::PgmIO(const string & file, IOMode rw)
00053 : filename(file), rw_mode(rw), pgm_file(0), is_big_endian(true),
00054 initialized(false), nx(0), ny(0), maxval(0), minval(0),
00055 file_offset(0), rendermin(0), rendermax(0)
00056 {}
00057
00058 PgmIO::~PgmIO()
00059 {
00060 if (pgm_file) {
00061 fclose(pgm_file);
00062 pgm_file = 0;
00063 }
00064 }
00065
00066
00067 namespace
00068 {
00069 int read_int_and_space(FILE * in)
00070 {
00071 char buf[32];
00072 int c = 0;
00073
00074 int i = 0;
00075 while (!isspace(c = getc(in))) {
00076 buf[i] = static_cast < char >(c);
00077 i++;
00078 }
00079
00080 return atoi(buf);
00081 }
00082 }
00083
00084 void PgmIO::init()
00085 {
00086 ENTERFUNC;
00087
00088 if (initialized) {
00089 return;
00090 }
00091
00092 initialized = true;
00093
00094 bool is_new_file = false;
00095 pgm_file = sfopen(filename, rw_mode, &is_new_file, true);
00096
00097 if (!is_new_file) {
00098 const int bufsz = 1024;
00099 char buf[bufsz];
00100
00101 buf[0] = static_cast < char >(getc(pgm_file));
00102 buf[1] = static_cast < char >(getc(pgm_file));
00103 buf[2] = '\0';
00104 getc(pgm_file);
00105
00106 if (!is_valid(&buf)) {
00107 throw ImageReadException(filename, "invalid PGM file");
00108 }
00109
00110 char c = '\0';
00111
00112 while ((c = static_cast < char >(getc(pgm_file))) == '#') {
00113 fgets(buf, bufsz, pgm_file);
00114 }
00115 ungetc(c, pgm_file);
00116
00117 nx = read_int_and_space(pgm_file);
00118 ny = read_int_and_space(pgm_file);
00119 maxval = read_int_and_space(pgm_file);
00120
00121 if (nx <= 0 || ny <= 0) {
00122 throw ImageReadException(filename, "file size < 0");
00123 }
00124
00125 file_offset = portable_ftell(pgm_file);
00126 }
00127 EXITFUNC;
00128 }
00129
00130 bool PgmIO::is_valid(const void *first_block)
00131 {
00132 ENTERFUNC;
00133 bool result = false;
00134 if (first_block) {
00135 result = Util::check_file_by_magic(first_block, MAGIC_BINARY);
00136 }
00137 EXITFUNC;
00138 return result;
00139 }
00140
00141 int PgmIO::read_header(Dict & dict, int image_index, const Region * area, bool)
00142 {
00143 ENTERFUNC;
00144
00145
00146 if(image_index == -1) {
00147 image_index = 0;
00148 }
00149
00150 if(image_index != 0) {
00151 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().");
00152 }
00153
00154 init();
00155
00156 check_read_access(image_index);
00157 check_region(area, IntSize(nx, ny));
00158 int xlen = 0, ylen = 0;
00159 EMUtil::get_region_dims(area, nx, &xlen, ny, &ylen);
00160
00161 dict["nx"] = xlen;
00162 dict["ny"] = ylen;
00163 dict["nz"] = 1;
00164
00165 dict["PGM.max_gray"] = maxval;
00166 dict["PGM.min_gray"] = minval;
00167
00168 EXITFUNC;
00169 return 0;
00170 }
00171
00172 int PgmIO::write_header(const Dict & dict, int image_index, const Region*,
00173 EMUtil::EMDataType, bool)
00174 {
00175 ENTERFUNC;
00176 int err = 0;
00177
00178
00179 if(image_index == -1) {
00180 image_index = 0;
00181 }
00182 if(image_index != 0) {
00183 throw ImageWriteException(filename, "PGM file does not support stack.");
00184 }
00185 check_write_access(rw_mode, image_index);
00186
00187 int nz = dict["nz"];
00188 if ((int)nz != 1) {
00189 LOGERR("Cannot write 3D image as PGM. Your image nz = %d", nz);
00190 err = 1;
00191 throw ImageWriteException("N/A", "Cannot write 3D image as PGM.");
00192 }
00193 else {
00194 nx = dict["nx"];
00195 ny = dict["ny"];
00196
00197 if(dict.has_key("min_grey")) minval = dict["min_gray"];
00198 if(dict.has_key("max_grey")) maxval = dict["max_gray"];
00199
00200
00201 #ifdef _WIN32
00202 if (maxval<=minval || _isnan(minval) || _isnan(maxval)) {
00203 #else
00204 if (maxval<=minval || std::isnan(minval) || std::isnan(maxval)) {
00205 #endif //_WIN32
00206 maxval = 255;
00207 }
00208
00209 if(dict.has_key("render_min")) rendermin=(float)dict["render_min"];
00210 if(dict.has_key("render_max")) rendermax=(float)dict["render_max"];
00211
00212 fprintf(pgm_file, "%s\n%d %d\n%d\n", MAGIC_BINARY, nx, ny, maxval);
00213 }
00214
00215 EXITFUNC;
00216 return err;
00217 }
00218
00219 int PgmIO::read_data(float *data, int image_index, const Region * area, bool)
00220 {
00221 ENTERFUNC;
00222
00223
00224 image_index = 0;
00225 check_read_access(image_index, data);
00226 check_region(area, IntSize(nx, ny));
00227
00228 portable_fseek(pgm_file, file_offset, SEEK_SET);
00229
00230 unsigned char *cdata = (unsigned char *) (data);
00231 size_t mode_size = sizeof(unsigned char);
00232
00233 EMUtil::process_region_io(cdata, pgm_file, READ_ONLY, image_index,
00234 mode_size, nx, ny, 1, area, true);
00235
00236 int xlen = 0, ylen = 0;
00237 EMUtil::get_region_dims(area, nx, &xlen, ny, &ylen);
00238
00239 for (int k = xlen * ylen - 1; k >= 0; k--) {
00240 data[k] = static_cast < float >(cdata[k]);
00241 }
00242
00243 EXITFUNC;
00244 return 0;
00245 }
00246
00247 int PgmIO::write_data(float *data, int image_index, const Region* area,
00248 EMUtil::EMDataType, bool)
00249 {
00250 ENTERFUNC;
00251
00252
00253 image_index = 0;
00254
00255
00256
00257
00258
00259 check_write_access(rw_mode, image_index, 1, data);
00260 check_region(area, IntSize(nx, ny));
00261
00262
00263 EMUtil::getRenderMinMax(data, nx, ny, rendermin, rendermax);
00264
00265 unsigned char *cdata=(unsigned char *)malloc(nx*ny);
00266
00267 int old_add = 0;
00268 int new_add = 0;
00269 for( int j=0; j<ny; ++j ) {
00270 for( int i=0; i<nx; ++i) {
00271 old_add = j*nx+i;
00272 new_add = (ny-1-j)*nx + i;
00273 if( data[old_add]<rendermin ) {
00274 cdata[new_add] = 0;
00275 }
00276 else if( data[old_add]>rendermax )
00277 {
00278 cdata[new_add] = 255;
00279 }
00280 else {
00281 cdata[new_add] = (unsigned char)((data[old_add]-rendermin)/(rendermax-rendermin)*256.0);
00282 }
00283 }
00284 }
00285
00286 size_t mode_size = sizeof(unsigned char);
00287
00288 EMUtil::process_region_io(cdata, pgm_file, WRITE_ONLY, image_index,
00289 mode_size, nx, ny, 1, area);
00290
00291 free(cdata);
00292 EXITFUNC;
00293 return 0;
00294 }
00295
00296 void PgmIO::flush()
00297 {
00298 fflush(pgm_file);
00299 }
00300
00301
00302 bool PgmIO::is_complex_mode()
00303 {
00304 return false;
00305 }
00306
00307 bool PgmIO::is_image_big_endian()
00308 {
00309 init();
00310 return is_big_endian;
00311 }
00312