15 #include "pnmFileTypeSoftImage.h" 17 #ifdef HAVE_SOFTIMAGE_PIC 19 #include "config_pnmimagetypes.h" 21 #include "pnmFileTypeRegistry.h" 22 #include "bamReader.h" 24 static const float imageVersionNumber = 3.0;
25 static const int imageCommentLength = 80;
26 static const char imageComment[imageCommentLength+1] =
27 "Written by pnmimage.";
30 #define UNCOMPRESSED 0x00 31 #define MIXED_RUN_LENGTH 0x02 34 #define RGB_CHANNEL 0xe0 35 #define ALPHA_CHANNEL 0x10 38 #define SOFTIMAGE_MAGIC1 0x5380 39 #define SOFTIMAGE_MAGIC2 0xf634 41 static const char *
const extensions_softimage[] = {
44 static const int num_extensions_softimage =
sizeof(extensions_softimage) /
sizeof(
const char *);
49 read_float(istream *file) {
52 if (pm_readbiglong(file, &l)==0) {
60 read_ushort_SI(istream *file) {
62 return pm_readbigshort(file, (
short *)&x)==0 ? x : 0;
66 read_uchar_SI(istream *file) {
69 return (x!=EOF) ? (
unsigned char)x : 0;
73 write_ushort_SI(ostream *file,
unsigned short x) {
74 pm_writebigshort(file, (
short)x);
78 write_uchar_SI(ostream *file,
unsigned char x) {
83 write_float(ostream *file,
float x) {
84 pm_writebiglong(file, *(
long *)&x);
88 read_channel_pkt(istream *file,
89 int &chained,
int &size,
int &type,
int &channel) {
90 chained = read_uchar_SI(file);
91 size = read_uchar_SI(file);
92 type = read_uchar_SI(file);
93 channel = read_uchar_SI(file);
95 if (file->eof() || file->fail()) {
100 pnmimage_soft_cat.error()
101 <<
"Don't know how to interpret " << size <<
" bits per pixel!\n";
109 read_rgb(
xel *row_data, xelval *, istream *file,
int x,
int repeat) {
110 xelval red, grn, blu;
111 red = read_uchar_SI(file);
112 grn = read_uchar_SI(file);
113 blu = read_uchar_SI(file);
116 PPM_ASSIGN(row_data[x], red, grn, blu);
123 read_alpha(
xel *, xelval *alpha_data, istream *file,
int x,
int repeat) {
124 xelval alpha = read_uchar_SI(file);
127 alpha_data[x] = alpha;
134 read_rgba(
xel *row_data, xelval *alpha_data, istream *file,
int x,
int repeat) {
135 xelval red, grn, blu, alpha;
136 red = read_uchar_SI(file);
137 grn = read_uchar_SI(file);
138 blu = read_uchar_SI(file);
139 alpha = read_uchar_SI(file);
142 PPM_ASSIGN(row_data[x], red, grn, blu);
143 alpha_data[x] = alpha;
151 read_scanline(
xel *row_data, xelval *alpha_data,
int cols, istream *file,
152 void (*read_data)(
xel *row_data, xelval *alpha_data, istream *file,
155 if (ctype==UNCOMPRESSED) {
156 for (
int x = 0; x<cols; x++) {
157 read_data(row_data, alpha_data, file, x, 1);
166 num = read_uchar_SI(file);
175 read_data(row_data, alpha_data, file, x, 1);
176 if (file->eof() || file->fail()) {
185 num = read_ushort_SI(file);
192 read_data(row_data, alpha_data, file, x, num);
193 if (file->eof() || file->fail()) {
209 PNMFileTypeSoftImage::
210 PNMFileTypeSoftImage() {
218 string PNMFileTypeSoftImage::
229 int PNMFileTypeSoftImage::
230 get_num_extensions()
const {
231 return num_extensions_softimage;
241 string PNMFileTypeSoftImage::
242 get_extension(
int n)
const {
243 nassertr(n >= 0 && n < num_extensions_softimage,
string());
244 return extensions_softimage[n];
254 string PNMFileTypeSoftImage::
255 get_suggested_extension()
const {
265 bool PNMFileTypeSoftImage::
266 has_magic_number()
const {
277 bool PNMFileTypeSoftImage::
278 matches_magic_number(
const string &magic_number)
const {
279 nassertr(magic_number.size() >= 2,
false);
281 ((
unsigned char)magic_number[0] << 8) |
282 ((
unsigned char)magic_number[1]);
283 return (mn == SOFTIMAGE_MAGIC1);
294 make_reader(istream *file,
bool owns_file,
const string &magic_number) {
296 return new Reader(
this, file, owns_file, magic_number);
307 make_writer(ostream *file,
bool owns_file) {
309 return new Writer(
this, file, owns_file);
318 PNMFileTypeSoftImage::Reader::
319 Reader(
PNMFileType *type, istream *file,
bool owns_file,
string magic_number) :
324 if (pnmimage_soft_cat.is_debug()) {
325 pnmimage_soft_cat.debug()
326 <<
"SoftImage image file appears to be empty.\n";
333 ((
unsigned char)magic_number[0] << 8) |
334 ((
unsigned char)magic_number[1]);
336 ((
unsigned char)magic_number[2] << 8) |
337 ((
unsigned char)magic_number[3]);
339 if (magic1 != SOFTIMAGE_MAGIC1 || magic2 != SOFTIMAGE_MAGIC2) {
348 _file->seekg(imageCommentLength, ios::cur);
351 _file->read(pict_id, 4);
352 if (_file->gcount() < 4) {
357 if (memcmp(pict_id,
"PICT", 4)!=0) {
362 _x_size = read_ushort_SI(_file);
363 _y_size = read_ushort_SI(_file);
366 read_ushort_SI(_file);
367 read_ushort_SI(_file);
369 int chained, size, channel;
370 if (!read_channel_pkt(_file, chained, size, rgb_ctype, channel)) {
375 soft_color = unknown;
377 if (channel == (RGB_CHANNEL | ALPHA_CHANNEL)) {
381 }
else if (channel == RGB_CHANNEL) {
386 if (!read_channel_pkt(_file, chained, size, alpha_ctype, channel)) {
391 if (channel == ALPHA_CHANNEL) {
398 switch (soft_color) {
409 pnmimage_soft_cat.error()
410 <<
"Image is not RGB or RGBA!\n";
416 pnmimage_soft_cat.error()
417 <<
"Unexpected additional channels in image file.\n";
424 if (pnmimage_soft_cat.is_debug()) {
425 pnmimage_soft_cat.debug()
426 <<
"Reading SoftImage " << *
this <<
"\n";
441 bool PNMFileTypeSoftImage::Reader::
442 supports_read_row()
const {
455 bool PNMFileTypeSoftImage::Reader::
456 read_row(
xel *row_data, xelval *alpha_data,
int x_size,
int) {
460 switch (soft_color) {
462 if (!read_scanline(row_data, alpha_data, x_size, _file,
463 read_rgb, rgb_ctype)) {
469 if (!read_scanline(row_data, alpha_data, x_size, _file,
470 read_rgba, rgb_ctype)) {
476 if (!read_scanline(row_data, alpha_data, x_size, _file,
477 read_rgb, rgb_ctype)) {
480 if (!read_scanline(row_data, alpha_data, x_size, _file,
481 read_alpha, alpha_ctype)) {
495 write_channel_pkt(ostream *file,
496 int chained,
int size,
int type,
int channel) {
497 write_uchar_SI(file, chained);
498 write_uchar_SI(file, size);
499 write_uchar_SI(file, type);
500 write_uchar_SI(file, channel);
504 write_rgb(
xel *row_data, xelval *, ostream *file,
int x) {
505 write_uchar_SI(file, PPM_GETR(row_data[x]));
506 write_uchar_SI(file, PPM_GETG(row_data[x]));
507 write_uchar_SI(file, PPM_GETB(row_data[x]));
511 compare_rgb(
xel *row_data, xelval *,
int x1,
int x2) {
512 return PPM_EQUAL(row_data[x1], row_data[x2]);
516 write_gray(
xel *row_data, xelval *, ostream *file,
int x) {
517 write_uchar_SI(file, PPM_GETB(row_data[x]));
518 write_uchar_SI(file, PPM_GETB(row_data[x]));
519 write_uchar_SI(file, PPM_GETB(row_data[x]));
523 compare_gray(
xel *row_data, xelval *,
int x1,
int x2) {
524 return (PPM_GETB(row_data[x1])==PPM_GETB(row_data[x2]));
528 write_alpha(
xel *, xelval *alpha_data, ostream *file,
int x) {
529 write_uchar_SI(file, alpha_data[x]);
533 compare_alpha(
xel *, xelval *alpha_data,
int x1,
int x2) {
534 return (alpha_data[x1]==alpha_data[x2]);
538 write_diff(
xel *row_data, xelval *alpha_data, ostream *file,
539 void (*
write_data)(
xel *row_data, xelval *alpha_data, ostream *file,
541 int tox,
int length) {
543 nassertv(length<=128);
545 write_uchar_SI(file, length-1);
548 write_data(row_data, alpha_data, file, tox-length);
554 write_same(
xel *row_data, xelval *alpha_data, ostream *file,
555 void (*
write_data)(
xel *row_data, xelval *alpha_data, ostream *file,
557 int tox,
int length) {
559 write_diff(row_data, alpha_data, file,
write_data, tox, length);
561 }
else if (length>0) {
563 write_uchar_SI(file, length+127);
565 write_uchar_SI(file, 128);
566 write_ushort_SI(file, length);
574 write_scanline(
xel *row_data, xelval *alpha_data,
int cols, ostream *file,
575 int (*compare_data)(
xel *row_data, xelval *alpha_data,
578 ostream *file,
int x)) {
593 if (!compare_data(row_data, alpha_data, x, x-run_length)) {
596 if (run_length <= 1) {
607 write_same(row_data, alpha_data, file,
write_data, x-1, run_length);
618 if (run_length>128) {
622 int excess = run_length - 128;
623 write_diff(row_data, alpha_data, file,
write_data, x-excess-1, 128);
626 }
else if (run_length > 2 &&
627 compare_data(row_data, alpha_data, x, x-1) &&
628 compare_data(row_data, alpha_data, x, x-2)) {
633 write_diff(row_data, alpha_data, file,
write_data, x-3, run_length-2);
647 write_same(row_data, alpha_data, file,
write_data, cols-1, run_length);
652 if (run_length>128) {
653 int excess = run_length - 128;
654 write_diff(row_data, alpha_data, file,
write_data, cols-excess-1, 128);
658 write_diff(row_data, alpha_data, file,
write_data, cols-1, run_length);
668 PNMFileTypeSoftImage::Writer::
669 Writer(
PNMFileType *type, ostream *file,
bool owns_file) :
684 bool PNMFileTypeSoftImage::Writer::
685 supports_write_row()
const {
703 bool PNMFileTypeSoftImage::Writer::
705 write_ushort_SI(_file, SOFTIMAGE_MAGIC1);
706 write_ushort_SI(_file, SOFTIMAGE_MAGIC2);
707 write_float(_file, imageVersionNumber);
709 _file->write(imageComment, imageCommentLength);
710 _file->write(
"PICT", 4);
712 write_ushort_SI(_file, _x_size);
713 write_ushort_SI(_file, _y_size);
715 write_float(_file, 1.0);
716 write_ushort_SI(_file, 3);
717 write_ushort_SI(_file, 0);
723 write_channel_pkt(_file, 1, 8, MIXED_RUN_LENGTH, RGB_CHANNEL);
724 write_channel_pkt(_file, 0, 8, MIXED_RUN_LENGTH, ALPHA_CHANNEL);
726 write_channel_pkt(_file, 0, 8, MIXED_RUN_LENGTH, RGB_CHANNEL);
747 bool PNMFileTypeSoftImage::Writer::
748 write_row(
xel *row_data, xelval *alpha_data) {
750 write_scanline(row_data, alpha_data, _x_size, _file, compare_gray, write_gray);
753 write_scanline(row_data, alpha_data, _x_size, _file, compare_rgb, write_rgb);
757 write_scanline(row_data, alpha_data, _x_size, _file, compare_alpha, write_alpha);
760 return !_file->fail();
771 void PNMFileTypeSoftImage::
772 register_with_read_factory() {
774 register_factory(get_class_type(), make_PNMFileTypeSoftImage);
794 #endif // HAVE_SOFTIMAGE_PIC bool is_valid() const
Returns true if the PNMWriter can be used to write data, false if something is wrong.
Base class for objects that can be written to and read from Bam files.
This is the base class of a family of classes that represent particular image file types that PNMImag...
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...
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...
This is an abstract base class that defines the interface for writing image files of various types...
virtual int write_data(xel *array, xelval *alpha)
Writes out an entire image all at once, including the header, based on the image data stored in the g...
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
TypeHandle is the identifier used to differentiate C++ class types.