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 "pifio.h"
00037 #include "portable_fileio.h"
00038 #include "geometry.h"
00039 #include "imageio.h"
00040 #include <cstring>
00041
00042 #ifdef WIN32
00043 #include <time.h>
00044 #endif
00045
00046 using namespace EMAN;
00047
00048 PifIO::PifIO(const string & pif_filename, IOMode rw)
00049 : filename(pif_filename), rw_mode(rw)
00050 {
00051 pif_file = 0;
00052 mode_size = 0;
00053 is_big_endian = ByteOrder::is_host_big_endian();
00054 initialized = false;
00055 real_scale_factor = 1;
00056 is_new_file = false;
00057 memset(&pfh, 0, sizeof(PifFileHeader));
00058 }
00059
00060 PifIO::~PifIO()
00061 {
00062 if (pif_file) {
00063 fclose(pif_file);
00064 pif_file = 0;
00065 }
00066 }
00067
00068
00069 int PifIO::get_mode_size(PifDataMode mode)
00070 {
00071 int size = 0;
00072
00073 switch (mode) {
00074 case PIF_CHAR:
00075 case PIF_BOXED_DATA:
00076 size = sizeof(char);
00077 break;
00078 case PIF_SHORT:
00079 case PIF_SHORT_FLOAT:
00080 case PIF_SHORT_COMPLEX:
00081 case PIF_SHORT_FLOAT_COMPLEX:
00082 case PIF_MAP_FLOAT_SHORT:
00083 size = sizeof(short);
00084 break;
00085 case PIF_FLOAT:
00086 case PIF_FLOAT_COMPLEX:
00087 size = sizeof(float);
00088 break;
00089 case PIF_FLOAT_INT:
00090 case PIF_FLOAT_INT_COMPLEX:
00091 case PIF_MAP_FLOAT_INT:
00092 size = sizeof(int);
00093 break;
00094 default:
00095 break;
00096 }
00097 return size;
00098 }
00099
00100 bool PifIO::is_float_int(int m)
00101 {
00102 PifDataMode mode = static_cast < PifDataMode > (m);
00103 switch (mode) {
00104 case PIF_SHORT_FLOAT:
00105 case PIF_SHORT_FLOAT_COMPLEX:
00106
00107 case PIF_FLOAT_INT:
00108
00109 case PIF_FLOAT_INT_COMPLEX:
00110 case PIF_MAP_FLOAT_SHORT:
00111 case PIF_MAP_FLOAT_INT:
00112 return true;
00113 default:
00114 break;
00115 }
00116 return false;
00117 }
00118
00119 void PifIO::init()
00120 {
00121 ENTERFUNC;
00122 if (initialized) {
00123 return;
00124 }
00125
00126 initialized = true;
00127 pif_file = sfopen(filename, rw_mode, &is_new_file);
00128
00129 if (!is_new_file) {
00130 if (fread(&pfh, sizeof(PifFileHeader), 1, pif_file) != 1) {
00131 throw ImageReadException(filename, "PIF file header");
00132 }
00133
00134 if (!is_valid(&pfh)) {
00135 throw ImageReadException(filename, "invalid PIF file");
00136 }
00137
00138 is_big_endian = ByteOrder::is_data_big_endian(&pfh.nz);
00139 become_host_endian(&pfh.htype);
00140
00141 if (pfh.htype != 1) {
00142 string desc = "only support PIF with all projects having the same dimensions";
00143 throw ImageReadException(filename, desc);
00144 }
00145
00146 become_host_endian(&pfh.mode);
00147 become_host_endian(&pfh.nx);
00148 become_host_endian(&pfh.ny);
00149 become_host_endian(&pfh.nz);
00150 become_host_endian(&pfh.nimg);
00151
00152 if (is_float_int(pfh.mode)) {
00153 real_scale_factor = (float) atof(pfh.scalefactor);
00154 }
00155
00156 mode_size = get_mode_size(static_cast < PifDataMode > (pfh.mode));
00157
00158 if (is_complex_mode()) {
00159 pfh.nx *= 2;
00160 }
00161 }
00162 EXITFUNC;
00163 }
00164
00165 bool PifIO::is_valid(const void *first_block)
00166 {
00167 ENTERFUNC;
00168 bool result = false;
00169
00170 if (first_block) {
00171 const int *data = static_cast < const int *>(first_block);
00172 int m1 = data[0];
00173 int m2 = data[1];
00174 int endian = data[7];
00175 bool data_big_endian = false;
00176 if (endian) {
00177 data_big_endian = true;
00178 }
00179
00180 if (data_big_endian != ByteOrder::is_host_big_endian()) {
00181 ByteOrder::swap_bytes(&m1);
00182 ByteOrder::swap_bytes(&m2);
00183 }
00184
00185 if (m1 == PIF_MAGIC_NUM && m2 == PIF_MAGIC_NUM) {
00186 result = true;
00187 }
00188 }
00189
00190 EXITFUNC;
00191 return result;
00192 }
00193
00194 void PifIO::fseek_to(int image_index)
00195 {
00196 int pih_sz = sizeof(PifImageHeader);
00197 int image_size = 0;
00198
00199 #if 0
00200
00201
00202
00203 if (pfh.nimg == 1) {
00204 image_size = pfh.nx * pfh.ny * pfh.nz;
00205 }
00206 else {
00207 image_size = pfh.nx * pfh.ny;
00208 }
00209 #endif
00210 image_size = pfh.nx * pfh.ny * pfh.nz;
00211
00212 size_t file_offset = sizeof(PifFileHeader) +
00213 (pih_sz + image_size * mode_size) * image_index;
00214
00215 portable_fseek(pif_file, file_offset, SEEK_SET);
00216 }
00217
00218
00219 int PifIO::read_header(Dict & dict, int image_index, const Region * area, bool)
00220 {
00221 ENTERFUNC;
00222
00223 check_read_access(image_index);
00224 fseek_to(image_index);
00225
00226 int pih_sz = sizeof(PifImageHeader);
00227 PifImageHeader pih;
00228
00229 if (fread(&pih, pih_sz, 1, pif_file) != 1) {
00230 throw ImageReadException(filename, "PIF Image header");
00231 }
00232 else {
00233 check_region(area, FloatSize(pih.nx, pih.ny, pih.nz), is_new_file);
00234 int xlen = 0, ylen = 0, zlen = 0;
00235 EMUtil::get_region_dims(area, pih.nx, &xlen, pih.ny, &ylen, pih.nz, &zlen);
00236
00237 dict["nx"] = xlen;
00238 dict["ny"] = ylen;
00239 dict["nz"] = zlen;
00240
00241 dict["datatype"] = to_em_datatype(pih.mode);
00242
00243 dict["apix_x"] = static_cast < float >(pih.xlen);
00244 dict["apix_y"] = static_cast < float >(pih.ylen);
00245 dict["apix_z"] = static_cast < float >(pih.zlen);
00246
00247 dict["minimum"] = static_cast < float >(pih.min);
00248 dict["maximum"] = static_cast < float >(pih.max);
00249 dict["mean"] = static_cast < float >(pih.mean);
00250 dict["sigma"] = static_cast < float >(pih.sigma);
00251
00252 dict["origin_x"] = static_cast < float >(pih.xorigin);
00253 dict["origin_y"] = static_cast < float >(pih.yorigin);
00254 }
00255
00256 EXITFUNC;
00257
00258 return 0;
00259 }
00260
00261 int PifIO::write_header(const Dict & dict, int image_index, const Region* area,
00262 EMUtil::EMDataType, bool)
00263 {
00264 ENTERFUNC;
00265
00266 check_write_access(rw_mode, image_index);
00267
00268 if (area) {
00269 check_region(area, FloatSize(pfh.nx, pfh.ny, pfh.nz), is_new_file);
00270 EXITFUNC;
00271 return 0;
00272 }
00273
00274 time_t t0 = time(0);
00275 struct tm *t = localtime(&t0);
00276
00277 if (!is_new_file) {
00278 if (is_big_endian != ByteOrder::is_host_big_endian()) {
00279 throw ImageWriteException(filename, "writing to opposite byteorder file");
00280 }
00281
00282 int nx1 = dict["nx"];
00283 int ny1 = dict["ny"];
00284 int nz1 = dict["nz"];
00285
00286 int mode1 = to_pif_datatype(dict["datatype"]);
00287
00288 if (nx1 != pfh.nx || ny1 != pfh.ny || nz1 != pfh.nz) {
00289 LOGERR("cannot write to different size file %s (%dx%dx%d != %dx%dx%d)",
00290 filename.c_str(), nx1, ny1, nz1, pfh.nx, pfh.ny, pfh.nz);
00291 throw ImageWriteException(filename, "different image size");
00292 }
00293
00294 if (mode1 != pfh.mode) {
00295 throw ImageWriteException(filename, "different data type");
00296 }
00297
00298 fseek_to(image_index);
00299 }
00300 else {
00301 pfh.magic[0] = PIF_MAGIC_NUM;
00302 pfh.magic[1] = PIF_MAGIC_NUM;
00303 sprintf(pfh.scalefactor, "1.0");
00304
00305 pfh.mode = PIF_FLOAT_INT;
00306 sprintf(pfh.program, "EMAN %d/%02d/%02d", t->tm_mon, t->tm_mday, t->tm_year);
00307
00308 pfh.htype = 1;
00309 pfh.nx = dict["nx"];
00310 pfh.ny = dict["ny"];
00311 pfh.nz = dict["nz"];
00312 pfh.nimg += 1;
00313 pfh.endian = (int) ByteOrder::is_host_big_endian();
00314 fwrite(&pfh, sizeof(PifFileHeader), 1, pif_file);
00315 }
00316
00317 PifImageHeader pih;
00318 memset(&pih, 0, sizeof(PifImageHeader));
00319 pih.nx = dict["nx"];
00320 pih.ny = dict["ny"];
00321 pih.nz = dict["nz"];
00322
00323 pih.mode = PIF_FLOAT;
00324 pih.xlen = dict["apix_x"];
00325 pih.ylen = dict["apix_y"];
00326 pih.zlen = dict["apix_z"];
00327 pih.alpha = 90;
00328 pih.beta = 90;
00329 pih.gamma = 90;
00330 pih.mapc = 1;
00331 pih.mapr = 2;
00332 pih.maps = 3;
00333 pih.min = dict["minimum"];
00334 pih.max = dict["maximum"];
00335 pih.mean = dict["mean"];
00336 pih.sigma = dict["sigma"];
00337
00338 pih.xorigin = dict["origin_x"];
00339 pih.yorigin = dict["origin_y"];
00340
00341 sprintf(pih.time, "%d/%02d/%02d %d:%02d",
00342 t->tm_mon, t->tm_mday, t->tm_year, t->tm_hour, t->tm_min);
00343 fwrite(&pih, sizeof(PifImageHeader), 1, pif_file);
00344
00345 EXITFUNC;
00346 return 0;
00347 }
00348
00349 int PifIO::read_data(float *data, int image_index, const Region *area, bool)
00350 {
00351 ENTERFUNC;
00352
00353 check_read_access(image_index, data);
00354 fseek_to(image_index);
00355
00356 int pih_sz = sizeof(PifImageHeader);
00357 PifImageHeader pih;
00358
00359 if (fread(&pih, pih_sz, 1, pif_file) != 1) {
00360 throw ImageReadException(filename, "PIF Image header");
00361 }
00362
00363 if (area) {
00364 check_region(area, FloatSize(pih.nx, pih.ny, pih.nz), is_new_file);
00365 }
00366
00367 PifDataMode data_mode = static_cast < PifDataMode > (pih.mode);
00368 int num_layers = pih.nz;
00369 #if 0
00370 if (pfh.nz == pfh.nimg) {
00371 num_layers = 1;
00372 }
00373 #endif
00374
00375
00376 unsigned char * cdata = (unsigned char*)data;
00377 short *sdata = (short*) data;
00378
00379 EMUtil::process_region_io(cdata, pif_file, READ_ONLY,
00380 0, mode_size, pih.nx, pih.ny,
00381 num_layers, area);
00382
00383 int xlen = 0, ylen = 0, zlen = 0;
00384 EMUtil::get_region_dims(area, pih.nx, &xlen, pih.ny, &ylen, pih.nz, &zlen);
00385 size_t size = xlen * ylen * zlen;
00386
00387 if(data_mode == PIF_FLOAT || data_mode == PIF_FLOAT_COMPLEX)
00388 {
00389 become_host_endian< float >(data, size);
00390 }
00391 else {
00392 if (mode_size == sizeof(short)) {
00393 become_host_endian((short *) sdata, size);
00394 }
00395 else if (mode_size == sizeof(int)) {
00396 become_host_endian((int *) data, size);
00397 }
00398
00399 if (mode_size == sizeof(char)) {
00400 for (size_t i = 0; i < size; i++) {
00401 size_t j = size - 1 - i;
00402 data[j] = (float)(cdata[j]) * real_scale_factor;
00403 }
00404 }
00405 else if (mode_size == sizeof(short)) {
00406 for (size_t i = 0; i < size; i++) {
00407 size_t j = size - 1 - i;
00408 data[j] = (float)(sdata[j]) * real_scale_factor;
00409 }
00410 }
00411 else if (mode_size == sizeof(int)) {
00412 for (size_t i = 0; i < size; i++) {
00413 size_t j = size - 1 - i;
00414 data[j] = (float) ((int *)data)[j] * real_scale_factor;
00415 }
00416 }
00417 }
00418
00419
00420
00421 #if 0
00422 int buf_size = pih.nx * mode_size;
00423 unsigned char *buf = new unsigned char[buf_size];
00424
00425 for (int l = 0; l < num_layers; l++) {
00426 int offset1 = l * pfh.nx * pfh.ny;
00427 for (int j = 0; j < pfh.ny; j++) {
00428 if (fread(buf, mode_size, pfh.nx, pif_file) != (unsigned int) pfh.nx) {
00429 if( buf )
00430 {
00431 delete[]buf;
00432 buf = 0;
00433 }
00434 throw ImageReadException(filename, "incomplete PIF read");
00435 }
00436
00437 if (mode_size == sizeof(short)) {
00438 become_host_endian((short *) buf, pfh.nx);
00439 }
00440 else if (mode_size == sizeof(int)) {
00441 become_host_endian((int *) buf, pfh.nx);
00442 }
00443
00444 int offset2 = offset1 + j * pfh.nx;
00445
00446 for (int k = 0; k < pfh.nx; k++) {
00447 float curr_data = 0;
00448
00449 if (mode_size == sizeof(char)) {
00450 curr_data = (float) buf[k];
00451 }
00452 else if (mode_size == sizeof(short)) {
00453 curr_data = (float) ((short *) buf)[k];
00454 }
00455 else if (mode_size == sizeof(int)) {
00456 curr_data = (float) ((int *) buf)[k];
00457 }
00458 data[offset2 + k] = curr_data * real_scale_factor;
00459 }
00460 }
00461 }
00462 if( buf )
00463 {
00464 delete[]buf;
00465 buf = 0;
00466 }
00467 #endif
00468 EXITFUNC;
00469 return 0;
00470 }
00471
00472
00473 int PifIO::write_data(float *data, int image_index, const Region* area,
00474 EMUtil::EMDataType, bool)
00475 {
00476 ENTERFUNC;
00477
00478 check_write_access(rw_mode, image_index, 0, data);
00479 fseek_to(image_index);
00480
00481 int nx = pfh.nx;
00482 int ny = pfh.ny;
00483 int nz = pfh.nz;
00484
00485 check_region(area, FloatSize(nx, ny, nz), is_new_file);
00486
00487
00488
00489 EMUtil::process_region_io(data, pif_file, WRITE_ONLY, 0,
00490 mode_size, nx, ny, nz, area);
00491
00492 #if 0
00493 size_t idx;
00494 int *buf = new int[nx];
00495 for (int i = 0; i < nz; i++) {
00496 for (int j = 0; j < ny; j++) {
00497 for (int k = 0; k < pfh.nx; k++) {
00498 idx = i * nx * ny + j * nx + k;
00499 buf[k] = (int) data[idx];
00500 }
00501 fwrite(buf, sizeof(int) * nx, 1, pif_file);
00502 }
00503 }
00504 if( buf )
00505 {
00506 delete[]buf;
00507 buf = 0;
00508 }
00509 #endif
00510
00511 EXITFUNC;
00512 return 0;
00513 }
00514
00515 void PifIO::flush()
00516 {
00517 fflush(pif_file);
00518 }
00519
00520 bool PifIO::is_complex_mode()
00521 {
00522 init();
00523 if (pfh.mode == PIF_SHORT_COMPLEX ||
00524 pfh.mode == PIF_FLOAT_INT_COMPLEX ||
00525 pfh.mode == PIF_FLOAT_COMPLEX || pfh.mode == PIF_SHORT_FLOAT_COMPLEX) {
00526 return true;
00527 }
00528 return false;
00529 }
00530
00531 bool PifIO::is_image_big_endian()
00532 {
00533 init();
00534 return is_big_endian;
00535 }
00536
00537 int PifIO::get_nimg()
00538 {
00539 init();
00540 return pfh.nimg;
00541 }
00542
00543
00544 int PifIO::to_em_datatype(int p)
00545 {
00546 PifDataMode mode = static_cast < PifDataMode > (p);
00547 EMUtil::EMDataType e = EMUtil::EM_UNKNOWN;
00548
00549 switch (mode) {
00550 case PIF_CHAR:
00551 case PIF_BOXED_DATA:
00552 e = EMUtil::EM_CHAR;
00553 break;
00554
00555 case PIF_SHORT:
00556 case PIF_SHORT_FLOAT:
00557 case PIF_MAP_FLOAT_SHORT:
00558 e = EMUtil::EM_SHORT;
00559 break;
00560
00561 case PIF_SHORT_COMPLEX:
00562 case PIF_SHORT_FLOAT_COMPLEX:
00563 e = EMUtil::EM_SHORT_COMPLEX;
00564 break;
00565
00566 case PIF_FLOAT:
00567 case PIF_FLOAT_INT:
00568 case PIF_MAP_FLOAT_INT:
00569 e = EMUtil::EM_FLOAT;
00570 break;
00571 case PIF_FLOAT_COMPLEX:
00572 case PIF_FLOAT_INT_COMPLEX:
00573 e = EMUtil::EM_FLOAT_COMPLEX;
00574 break;
00575 case PIF_INVALID:
00576 e = EMUtil::EM_UNKNOWN;
00577 break;
00578 }
00579 return e;
00580 }
00581
00582 int PifIO::to_pif_datatype(int e)
00583 {
00584 PifDataMode m = PIF_INVALID;
00585
00586 switch (e) {
00587 case EMUtil::EM_CHAR:
00588 m = PIF_BOXED_DATA;
00589 break;
00590 case EMUtil::EM_SHORT:
00591 m = PIF_SHORT;
00592 break;
00593 case EMUtil::EM_SHORT_COMPLEX:
00594 m = PIF_SHORT_COMPLEX;
00595 break;
00596 case EMUtil::EM_FLOAT:
00597 m = PIF_FLOAT_INT;
00598 break;
00599 case EMUtil::EM_FLOAT_COMPLEX:
00600 m = PIF_FLOAT_COMPLEX;
00601 break;
00602 default:
00603 LOGERR("unknown PIF mode: %d", e);
00604 }
00605
00606 return m;
00607 }