Panda3D
pnmFileTypePfm.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file pnmFileTypePfm.cxx
10  * @author drose
11  * @date 1998-04-04
12  */
13 
14 #include "pnmFileTypePfm.h"
15 #include "pfmFile.h"
16 #include "config_pnmimage.h"
17 
18 #include "pnmFileTypeRegistry.h"
19 #include "bamReader.h"
20 
21 using std::istream;
22 using std::ostream;
23 using std::string;
24 
25 TypeHandle PNMFileTypePfm::_type_handle;
26 
27 /**
28  *
29  */
30 PNMFileTypePfm::
31 PNMFileTypePfm() {
32 }
33 
34 /**
35  * Returns a few words describing the file type.
36  */
37 string PNMFileTypePfm::
38 get_name() const {
39  return "Portable Float Map";
40 }
41 
42 /**
43  * Returns the number of different possible filename extensions associated
44  * with this particular file type.
45  */
48  return 1;
49 }
50 
51 /**
52  * Returns the nth possible filename extension associated with this particular
53  * file type, without a leading dot.
54  */
55 string PNMFileTypePfm::
56 get_extension(int n) const {
57  return "pfm";
58 }
59 
60 /**
61  * Returns a suitable filename extension (without a leading dot) to suggest
62  * for files of this type, or empty string if no suggestions are available.
63  */
64 string PNMFileTypePfm::
66  return "pfm";
67 }
68 
69 /**
70  * Returns true if this particular file type uses a magic number to identify
71  * it, false otherwise.
72  */
75  return true;
76 }
77 
78 /**
79  * Returns true if the indicated "magic number" byte stream (the initial few
80  * bytes read from the file) matches this particular file type, false
81  * otherwise.
82  */
84 matches_magic_number(const string &magic_number) const {
85  return (magic_number.size() >= 2) &&
86  (magic_number.substr(0, 2) == "PF" ||
87  magic_number.substr(0, 2) == "Pf" ||
88  magic_number.substr(0, 2) == "pf");
89 }
90 
91 /**
92  * Allocates and returns a new PNMReader suitable for reading from this file
93  * type, if possible. If reading from this file type is not supported,
94  * returns NULL.
95  */
97 make_reader(istream *file, bool owns_file, const string &magic_number) {
98  return new Reader(this, file, owns_file, magic_number);
99 }
100 
101 /**
102  * Allocates and returns a new PNMWriter suitable for reading from this file
103  * type, if possible. If writing files of this type is not supported, returns
104  * NULL.
105  */
107 make_writer(ostream *file, bool owns_file) {
108  return new Writer(this, file, owns_file);
109 }
110 
111 
112 /**
113  *
114  */
115 PNMFileTypePfm::Reader::
116 Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number) :
117  PNMReader(type, file, owns_file)
118 {
119  read_magic_number(_file, magic_number, 2);
120 
121  if (magic_number == "pf") {
122  // In this case, we're probably reading a special-extension 4-channel pfm
123  // file, and we need a four-byte magic number to confirm this and fully
124  // identify the file format.
125  read_magic_number(_file, magic_number, 4);
126  }
127 
128  if (magic_number == "PF") {
129  _num_channels = 3;
130 
131  } else if (magic_number == "Pf") {
132  _num_channels = 1;
133 
134  } else if (magic_number == "pf2c") {
135  // Special DRZ extension.
136  _num_channels = 2;
137 
138  } else if (magic_number == "pf4c") {
139  // Special DRZ extension.
140  _num_channels = 4;
141 
142  } else {
143  pnmimage_cat.debug()
144  << "Not a PFM file\n";
145  _is_valid = false;
146  return;
147  }
148 
149  _maxval = PGM_MAXMAXVAL;
150 
151  (*_file) >> _x_size >> _y_size >> _scale;
152  if (!(*_file)) {
153  pnmimage_cat.debug()
154  << "Error parsing PFM header\n";
155  _is_valid = false;
156  return;
157  }
158 
159  // Skip the last newlinewhitespace character before the raw data begins.
160  (*_file).get();
161 }
162 
163 /**
164  * Returns true if this PNMFileType represents a floating-point image type,
165  * false if it is a normal, integer type. If this returns true, read_pfm() is
166  * implemented instead of read_data().
167  */
170  return true;
171 }
172 
173 /**
174  * Reads floating-point data directly into the indicated PfmFile. Returns
175  * true on success, false on failure.
176  */
179  if (!is_valid()) {
180  return false;
181  }
182 
183  bool little_endian = false;
184  if (_scale < 0) {
185  _scale = -_scale;
186  little_endian = true;
187  }
188  if (pfm_force_littleendian) {
189  little_endian = true;
190  }
191  if (pfm_reverse_dimensions) {
192  int t = _x_size;
193  _x_size = _y_size;
194  _y_size = t;
195  }
196 
197  pfm.clear(_x_size, _y_size, _num_channels);
198  pfm.set_scale(_scale);
199 
200  // So far, so good. Now read the data.
201  int size = _x_size * _y_size * _num_channels;
202 
203  pvector<PN_float32> table;
204  pfm.swap_table(table);
205 
206  (*_file).read((char *)&table[0], sizeof(PN_float32) * size);
207  if ((*_file).fail() && !(*_file).eof()) {
208  pfm.clear();
209  return false;
210  }
211 
212  // Now we may have to endian-reverse the data.
213 #ifdef WORDS_BIGENDIAN
214  bool endian_reversed = little_endian;
215 #else
216  bool endian_reversed = !little_endian;
217 #endif
218 
219  if (endian_reversed) {
220  for (int ti = 0; ti < size; ++ti) {
221  ReversedNumericData nd(&table[ti], sizeof(PN_float32));
222  nd.store_value(&table[ti], sizeof(PN_float32));
223  }
224  }
225 
226  pfm.swap_table(table);
227  return true;
228 }
229 
230 
231 /**
232  *
233  */
234 PNMFileTypePfm::Writer::
235 Writer(PNMFileType *type, ostream *file, bool owns_file) :
236  PNMWriter(type, file, owns_file)
237 {
238 }
239 
240 /**
241  * Returns true if this PNMFileType can accept a floating-point image type,
242  * false if it can only accept a normal, integer type. If this returns true,
243  * write_pfm() is implemented.
244  */
247  return true;
248 }
249 
250 /**
251  * Returns true if this PNMFileType can accept an integer image type, false if
252  * it can only accept a floating-point type. If this returns true,
253  * write_data() or write_row() is implemented.
254  */
257  return false;
258 }
259 
260 /**
261  * Writes floating-point data from the indicated PfmFile. Returns true on
262  * success, false on failure.
263  */
265 write_pfm(const PfmFile &pfm) {
266  nassertr(pfm.is_valid(), false);
267 
268  switch (pfm.get_num_channels()) {
269  case 1:
270  (*_file) << "Pf\n";
271  break;
272 
273  case 2:
274  (*_file) << "pf2c\n";
275  break;
276 
277  case 3:
278  (*_file) << "PF\n";
279  break;
280 
281  case 4:
282  (*_file) << "pf4c\n";
283  break;
284 
285  default:
286  nassert_raise("unexpected channel count");
287  return false;
288  }
289  (*_file) << pfm.get_x_size() << " " << pfm.get_y_size() << "\n";
290 
291  PN_float32 scale = cabs(pfm.get_scale());
292  if (scale == 0.0f) {
293  scale = 1.0f;
294  }
295 #ifndef WORDS_BIGENDIAN
296  // Little-endian computers must write a negative scale to indicate the
297  // little-endian nature of the output.
298  scale = -scale;
299 #endif
300  (*_file) << scale << "\n";
301 
302  int size = pfm.get_x_size() * pfm.get_y_size() * pfm.get_num_channels();
303  const pvector<PN_float32> &table = pfm.get_table();
304  (*_file).write((const char *)&table[0], sizeof(PN_float32) * size);
305 
306  if ((*_file).fail()) {
307  return false;
308  }
309  nassertr(sizeof(PN_float32) == 4, false);
310  return true;
311 }
312 
313 /**
314  * Registers the current object as something that can be read from a Bam file.
315  */
316 void PNMFileTypePfm::
319  register_factory(get_class_type(), make_PNMFileTypePfm);
320 }
321 
322 /**
323  * This method is called by the BamReader when an object of this type is
324  * encountered in a Bam file; it should allocate and return a new object with
325  * all the data read.
326  *
327  * In the case of the PNMFileType objects, since these objects are all shared,
328  * we just pull the object from the registry.
329  */
330 TypedWritable *PNMFileTypePfm::
331 make_PNMFileTypePfm(const FactoryParams &params) {
332  return PNMFileTypeRegistry::get_global_ptr()->get_type_by_handle(get_class_type());
333 }
virtual std::string get_name() const
Returns a few words describing the file type.
virtual std::string get_extension(int n) const
Returns the nth possible filename extension associated with this particular file type,...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual bool write_pfm(const PfmFile &pfm)
Writes floating-point data from the indicated PfmFile.
get_num_channels
Returns the number of channels in the image.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
This is the base class of a family of classes that represent particular image file types that PNMImag...
Definition: pnmFileType.h:32
virtual PNMWriter * make_writer(std::ostream *file, bool owns_file=true)
Allocates and returns a new PNMWriter suitable for reading from this file type, if possible.
virtual bool matches_magic_number(const std::string &magic_number) const
Returns true if the indicated "magic number" byte stream (the initial few bytes read from the file) m...
int get_y_size() const
Returns the number of pixels in the Y direction.
int get_x_size() const
Returns the number of pixels in the X direction.
static PNMFileTypeRegistry * get_global_ptr()
Returns a pointer to the global PNMFileTypeRegistry object.
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:42
virtual bool is_floating_point()
Returns true if this PNMFileType represents a floating-point image type, false if it is a normal,...
void swap_table(vector_float &table)
This is a very low-level function that completely exchanges the PfmFile's internal table of floating-...
Definition: pfmFile.I:549
virtual bool has_magic_number() const
Returns true if this particular file type uses a magic number to identify it, false otherwise.
virtual bool supports_floating_point()
Returns true if this PNMFileType can accept a floating-point image type, false if it can only accept ...
Defines a pfm file, a 2-d table of floating-point numbers, either 3-component or 1-component,...
Definition: pfmFile.h:31
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual bool read_pfm(PfmFile &pfm)
Reads floating-point data directly into the indicated PfmFile.
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
const vector_float & get_table() const
This is a very low-level function that returns a read-only reference to the internal table of floatin...
Definition: pfmFile.I:538
PNMFileType * get_type_by_handle(TypeHandle handle) const
Returns the PNMFileType instance stored in the registry for the given TypeHandle, e....
virtual bool supports_integer()
Returns true if this PNMFileType can accept an integer image type, false if it can only accept a floa...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual std::string get_suggested_extension() const
Returns a suitable filename extension (without a leading dot) to suggest for files of this type,...
get_scale
The "scale" is reported in the pfm header and is probably meaningless.
Definition: pfmFile.h:57
This is an abstract base class that defines the interface for reading image files of various types.
Definition: pnmReader.h:27
This is an abstract base class that defines the interface for writing image files of various types.
Definition: pnmWriter.h:27
NativeNumericData and ReversedNumericData work together to provide a sneaky interface for automatical...
virtual int get_num_extensions() const
Returns the number of different possible filename extensions associated with this particular file typ...
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual PNMReader * make_reader(std::istream *file, bool owns_file=true, const std::string &magic_number=std::string())
Allocates and returns a new PNMReader suitable for reading from this file type, if possible.
static void register_with_read_factory()
Registers the current object as something that can be read from a Bam file.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
void store_value(void *dest, size_t length) const
Copies the data, with byte reversal if appropriate, into the indicated numeric variable,...
set_scale
The "scale" is reported in the pfm header and is probably meaningless.
Definition: pfmFile.h:57
void clear()
Eliminates all data in the file.
Definition: pfmFile.cxx:77