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 }
PNMFileTypePfm::Reader
Definition: pnmFileTypePfm.h:46
PfmFile::set_scale
set_scale
The "scale" is reported in the pfm header and is probably meaningless.
Definition: pfmFile.h:57
PfmFile::clear
void clear()
Eliminates all data in the file.
Definition: pfmFile.cxx:77
pvector
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:42
PNMFileTypeRegistry::get_type_by_handle
PNMFileType * get_type_by_handle(TypeHandle handle) const
Returns the PNMFileType instance stored in the registry for the given TypeHandle, e....
Definition: pnmFileTypeRegistry.cxx:233
PNMFileTypePfm::get_name
virtual std::string get_name() const
Returns a few words describing the file type.
Definition: pnmFileTypePfm.cxx:38
PNMFileTypePfm::Reader::read_pfm
virtual bool read_pfm(PfmFile &pfm)
Reads floating-point data directly into the indicated PfmFile.
Definition: pnmFileTypePfm.cxx:178
ReversedNumericData::store_value
void store_value(void *dest, size_t length) const
Copies the data, with byte reversal if appropriate, into the indicated numeric variable,...
Definition: reversedNumericData.I:41
BamReader::get_factory
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
pfmFile.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PNMFileTypePfm::Writer::supports_integer
virtual bool supports_integer()
Returns true if this PNMFileType can accept an integer image type, false if it can only accept a floa...
Definition: pnmFileTypePfm.cxx:256
bamReader.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PNMFileTypePfm::Writer::write_pfm
virtual bool write_pfm(const PfmFile &pfm)
Writes floating-point data from the indicated PfmFile.
Definition: pnmFileTypePfm.cxx:265
TypedWritable
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
PNMFileTypePfm::Writer::supports_floating_point
virtual bool supports_floating_point()
Returns true if this PNMFileType can accept a floating-point image type, false if it can only accept ...
Definition: pnmFileTypePfm.cxx:246
PNMImageHeader::get_x_size
int get_x_size() const
Returns the number of pixels in the X direction.
Definition: pnmImageHeader.I:144
PNMImageHeader::get_num_channels
get_num_channels
Returns the number of channels in the image.
Definition: pnmImageHeader.h:60
PfmFile::swap_table
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
PfmFile
Defines a pfm file, a 2-d table of floating-point numbers, either 3-component or 1-component,...
Definition: pfmFile.h:31
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
FactoryParams
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
PNMImageHeader::get_y_size
int get_y_size() const
Returns the number of pixels in the Y direction.
Definition: pnmImageHeader.I:153
PNMFileTypePfm::get_suggested_extension
virtual std::string get_suggested_extension() const
Returns a suitable filename extension (without a leading dot) to suggest for files of this type,...
Definition: pnmFileTypePfm.cxx:65
PNMFileTypeRegistry::get_global_ptr
static PNMFileTypeRegistry * get_global_ptr()
Returns a pointer to the global PNMFileTypeRegistry object.
Definition: pnmFileTypeRegistry.cxx:277
PfmFile::get_table
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
pnmFileTypePfm.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
ReversedNumericData
NativeNumericData and ReversedNumericData work together to provide a sneaky interface for automatical...
Definition: reversedNumericData.h:42
PNMFileType::get_extension
get_extension
Returns the nth possible filename extension associated with this particular file type,...
Definition: pnmFileType.h:44
PNMReader
This is an abstract base class that defines the interface for reading image files of various types.
Definition: pnmReader.h:27
PfmFile::get_scale
get_scale
The "scale" is reported in the pfm header and is probably meaningless.
Definition: pfmFile.h:57
pnmFileTypeRegistry.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PNMFileTypePfm::make_reader
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.
Definition: pnmFileTypePfm.cxx:97
PNMFileTypePfm::Reader::is_floating_point
virtual bool is_floating_point()
Returns true if this PNMFileType represents a floating-point image type, false if it is a normal,...
Definition: pnmFileTypePfm.cxx:169
PNMWriter
This is an abstract base class that defines the interface for writing image files of various types.
Definition: pnmWriter.h:27
PNMFileTypePfm::get_num_extensions
virtual int get_num_extensions() const
Returns the number of different possible filename extensions associated with this particular file typ...
Definition: pnmFileTypePfm.cxx:47
PNMFileTypePfm::Writer
Definition: pnmFileTypePfm.h:57
PNMFileTypePfm::matches_magic_number
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...
Definition: pnmFileTypePfm.cxx:84
PNMFileType
This is the base class of a family of classes that represent particular image file types that PNMImag...
Definition: pnmFileType.h:32
PNMFileTypePfm::make_writer
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.
Definition: pnmFileTypePfm.cxx:107
config_pnmimage.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PNMFileTypePfm::has_magic_number
virtual bool has_magic_number() const
Returns true if this particular file type uses a magic number to identify it, false otherwise.
Definition: pnmFileTypePfm.cxx:74
PNMFileTypePfm::register_with_read_factory
static void register_with_read_factory()
Registers the current object as something that can be read from a Bam file.
Definition: pnmFileTypePfm.cxx:317