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 "gatan2io.h"
00037 #include "geometry.h"
00038 #include "portable_fileio.h"
00039 #include <cstring>
00040
00041 using namespace EMAN;
00042
00043 Gatan2IO::Gatan2IO(const string & file, IOMode rw)
00044 : filename(file), rw_mode(rw), gatan2_file(0), initialized(false)
00045 {
00046 is_big_endian = ByteOrder::is_host_big_endian();
00047 memset(&gatanh, 0, sizeof(Gatan2Header));
00048 }
00049
00050 Gatan2IO::~Gatan2IO()
00051 {
00052 if (gatan2_file) {
00053 fclose(gatan2_file);
00054 gatan2_file = 0;
00055 }
00056 }
00057
00058 void Gatan2IO::init()
00059 {
00060 ENTERFUNC;
00061
00062 if (initialized) {
00063 return;
00064 }
00065
00066 initialized = true;
00067
00068 bool is_new_file = false;
00069 gatan2_file = sfopen(filename, rw_mode, &is_new_file);
00070
00071 if (!is_new_file) {
00072 if (fread(&gatanh, sizeof(Gatan2Header), 1, gatan2_file) != 1) {
00073 throw ImageReadException(filename, "Gatan2 Header");
00074 }
00075
00076 if (!is_valid(&gatanh)) {
00077 throw ImageReadException(filename, "invalid Gatan2 file");
00078 }
00079
00080 is_big_endian = ByteOrder::is_data_big_endian(&gatanh.len);
00081 become_host_endian((short *) &gatanh, sizeof(Gatan2Header) / sizeof(short));
00082 }
00083 EXITFUNC;
00084 }
00085
00086 bool Gatan2IO::is_valid(const void *first_block)
00087 {
00088 ENTERFUNC;
00089 bool result = false;
00090
00091 if (!first_block) {
00092 result = false;
00093 }
00094 else {
00095 const short *data = static_cast < const short *>(first_block);
00096 short len = data[5];
00097 short type = data[6];
00098
00099 bool data_big_endian = ByteOrder::is_data_big_endian(&len);
00100
00101 if (data_big_endian != ByteOrder::is_host_big_endian()) {
00102 ByteOrder::swap_bytes(&len);
00103 ByteOrder::swap_bytes(&type);
00104 }
00105
00106 int double_size = sizeof(double);
00107 if (len > 0 && len <= double_size && type > 0 && type <= GATAN2_INVALID) {
00108 result = true;
00109 }
00110 }
00111 EXITFUNC;
00112 return result;
00113 }
00114
00115 int Gatan2IO::read_header(Dict & dict, int image_index, const Region * area, bool)
00116 {
00117 ENTERFUNC;
00118
00119 if(image_index == -1) {
00120 image_index = 0;
00121 }
00122
00123 if(image_index != 0) {
00124 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().");
00125 }
00126
00127 init();
00128
00129 if (is_complex_mode()) {
00130 throw ImageReadException(filename, "Cannot read complex Gatan2 files");
00131 }
00132 else {
00133 check_region(area, IntSize(gatanh.nx, gatanh.ny));
00134
00135 int xlen = 0, ylen = 0;
00136 EMUtil::get_region_dims(area, gatanh.nx, &xlen, gatanh.ny, &ylen);
00137
00138 dict["nx"] = xlen;
00139 dict["ny"] = ylen;
00140 dict["nz"] = 1;
00141 dict["datatype"] = to_em_datatype(gatanh.type);
00142 }
00143
00144 EXITFUNC;
00145 return 0;
00146 }
00147
00148 int Gatan2IO::write_header(const Dict &, int, const Region* , EMUtil::EMDataType, bool)
00149 {
00150 ENTERFUNC;
00151 LOGWARN("Gatan2 write is not supported.");
00152 EXITFUNC;
00153 return 1;
00154 }
00155
00156 int Gatan2IO::read_data(float *data, int image_index, const Region * area, bool )
00157 {
00158 ENTERFUNC;
00159
00160 image_index = 0;
00161 check_read_access(image_index, data);
00162
00163 if (is_complex_mode()) {
00164 throw ImageReadException(filename, "Cannot read complex Gatan2 files");
00165 }
00166
00167 check_region(area, IntSize(gatanh.nx, gatanh.ny));
00168
00169 portable_fseek(gatan2_file, sizeof(Gatan2Header), SEEK_SET);
00170
00171 #if 0
00172 if (fread(data, gatanh.nx * gatanh.len, gatanh.ny, gatan2_file) != (unsigned int) gatanh.ny) {
00173 LOGDEBUG("Data read incomplete in Gatan file '%s'", filename.c_str());
00174 return 1;
00175 }
00176 #endif
00177
00178 int size = gatanh.nx * gatanh.ny;
00179 short *sdata = (short *) data;
00180 unsigned char *cdata = (unsigned char *) data;
00181 int *ldata = (int *) data;
00182
00183 EMUtil::process_region_io(cdata, gatan2_file, READ_ONLY, image_index, gatanh.len,
00184 gatanh.nx, gatanh.ny, 1, area);
00185
00186 switch (gatanh.type) {
00187 case GATAN2_SHORT:
00188 become_host_endian((short *) data, size);
00189 for (int i = size - 1; i >= 0; i--) {
00190 data[i] = static_cast < float >(sdata[i]);
00191 }
00192 break;
00193 case GATAN2_FLOAT:
00194 become_host_endian(data, size);
00195 break;
00196 case GATAN2_CHAR:
00197 for (int i = size - 1; i >= 0; i--) {
00198 data[i] = static_cast < float >(cdata[i]);
00199 }
00200 break;
00201 case GATAN2_INT:
00202 become_host_endian((int *) data, size);
00203 for (int i = size - 1; i >= 0; i--) {
00204 data[i] = static_cast < float >(ldata[i]);
00205 }
00206 break;
00207 default:
00208 throw ImageReadException(filename, "unsupported Gatan2 data type");
00209 }
00210 EXITFUNC;
00211 return 0;
00212 }
00213
00214 int Gatan2IO::write_data(float *, int, const Region*, EMUtil::EMDataType, bool)
00215 {
00216 ENTERFUNC;
00217 LOGWARN("Gatan2 write is not supported.");
00218 EXITFUNC;
00219 return 1;
00220 }
00221
00222 void Gatan2IO::flush()
00223 {
00224 }
00225
00226 bool Gatan2IO::is_complex_mode()
00227 {
00228 init();
00229 if (gatanh.type == GATAN2_COMPLEX || gatanh.type == GATAN2_PACKED_COMPLEX) {
00230 return true;
00231 }
00232 return false;
00233 }
00234
00235 bool Gatan2IO::is_image_big_endian()
00236 {
00237 init();
00238 return is_big_endian;
00239 }
00240
00241
00242
00243 int Gatan2IO::to_em_datatype(int gatan_type)
00244 {
00245 switch (gatan_type) {
00246 case GATAN2_SHORT:
00247 return EMUtil::EM_SHORT;
00248
00249 case GATAN2_FLOAT:
00250 return EMUtil::EM_FLOAT;
00251
00252 case GATAN2_CHAR:
00253 return EMUtil::EM_CHAR;
00254
00255 case GATAN2_INT:
00256 return EMUtil::EM_INT;
00257 }
00258
00259 return EMUtil::EM_UNKNOWN;
00260 }