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, const Region *, bool)
00119 {
00120 ENTERFUNC;
00121 init();
00122
00123 char ll[MAXPATHLEN+10];
00124 char datatype[16] = "";
00125
00126 do {
00127 fgets(ll,MAXPATHLEN,amira_file);
00128
00129 if(char* s=strstr(ll,"define Lattice ")) {
00130 if(sscanf(s+15,"%d %d %d",&nx, &ny, &nz) == 3) {
00131 dict["nx"] = nx;
00132 dict["ny"] = ny;
00133 dict["nz"] = nz;
00134
00135 };
00136 }
00137 else if(char* s=strstr(ll,"BoundingBoxXY")) {
00138 float bx0, bx1, by0, by1;
00139 if (sscanf(s+13,"%f %f %f %f",&bx0, &bx1, &by0, &by1) == 4 ) {
00140 pixel = (bx1-bx0)/(nx-1);
00141 xorigin = bx0;
00142 yorigin = by0;
00143 dict["apix_x"] = pixel;
00144 dict["apix_y"] = pixel;
00145 dict["apix_z"] = pixel;
00146 dict["origin_x"] = xorigin;
00147 dict["origin_y"] = yorigin;
00148
00149 }
00150 }
00151 else if(char* s=strstr(ll,"BoundingBox")) {
00152 float bx0, bx1, by0, by1, bz0, bz1;
00153 if (sscanf(s+11,"%f %f %f %f %f %f",&bx0, &bx1, &by0, &by1, &bz0, &bz1) == 6 ) {
00154 pixel = (bx1-bx0)/(nx-1);
00155 xorigin = bx0;
00156 yorigin = by0;
00157 zorigin = bz0;
00158 dict["apix_x"] = pixel;
00159 dict["apix_y"] = pixel;
00160 dict["apix_z"] = pixel;
00161 dict["origin_x"] = xorigin;
00162 dict["origin_y"] = yorigin;
00163 dict["origin_z"] = zorigin;
00164
00165 }
00166 }
00167 else if(char* s=strstr(ll,"Lattice { ")) {
00168 sscanf(s+10,"%s ", datatype);
00169 if(!strncmp(datatype, "float", 5)) {
00170 dt = EMUtil::EM_FLOAT;
00171 dict["datatype"] = EMUtil::EM_FLOAT;
00172 }
00173 else if(!strncmp(datatype, "short", 5)) {
00174 dt = EMUtil::EM_SHORT;
00175 dict["datatype"] = EMUtil::EM_SHORT;
00176 }
00177 else if(!strncmp(datatype, "byte", 4)) {
00178 dt = EMUtil::EM_CHAR;
00179 dict["datatype"] = EMUtil::EM_CHAR;
00180 }
00181 else {
00182 fprintf(stderr,"AmiraIO::read_header: data type \"%s\" is not supported yet\n", datatype);
00183 return -1;
00184 }
00185 }
00186 } while (! ( ll[0]=='@' && ll[1]=='1') );
00187
00188 EXITFUNC;
00189 return 0;
00190
00191 }
00192
00193 int AmiraIO::write_header(const Dict & dict, int image_index, const Region*, EMUtil::EMDataType, bool)
00194 {
00195 ENTERFUNC;
00196 int err = 0;
00197
00198 check_write_access(rw_mode, image_index, 1);
00199
00200 nx = dict["nx"];
00201 ny = dict["ny"];
00202 nz = dict["nz"];
00203
00204 float xorigin = 0.0f;
00205 if(dict.has_key("origin_x")) xorigin = dict["origin_x"];
00206 float yorigin = 0.0f;
00207 if(dict.has_key("origin_y")) yorigin = dict["origin_y"];
00208 float zorigin = 0.0f;
00209 if(dict.has_key("origin_z")) zorigin = dict["origin_z"];
00210 float pixel = 0.0f;
00211 if(dict.has_key("apix_x")) pixel = dict["apix_x"];
00212
00213 rewind(amira_file);
00214
00215 string line1;
00216 if(ByteOrder::is_host_big_endian()) {
00217 line1= "# AmiraMesh 3D BINARY 2.1\n\n";
00218 }
00219 else {
00220 line1= "# AmiraMesh BINARY-LITTLE-ENDIAN 2.1\n\n";
00221 }
00222
00223 string type = "float";
00224
00225 if (fprintf(amira_file,line1.c_str()) <= 0) {
00226 LOGERR("cannot write to AmiraMesh file '%s'", filename.c_str());
00227 err = 1;
00228 }
00229 else {
00230 fprintf(amira_file,"define Lattice %d %d %d\n\n",nx,ny,nz);
00231 fprintf(amira_file,"Parameters {\n");
00232 fprintf(amira_file, "\tContent \"%dx%dx%d %s, uniform coordinates\",\n", nx,ny,nz,type.c_str());
00233 fprintf(amira_file, "\tCoordType \"uniform\",\n");
00234 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));
00235
00236 fprintf(amira_file, "Lattice { float ScalarField } @1\n\n# Data section follows\n@1\n");
00237 }
00238
00239 EXITFUNC;
00240 return err;
00241 }
00242
00243 int AmiraIO::read_data(float * rdata, int, const Region *, bool)
00244 {
00245 ENTERFUNC;
00246
00247 size_t size = nx*ny*nz;
00248 switch(dt) {
00249 case EMUtil::EM_FLOAT:
00250 fread(rdata,nx*nz,ny*sizeof(float),amira_file);
00251 if( (is_big_endian && ByteOrder::is_host_big_endian()) && !(is_big_endian || ByteOrder::is_host_big_endian()) ) {
00252 char tmpdata;
00253 char *cdata=(char*)rdata;
00254 for(size_t i=0;i<size;++i){
00255
00256 tmpdata=cdata[4*i+3];
00257 cdata[4*i+3]=cdata[4*i];
00258 cdata[4*i] = tmpdata;
00259
00260 tmpdata=cdata[4*i+2];
00261 cdata[4*i+2]=cdata[4*i+1];
00262 cdata[4*i+1] = tmpdata;
00263 }
00264 }
00265 break;
00266 case EMUtil::EM_SHORT:
00267 {
00268 short *datashort = (short*)malloc(sizeof(short)*nx*ny*nz);
00269 fread(datashort,nx*nz,ny*sizeof(short),amira_file);
00270 if( (is_big_endian && ByteOrder::is_host_big_endian()) && !(is_big_endian || ByteOrder::is_host_big_endian()) ) {
00271 char tmpdata;
00272 char *cdata=(char*)datashort;
00273 for(size_t i=0;i<size;i++){
00274
00275 tmpdata=cdata[2*i+1];
00276 cdata[2*i+1]=cdata[2*i];
00277 cdata[2*i] = tmpdata;
00278 }
00279 for(size_t i=0; i<size; i++) rdata[i] = float(datashort[i]);
00280 free(datashort);
00281 }
00282 }
00283 break;
00284 case EMUtil::EM_CHAR:
00285 {
00286 char *databyte = (char*)malloc(sizeof(char)*nx*ny*nz);
00287 fread(databyte,nx*nz,ny*sizeof(char),amira_file);
00288 for(size_t i=0; i<size; i++) rdata[i] = float(databyte[i]);
00289 free(databyte);
00290 }
00291 break;
00292 default:
00293 fprintf(stderr,"AmiraIO::read_data: data type is not supported yet\n");
00294 return -1;
00295 }
00296
00297 EXITFUNC;
00298 return 0;
00299 }
00300
00301 int AmiraIO::write_data(float *data, int image_index, const Region*, EMUtil::EMDataType, bool)
00302 {
00303 ENTERFUNC;
00304
00305 check_write_access(rw_mode, image_index, 1, data);
00306
00307
00308 if (fwrite(data, nx * nz, ny * sizeof(float), amira_file) != ny * sizeof(float)) {
00309 throw ImageWriteException(filename, "incomplete file write in AmiraMesh file");
00310 }
00311
00312 EXITFUNC;
00313 return 0;
00314 }
00315
00316 void AmiraIO::flush()
00317 {
00318 fflush(amira_file);
00319 }
00320
00321 bool AmiraIO::is_complex_mode()
00322 {
00323 return false;
00324 }
00325
00326 bool AmiraIO::is_image_big_endian()
00327 {
00328 init();
00329 return is_big_endian;
00330 }
00331