EMAN2
amiraio.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#ifndef WIN32
33#include <sys/param.h>
34#else
35#include <windows.h>
36 #define MAXPATHLEN (MAX_PATH*4)
37#endif //WIN32
38
39#include <cstdio>
40
41#include "amiraio.h"
42#include "util.h"
43
44using namespace EMAN;
45
46const char *AmiraIO::MAGIC = "# AmiraMesh";
47
48AmiraIO::AmiraIO(const string & fname, IOMode rw)
49: ImageIO(fname, rw),
50 is_big_endian(true), dt(EMUtil::EM_UNKNOWN),
51 nx(0), ny(0), nz(0),
52 pixel(0), xorigin(0), yorigin(0), zorigin(0)
53{
54}
55
57{
58 if (file) {
59 fclose(file);
60 file = 0;
61 }
62}
63
64void AmiraIO::init()
65{
67
68 if (initialized) {
69 return;
70 }
71
72 initialized = true;
73 bool is_new_file = false;
74
75 file = sfopen(filename, rw_mode, &is_new_file, true);
76
77 if (!is_new_file) {
78 char buf[MAXPATHLEN];
79 if (!fgets(buf, MAXPATHLEN, file)) {
80 throw ImageReadException(filename, "Amira Header");
81 }
82
83 if (!is_valid(buf)) {
84 throw ImageReadException(filename, "invalid Amira Mesh file");
85 }
86
87 if(strstr(buf,"BINARY-LITTLE-ENDIAN")!=0) {
88 is_big_endian = false;
89 }
90 else if(strstr(buf,"BINARY")!=0) {
91 is_big_endian = true;
92 }
93 else if(strstr(buf,"2.0")!=0) {
94 is_big_endian = true; //AMIRA convention(<=2.0): BIGENDIAN only
95 }
96 }
98}
99
100bool AmiraIO::is_valid(const void *first_block)
101{
102 ENTERFUNC;
103 bool result = false;
104 if (!first_block) {
105 result = false;
106 }
107 else {
108 result = Util::check_file_by_magic(first_block, MAGIC);
109 }
110 EXITFUNC;
111 return result;
112}
113
114int AmiraIO::read_header(Dict & dict, int image_index, const Region *, bool)
115{
116 ENTERFUNC;
117
118 //single image format, index can only be zero
119 if(image_index == -1) {
120 image_index = 0;
121 }
122
123 if(image_index != 0) {
124 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().");
125 }
126
127 init();
128
129 char ll[MAXPATHLEN+10];
130 char datatype[16] = "";
131
132 do {
133 char * str = fgets(ll,MAXPATHLEN,file); str = str;
134// printf("%s", ll);
135 if(char* s=strstr(ll,"define Lattice ")) {
136 if(sscanf(s+15,"%d %d %d",&nx, &ny, &nz) == 3) {
137 dict["nx"] = nx;
138 dict["ny"] = ny;
139 dict["nz"] = nz;
140// printf("nx = %d, ny = %d, nz = %d\n", nx, ny, nz);
141 };
142 }
143 else if(char* s=strstr(ll,"BoundingBoxXY")) { //amiramesh 2.1
144 float bx0, bx1, by0, by1;
145 if (sscanf(s+13,"%f %f %f %f",&bx0, &bx1, &by0, &by1) == 4 ) {
146 pixel = (bx1-bx0)/(nx-1);
147 xorigin = bx0;
148 yorigin = by0;
149 dict["apix_x"] = pixel;
150 dict["apix_y"] = pixel;
151 dict["apix_z"] = pixel;
152 dict["origin_x"] = xorigin;
153 dict["origin_y"] = yorigin;
154// printf("pixel=%g: xorigin=%g yorigin=%g \n", pixel, xorigin, yorigin);
155 }
156 }
157 else if(char* s=strstr(ll,"BoundingBox")) { //amiramesh 2.0
158 float bx0, bx1, by0, by1, bz0, bz1;
159 if (sscanf(s+11,"%f %f %f %f %f %f",&bx0, &bx1, &by0, &by1, &bz0, &bz1) == 6 ) {
160 pixel = (bx1-bx0)/(nx-1);
161 xorigin = bx0;
162 yorigin = by0;
163 zorigin = bz0;
164 dict["apix_x"] = pixel;
165 dict["apix_y"] = pixel;
166 dict["apix_z"] = pixel;
167 dict["origin_x"] = xorigin;
168 dict["origin_y"] = yorigin;
169 dict["origin_z"] = zorigin;
170// printf("pixel=%g: xorigin=%g yorigin=%g zorigin=%g\n", pixel, xorigin, yorigin, zorigin);
171 }
172 }
173 else if(char* s=strstr(ll,"Lattice { ")) {
174 sscanf(s+10,"%s ", datatype);
175 if(!strncmp(datatype, "float", 5)) {
177 dict["datatype"] = EMUtil::EM_FLOAT;
178 }
179 else if(!strncmp(datatype, "short", 5)) {
181 dict["datatype"] = EMUtil::EM_SHORT;
182 }
183 else if(!strncmp(datatype, "byte", 4)) {
185 dict["datatype"] = EMUtil::EM_CHAR;
186 }
187 else {
188 fprintf(stderr,"AmiraIO::read_header: data type \"%s\" is not supported yet\n", datatype);
189 return -1;
190 }
191 }
192 } while (! ( ll[0]=='@' && ll[1]=='1') );
193
194 EXITFUNC;
195 return 0;
196
197}
198
199int AmiraIO::write_header(const Dict & dict, int image_index, const Region*, EMUtil::EMDataType, bool)
200{
201 ENTERFUNC;
202 int err = 0;
203
204 //single image format, index can only be zero
205 if(image_index == -1) {
206 image_index = 0;
207 }
208
209 if(image_index != 0) {
210 throw ImageWriteException(filename, "Amira file does not support stack.");
211 }
212 check_write_access(rw_mode, image_index, 1);
213
214 nx = dict["nx"];
215 ny = dict["ny"];
216 nz = dict["nz"];
217
218 float xorigin = 0.0f;
219 if(dict.has_key("origin_x")) xorigin = dict["origin_x"];
220 float yorigin = 0.0f;
221 if(dict.has_key("origin_y")) yorigin = dict["origin_y"];
222 float zorigin = 0.0f;
223 if(dict.has_key("origin_z")) zorigin = dict["origin_z"];
224 float pixel = 0.0f;
225 if(dict.has_key("apix_x")) pixel = dict["apix_x"];
226
227 rewind(file);
228
229 string line1;
231 line1= "# AmiraMesh 3D BINARY 2.1\n\n";
232 }
233 else {
234 line1= "# AmiraMesh BINARY-LITTLE-ENDIAN 2.1\n\n";
235 }
236
237 string type = "float";
238
239 if (fprintf(file, "%s", line1.c_str()) <= 0) {
240 LOGERR("cannot write to AmiraMesh file '%s'", filename.c_str());
241 err = 1;
242 }
243 else {
244 fprintf(file,"define Lattice %d %d %d\n\n",nx,ny,nz);
245 fprintf(file,"Parameters {\n");
246 fprintf(file, "\tContent \"%dx%dx%d %s, uniform coordinates\",\n", nx,ny,nz,type.c_str());
247 fprintf(file, "\tCoordType \"uniform\",\n");
248 fprintf(file,"\tBoundingBox %.2f %.2f %.2f %.2f %.2f %.2f\n}\n\n",xorigin,xorigin+pixel*(nx-1),yorigin,yorigin+pixel*(ny-1),zorigin,zorigin+pixel*(nz-1));
249 fprintf(file, "Lattice { float ScalarField } @1\n\n# Data section follows\n@1\n");
250 }
251
252 EXITFUNC;
253 return err;
254}
255
256int AmiraIO::read_data(float * rdata, int, const Region *, bool)
257{
258 ENTERFUNC;
259
260 size_t nr;
261 size_t size = (size_t)nx*ny*nz;
262
263 switch(dt) {
264 case EMUtil::EM_FLOAT:
265
266 nr = fread(rdata,nx*nz,ny*sizeof(float),file); nr++;
267
269 char tmpdata;
270 char *cdata=(char*)rdata;
271
272 for(size_t i=0;i<size;++i){
273 //swap 0-3
274 tmpdata=cdata[4*i+3];
275 cdata[4*i+3]=cdata[4*i];
276 cdata[4*i] = tmpdata;
277 //swap 1-2
278 tmpdata=cdata[4*i+2];
279 cdata[4*i+2]=cdata[4*i+1];
280 cdata[4*i+1] = tmpdata;
281 }
282 }
283
284 float* copydata;
285 copydata=new float[size];
286
287 for (size_t i=0;i<size;i++){
288 copydata[i]=rdata[i];
289 }
290
291 for (int i=0;i<ny;i++){
292 for (int j=0;j<nx;j++){
293 rdata[i*nx+j]=copydata[(ny-1-i)*nx+j];
294 }
295 }
296 delete[] copydata;
297
298 break;
299 case EMUtil::EM_SHORT:
300 {
301 short *datashort = (short*)malloc(sizeof(short)*nx*ny*nz);
302 nr = fread(datashort,nx*nz,ny*sizeof(short),file); nr++;
303
305 char tmpdata;
306 char *cdata=(char*)datashort;
307 for(size_t i=0;i<size;++i){
308 //swap 0-1
309 tmpdata=cdata[2*i+1];
310 cdata[2*i+1]=cdata[2*i];
311 cdata[2*i] = tmpdata;
312 }
313 for(size_t i=0; i<size; ++i) rdata[i] = float(datashort[i]);
314 free(datashort);
315 }
316
317 float* copydata;
318 copydata=new float[size];
319
320 for (size_t i=0;i<size;i++){
321 copydata[i]=rdata[i];
322 }
323
324 for (int i=0;i<ny;i++){
325 for (int j=0;j<nx;j++){
326 rdata[i*nx+j]=copydata[(ny-1-i)*nx+j];
327 }
328 }
329 delete[] copydata;
330
331 }
332 break;
333 case EMUtil::EM_CHAR:
334 {
335 char *databyte = (char*)malloc(sizeof(char)*nx*ny*nz);
336 nr = fread(databyte,nx*nz,ny*sizeof(char),file); nr++;
337
338 for(size_t i=0; i<size; ++i) rdata[i] = float(databyte[i]);
339 free(databyte);
340
341 float* copydata;
342 copydata=new float[size];
343
344 for (size_t i=0;i<size;i++){
345 copydata[i]=rdata[i];
346 }
347
348 for (int i=0;i<ny;i++){
349 for (int j=0;j<nx;j++){
350 rdata[i*nx+j]=copydata[(ny-1-i)*nx+j];
351 }
352 }
353 delete[] copydata;
354
355 }
356 break;
357 default:
358 fprintf(stderr,"AmiraIO::read_data: data type is not supported yet\n");
359 return -1;
360 }
361
362 EXITFUNC;
363 return 0;
364}
365
366int AmiraIO::write_data(float *data, int image_index, const Region*, EMUtil::EMDataType, bool)
367{
368 ENTERFUNC;
369
370 check_write_access(rw_mode, image_index, 1, data);
371// ByteOrder::become_big_endian(data, nx * ny * nz);
372 size_t size = (size_t)nx*ny*nz;
373
374 float* copydata;
375 copydata=new float[size];
376
377 for (size_t i=0;i<size;i++){
378 copydata[i]=data[i];
379 }
380
381 for (int i=0;i<ny;i++){
382 for (int j=0;j<nx;j++){
383 data[i*nx+j]=copydata[(ny-1-i)*nx+j];
384 }
385 }
386 delete[] copydata;
387
388 if (fwrite(data, nx * nz, ny * sizeof(float), file) != ny * sizeof(float)) {
389 throw ImageWriteException(filename, "incomplete file write in AmiraMesh file");
390 }
391
392 EXITFUNC;
393 return 0;
394}
395
396void AmiraIO::flush()
397{
398 fflush(file);
399}
400
402{
403 return false;
404}
405
407{
408 init();
409 return is_big_endian;
410}
411
#define rdata(i)
Definition: analyzer.cpp:592
float xorigin
Definition: amiraio.h:64
EMUtil::EMDataType dt
Definition: amiraio.h:59
static const char * MAGIC
Definition: amiraio.h:66
float pixel
Definition: amiraio.h:63
float yorigin
Definition: amiraio.h:64
bool is_big_endian
Definition: amiraio.h:58
float zorigin
Definition: amiraio.h:64
static bool is_valid(const void *first_block)
Definition: amiraio.cpp:100
static bool is_host_big_endian()
Definition: byteorder.cpp:40
Dict is a dictionary to store <string, EMObject> pair.
Definition: emobject.h:385
bool has_key(const string &key) const
Ask the Dictionary if it as a particular key.
Definition: emobject.h:511
EMDataType
Image pixel data type used in EMAN.
Definition: emutil.h:92
@ EM_SHORT
Definition: emutil.h:96
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.
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
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
static bool check_file_by_magic(const void *first_block, const char *magic)
check whether a file starts with certain magic string.
Definition: util.cpp:239
#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