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 <cstring>
00037 #include <climits>
00038
00039 #include "mrcio.h"
00040 #include "portable_fileio.h"
00041 #include "geometry.h"
00042 #include "util.h"
00043 #include "ctf.h"
00044 #include "transform.h"
00045
00046 using namespace EMAN;
00047
00048 const char *MrcIO::CTF_MAGIC = "!-";
00049 const char *MrcIO::SHORT_CTF_MAGIC = "!$";
00050
00051 MrcIO::MrcIO(const string & mrc_filename, IOMode rw)
00052 : filename(mrc_filename), rw_mode(rw), mrcfile(0), mode_size(0),
00053 isFEI(false), is_ri(0), is_new_file(false), initialized(false),
00054 is_transpose(false)
00055 {
00056 memset(&mrch, 0, sizeof(MrcHeader));
00057 is_big_endian = ByteOrder::is_host_big_endian();
00058 }
00059
00060 MrcIO::~MrcIO()
00061 {
00062 if (mrcfile) {
00063 fclose(mrcfile);
00064 mrcfile = 0;
00065 }
00066 }
00067
00068 void MrcIO::init()
00069 {
00070 ENTERFUNC;
00071
00072 if (initialized) {
00073 return;
00074 }
00075
00076 initialized = true;
00077 mrcfile = sfopen(filename, rw_mode, &is_new_file);
00078
00079 if (!is_new_file) {
00080 if (fread(&mrch, sizeof(MrcHeader), 1, mrcfile) != 1) {
00081 throw ImageReadException(filename, "MRC header");
00082 }
00083
00084 if (!is_valid(&mrch)) {
00085 throw ImageReadException(filename, "invalid MRC");
00086 }
00087
00088 is_big_endian = ByteOrder::is_data_big_endian(&mrch.nz);
00089 if (is_big_endian != ByteOrder::is_host_big_endian()) {
00090 swap_header(mrch);
00091 }
00092
00093
00094 mode_size = get_mode_size(mrch.mode);
00095 if(is_complex_mode()) {
00096 is_ri = 1;
00097 }
00098
00099 if (mrch.nxstart != 0 || mrch.nystart != 0 || mrch.nzstart != 0) {
00100 LOGWARN("nx/ny/nz start not zero");
00101 }
00102
00103 if (is_complex_mode()) {
00104 mrch.nx *= 2;
00105 }
00106
00107 if (mrch.xlen == 0) {
00108 mrch.xlen = 1.0;
00109 }
00110
00111 if (mrch.ylen == 0) {
00112 mrch.ylen = 1.0;
00113 }
00114
00115 if (mrch.zlen == 0) {
00116 mrch.zlen = 1.0;
00117 }
00118
00119 if(mrch.nlabels>0) {
00120 if( string(mrch.labels[0],3) == "Fei") {
00121 isFEI = true;
00122 }
00123 }
00124
00125 if(mrch.mapc==2 && mrch.mapr==1) {
00126 is_transpose = true;
00127 }
00128 }
00129 EXITFUNC;
00130 }
00131
00132
00133 bool MrcIO::is_image_big_endian()
00134 {
00135 init();
00136 return is_big_endian;
00137 }
00138
00139 bool MrcIO::is_valid(const void *first_block, off_t file_size)
00140 {
00141 ENTERFUNC;
00142
00143 if (!first_block) {
00144 return false;
00145 }
00146
00147 const int *data = static_cast < const int *>(first_block);
00148 int nx = data[0];
00149 int ny = data[1];
00150 int nz = data[2];
00151 int mrcmode = data[3];
00152 int nsymbt = data[23];
00153
00154 bool data_big_endian = ByteOrder::is_data_big_endian(&nz);
00155
00156 if (data_big_endian != ByteOrder::is_host_big_endian()) {
00157 ByteOrder::swap_bytes(&nx);
00158 ByteOrder::swap_bytes(&ny);
00159 ByteOrder::swap_bytes(&nz);
00160 ByteOrder::swap_bytes(&mrcmode);
00161 ByteOrder::swap_bytes(&nsymbt);
00162 }
00163
00164 if (mrcmode == MRC_SHORT_COMPLEX || mrcmode == MRC_FLOAT_COMPLEX) {
00165 nx *= 2;
00166 }
00167
00168 const int max_dim = 1 << 20;
00169
00170 if ((mrcmode >= MRC_UCHAR && mrcmode < MRC_UNKNOWN) &&
00171 (nx > 1 && nx < max_dim) && (ny > 0 && ny < max_dim) && (nz > 0 && nz < max_dim)) {
00172
00173 if (file_size > 0) {
00174 off_t file_size1 = (off_t)nx * (off_t)ny * (off_t)nz * (off_t)get_mode_size(mrcmode) + (off_t)sizeof(MrcHeader) + nsymbt;
00175 if (file_size == file_size1) {
00176 return true;
00177 }
00178
00179 LOGWARN("image size check fails, still try to read it...");
00180 }
00181 else {
00182 return true;
00183 }
00184
00185 return true;
00186 }
00187 EXITFUNC;
00188 return false;
00189 }
00190
00191 int MrcIO::read_header(Dict & dict, int image_index, const Region * area, bool is_3d)
00192 {
00193 init();
00194
00195 if(isFEI) {
00196 return read_fei_header(dict, image_index, area, is_3d);
00197 }
00198 else {
00199 return read_mrc_header(dict, image_index, area, is_3d);
00200 }
00201 }
00202
00203 int MrcIO::read_mrc_header(Dict & dict, int image_index, const Region * area, bool)
00204 {
00205 ENTERFUNC;
00206
00207
00208 if(image_index < 0) {
00209 image_index = 0;
00210 }
00211 if(image_index != 0) {
00212 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().");
00213 }
00214
00215 check_region(area, FloatSize(mrch.nx, mrch.ny, mrch.nz), is_new_file, false);
00216
00217 int xlen = 0, ylen = 0, zlen = 0;
00218 EMUtil::get_region_dims(area, mrch.nx, &xlen, mrch.ny, &ylen, mrch.nz, &zlen);
00219
00220 dict["nx"] = xlen;
00221 dict["ny"] = ylen;
00222 dict["nz"] = zlen;
00223 dict["MRC.nx"] = mrch.nx;
00224 dict["MRC.ny"] = mrch.ny;
00225 dict["MRC.nz"] = mrch.nz;
00226
00227 dict["datatype"] = to_em_datatype(mrch.mode);
00228
00229 dict["MRC.nxstart"] = mrch.nxstart;
00230 dict["MRC.nystart"] = mrch.nystart;
00231 dict["MRC.nzstart"] = mrch.nzstart;
00232
00233 dict["MRC.mx"] = mrch.mx;
00234 dict["MRC.my"] = mrch.my;
00235 dict["MRC.mz"] = mrch.mz;
00236
00237 dict["MRC.xlen"] = mrch.xlen;
00238 dict["MRC.ylen"] = mrch.ylen;
00239 dict["MRC.zlen"] = mrch.zlen;
00240
00241 dict["MRC.alpha"] = mrch.alpha;
00242 dict["MRC.beta"] = mrch.beta;
00243 dict["MRC.gamma"] = mrch.gamma;
00244
00245 dict["MRC.mapc"] = mrch.mapc;
00246 dict["MRC.mapr"] = mrch.mapr;
00247 dict["MRC.maps"] = mrch.maps;
00248
00249 dict["MRC.minimum"] = mrch.amin;
00250 dict["MRC.maximum"] = mrch.amax;
00251 dict["MRC.mean"] = mrch.amean;
00252 dict["mean"] = mrch.amean;
00253
00254 dict["MRC.ispg"] = mrch.ispg;
00255 dict["MRC.nsymbt"] = mrch.nsymbt;
00256
00257 float apx = mrch.xlen / mrch.mx;
00258 float apy = mrch.ylen / mrch.my;
00259 float apz = mrch.zlen / mrch.mz;
00260 if(apx>1000 || apx<0.01) {
00261 dict["apix_x"] = 1.0f;
00262 }
00263 else {
00264 dict["apix_x"] = apx;
00265 }
00266 if(apy>1000 || apy<0.01) {
00267 dict["apix_y"] = 1.0f;
00268 }
00269 else {
00270 dict["apix_y"] = apy;
00271 }
00272 if(apz>1000 || apz<0.01) {
00273 dict["apix_z"] = 1.0f;
00274 }
00275 else {
00276 dict["apix_z"] = apz;
00277 }
00278
00279 if (area) {
00280 dict["origin_x"] = mrch.xorigin + mrch.xlen * area->origin[0];
00281 dict["origin_y"] = mrch.yorigin + mrch.xlen * area->origin[1];
00282
00283 if (area->get_ndim() == 3 && mrch.nz > 1) {
00284 dict["origin_z"] = mrch.zorigin + mrch.xlen * area->origin[2];
00285 }
00286 else {
00287 dict["origin_z"] = mrch.zorigin;
00288 }
00289 }
00290 else {
00291 dict["origin_x"] = mrch.xorigin;
00292 dict["origin_y"] = mrch.yorigin;
00293 dict["origin_z"] = mrch.zorigin;
00294 }
00295
00296 if (is_complex_mode()) {
00297 dict["is_complex"] = 1;
00298 dict["is_complex_ri"] = 1;
00299 }
00300
00301 dict["MRC.machinestamp"] = mrch.machinestamp;
00302
00303 dict["MRC.rms"] = mrch.rms;
00304 dict["sigma"] = mrch.rms;
00305 dict["MRC.nlabels"] = mrch.nlabels;
00306 for (int i = 0; i < mrch.nlabels; i++) {
00307 char label[32];
00308 sprintf(label, "MRC.label%d", i);
00309 dict[string(label)] = string(mrch.labels[i],80);
00310 }
00311
00312 EMAN1Ctf ctf_;
00313 if(read_ctf(ctf_) == 0) {
00314 vector<float> vctf = ctf_.to_vector();
00315 dict["ctf"] = vctf;
00316 }
00317
00318 if(is_transpose) {
00319 dict["nx"] = ylen;
00320 dict["ny"] = xlen;
00321 dict["MRC.nx"] = mrch.ny;
00322 dict["MRC.ny"] = mrch.nx;
00323 dict["MRC.mx"] = mrch.my;
00324 dict["MRC.my"] = mrch.mx;
00325 dict["apix_x"] = mrch.ylen / mrch.my;
00326 dict["apix_y"] = mrch.xlen / mrch.mx;
00327 dict["origin_x"] = mrch.yorigin;
00328 dict["origin_y"] = mrch.xorigin;
00329 dict["MRC.nxstart"] = mrch.nystart;
00330 dict["MRC.nystart"] = mrch.nxstart;
00331 }
00332
00333 Transform * trans = new Transform();
00334 if(is_transpose) {
00335 trans->set_trans(mrch.nystart, mrch.nxstart, mrch.nzstart);
00336 }
00337 else {
00338 trans->set_trans(mrch.nxstart, mrch.nystart, mrch.nzstart);
00339 }
00340
00341 if(zlen<=1) {
00342 dict["xform.projection"] = trans;
00343 }
00344 else {
00345 dict["xform.align3d"] = trans;
00346 }
00347
00348 if(trans) {delete trans; trans=0;}
00349
00350 EXITFUNC;
00351 return 0;
00352 }
00353
00354 int MrcIO::read_fei_header(Dict & dict, int image_index, const Region * area, bool)
00355 {
00356 ENTERFUNC;
00357
00358 if(image_index < 0) {
00359 image_index = 0;
00360 }
00361
00362 init();
00363
00364 check_region(area, FloatSize(feimrch.nx, feimrch.ny, feimrch.nz), is_new_file, false);
00365
00366 int xlen = 0, ylen = 0, zlen = 0;
00367 EMUtil::get_region_dims(area, feimrch.nx, &xlen, feimrch.ny, &ylen, feimrch.nz, &zlen);
00368
00369 dict["nx"] = xlen;
00370 dict["ny"] = ylen;
00371 dict["nz"] = zlen;
00372 dict["FEIMRC.nx"] = feimrch.nx;
00373 dict["FEIMRC.ny"] = feimrch.ny;
00374 dict["FEIMRC.nz"] = feimrch.nz;
00375
00376 dict["datatype"] = to_em_datatype(feimrch.mode);
00377
00378 dict["FEIMRC.nxstart"] = feimrch.nxstart;
00379 dict["FEIMRC.nystart"] = feimrch.nystart;
00380 dict["FEIMRC.nzstart"] = feimrch.nzstart;
00381
00382 dict["FEIMRC.mx"] = feimrch.mx;
00383 dict["FEIMRC.my"] = feimrch.my;
00384 dict["FEIMRC.mz"] = feimrch.mz;
00385
00386 dict["FEIMRC.xlen"] = feimrch.xlen;
00387 dict["FEIMRC.ylen"] = feimrch.ylen;
00388 dict["FEIMRC.zlen"] = feimrch.zlen;
00389
00390 dict["FEIMRC.alpha"] = feimrch.alpha;
00391 dict["FEIMRC.beta"] = feimrch.beta;
00392 dict["FEIMRC.gamma"] = feimrch.gamma;
00393
00394 dict["FEIMRC.mapc"] = feimrch.mapc;
00395 dict["FEIMRC.mapr"] = feimrch.mapr;
00396 dict["FEIMRC.maps"] = feimrch.maps;
00397
00398 dict["FEIMRC.minimum"] = feimrch.amin;
00399 dict["FEIMRC.maximum"] = feimrch.amax;
00400 dict["FEIMRC.mean"] = feimrch.amean;
00401 dict["mean"] = feimrch.amean;
00402
00403 dict["FEIMRC.ispg"] = feimrch.ispg;
00404 dict["FEIMRC.nsymbt"] = feimrch.nsymbt;
00405
00406 dict["apix_x"] = feimrch.xlen / feimrch.mx;
00407 dict["apix_y"] = feimrch.ylen / feimrch.my;
00408 dict["apix_z"] = feimrch.zlen / feimrch.mz;
00409
00410 dict["FEIMRC.next"] = feimrch.next;
00411 dict["FEIMRC.dvid"] = feimrch.dvid;
00412 dict["FEIMRC.numintegers"] = feimrch.numintegers;
00413 dict["FEIMRC.numfloats"] = feimrch.numfloats;
00414 dict["FEIMRC.sub"] = feimrch.sub;
00415 dict["FEIMRC.zfac"] = feimrch.zfac;
00416
00417 dict["FEIMRC.min2"] = feimrch.min2;
00418 dict["FEIMRC.max2"] = feimrch.max2;
00419 dict["FEIMRC.min3"] = feimrch.min3;
00420 dict["FEIMRC.max3"] = feimrch.max3;
00421 dict["FEIMRC.min4"] = feimrch.min4;
00422 dict["FEIMRC.max4"] = feimrch.max4;
00423
00424 dict["FEIMRC.idtype"] = feimrch.idtype;
00425 dict["FEIMRC.lens"] = feimrch.lens;
00426 dict["FEIMRC.nd1"] = feimrch.nd1;
00427 dict["FEIMRC.nd2"] = feimrch.nd2;
00428 dict["FEIMRC.vd1"] = feimrch.vd1;
00429 dict["FEIMRC.vd2"] = feimrch.vd2;
00430
00431 for(int i=0; i<9; i++) {
00432 char label[32];
00433 sprintf(label, "MRC.tiltangles%d", i);
00434 dict[string(label)] = feimrch.tiltangles[i];
00435 }
00436
00437 dict["FEIMRC.zorg"] = feimrch.zorg;
00438 dict["FEIMRC.xorg"] = feimrch.xorg;
00439 dict["FEIMRC.yorg"] = feimrch.yorg;
00440
00441 dict["FEIMRC.nlabl"] = feimrch.nlabl;
00442 for (int i = 0; i < feimrch.nlabl; i++) {
00443 char label[32];
00444 sprintf(label, "MRC.label%d", i);
00445 dict[string(label)] = string(feimrch.labl[i], 80);
00446 }
00447
00448
00449 FeiMrcExtHeader feiexth;
00450 portable_fseek(mrcfile, sizeof(FeiMrcHeader)+sizeof(FeiMrcExtHeader)*image_index, SEEK_SET);
00451 if (fread(&feiexth, sizeof(FeiMrcExtHeader), 1, mrcfile) != 1) {
00452 throw ImageReadException(filename, "FEI MRC extended header");
00453 }
00454
00455 dict["FEIMRC.a_tilt"] = feiexth.a_tilt;
00456 dict["FEIMRC.b_tilt"] = feiexth.b_tilt;
00457
00458 dict["FEIMRC.x_stage"] = feiexth.x_stage;
00459 dict["FEIMRC.y_stage"] = feiexth.y_stage;
00460 dict["FEIMRC.z_stage"] = feiexth.z_stage;
00461
00462 dict["FEIMRC.x_shift"] = feiexth.x_shift;
00463 dict["FEIMRC.y_shift"] = feiexth.y_shift;
00464
00465 dict["FEIMRC.defocus"] = feiexth.defocus;
00466 dict["FEIMRC.exp_time"] = feiexth.exp_time;
00467 dict["FEIMRC.mean_int"] = feiexth.mean_int;
00468 dict["FEIMRC.tilt_axis"] = feiexth.tilt_axis;
00469
00470 dict["FEIMRC.pixel_size"] = feiexth.pixel_size;
00471 dict["FEIMRC.magnification"] = feiexth.magnification;
00472 dict["FEIMRC.ht"] = feiexth.ht;
00473 dict["FEIMRC.binning"] = feiexth.binning;
00474 dict["FEIMRC.appliedDefocus"] = feiexth.appliedDefocus;
00475
00476
00477
00478 EXITFUNC;
00479 return 0;
00480 }
00481
00482 int MrcIO::write_header(const Dict & dict, int image_index, const Region* area,
00483 EMUtil::EMDataType filestoragetype, bool use_host_endian)
00484 {
00485 ENTERFUNC;
00486
00487
00488 if(image_index == -1) {
00489 image_index = 0;
00490 }
00491 if(image_index != 0) {
00492 throw ImageWriteException(filename, "MRC file does not support stack.");
00493 }
00494 check_write_access(rw_mode, image_index, 1);
00495 if (area) {
00496 check_region(area, FloatSize(mrch.nx, mrch.ny, mrch.nz), is_new_file);
00497 EXITFUNC;
00498 return 0;
00499 }
00500
00501 int new_mode = to_mrcmode(filestoragetype, (int) dict["is_complex"]);
00502 int nx = dict["nx"];
00503 int ny = dict["ny"];
00504 int nz = dict["nz"];
00505 is_ri = dict["is_complex_ri"];
00506
00507 bool opposite_endian = false;
00508
00509 if (!is_new_file) {
00510 if (is_big_endian != ByteOrder::is_host_big_endian()) {
00511 opposite_endian = true;
00512 }
00513 #if 0
00514 if (new_mode != mrch.mode) {
00515 LOGERR("cannot write to different mode file %s", filename.c_str());
00516 return 1;
00517 }
00518 #endif
00519 portable_fseek(mrcfile, 0, SEEK_SET);
00520 }
00521 else {
00522 mrch.alpha = mrch.beta = mrch.gamma = 90.0f;
00523 mrch.mapc = 1;
00524 mrch.mapr = 2;
00525 mrch.maps = 3;
00526 mrch.nxstart = mrch.nystart = mrch.nzstart = 0;
00527 }
00528
00529 if(nz<=1 && dict.has_key("xform.projection") && !dict.has_key("UCSF.chimera")) {
00530 Transform * t = dict["xform.projection"];
00531 Dict d = t->get_params("imagic");
00532 mrch.alpha = d["alpha"];
00533 mrch.beta = d["beta"];
00534 mrch.gamma = d["gamma"];
00535 mrch.xorigin = d["tx"];
00536 mrch.yorigin = d["ty"];
00537 mrch.zorigin = d["tz"];
00538 if(t) {delete t; t=0;}
00539 }
00540 else if(nz>1 && dict.has_key("xform.align3d") && !dict.has_key("UCSF.chimera")) {
00541 Transform * t = dict["xform.align3d"];
00542 Dict d = t->get_params("imagic");
00543 mrch.alpha = d["alpha"];
00544 mrch.beta = d["beta"];
00545 mrch.gamma = d["gamma"];
00546 mrch.xorigin = d["tx"];
00547 mrch.yorigin = d["ty"];
00548 mrch.zorigin = d["tz"];
00549 if(t) {delete t; t=0;}
00550 }
00551
00552 if(dict.has_key("origin_x") && dict.has_key("origin_y") && dict.has_key("origin_z")){
00553 mrch.xorigin = (float)dict["origin_x"];
00554 mrch.yorigin = (float)dict["origin_y"];
00555
00556 if (is_new_file) {
00557 mrch.zorigin = (float)dict["origin_z"];
00558 }
00559 else {
00560 mrch.zorigin = (float) dict["origin_z"] - (float) dict["apix_z"] * image_index;
00561 }
00562 }
00563
00564 if (dict.has_key("MRC.nlabels")) {
00565 mrch.nlabels = dict["MRC.nlabels"];
00566 }
00567
00568 for (int i = 0; i < MRC_NUM_LABELS; i++) {
00569 char label[32];
00570 #ifdef _WIN32
00571 _snprintf(label,31, "MRC.label%d", i);
00572 #else
00573 snprintf(label,31, "MRC.label%d", i);
00574 #endif //_WIN32
00575 if (dict.has_key(label)) {
00576 #ifdef _WIN32
00577 _snprintf(&mrch.labels[i][0],80, "%s", (const char *) dict[label]);
00578 #else
00579 snprintf(&mrch.labels[i][0],80, "%s", (const char *) dict[label]);
00580 #endif //_WIN32
00581 mrch.nlabels = i + 1;
00582 }
00583 }
00584
00585 if (mrch.nlabels < (MRC_NUM_LABELS - 1)) {
00586 #ifdef _WIN32
00587 _snprintf(&mrch.labels[mrch.nlabels][0],79, "EMAN %s", Util::get_time_label().c_str());
00588 #else
00589 snprintf(&mrch.labels[mrch.nlabels][0],79, "EMAN %s", Util::get_time_label().c_str());
00590 #endif //_WIN32
00591 mrch.nlabels++;
00592 }
00593
00594 mrch.labels[mrch.nlabels][0] = '\0';
00595 mrch.mode = new_mode;
00596
00597 if (is_complex_mode()) {
00598 mrch.nx = nx / 2;
00599 }
00600 else {
00601 mrch.nx = nx;
00602 }
00603 mrch.ny = ny;
00604
00605 if (is_new_file) {
00606 mrch.nz = nz;
00607 }
00608 else if (image_index >= mrch.nz) {
00609 mrch.nz = image_index + 1;
00610 }
00611
00612 mrch.ispg = dict.has_key("MRC.ispg") ? (int)dict["MRC.ispg"] : 0;
00613 mrch.nsymbt = 0;
00614 mrch.amin = dict["minimum"];
00615 mrch.amax = dict["maximum"];
00616 mrch.amean = dict["mean"];
00617 mrch.rms = dict["sigma"];
00618
00621
00622
00623
00624
00625 mrch.mx = nx;
00626
00627
00628
00629
00630
00631 mrch.my = ny;
00632
00633
00634
00635
00636
00637 mrch.mz = nz;
00638
00639
00640 mrch.xlen = mrch.mx * (float) dict["apix_x"];
00641 mrch.ylen = mrch.my * (float) dict["apix_y"];
00642 mrch.zlen = mrch.mz * (float) dict["apix_z"];
00643
00644 if(dict.has_key("MRC.nxstart")) {
00645 mrch.nxstart = dict["MRC.nxstart"];
00646 }
00647 else {
00648 mrch.nxstart = -nx / 2;
00649 }
00650 if(dict.has_key("MRC.nystart")) {
00651 mrch.nystart = dict["MRC.nystart"];
00652 }
00653 else {
00654 mrch.nystart = -ny / 2;
00655 }
00656 if(dict.has_key("MRC.nzstart")) {
00657 mrch.nzstart = dict["MRC.nzstart"];
00658 }
00659 else {
00660 mrch.nzstart = -nz / 2;
00661 }
00662
00663 strncpy(mrch.map,"MAP ",4);
00664 mrch.machinestamp = generate_machine_stamp();
00665
00666 MrcHeader mrch2 = mrch;
00667
00668 if (opposite_endian || !use_host_endian) {
00669 swap_header(mrch2);
00670 }
00671
00672 if (fwrite(&mrch2, sizeof(MrcHeader), 1, mrcfile) != 1) {
00673 throw ImageWriteException(filename, "MRC header");
00674 }
00675
00676 mode_size = get_mode_size(mrch.mode);
00677 is_new_file = false;
00678
00679 if( dict.has_key("ctf") ) {
00680 vector<float> vctf = dict["ctf"];
00681 EMAN1Ctf ctf_;
00682 ctf_.from_vector(vctf);
00683 write_ctf(ctf_);
00684 }
00685
00686 EXITFUNC;
00687 return 0;
00688 }
00689
00690 int MrcIO::read_data(float *rdata, int image_index, const Region * area, bool )
00691 {
00692 ENTERFUNC;
00693
00694 if(!isFEI) {
00695
00696 image_index = 0;
00697 }
00698
00699 if(is_transpose && area!=0) {
00700 printf("Warning: This image dimension is in (y,x,z), region I/O not supported, return the whole image instead.");
00701 }
00702
00703 check_read_access(image_index, rdata);
00704
00705 if (area && is_complex_mode()) {
00706 LOGERR("Error: cannot read a region of a complex image.");
00707 return 1;
00708 }
00709
00710 unsigned char *cdata = (unsigned char *) rdata;
00711 short *sdata = (short *) rdata;
00712 unsigned short *usdata = (unsigned short *) rdata;
00713
00714 size_t size = 0;
00715 int xlen = 0, ylen = 0, zlen = 0;
00716 if(isFEI) {
00717 check_region(area, FloatSize(feimrch.nx, feimrch.ny, feimrch.nz), is_new_file, false);
00718 portable_fseek(mrcfile, sizeof(MrcHeader)+feimrch.next, SEEK_SET);
00719
00720 EMUtil::process_region_io(cdata, mrcfile, READ_ONLY,
00721 image_index, mode_size,
00722 feimrch.nx, feimrch.ny, feimrch.nz, area);
00723
00724 EMUtil::get_region_dims(area, feimrch.nx, &xlen, feimrch.ny, &ylen, feimrch.nz, &zlen);
00725
00726 size = (size_t)xlen * ylen * zlen;
00727 }
00728 else {
00729 check_region(area, FloatSize(mrch.nx, mrch.ny, mrch.nz), is_new_file, false);
00730 portable_fseek(mrcfile, sizeof(MrcHeader)+mrch.nsymbt, SEEK_SET);
00731
00732 EMUtil::process_region_io(cdata, mrcfile, READ_ONLY,
00733 image_index, mode_size,
00734 mrch.nx, mrch.ny, mrch.nz, area);
00735
00736 EMUtil::get_region_dims(area, mrch.nx, &xlen, mrch.ny, &ylen, mrch.nz, &zlen);
00737
00738 size = xlen * ylen * zlen;
00739 }
00740
00741 if (mrch.mode != MRC_UCHAR) {
00742 if (mode_size == sizeof(short)) {
00743 become_host_endian < short >(sdata, size);
00744 }
00745 else if (mode_size == sizeof(float)) {
00746 become_host_endian < float >(rdata, size);
00747 }
00748 }
00749
00750 if (mrch.mode == MRC_UCHAR) {
00751 for (size_t i = 0; i < size; ++i) {
00752 size_t j = size - 1 - i;
00753
00754 rdata[j] = static_cast < float >(cdata[j]);
00755 }
00756 }
00757 else if (mrch.mode == MRC_SHORT ) {
00758 for (size_t i = 0; i < size; ++i) {
00759 size_t j = size - 1 - i;
00760 rdata[j] = static_cast < float >(sdata[j]);
00761 }
00762 }
00763 else if (mrch.mode == MRC_USHORT) {
00764 for (size_t i = 0; i < size; ++i) {
00765 size_t j = size - 1 - i;
00766 rdata[j] = static_cast < float >(usdata[j]);
00767 }
00768 }
00769
00770 if(is_transpose) {
00771 transpose(rdata, xlen, ylen, zlen);
00772 }
00773
00774 if (is_complex_mode()) {
00775 if(!is_ri) Util::ap2ri(rdata, size);
00776 Util::flip_complex_phase(rdata, size);
00777 Util::rotate_phase_origin(rdata, xlen, ylen, zlen);
00778 }
00779 EXITFUNC;
00780 return 0;
00781 }
00782
00783 int MrcIO::write_data(float *data, int image_index, const Region* area,
00784 EMUtil::EMDataType, bool use_host_endian)
00785 {
00786 ENTERFUNC;
00787
00788 image_index = 0;
00789 check_write_access(rw_mode, image_index, 1, data);
00790 check_region(area, FloatSize(mrch.nx, mrch.ny, mrch.nz), is_new_file);
00791
00792 int nx, ny, nz;
00793 if(!area) {
00794 nx = mrch.nx;
00795 ny = mrch.ny;
00796 nz = mrch.nz;
00797 }
00798 else {
00799 nx = area->get_width();
00800 ny = area->get_height();
00801 nz = area->get_depth();
00802 }
00803 size_t size = (size_t)nx * ny * nz;
00804
00805 if (is_complex_mode()) {
00806 nx *= 2;
00807 if (!is_ri) {
00808 Util::ap2ri(data, size);
00809 is_ri = 1;
00810 }
00811 Util::flip_complex_phase(data, size);
00812 Util::rotate_phase_origin(data, nx, ny, nz);
00813 }
00814
00815 portable_fseek(mrcfile, sizeof(MrcHeader), SEEK_SET);
00816
00817 if ( (is_big_endian != ByteOrder::is_host_big_endian()) || !use_host_endian) {
00818 if (mrch.mode != MRC_UCHAR) {
00819 if (mode_size == sizeof(short)) {
00820 ByteOrder::swap_bytes((short*) data, size);
00821 }
00822 else if (mode_size == sizeof(float)) {
00823 ByteOrder::swap_bytes((float*) data, size);
00824 }
00825 }
00826 }
00827 mode_size = get_mode_size(mrch.mode);
00828
00829
00830
00831
00832 void * ptr_data = data;
00833
00834 float rendermin = 0.0f;
00835 float rendermax = 0.0f;
00836 EMUtil::getRenderMinMax(data, nx, ny, rendermin, rendermax, nz);
00837
00838 unsigned char *cdata = 0;
00839 short *sdata = 0;
00840 unsigned short *usdata = 0;
00841 if (mrch.mode == MRC_UCHAR) {
00842 cdata = new unsigned char[size];
00843 for (size_t i = 0; i < size; ++i) {
00844 if(data[i] <= rendermin) {
00845 cdata[i] = 0;
00846 }
00847 else if(data[i] >= rendermax){
00848 cdata[i] = UCHAR_MAX;
00849 }
00850 else {
00851 cdata[i]=(unsigned char)((data[i]-rendermin)/(rendermax-rendermin)*UCHAR_MAX);
00852 }
00853 }
00854 ptr_data = cdata;
00855 update_stat((void *)cdata);
00856 }
00857 else if (mrch.mode == MRC_SHORT || mrch.mode == MRC_SHORT_COMPLEX) {
00858 sdata = new short[size];
00859 for (size_t i = 0; i < size; ++i) {
00860 if(data[i] <= rendermin) {
00861 sdata[i] = SHRT_MIN;
00862 }
00863 else if(data[i] >= rendermax) {
00864 sdata[i] = SHRT_MAX;
00865 }
00866 else {
00867 sdata[i]=(short)(((data[i]-rendermin)/(rendermax-rendermin))*(SHRT_MAX-SHRT_MIN) - SHRT_MAX);
00868 }
00869 }
00870 ptr_data = sdata;
00871 update_stat((void *)sdata);
00872 }
00873 else if (mrch.mode == MRC_USHORT) {
00874 usdata = new unsigned short[size];
00875 for (size_t i = 0; i < size; ++i) {
00876 if(data[i] <= rendermin) {
00877 usdata[i] = 0;
00878 }
00879 else if(data[i] >= rendermax) {
00880 usdata[i] = USHRT_MAX;
00881 }
00882 else {
00883 usdata[i]=(unsigned short)((data[i]-rendermin)/(rendermax-rendermin)*USHRT_MAX);
00884 }
00885 }
00886 ptr_data = usdata;
00887 update_stat((void *)usdata);
00888 }
00889
00890
00891
00892
00893 EMUtil::process_region_io(ptr_data, mrcfile, WRITE_ONLY, image_index,
00894 mode_size, nx, mrch.ny, mrch.nz, area);
00895
00896 if(cdata) {delete [] cdata; cdata=0;}
00897 if(sdata) {delete [] sdata; sdata=0;}
00898 if(usdata) {delete [] usdata; usdata=0;}
00899
00900 #if 0
00901 int row_size = nx * get_mode_size(mrch.mode);
00902 int sec_size = nx * ny;
00903
00904 unsigned char *cbuf = new unsigned char[row_size];
00905 unsigned short *sbuf = (unsigned short *) cbuf;
00906
00907 for (int i = 0; i < nz; i++) {
00908 int i2 = i * sec_size;
00909 for (int j = 0; j < ny; j++) {
00910 int k = i2 + j * nx;
00911 void *pbuf = 0;
00912
00913 switch (mrch.mode) {
00914 case MRC_UCHAR:
00915 for (int l = 0; l < nx; l++) {
00916 cbuf[l] = static_cast < unsigned char >(data[k + l]);
00917 }
00918 pbuf = cbuf;
00919 fwrite(cbuf, row_size, 1, mrcfile);
00920 break;
00921
00922 case MRC_SHORT:
00923 case MRC_SHORT_COMPLEX:
00924 for (int l = 0; l < nx; l++) {
00925 sbuf[l] = static_cast < short >(data[k + l]);
00926 }
00927 pbuf = sbuf;
00928 fwrite(sbuf, row_size, 1, mrcfile);
00929 break;
00930
00931 case MRC_USHORT:
00932 for (int l = 0; l < nx; l++) {
00933 sbuf[l] = static_cast < unsigned short >(data[k + l]);
00934 }
00935 pbuf = sbuf;
00936 fwrite(sbuf, row_size, 1, mrcfile);
00937 break;
00938
00939 case MRC_FLOAT:
00940 case MRC_FLOAT_COMPLEX:
00941 pbuf = &data[k];
00942 break;
00943 }
00944 if (pbuf) {
00945 fwrite(pbuf, row_size, 1, mrcfile);
00946 }
00947 }
00948 }
00949
00950 if(cbuf)
00951 {
00952 delete[]cbuf;
00953 cbuf = 0;
00954 }
00955 #endif
00956
00957 EXITFUNC;
00958 return 0;
00959 }
00960
00961 void MrcIO::update_stat(void* data)
00962 {
00963 size_t size = mrch.nx * mrch.ny * mrch.nz;
00964 float v = 0.0f;
00965 double sum = 0.0;
00966 double square_sum = 0.0;
00967 double mean = 0.0;
00968 float min, max;
00969
00970 unsigned char * cdata = 0;
00971 short * sdata = 0;
00972 unsigned short * usdata = 0;
00973
00974 if (mrch.mode == MRC_UCHAR) {
00975 max = 0.0f;
00976 min = UCHAR_MAX;
00977 cdata = (unsigned char *)data;
00978
00979 for (size_t i = 0; i < size; ++i) {
00980 v = (float)(cdata[i]);
00981 #ifdef _WIN32
00982 max = _cpp_max(max,v);
00983 min = _cpp_min(min,v);
00984 #else
00985 max=std::max<float>(max,v);
00986 min=std::min<float>(min,v);
00987 #endif //_WIN32
00988
00989 sum += v;
00990 square_sum += v * v;
00991 }
00992 }
00993 else if (mrch.mode == MRC_SHORT || mrch.mode == MRC_SHORT_COMPLEX) {
00994 max = (float)SHRT_MIN;
00995 min = (float)SHRT_MAX;
00996 sdata = (short *)data;
00997
00998 for (size_t i = 0; i < size; ++i) {
00999 v = (float)(sdata[i]);
01000 #ifdef _WIN32
01001 max = _cpp_max(max,v);
01002 min = _cpp_min(min,v);
01003 #else
01004 max=std::max<float>(max,v);
01005 min=std::min<float>(min,v);
01006 #endif //_WIN32
01007
01008 sum += v;
01009 square_sum += v * v;
01010 }
01011 }
01012 else if (mrch.mode == MRC_USHORT) {
01013 max = 0.0f;
01014 min = (float)USHRT_MAX;
01015 usdata = (unsigned short*)data;
01016
01017 for (size_t i = 0; i < size; ++i) {
01018 v = (float)(usdata[i]);
01019 #ifdef _WIN32
01020 max = _cpp_max(max,v);
01021 min = _cpp_min(min,v);
01022 #else
01023 max=std::max<float>(max,v);
01024 min=std::min<float>(min,v);
01025 #endif //_WIN32
01026
01027 sum += v;
01028 square_sum += v * v;
01029 }
01030 }
01031 else {
01032 throw InvalidCallException("This function is used to write 8bit/16bit mrc file only.");
01033 }
01034
01035 mean = sum/size;
01036 #ifdef _WIN32
01037 float sigma = (float)std::sqrt( _cpp_max(0.0,(square_sum - sum*sum / size)/(size-1)));
01038 #else
01039 float sigma = (float)std::sqrt(std::max<float>(0.0,(square_sum - sum*sum / size)/(size-1)));
01040 #endif //_WIN32
01041
01042
01043 mrch.amin = min;
01044 mrch.amax = max;
01045 mrch.amean = (float)mean;
01046 mrch.rms = sigma;
01047
01048 MrcHeader mrch2 = mrch;
01049
01050
01051
01052
01053
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065 portable_fseek(mrcfile, 0, SEEK_SET);
01066
01067 if (fwrite(&mrch2, sizeof(MrcHeader), 1, mrcfile) != 1) {
01068 throw ImageWriteException(filename, "MRC header");
01069 }
01070
01071 portable_fseek(mrcfile, sizeof(MrcHeader), SEEK_SET);
01072 }
01073
01074 bool MrcIO::is_complex_mode()
01075 {
01076 init();
01077 if (mrch.mode == MRC_SHORT_COMPLEX || mrch.mode == MRC_FLOAT_COMPLEX) {
01078 return true;
01079 }
01080 return false;
01081 }
01082
01083
01084 int MrcIO::read_ctf(Ctf & ctf, int)
01085 {
01086 ENTERFUNC;
01087 init();
01088 size_t n = strlen(CTF_MAGIC);
01089
01090 int err = 1;
01091 if (strncmp(&mrch.labels[0][0], CTF_MAGIC, n) == 0) {
01092 err = ctf.from_string(string(&mrch.labels[0][n]));
01093 }
01094 EXITFUNC;
01095 return err;
01096 }
01097
01098 void MrcIO::write_ctf(const Ctf & ctf, int)
01099 {
01100 ENTERFUNC;
01101 init();
01102
01103 string ctf_str = ctf.to_string();
01104 #ifdef _WIN32
01105 _snprintf(&mrch.labels[0][0],80, "%s%s", CTF_MAGIC, ctf_str.c_str());
01106 #else
01107 snprintf(&mrch.labels[0][0],80, "%s%s", CTF_MAGIC, ctf_str.c_str());
01108 #endif //_WIN32
01109 rewind(mrcfile);
01110
01111 if (fwrite(&mrch, sizeof(MrcHeader), 1, mrcfile) != 1) {
01112 throw ImageWriteException(filename, "write CTF info to header failed");
01113 }
01114 EXITFUNC;
01115 }
01116
01117 void MrcIO::flush()
01118 {
01119 fflush(mrcfile);
01120 }
01121
01122
01123 int MrcIO::get_mode_size(int mm)
01124 {
01125 MrcIO::MrcMode m = static_cast < MrcMode > (mm);
01126
01127 int msize = 0;
01128 switch (m) {
01129 case MRC_UCHAR:
01130 msize = sizeof(char);
01131 break;
01132 case MRC_SHORT:
01133 case MRC_USHORT:
01134 case MRC_SHORT_COMPLEX:
01135 msize = sizeof(short);
01136 break;
01137 case MRC_FLOAT:
01138 case MRC_FLOAT_COMPLEX:
01139 msize = sizeof(float);
01140 break;
01141 default:
01142 msize = 0;
01143 }
01144
01145 return msize;
01146 }
01147
01148 int MrcIO::to_em_datatype(int m)
01149 {
01150 EMUtil::EMDataType e = EMUtil::EM_UNKNOWN;
01151
01152 switch (m) {
01153 case MRC_UCHAR:
01154 e = EMUtil::EM_UCHAR;
01155 break;
01156 case MRC_SHORT:
01157 e = EMUtil::EM_SHORT;
01158 break;
01159 case MRC_USHORT:
01160 e = EMUtil::EM_USHORT;
01161 break;
01162 case MRC_SHORT_COMPLEX:
01163 e = EMUtil::EM_SHORT_COMPLEX;
01164 break;
01165 case MRC_FLOAT:
01166 e = EMUtil::EM_FLOAT;
01167 break;
01168 case MRC_FLOAT_COMPLEX:
01169 e = EMUtil::EM_FLOAT_COMPLEX;
01170 break;
01171 default:
01172 e = EMUtil::EM_UNKNOWN;
01173 }
01174 return e;
01175 }
01176
01177
01178 int MrcIO::to_mrcmode(int e, int is_complex)
01179 {
01180 MrcMode m = MRC_UNKNOWN;
01181 EMUtil::EMDataType em_type = static_cast < EMUtil::EMDataType > (e);
01182
01183 switch (em_type) {
01184 case EMUtil::EM_UCHAR:
01185 m = MRC_UCHAR;
01186 break;
01187 case EMUtil::EM_USHORT:
01188 if (is_complex) {
01189 m = MRC_SHORT_COMPLEX;
01190 }
01191 else {
01192 m = MRC_USHORT;
01193 }
01194 break;
01195 case EMUtil::EM_SHORT:
01196 if (is_complex) {
01197 m = MRC_SHORT_COMPLEX;
01198 }
01199 else {
01200 m = MRC_SHORT;
01201 }
01202 break;
01203 case EMUtil::EM_SHORT_COMPLEX:
01204 case EMUtil::EM_USHORT_COMPLEX:
01205 m = MRC_SHORT_COMPLEX;
01206 break;
01207 case EMUtil::EM_CHAR:
01208 case EMUtil::EM_INT:
01209 case EMUtil::EM_UINT:
01210 case EMUtil::EM_FLOAT:
01211 if (is_complex) {
01212 m = MRC_FLOAT_COMPLEX;
01213 }
01214 else {
01215 m = MRC_FLOAT;
01216 }
01217 break;
01218 case EMUtil::EM_FLOAT_COMPLEX:
01219 m = MRC_FLOAT_COMPLEX;
01220 break;
01221 default:
01222 m = MRC_FLOAT;
01223 }
01224
01225 return m;
01226 }
01227
01228
01229
01230 int MrcIO::generate_machine_stamp()
01231 {
01232 int stamp = 0;
01233 char *p = (char *) (&stamp);
01234
01235 if (ByteOrder::is_host_big_endian()) {
01236 p[0] = 0x11;
01237 p[1] = 0x11;
01238 p[2] = 0;
01239 p[3] = 0;
01240 }
01241 else {
01242 p[0] = 0x44;
01243 p[1] = 0x41;
01244 p[2] = 0;
01245 p[3] = 0;
01246 }
01247 return stamp;
01248 }
01249
01250 void MrcIO::swap_header(MrcHeader& mrch)
01251 {
01252 ByteOrder::swap_bytes((int *) &mrch, NUM_4BYTES_PRE_MAP);
01253 ByteOrder::swap_bytes((int *) &mrch.machinestamp, NUM_4BYTES_AFTER_MAP);
01254 }
01255
01256 int MrcIO::get_nimg()
01257 {
01258 init();
01259
01260 return 1;
01261 }
01262
01263 int MrcIO::transpose(float *data, int xlen, int ylen, int zlen) const
01264 {
01265 float * tmp = new float[xlen*ylen];
01266
01267 for(size_t z=0; z<(size_t)zlen; ++z) {
01268 for(size_t y=0; y<(size_t)ylen; ++y) {
01269 for(size_t x=0; x<(size_t)xlen; ++x) {
01270 tmp[x*ylen+y] = data[z*xlen*ylen+y*xlen+x];
01271 }
01272 }
01273 std::copy(tmp, tmp+xlen*ylen, data+z*xlen*ylen);
01274 }
01275
01276 delete [] tmp;
01277
01278 return 0;
01279 }