EMAN2
serio.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 "serio.h"
33#include "util.h"
34#include "portable_fileio.h"
35
36#include <cassert>
37
38using namespace EMAN;
39
40static const short SER_BYTE_ORDER = 0x4949;
41static const short SER_SERIES_ID = 0x0197;
42//static const short SER_SERIES_VERSION = 0x0210; // can also be 0x220 now
43static const int ValidNumberElementsOffset = 18; //the offset to ValidNumberElements, which is the number of images in the file
44
45SerIO::SerIO(const string & fname, IOMode rw) :
46 ImageIO(fname, rw),
47 is_new_file(false), data_offset_array(0),tag_offset_array(0),
48 nimg(0), nx(0), ny(0), nz(0), datatypeid(0), datamode(0)
49{
50}
51
53{
54 if (file) {
55 fclose(file);
56 file = 0;
57 }
58
60 delete [] data_offset_array;
62 }
63
64 if (tag_offset_array) {
65 delete [] tag_offset_array;
67 }
68}
69
70void SerIO::init()
71{
73
74 if (initialized) {
75 return;
76 }
77
78 initialized = true;
80
81 if (!is_new_file) {
82 if (fread(&serh, sizeof(SerHeader), 1, file) != 1) {
83 throw ImageReadException(filename, "SER header");
84 }
85
86 if (!is_valid(&serh)) {
87 throw ImageReadException(filename, "invalid SER");
88 }
89 }
90
92}
93
94bool SerIO::is_valid(const void *first_block)
95{
97
98 if (!first_block) {
99 return false;
100 }
101
102 const short *data = static_cast < const short *>(first_block);
103 short ByteOrder = data[0];
104 short SeriesID = data[1];
105
106 if(ByteOrder != 0x4949 || SeriesID != 0x0197) {
107 return false;
108 }
109
110 EXITFUNC;
111 return true;
112}
113
114int SerIO::read_header(Dict & dict, int image_index, const Region * area, bool is_3d)
115{
116 ENTERFUNC;
117 init();
118 rewind(file);
119
120 short hitem1[3];
121 if (fread(hitem1, sizeof(short), 3, file) != 3) {
122 throw ImageReadException(filename, "SER header");
123 }
124
125 dict["SER.ByteOrder"] = hitem1[0];
126 dict["SER.SeriesID"] = hitem1[1];
127 dict["SER.SeriesVersion"] = hitem1[2];
128
129 if((hitem1[0]!=SER_BYTE_ORDER) || (hitem1[1]!=SER_SERIES_ID) || (hitem1[2]!=0x210 && hitem1[2]!=0x220) ) {
130 throw ImageReadException(filename, "SER header");
131 }
132 int hitem2[6];
133 uint64_t offset_array;
134 if (hitem1[2]==0x210) {
135 if (fread(hitem2, sizeof(int), 6, file) != 6) {
136 throw ImageReadException(filename, "SER header");
137 }
138 dict["SER.OffsetArrayOffset"] = hitem2[4];
139 offset_array=(uint64_t)hitem2[4];
140 }
141 else {
142 if (fread(hitem2, sizeof(int), 4, file) != 4) {
143 throw ImageReadException(filename, "SER header");
144 }
145 fread(&offset_array, 8,1,file);
146 fread(&hitem2[5],4,1,file);
147 }
148
149
150
151 dict["SER.DataTypeID"] = hitem2[0];
152 dict["SER.TagTypeID"] = hitem2[1];
153 dict["SER.TotalNumberElements"] = hitem2[2];
154 dict["SER.ValidNumberElements"] = hitem2[3];
155 dict["SER.NumberDimensions"] = hitem2[5];
156
157 nimg = (int)dict["SER.ValidNumberElements"];
158
159 if(image_index >= (int)dict["SER.ValidNumberElements"]) {
160 throw ImageReadException(filename, "Image index out of bound");
161 }
162
163 for(int idx=0; idx<(int)dict["SER.NumberDimensions"]; idx++) {
164 read_dim_arr(dict, idx);
165 }
166
167// long pos = ftell(serfile);
168// assert(pos == (int)dict["SER.OffsetArrayOffset"]);
169 portable_fseek(file,(off_t)offset_array,SEEK_SET);
170
171 int tot = (int)dict["SER.TotalNumberElements"];
172
173 data_offset_array = new uint64_t[tot];
174 tag_offset_array = new uint64_t[tot];
175 if (hitem1[2]==0x210) {
176 int *off=new int[tot*2];
177 if (fread(off, 4, tot*2, file) != (unsigned int)tot*2) {
178 throw ImageReadException(filename, "SER header");
179 }
180 for (int i=0; i<tot; i++) {
181 data_offset_array[i]=(uint64_t)off[i];
182 tag_offset_array[i]=(uint64_t)off[i+tot];
183 }
184 delete[] off;
185 }
186 else {
187 if (fread(data_offset_array, sizeof(uint64_t), tot, file) != (unsigned int)tot) {
188 throw ImageReadException(filename, "SER header");
189 }
190 if (fread(tag_offset_array, sizeof(uint64_t), tot, file) != (unsigned int)tot) {
191 throw ImageReadException(filename, "SER header");
192 }
193 }
194
195 this->datatypeid = (int)dict["SER.DataTypeID"];
196
197 off_t dataoffset = data_offset_array[image_index];
198 portable_fseek(file, dataoffset, SEEK_SET);
199
200 //To read the attribute in data element(not the actual data)
201 read_data_element(dict);
202
203 off_t tagoffset = tag_offset_array[image_index];
204 portable_fseek(file, tagoffset, SEEK_SET);
205
206 //To read the data tag appended after data values
207 read_data_tag(dict);
208
209 EXITFUNC;
210 return 0;
211}
212
213int SerIO::write_header(const Dict & dict, int image_index, const Region* area,
214 EMUtil::EMDataType filestoragetype, bool use_host_endian)
215{
216 ENTERFUNC;
217
218 throw ImageWriteException(filename, "SER Writing not supported");
219
220 EXITFUNC;
221 return 0;
222}
223
224int SerIO::read_data(float *rdata, int image_index, const Region *, bool )
225{
226 ENTERFUNC;
227
228 if(!data_offset_array) {
229 throw ImageReadException(filename, "SER header, empty DataOffsetarray");
230 }
231
232 size_t size = (size_t)nx * ny * nz;
233 off_t data_offset = data_offset_array[image_index];
234
235 size_t i; //loop index
236 unsigned char * puchar = 0;
237 char * pchar = 0;
238 int * pint = 0;
239 unsigned int * puint = 0;
240 short * pshort = 0;
241 unsigned short * pushort = 0;
242 double * pdouble = 0;
243 switch(this->datatypeid) {
244 case oneD:
245 portable_fseek(file, data_offset+26, SEEK_SET); //offset 26 to actual data values
246 break;
247 case twoD:
248 portable_fseek(file, data_offset+50, SEEK_SET); //offset 50 to actual data values
249 break;
250 default:
251 throw ImageReadException(filename, "SER header, wrong DataTypeID");
252 }
253
254 switch(this->datamode) {
255 case SER_UCHAR:
256 puchar = new unsigned char[size];
257 if (fread(puchar, sizeof(unsigned char), size, file) != size) {
258 throw ImageReadException(filename, "SER data");
259 }
260 for (i = 0; i<size; ++i) {
261 rdata[i] = static_cast<float>(puchar[i]);
262 }
263 delete [] puchar;
264 break;
265 case SER_USHORT:
266 pushort = new unsigned short[size];
267 if (fread(pushort, sizeof(unsigned short), size, file) != size) {
268 throw ImageReadException(filename, "SER data");
269 }
270 for (i = 0; i<size; ++i) {
271 rdata[i] = static_cast<float>(pushort[i]);
272 }
273 delete [] pushort;
274 break;
275 case SER_UINT:
276 puint = new unsigned int[size];
277 if (fread(puint, sizeof(unsigned int), size, file) != size) {
278 throw ImageReadException(filename, "SER data");
279 }
280 for (i = 0; i<size; ++i) {
281 rdata[i] = static_cast<float>(puint[i]);
282 }
283 delete [] puint;
284 break;
285 case SER_CHAR:
286 pchar = new char[size];
287 if (fread(pchar, sizeof(unsigned char), size, file) != size) {
288 throw ImageReadException(filename, "SER data");
289 }
290 for (i = 0; i<size; ++i) {
291 rdata[i] = static_cast<float>(pchar[i]);
292 }
293 delete [] pchar;
294 break;
295 case SER_SHORT:
296 pshort = new short[size];
297 if (fread(pshort, sizeof(short), size, file) != size) {
298 throw ImageReadException(filename, "SER data");
299 }
300 for (i = 0; i<size; ++i) {
301 rdata[i] = static_cast<float>(pshort[i]);
302 }
303 delete [] pshort;
304 break;
305 case SER_INT:
306 pint = new int[size];
307 if (fread(pint, sizeof(int), size, file) != size) {
308 throw ImageReadException(filename, "SER data");
309 }
310 for (i = 0; i<size; ++i) {
311 rdata[i] = static_cast<float>(pint[i]);
312 }
313 delete [] pint;
314 break;
315 case SER_FLOAT:
316 if (fread(rdata, sizeof(float), size, file) != size) {
317 throw ImageReadException(filename, "SER data");
318 }
319 break;
320 case SER_DOUBLE:
321 pdouble = new double[size];
322 if (fread(pdouble, sizeof(double), size, file) != size) {
323 throw ImageReadException(filename, "SER data");
324 }
325 for (i = 0; i<size; ++i) {
326 rdata[i] = static_cast<float>(pdouble[i]);
327 }
328 delete [] pdouble;
329 break;
330 case SER_COMPLEX8:
331 case SER_COMPLEX16:
332 throw ImageReadException(filename, "complex data not supported.");
333 break;
334 default:
335 throw ImageReadException(filename, "Unknown data value type");
336 }
337
338 EXITFUNC;
339 return 0;
340}
341
342int SerIO::write_data(float *data, int image_index, const Region* area,
343 EMUtil::EMDataType, bool use_host_endian)
344{
345 ENTERFUNC;
346
347 throw ImageWriteException(filename, "SER Writing not supported");
348
349 EXITFUNC;
350 return 0;
351}
352
354{
355 return false; //not support complex ser for now
356}
357
358void SerIO::flush()
359{
360 fflush(file);
361}
362
364{
365 return false; //ser image is always little endian
366}
367
369 init();
370
372 int nimg;
373 if (fread(&nimg, sizeof(int), 1, file) != 1) {
374 throw ImageReadException(filename, "SER header");
375 }
376
377 return nimg;
378}
379
380void SerIO::read_dim_arr(Dict & dict, int idx)
381{
382 int dimsize;
383 if (fread(&dimsize, sizeof(int), 1, file) != 1) {
384 throw ImageReadException(filename, "SER header");
385 }
386
387 string sidx = Util::int2str(idx);
388 dict["SER.DimensionSize"+sidx] = dimsize;
389
390 double hitem3[2];
391 if (fread(hitem3, sizeof(double), 2, file) != 2) {
392 throw ImageReadException(filename, "SER header");
393 }
394 dict["SER.CalibrationOffset"+sidx] = hitem3[0];
395 dict["SER.CalibrationDelta"+sidx] = hitem3[1];
396
397 int celement;
398 if (fread(&celement, sizeof(int), 1, file) != 1) {
399 throw ImageReadException(filename, "SER header");
400 }
401 dict["SER.CalibrationElement"+sidx] = celement;
402
403 int desclen;
404 if (fread(&desclen, sizeof(int), 1, file) != 1) {
405 throw ImageReadException(filename, "SER header");
406 }
407 dict["SER.DescriptionLength"+sidx] = desclen;
408
409 if(desclen != 0) {
410 char * descr = new char[desclen+1];
411 //char descr[desclen+1];
412 if (fread(descr, sizeof(char), desclen, file) != (unsigned int)desclen) {
413 throw ImageReadException(filename, "SER header");
414 }
415 descr[desclen] = '\0';
416 string sdescr(descr);
417 dict["SER.Description"+sidx] = sdescr;
418 delete [] descr;
419 }
420
421 int unitslen;
422 if (fread(&unitslen, sizeof(int), 1, file) != 1) {
423 throw ImageReadException(filename, "SER header");
424 }
425 dict["SER.UnitsLength"+sidx] = unitslen;
426
427 if(unitslen != 0) {
428 char * units = new char[unitslen+1];
429 //char units[unitslen+1];
430 if (fread(units, sizeof(int), unitslen, file) != (unsigned int)unitslen) {
431 throw ImageReadException(filename, "SER header");
432 }
433 units[unitslen] = '\0';
434 string sunits(units);
435 dict["SER.Units"+sidx] = sunits;
436 delete [] units;
437 }
438
439}
440
442{
443 if(this->datatypeid == oneD) { //1D image
444 double hitem4[2];
445 if (fread(hitem4, sizeof(double), 2, file) != 2) {
446 throw ImageReadException(filename, "SER header");
447 }
448 dict["SER.CalibrationOffset"] = hitem4[0];
449 dict["SER.CalibrationDelta"] = hitem4[1];
450
451 int cali;
452 if (fread(&cali, sizeof(int), 1, file) != 1) {
453 throw ImageReadException(filename, "SER header");
454 }
455 dict["SER.CalibrationElement"] = cali;
456
457 short datatype;
458 if (fread(&datatype, sizeof(short), 1, file) != 1) {
459 throw ImageReadException(filename, "SER header");
460 }
461 dict["SER.DataType"] = datatype;
462
463 int arrlen;
464 if (fread(&arrlen, sizeof(int), 1, file) != 1) {
465 throw ImageReadException(filename, "SER header");
466 }
467 dict["nx"] = arrlen;
468 dict["ny"] = 1;
469 dict["nz"] = 1;
470
471 nx = arrlen;
472 ny = 1;
473 nz = 1;
474 }
475 else if(this->datatypeid == twoD) { //2D image
476 double hitem4[2];
477 if (fread(hitem4, sizeof(double), 2, file) != 2) {
478 throw ImageReadException(filename, "SER header");
479 }
480 dict["SER.CalibrationOffsetX"] = hitem4[0];
481 dict["SER.CalibrationDeltaX"] = hitem4[1];
482
483 int calix;
484 if (fread(&calix, sizeof(int), 1, file) != 1) {
485 throw ImageReadException(filename, "SER header");
486 }
487 dict["SER.CalibrationElementX"] = calix;
488
489 double hitem5[2];
490 if (fread(hitem5, sizeof(double), 2, file) != 2) {
491 throw ImageReadException(filename, "SER header");
492 }
493 dict["SER.CalibrationOffsetX"] = hitem5[0];
494 dict["SER.CalibrationDeltaX"] = hitem5[1];
495
496 int caliy;
497 if (fread(&caliy, sizeof(int), 1, file) != 1) {
498 throw ImageReadException(filename, "SER header");
499 }
500 dict["SER.CalibrationElementY"] = caliy;
501
502 short datatype;
503 if (fread(&datatype, sizeof(short), 1, file) != 1) {
504 throw ImageReadException(filename, "SER header");
505 }
506 dict["SER.DataType"] = datatype;
507 this->datamode = datatype;
508
509 int arrsize[2];
510 if (fread(&arrsize, sizeof(int), 2, file) != 2) {
511 throw ImageReadException(filename, "SER header");
512 }
513 dict["nx"] = arrsize[0];
514 dict["ny"] = arrsize[1];
515 dict["nz"] = 1;
516
517 nx = arrsize[0];
518 ny = arrsize[1];
519 nz = 1;
520 }
521}
522
524{
525 int tag_type = (int)dict["SER.TagTypeID"];
526 if( tag_type == timeOnly ) {
527 short tagtype;
528 if (fread(&tagtype, sizeof(short), 1, file) != 1) {
529 throw ImageReadException(filename, "SER header");
530 }
531 assert((int)tagtype == tag_type);
532
533 int sertime;
534 if (fread(&sertime, sizeof(int), 1, file) != 1) {
535 throw ImageReadException(filename, "SER header");
536 }
537 dict["SER.Time"] = sertime;
538 }
539 else if( tag_type == posTime ) {
540 short tagtype;
541 if (fread(&tagtype, sizeof(short), 1, file) != 1) {
542 throw ImageReadException(filename, "SER header");
543 }
544 assert((int)tagtype == tag_type);
545
546 int sertime;
547 if (fread(&sertime, sizeof(int), 1, file) != 1) {
548 throw ImageReadException(filename, "SER header");
549 }
550 dict["SER.Time"] = sertime;
551
552 double pos[2];
553 if (fread(&pos, sizeof(double), 2, file) != 2) {
554 throw ImageReadException(filename, "SER header");
555 }
556 dict["SER.PosionX"] = pos[0];
557 dict["SER.PosionY"] = pos[1];
558 }
559 else {
560 throw ImageReadException(filename, "SER header, wrong TagTypeID");
561 }
562}
#define rdata(i)
Definition: analyzer.cpp:592
ByteOrder defines functions to work on big/little endian byte orders.
Definition: byteorder.h:59
Dict is a dictionary to store <string, EMObject> pair.
Definition: emobject.h:385
EMDataType
Image pixel data type used in EMAN.
Definition: emutil.h:92
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
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
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.
virtual bool is_image_big_endian()=0
Is this image in big endian or not.
Region defines a 2D or 3D rectangular region specified by its origin coordinates and all edges' sizes...
Definition: geometry.h:497
@ posTime
Definition: serio.h:73
@ timeOnly
Definition: serio.h:72
bool is_new_file
Definition: serio.h:104
void read_data_element(Dict &dict)
helper function to read header attributes in data element
Definition: serio.cpp:441
static bool is_valid(const void *first_block)
Definition: serio.cpp:94
@ twoD
Definition: serio.h:68
@ oneD
Definition: serio.h:67
void read_data_tag(Dict &dict)
helper function to read header attributes in data tag
Definition: serio.cpp:523
@ SER_COMPLEX16
Definition: serio.h:86
@ SER_USHORT
Definition: serio.h:78
@ SER_INT
Definition: serio.h:82
@ SER_CHAR
Definition: serio.h:80
@ SER_UCHAR
Definition: serio.h:77
@ SER_UINT
Definition: serio.h:79
@ SER_DOUBLE
Definition: serio.h:84
@ SER_FLOAT
Definition: serio.h:83
@ SER_SHORT
Definition: serio.h:81
@ SER_COMPLEX8
Definition: serio.h:85
int get_nimg()
Return the number of images in this image file.
Definition: serio.cpp:368
int datamode
Definition: serio.h:116
int datatypeid
Definition: serio.h:115
void read_dim_arr(Dict &dict, int idx)
helper function to read attributes in dimension array
Definition: serio.cpp:380
int nx
Definition: serio.h:112
uint64_t * data_offset_array
Definition: serio.h:108
int ny
Definition: serio.h:113
int nimg
Definition: serio.h:111
int nz
Definition: serio.h:114
uint64_t * tag_offset_array
Definition: serio.h:109
SerHeader serh
Definition: serio.h:106
static string int2str(int n)
Get a string format of an integer, e.g.
Definition: util.cpp:315
#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)
static const int ValidNumberElementsOffset
Definition: serio.cpp:43
static const short SER_BYTE_ORDER
Definition: serio.cpp:40
static const short SER_SERIES_ID
Definition: serio.cpp:41