pifio.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 #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         //case PIF_FLOAT:
00107         case PIF_FLOAT_INT:
00108         //case PIF_FLOAT_COMPLEX:
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         // this works for some images that PURDUE people gave to me.
00201         // But those images don't follow the PIF specification. So
00202         // I believe they are in wrong format.
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         // new way to read PIF data. The new way includes region reading.
00375         // If it is tested to be OK, remove the code in #if 0 ... #endif
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         // end of new way for region reading
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         // to write a region; if it works, please remove the code
00488         // in #if 0 ... #endif
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 }

Generated on Sat Nov 21 02:19:16 2009 for EMAN2 by  doxygen 1.5.6