16#ifdef HAVE_SOFTIMAGE_PIC
27static const float imageVersionNumber = 3.0;
28static const int imageCommentLength = 80;
29static const char imageComment[imageCommentLength+1] =
30 "Written by pnmimage.";
33#define UNCOMPRESSED 0x00
34#define MIXED_RUN_LENGTH 0x02
37#define RGB_CHANNEL 0xe0
38#define ALPHA_CHANNEL 0x10
41#define SOFTIMAGE_MAGIC1 0x5380
42#define SOFTIMAGE_MAGIC2 0xf634
44static const char *
const extensions_softimage[] = {
47static const int num_extensions_softimage =
sizeof(extensions_softimage) /
sizeof(
const char *);
52read_float(istream *file) {
55 if (pm_readbiglong(file, &l)==0) {
63read_ushort_SI(istream *file) {
65 return pm_readbigshort(file, (
short *)&x)==0 ? x : 0;
69read_uchar_SI(istream *file) {
72 return (x!=EOF) ? (
unsigned char)x : 0;
76write_ushort_SI(ostream *file,
unsigned short x) {
77 pm_writebigshort(file, (
short)x);
81write_uchar_SI(ostream *file,
unsigned char x) {
86write_float(ostream *file,
float x) {
87 pm_writebiglong(file, *(
long *)&x);
91read_channel_pkt(istream *file,
92 int &chained,
int &size,
int &type,
int &channel) {
93 chained = read_uchar_SI(file);
94 size = read_uchar_SI(file);
95 type = read_uchar_SI(file);
96 channel = read_uchar_SI(file);
98 if (file->eof() || file->fail()) {
103 pnmimage_soft_cat.error()
104 <<
"Don't know how to interpret " << size <<
" bits per pixel!\n";
112read_rgb(
xel *row_data, xelval *, istream *file,
int x,
int repeat) {
113 xelval red, grn, blu;
114 red = read_uchar_SI(file);
115 grn = read_uchar_SI(file);
116 blu = read_uchar_SI(file);
119 PPM_ASSIGN(row_data[x], red, grn, blu);
126read_alpha(
xel *, xelval *alpha_data, istream *file,
int x,
int repeat) {
127 xelval alpha = read_uchar_SI(file);
130 alpha_data[x] = alpha;
137read_rgba(
xel *row_data, xelval *alpha_data, istream *file,
int x,
int repeat) {
138 xelval red, grn, blu, alpha;
139 red = read_uchar_SI(file);
140 grn = read_uchar_SI(file);
141 blu = read_uchar_SI(file);
142 alpha = read_uchar_SI(file);
145 PPM_ASSIGN(row_data[x], red, grn, blu);
146 alpha_data[x] = alpha;
154read_scanline(
xel *row_data, xelval *alpha_data,
int cols, istream *file,
155 void (*read_data)(
xel *row_data, xelval *alpha_data, istream *file,
158 if (ctype==UNCOMPRESSED) {
159 for (
int x = 0; x<cols; x++) {
160 read_data(row_data, alpha_data, file, x, 1);
169 num = read_uchar_SI(file);
178 read_data(row_data, alpha_data, file, x, 1);
179 if (file->eof() || file->fail()) {
188 num = read_ushort_SI(file);
195 read_data(row_data, alpha_data, file, x, num);
196 if (file->eof() || file->fail()) {
210PNMFileTypeSoftImage::
211PNMFileTypeSoftImage() {
217string PNMFileTypeSoftImage::
226int PNMFileTypeSoftImage::
227get_num_extensions()
const {
228 return num_extensions_softimage;
235string PNMFileTypeSoftImage::
236get_extension(
int n)
const {
237 nassertr(n >= 0 && n < num_extensions_softimage,
string());
238 return extensions_softimage[n];
245string PNMFileTypeSoftImage::
246get_suggested_extension()
const {
254bool PNMFileTypeSoftImage::
255has_magic_number()
const {
264bool PNMFileTypeSoftImage::
265matches_magic_number(
const string &magic_number)
const {
266 nassertr(magic_number.size() >= 2,
false);
268 ((
unsigned char)magic_number[0] << 8) |
269 ((
unsigned char)magic_number[1]);
270 return (mn == SOFTIMAGE_MAGIC1);
279make_reader(istream *file,
bool owns_file,
const string &magic_number) {
281 return new Reader(
this, file, owns_file, magic_number);
290make_writer(ostream *file,
bool owns_file) {
292 return new Writer(
this, file, owns_file);
299PNMFileTypeSoftImage::Reader::
300Reader(
PNMFileType *type, istream *file,
bool owns_file,
string magic_number) :
303 if (!read_magic_number(_file, magic_number, 4)) {
305 if (pnmimage_soft_cat.is_debug()) {
306 pnmimage_soft_cat.debug()
307 <<
"SoftImage image file appears to be empty.\n";
314 ((
unsigned char)magic_number[0] << 8) |
315 ((
unsigned char)magic_number[1]);
317 ((
unsigned char)magic_number[2] << 8) |
318 ((
unsigned char)magic_number[3]);
320 if (magic1 != SOFTIMAGE_MAGIC1 || magic2 != SOFTIMAGE_MAGIC2) {
329 _file->seekg(imageCommentLength, std::ios::cur);
332 _file->read(pict_id, 4);
333 if (_file->gcount() < 4) {
338 if (memcmp(pict_id,
"PICT", 4)!=0) {
343 _x_size = read_ushort_SI(_file);
344 _y_size = read_ushort_SI(_file);
347 read_ushort_SI(_file);
348 read_ushort_SI(_file);
350 int chained, size, channel;
351 if (!read_channel_pkt(_file, chained, size, rgb_ctype, channel)) {
356 soft_color = unknown;
358 if (channel == (RGB_CHANNEL | ALPHA_CHANNEL)) {
362 }
else if (channel == RGB_CHANNEL) {
367 if (!read_channel_pkt(_file, chained, size, alpha_ctype, channel)) {
372 if (channel == ALPHA_CHANNEL) {
379 switch (soft_color) {
390 pnmimage_soft_cat.error()
391 <<
"Image is not RGB or RGBA!\n";
397 pnmimage_soft_cat.error()
398 <<
"Unexpected additional channels in image file.\n";
405 if (pnmimage_soft_cat.is_debug()) {
406 pnmimage_soft_cat.debug()
407 <<
"Reading SoftImage " << *
this <<
"\n";
418bool PNMFileTypeSoftImage::Reader::
419supports_read_row()
const {
429bool PNMFileTypeSoftImage::Reader::
430read_row(
xel *row_data, xelval *alpha_data,
int x_size,
int) {
434 switch (soft_color) {
436 if (!read_scanline(row_data, alpha_data, x_size, _file,
437 read_rgb, rgb_ctype)) {
443 if (!read_scanline(row_data, alpha_data, x_size, _file,
444 read_rgba, rgb_ctype)) {
450 if (!read_scanline(row_data, alpha_data, x_size, _file,
451 read_rgb, rgb_ctype)) {
454 if (!read_scanline(row_data, alpha_data, x_size, _file,
455 read_alpha, alpha_ctype)) {
469write_channel_pkt(ostream *file,
470 int chained,
int size,
int type,
int channel) {
471 write_uchar_SI(file, chained);
472 write_uchar_SI(file, size);
473 write_uchar_SI(file, type);
474 write_uchar_SI(file, channel);
478write_rgb(
xel *row_data, xelval *, ostream *file,
int x) {
479 write_uchar_SI(file, PPM_GETR(row_data[x]));
480 write_uchar_SI(file, PPM_GETG(row_data[x]));
481 write_uchar_SI(file, PPM_GETB(row_data[x]));
485compare_rgb(
xel *row_data, xelval *,
int x1,
int x2) {
486 return PPM_EQUAL(row_data[x1], row_data[x2]);
490write_gray(
xel *row_data, xelval *, ostream *file,
int x) {
491 write_uchar_SI(file, PPM_GETB(row_data[x]));
492 write_uchar_SI(file, PPM_GETB(row_data[x]));
493 write_uchar_SI(file, PPM_GETB(row_data[x]));
497compare_gray(
xel *row_data, xelval *,
int x1,
int x2) {
498 return (PPM_GETB(row_data[x1])==PPM_GETB(row_data[x2]));
502write_alpha(
xel *, xelval *alpha_data, ostream *file,
int x) {
503 write_uchar_SI(file, alpha_data[x]);
507compare_alpha(
xel *, xelval *alpha_data,
int x1,
int x2) {
508 return (alpha_data[x1]==alpha_data[x2]);
512write_diff(
xel *row_data, xelval *alpha_data, ostream *file,
513 void (*write_data)(
xel *row_data, xelval *alpha_data, ostream *file,
515 int tox,
int length) {
517 nassertv(length<=128);
519 write_uchar_SI(file, length-1);
522 write_data(row_data, alpha_data, file, tox-length);
528write_same(
xel *row_data, xelval *alpha_data, ostream *file,
529 void (*write_data)(
xel *row_data, xelval *alpha_data, ostream *file,
531 int tox,
int length) {
533 write_diff(row_data, alpha_data, file, write_data, tox, length);
535 }
else if (length>0) {
537 write_uchar_SI(file, length+127);
539 write_uchar_SI(file, 128);
540 write_ushort_SI(file, length);
542 write_data(row_data, alpha_data, file, tox);
548write_scanline(
xel *row_data, xelval *alpha_data,
int cols, ostream *file,
549 int (*compare_data)(
xel *row_data, xelval *alpha_data,
551 void (*write_data)(
xel *row_data, xelval *alpha_data,
552 ostream *file,
int x)) {
567 if (!compare_data(row_data, alpha_data, x, x-run_length)) {
570 if (run_length <= 1) {
581 write_same(row_data, alpha_data, file, write_data, x-1, run_length);
592 if (run_length>128) {
596 int excess = run_length - 128;
597 write_diff(row_data, alpha_data, file, write_data, x-excess-1, 128);
600 }
else if (run_length > 2 &&
601 compare_data(row_data, alpha_data, x, x-1) &&
602 compare_data(row_data, alpha_data, x, x-2)) {
607 write_diff(row_data, alpha_data, file, write_data, x-3, run_length-2);
621 write_same(row_data, alpha_data, file, write_data, cols-1, run_length);
625 if (run_length>128) {
626 int excess = run_length - 128;
627 write_diff(row_data, alpha_data, file, write_data, cols-excess-1, 128);
631 write_diff(row_data, alpha_data, file, write_data, cols-1, run_length);
639PNMFileTypeSoftImage::Writer::
640Writer(
PNMFileType *type, ostream *file,
bool owns_file) :
651bool PNMFileTypeSoftImage::Writer::
652supports_write_row()
const {
666bool PNMFileTypeSoftImage::Writer::
668 write_ushort_SI(_file, SOFTIMAGE_MAGIC1);
669 write_ushort_SI(_file, SOFTIMAGE_MAGIC2);
670 write_float(_file, imageVersionNumber);
672 _file->write(imageComment, imageCommentLength);
673 _file->write(
"PICT", 4);
675 write_ushort_SI(_file, _x_size);
676 write_ushort_SI(_file, _y_size);
678 write_float(_file, 1.0);
679 write_ushort_SI(_file, 3);
680 write_ushort_SI(_file, 0);
686 write_channel_pkt(_file, 1, 8, MIXED_RUN_LENGTH, RGB_CHANNEL);
687 write_channel_pkt(_file, 0, 8, MIXED_RUN_LENGTH, ALPHA_CHANNEL);
689 write_channel_pkt(_file, 0, 8, MIXED_RUN_LENGTH, RGB_CHANNEL);
706bool PNMFileTypeSoftImage::Writer::
707write_row(
xel *row_data, xelval *alpha_data) {
708 if (is_grayscale()) {
709 write_scanline(row_data, alpha_data, _x_size, _file, compare_gray, write_gray);
712 write_scanline(row_data, alpha_data, _x_size, _file, compare_rgb, write_rgb);
716 write_scanline(row_data, alpha_data, _x_size, _file, compare_alpha, write_alpha);
719 return !_file->fail();
727void PNMFileTypeSoftImage::
728register_with_read_factory() {
730 register_factory(get_class_type(), make_PNMFileTypeSoftImage);
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
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....
static PNMFileTypeRegistry * get_global_ptr()
Returns a pointer to the global PNMFileTypeRegistry object.
This is the base class of a family of classes that represent particular image file types that PNMImag...
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.
TypeHandle is the identifier used to differentiate C++ class types.
Base class for objects that can be written to and read from Bam files.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.