Panda3D
pnmFileTypeIMG.cxx
1 // Filename: pnmFileTypeIMG.cxx
2 // Created by: drose (19Jun00)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "pnmFileTypeIMG.h"
16 
17 #ifdef HAVE_IMG
18 
19 #include "config_pnmimagetypes.h"
20 
21 #include "pnmFileTypeRegistry.h"
22 #include "bamReader.h"
23 
24 // Since raw image files don't have a magic number, we'll make a little
25 // sanity check on the size of the image. If either the width or height is
26 // larger than this, it must be bogus.
27 #define INSANE_SIZE 20000
28 
29 static const char * const extensions_img[] = {
30  "img"
31 };
32 static const int num_extensions_img = sizeof(extensions_img) / sizeof(const char *);
33 
34 TypeHandle PNMFileTypeIMG::_type_handle;
35 
36 ////////////////////////////////////////////////////////////////////
37 // Function: PNMFileTypeIMG::Constructor
38 // Access: Public
39 // Description:
40 ////////////////////////////////////////////////////////////////////
41 PNMFileTypeIMG::
42 PNMFileTypeIMG() {
43 }
44 
45 ////////////////////////////////////////////////////////////////////
46 // Function: PNMFileTypeIMG::get_name
47 // Access: Public, Virtual
48 // Description: Returns a few words describing the file type.
49 ////////////////////////////////////////////////////////////////////
50 string PNMFileTypeIMG::
51 get_name() const {
52  return "Raw binary RGB";
53 }
54 
55 ////////////////////////////////////////////////////////////////////
56 // Function: PNMFileTypeIMG::get_num_extensions
57 // Access: Public, Virtual
58 // Description: Returns the number of different possible filename
59 // extensions associated with this particular file type.
60 ////////////////////////////////////////////////////////////////////
61 int PNMFileTypeIMG::
62 get_num_extensions() const {
63  return num_extensions_img;
64 }
65 
66 ////////////////////////////////////////////////////////////////////
67 // Function: PNMFileTypeIMG::get_extension
68 // Access: Public, Virtual
69 // Description: Returns the nth possible filename extension
70 // associated with this particular file type, without a
71 // leading dot.
72 ////////////////////////////////////////////////////////////////////
73 string PNMFileTypeIMG::
74 get_extension(int n) const {
75  nassertr(n >= 0 && n < num_extensions_img, string());
76  return extensions_img[n];
77 }
78 
79 ////////////////////////////////////////////////////////////////////
80 // Function: PNMFileTypeIMG::get_suggested_extension
81 // Access: Public, Virtual
82 // Description: Returns a suitable filename extension (without a
83 // leading dot) to suggest for files of this type, or
84 // empty string if no suggestions are available.
85 ////////////////////////////////////////////////////////////////////
86 string PNMFileTypeIMG::
87 get_suggested_extension() const {
88  return "img";
89 }
90 
91 ////////////////////////////////////////////////////////////////////
92 // Function: PNMFileTypeIMG::make_reader
93 // Access: Public, Virtual
94 // Description: Allocates and returns a new PNMReader suitable for
95 // reading from this file type, if possible. If reading
96 // from this file type is not supported, returns NULL.
97 ////////////////////////////////////////////////////////////////////
98 PNMReader *PNMFileTypeIMG::
99 make_reader(istream *file, bool owns_file, const string &magic_number) {
100  init_pnm();
101  return new Reader(this, file, owns_file, magic_number);
102 }
103 
104 ////////////////////////////////////////////////////////////////////
105 // Function: PNMFileTypeIMG::make_writer
106 // Access: Public, Virtual
107 // Description: Allocates and returns a new PNMWriter suitable for
108 // reading from this file type, if possible. If writing
109 // files of this type is not supported, returns NULL.
110 ////////////////////////////////////////////////////////////////////
111 PNMWriter *PNMFileTypeIMG::
112 make_writer(ostream *file, bool owns_file) {
113  init_pnm();
114  return new Writer(this, file, owns_file);
115 }
116 
117 
118 inline unsigned long
119 read_ulong(istream *file) {
120  unsigned long x;
121  return pm_readbiglong(file, (long *)&x)==0 ? x : 0;
122 }
123 
124 inline unsigned short
125 read_ushort_IMG(istream *file) {
126  unsigned short x;
127  return pm_readbigshort(file, (short *)&x)==0 ? x : 0;
128 }
129 
130 inline unsigned char
131 read_uchar_IMG(istream *file) {
132  int x;
133  x = file->get();
134  return (x!=EOF) ? (unsigned char)x : 0;
135 }
136 
137 inline void
138 write_ulong(ostream *file, unsigned long x) {
139  pm_writebiglong(file, (long)x);
140 }
141 
142 inline void
143 write_ushort_IMG(ostream *file, unsigned long x) {
144  pm_writebigshort(file, (short)(long)x);
145 }
146 
147 inline void
148 write_uchar_IMG(ostream *file, unsigned char x) {
149  file->put(x);
150 }
151 
152 ////////////////////////////////////////////////////////////////////
153 // Function: PNMFileTypeIMG::Reader::Constructor
154 // Access: Public
155 // Description:
156 ////////////////////////////////////////////////////////////////////
157 PNMFileTypeIMG::Reader::
158 Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number) :
159  PNMReader(type, file, owns_file)
160 {
161  if (img_header_type == IHT_long) {
162  if (!read_magic_number(_file, magic_number, 8)) {
163  // Although raw IMG files have no magic number, they may have a
164  // pair of ushorts or ulongs at the beginning to indicate the file
165  // size.
166  if (pnmimage_img_cat.is_debug()) {
167  pnmimage_img_cat.debug()
168  << "IMG image file appears to be empty.\n";
169  }
170  _is_valid = false;
171  return;
172  }
173 
174  _x_size =
175  ((unsigned char)magic_number[0] << 24) |
176  ((unsigned char)magic_number[1] << 16) |
177  ((unsigned char)magic_number[2] << 8) |
178  ((unsigned char)magic_number[3]);
179 
180  _y_size =
181  ((unsigned char)magic_number[4] << 24) |
182  ((unsigned char)magic_number[5] << 16) |
183  ((unsigned char)magic_number[6] << 8) |
184  ((unsigned char)magic_number[7]);
185 
186  } else if (img_header_type == IHT_short) {
187  if (!read_magic_number(_file, magic_number, 4)) {
188  if (pnmimage_img_cat.is_debug()) {
189  pnmimage_img_cat.debug()
190  << "IMG image file appears to be empty.\n";
191  }
192  _is_valid = false;
193  return;
194  }
195 
196  _x_size =
197  ((unsigned char)magic_number[0] << 8) |
198  ((unsigned char)magic_number[1]);
199 
200  _y_size =
201  ((unsigned char)magic_number[2] << 8) |
202  ((unsigned char)magic_number[3]);
203 
204  } else {
205  _x_size = img_size[0];
206  _y_size = img_size[1];
207  }
208 
209  if (_x_size == 0 || _y_size == 0 ||
210  _x_size > INSANE_SIZE || _y_size > INSANE_SIZE) {
211  _is_valid = false;
212  if (img_header_type == IHT_none) {
213  pnmimage_img_cat.error()
214  << "Must specify img-xsize and img-ysize to load headerless raw files.\n";
215  } else {
216  pnmimage_img_cat.debug()
217  << "IMG file does not have a valid xsize,ysize header.\n";
218  }
219  return;
220  }
221 
222  _maxval = 255;
223  _num_channels = 3;
224 
225  if (pnmimage_img_cat.is_debug()) {
226  pnmimage_img_cat.debug()
227  << "Reading IMG " << *this << "\n";
228  }
229 }
230 
231 ////////////////////////////////////////////////////////////////////
232 // Function: PNMFileTypeIMG::Reader::supports_read_row
233 // Access: Public, Virtual
234 // Description: Returns true if this particular PNMReader supports a
235 // streaming interface to reading the data: that is, it
236 // is capable of returning the data one row at a time,
237 // via repeated calls to read_row(). Returns false if
238 // the only way to read from this file is all at once,
239 // via read_data().
240 ////////////////////////////////////////////////////////////////////
241 bool PNMFileTypeIMG::Reader::
242 supports_read_row() const {
243  return true;
244 }
245 
246 ////////////////////////////////////////////////////////////////////
247 // Function: PNMFileTypeIMG::Reader::read_row
248 // Access: Public, Virtual
249 // Description: If supports_read_row(), above, returns true, this
250 // function may be called repeatedly to read the image,
251 // one horizontal row at a time, beginning from the top.
252 // Returns true if the row is successfully read, false
253 // if there is an error or end of file.
254 ////////////////////////////////////////////////////////////////////
255 bool PNMFileTypeIMG::Reader::
256 read_row(xel *row_data, xelval *, int x_size, int) {
257  int x;
258  xelval red, grn, blu;
259  for (x = 0; x < x_size; x++) {
260  red = read_uchar_IMG(_file);
261  grn = read_uchar_IMG(_file);
262  blu = read_uchar_IMG(_file);
263 
264  PPM_ASSIGN(row_data[x], red, grn, blu);
265  }
266 
267  return true;
268 }
269 
270 ////////////////////////////////////////////////////////////////////
271 // Function: PNMFileTypeIMG::Writer::Constructor
272 // Access: Public
273 // Description:
274 ////////////////////////////////////////////////////////////////////
275 PNMFileTypeIMG::Writer::
276 Writer(PNMFileType *type, ostream *file, bool owns_file) :
277  PNMWriter(type, file, owns_file)
278 {
279 }
280 
281 ////////////////////////////////////////////////////////////////////
282 // Function: PNMFileTypeIMG::Writer::supports_write_row
283 // Access: Public, Virtual
284 // Description: Returns true if this particular PNMWriter supports a
285 // streaming interface to writing the data: that is, it
286 // is capable of writing the image one row at a time,
287 // via repeated calls to write_row(). Returns false if
288 // the only way to write from this file is all at once,
289 // via write_data().
290 ////////////////////////////////////////////////////////////////////
291 bool PNMFileTypeIMG::Writer::
292 supports_write_row() const {
293  return true;
294 }
295 
296 ////////////////////////////////////////////////////////////////////
297 // Function: PNMFileTypeIMG::Writer::write_header
298 // Access: Public, Virtual
299 // Description: If supports_write_row(), above, returns true, this
300 // function may be called to write out the image header
301 // in preparation to writing out the image data one row
302 // at a time. Returns true if the header is
303 // successfully written, false if there is an error.
304 //
305 // It is the user's responsibility to fill in the header
306 // data via calls to set_x_size(), set_num_channels(),
307 // etc., or copy_header_from(), before calling
308 // write_header().
309 ////////////////////////////////////////////////////////////////////
310 bool PNMFileTypeIMG::Writer::
311 write_header() {
312  if (img_header_type == IHT_long) {
313  write_ulong(_file, _x_size);
314  write_ulong(_file, _y_size);
315  } else if (img_header_type == IHT_short) {
316  write_ushort_IMG(_file, _x_size);
317  write_ushort_IMG(_file, _y_size);
318  }
319  return true;
320 }
321 
322 ////////////////////////////////////////////////////////////////////
323 // Function: PNMFileTypeIMG::Writer::write_row
324 // Access: Public, Virtual
325 // Description: If supports_write_row(), above, returns true, this
326 // function may be called repeatedly to write the image,
327 // one horizontal row at a time, beginning from the top.
328 // Returns true if the row is successfully written,
329 // false if there is an error.
330 //
331 // You must first call write_header() before writing the
332 // individual rows. It is also important to delete the
333 // PNMWriter class after successfully writing the last
334 // row. Failing to do this may result in some data not
335 // getting flushed!
336 ////////////////////////////////////////////////////////////////////
337 bool PNMFileTypeIMG::Writer::
338 write_row(xel *row_data, xelval *) {
339  int x;
340  for (x = 0; x < _x_size; x++) {
341  write_uchar_IMG(_file, (unsigned char)(255*PPM_GETR(row_data[x])/_maxval));
342  write_uchar_IMG(_file, (unsigned char)(255*PPM_GETG(row_data[x])/_maxval));
343  write_uchar_IMG(_file, (unsigned char)(255*PPM_GETB(row_data[x])/_maxval));
344  }
345 
346  return true;
347 }
348 
349 
350 
351 ////////////////////////////////////////////////////////////////////
352 // Function: PNMFileTypeIMG::register_with_read_factory
353 // Access: Public, Static
354 // Description: Registers the current object as something that can be
355 // read from a Bam file.
356 ////////////////////////////////////////////////////////////////////
357 void PNMFileTypeIMG::
358 register_with_read_factory() {
360  register_factory(get_class_type(), make_PNMFileTypeIMG);
361 }
362 
363 ////////////////////////////////////////////////////////////////////
364 // Function: PNMFileTypeIMG::make_PNMFileTypeIMG
365 // Access: Protected, Static
366 // Description: This method is called by the BamReader when an object
367 // of this type is encountered in a Bam file; it should
368 // allocate and return a new object with all the data
369 // read.
370 //
371 // In the case of the PNMFileType objects, since these
372 // objects are all shared, we just pull the object from
373 // the registry.
374 ////////////////////////////////////////////////////////////////////
375 TypedWritable *PNMFileTypeIMG::
376 make_PNMFileTypeIMG(const FactoryParams &params) {
377  return PNMFileTypeRegistry::get_global_ptr()->get_type_by_handle(get_class_type());
378 }
379 
380 #endif // HAVE_IMG
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:37
This is the base class of a family of classes that represent particular image file types that PNMImag...
Definition: pnmFileType.h:35
static PNMFileTypeRegistry * get_global_ptr()
Returns a pointer to the global PNMFileTypeRegistry object.
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:40
PNMFileType * get_type_by_handle(TypeHandle handle) const
Returns the PNMFileType instance stored in the registry for the given TypeHandle, e...
This is an abstract base class that defines the interface for reading image files of various types...
Definition: pnmReader.h:31
This is an abstract base class that defines the interface for writing image files of various types...
Definition: pnmWriter.h:31
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:213
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85