EMAN2
pgmio.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 "pgmio.h"
33#include "geometry.h"
34#include "util.h"
35#include "portable_fileio.h"
36
37using namespace EMAN;
38
39const char *PgmIO::MAGIC_BINARY = "P5";
40const char *PgmIO::MAGIC_ASCII = "P2";
41
42PgmIO::PgmIO(const string & fname, IOMode rw)
43: ImageIO(fname, rw), is_big_endian(true),
44 nx(0), ny(0), maxval(0), minval(0),
45 file_offset(0), rendermin(0), rendermax(0), renderbits(16)
46{}
47
49{
50 if (file) {
51 fclose(file);
52 file = 0;
53 }
54}
55
56//anonymous namespace make this function local for this file
57namespace
58{
59 int read_int_and_space(FILE * in)
60 {
61 char buf[32];
62 int c = 0;
63
64 int i = 0;
65 while (!isspace(c = getc(in))) {
66 buf[i] = static_cast < char >(c);
67 i++;
68 }
69
70 return atoi(buf);
71 }
72}
73
74void PgmIO::init()
75{
77
78 if (initialized) {
79 return;
80 }
81
82 initialized = true;
83
84 bool is_new_file = false;
85 file = sfopen(filename, rw_mode, &is_new_file, true);
86
87 if (!is_new_file) {
88 const int bufsz = 1024;
89 char buf[bufsz];
90
91 buf[0] = static_cast < char >(getc(file));
92 buf[1] = static_cast < char >(getc(file));
93 buf[2] = '\0';
94 getc(file);
95
96 if (!is_valid(&buf)) {
97 throw ImageReadException(filename, "invalid PGM file");
98 }
99
100 char c = '\0';
101
102 while ((c = static_cast < char >(getc(file))) == '#') {
103 fgets(buf, bufsz, file);
104 }
105 ungetc(c, file);
106
107 nx = read_int_and_space(file);
108 ny = read_int_and_space(file);
109 maxval = read_int_and_space(file);
110
111 if (nx <= 0 || ny <= 0) {
112 throw ImageReadException(filename, "file size < 0");
113 }
114
116 }
117 EXITFUNC;
118}
119
120bool PgmIO::is_valid(const void *first_block)
121{
122 ENTERFUNC;
123 bool result = false;
124 if (first_block) {
125 result = Util::check_file_by_magic(first_block, MAGIC_BINARY);
126 }
127 EXITFUNC;
128 return result;
129}
130
131int PgmIO::read_header(Dict & dict, int image_index, const Region * area, bool)
132{
133 ENTERFUNC;
134
135 //single image format, index can only be zero
136 if(image_index == -1) {
137 image_index = 0;
138 }
139
140 if(image_index != 0) {
141 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().");
142 }
143
144 init();
145
146 check_read_access(image_index);
147 check_region(area, IntSize(nx, ny));
148 int xlen = 0, ylen = 0;
149 EMUtil::get_region_dims(area, nx, &xlen, ny, &ylen);
150
151 dict["nx"] = xlen;
152 dict["ny"] = ylen;
153 dict["nz"] = 1;
154
155 dict["PGM.max_gray"] = maxval;
156 dict["PGM.min_gray"] = minval;
157
158 EXITFUNC;
159 return 0;
160}
161
162int PgmIO::write_header(const Dict & dict, int image_index, const Region*,
163 EMUtil::EMDataType, bool)
164{
165 ENTERFUNC;
166 int err = 0;
167
168 //single image format, index can only be zero
169 if(image_index == -1) {
170 image_index = 0;
171 }
172 if(image_index != 0) {
173 throw ImageWriteException(filename, "PGM file does not support stack.");
174 }
175 check_write_access(rw_mode, image_index);
176
177 int nz = dict["nz"];
178 if ((int)nz != 1) {
179 LOGERR("Cannot write 3D image as PGM. Your image nz = %d", nz);
180 err = 1;
181 throw ImageWriteException("N/A", "Cannot write 3D image as PGM.");
182 }
183 else {
184 nx = dict["nx"];
185 ny = dict["ny"];
186
187 if (dict.has_key("min_grey")) minval = dict["min_gray"];
188 if (dict.has_key("max_grey")) maxval = dict["max_gray"];
189
190 // if we didn't get any good values from attributes, assign to 255 by default
191
193 maxval = 255;
194 }
195
197
198 fprintf(file, "%s\n%d %d\n%d\n", MAGIC_BINARY, nx, ny, maxval);
199 }
200
201 EXITFUNC;
202 return err;
203}
204
205int PgmIO::read_data(float *data, int image_index, const Region * area, bool)
206{
207 ENTERFUNC;
208
209 //single image format, index can only be zero
210 image_index = 0;
211 check_read_access(image_index, data);
212 check_region(area, IntSize(nx, ny));
213
214 portable_fseek(file, file_offset, SEEK_SET);
215
216 unsigned char *cdata = (unsigned char *) (data);
217 size_t mode_size = sizeof(unsigned char);
218
219 EMUtil::process_region_io(cdata, file, READ_ONLY, image_index,
220 mode_size, nx, ny, 1, area, true);
221
222 int xlen = 0, ylen = 0;
223 EMUtil::get_region_dims(area, nx, &xlen, ny, &ylen);
224
225 for (int k = xlen * ylen - 1; k >= 0; k--) {
226 data[k] = static_cast < float >(cdata[k]);
227 }
228
229 EXITFUNC;
230 return 0;
231}
232
233int PgmIO::write_data(float *data, int image_index, const Region* area,
234 EMUtil::EMDataType, bool)
235{
236 ENTERFUNC;
237
238 //single image format, index can only be zero
239 image_index = 0;
240/* if(area && (area->size[0]!=nx || area->size[1]!=ny)) {
241 throw ImageWriteException("N/A", "No region writing for PGM images");
242 }
243*/
244
245 check_write_access(rw_mode, image_index, 1, data);
246 check_region(area, IntSize(nx, ny));
247
248 if (renderbits==0 || renderbits>8) renderbits=8;
249
250 // If we didn't get any parameters in 'render_min' or 'render_max', we need to find some good ones
252
253 unsigned char *cdata=(unsigned char *)malloc(nx*ny); //cdata is the normalized data
254
255 int old_add = 0;
256 int new_add = 0;
257 for( int j=0; j<ny; ++j ) {
258 for( int i=0; i<nx; ++i) {
259 old_add = j*nx+i;
260 new_add = (ny-1-j)*nx + i;
261 if( data[old_add]<rendermin ) {
262 cdata[new_add] = 0;
263 }
264 else if( data[old_add]>rendermax )
265 {
266 cdata[new_add] = 255;
267 }
268 else {
269 cdata[new_add] = (unsigned char)((data[old_add]-rendermin)/(rendermax-rendermin)*256.0);
270 }
271 }
272 }
273
274 size_t mode_size = sizeof(unsigned char);
275 //fwrite(cdata, nx, ny, pgm_file);
276 EMUtil::process_region_io(cdata, file, WRITE_ONLY, image_index,
277 mode_size, nx, ny, 1, area);
278
279 free(cdata);
280 EXITFUNC;
281 return 0;
282}
283
284void PgmIO::flush()
285{
286 fflush(file);
287}
288
289
291{
292 return false;
293}
294
296{
297 init();
298 return is_big_endian;
299}
300
Dict is a dictionary to store <string, EMObject> pair.
Definition: emobject.h:385
bool has_key(const string &key) const
Ask the Dictionary if it as a particular key.
Definition: emobject.h:511
static void process_region_io(void *cdata, FILE *file, int rw_mode, int image_index, size_t mode_size, int nx, int ny, int nz=1, const Region *area=0, bool need_flip=false, ImageType imgtype=IMAGE_UNKNOWN, int pre_row=0, int post_row=0)
Process image region IO.
Definition: emutil.cpp:931
EMDataType
Image pixel data type used in EMAN.
Definition: emutil.h:92
static void getRenderMinMax(float *data, const int nx, const int ny, float &rendermin, float &rendermax, int &renderbits, const int nz=1)
Calculate the min and max pixel value accepted for image nomalization, if we did not get them from im...
Definition: emutil.cpp:1706
static void getRenderLimits(const Dict &dict, float &rendermin, float &rendermax, int &renderbits)
Get the min and max pixel value accepted for image nomalization from image attribute dictionary,...
Definition: emutil.cpp:1689
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
int nx
Definition: pgmio.h:69
int minval
Definition: pgmio.h:72
int renderbits
Definition: pgmio.h:78
int ny
Definition: pgmio.h:70
float rendermax
Definition: pgmio.h:77
off_t file_offset
Definition: pgmio.h:74
int maxval
Definition: pgmio.h:71
static bool is_valid(const void *first_block)
Definition: pgmio.cpp:120
static const char * MAGIC_BINARY
Definition: pgmio.h:57
bool is_big_endian
Definition: pgmio.h:67
float rendermin
Definition: pgmio.h:76
Region defines a 2D or 3D rectangular region specified by its origin coordinates and all edges' sizes...
Definition: geometry.h:497
static bool is_nan(const float number)
tell whether a float value is a NaN
Definition: util.h:105
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
#define ImageReadException(filename, desc)
Definition: exception.h:204
#define ImageWriteException(imagename, desc)
Definition: exception.h:223
#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)