EMAN2
emio.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 "emio.h"
33#include "portable_fileio.h"
34#include "geometry.h"
35
36using namespace EMAN;
37
38EmIO::EmIO(const string & fname, IOMode rw)
39: ImageIO(fname, rw)
40{
41 mode_size = 0;
44 is_new_file = false;
45 memset(&emh, 0, sizeof(EMHeader));
46}
47
49{
50 if (file) {
51 fclose(file);
52 file = 0;
53 }
54}
55
56void EmIO::init()
57{
59
60 if (initialized) {
61 return;
62 }
63
64
65 initialized = true;
67
68 if (!is_new_file) {
69 if (fread(&emh, sizeof(EMHeader), 1, file) != 1) {
70 throw ImageReadException(filename, "EM header");
71 }
72 if (!is_valid(&emh)) {
73 throw ImageReadException(filename, "invalid EM image");
74 }
75
80
82
83 if (mode == EM_EM_DOUBLE) {
84 throw ImageReadException(filename, "DOUBLE data type not supported for EM image");
85 }
86
88 if (is_complex_mode()) {
89 emh.nx *= 2;
90 }
91 }
93}
94
95bool EmIO::is_valid(const void *first_block, off_t file_size)
96{
98
99 if (!first_block) {
100 return false;
101 }
102
103 const char *data = static_cast < const char *>(first_block);
104 char machine = data[0];
105 char is_new_ver = data[1];
106 char data_type = data[3];
107
108 const int *data1 = static_cast < const int *>(first_block);
109 int nx = data1[1];
110 int ny = data1[2];
111 int nz = data1[3];
112
113 bool data_big_endian = ByteOrder::is_data_big_endian(&nz);
114 if (data_big_endian != ByteOrder::is_host_big_endian()) {
118 }
119
120 const int max_dim = 1 << 20;
121
122 if (((int) machine >= EM_OS8 && machine <= EM_PC) &&
123 (is_new_ver == 0 || is_new_ver == 1) &&
124 (data_type >= EM_EM_CHAR && data_type <= EM_EM_DOUBLE) &&
125 (nx > 1 && nx < max_dim) && (ny > 0 && ny < max_dim) && (nz > 0 && nz < max_dim)) {
126 if (file_size > 0) {
127 off_t file_size1 = (off_t)nx * (off_t)ny * (off_t)nz * (off_t)get_mode_size(data_type) + (off_t)sizeof(EMHeader);
128 if (file_size == file_size1) {
129 return true;
130 }
131 }
132 else {
133 return true;
134 }
135 }
136
137 return false;
138}
139
140int EmIO::read_header(Dict & dict, int image_index, const Region * area, bool)
141{
142 ENTERFUNC;
143 //single image format, index can only be zero
144 if(image_index == -1) {
145 image_index = 0;
146 }
147
148 if(image_index != 0) {
149 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().");
150 }
151
152 init();
153 check_region(area, IntSize(emh.nx, emh.ny, emh.nz),false,false);
154
155 int xlen = 0, ylen = 0, zlen = 0;
156 EMUtil::get_region_dims(area, emh.nx, &xlen, emh.ny, &ylen, emh.nz, &zlen);
157 dict["nx"] = xlen;
158 dict["ny"] = ylen;
159 dict["nz"] = zlen;
160 dict["datatype"] = to_em_datatype(emh.data_type);
161 EXITFUNC;
162 return 0;
163}
164
165int EmIO::write_header(const Dict & dict, int image_index, const Region* area,
166 EMUtil::EMDataType, bool)
167{
168 ENTERFUNC;
169 //single image format, index can only be zero
170 if(image_index == -1) {
171 image_index = 0;
172 }
173 if(image_index != 0) {
174 throw ImageWriteException(filename, "EM file does not support stack.");
175 }
176 check_write_access(rw_mode, image_index, 1);
177 if (area) {
179 EXITFUNC;
180 return 0;
181 }
182
183 emh.machine = static_cast < char >(get_machine_type());
184 emh.nx = dict["nx"];
185 emh.ny = dict["ny"];
186 emh.nz = dict["nz"];
188
189 rewind(file);
190 if (fwrite(&emh, sizeof(EMHeader), 1, file) != 1) {
191 throw ImageWriteException(filename, "EM Header");
192 }
193
194 EXITFUNC;
195 return 0;
196}
197
198int EmIO::read_data(float *data, int image_index, const Region * area, bool)
199{
200 ENTERFUNC;
201
202 //single image format, index can only be zero
203 image_index = 0;
204 check_read_access(image_index, data);
205 check_region(area, IntSize(emh.nx, emh.ny, emh.nz),false,false);
206
207 portable_fseek(file, sizeof(EMHeader), SEEK_SET);
208
209 unsigned char *cdata = (unsigned char *) data;
211 emh.nx, emh.ny, emh.nz, area);
212
213 int xlen = 0, ylen = 0, zlen = 0;
214 EMUtil::get_region_dims(area, emh.nx, &xlen, emh.ny, &ylen, emh.nz, &zlen);
215
216 int total_sz = xlen * ylen * zlen;
217
218 if (mode_size == sizeof(short)) {
219 become_host_endian((short *) cdata, total_sz);
220 }
221 else if (mode_size == sizeof(int)) {
222 become_host_endian((int *) cdata, total_sz);
223 }
224 else if (mode_size == sizeof(double)) {
225 throw ImageReadException(filename, "double type image is not supported");
226 }
227
228 for (int k = total_sz - 1; k >= 0; k--) {
229 float curr_data = 0;
230
231 if (mode == EM_EM_CHAR) {
232 curr_data = static_cast < float >(cdata[k]);
233 }
234 else if (mode == EM_EM_SHORT) {
235 curr_data = static_cast < float >(((short *) cdata)[k]);
236 }
237 else if (mode == EM_EM_INT) {
238 curr_data = static_cast < float >(((int *) cdata)[k]);
239 }
240 else if (mode == EM_EM_FLOAT || mode == EM_EM_COMPLEX) {
241 curr_data = ((float *) cdata)[k];
242 }
243 else if (mode_size == sizeof(double)) {
244 throw ImageReadException(filename, "double type image is not supported");
245 }
246
247 data[k] = curr_data;
248 }
249
250 EXITFUNC;
251 return 0;
252}
253
254int EmIO::write_data(float *data, int image_index, const Region* area, EMUtil::EMDataType, bool)
255{
256 ENTERFUNC;
257 //single image format, index can only be zero
258 image_index = 0;
259 check_write_access(rw_mode, image_index, 1, data);
260 portable_fseek(file, sizeof(EMHeader), SEEK_SET);
261
263 image_index, sizeof(float),
264 emh.nx, emh.ny, emh.nz, area);
265#if 0
266 int sec_size = emh.nx * emh.ny;
267 int row_size = sizeof(float) * emh.nx;
268
269 for (int i = 0; i < emh.nz; i++) {
270 int k = i * sec_size;
271 for (int j = 0; j < emh.ny; j++) {
272 fwrite(&data[k + j * emh.nx], row_size, 1, file);
273 }
274 }
275#endif
276
277 EXITFUNC;
278 return 0;
279}
280
281void EmIO::flush()
282{
283 fflush(file);
284}
285
287{
288 init();
289 if (emh.data_type == EM_EM_COMPLEX) {
290 return true;
291 }
292 return false;
293}
294
296{
297 init();
298 return is_big_endian;
299}
300
301
303{
304 DataType type = static_cast < DataType > (t);
305 switch (type) {
306 case EM_EM_CHAR:
307 return EMUtil::EM_CHAR;
308 case EM_EM_SHORT:
309 return EMUtil::EM_SHORT;
310 case EM_EM_INT:
311 return EMUtil::EM_INT;
312 case EM_EM_FLOAT:
313 return EMUtil::EM_FLOAT;
314 case EM_EM_DOUBLE:
315 return EMUtil::EM_DOUBLE;
316 case EM_EM_COMPLEX:
318 default:
319 break;
320 }
321 return EMUtil::EM_UNKNOWN;
322}
323
325{
326 int m = EM_UNKNOWN_MACHINE;
327#ifdef __sgi
328 m = EM_SGI;
329#elif defined __linux__
330 m = EM_PC;
331#elif defined __CYGWIN__
332 m = EM_PC;
333#elif defined WIN32
334 m = EM_PC;
335#elif defined MACOS
336 m = EM_MAC;
337#elif defined macintosh
338 m = EM_MAC;
339#elif defined __darwin__
340 m = EM_MAC;
341#elif defined __APPLE__
342 m = EM_MAC;
343#else
345#endif
346 return m;
347}
348
349size_t EmIO::get_mode_size(char data_type)
350{
351 int mode = (int) data_type;
352 switch (mode) {
353 case EM_EM_CHAR:
354 return sizeof(char);
355 case EM_EM_SHORT:
356 return sizeof(short);
357 case EM_EM_INT:
358 case EM_EM_FLOAT:
359 case EM_EM_COMPLEX:
360 return sizeof(int);
361 case EM_EM_DOUBLE:
362 return sizeof(double);
363 }
364 return 0;
365}
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
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
DataType
Definition: emio.h:74
@ EM_EM_UNKNOWN
Definition: emio.h:81
@ EM_EM_CHAR
Definition: emio.h:75
@ EM_EM_FLOAT
Definition: emio.h:78
@ EM_EM_COMPLEX
Definition: emio.h:79
@ EM_EM_SHORT
Definition: emio.h:76
@ EM_EM_DOUBLE
Definition: emio.h:80
@ EM_EM_INT
Definition: emio.h:77
static size_t get_mode_size(char data_type)
Definition: emio.cpp:349
static int get_machine_type()
Definition: emio.cpp:324
@ EM_SGI
Definition: emio.h:89
@ EM_UNKNOWN_MACHINE
Definition: emio.h:92
@ EM_PC
Definition: emio.h:91
@ EM_OS8
Definition: emio.h:86
@ EM_MAC
Definition: emio.h:90
static bool is_valid(const void *first_block, off_t file_size=0)
Definition: emio.cpp:95
static int to_em_datatype(char t)
Definition: emio.cpp:302
EMHeader emh
Definition: emio.h:96
size_t mode_size
Definition: emio.h:98
DataType mode
Definition: emio.h:99
bool is_new_file
Definition: emio.h:101
bool is_big_endian
Definition: emio.h:100
~EmIO()
Definition: emio.cpp:48
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
string filename
Definition: imageio.h:352
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.
IntSize is used to describe a 1D, 2D or 3D rectangular size in integers.
Definition: geometry.h:49
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 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)