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 "amiraio.h"
00037 #include "util.h"
00038
00039 #ifndef WIN32
00040 #include <sys/param.h>
00041 #else
00042 #include <windows.h>
00043 #define MAXPATHLEN (MAX_PATH*4)
00044 #endif //WIN32
00045
00046 #include <cstdio>
00047
00048 using namespace EMAN;
00049
00050 const char *AmiraIO::MAGIC = "# AmiraMesh";
00051
00052 AmiraIO::AmiraIO(const string & file, IOMode rw)
00053 : filename(file), rw_mode(rw), amira_file(0),
00054 is_big_endian(true), initialized(false), dt(EMUtil::EM_UNKNOWN),
00055 nx(0), ny(0), nz(0),
00056 pixel(0), xorigin(0), yorigin(0), zorigin(0)
00057 {
00058 }
00059
00060 AmiraIO::~AmiraIO()
00061 {
00062 if (amira_file) {
00063 fclose(amira_file);
00064 amira_file = 0;
00065 }
00066 }
00067
00068 void AmiraIO::init()
00069 {
00070 ENTERFUNC;
00071
00072 if (initialized) {
00073 return;
00074 }
00075
00076 initialized = true;
00077 bool is_new_file = false;
00078
00079 amira_file = sfopen(filename, rw_mode, &is_new_file, true);
00080
00081 if (!is_new_file) {
00082 char buf[MAXPATHLEN];
00083 if (!fgets(buf, MAXPATHLEN, amira_file)) {
00084 throw ImageReadException(filename, "Amira Header");
00085 }
00086
00087 if (!is_valid(buf)) {
00088 throw ImageReadException(filename, "invalid Amira Mesh file");
00089 }
00090
00091 if(strstr(buf,"BINARY-LITTLE-ENDIAN")!=0) {
00092 is_big_endian = false;
00093 }
00094 else if(strstr(buf,"BINARY")!=0) {
00095 is_big_endian = true;
00096 }
00097 else if(strstr(buf,"2.0")!=0) {
00098 is_big_endian = true;
00099 }
00100 }
00101 EXITFUNC;
00102 }
00103
00104 bool AmiraIO::is_valid(const void *first_block)
00105 {
00106 ENTERFUNC;
00107 bool result = false;
00108 if (!first_block) {
00109 result = false;
00110 }
00111 else {
00112 result = Util::check_file_by_magic(first_block, MAGIC);
00113 }
00114 EXITFUNC;
00115 return result;
00116 }
00117
00118 int AmiraIO::read_header(Dict & dict, int image_index, const Region *, bool)
00119 {
00120 ENTERFUNC;
00121
00122
00123 if(image_index == -1) {
00124 image_index = 0;
00125 }
00126
00127 if(image_index != 0) {
00128 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().");
00129 }
00130
00131 init();
00132
00133 char ll[MAXPATHLEN+10];
00134 char datatype[16] = "";
00135
00136 do {
00137 fgets(ll,MAXPATHLEN,amira_file);
00138
00139 if(char* s=strstr(ll,"define Lattice ")) {
00140 if(sscanf(s+15,"%d %d %d",&nx, &ny, &nz) == 3) {
00141 dict["nx"] = nx;
00142 dict["ny"] = ny;
00143 dict["nz"] = nz;
00144
00145 };
00146 }
00147 else if(char* s=strstr(ll,"BoundingBoxXY")) {
00148 float bx0, bx1, by0, by1;
00149 if (sscanf(s+13,"%f %f %f %f",&bx0, &bx1, &by0, &by1) == 4 ) {
00150 pixel = (bx1-bx0)/(nx-1);
00151 xorigin = bx0;
00152 yorigin = by0;
00153 dict["apix_x"] = pixel;
00154 dict["apix_y"] = pixel;
00155 dict["apix_z"] = pixel;
00156 dict["origin_x"] = xorigin;
00157 dict["origin_y"] = yorigin;
00158
00159 }
00160 }
00161 else if(char* s=strstr(ll,"BoundingBox")) {
00162 float bx0, bx1, by0, by1, bz0, bz1;
00163 if (sscanf(s+11,"%f %f %f %f %f %f",&bx0, &bx1, &by0, &by1, &bz0, &bz1) == 6 ) {
00164 pixel = (bx1-bx0)/(nx-1);
00165 xorigin = bx0;
00166 yorigin = by0;
00167 zorigin = bz0;
00168 dict["apix_x"] = pixel;
00169 dict["apix_y"] = pixel;
00170 dict["apix_z"] = pixel;
00171 dict["origin_x"] = xorigin;
00172 dict["origin_y"] = yorigin;
00173 dict["origin_z"] = zorigin;
00174
00175 }
00176 }
00177 else if(char* s=strstr(ll,"Lattice { ")) {
00178 sscanf(s+10,"%s ", datatype);
00179 if(!strncmp(datatype, "float", 5)) {
00180 dt = EMUtil::EM_FLOAT;
00181 dict["datatype"] = EMUtil::EM_FLOAT;
00182 }
00183 else if(!strncmp(datatype, "short", 5)) {
00184 dt = EMUtil::EM_SHORT;
00185 dict["datatype"] = EMUtil::EM_SHORT;
00186 }
00187 else if(!strncmp(datatype, "byte", 4)) {
00188 dt = EMUtil::EM_CHAR;
00189 dict["datatype"] = EMUtil::EM_CHAR;
00190 }
00191 else {
00192 fprintf(stderr,"AmiraIO::read_header: data type \"%s\" is not supported yet\n", datatype);
00193 return -1;
00194 }
00195 }
00196 } while (! ( ll[0]=='@' && ll[1]=='1') );
00197
00198 EXITFUNC;
00199 return 0;
00200
00201 }
00202
00203 int AmiraIO::write_header(const Dict & dict, int image_index, const Region*, EMUtil::EMDataType, bool)
00204 {
00205 ENTERFUNC;
00206 int err = 0;
00207
00208
00209 if(image_index == -1) {
00210 image_index = 0;
00211 }
00212
00213 if(image_index != 0) {
00214 throw ImageWriteException(filename, "Amira file does not support stack.");
00215 }
00216 check_write_access(rw_mode, image_index, 1);
00217
00218 nx = dict["nx"];
00219 ny = dict["ny"];
00220 nz = dict["nz"];
00221
00222 float xorigin = 0.0f;
00223 if(dict.has_key("origin_x")) xorigin = dict["origin_x"];
00224 float yorigin = 0.0f;
00225 if(dict.has_key("origin_y")) yorigin = dict["origin_y"];
00226 float zorigin = 0.0f;
00227 if(dict.has_key("origin_z")) zorigin = dict["origin_z"];
00228 float pixel = 0.0f;
00229 if(dict.has_key("apix_x")) pixel = dict["apix_x"];
00230
00231 rewind(amira_file);
00232
00233 string line1;
00234 if(ByteOrder::is_host_big_endian()) {
00235 line1= "# AmiraMesh 3D BINARY 2.1\n\n";
00236 }
00237 else {
00238 line1= "# AmiraMesh BINARY-LITTLE-ENDIAN 2.1\n\n";
00239 }
00240
00241 string type = "float";
00242
00243 if (fprintf(amira_file, "%s", line1.c_str()) <= 0) {
00244 LOGERR("cannot write to AmiraMesh file '%s'", filename.c_str());
00245 err = 1;
00246 }
00247 else {
00248 fprintf(amira_file,"define Lattice %d %d %d\n\n",nx,ny,nz);
00249 fprintf(amira_file,"Parameters {\n");
00250 fprintf(amira_file, "\tContent \"%dx%dx%d %s, uniform coordinates\",\n", nx,ny,nz,type.c_str());
00251 fprintf(amira_file, "\tCoordType \"uniform\",\n");
00252 fprintf(amira_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));
00253
00254 fprintf(amira_file, "Lattice { float ScalarField } @1\n\n# Data section follows\n@1\n");
00255 }
00256
00257 EXITFUNC;
00258 return err;
00259 }
00260
00261 int AmiraIO::read_data(float * rdata, int, const Region *, bool)
00262 {
00263 ENTERFUNC;
00264
00265 size_t size = (size_t)nx*ny*nz;
00266 switch(dt) {
00267 case EMUtil::EM_FLOAT:
00268 fread(rdata,nx*nz,ny*sizeof(float),amira_file);
00269 if( (is_big_endian && ByteOrder::is_host_big_endian()) && !(is_big_endian || ByteOrder::is_host_big_endian()) ) {
00270 char tmpdata;
00271 char *cdata=(char*)rdata;
00272 for(size_t i=0;i<size;++i){
00273
00274 tmpdata=cdata[4*i+3];
00275 cdata[4*i+3]=cdata[4*i];
00276 cdata[4*i] = tmpdata;
00277
00278 tmpdata=cdata[4*i+2];
00279 cdata[4*i+2]=cdata[4*i+1];
00280 cdata[4*i+1] = tmpdata;
00281 }
00282 }
00283 break;
00284 case EMUtil::EM_SHORT:
00285 {
00286 short *datashort = (short*)malloc(sizeof(short)*nx*ny*nz);
00287 fread(datashort,nx*nz,ny*sizeof(short),amira_file);
00288 if( (is_big_endian && ByteOrder::is_host_big_endian()) && !(is_big_endian || ByteOrder::is_host_big_endian()) ) {
00289 char tmpdata;
00290 char *cdata=(char*)datashort;
00291 for(size_t i=0;i<size;++i){
00292
00293 tmpdata=cdata[2*i+1];
00294 cdata[2*i+1]=cdata[2*i];
00295 cdata[2*i] = tmpdata;
00296 }
00297 for(size_t i=0; i<size; ++i) rdata[i] = float(datashort[i]);
00298 free(datashort);
00299 }
00300 }
00301 break;
00302 case EMUtil::EM_CHAR:
00303 {
00304 char *databyte = (char*)malloc(sizeof(char)*nx*ny*nz);
00305 fread(databyte,nx*nz,ny*sizeof(char),amira_file);
00306 for(size_t i=0; i<size; ++i) rdata[i] = float(databyte[i]);
00307 free(databyte);
00308 }
00309 break;
00310 default:
00311 fprintf(stderr,"AmiraIO::read_data: data type is not supported yet\n");
00312 return -1;
00313 }
00314
00315 EXITFUNC;
00316 return 0;
00317 }
00318
00319 int AmiraIO::write_data(float *data, int image_index, const Region*, EMUtil::EMDataType, bool)
00320 {
00321 ENTERFUNC;
00322
00323 check_write_access(rw_mode, image_index, 1, data);
00324
00325
00326 if (fwrite(data, nx * nz, ny * sizeof(float), amira_file) != ny * sizeof(float)) {
00327 throw ImageWriteException(filename, "incomplete file write in AmiraMesh file");
00328 }
00329
00330 EXITFUNC;
00331 return 0;
00332 }
00333
00334 void AmiraIO::flush()
00335 {
00336 fflush(amira_file);
00337 }
00338
00339 bool AmiraIO::is_complex_mode()
00340 {
00341 return false;
00342 }
00343
00344 bool AmiraIO::is_image_big_endian()
00345 {
00346 init();
00347 return is_big_endian;
00348 }
00349