EMAN2
vtkio.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#include <cstring>
33#include <climits>
34#include "vtkio.h"
35#include "util.h"
36#include "geometry.h"
37#include "portable_fileio.h"
38
39using namespace EMAN;
40
41const char *VtkIO::MAGIC = "# vtk DataFile Version";
42
43VtkIO::VtkIO(const string & fname, IOMode rw)
44: ImageIO(fname, rw)
45{
47 is_new_file = false;
48
51 nx = 0;
52 ny = 0;
53 nz = 0;
54 originx = 0;
55 originy = 0;
56 originz = 0;
57 spacingx = 0;
58 spacingy = 0;
59 spacingz = 0;
60 file_offset = 0;
61}
62
64{
65 if (file) {
66 fclose(file);
67 file = 0;
68 }
69}
70
71static int samestr(const char *s1, const char *s2)
72{
73 return (strncmp(s1, s2, strlen(s2)) == 0);
74}
75
76
77void VtkIO::init()
78{
79 if (initialized) {
80 return;
81 }
83 initialized = true;
84
86
87 if (!is_new_file) {
88 char buf[1024];
89 int bufsz = sizeof(buf);
90 if (fgets(buf, bufsz, file) == 0) {
91 throw ImageReadException(filename, "first block");
92 }
93
94 if (!is_valid(&buf)) {
95 throw ImageReadException(filename, "invalid VTK");
96 }
97
98 if (fgets(buf, bufsz, file) == 0) {
99 throw ImageReadException(filename, "read VTK file failed");
100 }
101
102 if (fgets(buf, bufsz, file)) {
103 if (samestr(buf, "ASCII")) {
105 }
106 else if (samestr(buf, "BINARY")) {
108 }
109 }
110 else {
111 throw ImageReadException(filename, "read VTK file failed");
112 }
113
114 if (fgets(buf, bufsz, file)) {
115 if (samestr(buf, "DATASET")) {
116 char dataset_name[128];
117 sscanf(buf, "DATASET %s", dataset_name);
118 DatasetType ds_type = get_datasettype_from_name(dataset_name);
119 read_dataset(ds_type);
120 }
121 }
122 else {
123 throw ImageReadException(filename, "read VTK file failed");
124 }
125
126 while (fgets(buf, bufsz, file)) {
127 if (samestr(buf, "SCALARS")) {
128 char datatypestr[32];
129 char scalartype[32];
130 sscanf(buf, "SCALARS %s %s", scalartype, datatypestr);
131
132 datatype = get_datatype_from_name(datatypestr);
133 if (datatype != UNSIGNED_SHORT && datatype != FLOAT) {
134 string desc = "unknown data type: " + string(datatypestr);
135 throw ImageReadException(filename, desc);
136 }
137 }
138 else if (samestr(buf, "LOOKUP_TABLE")) {
139 char tablename[128];
140 sscanf(buf, "LOOKUP_TABLE %s", tablename);
141 if (!samestr(tablename, "default")) {
142 throw ImageReadException(filename, "only default LOOKUP_TABLE supported");
143 }
144 else {
145 break;
146 }
147 }
148 }
149#if 0
150 if (filetype == VTK_BINARY) {
151 throw ImageReadException(filename, "binary VTK is not supported");
152 }
153#endif
155 }
156 EXITFUNC;
157}
158
159
160bool VtkIO::is_valid(const void *first_block)
161{
162 ENTERFUNC;
163 bool result = false;
164 if (first_block) {
165 result = Util::check_file_by_magic(first_block, MAGIC);
166 }
167 EXITFUNC;
168 return result;
169}
170
171int VtkIO::read_header(Dict & dict, int image_index, const Region * area, bool)
172{
173 ENTERFUNC;
174
175 //single image format, index can only be zero
176 if(image_index == -1) {
177 image_index = 0;
178 }
179
180 if(image_index != 0) {
181 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().");
182 }
183
184 init();
185 check_region(area, IntSize(nx, ny, nz));
186
187 int xlen = 0, ylen = 0, zlen = 0;
188 EMUtil::get_region_dims(area, nx, &xlen, ny, &ylen, nz, &zlen);
189
190 dict["nx"] = xlen;
191 dict["ny"] = ylen;
192 dict["nz"] = zlen;
193
194 dict["datatype"] = to_em_datatype(datatype);
195
196 dict["apix_x"] = spacingx;
197 dict["apix_y"] = spacingy;
198 dict["apix_z"] = spacingz;
199
200 dict["origin_x"] = originx;
201 dict["origin_y"] = originy;
202 dict["origin_z"] = originz;
203
204 EXITFUNC;
205 return 0;
206}
207
208int VtkIO::write_header(const Dict & dict, int image_index, const Region*,
209 EMUtil::EMDataType, bool)
210{
211 ENTERFUNC;
212
213 //single image format, index can only be zero
214 if(image_index == -1) {
215 image_index = 0;
216 }
217 if(image_index != 0) {
218 throw ImageWriteException(filename, "VTK file does not support stack.");
219 }
220 check_write_access(rw_mode, image_index);
221
222 nx = dict["nx"];
223 ny = dict["ny"];
224 nz = dict["nz"];
225
226 originx = dict["origin_x"];
227 originy = dict["origin_y"];
228 originz = dict["origin_z"];
229
230 spacingx = dict["apix_x"];
231 spacingy = dict["apix_y"];
232 spacingz = dict["apix_z"];
233
234 fprintf(file, "# vtk DataFile Version 2.0\n");
235 fprintf(file, "EMAN\n");
236 fprintf(file, "BINARY\n");
237 fprintf(file, "DATASET STRUCTURED_POINTS\n");
238 fprintf(file, "DIMENSIONS %0d %0d %0d\nORIGIN %f %f %f\nSPACING %f %f %f\n",
240
241
242 fprintf(file, "POINT_DATA %0lu\nSCALARS density float 1\nLOOKUP_TABLE default\n",
243 (size_t)nx * ny * nz);
244 EXITFUNC;
245 return 0;
246}
247
248int VtkIO::read_data(float *data, int image_index, const Region * area, bool)
249{
250 ENTERFUNC;
251
252 //single image format, index can only be zero
253 image_index = 0;
254 check_read_access(image_index, data);
255
256 if (area) {
257 LOGWARN("read VTK region is not supported yet. Read whole image instead.");
258 }
259
260 portable_fseek(file, file_offset, SEEK_SET);
261
262 int xlen = 0, ylen = 0, zlen = 0;
263 int x0 = 0, y0 = 0, z0 = 0;
264 EMUtil::get_region_dims(area, nx, &xlen, ny, &ylen, nz, &zlen);
265 EMUtil::get_region_origins(area, &x0, &y0, &z0, nz, image_index);
266
267 if (filetype == VTK_ASCII) {
268
269 int bufsz = nx * get_mode_size(datatype) * CHAR_BIT;
270 char *buf = new char[bufsz];
271 int i = 0;
272
273 while (fgets(buf, bufsz, file)) {
274 size_t bufslen = strlen(buf) - 1;
275 char numstr[32];
276 int k = 0;
277 for (size_t j = 0; j < bufslen; j++) {
278 if (!isspace(buf[j])) {
279 numstr[k++] = buf[j];
280 }
281 else {
282 numstr[k] = '\0';
283 data[i++] = (float)atoi(numstr);
284 k = 0;
285 }
286 }
287 }
288 if( buf )
289 {
290 delete[]buf;
291 buf = 0;
292 }
293 }
294 else if (filetype == VTK_BINARY) {
295 int nxy = nx * ny;
296 int row_size = nx * get_mode_size(datatype);
297
298 for (int i = 0; i < nz; i++) {
299 int i2 = i * nxy;
300 for (int j = 0; j < ny; j++) {
301 fread(&data[i2 + j * nx], row_size, 1, file);
302 }
303 }
304
306 ByteOrder::swap_bytes(data, (size_t)nx * ny * nz);
307 }
308 }
309
310 EXITFUNC;
311 return 0;
312}
313
314int VtkIO::write_data(float *data, int image_index, const Region* ,
315 EMUtil::EMDataType, bool)
316{
317 ENTERFUNC;
318
319 //single image format, index can only be zero
320 image_index = 0;
321 check_write_access(rw_mode, image_index, 1, data);
322
323 bool swapped = false;
325 ByteOrder::swap_bytes(data, (size_t)nx * ny * nz);
326 swapped = true;
327 }
328
329 fwrite(data, nx * nz, ny * sizeof(float), file);
330
331 if (swapped) {
332 ByteOrder::swap_bytes(data, (size_t)nx * ny * nz);
333 }
334 EXITFUNC;
335 return 0;
336}
337
338void VtkIO::flush()
339{
340 fflush(file);
341}
342
344{
345 return false;
346}
347
349{
350 return true;
351}
352
353int VtkIO::to_em_datatype(int vtk_datatype)
354{
355 DataType d = static_cast < DataType > (vtk_datatype);
356 switch (d) {
357 case UNSIGNED_SHORT:
358 return EMUtil::EM_USHORT;
359 case FLOAT:
360 return EMUtil::EM_FLOAT;
361 default:
362 break;
363 }
364 return EMUtil::EM_UNKNOWN;
365}
366
367
369{
370 switch (d) {
371 case UNSIGNED_CHAR:
372 case CHAR:
373 return sizeof(char);
374 case UNSIGNED_SHORT:
375 case SHORT:
376 return sizeof(short);
377 case UNSIGNED_INT:
378 case INT:
379 return sizeof(int);
380 case UNSIGNED_LONG:
381 case LONG:
382 return sizeof(long);
383 case FLOAT:
384 return sizeof(float);
385 case DOUBLE:
386 return sizeof(double);
387 default:
388 LOGERR("don't support this data type '%d'", d);
389 break;
390 }
391 return 0;
392}
393
395{
396 static bool initialized = false;
397 static map < string, VtkIO::DataType > datatypes;
398
399 if (!initialized) {
400 datatypes["bit"] = BIT;
401
402 datatypes["unsigned_char"] = UNSIGNED_CHAR;
403 datatypes["char"] = CHAR;
404
405 datatypes["unsigned_short"] = UNSIGNED_SHORT;
406 datatypes["short"] = SHORT;
407
408 datatypes["unsigned_int"] = UNSIGNED_INT;
409 datatypes["int"] = INT;
410
411 datatypes["unsigned_long"] = UNSIGNED_LONG;
412 datatypes["long"] = LONG;
413
414 datatypes["float"] = FLOAT;
415 datatypes["double"] = DOUBLE;
416 initialized = true;
417 }
418
419 DataType result = DATATYPE_UNKNOWN;
420
421 if (datatypes.find(datatype_name) != datatypes.end()) {
422 result = datatypes[datatype_name];
423 }
424 return result;
425}
426
428{
429
430 static bool initialized = false;
431 static map < string, DatasetType > types;
432
433 if (!initialized) {
434 types["STRUCTURED_POINTS"] = STRUCTURED_POINTS;
435 types["STRUCTURED_GRID"] = STRUCTURED_GRID;
436 types["RECTILINEAR_GRID"] = RECTILINEAR_GRID;
437 types["UNSTRUCTURED_GRID"] = UNSTRUCTURED_GRID;
438 types["POLYDATA"] = POLYDATA;
439 }
440
442 if (types.find(dataset_name) != types.end()) {
443 result = types[dataset_name];
444 }
445 return result;
446}
447
449{
450 char buf[1024];
451 int bufsz = sizeof(buf);
452
453 if (dstype == STRUCTURED_POINTS) {
454 int nlines = 3;
455 int i = 0;
456 while (i < nlines && fgets(buf, bufsz, file)) {
457 if (samestr(buf, "DIMENSIONS")) {
458 sscanf(buf, "DIMENSIONS %d %d %d", &nx, &ny, &nz);
459 }
460 else if (samestr(buf, "ORIGIN")) {
461 sscanf(buf, "ORIGIN %f %f %f", &originx, &originy, &originz);
462 }
463 else if (samestr(buf, "SPACING") || samestr(buf, "ASPECT_RATIO")) {
464 if (samestr(buf, "SPACING")) {
465 sscanf(buf, "SPACING %f %f %f", &spacingx, &spacingy, &spacingz);
466 }
467 else {
468 sscanf(buf, "ASPECT_RATIO %f %f %f", &spacingx, &spacingy, &spacingz);
469 }
470
471 if (spacingx != spacingy || spacingx != spacingz || spacingy != spacingz) {
473 "not support non-uniform spacing VTK so far\n");
474 }
475 }
476 i++;
477 }
478
479 if (i != nlines) {
480 throw ImageReadException(filename, "read VTK file failed");
481 }
482 }
483 else {
484 throw ImageReadException(filename, "only STRUCTURED_POINTS is supported so far");
485 }
486}
487
static bool is_host_big_endian()
Definition: byteorder.cpp:40
static void swap_bytes(T *data, size_t n=1)
swap the byte order of data with 'n' T-type elements.
Definition: byteorder.h:131
Dict is a dictionary to store <string, EMObject> pair.
Definition: emobject.h:385
EMDataType
Image pixel data type used in EMAN.
Definition: emutil.h:92
@ EM_UNKNOWN
Definition: emutil.h:93
@ EM_USHORT
Definition: emutil.h:97
static void get_region_origins(const Region *area, int *p_x0, int *p_y0, int *p_z0=0, int nz=1, int image_index=0)
Get a region's original locations.
Definition: emutil.cpp:891
static void get_region_dims(const Region *area, int nx, int *area_x, int ny, int *area_y, int nz=1, int *area_z=0)
Get a region's dimensions.
Definition: emutil.cpp:860
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
void check_region(const Region *area, const FloatSize &max_size, bool is_new_file=false, bool inbounds_only=true)
Validate image I/O region.
Definition: imageio.cpp:58
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
void check_read_access(int image_index)
Validate 'image_index' in file reading.
Definition: imageio.cpp:95
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.
IntSize is used to describe a 1D, 2D or 3D rectangular size in integers.
Definition: geometry.h:49
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
off_t file_offset
Definition: vtkio.h:138
float originx
Definition: vtkio.h:132
@ VTK_UNKNOWN
Definition: vtkio.h:86
@ VTK_BINARY
Definition: vtkio.h:88
@ VTK_ASCII
Definition: vtkio.h:87
@ STRUCTURED_GRID
Definition: vtkio.h:111
@ STRUCTURED_POINTS
Definition: vtkio.h:110
@ UNSTRUCTURED_GRID
Definition: vtkio.h:113
@ POLYDATA
Definition: vtkio.h:114
@ RECTILINEAR_GRID
Definition: vtkio.h:112
@ DATASET_UNKNOWN
Definition: vtkio.h:109
float spacingx
Definition: vtkio.h:135
bool is_new_file
Definition: vtkio.h:125
float spacingy
Definition: vtkio.h:136
float originz
Definition: vtkio.h:134
DataType datatype
Definition: vtkio.h:127
DataType get_datatype_from_name(const string &datatype_name)
Definition: vtkio.cpp:394
float originy
Definition: vtkio.h:133
DatasetType get_datasettype_from_name(const string &dataset_name)
Definition: vtkio.cpp:427
@ DOUBLE
Definition: vtkio.h:104
@ DATATYPE_UNKNOWN
Definition: vtkio.h:93
@ SHORT
Definition: vtkio.h:98
@ UNSIGNED_SHORT
Definition: vtkio.h:97
@ CHAR
Definition: vtkio.h:96
@ UNSIGNED_LONG
Definition: vtkio.h:101
@ UNSIGNED_CHAR
Definition: vtkio.h:95
@ UNSIGNED_INT
Definition: vtkio.h:99
int nx
Definition: vtkio.h:129
VtkType filetype
Definition: vtkio.h:128
int ny
Definition: vtkio.h:130
int get_mode_size(DataType d)
Definition: vtkio.cpp:368
static const char * MAGIC
Definition: vtkio.h:82
bool is_big_endian
Definition: vtkio.h:124
void read_dataset(DatasetType dstype)
Definition: vtkio.cpp:448
float spacingz
Definition: vtkio.h:137
int to_em_datatype(int vtk_datatype)
Definition: vtkio.cpp:353
static bool is_valid(const void *first_block)
Definition: vtkio.cpp:160
int nz
Definition: vtkio.h:131
#define ImageReadException(filename, desc)
Definition: exception.h:204
#define ImageWriteException(imagename, desc)
Definition: exception.h:223
#define LOGWARN
Definition: log.h:53
#define LOGERR
Definition: log.h:51
#define ENTERFUNC
Definition: log.h:48
#define EXITFUNC
Definition: log.h:49
E2Exception class.
Definition: aligner.h:40
off_t portable_ftell(FILE *fp)
int portable_fseek(FILE *fp, off_t offset, int whence)
static int samestr(const char *s1, const char *s2)
Definition: vtkio.cpp:71