EMAN2
pifio.cpp
Go to the documentation of this file.
1/*
2 * Author: Steven Ludtke, 04/10/2003 (sludtke@bcm.edu)
3 * Copyright (c) 2000-2006 Baylor College of Medicine
4 *
5 * This software is issued under a joint BSD/GNU license. You may use the
6 * source code in this file under either license. However, note that the
7 * complete EMAN2 and SPARX software packages have some GPL dependencies,
8 * so you are responsible for compliance with the licenses of these packages
9 * if you opt to use BSD licensing. The warranty disclaimer below holds
10 * in either instance.
11 *
12 * This complete copyright notice must be included in any revised version of the
13 * source code. Additional authorship citations may be added, but existing
14 * author citations must be preserved.
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 *
30 * */
31
32#include "pifio.h"
33#include "portable_fileio.h"
34#include "geometry.h"
35#include "imageio.h"
36#include <cstring>
37
38#ifdef WIN32
39#include <time.h>
40#endif
41
42using namespace EMAN;
43
44PifIO::PifIO(const string & fname, IOMode rw)
45: ImageIO(fname, rw)
46{
47 file = 0;
48 mode_size = 0;
51 is_new_file = false;
52 memset(&pfh, 0, sizeof(PifFileHeader));
53}
54
56{
57 if (file) {
58 fclose(file);
59 file = 0;
60 }
61}
62
63
65{
66 int size = 0;
67
68 switch (mode) {
69 case PIF_CHAR:
70 case PIF_BOXED_DATA:
71 size = sizeof(char);
72 break;
73 case PIF_SHORT:
74 case PIF_SHORT_FLOAT:
78 size = sizeof(short);
79 break;
80 case PIF_FLOAT:
82 size = sizeof(float);
83 break;
84 case PIF_FLOAT_INT:
89 size = sizeof(int);
90 break;
91 default:
92 break;
93 }
94 return size;
95}
96
98{
99 PifDataMode mode = static_cast < PifDataMode > (m);
100 switch (mode) {
101 case PIF_SHORT_FLOAT:
103 //case PIF_FLOAT:
104 case PIF_FLOAT_INT:
105 //case PIF_FLOAT_COMPLEX:
111 return true;
112 default:
113 break;
114 }
115 return false;
116}
117
118void PifIO::init()
119{
120 ENTERFUNC;
121 if (initialized) {
122 return;
123 }
124
125 initialized = true;
127
128 if (!is_new_file) {
129 if (fread(&pfh, sizeof(PifFileHeader), 1, file) != 1) {
130 throw ImageReadException(filename, "PIF file header");
131 }
132
133 if (!is_valid(&pfh)) {
134 throw ImageReadException(filename, "invalid PIF file");
135 }
136
139
140 if (pfh.htype != 1) {
141 string desc = "only support PIF with all projects having the same dimensions";
142 throw ImageReadException(filename, desc);
143 }
144
150
151 if (is_float_int(pfh.mode)) {
152 real_scale_factor = (float) atof(pfh.scalefactor);
153 }
154
155 mode_size = get_mode_size(static_cast < PifDataMode > (pfh.mode));
156
157 if (is_complex_mode()) {
158 pfh.nx *= 2;
159 }
160 }
161 EXITFUNC;
162}
163
164bool PifIO::is_valid(const void *first_block)
165{
166 ENTERFUNC;
167 bool result = false;
168
169 if (first_block) {
170 const int *data = static_cast < const int *>(first_block);
171 int m1 = data[0];
172 int m2 = data[1];
173 int endian = data[7];
174 bool data_big_endian = false;
175 if (endian) {
176 data_big_endian = true;
177 }
178
179 if (data_big_endian != ByteOrder::is_host_big_endian()) {
182 }
183
184 if (m1 == PIF_MAGIC_NUM && m2 == PIF_MAGIC_NUM) {
185 result = true;
186 }
187 }
188
189 EXITFUNC;
190 return result;
191}
192
193void PifIO::fseek_to(int image_index)
194{
195 int pih_sz = sizeof(PifImageHeader);
196 int image_size = 0;
197
198#if 0
199 // this works for some images that PURDUE people gave to me.
200 // But those images don't follow the PIF specification. So
201 // I believe they are in wrong format.
202 if (pfh.nimg == 1) {
203 image_size = pfh.nx * pfh.ny * pfh.nz;
204 }
205 else {
206 image_size = pfh.nx * pfh.ny;
207 }
208#endif
209 image_size = pfh.nx * pfh.ny * pfh.nz;
210
211 size_t file_offset = sizeof(PifFileHeader) +
212 (pih_sz + image_size * mode_size) * image_index;
213
214 portable_fseek(file, file_offset, SEEK_SET);
215}
216
217
218int PifIO::read_header(Dict & dict, int image_index, const Region * area, bool)
219{
220 ENTERFUNC;
221
222 check_read_access(image_index);
223 fseek_to(image_index);
224
225 int pih_sz = sizeof(PifImageHeader);
226 PifImageHeader pih;
227
228 if (fread(&pih, pih_sz, 1, file) != 1) {
229 throw ImageReadException(filename, "PIF Image header");
230 }
231 else {
232 check_region(area, FloatSize(pih.nx, pih.ny, pih.nz), is_new_file);
233 int xlen = 0, ylen = 0, zlen = 0;
234 EMUtil::get_region_dims(area, pih.nx, &xlen, pih.ny, &ylen, pih.nz, &zlen);
235
236 dict["nx"] = xlen;
237 dict["ny"] = ylen;
238 dict["nz"] = zlen;
239
240 dict["datatype"] = to_em_datatype(pih.mode);
241
242 dict["apix_x"] = static_cast < float >(pih.xlen);
243 dict["apix_y"] = static_cast < float >(pih.ylen);
244 dict["apix_z"] = static_cast < float >(pih.zlen);
245
246 dict["minimum"] = static_cast < float >(pih.min);
247 dict["maximum"] = static_cast < float >(pih.max);
248 dict["mean"] = static_cast < float >(pih.mean);
249 dict["sigma"] = static_cast < float >(pih.sigma);
250
251 dict["origin_x"] = static_cast < float >(pih.xorigin);
252 dict["origin_y"] = static_cast < float >(pih.yorigin);
253 }
254
255 EXITFUNC;
256
257 return 0;
258}
259
260int PifIO::write_header(const Dict & dict, int image_index, const Region* area,
261 EMUtil::EMDataType, bool)
262{
263 ENTERFUNC;
264
265 if(image_index<0) {
266 image_index = get_nimg();
267 }
268
269 check_write_access(rw_mode, image_index);
270
271 if (area) {
273 EXITFUNC;
274 return 0;
275 }
276
277 time_t t0 = time(0);
278 struct tm *t = localtime(&t0);
279
280 if (!is_new_file) {
282 throw ImageWriteException(filename, "writing to opposite byteorder file");
283 }
284
285 int nx1 = dict["nx"];
286 int ny1 = dict["ny"];
287 int nz1 = dict["nz"];
288
289 int mode1 = to_pif_datatype(dict["datatype"]);
290
291 if (nx1 != pfh.nx || ny1 != pfh.ny || nz1 != pfh.nz) {
292 LOGERR("cannot write to different size file %s (%dx%dx%d != %dx%dx%d)",
293 filename.c_str(), nx1, ny1, nz1, pfh.nx, pfh.ny, pfh.nz);
294 throw ImageWriteException(filename, "different image size");
295 }
296
297 if (mode1 != pfh.mode) {
298 throw ImageWriteException(filename, "different data type");
299 }
300
301 fseek_to(image_index);
302 }
303 else {
306 sprintf(pfh.scalefactor, "1.0");
307
309 sprintf(pfh.program, "EMAN %d/%02d/%02d", t->tm_mon, t->tm_mday, t->tm_year);
310
311 pfh.htype = 1;
312 pfh.nx = dict["nx"];
313 pfh.ny = dict["ny"];
314 pfh.nz = dict["nz"];
315 pfh.nimg += 1;
317 fwrite(&pfh, sizeof(PifFileHeader), 1, file);
318 }
319
320 PifImageHeader pih;
321 memset(&pih, 0, sizeof(PifImageHeader));
322 pih.nx = dict["nx"];
323 pih.ny = dict["ny"];
324 pih.nz = dict["nz"];
325
326 pih.mode = PIF_FLOAT;
327 pih.xlen = dict["apix_x"];
328 pih.ylen = dict["apix_y"];
329 pih.zlen = dict["apix_z"];
330 pih.alpha = 90;
331 pih.beta = 90;
332 pih.gamma = 90;
333 pih.mapc = 1;
334 pih.mapr = 2;
335 pih.maps = 3;
336 pih.min = dict["minimum"];
337 pih.max = dict["maximum"];
338 pih.mean = dict["mean"];
339 pih.sigma = dict["sigma"];
340
341 pih.xorigin = dict["origin_x"];
342 pih.yorigin = dict["origin_y"];
343
344 sprintf(pih.time, "%d/%02d/%02d %d:%02d",
345 t->tm_mon, t->tm_mday, t->tm_year, t->tm_hour, t->tm_min);
346 fwrite(&pih, sizeof(PifImageHeader), 1, file);
347
348 EXITFUNC;
349 return 0;
350}
351
352int PifIO::read_data(float *data, int image_index, const Region *area, bool)
353{
354 ENTERFUNC;
355
356 check_read_access(image_index, data);
357 fseek_to(image_index);
358
359 int pih_sz = sizeof(PifImageHeader);
360 PifImageHeader pih;
361
362 if (fread(&pih, pih_sz, 1, file) != 1) {
363 throw ImageReadException(filename, "PIF Image header");
364 }
365
366 if (area) {
367 check_region(area, FloatSize(pih.nx, pih.ny, pih.nz), is_new_file);
368 }
369
370 PifDataMode data_mode = static_cast < PifDataMode > (pih.mode);
371 int num_layers = pih.nz;
372#if 0
373 if (pfh.nz == pfh.nimg) {
374 num_layers = 1;
375 }
376#endif
377 // new way to read PIF data. The new way includes region reading.
378 // If it is tested to be OK, remove the code in #if 0 ... #endif
379 unsigned char * cdata = (unsigned char*)data;
380 short *sdata = (short*) data;
381
383 0, mode_size, pih.nx, pih.ny,
384 num_layers, area);
385
386 int xlen = 0, ylen = 0, zlen = 0;
387 EMUtil::get_region_dims(area, pih.nx, &xlen, pih.ny, &ylen, pih.nz, &zlen);
388 size_t size = xlen * ylen * zlen;
389
390 if(data_mode == PIF_FLOAT || data_mode == PIF_FLOAT_COMPLEX)
391 {
392 become_host_endian< float >(data, size);
393 }
394 else {
395 if (mode_size == sizeof(short)) {
396 become_host_endian((short *) sdata, size);
397 }
398 else if (mode_size == sizeof(int)) {
399 become_host_endian((int *) data, size);
400 }
401
402 if (mode_size == sizeof(char)) {
403 for (size_t i = 0; i < size; i++) {
404 size_t j = size - 1 - i;
405 data[j] = (float)(cdata[j]) * real_scale_factor;
406 }
407 }
408 else if (mode_size == sizeof(short)) {
409 for (size_t i = 0; i < size; i++) {
410 size_t j = size - 1 - i;
411 data[j] = (float)(sdata[j]) * real_scale_factor;
412 }
413 }
414 else if (mode_size == sizeof(int)) {
415 for (size_t i = 0; i < size; i++) {
416 size_t j = size - 1 - i;
417 data[j] = (float) ((int *)data)[j] * real_scale_factor;
418 }
419 }
420 }
421
422 // end of new way for region reading
423
424#if 0
425 int buf_size = pih.nx * mode_size;
426 unsigned char *buf = new unsigned char[buf_size];
427
428 for (int l = 0; l < num_layers; l++) {
429 int offset1 = l * pfh.nx * pfh.ny;
430 for (int j = 0; j < pfh.ny; j++) {
431 if (fread(buf, mode_size, pfh.nx, file) != (unsigned int) pfh.nx) {
432 if( buf )
433 {
434 delete[]buf;
435 buf = 0;
436 }
437 throw ImageReadException(filename, "incomplete PIF read");
438 }
439
440 if (mode_size == sizeof(short)) {
441 become_host_endian((short *) buf, pfh.nx);
442 }
443 else if (mode_size == sizeof(int)) {
444 become_host_endian((int *) buf, pfh.nx);
445 }
446
447 int offset2 = offset1 + j * pfh.nx;
448
449 for (int k = 0; k < pfh.nx; k++) {
450 float curr_data = 0;
451
452 if (mode_size == sizeof(char)) {
453 curr_data = (float) buf[k];
454 }
455 else if (mode_size == sizeof(short)) {
456 curr_data = (float) ((short *) buf)[k];
457 }
458 else if (mode_size == sizeof(int)) {
459 curr_data = (float) ((int *) buf)[k];
460 }
461 data[offset2 + k] = curr_data * real_scale_factor;
462 }
463 }
464 }
465 if( buf )
466 {
467 delete[]buf;
468 buf = 0;
469 }
470#endif
471 EXITFUNC;
472 return 0;
473}
474
475
476int PifIO::write_data(float *data, int image_index, const Region* area,
477 EMUtil::EMDataType, bool)
478{
479 ENTERFUNC;
480
481 check_write_access(rw_mode, image_index, 0, data);
482 fseek_to(image_index);
483
484 int nx = pfh.nx;
485 int ny = pfh.ny;
486 int nz = pfh.nz;
487
488 check_region(area, FloatSize(nx, ny, nz), is_new_file);
489
490 // to write a region; if it works, please remove the code
491 // in #if 0 ... #endif
493 mode_size, nx, ny, nz, area);
494
495#if 0
496 size_t idx;
497 int *buf = new int[nx];
498 for (int i = 0; i < nz; i++) {
499 for (int j = 0; j < ny; j++) {
500 for (int k = 0; k < pfh.nx; k++) {
501 idx = i * nx * ny + j * nx + k;
502 buf[k] = (int) data[idx];
503 }
504 fwrite(buf, sizeof(int) * nx, 1, file);
505 }
506 }
507 if( buf )
508 {
509 delete[]buf;
510 buf = 0;
511 }
512#endif
513
514 EXITFUNC;
515 return 0;
516}
517
518void PifIO::flush()
519{
520 fflush(file);
521}
522
524{
525 init();
526 if (pfh.mode == PIF_SHORT_COMPLEX ||
529 return true;
530 }
531 return false;
532}
533
535{
536 init();
537 return is_big_endian;
538}
539
541{
542 init();
543 return pfh.nimg;
544}
545
546
548{
549 PifDataMode mode = static_cast < PifDataMode > (p);
551
552 switch (mode) {
553 case PIF_CHAR:
554 case PIF_BOXED_DATA:
555 e = EMUtil::EM_CHAR;
556 break;
557
558 case PIF_SHORT:
559 case PIF_SHORT_FLOAT:
562 break;
563
567 break;
568
569 case PIF_FLOAT:
570 case PIF_FLOAT_INT:
575 break;
579 break;
580 case PIF_INVALID:
582 break;
583 }
584 return e;
585}
586
588{
590
591 switch (e) {
592 case EMUtil::EM_CHAR:
593 m = PIF_BOXED_DATA;
594 break;
595 case EMUtil::EM_SHORT:
596 m = PIF_SHORT;
597 break;
600 break;
601 case EMUtil::EM_FLOAT:
602 m = PIF_FLOAT_INT;
603 break;
606 break;
607 default:
608 LOGERR("unknown PIF mode: %d", e);
609 }
610
611 return m;
612}
static bool is_host_big_endian()
Definition: byteorder.cpp:40
static void swap_bytes(T *data, size_t n=1)
swap the byte order of data with 'n' T-type elements.
Definition: byteorder.h:131
static bool is_data_big_endian(const T *small_num_addr)
given a pointer to a reasonable small integer number, return whether the number is big endian or not.
Definition: byteorder.h:76
Dict is a dictionary to store <string, EMObject> pair.
Definition: emobject.h:385
static void process_region_io(void *cdata, FILE *file, int rw_mode, int image_index, size_t mode_size, int nx, int ny, int nz=1, const Region *area=0, bool need_flip=false, ImageType imgtype=IMAGE_UNKNOWN, int pre_row=0, int post_row=0)
Process image region IO.
Definition: emutil.cpp:931
EMDataType
Image pixel data type used in EMAN.
Definition: emutil.h:92
@ EM_UNKNOWN
Definition: emutil.h:93
@ EM_FLOAT_COMPLEX
Definition: emutil.h:104
@ EM_SHORT_COMPLEX
Definition: emutil.h:102
@ EM_SHORT
Definition: emutil.h:96
static void get_region_dims(const Region *area, int nx, int *area_x, int ny, int *area_y, int nz=1, int *area_z=0)
Get a region's dimensions.
Definition: emutil.cpp:860
FloatSize is used to describe a 1D, 2D or 3D rectangular size in floating numbers.
Definition: geometry.h:105
ImageIO classes are designed for reading/writing various electron micrography image formats,...
Definition: imageio.h:127
IOMode rw_mode
Definition: imageio.h:353
void check_region(const Region *area, const FloatSize &max_size, bool is_new_file=false, bool inbounds_only=true)
Validate image I/O region.
Definition: imageio.cpp:58
virtual void flush()=0
Flush the IO buffer.
virtual int write_header(const Dict &dict, int image_index=0, const Region *area=0, EMUtil::EMDataType filestoragetype=EMUtil::EM_FLOAT, bool use_host_endian=true)=0
Write a header to an image.
bool initialized
Definition: imageio.h:355
virtual int write_data(float *data, int image_index=0, const Region *area=0, EMUtil::EMDataType filestoragetype=EMUtil::EM_FLOAT, bool use_host_endian=true)=0
Write data to an image.
virtual bool is_complex_mode()=0
Is this an complex image or not.
virtual int read_header(Dict &dict, int image_index=0, const Region *area=0, bool is_3d=false)=0
Read the header from an image.
FILE * sfopen(const string &filename, IOMode mode, bool *is_new=0, bool overwrite=false)
Run fopen safely.
Definition: imageio.cpp:135
void check_read_access(int image_index)
Validate 'image_index' in file reading.
Definition: imageio.cpp:95
virtual int read_data(float *data, int image_index=0, const Region *area=0, bool is_3d=false)=0
Read the data from an image.
FILE * file
Definition: imageio.h:354
virtual void init()=0
Do some initialization before doing the read/write.
void check_write_access(IOMode rw_mode, int image_index, int max_nimg=0)
Validate rw_mode and image_index in file writing.
Definition: imageio.cpp:113
void become_host_endian(T *data, size_t n=1)
Convert data of this image into host endian format.
Definition: imageio.h:261
virtual bool is_image_big_endian()=0
Is this image in big endian or not.
int mode_size
Definition: pifio.h:176
@ PIF_MAGIC_NUM
Definition: pifio.h:70
bool is_float_int(int mode)
Definition: pifio.cpp:97
string filename
Definition: pifio.h:174
int get_mode_size(PifDataMode mode)
Definition: pifio.cpp:64
bool is_new_file
Definition: pifio.h:178
int get_nimg()
Return the number of images in this image file.
Definition: pifio.cpp:540
static bool is_valid(const void *first_block)
Definition: pifio.cpp:164
PifFileHeader pfh
Definition: pifio.h:175
int to_em_datatype(int pif_datatype)
Definition: pifio.cpp:547
PifDataMode
Definition: pifio.h:74
@ PIF_FLOAT_INT
Definition: pifio.h:77
@ PIF_SHORT
Definition: pifio.h:76
@ PIF_SHORT_COMPLEX
Definition: pifio.h:78
@ PIF_FLOAT_COMPLEX
Definition: pifio.h:84
@ PIF_MAP_FLOAT_SHORT
Definition: pifio.h:85
@ PIF_BOXED_FLOAT_INT
Definition: pifio.h:88
@ PIF_SHORT_FLOAT
Definition: pifio.h:81
@ PIF_FLOAT
Definition: pifio.h:83
@ PIF_BOXED_DATA
Definition: pifio.h:80
@ PIF_MAP_FLOAT_INT
Definition: pifio.h:86
@ PIF_CHAR
Definition: pifio.h:75
@ PIF_INVALID
Definition: pifio.h:89
@ PIF_MAP_FLOAT_INT_2
Definition: pifio.h:87
@ PIF_FLOAT_INT_COMPLEX
Definition: pifio.h:79
@ PIF_SHORT_FLOAT_COMPLEX
Definition: pifio.h:82
bool is_big_endian
Definition: pifio.h:177
void fseek_to(int image_index)
Definition: pifio.cpp:193
int to_pif_datatype(int em_datatype)
Definition: pifio.cpp:587
float real_scale_factor
Definition: pifio.h:179
Region defines a 2D or 3D rectangular region specified by its origin coordinates and all edges' sizes...
Definition: geometry.h:497
#define ImageReadException(filename, desc)
Definition: exception.h:204
#define ImageWriteException(imagename, desc)
Definition: exception.h:223
#define LOGERR
Definition: log.h:51
#define ENTERFUNC
Definition: log.h:48
#define EXITFUNC
Definition: log.h:49
E2Exception class.
Definition: aligner.h:40
int portable_fseek(FILE *fp, off_t offset, int whence)