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 "salio.h"
00037 #include "util.h"
00038 #include "geometry.h"
00039
00040 #ifndef WIN32
00041 #include <sys/param.h>
00042 #else
00043 #define MAXPATHLEN (MAX_PATH * 4)
00044 #endif
00045
00046 #include <cstdio>
00047 #include <climits>
00048 #include <cstring>
00049
00050 using namespace EMAN;
00051
00052 const char *SalIO::HDR_EXT = "hdr";
00053 const char *SalIO::IMG_EXT = "img";
00054 const char *SalIO::MAGIC = " IDENTIFICATION";
00055
00056
00057 SalIO::SalIO(const string & file, IOMode rw)
00058 : filename(file), rw_mode(rw), sal_file(0), initialized(false)
00059 {
00060 nx = 0;
00061 ny = 0;
00062 record_length = 512;
00063 scan_mode = NON_RASTER_SCAN;
00064 pixel = 4.6667f;
00065 }
00066
00067 SalIO::~SalIO()
00068 {
00069 if (sal_file) {
00070 fclose(sal_file);
00071 sal_file = 0;
00072 }
00073 }
00074
00075 void SalIO::init()
00076 {
00077 ENTERFUNC;
00078
00079 if (initialized) {
00080 return;
00081 }
00082
00083 initialized = true;
00084
00085 string hdr_filename = Util::change_filename_ext(filename, HDR_EXT);
00086 string img_filename = Util::change_filename_ext(filename, IMG_EXT);
00087
00088 bool is_new_file = false;
00089 sal_file = sfopen(hdr_filename, rw_mode, &is_new_file);
00090
00091 char scan_type[MAXPATHLEN];
00092 ScanAxis axis = X_SCAN_AXIS;
00093
00094 if (!is_new_file) {
00095 char buf[MAXPATHLEN];
00096 if (fgets(buf, MAXPATHLEN, sal_file)) {
00097 if (!is_valid(buf)) {
00098 throw ImageReadException(filename, "ivalid SAL");
00099 }
00100 }
00101
00102 while (fgets(buf, MAXPATHLEN, sal_file)) {
00103 const char *buf1 = buf + 1;
00104
00105 if (Util::sstrncmp(buf1, "NXP")) {
00106 sscanf(strchr(buf, '=') + 1, " %d", &nx);
00107 }
00108 else if (Util::sstrncmp(buf1, "NYP")) {
00109 sscanf(strchr(buf, '=') + 1, " %d", &ny);
00110 }
00111 else if (Util::sstrncmp(buf1, "AXSCAN")) {
00112 char *t = strrchr(buf, '\'');
00113 if (t && t[-1] == 'Y') {
00114 axis = Y_SCAN_AXIS;
00115 }
00116 }
00117 else if (Util::sstrncmp(buf1, "FILE REC LEN")) {
00118 sscanf(strchr(buf, '=') + 1, " %d", &record_length);
00119 }
00120 else if (Util::sstrncmp(buf1, "SCAN TYPE")) {
00121 sscanf(strchr(buf, '\'') + 1, " %s", scan_type);
00122 if (scan_type[0] == 'R') {
00123 scan_mode = RASTER_SCAN;
00124 }
00125 }
00126 else if (Util::sstrncmp(buf1, "DELTAX")) {
00127 sscanf(strchr(buf, '=') + 1, " %f", &pixel);
00128 pixel /= 3.0;
00129 }
00130 }
00131
00132
00133 if (axis == Y_SCAN_AXIS) {
00134 int t = nx;
00135 nx = ny;
00136 ny = t;
00137 }
00138 }
00139 fclose(sal_file);
00140 sal_file = sfopen(img_filename, rw_mode);
00141
00142 EXITFUNC;
00143 }
00144
00145 bool SalIO::is_valid(const void *first_block)
00146 {
00147 ENTERFUNC;
00148 bool result = false;
00149
00150 if (!first_block) {
00151 result = false;
00152 }
00153 result = Util::check_file_by_magic(first_block, MAGIC);
00154 EXITFUNC;
00155 return result;
00156 }
00157
00158 int SalIO::read_header(Dict & dict, int image_index, const Region * area, bool)
00159 {
00160 ENTERFUNC;
00161
00162
00163 if(image_index == -1) {
00164 image_index = 0;
00165 }
00166
00167 if(image_index != 0) {
00168 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().");
00169 }
00170
00171 init();
00172
00173 check_region(area, IntSize(nx, ny));
00174
00175 int xlen = 0, ylen = 0;
00176 EMUtil::get_region_dims(area, nx, &xlen, ny, &ylen);
00177
00178 dict["nx"] = xlen;
00179 dict["ny"] = ylen;
00180 dict["nz"] = 1;
00181 dict["datatype"] = EMUtil::EM_SHORT;
00182 dict["SAL.pixel"] = pixel;
00183
00184 EXITFUNC;
00185 return 0;
00186 }
00187
00188 int SalIO::write_header(const Dict &, int, const Region* , EMUtil::EMDataType, bool)
00189 {
00190 ENTERFUNC;
00191 LOGWARN("SAL write is not supported.");
00192 EXITFUNC;
00193 return 1;
00194 }
00195
00196 int SalIO::read_data(float *data, int image_index, const Region * area, bool)
00197 {
00198 ENTERFUNC;
00199
00200
00201 image_index = 0;
00202 check_read_access(image_index, data);
00203 check_region(area, IntSize(nx, ny));
00204
00205 if (scan_mode != NON_RASTER_SCAN) {
00206 LOGERR("only NON_RASTER_SCAN scan mode is supported in a SAL image");
00207 return 1;
00208 }
00209
00210 rewind(sal_file);
00211
00212 int mode_size = (int)sizeof(short);
00213 unsigned char *cdata = (unsigned char *) data;
00214 short *sdata = (short *) data;
00215 size_t row_size = nx * mode_size;
00216 size_t block_size = (((row_size - 1) / record_length) + 1) * record_length;
00217 size_t post_row = block_size - row_size;
00218
00219 EMUtil::process_region_io(cdata, sal_file, READ_ONLY, image_index,
00220 mode_size, nx, ny, 1, area, false,
00221 EMUtil::IMAGE_SAL, 0, post_row);
00222
00223 #if 0
00224 int row_size = nx * mode_size;
00225 int block_size = (((row_size - 1) / record_length) + 1) * record_length;
00226
00227 for (int j = 0; j < ny; j++) {
00228 if (fread(&cdata[j * row_size], block_size, 1, sal_file) != 1) {
00229 LOGERR("Incomplete SAL data read %d/%d blocks", j, ny);
00230 return 1;
00231 }
00232 }
00233 #endif
00234
00235 int xlen = 0, ylen = 0;
00236 EMUtil::get_region_dims(area, nx, &xlen, ny, &ylen);
00237
00238 if (scan_mode == NON_RASTER_SCAN) {
00239 become_host_endian(sdata, xlen * ylen);
00240
00241 for (int i = 0; i < ylen; i += 2) {
00242 for (int j = 0; j < xlen / 2; j++) {
00243 short sw = sdata[i * xlen + j];
00244 sdata[i * xlen + j] = sdata[i * xlen + xlen - j - 1];
00245 sdata[i * xlen + xlen - j - 1] = sw;
00246 }
00247 }
00248 }
00249
00250 for (int i = xlen * ylen - 1; i >= 0; i--) {
00251 data[i] = static_cast < float >((cdata[i * 2 + 1] * UCHAR_MAX) + cdata[i * 2]);
00252 }
00253 EXITFUNC;
00254 return 0;
00255 }
00256
00257 int SalIO::write_data(float *, int, const Region* , EMUtil::EMDataType, bool)
00258 {
00259 ENTERFUNC;
00260 LOGWARN("SAL write is not supported.");
00261 EXITFUNC;
00262 return 1;
00263 }
00264
00265 void SalIO::flush()
00266 {
00267 }
00268
00269
00270 bool SalIO::is_complex_mode()
00271 {
00272 return false;
00273 }
00274
00275 bool SalIO::is_image_big_endian()
00276 {
00277 return false;
00278 }
00279