*** empty log message ***
This commit is contained in:
parent
d0e0566716
commit
efdb07d62f
|
|
@ -49,6 +49,7 @@ ConfigureFn(config_egg) {
|
|||
EggComment::init_type();
|
||||
EggCoordinateSystem::init_type();
|
||||
EggCurve::init_type();
|
||||
EggData::init_type();
|
||||
EggExternalReference::init_type();
|
||||
EggFilenameNode::init_type();
|
||||
EggGroup::init_type();
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ extern int eggyyparse(void);
|
|||
#include "parserDefs.h"
|
||||
#include "lexerDefs.h"
|
||||
|
||||
TypeHandle EggData::_type_handle;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggData::resolve_egg_filename
|
||||
// Access: Public, Static
|
||||
|
|
|
|||
|
|
@ -62,6 +62,23 @@ private:
|
|||
|
||||
CoordinateSystem _coordsys;
|
||||
Filename _egg_filename;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
EggGroupNode::init_type();
|
||||
register_type(_type_handle, "EggData",
|
||||
EggGroupNode::get_class_type());
|
||||
}
|
||||
virtual TypeHandle get_type() const {
|
||||
return get_class_type();
|
||||
}
|
||||
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
|
||||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
};
|
||||
|
||||
#include "eggData.I"
|
||||
|
|
|
|||
|
|
@ -116,7 +116,6 @@ private:
|
|||
|
||||
|
||||
public:
|
||||
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,8 +22,28 @@ LODSwitch(float in, float out) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void LODSwitch::
|
||||
get_range(float &in, float &out) const {
|
||||
in = sqrtf(_in);
|
||||
out = sqrtf(_out);
|
||||
in = get_in();
|
||||
out = get_out();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: LODSwitch::get_in
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE float LODSwitch::
|
||||
get_in() const {
|
||||
return sqrtf(_in);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: LODSwitch::get_out
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE float LODSwitch::
|
||||
get_out() const {
|
||||
return sqrtf(_out);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include <datagram.h>
|
||||
#include <datagramIterator.h>
|
||||
#include <indent.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Static variables
|
||||
|
|
@ -127,3 +128,46 @@ read_datagram(DatagramIterator &source) {
|
|||
_switch_vector.back().read_datagram(source);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: LOD::output
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void LOD::
|
||||
output(ostream &out) const {
|
||||
if (_switch_vector.empty()) {
|
||||
out << "no switches.";
|
||||
} else {
|
||||
LODSwitchVector::const_iterator si;
|
||||
si = _switch_vector.begin();
|
||||
out << "(" << (*si).get_in() << "/" << (*si).get_out() << ")";
|
||||
++si;
|
||||
while (si != _switch_vector.end()) {
|
||||
out << " (" << (*si).get_in() << "/" << (*si).get_out() << ")";
|
||||
++si;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: LOD::write
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void LOD::
|
||||
write(ostream &out, int indent_level) const {
|
||||
indent(out, indent_level)
|
||||
<< "LOD, " << _switch_vector.size() << " switches:\n";
|
||||
LODSwitchVector::const_iterator si;
|
||||
int i = 0;
|
||||
for (si = _switch_vector.begin();
|
||||
si != _switch_vector.end();
|
||||
++si) {
|
||||
indent(out, indent_level + 2)
|
||||
<< i << ". in at " << (*si).get_in()
|
||||
<< ", out at " << (*si).get_out() << "\n";
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,9 +11,8 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
#include <pandabase.h>
|
||||
|
||||
#include <typeHandle.h>
|
||||
#include <luse.h>
|
||||
#include <referenceCount.h>
|
||||
#include <typedReferenceCount.h>
|
||||
|
||||
class Datagram;
|
||||
class DatagramIterator;
|
||||
|
|
@ -34,6 +33,8 @@ class EXPCL_PANDA LODSwitch {
|
|||
public:
|
||||
INLINE LODSwitch(float in, float out);
|
||||
INLINE void get_range(float &in, float &out) const;
|
||||
INLINE float get_in() const;
|
||||
INLINE float get_out() const;
|
||||
INLINE void set_range(float in, float out);
|
||||
INLINE bool in_range(float dist_squared) const;
|
||||
|
||||
|
|
@ -61,7 +62,7 @@ typedef vector<LODSwitch> LODSwitchVector;
|
|||
// Description : Computes whether a level-of-detail should be rendered
|
||||
// or not based on distance from the rendering camera.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA LOD : public ReferenceCount, public TypedObject {
|
||||
class EXPCL_PANDA LOD : public TypedReferenceCount {
|
||||
public:
|
||||
LOD(void);
|
||||
LOD(const LOD ©);
|
||||
|
|
@ -75,6 +76,9 @@ public:
|
|||
void write_datagram(Datagram &destination) const;
|
||||
void read_datagram(DatagramIterator &source);
|
||||
|
||||
void output(ostream &out) const;
|
||||
void write(ostream &out, int indent_level = 0) const;
|
||||
|
||||
public:
|
||||
LPoint3f _center;
|
||||
LODSwitchVector _switch_vector;
|
||||
|
|
@ -84,11 +88,9 @@ public:
|
|||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
ReferenceCount::init_type();
|
||||
TypedObject::init_type();
|
||||
TypedReferenceCount::init_type();
|
||||
register_type(_type_handle, "LOD",
|
||||
ReferenceCount::get_class_type(),
|
||||
TypedObject::get_class_type());
|
||||
TypedReferenceCount::get_class_type());
|
||||
}
|
||||
virtual TypeHandle get_type() const {
|
||||
return get_class_type();
|
||||
|
|
@ -99,6 +101,11 @@ private:
|
|||
static TypeHandle _type_handle;
|
||||
};
|
||||
|
||||
INLINE ostream &operator << (ostream &out, const LOD &lod) {
|
||||
lod.output(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
#include "LOD.I"
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,178 +0,0 @@
|
|||
// pnm-image-alias.cc
|
||||
//
|
||||
// PNMImage::ReadAlias()
|
||||
// PNMImage::WriteAlias()
|
||||
|
||||
#include <pandabase.h>
|
||||
|
||||
#include "pnmImage.h"
|
||||
#include "pnmReader.h"
|
||||
#include "pnmReaderTypes.h"
|
||||
#include "pnmWriter.h"
|
||||
#include "pnmWriterTypes.h"
|
||||
|
||||
// Since Alias image files don't have a magic number, we'll make a little
|
||||
// sanity check on the size of the image. If either the width or height is
|
||||
// larger than this, it must be bogus.
|
||||
#define INSANE_SIZE 20000
|
||||
|
||||
inline unsigned short
|
||||
read_ushort(FILE *file) {
|
||||
unsigned short x;
|
||||
return pm_readbigshort(file, (short *)&x)==0 ? x : 0;
|
||||
}
|
||||
|
||||
inline unsigned char
|
||||
read_uchar(FILE *file) {
|
||||
int x;
|
||||
x = getc(file);
|
||||
return (x!=EOF) ? (unsigned char)x : 0;
|
||||
}
|
||||
|
||||
inline void
|
||||
write_ushort(FILE *file, unsigned short x) {
|
||||
pm_writebigshort(file, (short)x);
|
||||
}
|
||||
|
||||
inline void
|
||||
write_uchar(FILE *file, unsigned char x) {
|
||||
putc(x, file);
|
||||
}
|
||||
|
||||
PNMReaderAlias::
|
||||
PNMReaderAlias(FILE *file, int already_read_magic) : PNMReader(file) {
|
||||
if (already_read_magic >= 0) {
|
||||
cols = already_read_magic;
|
||||
} else {
|
||||
cols = read_ushort(file);
|
||||
}
|
||||
rows = read_ushort(file);
|
||||
|
||||
if (cols==0 || rows==0 ||
|
||||
cols>INSANE_SIZE || rows>INSANE_SIZE) {
|
||||
valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
read_ushort(file);
|
||||
read_ushort(file);
|
||||
|
||||
int bpp = read_ushort(file);
|
||||
|
||||
switch (bpp) {
|
||||
case 8:
|
||||
color_type = PNMImage::Grayscale;
|
||||
break;
|
||||
|
||||
case 24:
|
||||
color_type = PNMImage::Color;
|
||||
break;
|
||||
|
||||
default:
|
||||
valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
maxval = 255;
|
||||
}
|
||||
|
||||
bool PNMReaderAlias::
|
||||
ReadRow(xel *row, xelval *) {
|
||||
int x;
|
||||
int num;
|
||||
unsigned char red, grn, blu;
|
||||
|
||||
x = 0;
|
||||
while (x < cols) {
|
||||
num = read_uchar(file);
|
||||
if (num==0 || x+num > cols) {
|
||||
return false;
|
||||
}
|
||||
blu = read_uchar(file);
|
||||
|
||||
if (color_type == PNMImage::Color) {
|
||||
grn = read_uchar(file);
|
||||
red = read_uchar(file);
|
||||
while (num>0) {
|
||||
PPM_ASSIGN(row[x], red, grn, blu);
|
||||
x++;
|
||||
num--;
|
||||
}
|
||||
} else {
|
||||
while (num>0) {
|
||||
PPM_PUTB(row[x], blu);
|
||||
x++;
|
||||
num--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static unsigned char last_red = 0, last_blu = 0, last_grn = 0;
|
||||
static int num_count = 0;
|
||||
|
||||
static void
|
||||
flush_color(FILE *file) {
|
||||
if (num_count>0) {
|
||||
write_uchar(file, num_count);
|
||||
write_uchar(file, last_blu);
|
||||
write_uchar(file, last_grn);
|
||||
write_uchar(file, last_red);
|
||||
num_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
write_color(FILE *file,
|
||||
unsigned char red, unsigned char blu, unsigned char grn) {
|
||||
if (red==last_red && blu==last_blu && grn==last_grn && num_count<0377) {
|
||||
num_count++;
|
||||
} else {
|
||||
flush_color(file);
|
||||
last_red = red;
|
||||
last_grn = grn;
|
||||
last_blu = blu;
|
||||
num_count = 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool PNMWriterAlias::
|
||||
WriteHeader() {
|
||||
write_ushort(file, cols);
|
||||
write_ushort(file, rows);
|
||||
|
||||
write_ushort(file, 0);
|
||||
write_ushort(file, 0);
|
||||
|
||||
// We'll always write full-color Alias images, even if the source was
|
||||
// grayscale. Many programs don't seem to understand grayscale Alias images.
|
||||
write_ushort(file, 24);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PNMWriterAlias::
|
||||
WriteRow(xel *row_data, xelval *) {
|
||||
int x;
|
||||
unsigned char red, grn, blu;
|
||||
|
||||
int is_grayscale = PNMImage::IsGrayscale(color_type);
|
||||
|
||||
for (x = 0; x<cols; x++) {
|
||||
if (is_grayscale) {
|
||||
red = grn = blu = (unsigned char)(255*PPM_GETB(row_data[x])/maxval);
|
||||
} else {
|
||||
red = (unsigned char)(255*PPM_GETR(row_data[x])/maxval);
|
||||
grn = (unsigned char)(255*PPM_GETG(row_data[x])/maxval);
|
||||
blu = (unsigned char)(255*PPM_GETB(row_data[x])/maxval);
|
||||
}
|
||||
|
||||
write_color(file, red, blu, grn);
|
||||
}
|
||||
flush_color(file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,103 +0,0 @@
|
|||
// pnm-image-img.cc
|
||||
//
|
||||
// PNMImage::ReadImg()
|
||||
// PNMImage::WriteImg()
|
||||
|
||||
#include <pandabase.h>
|
||||
|
||||
#include "pnmImage.h"
|
||||
#include "pnmReader.h"
|
||||
#include "pnmReaderTypes.h"
|
||||
#include "pnmWriter.h"
|
||||
#include "pnmWriterTypes.h"
|
||||
|
||||
// Since raw image files don't have a magic number, we'll make a little
|
||||
// sanity check on the size of the image. If either the width or height is
|
||||
// larger than this, it must be bogus.
|
||||
#define INSANE_SIZE 20000
|
||||
|
||||
|
||||
inline unsigned long
|
||||
read_ulong(FILE *file) {
|
||||
unsigned long x;
|
||||
return pm_readbiglong(file, (long *)&x)==0 ? x : 0;
|
||||
}
|
||||
|
||||
inline unsigned short
|
||||
read_ushort(FILE *file) {
|
||||
unsigned short x;
|
||||
return pm_readbigshort(file, (short *)&x)==0 ? x : 0;
|
||||
}
|
||||
|
||||
inline unsigned char
|
||||
read_uchar(FILE *file) {
|
||||
int x;
|
||||
x = getc(file);
|
||||
return (x!=EOF) ? (unsigned char)x : 0;
|
||||
}
|
||||
|
||||
inline void
|
||||
write_ulong(FILE *file, unsigned long x) {
|
||||
pm_writebiglong(file, (long)x);
|
||||
}
|
||||
|
||||
inline void
|
||||
write_uchar(FILE *file, unsigned char x) {
|
||||
putc(x, file);
|
||||
}
|
||||
|
||||
PNMReaderIMG::
|
||||
PNMReaderIMG(FILE *file, int already_read_magic) : PNMReader(file) {
|
||||
if (already_read_magic>=0) {
|
||||
cols = (already_read_magic << 16) | read_ushort(file);
|
||||
} else {
|
||||
cols = (int)read_ulong(file);
|
||||
}
|
||||
|
||||
rows = (int)read_ulong(file);
|
||||
color_type = PNMImage::Color;
|
||||
|
||||
if (cols==0 || rows==0 ||
|
||||
cols>INSANE_SIZE || rows>INSANE_SIZE) {
|
||||
valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
maxval = 255;
|
||||
}
|
||||
|
||||
bool PNMReaderIMG::
|
||||
ReadRow(xel *row, xelval *) {
|
||||
int x;
|
||||
xelval red, grn, blu;
|
||||
for (x = 0; x<cols; x++) {
|
||||
red = read_uchar(file);
|
||||
grn = read_uchar(file);
|
||||
blu = read_uchar(file);
|
||||
|
||||
PPM_ASSIGN(row[x], red, grn, blu);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PNMWriterIMG::
|
||||
WriteHeader() {
|
||||
write_ulong(file, cols);
|
||||
write_ulong(file, rows);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PNMWriterIMG::
|
||||
WriteRow(xel *row_data, xelval *) {
|
||||
int x;
|
||||
for (x = 0; x<cols; x++) {
|
||||
write_uchar(file, (unsigned char)(255*PPM_GETR(row_data[x])/maxval));
|
||||
write_uchar(file, (unsigned char)(255*PPM_GETG(row_data[x])/maxval));
|
||||
write_uchar(file, (unsigned char)(255*PPM_GETB(row_data[x])/maxval));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,151 +0,0 @@
|
|||
// pnm-image-radiance.cc
|
||||
//
|
||||
// PNMImage::ReadRadiance() and PNMImage::WriteRadiance().
|
||||
|
||||
// Code in this file was initially taken from ra_skel.c, a skeletal Radiance
|
||||
// picture file conversion program provided on the Radiance WWW server, and
|
||||
// heavily modified.
|
||||
|
||||
|
||||
/* Copyright (c) 1992 Regents of the University of California */
|
||||
|
||||
/*
|
||||
* Skeletal 24-bit image conversion program. Replace "skel"
|
||||
* in this file with a more appropriate image type identifier.
|
||||
*
|
||||
* The Rmakefile entry should look something like this:
|
||||
* ra_skel: ra_skel.o
|
||||
* cc $(CFLAGS) -o ra_skel ra_skel.o -lrt -lm
|
||||
* ra_skel.o: ../common/color.h ../common/resolu.h
|
||||
*
|
||||
* If you like to do things the hard way, you can link directly
|
||||
* to the object files "color.o colrops.o resolu.o header.o" in
|
||||
* the common subdirectory instead of using the -lrt library.
|
||||
*/
|
||||
|
||||
#include <pandabase.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "pnmImage.h"
|
||||
#include "pnmReader.h"
|
||||
#include "pnmReaderTypes.h"
|
||||
#include "pnmWriter.h"
|
||||
#include "pnmWriterTypes.h"
|
||||
|
||||
extern "C" {
|
||||
#include "color.h"
|
||||
#include "resolu.h"
|
||||
|
||||
void setcolrgam(double);
|
||||
int checkheader(FILE *, char *, FILE *);
|
||||
int fgetresolu(int *, int *, FILE *);
|
||||
int freadcolrs(COLR *, int, FILE *);
|
||||
int fwritecolrs(COLR *, unsigned, FILE *);
|
||||
void fputformat(char *, FILE *);
|
||||
void shiftcolrs(COLR *, int, int);
|
||||
void colrs_gambs(COLR *, int);
|
||||
void newheader(char *, FILE *);
|
||||
void printargs(int, char **, FILE *);
|
||||
void gambs_colrs(COLR *, int);
|
||||
}
|
||||
|
||||
double gamcor = 2.2; /* gamma correction */
|
||||
|
||||
int bradj = 0; /* brightness adjustment */
|
||||
|
||||
static const int COLR_MAX = 255;
|
||||
|
||||
|
||||
PNMReaderRadiance::
|
||||
PNMReaderRadiance(FILE *file, int already_read_magic) : PNMReader(file) {
|
||||
setcolrgam(gamcor); /* set up gamma correction */
|
||||
|
||||
if (already_read_magic >= 0) {
|
||||
ungetc(already_read_magic >> 8, file);
|
||||
ungetc(already_read_magic & 0xff, file);
|
||||
}
|
||||
|
||||
/* get our header */
|
||||
if (checkheader(file, COLRFMT, NULL) < 0 ||
|
||||
fgetresolu(&cols, &rows, file) < 0) {
|
||||
valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
color_type = PNMImage::Color;
|
||||
maxval = COLR_MAX;
|
||||
}
|
||||
|
||||
bool PNMReaderRadiance::
|
||||
ReadRow(xel *row_data, xelval *) {
|
||||
COLR *scanin;
|
||||
int x;
|
||||
|
||||
scanin = (COLR *)alloca(cols * sizeof(COLR));
|
||||
|
||||
if (freadcolrs(scanin, cols, file) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bradj) { /* adjust exposure */
|
||||
shiftcolrs(scanin, cols, bradj);
|
||||
}
|
||||
|
||||
colrs_gambs(scanin, cols); /* gamma correction */
|
||||
|
||||
for (x = 0; x < cols; x++) {
|
||||
PPM_ASSIGN(row_data[x], scanin[x][RED], scanin[x][GRN], scanin[x][BLU]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PNMWriterRadiance::
|
||||
WriteHeader() {
|
||||
setcolrgam(gamcor); /* set up gamma correction */
|
||||
|
||||
/* put our header */
|
||||
newheader("RADIANCE", file);
|
||||
fputs("Generated via DRR's pnm-image library\n", file);
|
||||
fputformat(COLRFMT, file);
|
||||
putc('\n', file);
|
||||
fprtresolu(cols, rows, file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PNMWriterRadiance::
|
||||
WriteRow(xel *row_data, xelval *) {
|
||||
/* convert file */
|
||||
int is_grayscale = PNMImage::IsGrayscale(color_type);
|
||||
|
||||
COLR *scanout;
|
||||
int x;
|
||||
|
||||
/* allocate scanline */
|
||||
scanout = (COLR *)alloca(cols * sizeof(COLR));
|
||||
|
||||
/* convert image */
|
||||
for (x = 0; x < cols; x++) {
|
||||
if (is_grayscale) {
|
||||
scanout[x][RED] =
|
||||
scanout[x][GRN] =
|
||||
scanout[x][BLU] = (BYTE)((int)COLR_MAX * PPM_GETB(row_data[x]) / maxval);
|
||||
} else {
|
||||
scanout[x][RED] = (BYTE)((int)COLR_MAX * PPM_GETR(row_data[x]) / maxval);
|
||||
scanout[x][GRN] = (BYTE)((int)COLR_MAX * PPM_GETG(row_data[x]) / maxval);
|
||||
scanout[x][BLU] = (BYTE)((int)COLR_MAX * PPM_GETB(row_data[x]) / maxval);
|
||||
}
|
||||
}
|
||||
|
||||
/* undo gamma */
|
||||
gambs_colrs(scanout, cols);
|
||||
if (bradj) /* adjust exposure */
|
||||
shiftcolrs(scanout, cols, bradj);
|
||||
if (fwritecolrs(scanout, cols, file) < 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1,515 +0,0 @@
|
|||
// pnm-image-readbmp.cc
|
||||
//
|
||||
// PNMImage::ReadBMP() and supporting functions.
|
||||
|
||||
|
||||
|
||||
// Much code in this file is borrowed from Netpbm, specifically bmptoppm.c.
|
||||
/*\
|
||||
* $Id$
|
||||
*
|
||||
* bmptoppm.c - Converts from a Microsoft Windows or OS/2 .BMP file to a
|
||||
* PPM file.
|
||||
*
|
||||
* The current implementation is probably not complete, but it works for
|
||||
* all the BMP files I have. I welcome feedback.
|
||||
*
|
||||
* Copyright (C) 1992 by David W. Sanderson.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software and its
|
||||
* documentation for any purpose and without fee is hereby granted,
|
||||
* provided that the above copyright notice appear in all copies and
|
||||
* that both that copyright notice and this permission notice appear
|
||||
* in supporting documentation. This software is provided "as is"
|
||||
* without express or implied warranty.
|
||||
*
|
||||
* $Log$
|
||||
* Revision 1.2 2000/10/17 21:49:09 drose
|
||||
* *** empty log message ***
|
||||
*
|
||||
* Revision 1.1.1.1 2000/10/04 01:14:42 drose
|
||||
*
|
||||
*
|
||||
* Revision 1.10 1992/11/24 19:38:17 dws
|
||||
* Added code to verify that reading occurred at the correct offsets.
|
||||
* Added copyright.
|
||||
*
|
||||
* Revision 1.9 1992/11/17 02:15:24 dws
|
||||
* Changed to include bmp.h.
|
||||
* Eliminated need for fseek(), and therefore the need for a
|
||||
* temporary file.
|
||||
*
|
||||
* Revision 1.8 1992/11/13 23:48:57 dws
|
||||
* Made definition of Seekable() static, to match its prototype.
|
||||
*
|
||||
* Revision 1.7 1992/11/11 00:17:50 dws
|
||||
* Generalized to use bitio routines.
|
||||
*
|
||||
* Revision 1.6 1992/11/10 23:51:44 dws
|
||||
* Enhanced command-line handling.
|
||||
*
|
||||
* Revision 1.5 1992/11/08 00:38:46 dws
|
||||
* Changed some names to help w/ addition of ppmtobmp.
|
||||
*
|
||||
* Revision 1.4 1992/10/27 06:28:28 dws
|
||||
* Corrected stupid typo.
|
||||
*
|
||||
* Revision 1.3 1992/10/27 06:17:10 dws
|
||||
* Removed a magic constant value.
|
||||
*
|
||||
* Revision 1.2 1992/10/27 06:09:58 dws
|
||||
* Made stdin seekable.
|
||||
*
|
||||
* Revision 1.1 1992/10/27 05:31:41 dws
|
||||
* Initial revision
|
||||
\*/
|
||||
|
||||
#include "pnmImage.h"
|
||||
#include "pnmReader.h"
|
||||
#include "pnmReaderTypes.h"
|
||||
|
||||
extern "C" {
|
||||
#include "../pnm/bmp.h"
|
||||
#include "../pnm/bitio.h"
|
||||
}
|
||||
|
||||
static char *ifname;
|
||||
|
||||
/*
|
||||
* Utilities
|
||||
*/
|
||||
|
||||
static int GetByte ARGS((FILE * fp));
|
||||
static short GetShort ARGS((FILE * fp));
|
||||
static long GetLong ARGS((FILE * fp));
|
||||
static void readto ARGS((FILE *fp, unsigned long *ppos, unsigned long dst));
|
||||
static void BMPreadfileheader ARGS((FILE *fp, unsigned long *ppos,
|
||||
unsigned long *poffBits));
|
||||
static void BMPreadinfoheader ARGS((FILE *fp, unsigned long *ppos,
|
||||
unsigned long *pcx, unsigned long *pcy, unsigned short *pcBitCount,
|
||||
int *pclassv));
|
||||
static int BMPreadrgbtable ARGS((FILE *fp, unsigned long *ppos,
|
||||
unsigned short cBitCount, int classv, pixval *R, pixval *G, pixval *B));
|
||||
static int BMPreadrow ARGS((FILE *fp, unsigned long *ppos, pixel *row,
|
||||
unsigned long cx, unsigned short cBitCount, pixval *R, pixval *G, pixval *B));
|
||||
static pixel ** BMPreadbits ARGS((FILE *fp, unsigned long *ppos,
|
||||
unsigned long offBits, unsigned long cx, unsigned long cy,
|
||||
unsigned short cBitCount, int classv, pixval *R, pixval *G, pixval *B));
|
||||
|
||||
static char er_read[] = "%s: read error";
|
||||
static char er_seek[] = "%s: seek error";
|
||||
|
||||
static int
|
||||
GetByte(FILE *fp)
|
||||
{
|
||||
int v;
|
||||
|
||||
if ((v = getc(fp)) == EOF)
|
||||
{
|
||||
pm_error(er_read, ifname);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
static short
|
||||
GetShort(FILE *fp)
|
||||
{
|
||||
short v;
|
||||
|
||||
if (pm_readlittleshort(fp, &v) == -1)
|
||||
{
|
||||
pm_error(er_read, ifname);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
static long
|
||||
GetLong(FILE *fp)
|
||||
{
|
||||
long v;
|
||||
|
||||
if (pm_readlittlelong(fp, &v) == -1)
|
||||
{
|
||||
pm_error(er_read, ifname);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
/*
|
||||
* readto - read as many bytes as necessary to position the
|
||||
* file at the desired offset.
|
||||
*/
|
||||
|
||||
static void
|
||||
readto(FILE *fp,
|
||||
unsigned long *ppos, /* pointer to number of bytes read from fp */
|
||||
unsigned long dst)
|
||||
{
|
||||
unsigned long pos;
|
||||
|
||||
if(!fp || !ppos)
|
||||
return;
|
||||
|
||||
pos = *ppos;
|
||||
|
||||
if(pos > dst)
|
||||
pm_error("%s: internal error in readto()", ifname);
|
||||
|
||||
for(; pos < dst; pos++)
|
||||
{
|
||||
if (getc(fp) == EOF)
|
||||
{
|
||||
pm_error(er_read, ifname);
|
||||
}
|
||||
}
|
||||
|
||||
*ppos = pos;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* BMP reading routines
|
||||
*/
|
||||
|
||||
static void
|
||||
BMPreadfileheader(
|
||||
FILE *fp,
|
||||
unsigned long *ppos, /* number of bytes read from fp */
|
||||
unsigned long *poffBits)
|
||||
{
|
||||
/*
|
||||
unsigned long cbSize;
|
||||
unsigned short xHotSpot;
|
||||
unsigned short yHotSpot;
|
||||
*/
|
||||
unsigned long offBits;
|
||||
|
||||
/*
|
||||
We've already read the magic number.
|
||||
if (GetByte(fp) != 'B')
|
||||
{
|
||||
pm_error("%s is not a BMP file", ifname);
|
||||
}
|
||||
if (GetByte(fp) != 'M')
|
||||
{
|
||||
pm_error("%s is not a BMP file", ifname);
|
||||
}
|
||||
*/
|
||||
|
||||
/* cbSize = */ GetLong(fp);
|
||||
/* xHotSpot = */ GetShort(fp);
|
||||
/* yHotSpot = */ GetShort(fp);
|
||||
offBits = GetLong(fp);
|
||||
|
||||
*poffBits = offBits;
|
||||
|
||||
*ppos += 14;
|
||||
}
|
||||
|
||||
static void
|
||||
BMPreadinfoheader(
|
||||
FILE *fp,
|
||||
unsigned long *ppos, /* number of bytes read from fp */
|
||||
unsigned long *pcx,
|
||||
unsigned long *pcy,
|
||||
unsigned short *pcBitCount,
|
||||
int *pclassv)
|
||||
{
|
||||
unsigned long cbFix;
|
||||
unsigned short cPlanes;
|
||||
|
||||
unsigned long cx;
|
||||
unsigned long cy;
|
||||
unsigned short cBitCount;
|
||||
int classv;
|
||||
|
||||
cbFix = GetLong(fp);
|
||||
|
||||
switch (cbFix)
|
||||
{
|
||||
case 12:
|
||||
classv = C_OS2;
|
||||
|
||||
cx = GetShort(fp);
|
||||
cy = GetShort(fp);
|
||||
cPlanes = GetShort(fp);
|
||||
cBitCount = GetShort(fp);
|
||||
|
||||
break;
|
||||
case 40:
|
||||
classv = C_WIN;
|
||||
|
||||
cx = GetLong(fp);
|
||||
cy = GetLong(fp);
|
||||
cPlanes = GetShort(fp);
|
||||
cBitCount = GetShort(fp);
|
||||
|
||||
/*
|
||||
* We've read 16 bytes so far, need to read 24 more
|
||||
* for the required total of 40.
|
||||
*/
|
||||
|
||||
GetLong(fp);
|
||||
GetLong(fp);
|
||||
GetLong(fp);
|
||||
GetLong(fp);
|
||||
GetLong(fp);
|
||||
GetLong(fp);
|
||||
|
||||
break;
|
||||
default:
|
||||
pm_error("%s: unknown cbFix: %d", ifname, cbFix);
|
||||
break;
|
||||
}
|
||||
|
||||
if (cPlanes != 1)
|
||||
{
|
||||
pm_error("%s: don't know how to handle cPlanes = %d"
|
||||
,ifname
|
||||
,cPlanes);
|
||||
}
|
||||
|
||||
switch (classv)
|
||||
{
|
||||
case C_WIN:
|
||||
pm_message("Windows BMP, %dx%dx%d"
|
||||
,cx
|
||||
,cy
|
||||
,cBitCount);
|
||||
break;
|
||||
case C_OS2:
|
||||
pm_message("OS/2 BMP, %dx%dx%d"
|
||||
,cx
|
||||
,cy
|
||||
,cBitCount);
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
pm_message("cbFix: %d", cbFix);
|
||||
pm_message("cx: %d", cx);
|
||||
pm_message("cy: %d", cy);
|
||||
pm_message("cPlanes: %d", cPlanes);
|
||||
pm_message("cBitCount: %d", cBitCount);
|
||||
#endif
|
||||
|
||||
*pcx = cx;
|
||||
*pcy = cy;
|
||||
*pcBitCount = cBitCount;
|
||||
*pclassv = classv;
|
||||
|
||||
*ppos += cbFix;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns the number of bytes read, or -1 on error.
|
||||
*/
|
||||
static int
|
||||
BMPreadrgbtable(
|
||||
FILE *fp,
|
||||
unsigned long *ppos, /* number of bytes read from fp */
|
||||
unsigned short cBitCount,
|
||||
int classv,
|
||||
pixval *R,
|
||||
pixval *G,
|
||||
pixval *B)
|
||||
{
|
||||
int i;
|
||||
int nbyte = 0;
|
||||
|
||||
long ncolors = (1 << cBitCount);
|
||||
|
||||
for (i = 0; i < ncolors; i++)
|
||||
{
|
||||
B[i] = (pixval) GetByte(fp);
|
||||
G[i] = (pixval) GetByte(fp);
|
||||
R[i] = (pixval) GetByte(fp);
|
||||
nbyte += 3;
|
||||
|
||||
if (classv == C_WIN)
|
||||
{
|
||||
(void) GetByte(fp);
|
||||
nbyte++;
|
||||
}
|
||||
}
|
||||
|
||||
*ppos += nbyte;
|
||||
return nbyte;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns the number of bytes read, or -1 on error.
|
||||
*/
|
||||
static int
|
||||
BMPreadrow(
|
||||
FILE *fp,
|
||||
unsigned long *ppos, /* number of bytes read from fp */
|
||||
pixel *row,
|
||||
unsigned long cx,
|
||||
unsigned short cBitCount,
|
||||
int indexed,
|
||||
pixval *R,
|
||||
pixval *G,
|
||||
pixval *B)
|
||||
{
|
||||
BITSTREAM b;
|
||||
unsigned nbyte = 0;
|
||||
int rc;
|
||||
unsigned x;
|
||||
|
||||
if (indexed) {
|
||||
if ((b = pm_bitinit(fp, "r")) == (BITSTREAM) 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
for (x = 0; x < cx; x++, row++)
|
||||
{
|
||||
unsigned long v;
|
||||
|
||||
if (!indexed) {
|
||||
int r, g, b;
|
||||
b = GetByte(fp);
|
||||
g = GetByte(fp);
|
||||
r = GetByte(fp);
|
||||
nbyte += 3;
|
||||
PPM_ASSIGN(*row, r, g, b);
|
||||
} else {
|
||||
if ((rc = pm_bitread(b, cBitCount, &v)) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
nbyte += rc;
|
||||
|
||||
PPM_ASSIGN(*row, R[v], G[v], B[v]);
|
||||
}
|
||||
}
|
||||
|
||||
if (indexed) {
|
||||
if ((rc = pm_bitfini(b)) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure we read a multiple of 4 bytes.
|
||||
*/
|
||||
while (nbyte % 4)
|
||||
{
|
||||
GetByte(fp);
|
||||
nbyte++;
|
||||
}
|
||||
|
||||
*ppos += nbyte;
|
||||
return nbyte;
|
||||
}
|
||||
|
||||
static void
|
||||
BMPreadbits(xel *array,
|
||||
FILE *fp,
|
||||
unsigned long *ppos, /* number of bytes read from fp */
|
||||
unsigned long offBits,
|
||||
unsigned long cx,
|
||||
unsigned long cy,
|
||||
unsigned short cBitCount,
|
||||
int /* classv */,
|
||||
int indexed,
|
||||
pixval *R,
|
||||
pixval *G,
|
||||
pixval *B)
|
||||
{
|
||||
long y;
|
||||
|
||||
readto(fp, ppos, offBits);
|
||||
|
||||
if(cBitCount > 24)
|
||||
{
|
||||
pm_error("%s: cannot handle cBitCount: %d"
|
||||
,ifname
|
||||
,cBitCount);
|
||||
}
|
||||
|
||||
/*
|
||||
* The picture is stored bottom line first, top line last
|
||||
*/
|
||||
|
||||
for (y = (long)cy - 1; y >= 0; y--)
|
||||
{
|
||||
int rc;
|
||||
rc = BMPreadrow(fp, ppos, array + y*cx, cx, cBitCount, indexed, R, G, B);
|
||||
if(rc == -1)
|
||||
{
|
||||
pm_error("%s: couldn't read row %d"
|
||||
,ifname
|
||||
,y);
|
||||
}
|
||||
if(rc%4)
|
||||
{
|
||||
pm_error("%s: row had bad number of bytes: %d"
|
||||
,ifname
|
||||
,rc);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
PNMReaderBMP::
|
||||
PNMReaderBMP(FILE *file, int already_read_magic) : PNMReader(file) {
|
||||
int rc;
|
||||
|
||||
unsigned long cx;
|
||||
unsigned long cy;
|
||||
|
||||
if (already_read_magic < 0) {
|
||||
// Skip the magic number.
|
||||
GetByte(file);
|
||||
GetByte(file);
|
||||
}
|
||||
|
||||
pos = 0;
|
||||
|
||||
BMPreadfileheader(file, &pos, &offBits);
|
||||
BMPreadinfoheader(file, &pos, &cx, &cy, &cBitCount, &classv);
|
||||
|
||||
if (offBits != BMPoffbits(classv, cBitCount)) {
|
||||
pm_message("warning: offBits is %d, expected %d",
|
||||
offBits,
|
||||
BMPoffbits(classv, cBitCount));
|
||||
}
|
||||
|
||||
indexed = false;
|
||||
|
||||
if (cBitCount <= 8) {
|
||||
indexed = true;
|
||||
rc = BMPreadrgbtable(file, &pos, cBitCount, classv, R, G, B);
|
||||
|
||||
if (rc != BMPlenrgbtable(classv, cBitCount)) {
|
||||
pm_message("warning: %d-byte RGB table, expected %d bytes",
|
||||
rc,
|
||||
BMPlenrgbtable(classv, cBitCount));
|
||||
}
|
||||
}
|
||||
|
||||
color_type = Color;
|
||||
cols = (int)cx;
|
||||
rows = (int)cy;
|
||||
maxval = 255;
|
||||
}
|
||||
|
||||
int PNMReaderBMP::
|
||||
ReadData(xel *array, xelval *) {
|
||||
BMPreadbits(array, file, &pos, offBits, cols, rows,
|
||||
cBitCount, classv, indexed, R, G, B);
|
||||
|
||||
if (pos != BMPlenfile(classv, cBitCount, cols, rows)) {
|
||||
pm_message("warning: read %d bytes, expected to read %d bytes",
|
||||
pos, BMPlenfile(classv, cBitCount, cols, rows));
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
|
@ -1,430 +0,0 @@
|
|||
// pnm-image-readsgi.cc
|
||||
//
|
||||
// PNMImage::ReadSGI() and supporting functions.
|
||||
|
||||
|
||||
|
||||
// Much code in this file is borrowed from Netpbm, specifically sgitopnm.c.
|
||||
|
||||
/* sgitopnm.c - read an SGI image and and produce a portable anymap
|
||||
**
|
||||
** Copyright (C) 1994 by Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
|
||||
**
|
||||
** Based on the SGI image description v0.9 by Paul Haeberli (paul@sgi.comp)
|
||||
** Available via ftp from sgi.com:graphics/SGIIMAGESPEC
|
||||
**
|
||||
** Permission to use, copy, modify, and distribute this software and its
|
||||
** documentation for any purpose and without fee is hereby granted, provided
|
||||
** that the above copyright notice appear in all copies and that both that
|
||||
** copyright notice and this permission notice appear in supporting
|
||||
** documentation. This software is provided "as is" without express or
|
||||
** implied warranty.
|
||||
**
|
||||
** 29Jan94: first version
|
||||
** 08Feb94: minor bugfix
|
||||
*/
|
||||
|
||||
#include "pnmImage.h"
|
||||
#include "pnmReader.h"
|
||||
#include "pnmReaderTypes.h"
|
||||
#include "../pnm/sgi.h"
|
||||
#include <notify.h>
|
||||
|
||||
/* entry in RLE offset table */
|
||||
typedef PNMReaderSGI::TabEntry TabEntry;
|
||||
|
||||
typedef short ScanElem;
|
||||
typedef ScanElem * ScanLine;
|
||||
|
||||
/* prototypes */
|
||||
static unsigned char get_byte ( FILE* f );
|
||||
static long get_big_long (FILE *f);
|
||||
static short get_big_short (FILE *f);
|
||||
static short get_byte_as_short (FILE *f);
|
||||
static int readerr (FILE *f);
|
||||
static void * xmalloc (int bytes);
|
||||
#define MALLOC(n, type) (type *)xmalloc((n) * sizeof(type))
|
||||
//static char * compression_name (char compr);
|
||||
static void read_bytes (FILE *ifp, int n, char *buf);
|
||||
static void read_header(FILE *ifp, Header *head, int already_read_magic);
|
||||
static TabEntry * read_table (FILE *ifp, int tablen);
|
||||
static void read_channel (FILE *ifp, int xsize, int ysize,
|
||||
int zsize, int bpc, TabEntry *table,
|
||||
ScanElem *channel_data, long table_start,
|
||||
int channel, int row);
|
||||
static void rle_decompress (ScanElem *src, long srclen, ScanElem *dest, long destlen);
|
||||
|
||||
#define WORSTCOMPR(x) (2*(x) + 2)
|
||||
|
||||
#define MAXVAL_BYTE 255
|
||||
#define MAXVAL_WORD 65535
|
||||
|
||||
static int eof_err = false;
|
||||
|
||||
PNMReaderSGI::
|
||||
PNMReaderSGI(FILE *file, int already_read_magic) : PNMReader(file) {
|
||||
eof_err = false;
|
||||
|
||||
table = NULL;
|
||||
Header head;
|
||||
|
||||
read_header(file, &head, already_read_magic);
|
||||
|
||||
long pixmax = (head.bpc == 1) ? MAXVAL_BYTE : MAXVAL_WORD;
|
||||
if( pixmax > PNM_MAXMAXVAL )
|
||||
pm_error("pixel values too large - try reconfiguring with PGM_BIGGRAYS\n or without PPM_PACKCOLORS");
|
||||
|
||||
maxval = (xelval)pixmax;
|
||||
|
||||
table_start = ftell(file);
|
||||
if( head.storage != STORAGE_VERBATIM )
|
||||
table = read_table(file, head.ysize * head.zsize);
|
||||
|
||||
cols = head.xsize;
|
||||
rows = head.ysize;
|
||||
zsize = head.zsize;
|
||||
bpc = head.bpc;
|
||||
|
||||
switch (zsize) {
|
||||
case 1:
|
||||
color_type = PNMImage::Grayscale;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
color_type = PNMImage::TwoChannel;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
color_type = PNMImage::Color;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
color_type = PNMImage::FourChannel;
|
||||
break;
|
||||
|
||||
default:
|
||||
pm_error("Can't happen.");
|
||||
}
|
||||
|
||||
current_row = rows-1;
|
||||
}
|
||||
|
||||
bool PNMReaderSGI::
|
||||
ReadRow(xel *row_data, xelval *alpha_data) {
|
||||
nassertr(current_row >= 0, false);
|
||||
|
||||
int is_grayscale = PNMImage::IsGrayscale(color_type);
|
||||
int has_alpha = PNMImage::HasAlpha(color_type);
|
||||
int col;
|
||||
|
||||
ScanElem *red = (ScanElem *)alloca(cols * sizeof(ScanElem));
|
||||
ScanElem *grn = (ScanElem *)alloca(cols * sizeof(ScanElem));
|
||||
ScanElem *blu = (ScanElem *)alloca(cols * sizeof(ScanElem));
|
||||
ScanElem *alpha = (ScanElem *)alloca(cols * sizeof(ScanElem));
|
||||
|
||||
read_channel(file, cols, rows, zsize, bpc, table, red, table_start,
|
||||
0, current_row);
|
||||
|
||||
if (!is_grayscale) {
|
||||
read_channel(file, cols, rows, zsize, bpc, table, grn, table_start,
|
||||
1, current_row);
|
||||
read_channel(file, cols, rows, zsize, bpc, table, blu, table_start,
|
||||
2, current_row);
|
||||
}
|
||||
|
||||
if (has_alpha) {
|
||||
read_channel(file, cols, rows, zsize, bpc, table, alpha, table_start,
|
||||
zsize-1, current_row);
|
||||
}
|
||||
|
||||
for ( col = 0; col < cols; col++ ) {
|
||||
if (is_grayscale) {
|
||||
PPM_PUTB(row_data[col], (xelval)red[col]);
|
||||
} else {
|
||||
xelval r, g, b;
|
||||
r = (xelval)red[col];
|
||||
g = (xelval)grn[col];
|
||||
b = (xelval)blu[col];
|
||||
PPM_ASSIGN(row_data[col], r, g, b);
|
||||
}
|
||||
|
||||
if (has_alpha) {
|
||||
alpha_data[col] = (xelval)alpha[col];
|
||||
}
|
||||
}
|
||||
current_row--;
|
||||
return true;
|
||||
}
|
||||
|
||||
PNMReaderSGI::
|
||||
~PNMReaderSGI() {
|
||||
if (table != NULL) {
|
||||
free(table);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
read_header(FILE *ifp, Header *head, int already_read_magic) {
|
||||
if (already_read_magic >= 0) {
|
||||
head->magic = (short)already_read_magic;
|
||||
} else {
|
||||
head->magic = get_big_short(ifp);
|
||||
}
|
||||
|
||||
head->storage = get_byte(ifp);
|
||||
head->bpc = get_byte(ifp);
|
||||
head->dimension = get_big_short(ifp);
|
||||
head->xsize = get_big_short(ifp);
|
||||
head->ysize = get_big_short(ifp);
|
||||
head->zsize = get_big_short(ifp);
|
||||
head->pixmin = get_big_long(ifp);
|
||||
head->pixmax = get_big_long(ifp);
|
||||
read_bytes(ifp, 4, head->dummy1);
|
||||
read_bytes(ifp, 80, head->name);
|
||||
head->colormap = get_big_long(ifp);
|
||||
read_bytes(ifp, 404, head->dummy2);
|
||||
|
||||
if( head->magic != SGI_MAGIC )
|
||||
pm_error("bad magic number - not an SGI image");
|
||||
if( head->storage != 0 && head->storage != 1 )
|
||||
pm_error("unknown compression type");
|
||||
if( head->bpc < 1 || head->bpc > 2 )
|
||||
pm_error("illegal precision value %d (only 1-2 allowed)", head->bpc );
|
||||
if( head->colormap != CMAP_NORMAL )
|
||||
pm_message("unsupported non-normal pixel data (%d)",
|
||||
head->colormap);
|
||||
|
||||
/* adjust ysize/zsize to dimension, just to be sure */
|
||||
switch( head->dimension ) {
|
||||
case 1:
|
||||
head->ysize = 1;
|
||||
break;
|
||||
case 2:
|
||||
head->zsize = 1;
|
||||
break;
|
||||
case 3:
|
||||
switch( head->zsize ) {
|
||||
case 1:
|
||||
case 2:
|
||||
head->dimension = 2;
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
break;
|
||||
|
||||
default:
|
||||
pm_message("%d-channel image, using only first 4 channels", head->zsize);
|
||||
head->zsize = 4;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
pm_error("illegal dimension value %d (only 1-3 allowed)", head->dimension);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "raster size %dx%d, %d channels\n", head->xsize, head->ysize, head->zsize);
|
||||
fprintf(stderr, "compression: %d = %s\n", head->storage, compression_name(head->storage));
|
||||
head->name[79] = '\0'; /* just to be safe */
|
||||
fprintf(stderr, "Image name: \"%s\"\n", head->name);
|
||||
fprintf(stderr, "bpc: %d dimension: %d zsize: %d\n", head->bpc, head->dimension, head->zsize);
|
||||
fprintf(stderr, "pixmin: %ld pixmax: %ld colormap: %ld\n", head->pixmin, head->pixmax, head->colormap);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static TabEntry *
|
||||
read_table(FILE *ifp, int tablen) {
|
||||
TabEntry *table;
|
||||
int i;
|
||||
|
||||
table = MALLOC(tablen, TabEntry);
|
||||
|
||||
for( i = 0; i < tablen; i++ )
|
||||
table[i].start = get_big_long(ifp);
|
||||
for( i = 0; i < tablen; i++ )
|
||||
table[i].length = get_big_long(ifp);
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
read_channel(FILE *ifp,
|
||||
int xsize, int ysize, int, int bpc,
|
||||
TabEntry *table,
|
||||
ScanElem *channel_data, long table_start,
|
||||
int channel, int row) {
|
||||
ScanElem *temp;
|
||||
int sgi_index, i;
|
||||
long offset, length;
|
||||
|
||||
short (*func)(FILE *);
|
||||
func = (bpc==1) ? get_byte_as_short : get_big_short;
|
||||
|
||||
if ( table )
|
||||
temp = (ScanElem *)alloca(WORSTCOMPR(xsize) * sizeof(ScanElem));
|
||||
|
||||
sgi_index = channel * ysize + row;
|
||||
if( table ) {
|
||||
offset = table[sgi_index].start;
|
||||
length = table[sgi_index].length;
|
||||
if( bpc == 2 )
|
||||
length /= 2; /* doc says length is in bytes, we are reading words */
|
||||
if( fseek(ifp, offset, SEEK_SET) != 0 )
|
||||
pm_error("seek error for offset %ld", offset);
|
||||
|
||||
for( i = 0; i < length; i++ )
|
||||
temp[i] = (*func)(ifp);
|
||||
|
||||
rle_decompress(temp, length, channel_data, xsize);
|
||||
}
|
||||
else {
|
||||
offset = sgi_index * xsize + table_start;
|
||||
if( fseek(ifp, offset, SEEK_SET) != 0 )
|
||||
pm_error("seek error for offset %ld", offset);
|
||||
for( i = 0; i < xsize; i++ )
|
||||
channel_data[i] = (*func)(ifp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
rle_decompress(ScanElem *src,
|
||||
long srcleft,
|
||||
ScanElem *dest,
|
||||
long destleft) {
|
||||
int count;
|
||||
unsigned char el;
|
||||
|
||||
while( srcleft ) {
|
||||
el = (unsigned char)(*src++ & 0xff);
|
||||
--srcleft;
|
||||
count = (int)(el & 0x7f);
|
||||
|
||||
if( count == 0 )
|
||||
return;
|
||||
if( destleft < count )
|
||||
pm_error("RLE error: too much input data (space left %d, need %d)", destleft, count);
|
||||
destleft -= count;
|
||||
if( el & 0x80 ) {
|
||||
if( srcleft < count )
|
||||
pm_error("RLE error: not enough data for literal run (data left %d, need %d)", srcleft, count);
|
||||
srcleft -= count;
|
||||
while( count-- )
|
||||
*dest++ = *src++;
|
||||
}
|
||||
else {
|
||||
if( srcleft == 0 )
|
||||
pm_error("RLE error: not enough data for replicate run");
|
||||
while( count-- )
|
||||
*dest++ = *src;
|
||||
++src;
|
||||
--srcleft;
|
||||
}
|
||||
}
|
||||
pm_error("RLE error: no terminating 0-byte");
|
||||
}
|
||||
|
||||
|
||||
/* basic I/O functions, taken from ilbmtoppm.c */
|
||||
|
||||
static short
|
||||
get_big_short(FILE *ifp) {
|
||||
short s;
|
||||
|
||||
if( pm_readbigshort(ifp, &s) == -1 )
|
||||
s = readerr(ifp);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static long
|
||||
get_big_long(FILE *ifp) {
|
||||
long l;
|
||||
|
||||
if( pm_readbiglong(ifp, &l) == -1 )
|
||||
l = readerr(ifp);
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
static unsigned char
|
||||
get_byte(FILE *ifp) {
|
||||
int i;
|
||||
|
||||
i = getc(ifp);
|
||||
if( i == EOF )
|
||||
i = readerr(ifp);
|
||||
|
||||
return (unsigned char) i;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
readerr(FILE *f) {
|
||||
// This will return only if the error is EOF.
|
||||
if( ferror(f) )
|
||||
pm_error("read error");
|
||||
|
||||
static FILE *last_eof = NULL;
|
||||
|
||||
if (!eof_err) {
|
||||
fprintf(stderr, "Warning: premature EOF on file\n");
|
||||
eof_err = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
read_bytes(FILE *ifp,
|
||||
int n,
|
||||
char *buf) {
|
||||
int r;
|
||||
|
||||
r = fread((void *)buf, 1, n, ifp);
|
||||
if( r != n ) {
|
||||
readerr(ifp);
|
||||
memset(buf+r, 0, n-r);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static short
|
||||
get_byte_as_short(FILE *ifp) {
|
||||
return (short)get_byte(ifp);
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
xmalloc(int bytes) {
|
||||
void *mem;
|
||||
|
||||
if( bytes == 0 )
|
||||
return NULL;
|
||||
|
||||
mem = malloc(bytes);
|
||||
if( mem == NULL )
|
||||
pm_error("out of memory allocating %d bytes", bytes);
|
||||
return mem;
|
||||
}
|
||||
|
||||
/*
|
||||
static char *
|
||||
compression_name(char compr) {
|
||||
switch( compr ) {
|
||||
case STORAGE_VERBATIM:
|
||||
return "none";
|
||||
case STORAGE_RLE:
|
||||
return "RLE";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
|
@ -1,114 +0,0 @@
|
|||
// pnm-image-readyuv.cc
|
||||
//
|
||||
// PNMImage::ReadYUV() and supporting functions.
|
||||
|
||||
|
||||
|
||||
// Much code in this file is borrowed from Netpbm, specifically yuvtoppm.c.
|
||||
/* yuvtoppm.c - convert Abekas YUV bytes into a portable pixmap
|
||||
**
|
||||
** by Marc Boucher
|
||||
** Internet: marc@PostImage.cxxOM
|
||||
**
|
||||
** Based on Example Conversion Program, A60/A64 Digital Video Interface
|
||||
** Manual, page 69
|
||||
**
|
||||
** Uses integer arithmetic rather than floating point for better performance
|
||||
**
|
||||
** Copyright (C) 1991 by DHD PostImage Inc.
|
||||
** Copyright (C) 1987 by Abekas Video Systems Inc.
|
||||
** Copyright (C) 1991 by Jef Poskanzer.
|
||||
**
|
||||
** Permission to use, copy, modify, and distribute this software and its
|
||||
** documentation for any purpose and without fee is hereby granted, provided
|
||||
** that the above copyright notice appear in all copies and that both that
|
||||
** copyright notice and this permission notice appear in supporting
|
||||
** documentation. This software is provided "as is" without express or
|
||||
** implied warranty.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "pnmImage.h"
|
||||
#include "pnmReader.h"
|
||||
#include "pnmReaderTypes.h"
|
||||
|
||||
#include <notify.h>
|
||||
|
||||
// YUV format doesn't include an image size specification, so the image size
|
||||
// must be specified externally. The defaults here are likely candidates,
|
||||
// since this is the Abekas native size; the ysize is automatically adjusted
|
||||
// down to account for a short file.
|
||||
int yuv_xsize = 720;
|
||||
int yuv_ysize = 486;
|
||||
|
||||
/* x must be signed for the following to work correctly */
|
||||
#define limit(x) (xelval)(((x>0xffffff)?0xff0000:((x<=0xffff)?0:x&0xff0000))>>16)
|
||||
|
||||
PNMReaderYUV::
|
||||
PNMReaderYUV(FILE *file, int already_read_magic) : PNMReader(file) {
|
||||
yuvbuf = NULL;
|
||||
|
||||
if (already_read_magic >= 0) {
|
||||
ungetc(already_read_magic >> 8, file);
|
||||
ungetc(already_read_magic & 0xff, file);
|
||||
}
|
||||
|
||||
cols = yuv_xsize;
|
||||
rows = yuv_ysize;
|
||||
color_type = PNMImage::Color;
|
||||
|
||||
if (cols <= 0 || rows <= 0) {
|
||||
valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
nassertv(255 <= PGM_MAXMAXVAL);
|
||||
|
||||
yuvbuf = (long *) pm_allocrow(cols, 2);
|
||||
|
||||
maxval = 255;
|
||||
}
|
||||
|
||||
bool PNMReaderYUV::
|
||||
ReadRow(xel *row_data, xelval *) {
|
||||
long tmp, y, u, v, y1, r, g, b, *yuvptr;
|
||||
int col;
|
||||
|
||||
if (fread(yuvbuf, cols * 2, 1, file) != 1) {
|
||||
// Short file--perhaps it's just a field instead of a full frame.
|
||||
// Since the YUV format does not include a length designation, we'll
|
||||
// have to assume this is not a problem and just truncate here.
|
||||
return false;
|
||||
}
|
||||
|
||||
for (col = 0, yuvptr = yuvbuf; col < cols; col += 2) {
|
||||
tmp = *yuvptr++;
|
||||
u = (0xff & (tmp >> 24)) - 128;
|
||||
y = ((0xff & (tmp >> 16)) - 16);
|
||||
if (y < 0) y = 0;
|
||||
|
||||
v = (0xff & (tmp >> 8)) - 128;
|
||||
y1 = ((0xff & tmp) - 16);
|
||||
if (y1 < 0) y1 = 0;
|
||||
|
||||
r = 104635 * v;
|
||||
g = -25690 * u + -53294 * v;
|
||||
b = 132278 * u;
|
||||
|
||||
y*=76310; y1*=76310;
|
||||
|
||||
PPM_ASSIGN(row_data[col], limit(r+y), limit(g+y), limit(b+y));
|
||||
PPM_ASSIGN(row_data[col+1], limit(r+y1), limit(g+y1), limit(b+y1));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
PNMReaderYUV::
|
||||
~PNMReaderYUV() {
|
||||
if (yuvbuf!=NULL) {
|
||||
pm_freerow((char *)yuvbuf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,539 +0,0 @@
|
|||
// pnm-image-softimage.cc
|
||||
//
|
||||
// PNMImage::ReadSoftImage()
|
||||
// PNMImage::WriteSoftImage()
|
||||
|
||||
#include "pnmImage.h"
|
||||
#include "pnmReader.h"
|
||||
#include "pnmReaderTypes.h"
|
||||
#include "pnmWriter.h"
|
||||
#include "pnmWriterTypes.h"
|
||||
#include "config_pnmimage.h"
|
||||
#include <notify.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static const float imageVersionNumber = 3.0;
|
||||
static const int imageCommentLength = 80;
|
||||
static const char imageComment[imageCommentLength+1] =
|
||||
"Written by DRR's PNMImage library.";
|
||||
|
||||
|
||||
|
||||
// Values to indicate compressed/uncompressed types
|
||||
#define UNCOMPRESSED 0x00
|
||||
#define MIXED_RUN_LENGTH 0x02
|
||||
|
||||
// Bits to indicate channel type
|
||||
#define RGB_CHANNEL 0xe0
|
||||
#define ALPHA_CHANNEL 0x10
|
||||
|
||||
inline float
|
||||
read_float(FILE *file) {
|
||||
long l;
|
||||
|
||||
if (pm_readbiglong(file, &l)==0) {
|
||||
return *(float *)&l;
|
||||
} else {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
inline unsigned short
|
||||
read_ushort(FILE *file) {
|
||||
unsigned short x;
|
||||
return pm_readbigshort(file, (short *)&x)==0 ? x : 0;
|
||||
}
|
||||
|
||||
inline unsigned char
|
||||
read_uchar(FILE *file) {
|
||||
int x;
|
||||
x = getc(file);
|
||||
return (x!=EOF) ? (unsigned char)x : 0;
|
||||
}
|
||||
|
||||
inline void
|
||||
write_ushort(FILE *file, unsigned short x) {
|
||||
pm_writebigshort(file, (short)x);
|
||||
}
|
||||
|
||||
inline void
|
||||
write_uchar(FILE *file, unsigned char x) {
|
||||
putc(x, file);
|
||||
}
|
||||
|
||||
inline void
|
||||
write_float(FILE *file, float x) {
|
||||
pm_writebiglong(file, *(long *)&x);
|
||||
}
|
||||
|
||||
static int
|
||||
read_channel_pkt(FILE *file,
|
||||
int &chained, int &size, int &type, int &channel) {
|
||||
chained = read_uchar(file);
|
||||
size = read_uchar(file);
|
||||
type = read_uchar(file);
|
||||
channel = read_uchar(file);
|
||||
|
||||
if (feof(file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (size!=8) {
|
||||
pnmimage_cat.error()
|
||||
<< "Don't know how to interpret " << size << " bits per pixel!\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
read_rgb(xel *row_data, xelval *, FILE *file, int x, int repeat) {
|
||||
xelval red, grn, blu;
|
||||
red = read_uchar(file);
|
||||
grn = read_uchar(file);
|
||||
blu = read_uchar(file);
|
||||
|
||||
while (repeat>0) {
|
||||
PPM_ASSIGN(row_data[x], red, grn, blu);
|
||||
x++;
|
||||
repeat--;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
read_alpha(xel *, xelval *alpha_data, FILE *file, int x, int repeat) {
|
||||
xelval alpha = read_uchar(file);
|
||||
|
||||
while (repeat>0) {
|
||||
alpha_data[x] = alpha;
|
||||
x++;
|
||||
repeat--;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
read_rgba(xel *row_data, xelval *alpha_data, FILE *file, int x, int repeat) {
|
||||
xelval red, grn, blu, alpha;
|
||||
red = read_uchar(file);
|
||||
grn = read_uchar(file);
|
||||
blu = read_uchar(file);
|
||||
alpha = read_uchar(file);
|
||||
|
||||
while (repeat>0) {
|
||||
PPM_ASSIGN(row_data[x], red, grn, blu);
|
||||
alpha_data[x] = alpha;
|
||||
x++;
|
||||
repeat--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
read_scanline(xel *row_data, xelval *alpha_data, int cols, FILE *file,
|
||||
void (*read_data)(xel *row_data, xelval *alpha_data, FILE *file,
|
||||
int x, int repeat),
|
||||
int ctype) {
|
||||
if (ctype==UNCOMPRESSED) {
|
||||
for (int x = 0; x<cols; x++) {
|
||||
read_data(row_data, alpha_data, file, x, 1);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
int x;
|
||||
int num;
|
||||
|
||||
x = 0;
|
||||
while (x < cols) {
|
||||
num = read_uchar(file);
|
||||
|
||||
if (num<128) {
|
||||
// Sequence of non-repeated values.
|
||||
num++;
|
||||
if (x+num > cols) {
|
||||
return false;
|
||||
}
|
||||
while (num>0) {
|
||||
read_data(row_data, alpha_data, file, x, 1);
|
||||
if (feof(file)) {
|
||||
return false;
|
||||
}
|
||||
x++;
|
||||
num--;
|
||||
}
|
||||
} else {
|
||||
// Sequence of repeated values.
|
||||
if (num==128) {
|
||||
num = read_ushort(file);
|
||||
} else {
|
||||
num -= 127;
|
||||
}
|
||||
if (x+num > cols) {
|
||||
return false;
|
||||
}
|
||||
read_data(row_data, alpha_data, file, x, num);
|
||||
if (feof(file)) {
|
||||
return false;
|
||||
}
|
||||
x += num;
|
||||
}
|
||||
}
|
||||
|
||||
return (x==cols);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PNMReaderSoftImage::
|
||||
PNMReaderSoftImage(FILE *file, int already_read_magic) : PNMReader(file) {
|
||||
unsigned short magic1, magic2;
|
||||
|
||||
magic1 = (already_read_magic >= 0) ? already_read_magic : read_ushort(file);
|
||||
if (magic1 != SOFTIMAGE_MAGIC1) {
|
||||
valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
magic2 = read_ushort(file);
|
||||
if (magic2 != SOFTIMAGE_MAGIC2) {
|
||||
valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// skip version number
|
||||
read_float(file);
|
||||
|
||||
// Skip comment
|
||||
fseek(file, imageCommentLength, SEEK_CUR);
|
||||
|
||||
char pict_id[4];
|
||||
if (fread(pict_id, 1, 4, file) < 4) {
|
||||
valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (memcmp(pict_id, "PICT", 4)!=0) {
|
||||
valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
cols = read_ushort(file);
|
||||
rows = read_ushort(file);
|
||||
|
||||
float ratio = read_float(file);
|
||||
int fields = read_ushort(file);
|
||||
read_ushort(file);
|
||||
|
||||
int chained, size, channel;
|
||||
if (!read_channel_pkt(file, chained, size, rgb_ctype, channel)) {
|
||||
valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
soft_color = unknown;
|
||||
|
||||
if (channel == (RGB_CHANNEL | ALPHA_CHANNEL)) {
|
||||
// Four components in the first part: RGBA.
|
||||
soft_color = rgba;
|
||||
|
||||
} else if (channel == RGB_CHANNEL) {
|
||||
// Three components in the first part: RGB.
|
||||
soft_color = rgb;
|
||||
|
||||
if (chained) {
|
||||
if (!read_channel_pkt(file, chained, size, alpha_ctype, channel)) {
|
||||
valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (channel == ALPHA_CHANNEL) {
|
||||
// Alpha component in the second part: RGBA.
|
||||
soft_color = rgb_a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (soft_color) {
|
||||
case rgb:
|
||||
color_type = PNMImage::Color;
|
||||
break;
|
||||
|
||||
case rgba:
|
||||
case rgb_a:
|
||||
color_type = PNMImage::FourChannel;
|
||||
break;
|
||||
|
||||
default:
|
||||
pnmimage_cat.error()
|
||||
<< "Image is not RGB or RGBA!\n";
|
||||
valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (chained) {
|
||||
pnmimage_cat.error()
|
||||
<< "Unexpected additional channels in image file.\n";
|
||||
valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
maxval = 255;
|
||||
}
|
||||
|
||||
bool PNMReaderSoftImage::
|
||||
ReadRow(xel *row_data, xelval *alpha_data) {
|
||||
switch (soft_color) {
|
||||
case rgb:
|
||||
if (!read_scanline(row_data, alpha_data, cols, file,
|
||||
read_rgb, rgb_ctype)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case rgba:
|
||||
if (!read_scanline(row_data, alpha_data, cols, file,
|
||||
read_rgba, rgb_ctype)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case rgb_a:
|
||||
if (!read_scanline(row_data, alpha_data, cols, file,
|
||||
read_rgb, rgb_ctype)) {
|
||||
return false;
|
||||
}
|
||||
if (!read_scanline(row_data, alpha_data, cols, file,
|
||||
read_alpha, alpha_ctype)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
write_channel_pkt(FILE *file,
|
||||
int chained, int size, int type, int channel) {
|
||||
write_uchar(file, chained);
|
||||
write_uchar(file, size);
|
||||
write_uchar(file, type);
|
||||
write_uchar(file, channel);
|
||||
}
|
||||
|
||||
static void
|
||||
write_rgb(xel *row_data, xelval *, FILE *file, int x) {
|
||||
write_uchar(file, PPM_GETR(row_data[x]));
|
||||
write_uchar(file, PPM_GETG(row_data[x]));
|
||||
write_uchar(file, PPM_GETB(row_data[x]));
|
||||
}
|
||||
|
||||
static int
|
||||
compare_rgb(xel *row_data, xelval *, int x1, int x2) {
|
||||
return PPM_EQUAL(row_data[x1], row_data[x2]);
|
||||
}
|
||||
|
||||
static void
|
||||
write_gray(xel *row_data, xelval *, FILE *file, int x) {
|
||||
write_uchar(file, PPM_GETB(row_data[x]));
|
||||
write_uchar(file, PPM_GETB(row_data[x]));
|
||||
write_uchar(file, PPM_GETB(row_data[x]));
|
||||
}
|
||||
|
||||
static int
|
||||
compare_gray(xel *row_data, xelval *, int x1, int x2) {
|
||||
return (PPM_GETB(row_data[x1])==PPM_GETB(row_data[x2]));
|
||||
}
|
||||
|
||||
static void
|
||||
write_alpha(xel *, xelval *alpha_data, FILE *file, int x) {
|
||||
write_uchar(file, alpha_data[x]);
|
||||
}
|
||||
|
||||
static int
|
||||
compare_alpha(xel *, xelval *alpha_data, int x1, int x2) {
|
||||
return (alpha_data[x1]==alpha_data[x2]);
|
||||
}
|
||||
|
||||
static void
|
||||
write_diff(xel *row_data, xelval *alpha_data, FILE *file,
|
||||
void (*write_data)(xel *row_data, xelval *alpha_data, FILE *file,
|
||||
int x),
|
||||
int tox, int length) {
|
||||
if (length>0) {
|
||||
nassertv(length<=128);
|
||||
|
||||
write_uchar(file, length-1);
|
||||
while (length>0) {
|
||||
length--;
|
||||
write_data(row_data, alpha_data, file, tox-length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
write_same(xel *row_data, xelval *alpha_data, FILE *file,
|
||||
void (*write_data)(xel *row_data, xelval *alpha_data, FILE *file,
|
||||
int x),
|
||||
int tox, int length) {
|
||||
if (length==1) {
|
||||
write_diff(row_data, alpha_data, file, write_data, tox, length);
|
||||
|
||||
} else if (length>0) {
|
||||
if (length<128) {
|
||||
write_uchar(file, length+127);
|
||||
} else {
|
||||
write_uchar(file, 128);
|
||||
write_ushort(file, length);
|
||||
}
|
||||
write_data(row_data, alpha_data, file, tox);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
write_scanline(xel *row_data, xelval *alpha_data, int cols, FILE *file,
|
||||
int (*compare_data)(xel *row_data, xelval *alpha_data,
|
||||
int x1, int x2),
|
||||
void (*write_data)(xel *row_data, xelval *alpha_data,
|
||||
FILE *file, int x)) {
|
||||
int run_length = 0;
|
||||
|
||||
int x = 0;
|
||||
int same = true;
|
||||
|
||||
// Go through each value in the scanline, from beginning to end, looking
|
||||
// for runs of identical values.
|
||||
while (x < cols) {
|
||||
|
||||
if (same) {
|
||||
|
||||
// We have been scanning past a run of identical values. In this case,
|
||||
// the run is the sequence of values from x-run_length to x-1.
|
||||
|
||||
if (!compare_data(row_data, alpha_data, x, x-run_length)) {
|
||||
// Oops, the end of a run.
|
||||
|
||||
if (run_length <= 1) {
|
||||
// If run_length is only 1, no big deal--this is actually the
|
||||
// beginning of a different-valued run.
|
||||
|
||||
same = false;
|
||||
|
||||
} else {
|
||||
// Write out the old run and begin a new one. We'll be optimistic
|
||||
// and hope the new run will also represent a sequence of identical
|
||||
// values (until we find otherwise).
|
||||
|
||||
write_same(row_data, alpha_data, file, write_data, x-1, run_length);
|
||||
same = true;
|
||||
run_length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
} else { // !same
|
||||
|
||||
// We have been scanning past a run of different values. In this case,
|
||||
// the run is the sequence of values from x-run_length to x-1.
|
||||
|
||||
if (run_length>128) {
|
||||
// We can't have different runs of more than 128 characters. Close
|
||||
// off the old run.
|
||||
|
||||
int excess = run_length - 128;
|
||||
write_diff(row_data, alpha_data, file, write_data, x-excess-1, 128);
|
||||
run_length = excess;
|
||||
|
||||
} else if (run_length > 2 &&
|
||||
compare_data(row_data, alpha_data, x, x-1) &&
|
||||
compare_data(row_data, alpha_data, x, x-2)) {
|
||||
|
||||
// If the last three values have been the same, then it's time to
|
||||
// begin a new run of similar values. Close off the old run.
|
||||
|
||||
write_diff(row_data, alpha_data, file, write_data, x-3, run_length-2);
|
||||
same = true;
|
||||
run_length = 2;
|
||||
}
|
||||
}
|
||||
|
||||
x++;
|
||||
run_length++;
|
||||
}
|
||||
|
||||
// We made it all the way to the end. Flush out the last run.
|
||||
|
||||
if (run_length>0) {
|
||||
if (same) {
|
||||
write_same(row_data, alpha_data, file, write_data, cols-1, run_length);
|
||||
} else {
|
||||
|
||||
// Mighty unlikely, but we might have just run over the
|
||||
// 128-pixel limit.
|
||||
if (run_length>128) {
|
||||
int excess = run_length - 128;
|
||||
write_diff(row_data, alpha_data, file, write_data, cols-excess-1, 128);
|
||||
run_length = excess;
|
||||
}
|
||||
|
||||
write_diff(row_data, alpha_data, file, write_data, cols-1, run_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool PNMWriterSoftImage::
|
||||
WriteHeader() {
|
||||
write_ushort(file, SOFTIMAGE_MAGIC1);
|
||||
write_ushort(file, SOFTIMAGE_MAGIC2);
|
||||
write_float(file, imageVersionNumber);
|
||||
|
||||
fwrite(imageComment, 1, imageCommentLength, file);
|
||||
fwrite("PICT", 1, 4, file);
|
||||
|
||||
write_ushort(file, cols);
|
||||
write_ushort(file, rows);
|
||||
|
||||
write_float(file, 1.0); // pixel aspect ratio; we don't know.
|
||||
write_ushort(file, 3); // fields value; we don't really know either.
|
||||
write_ushort(file, 0); // padding
|
||||
|
||||
// There doesn't seem to be a variation on SoftImage image formats for
|
||||
// grayscale images. We'll write out grayscale as a 3-channel image.
|
||||
|
||||
switch (color_type) {
|
||||
case PNMImage::Grayscale:
|
||||
case PNMImage::Color:
|
||||
write_channel_pkt(file, 0, 8, MIXED_RUN_LENGTH, RGB_CHANNEL);
|
||||
break;
|
||||
|
||||
case PNMImage::FourChannel:
|
||||
case PNMImage::TwoChannel:
|
||||
write_channel_pkt(file, 1, 8, MIXED_RUN_LENGTH, RGB_CHANNEL);
|
||||
write_channel_pkt(file, 0, 8, MIXED_RUN_LENGTH, ALPHA_CHANNEL);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PNMWriterSoftImage::
|
||||
WriteRow(xel *row_data, xelval *alpha_data) {
|
||||
if (PNMImage::IsGrayscale(color_type)) {
|
||||
write_scanline(row_data, alpha_data, cols, file, compare_gray, write_gray);
|
||||
|
||||
} else {
|
||||
write_scanline(row_data, alpha_data, cols, file, compare_rgb, write_rgb);
|
||||
}
|
||||
|
||||
if (PNMImage::HasAlpha(color_type)) {
|
||||
write_scanline(row_data, alpha_data, cols, file, compare_alpha, write_alpha);
|
||||
}
|
||||
|
||||
return !ferror(file);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,561 +0,0 @@
|
|||
// pnm-image-readtiff.cc
|
||||
//
|
||||
// PNMImage::ReadTIFF() and supporting functions.
|
||||
|
||||
|
||||
|
||||
// Much code in this file is borrowed from Netpbm, specifically tifftopnm.c
|
||||
// and pnmtotiff.c.
|
||||
/*
|
||||
** tifftopnm.c - converts a Tagged Image File to a portable anymap
|
||||
**
|
||||
** Derived by Jef Poskanzer from tif2ras.c, which is:
|
||||
**
|
||||
** Copyright (c) 1990 by Sun Microsystems, Inc.
|
||||
**
|
||||
** Author: Patrick J. Naughton
|
||||
** naughton@wind.sun.com
|
||||
**
|
||||
** Permission to use, copy, modify, and distribute this software and its
|
||||
** documentation for any purpose and without fee is hereby granted,
|
||||
** provided that the above copyright notice appear in all copies and that
|
||||
** both that copyright notice and this permission notice appear in
|
||||
** supporting documentation.
|
||||
**
|
||||
** This file is provided AS IS with no warranties of any kind. The author
|
||||
** shall have no liability with respect to the infringement of copyrights,
|
||||
** trade secrets or any patents by this file or any part thereof. In no
|
||||
** event will the author be liable for any lost revenue or profits or
|
||||
** other special, indirect and consequential damages.
|
||||
*/
|
||||
|
||||
#include "pnmImage.h"
|
||||
#include "pnmReader.h"
|
||||
#include "pnmReaderTypes.h"
|
||||
#include "pnmWriter.h"
|
||||
#include "pnmWriterTypes.h"
|
||||
|
||||
extern "C" {
|
||||
#include "../pnm/sgi.h"
|
||||
#include "../pnm/ppmcmap.h"
|
||||
#include "../tiff/tiff.h"
|
||||
#include "../tiff/tiffio.h"
|
||||
}
|
||||
|
||||
// true to display image information on load; false otherwise.
|
||||
int tiff_headerdump = false;
|
||||
|
||||
// These are configurable parameters to specify TIFF details on output.
|
||||
// See tools/drr/../pnm/libtiff/tiff.h or type man pnmtotiff for a better
|
||||
// explanation of options.
|
||||
|
||||
unsigned short tiff_compression = COMPRESSION_LZW;
|
||||
/* One of:
|
||||
COMPRESSION_NONE
|
||||
COMPRESSION_CCITTRLE
|
||||
COMPRESSION_CCITTFAX3
|
||||
COMPRESSION_CCITTFAX4
|
||||
COMPRESSION_LZW
|
||||
COMPRESSION_JPEG
|
||||
COMPRESSION_NEXT
|
||||
COMPRESSION_CCITTRLEW
|
||||
COMPRESSION_PACKBITS
|
||||
COMPRESSION_THUNDERSCAN
|
||||
*/
|
||||
|
||||
long tiff_g3options = 0;
|
||||
/* One or more of:
|
||||
GROUP3OPT_2DENCODING
|
||||
GROUP3OPT_FILLBITS
|
||||
|
||||
meaningful when tiff_compression == COMPRESSION_CCITTFAX3.
|
||||
*/
|
||||
|
||||
unsigned short tiff_fillorder = FILLORDER_MSB2LSB;
|
||||
/* One of:
|
||||
FILLORDER_MSB2LSB
|
||||
FILLORDER_LSB2MSB
|
||||
*/
|
||||
|
||||
short tiff_predictor = 0;
|
||||
/* 0, 1, or 2; meaningful when tiff_compression == COMPRESSION_LZW. */
|
||||
|
||||
|
||||
long tiff_rowsperstrip = 0;
|
||||
/* 0 or any positive number */
|
||||
|
||||
#define MAXCOLORS 1024
|
||||
#ifndef PHOTOMETRIC_DEPTH
|
||||
#define PHOTOMETRIC_DEPTH 32768
|
||||
#endif
|
||||
|
||||
static tsize_t
|
||||
StdioReadProc(thandle_t fd, tdata_t buf, tsize_t size)
|
||||
{
|
||||
return ((tsize_t)fread((void *)buf, 1, (size_t) size, (FILE *)fd));
|
||||
}
|
||||
|
||||
static tsize_t
|
||||
StdioWriteProc(thandle_t fd, tdata_t buf, tsize_t size)
|
||||
{
|
||||
return ((tsize_t)fwrite((void *)buf, 1, (size_t) size, (FILE *)fd));
|
||||
}
|
||||
|
||||
static toff_t
|
||||
StdioSeekProc(thandle_t fd, off_t off, int whence)
|
||||
{
|
||||
fseek((FILE *)fd, (long)off, whence);
|
||||
return (toff_t)ftell((FILE *)fd);
|
||||
}
|
||||
|
||||
static int
|
||||
StdioCloseProc(thandle_t)
|
||||
{
|
||||
// We don't actually close the file; we'll leave that up to our calling
|
||||
// procedure.
|
||||
return true;
|
||||
}
|
||||
|
||||
static toff_t
|
||||
StdioSizeProc(thandle_t fd)
|
||||
{
|
||||
fseek((FILE *)fd, 0, SEEK_END);
|
||||
return (toff_t)ftell((FILE *)fd);
|
||||
}
|
||||
|
||||
static int
|
||||
StdioMapProc(thandle_t, tdata_t*, toff_t*)
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
StdioUnmapProc(thandle_t, tdata_t, toff_t)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
PNMReaderTIFF::
|
||||
PNMReaderTIFF(FILE *file, int already_read_magic) : PNMReader(file) {
|
||||
int grayscale;
|
||||
int numcolors;
|
||||
int i;
|
||||
unsigned short* redcolormap;
|
||||
unsigned short* greencolormap;
|
||||
unsigned short* bluecolormap;
|
||||
|
||||
if (already_read_magic >= 0) {
|
||||
ungetc(already_read_magic >> 8, file);
|
||||
ungetc(already_read_magic & 0xff, file);
|
||||
}
|
||||
|
||||
tif = TIFFClientOpen("TIFF file", "r",
|
||||
(thandle_t) file,
|
||||
StdioReadProc, StdioWriteProc,
|
||||
(TIFFSeekProc)StdioSeekProc,
|
||||
StdioCloseProc, StdioSizeProc,
|
||||
StdioMapProc, StdioUnmapProc);
|
||||
|
||||
if ( tif == NULL )
|
||||
pm_error( "error opening TIFF file" );
|
||||
|
||||
if ( tiff_headerdump )
|
||||
TIFFPrintDirectory( tif, stderr, TIFFPRINT_NONE );
|
||||
|
||||
if ( ! TIFFGetField( tif, TIFFTAG_BITSPERSAMPLE, &bps ) )
|
||||
bps = 1;
|
||||
if ( ! TIFFGetField( tif, TIFFTAG_SAMPLESPERPIXEL, &spp ) )
|
||||
spp = 1;
|
||||
if ( ! TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photomet ) )
|
||||
pm_error( "error getting photometric" );
|
||||
|
||||
switch ( spp )
|
||||
{
|
||||
case 1:
|
||||
color_type = PNMImage::Grayscale;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
color_type = PNMImage::Color;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
color_type = PNMImage::FourChannel;
|
||||
break;
|
||||
|
||||
default:
|
||||
pm_error(
|
||||
"can only handle 1-channel gray scale or 1- or 3-channel color" );
|
||||
}
|
||||
|
||||
(void) TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &cols );
|
||||
(void) TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &rows );
|
||||
|
||||
if ( tiff_headerdump )
|
||||
{
|
||||
pm_message( "%dx%dx%d image", cols, rows, bps * spp );
|
||||
pm_message( "%d bits/sample, %d samples/pixel", bps, spp );
|
||||
}
|
||||
|
||||
maxval = ( 1 << bps ) - 1;
|
||||
if ( maxval == 1 && spp == 1 )
|
||||
{
|
||||
if ( tiff_headerdump )
|
||||
pm_message("monochrome" );
|
||||
grayscale = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch ( photomet )
|
||||
{
|
||||
case PHOTOMETRIC_MINISBLACK:
|
||||
if ( tiff_headerdump )
|
||||
pm_message( "%d graylevels (min=black)", maxval + 1 );
|
||||
grayscale = 1;
|
||||
break;
|
||||
|
||||
case PHOTOMETRIC_MINISWHITE:
|
||||
if ( tiff_headerdump )
|
||||
pm_message( "%d graylevels (min=white)", maxval + 1 );
|
||||
grayscale = 1;
|
||||
break;
|
||||
|
||||
case PHOTOMETRIC_PALETTE:
|
||||
if ( tiff_headerdump )
|
||||
pm_message( "colormapped" );
|
||||
if ( ! TIFFGetField( tif, TIFFTAG_COLORMAP, &redcolormap, &greencolormap, &bluecolormap ) )
|
||||
pm_error( "error getting colormaps" );
|
||||
numcolors = maxval + 1;
|
||||
if ( numcolors > MAXCOLORS )
|
||||
pm_error( "too many colors" );
|
||||
maxval = PNM_MAXMAXVAL;
|
||||
grayscale = 0;
|
||||
for ( i = 0; i < numcolors; ++i )
|
||||
{
|
||||
xelval r, g, b;
|
||||
r = (xelval)(maxval * (double)(redcolormap[i] / 65535.0));
|
||||
g = (xelval)(maxval * (double)(greencolormap[i] / 65535.0));
|
||||
b = (xelval)(maxval * (double)(bluecolormap[i] / 65535.0));
|
||||
PPM_ASSIGN( colormap[i], r, g, b );
|
||||
}
|
||||
break;
|
||||
|
||||
case PHOTOMETRIC_RGB:
|
||||
if ( tiff_headerdump )
|
||||
pm_message( "truecolor" );
|
||||
grayscale = 0;
|
||||
break;
|
||||
|
||||
case PHOTOMETRIC_MASK:
|
||||
pm_error( "don't know how to handle PHOTOMETRIC_MASK" );
|
||||
|
||||
case PHOTOMETRIC_DEPTH:
|
||||
pm_error( "don't know how to handle PHOTOMETRIC_DEPTH" );
|
||||
|
||||
default:
|
||||
pm_error( "unknown photometric: %d", photomet );
|
||||
}
|
||||
}
|
||||
if ( maxval > PNM_MAXMAXVAL )
|
||||
pm_error(
|
||||
"bits/sample is too large - try reconfiguring with PGM_BIGGRAYS\n or without PPM_PACKCOLORS" );
|
||||
|
||||
|
||||
if ( grayscale ) {
|
||||
color_type = PNMImage::Grayscale;
|
||||
} else if (color_type == PNMImage::Grayscale) {
|
||||
color_type = PNMImage::Color;
|
||||
}
|
||||
|
||||
current_row = 0;
|
||||
}
|
||||
|
||||
#define NEXTSAMPLE \
|
||||
{ \
|
||||
if ( bitsleft == 0 ) \
|
||||
{ \
|
||||
++inP; \
|
||||
bitsleft = 8; \
|
||||
} \
|
||||
bitsleft -= bps; \
|
||||
sample = ( *inP >> bitsleft ) & maxval; \
|
||||
}
|
||||
|
||||
bool PNMReaderTIFF::
|
||||
ReadRow(xel *row_data, xelval *alpha_data) {
|
||||
unsigned char *buf = (unsigned char*) alloca((size_t)TIFFScanlineSize(tif));
|
||||
int col;
|
||||
unsigned char sample;
|
||||
|
||||
if ( TIFFReadScanline( tif, buf, current_row, 0 ) < 0 )
|
||||
pm_error( "bad data read on line %d", current_row );
|
||||
unsigned char *inP = buf;
|
||||
int bitsleft = 8;
|
||||
|
||||
switch ( photomet ) {
|
||||
case PHOTOMETRIC_MINISBLACK:
|
||||
for ( col = 0; col < cols; ++col )
|
||||
{
|
||||
NEXTSAMPLE;
|
||||
PPM_PUTB(row_data[col], sample);
|
||||
}
|
||||
break;
|
||||
|
||||
case PHOTOMETRIC_MINISWHITE:
|
||||
for ( col = 0; col < cols; ++col )
|
||||
{
|
||||
NEXTSAMPLE;
|
||||
sample = maxval - sample;
|
||||
PPM_PUTB(row_data[col], sample);
|
||||
}
|
||||
break;
|
||||
|
||||
case PHOTOMETRIC_PALETTE:
|
||||
for ( col = 0; col < cols; ++col )
|
||||
{
|
||||
NEXTSAMPLE;
|
||||
row_data[col] = colormap[sample];
|
||||
}
|
||||
break;
|
||||
|
||||
case PHOTOMETRIC_RGB:
|
||||
for ( col = 0; col < cols; ++col ) {
|
||||
xelval r, g, b;
|
||||
|
||||
NEXTSAMPLE;
|
||||
r = sample;
|
||||
NEXTSAMPLE;
|
||||
g = sample;
|
||||
NEXTSAMPLE;
|
||||
b = sample;
|
||||
PPM_ASSIGN(row_data[col], r, g, b);
|
||||
if ( spp == 4 ) {
|
||||
NEXTSAMPLE; // Alpha channel
|
||||
alpha_data[col] = sample;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
pm_error( "unknown photometric: %d", photomet );
|
||||
}
|
||||
|
||||
current_row++;
|
||||
return true;
|
||||
}
|
||||
|
||||
PNMReaderTIFF::
|
||||
~PNMReaderTIFF() {
|
||||
TIFFClose( tif );
|
||||
// owns_file = false;
|
||||
}
|
||||
|
||||
|
||||
int PNMWriterTIFF::
|
||||
WriteData(xel *array, xelval *alpha) {
|
||||
colorhist_vector chv;
|
||||
colorhash_table cht;
|
||||
unsigned short red[MAXCOLORS], grn[MAXCOLORS], blu[MAXCOLORS];
|
||||
int row, colors, i;
|
||||
register int col;
|
||||
int grayscale;
|
||||
struct tiff * tif;
|
||||
short photometric;
|
||||
short samplesperpixel;
|
||||
short bitspersample;
|
||||
int bytesperrow;
|
||||
unsigned char* buf;
|
||||
unsigned char* tP;
|
||||
|
||||
/* Check for grayscale. */
|
||||
int is_grayscale = PNMImage::IsGrayscale(color_type);
|
||||
|
||||
switch ( color_type ) {
|
||||
case PNMImage::Color:
|
||||
pm_message( "computing colormap..." );
|
||||
|
||||
// This call is a bit of fakery to convert our proper 2-d array of
|
||||
// xels to an indirect 2-d array of pixels. We make it look like a
|
||||
// single row of cols * rows pixels.
|
||||
chv = ppm_computecolorhist( (pixel **)&array, cols * rows, 1,
|
||||
MAXCOLORS, &colors );
|
||||
if ( chv == (colorhist_vector) 0 ) {
|
||||
pm_message("Too many colors - proceeding to write a 24-bit RGB file." );
|
||||
pm_message("If you want an 8-bit palette file, try doing a 'ppmquant %d'.",
|
||||
MAXCOLORS );
|
||||
grayscale = 0;
|
||||
} else {
|
||||
pm_message( "%d colors found", colors );
|
||||
grayscale = 1;
|
||||
for ( i = 0; i < colors; ++i ) {
|
||||
register xelval r, g, b;
|
||||
|
||||
r = PPM_GETR( chv[i].color );
|
||||
g = PPM_GETG( chv[i].color );
|
||||
b = PPM_GETB( chv[i].color );
|
||||
if ( r != g || g != b ) {
|
||||
grayscale = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PNMImage::FourChannel:
|
||||
chv = (colorhist_vector) 0;
|
||||
grayscale = 0;
|
||||
break;
|
||||
|
||||
case PNMImage::TwoChannel: // We don't yet support two-channel output for TIFF's.
|
||||
case PNMImage::Grayscale:
|
||||
chv = (colorhist_vector) 0;
|
||||
grayscale = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Open output file. */
|
||||
tif = TIFFClientOpen("TIFF file", "w",
|
||||
(thandle_t) file,
|
||||
StdioReadProc, StdioWriteProc,
|
||||
(TIFFSeekProc)StdioSeekProc,
|
||||
StdioCloseProc, StdioSizeProc,
|
||||
StdioMapProc, StdioUnmapProc);
|
||||
if ( tif == NULL )
|
||||
return 0;
|
||||
|
||||
/* Figure out TIFF parameters. */
|
||||
switch ( color_type ) {
|
||||
case PNMImage::Color:
|
||||
case PNMImage::FourChannel:
|
||||
if ( chv == (colorhist_vector) 0 ) {
|
||||
samplesperpixel = (color_type==PNMImage::FourChannel ? 4 : 3);
|
||||
bitspersample = 8;
|
||||
photometric = PHOTOMETRIC_RGB;
|
||||
bytesperrow = cols * samplesperpixel;
|
||||
} else if ( grayscale ) {
|
||||
samplesperpixel = 1;
|
||||
bitspersample = pm_maxvaltobits( maxval );
|
||||
photometric = PHOTOMETRIC_MINISBLACK;
|
||||
bytesperrow = ( cols + i - 1 ) / i;
|
||||
} else {
|
||||
samplesperpixel = 1;
|
||||
bitspersample = 8;
|
||||
photometric = PHOTOMETRIC_PALETTE;
|
||||
bytesperrow = cols;
|
||||
}
|
||||
break;
|
||||
|
||||
case PNMImage::Grayscale:
|
||||
case PNMImage::TwoChannel:
|
||||
samplesperpixel = 1;
|
||||
bitspersample = pm_maxvaltobits( maxval );
|
||||
photometric = PHOTOMETRIC_MINISBLACK;
|
||||
i = 8 / bitspersample;
|
||||
bytesperrow = ( cols + i - 1 ) / i;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( tiff_rowsperstrip == 0 )
|
||||
tiff_rowsperstrip = ( 8 * 1024 ) / bytesperrow;
|
||||
buf = (unsigned char*) malloc( bytesperrow );
|
||||
if ( buf == (unsigned char*) 0 )
|
||||
pm_error( "can't allocate memory for row buffer" );
|
||||
|
||||
/* Set TIFF parameters. */
|
||||
TIFFSetField( tif, TIFFTAG_IMAGEWIDTH, cols );
|
||||
TIFFSetField( tif, TIFFTAG_IMAGELENGTH, rows );
|
||||
TIFFSetField( tif, TIFFTAG_BITSPERSAMPLE, bitspersample );
|
||||
TIFFSetField( tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT );
|
||||
TIFFSetField( tif, TIFFTAG_COMPRESSION, tiff_compression );
|
||||
if ( tiff_compression == COMPRESSION_CCITTFAX3 && tiff_g3options != 0 )
|
||||
TIFFSetField( tif, TIFFTAG_GROUP3OPTIONS, tiff_g3options );
|
||||
if ( tiff_compression == COMPRESSION_LZW && tiff_predictor != 0 )
|
||||
TIFFSetField( tif, TIFFTAG_PREDICTOR, tiff_predictor );
|
||||
TIFFSetField( tif, TIFFTAG_PHOTOMETRIC, photometric );
|
||||
TIFFSetField( tif, TIFFTAG_FILLORDER, tiff_fillorder );
|
||||
//TIFFSetField( tif, TIFFTAG_DOCUMENTNAME, "TIFF Image File");
|
||||
TIFFSetField( tif, TIFFTAG_IMAGEDESCRIPTION,
|
||||
"Generated via DRR's pnm-image library\n" );
|
||||
TIFFSetField( tif, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel );
|
||||
TIFFSetField( tif, TIFFTAG_ROWSPERSTRIP, tiff_rowsperstrip );
|
||||
/* TIFFSetField( tif, TIFFTAG_STRIPBYTECOUNTS, rows / tiff_rowsperstrip ); */
|
||||
TIFFSetField( tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG );
|
||||
|
||||
if ( chv == (colorhist_vector) 0 ) {
|
||||
cht = (colorhash_table) 0;
|
||||
} else {
|
||||
/* Make TIFF colormap. */
|
||||
for ( i = 0; i < colors; ++i ) {
|
||||
red[i] = (unsigned short) (PPM_GETR( chv[i].color ) * 65535L / maxval);
|
||||
grn[i] = (unsigned short) (PPM_GETG( chv[i].color ) * 65535L / maxval);
|
||||
blu[i] = (unsigned short) (PPM_GETB( chv[i].color ) * 65535L / maxval);
|
||||
}
|
||||
TIFFSetField( tif, TIFFTAG_COLORMAP, red, grn, blu );
|
||||
|
||||
/* Convert color vector to color hash table, for fast lookup. */
|
||||
cht = ppm_colorhisttocolorhash( chv, colors );
|
||||
ppm_freecolorhist( chv );
|
||||
}
|
||||
|
||||
/* Now write the TIFF data. */
|
||||
for ( row = 0; row < rows; ++row ) {
|
||||
xel *row_data = array + row*cols;
|
||||
xelval *alpha_data = alpha + row*cols;
|
||||
|
||||
if ( !is_grayscale && ! grayscale ) {
|
||||
if ( cht == (colorhash_table) 0 ) {
|
||||
tP = buf;
|
||||
for ( col = 0; col < cols; ++col ) {
|
||||
*tP++ = (unsigned char)(255 * PPM_GETR(row_data[col]) / maxval);
|
||||
*tP++ = (unsigned char)(255 * PPM_GETG(row_data[col]) / maxval);
|
||||
*tP++ = (unsigned char)(255 * PPM_GETB(row_data[col]) / maxval);
|
||||
if (samplesperpixel==4) {
|
||||
*tP++ = (unsigned char)(255 * alpha_data[col] / maxval);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tP = buf;
|
||||
for ( col = 0; col < cols; ++col ) {
|
||||
register int s;
|
||||
|
||||
s = ppm_lookupcolor( cht, (pixel *)(&row_data[col]) );
|
||||
if ( s == -1 )
|
||||
pm_error("color not found?!? row=%d col=%d", row, col);
|
||||
*tP++ = (unsigned char) s;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
register xelval bigger_maxval;
|
||||
register int bitshift;
|
||||
register unsigned char byte;
|
||||
register xelval s;
|
||||
|
||||
bigger_maxval = pm_bitstomaxval( bitspersample );
|
||||
bitshift = 8 - bitspersample;
|
||||
byte = 0;
|
||||
tP = buf;
|
||||
for ( col = 0; col < cols; ++col ) {
|
||||
s = PPM_GETB(row_data[col]);
|
||||
if ( maxval != bigger_maxval )
|
||||
s = (xelval)((long) s * bigger_maxval / maxval);
|
||||
byte |= s << bitshift;
|
||||
bitshift -= bitspersample;
|
||||
if ( bitshift < 0 ) {
|
||||
*tP++ = byte;
|
||||
bitshift = 8 - bitspersample;
|
||||
byte = 0;
|
||||
}
|
||||
}
|
||||
if ( bitshift != 8 - bitspersample )
|
||||
*tP++ = byte;
|
||||
}
|
||||
|
||||
if ( TIFFWriteScanline( tif, buf, row, 0 ) < 0 )
|
||||
pm_error( "failed a scanline write on row %d", row );
|
||||
}
|
||||
TIFFFlushData( tif );
|
||||
TIFFClose( tif );
|
||||
// owns_file = false;
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
|
@ -1,606 +0,0 @@
|
|||
// pnm-image-writebmp.cc
|
||||
//
|
||||
// PNMImage::WriteBMP() and supporting functions.
|
||||
|
||||
|
||||
|
||||
// Much code in this file is borrowed from Netpbm, specifically ppmtobmp.c.
|
||||
/*\
|
||||
* $Id$
|
||||
*
|
||||
* ppmtobmp.c - Converts from a PPM file to a Microsoft Windows or OS/2
|
||||
* .BMP file.
|
||||
*
|
||||
* The current implementation is probably not complete, but it works for
|
||||
* me. I welcome feedback.
|
||||
*
|
||||
* Copyright (C) 1992 by David W. Sanderson.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software and its
|
||||
* documentation for any purpose and without fee is hereby granted,
|
||||
* provided that the above copyright notice appear in all copies and
|
||||
* that both that copyright notice and this permission notice appear
|
||||
* in supporting documentation. This software is provided "as is"
|
||||
* without express or implied warranty.
|
||||
*
|
||||
* $Log$
|
||||
* Revision 1.2 2000/10/17 21:49:09 drose
|
||||
* *** empty log message ***
|
||||
*
|
||||
* Revision 1.1.1.1 2000/10/04 01:14:42 drose
|
||||
*
|
||||
*
|
||||
* Revision 1.9 1992/11/24 19:39:33 dws
|
||||
* Added copyright.
|
||||
*
|
||||
* Revision 1.8 1992/11/17 02:16:52 dws
|
||||
* Moved length functions to bmp.h.
|
||||
*
|
||||
* Revision 1.7 1992/11/11 23:18:16 dws
|
||||
* Modified to adjust the bits per pixel to 1, 4, or 8.
|
||||
*
|
||||
* Revision 1.6 1992/11/11 22:43:39 dws
|
||||
* Commented out a superfluous message.
|
||||
*
|
||||
* Revision 1.5 1992/11/11 05:58:06 dws
|
||||
* First version that works.
|
||||
*
|
||||
* Revision 1.4 1992/11/11 03:40:32 dws
|
||||
* Moved calculation of bits per pixel to BMPEncode.
|
||||
*
|
||||
* Revision 1.3 1992/11/11 03:02:34 dws
|
||||
* Added BMPEncode function.
|
||||
*
|
||||
* Revision 1.2 1992/11/08 01:44:35 dws
|
||||
* Added option processing and reading of PPM file.
|
||||
*
|
||||
* Revision 1.1 1992/11/08 00:46:07 dws
|
||||
* Initial revision
|
||||
\*/
|
||||
|
||||
#include "pnmImage.h"
|
||||
#include "pnmWriter.h"
|
||||
#include "pnmWriterTypes.h"
|
||||
|
||||
extern "C" {
|
||||
#include "../pnm/bmp.h"
|
||||
#include "../pnm/ppmcmap.h"
|
||||
#include "../pnm/bitio.h"
|
||||
}
|
||||
|
||||
#define MAXCOLORS 256
|
||||
|
||||
/*
|
||||
* Utilities
|
||||
*/
|
||||
|
||||
static char er_write[] = "stdout: write error";
|
||||
|
||||
/* prototypes */
|
||||
static void PutByte ARGS((FILE *fp, char v));
|
||||
static void PutShort ARGS((FILE *fp, short v));
|
||||
static void PutLong ARGS((FILE *fp, long v));
|
||||
static int BMPwritefileheader ARGS((FILE *fp, int classv, unsigned long bitcount,
|
||||
unsigned long x, unsigned long y));
|
||||
static int BMPwriteinfoheader ARGS((FILE *fp, int classv, unsigned long bitcount,
|
||||
unsigned long x, unsigned long y));
|
||||
static int BMPwritergb ARGS((FILE *fp, int classv, pixval R, pixval G, pixval B));
|
||||
static int BMPwritergbtable ARGS((FILE *fp, int classv, int bpp, int colors,
|
||||
pixval *R, pixval *G, pixval *B));
|
||||
static int BMPwriterow ARGS((FILE *fp, pixel *row, unsigned long cx,
|
||||
unsigned short bpp, colorhash_table cht));
|
||||
static int BMPwritebits ARGS((FILE *fp, unsigned long cx, unsigned long cy,
|
||||
unsigned short cBitCount, pixel **pixels, colorhash_table cht));
|
||||
static int colorstobpp ARGS((int colors));
|
||||
static void BMPEncode ARGS((FILE *fp, int classv, int x, int y, pixel **pixels,
|
||||
int colors, colorhash_table cht, pixval *R, pixval *G, pixval *B));
|
||||
static void
|
||||
PutByte(
|
||||
FILE *fp,
|
||||
char v)
|
||||
{
|
||||
if (putc(v, fp) == EOF)
|
||||
{
|
||||
pm_error(er_write);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
PutShort(
|
||||
FILE *fp,
|
||||
short v)
|
||||
{
|
||||
if (pm_writelittleshort(fp, v) == -1)
|
||||
{
|
||||
pm_error(er_write);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
PutLong(
|
||||
FILE *fp,
|
||||
long v)
|
||||
{
|
||||
if (pm_writelittlelong(fp, v) == -1)
|
||||
{
|
||||
pm_error(er_write);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* BMP writing
|
||||
*/
|
||||
|
||||
/*
|
||||
* returns the number of bytes written, or -1 on error.
|
||||
*/
|
||||
static int
|
||||
BMPwritefileheader(
|
||||
FILE *fp,
|
||||
int classv,
|
||||
unsigned long bitcount,
|
||||
unsigned long x,
|
||||
unsigned long y)
|
||||
{
|
||||
PutByte(fp, 'B');
|
||||
PutByte(fp, 'M');
|
||||
|
||||
/* cbSize */
|
||||
PutLong(fp, (long)BMPlenfile(classv, bitcount, x, y));
|
||||
|
||||
/* xHotSpot */
|
||||
PutShort(fp, 0);
|
||||
|
||||
/* yHotSpot */
|
||||
PutShort(fp, 0);
|
||||
|
||||
/* offBits */
|
||||
PutLong(fp, (long)BMPoffbits(classv, bitcount));
|
||||
|
||||
return 14;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns the number of bytes written, or -1 on error.
|
||||
*/
|
||||
static int
|
||||
BMPwriteinfoheader(
|
||||
FILE *fp,
|
||||
int classv,
|
||||
unsigned long bitcount,
|
||||
unsigned long x,
|
||||
unsigned long y)
|
||||
{
|
||||
long cbFix;
|
||||
|
||||
/* cbFix */
|
||||
switch (classv)
|
||||
{
|
||||
case C_WIN:
|
||||
cbFix = 40;
|
||||
PutLong(fp, cbFix);
|
||||
|
||||
/* cx */
|
||||
PutLong(fp, (long)x);
|
||||
/* cy */
|
||||
PutLong(fp, (long)y);
|
||||
/* cPlanes */
|
||||
PutShort(fp, 1);
|
||||
/* cBitCount */
|
||||
PutShort(fp, (short)bitcount);
|
||||
|
||||
/*
|
||||
* We've written 16 bytes so far, need to write 24 more
|
||||
* for the required total of 40.
|
||||
*/
|
||||
|
||||
PutLong(fp, 0);
|
||||
PutLong(fp, 0);
|
||||
PutLong(fp, 0);
|
||||
PutLong(fp, 0);
|
||||
PutLong(fp, 0);
|
||||
PutLong(fp, 0);
|
||||
|
||||
|
||||
break;
|
||||
case C_OS2:
|
||||
cbFix = 12;
|
||||
PutLong(fp, cbFix);
|
||||
|
||||
/* cx */
|
||||
PutShort(fp, (short)x);
|
||||
/* cy */
|
||||
PutShort(fp, (short)y);
|
||||
/* cPlanes */
|
||||
PutShort(fp, 1);
|
||||
/* cBitCount */
|
||||
PutShort(fp, (short)bitcount);
|
||||
|
||||
break;
|
||||
default:
|
||||
pm_error(er_internal, "BMPwriteinfoheader");
|
||||
}
|
||||
|
||||
return cbFix;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns the number of bytes written, or -1 on error.
|
||||
*/
|
||||
static int
|
||||
BMPwritergb(
|
||||
FILE *fp,
|
||||
int classv,
|
||||
pixval R,
|
||||
pixval G,
|
||||
pixval B)
|
||||
{
|
||||
switch (classv)
|
||||
{
|
||||
case C_WIN:
|
||||
PutByte(fp, B);
|
||||
PutByte(fp, G);
|
||||
PutByte(fp, R);
|
||||
PutByte(fp, 0);
|
||||
return 4;
|
||||
case C_OS2:
|
||||
PutByte(fp, B);
|
||||
PutByte(fp, G);
|
||||
PutByte(fp, R);
|
||||
return 3;
|
||||
default:
|
||||
pm_error(er_internal, "BMPwritergb");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns the number of bytes written, or -1 on error.
|
||||
*/
|
||||
static int
|
||||
BMPwritergbtable(
|
||||
FILE *fp,
|
||||
int classv,
|
||||
int bpp,
|
||||
int colors,
|
||||
pixval *R,
|
||||
pixval *G,
|
||||
pixval *B)
|
||||
{
|
||||
int nbyte = 0;
|
||||
int i;
|
||||
long ncolors;
|
||||
|
||||
for (i = 0; i < colors; i++)
|
||||
{
|
||||
nbyte += BMPwritergb(fp,classv,R[i],G[i],B[i]);
|
||||
}
|
||||
|
||||
ncolors = (1 << bpp);
|
||||
|
||||
for (; i < ncolors; i++)
|
||||
{
|
||||
nbyte += BMPwritergb(fp,classv,0,0,0);
|
||||
}
|
||||
|
||||
return nbyte;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns the number of bytes written, or -1 on error.
|
||||
*/
|
||||
static int
|
||||
BMPwriterow(
|
||||
FILE *fp,
|
||||
pixel *row,
|
||||
unsigned long cx,
|
||||
unsigned short bpp,
|
||||
int indexed,
|
||||
colorhash_table cht)
|
||||
{
|
||||
BITSTREAM b;
|
||||
unsigned nbyte = 0;
|
||||
int rc;
|
||||
unsigned x;
|
||||
|
||||
if (indexed) {
|
||||
if ((b = pm_bitinit(fp, "w")) == (BITSTREAM) 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (x = 0; x < cx; x++, row++)
|
||||
{
|
||||
if ((rc = pm_bitwrite(b, bpp, ppm_lookupcolor(cht, row))) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
nbyte += rc;
|
||||
}
|
||||
|
||||
if ((rc = pm_bitfini(b)) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
nbyte += rc;
|
||||
} else {
|
||||
|
||||
for (x = 0; x < cx; x++, row++)
|
||||
{
|
||||
PutByte(fp, PPM_GETB(*row));
|
||||
PutByte(fp, PPM_GETG(*row));
|
||||
PutByte(fp, PPM_GETR(*row));
|
||||
nbyte += 3;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure we write a multiple of 4 bytes.
|
||||
*/
|
||||
while (nbyte % 4)
|
||||
{
|
||||
PutByte(fp, 0);
|
||||
nbyte++;
|
||||
}
|
||||
|
||||
return nbyte;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns the number of bytes written, or -1 on error.
|
||||
*/
|
||||
static int
|
||||
BMPwritebits(
|
||||
FILE *fp,
|
||||
unsigned long cx,
|
||||
unsigned long cy,
|
||||
unsigned short cBitCount,
|
||||
pixel **pixels,
|
||||
int indexed,
|
||||
colorhash_table cht)
|
||||
{
|
||||
int nbyte = 0;
|
||||
long y;
|
||||
|
||||
if(cBitCount > 24)
|
||||
{
|
||||
pm_error("cannot handle cBitCount: %d"
|
||||
,cBitCount);
|
||||
}
|
||||
|
||||
/*
|
||||
* The picture is stored bottom line first, top line last
|
||||
*/
|
||||
|
||||
for (y = (long)cy - 1; y >= 0; y--)
|
||||
{
|
||||
int rc;
|
||||
rc = BMPwriterow(fp, pixels[y], cx, cBitCount, indexed, cht);
|
||||
|
||||
if(rc == -1)
|
||||
{
|
||||
pm_error("couldn't write row %d"
|
||||
,y);
|
||||
}
|
||||
if(rc%4)
|
||||
{
|
||||
pm_error("row had bad number of bytes: %d"
|
||||
,rc);
|
||||
}
|
||||
nbyte += rc;
|
||||
}
|
||||
|
||||
return nbyte;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the number of bits per pixel required to represent the
|
||||
* given number of colors.
|
||||
*/
|
||||
|
||||
static int
|
||||
colorstobpp(int colors)
|
||||
{
|
||||
int bpp;
|
||||
|
||||
if (colors < 1)
|
||||
{
|
||||
pm_error("can't have less than one color");
|
||||
}
|
||||
|
||||
if ((bpp = pm_maxvaltobits(colors - 1)) > 8)
|
||||
{
|
||||
pm_error("can't happen");
|
||||
}
|
||||
|
||||
return bpp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a BMP file of the given classv.
|
||||
*
|
||||
* Note that we must have 'colors' in order to know exactly how many
|
||||
* colors are in the R, G, B, arrays. Entries beyond those in the
|
||||
* arrays are undefined.
|
||||
*/
|
||||
static void
|
||||
BMPEncode(
|
||||
FILE *fp,
|
||||
int classv,
|
||||
int x,
|
||||
int y,
|
||||
pixel **pixels,
|
||||
int colors, /* number of valid entries in R,G,B */
|
||||
colorhash_table cht,
|
||||
pixval *R,
|
||||
pixval *G,
|
||||
pixval *B)
|
||||
{
|
||||
int bpp; /* bits per pixel */
|
||||
unsigned long nbyte = 0;
|
||||
|
||||
bpp = colorstobpp(colors);
|
||||
|
||||
/*
|
||||
* I have found empirically at least one BMP-displaying program
|
||||
* that can't deal with (for instance) using 3 bits per pixel.
|
||||
* I have seen no programs that can deal with using 3 bits per
|
||||
* pixel. I have seen programs which can deal with 1, 4, and
|
||||
* 8 bits per pixel.
|
||||
*
|
||||
* Based on this, I adjust actual the number of bits per pixel
|
||||
* as follows. If anyone knows better, PLEASE tell me!
|
||||
*/
|
||||
switch(bpp)
|
||||
{
|
||||
case 2:
|
||||
case 3:
|
||||
bpp = 4;
|
||||
break;
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
bpp = 8;
|
||||
break;
|
||||
}
|
||||
|
||||
pm_message("Using %d bits per pixel", bpp);
|
||||
|
||||
nbyte += BMPwritefileheader(fp, classv, bpp, x, y);
|
||||
nbyte += BMPwriteinfoheader(fp, classv, bpp, x, y);
|
||||
nbyte += BMPwritergbtable(fp, classv, bpp, colors, R, G, B);
|
||||
|
||||
if(nbyte != ( BMPlenfileheader(classv)
|
||||
+ BMPleninfoheader(classv)
|
||||
+ BMPlenrgbtable(classv, bpp)))
|
||||
{
|
||||
pm_error(er_internal, "BMPEncode");
|
||||
}
|
||||
|
||||
nbyte += BMPwritebits(fp, x, y, bpp, pixels, true, cht);
|
||||
if(nbyte != BMPlenfile(classv, bpp, x, y))
|
||||
{
|
||||
pm_error(er_internal, "BMPEncode");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a BMP file of the given class, with 24 bits per pixel nonindexed.
|
||||
*/
|
||||
static void
|
||||
BMPEncode24(
|
||||
FILE *fp,
|
||||
int classv,
|
||||
int x,
|
||||
int y,
|
||||
pixel **pixels)
|
||||
{
|
||||
unsigned long nbyte = 0;
|
||||
int bpp = 24;
|
||||
|
||||
pm_message("Using %d bits per pixel", bpp);
|
||||
|
||||
nbyte += BMPwritefileheader(fp, classv, bpp, x, y);
|
||||
nbyte += BMPwriteinfoheader(fp, classv, bpp, x, y);
|
||||
|
||||
if(nbyte != ( BMPlenfileheader(classv)
|
||||
+ BMPleninfoheader(classv)))
|
||||
{
|
||||
pm_error(er_internal, "BMPEncode24");
|
||||
}
|
||||
|
||||
nbyte += BMPwritebits(fp, x, y, bpp, pixels, false, colorhash_table());
|
||||
if(nbyte != BMPlenfile(classv, bpp, x, y))
|
||||
{
|
||||
pm_error(er_internal, "BMPEncode24");
|
||||
}
|
||||
}
|
||||
|
||||
int PNMWriterBMP::
|
||||
WriteData(xel *array, xelval *) {
|
||||
if (rows<=0 || cols<=0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int classv = C_WIN;
|
||||
|
||||
int colors;
|
||||
int i;
|
||||
colorhist_vector chv;
|
||||
pixval Red[MAXCOLORS];
|
||||
pixval Green[MAXCOLORS];
|
||||
pixval Blue[MAXCOLORS];
|
||||
|
||||
pixel** pixels;
|
||||
colorhash_table cht;
|
||||
|
||||
#if 0
|
||||
{
|
||||
char *name;
|
||||
switch (classv)
|
||||
{
|
||||
case C_WIN:
|
||||
name = "a Windows";
|
||||
break;
|
||||
case C_OS2:
|
||||
name = "an OS/2";
|
||||
break;
|
||||
default:
|
||||
pm_error(er_internal, "report");
|
||||
break;
|
||||
}
|
||||
pm_message("generating %s BMP file", name);
|
||||
}
|
||||
#endif
|
||||
|
||||
// We need an honest 2-d array of pixels, instead of one big 1-d array.
|
||||
pixels = (pixel **)alloca(sizeof(pixel *) * rows);
|
||||
for (i = 0; i < rows; i++) {
|
||||
pixels[i] = (pixel *)(array + i * cols);
|
||||
}
|
||||
|
||||
/* Figure out the colormap. */
|
||||
pm_message("computing colormap...");
|
||||
chv = ppm_computecolorhist(pixels, cols, rows, MAXCOLORS, &colors);
|
||||
if (chv == (colorhist_vector) 0) {
|
||||
pm_message("too many colors; generating 24-bit BMP file");
|
||||
|
||||
BMPEncode24(file, classv, cols, rows, pixels);
|
||||
|
||||
} else {
|
||||
pm_message("%d colors found", colors);
|
||||
|
||||
/*
|
||||
* Now turn the ppm colormap into the appropriate GIF
|
||||
* colormap.
|
||||
*/
|
||||
if (maxval > 255)
|
||||
{
|
||||
pm_message("maxval is not 255 - automatically rescaling colors");
|
||||
}
|
||||
for (i = 0; i < colors; ++i)
|
||||
{
|
||||
if (maxval == 255)
|
||||
{
|
||||
Red[i] = PPM_GETR(chv[i].color);
|
||||
Green[i] = PPM_GETG(chv[i].color);
|
||||
Blue[i] = PPM_GETB(chv[i].color);
|
||||
}
|
||||
else
|
||||
{
|
||||
Red[i] = (pixval) PPM_GETR(chv[i].color) * 255 / maxval;
|
||||
Green[i] = (pixval) PPM_GETG(chv[i].color) * 255 / maxval;
|
||||
Blue[i] = (pixval) PPM_GETB(chv[i].color) * 255 / maxval;
|
||||
}
|
||||
}
|
||||
|
||||
/* And make a hash table for fast lookup. */
|
||||
cht = ppm_colorhisttocolorhash(chv, colors);
|
||||
ppm_freecolorhist(chv);
|
||||
|
||||
BMPEncode(file, classv, cols, rows, pixels, colors, cht,
|
||||
Red, Green, Blue);
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
|
@ -1,304 +0,0 @@
|
|||
// pnm-image-writesgi.cc
|
||||
//
|
||||
// PNMImage::WriteSGI() and supporting functions.
|
||||
|
||||
|
||||
|
||||
// Much code in this file originally came from from Netpbm,
|
||||
// specifically pnmtosgi.c. It has since been fairly heavily
|
||||
// modified.
|
||||
|
||||
/* pnmtosgi.c - convert portable anymap to SGI image
|
||||
**
|
||||
** Copyright (C) 1994 by Ingo Wilken (Ingo.Wilken@informatik.uni-oldenburg.de)
|
||||
**
|
||||
** Based on the SGI image description v0.9 by Paul Haeberli (paul@sgi.comp)
|
||||
** Available via ftp from sgi.com:graphics/SGIIMAGESPEC
|
||||
**
|
||||
** Permission to use, copy, modify, and distribute this software and its
|
||||
** documentation for any purpose and without fee is hereby granted, provided
|
||||
** that the above copyright notice appear in all copies and that both that
|
||||
** copyright notice and this permission notice appear in supporting
|
||||
** documentation. This software is provided "as is" without express or
|
||||
** implied warranty.
|
||||
**
|
||||
** 29Jan94: first version
|
||||
*/
|
||||
|
||||
#include "pnmImage.h"
|
||||
#include "pnmWriter.h"
|
||||
#include "pnmWriterTypes.h"
|
||||
#include "../pnm/sgi.h"
|
||||
|
||||
|
||||
|
||||
#define WORSTCOMPR(x) (2*(x) + 2)
|
||||
|
||||
|
||||
#define MAXVAL_BYTE 255
|
||||
#define MAXVAL_WORD 65535
|
||||
|
||||
static char storage = STORAGE_RLE;
|
||||
|
||||
inline void
|
||||
put_byte(FILE *out_file, unsigned char b) {
|
||||
putc(b, out_file);
|
||||
}
|
||||
|
||||
static void
|
||||
put_big_short(FILE *out_file, short s) {
|
||||
if ( pm_writebigshort( out_file, s ) == -1 )
|
||||
pm_error( "write error" );
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
put_big_long(FILE *out_file, long l) {
|
||||
if ( pm_writebiglong( out_file, l ) == -1 )
|
||||
pm_error( "write error" );
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
put_short_as_byte(FILE *out_file, short s) {
|
||||
put_byte(out_file, (unsigned char)s);
|
||||
}
|
||||
|
||||
PNMWriterSGI::
|
||||
~PNMWriterSGI() {
|
||||
if (table!=NULL) {
|
||||
// Rewrite the table with the correct values in it.
|
||||
fseek(file, table_start, SEEK_SET);
|
||||
WriteTable();
|
||||
delete[] table;
|
||||
}
|
||||
}
|
||||
|
||||
bool PNMWriterSGI::
|
||||
WriteHeader() {
|
||||
table = NULL;
|
||||
|
||||
switch (color_type) {
|
||||
case PNMImage::Grayscale:
|
||||
dimensions = 2; channels = 1;
|
||||
break;
|
||||
|
||||
case PNMImage::TwoChannel:
|
||||
dimensions = 2; channels = 2;
|
||||
break;
|
||||
|
||||
case PNMImage::Color:
|
||||
dimensions = 3; channels = 3;
|
||||
break;
|
||||
|
||||
case PNMImage::FourChannel:
|
||||
dimensions = 3; channels = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
// For some reason, we have problems with SGI image files whose pixmax value
|
||||
// is not 255 or 65535. So, we'll round up when writing.
|
||||
if( maxval <= MAXVAL_BYTE ) {
|
||||
bpc = 1;
|
||||
new_maxval = MAXVAL_BYTE;
|
||||
} else if( maxval <= MAXVAL_WORD ) {
|
||||
bpc = 2;
|
||||
new_maxval = MAXVAL_WORD;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if( storage != STORAGE_VERBATIM ) {
|
||||
table = new TabEntry[channels * rows];
|
||||
memset(table, 0, channels * rows * sizeof(TabEntry));
|
||||
}
|
||||
|
||||
write_header("no name");
|
||||
if (table!=NULL) {
|
||||
table_start = ftell(file);
|
||||
|
||||
// The first time we write the table, it has zeroes. We'll correct
|
||||
// this later.
|
||||
WriteTable();
|
||||
}
|
||||
|
||||
current_row = rows-1;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PNMWriterSGI::
|
||||
WriteRow(xel *row_data, xelval *alpha_data) {
|
||||
ScanLine channel[4];
|
||||
|
||||
BuildScanline(channel, row_data, alpha_data);
|
||||
|
||||
if( bpc == 1 )
|
||||
WriteChannels(channel, put_short_as_byte);
|
||||
else
|
||||
WriteChannels(channel, put_big_short);
|
||||
|
||||
for (int i = 0; i < channels; i++) {
|
||||
delete[] channel[i].data;
|
||||
}
|
||||
|
||||
current_row--;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void PNMWriterSGI::
|
||||
write_header(char *imagename) {
|
||||
int i;
|
||||
|
||||
put_big_short(file, SGI_MAGIC);
|
||||
put_byte(file, storage);
|
||||
put_byte(file, (char)bpc);
|
||||
put_big_short(file, dimensions);
|
||||
put_big_short(file, cols);
|
||||
put_big_short(file, rows);
|
||||
put_big_short(file, channels);
|
||||
put_big_long(file, 0); /* PIXMIN */
|
||||
put_big_long(file, maxval); /* PIXMAX */
|
||||
for( i = 0; i < 4; i++ )
|
||||
put_byte(file, 0);
|
||||
for( i = 0; i < 79 && imagename[i] != '\0'; i++ )
|
||||
put_byte(file, imagename[i]);
|
||||
for(; i < 80; i++ )
|
||||
put_byte(file, 0);
|
||||
put_big_long(file, CMAP_NORMAL);
|
||||
for( i = 0; i < 404; i++ )
|
||||
put_byte(file, 0);
|
||||
}
|
||||
|
||||
|
||||
void PNMWriterSGI::
|
||||
WriteTable() {
|
||||
int i;
|
||||
int tabsize = rows*channels;
|
||||
|
||||
for( i = 0; i < tabsize; i++ ) {
|
||||
put_big_long(file, table[i].start);
|
||||
}
|
||||
for( i = 0; i < tabsize; i++ )
|
||||
put_big_long(file, table[i].length);
|
||||
}
|
||||
|
||||
|
||||
void PNMWriterSGI::
|
||||
WriteChannels(ScanLine channel[], void (*put)(FILE *, short)) {
|
||||
int i, col;
|
||||
|
||||
for( i = 0; i < channels; i++ ) {
|
||||
Table(i).start = ftell(file);
|
||||
Table(i).length = channel[i].length * bpc;
|
||||
|
||||
for( col = 0; col < channel[i].length; col++ ) {
|
||||
(*put)(file, channel[i].data[col]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PNMWriterSGI::
|
||||
BuildScanline(ScanLine output[], xel *row_data, xelval *alpha_data) {
|
||||
int col;
|
||||
ScanElem *temp;
|
||||
|
||||
if( storage != STORAGE_VERBATIM ) {
|
||||
rletemp = (ScanElem *)alloca(WORSTCOMPR(cols) * sizeof(ScanElem));
|
||||
}
|
||||
temp = new ScanElem[cols];
|
||||
|
||||
if( channels <= 2 ) {
|
||||
for( col = 0; col < cols; col++ )
|
||||
temp[col] = (ScanElem)
|
||||
(new_maxval * PPM_GETB(row_data[col]) / maxval);
|
||||
temp = Compress(temp, output[0]);
|
||||
|
||||
if (channels == 2) {
|
||||
for( col = 0; col < cols; col++ )
|
||||
temp[col] = (ScanElem)
|
||||
(new_maxval * alpha_data[col] / maxval);
|
||||
temp = Compress(temp, output[1]);
|
||||
}
|
||||
|
||||
} else {
|
||||
for( col = 0; col < cols; col++ )
|
||||
temp[col] = (ScanElem)
|
||||
(new_maxval * PPM_GETR(row_data[col]) / maxval);
|
||||
temp = Compress(temp, output[0]);
|
||||
for( col = 0; col < cols; col++ )
|
||||
temp[col] = (ScanElem)
|
||||
(new_maxval * PPM_GETG(row_data[col]) / maxval);
|
||||
temp = Compress(temp, output[1]);
|
||||
for( col = 0; col < cols; col++ )
|
||||
temp[col] = (ScanElem)
|
||||
(new_maxval * PPM_GETB(row_data[col]) / maxval);
|
||||
temp = Compress(temp, output[2]);
|
||||
if (channels == 4) {
|
||||
for( col = 0; col < cols; col++ )
|
||||
temp[col] = (ScanElem)
|
||||
(new_maxval * alpha_data[col] / maxval);
|
||||
temp = Compress(temp, output[3]);
|
||||
}
|
||||
}
|
||||
|
||||
delete[] temp;
|
||||
}
|
||||
|
||||
|
||||
PNMWriterSGI::ScanElem *PNMWriterSGI::
|
||||
Compress(ScanElem *temp, ScanLine &output) {
|
||||
int len;
|
||||
|
||||
switch( storage ) {
|
||||
case STORAGE_VERBATIM:
|
||||
output.length = cols;
|
||||
output.data = temp;
|
||||
temp = new ScanElem[cols];
|
||||
break;
|
||||
case STORAGE_RLE:
|
||||
len = RLECompress(temp, cols); /* writes result into rletemp */
|
||||
output.length = len;
|
||||
output.data = new ScanElem[len];
|
||||
memcpy(output.data, rletemp, len * sizeof(ScanElem));
|
||||
break;
|
||||
default:
|
||||
pm_error("unknown storage type - can\'t happen");
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
slightly modified RLE algorithm from ppmtoilbm.c
|
||||
written by Robert A. Knop (rknop@mop.caltech.edu)
|
||||
*/
|
||||
int PNMWriterSGI::
|
||||
RLECompress(ScanElem *inbuf, int size) {
|
||||
int in, out, hold, count;
|
||||
ScanElem *outbuf = rletemp;
|
||||
|
||||
in=out=0;
|
||||
while( in<size ) {
|
||||
if( (in<size-1) && (inbuf[in]==inbuf[in+1]) ) { /*Begin replicate run*/
|
||||
for( count=0,hold=in; in<size && inbuf[in]==inbuf[hold] && count<127; in++,count++)
|
||||
;
|
||||
outbuf[out++]=(ScanElem)(count);
|
||||
outbuf[out++]=inbuf[hold];
|
||||
}
|
||||
else { /*Do a literal run*/
|
||||
hold=out; out++; count=0;
|
||||
while( ((in>=size-2)&&(in<size)) || ((in<size-2) && ((inbuf[in]!=inbuf[in+1])||(inbuf[in]!=inbuf[in+2]))) ) {
|
||||
outbuf[out++]=inbuf[in++];
|
||||
if( ++count>=127 )
|
||||
break;
|
||||
}
|
||||
outbuf[hold]=(ScanElem)(count | 0x80);
|
||||
}
|
||||
}
|
||||
outbuf[out++] = (ScanElem)0; /* terminator */
|
||||
return(out);
|
||||
}
|
||||
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
// pnm-image-writeyuv.cc
|
||||
//
|
||||
// PNMImage::WriteYUV() and supporting functions.
|
||||
|
||||
|
||||
|
||||
// Much code in this file is borrowed from Netpbm, specifically ppmtoyuv.c.
|
||||
/* ppmtoyuv.c - convert a portable pixmap into an Abekas YUV file
|
||||
**
|
||||
** by Marc Boucher
|
||||
** Internet: marc@PostImage.cxxOM
|
||||
**
|
||||
** Based on Example Conversion Program, A60/A64 Digital Video Interface
|
||||
** Manual, page 69.
|
||||
**
|
||||
** Copyright (C) 1991 by DHD PostImage Inc.
|
||||
** Copyright (C) 1987 by Abekas Video Systems Inc.
|
||||
**
|
||||
** Permission to use, copy, modify, and distribute this software and its
|
||||
** documentation for any purpose and without fee is hereby granted, provided
|
||||
** that the above copyright notice appear in all copies and that both that
|
||||
** copyright notice and this permission notice appear in supporting
|
||||
** documentation. This software is provided "as is" without express or
|
||||
** implied warranty.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "pnmImage.h"
|
||||
#include "pnmWriter.h"
|
||||
#include "pnmWriterTypes.h"
|
||||
|
||||
|
||||
bool PNMWriterYUV::
|
||||
WriteHeader() {
|
||||
if (yuvbuf!=NULL) {
|
||||
pm_freerow((char *)yuvbuf);
|
||||
}
|
||||
|
||||
yuvbuf = (unsigned char *) pm_allocrow( cols, 2 );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PNMWriterYUV::
|
||||
WriteRow(xel *row_data, xelval *) {
|
||||
int col;
|
||||
unsigned long y1, y2=0, u=0, v=0, u0=0, u1, u2, v0=0, v1, v2;
|
||||
static const int max_byte = 255;
|
||||
|
||||
unsigned char *yuvptr;
|
||||
|
||||
for (col = 0, yuvptr=yuvbuf; col < cols; col += 2) {
|
||||
pixval r, g, b;
|
||||
|
||||
/* first pixel gives Y and 0.5 of chroma */
|
||||
r = (pixval)(max_byte * PPM_GETR(row_data[col])/maxval);
|
||||
g = (pixval)(max_byte * PPM_GETG(row_data[col])/maxval);
|
||||
b = (pixval)(max_byte * PPM_GETB(row_data[col])/maxval);
|
||||
|
||||
y1 = 16829 * r + 33039 * g + 6416 * b + (0xffff & y2);
|
||||
u1 = -4853 * r - 9530 * g + 14383 * b;
|
||||
v1 = 14386 * r - 12046 * g - 2340 * b;
|
||||
|
||||
/* second pixel just yields a Y and 0.25 U, 0.25 V */
|
||||
r = (pixval)(max_byte * PPM_GETR(row_data[col])/maxval);
|
||||
g = (pixval)(max_byte * PPM_GETG(row_data[col])/maxval);
|
||||
b = (pixval)(max_byte * PPM_GETB(row_data[col])/maxval);
|
||||
|
||||
y2 = 16829 * r + 33039 * g + 6416 * b + (0xffff & y1);
|
||||
u2 = -2426 * r - 4765 * g + 7191 * b;
|
||||
v2 = 7193 * r - 6023 * g - 1170 * b;
|
||||
|
||||
/* filter the chroma */
|
||||
u = u0 + u1 + u2 + (0xffff & u);
|
||||
v = v0 + v1 + v2 + (0xffff & v);
|
||||
|
||||
u0 = u2;
|
||||
v0 = v2;
|
||||
|
||||
*yuvptr++ = (unsigned char)((u >> 16) + 128);
|
||||
*yuvptr++ = (unsigned char)((y1 >> 16) + 16);
|
||||
*yuvptr++ = (unsigned char)((v >> 16) + 128);
|
||||
*yuvptr++ = (unsigned char)((y2 >> 16) + 16);
|
||||
}
|
||||
fwrite(yuvbuf, cols*2, 1, file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
PNMWriterYUV::
|
||||
~PNMWriterYUV() {
|
||||
if (yuvbuf!=NULL) {
|
||||
pm_freerow((char *)yuvbuf);
|
||||
}
|
||||
}
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PNMImageHeader::read_header
|
||||
// Access: Public, Static
|
||||
// Access: Public
|
||||
// Description: Opens up the image file and tries to read its header
|
||||
// information to determine its size, number of
|
||||
// channels, etc. If successful, updates the header
|
||||
|
|
@ -24,6 +24,7 @@ read_header(const Filename &filename, PNMFileType *type) {
|
|||
if (reader != (PNMReader *)NULL) {
|
||||
(*this) = (*reader);
|
||||
_type = reader->get_type();
|
||||
delete reader;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -32,13 +33,16 @@ read_header(const Filename &filename, PNMFileType *type) {
|
|||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PNMImageHeader::make_reader
|
||||
// Access: Public, Static
|
||||
// Description: Returns a PNMReader of the suitable type for reading
|
||||
// from the indicated image filename, or NULL if the
|
||||
// filename cannot be read for some reason. The
|
||||
// filename "-" always stands for standard input. If
|
||||
// type is specified, it is a suggestion for the file
|
||||
// type to use.
|
||||
// Access: Public
|
||||
// Description: Returns a newly-allocated PNMReader of the suitable
|
||||
// type for reading from the indicated image filename,
|
||||
// or NULL if the filename cannot be read for some
|
||||
// reason. The filename "-" always stands for standard
|
||||
// input. If type is specified, it is a suggestion for
|
||||
// the file type to use.
|
||||
//
|
||||
// The PNMReader should be deleted when it is no longer
|
||||
// needed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PNMReader *PNMImageHeader::
|
||||
make_reader(const Filename &filename, PNMFileType *type) const {
|
||||
|
|
@ -87,10 +91,10 @@ make_reader(const Filename &filename, PNMFileType *type) const {
|
|||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PNMImageHeader::make_reader
|
||||
// Access: Public, Static
|
||||
// Description: Returns a PNMReader of the suitable type for reading
|
||||
// from the already-opened image file, or NULL if the
|
||||
// file cannot be read for some reason.
|
||||
// Access: Public
|
||||
// Description: Returns a newly-allocated PNMReader of the suitable
|
||||
// type for reading from the already-opened image file,
|
||||
// or NULL if the file cannot be read for some reason.
|
||||
//
|
||||
// owns_file should be set true if the PNMReader is to
|
||||
// be considered the owner of the FILE stream (in which
|
||||
|
|
@ -110,6 +114,9 @@ make_reader(const Filename &filename, PNMFileType *type) const {
|
|||
//
|
||||
// If type is non-NULL, it is a suggestion for the file
|
||||
// type to use.
|
||||
//
|
||||
// The PNMReader should be deleted when it is no longer
|
||||
// needed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PNMReader *PNMImageHeader::
|
||||
make_reader(FILE *file, bool owns_file, const Filename &filename,
|
||||
|
|
@ -199,13 +206,16 @@ make_reader(FILE *file, bool owns_file, const Filename &filename,
|
|||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PNMImageHeader::make_writer
|
||||
// Access: Public, Static
|
||||
// Description: Returns a PNMWriter of the suitable type for writing
|
||||
// an image to the indicated filename, or NULL if the
|
||||
// filename cannot be written for some reason. The
|
||||
// filename "-" always stands for standard output. If
|
||||
// type is specified, it is a suggestion for the file
|
||||
// type to use.
|
||||
// Access: Public
|
||||
// Description: Returns a newly-allocated PNMWriter of the suitable
|
||||
// type for writing an image to the indicated filename,
|
||||
// or NULL if the filename cannot be written for some
|
||||
// reason. The filename "-" always stands for standard
|
||||
// output. If type is specified, it is a suggestion for
|
||||
// the file type to use.
|
||||
//
|
||||
// The PNMWriter should be deleted when it is no longer
|
||||
// needed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PNMWriter *PNMImageHeader::
|
||||
make_writer(const Filename &filename, PNMFileType *type) const {
|
||||
|
|
@ -244,10 +254,10 @@ make_writer(const Filename &filename, PNMFileType *type) const {
|
|||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PNMImageHeader::make_writer
|
||||
// Access: Public, Static
|
||||
// Description: Returns a PNMWriter of the suitable type for writing
|
||||
// to the already-opened image file, or NULL if the
|
||||
// file cannot be written for some reason.
|
||||
// Access: Public
|
||||
// Description: Returns a newly-allocated PNMWriter of the suitable
|
||||
// type for writing to the already-opened image file, or
|
||||
// NULL if the file cannot be written for some reason.
|
||||
//
|
||||
// owns_file should be set true if the PNMWriter is to
|
||||
// be considered the owner of the FILE stream (in which
|
||||
|
|
@ -262,6 +272,9 @@ make_writer(const Filename &filename, PNMFileType *type) const {
|
|||
//
|
||||
// If type is non-NULL, it is a suggestion for the file
|
||||
// type to use.
|
||||
//
|
||||
// The PNMWriter should be deleted when it is no longer
|
||||
// needed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PNMWriter *PNMImageHeader::
|
||||
make_writer(FILE *file, bool owns_file, const Filename &filename,
|
||||
|
|
@ -325,7 +338,7 @@ make_writer(FILE *file, bool owns_file, const Filename &filename,
|
|||
////////////////////////////////////////////////////////////////////
|
||||
bool PNMImageHeader::
|
||||
read_magic_number(FILE *file, string &magic_number, int num_bytes) {
|
||||
while (magic_number.size() < num_bytes) {
|
||||
while ((int)magic_number.size() < num_bytes) {
|
||||
int ch = getc(file);
|
||||
if (ch == EOF) {
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@
|
|||
INLINE PNMReader::
|
||||
PNMReader(PNMFileType *type, FILE *file, bool owns_file) :
|
||||
_type(type),
|
||||
_file(file),
|
||||
_owns_file(owns_file),
|
||||
_file(file),
|
||||
_is_valid(true)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@
|
|||
INLINE PNMWriter::
|
||||
PNMWriter(PNMFileType *type, FILE *file, bool owns_file) :
|
||||
_type(type),
|
||||
_file(file),
|
||||
_owns_file(owns_file)
|
||||
_owns_file(owns_file),
|
||||
_file(file)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,19 +6,6 @@
|
|||
//
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 1992,93,94,95 Walt Disney Imagineering, Inc.
|
||||
//
|
||||
// These coded instructions, statements, data structures and
|
||||
// computer programs contain unpublished proprietary information of
|
||||
// Walt Disney Imagineering and are protected by Federal copyright
|
||||
// law. They may not be disclosed to third parties or copied or
|
||||
// duplicated in any form, in whole or in part, without the prior
|
||||
// written consent of Walt Disney Imagineering Inc.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// RCSID:
|
||||
// $Header$
|
||||
//
|
||||
|
||||
#ifndef _PNMMINMAX_H_
|
||||
#define _PNMMINMAX_H_
|
||||
|
|
|
|||
|
|
@ -74,3 +74,42 @@ clear_switches(void) {
|
|||
_lod._switch_vector.erase(_lod._switch_vector.begin(),
|
||||
_lod._switch_vector.end());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: LODNode::get_num_switches
|
||||
// Access: Public
|
||||
// Description: Returns the number of switch ranges added to the
|
||||
// LODNode. This should correspond to the number of
|
||||
// children of the node in order for the LODNode to
|
||||
// function correctly.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int LODNode::
|
||||
get_num_switches() const {
|
||||
return _lod._switch_vector.size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: LODNode::get_in
|
||||
// Access: Public
|
||||
// Description: Returns the "in" distance of the indicated switch
|
||||
// range. This should be larger than the "out" distance
|
||||
// of the same range.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE float LODNode::
|
||||
get_in(int index) const {
|
||||
nassertr(index >= 0 && index < (int)_lod._switch_vector.size(), 0.0);
|
||||
return _lod._switch_vector[index].get_in();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: LODNode::get_out
|
||||
// Access: Public
|
||||
// Description: Returns the "out" distance of the indicated switch
|
||||
// range. This should be smaller than the "in" distance
|
||||
// of the same range.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE float LODNode::
|
||||
get_out(int index) const {
|
||||
nassertr(index >= 0 && index < (int)_lod._switch_vector.size(), 0.0);
|
||||
return _lod._switch_vector[index].get_out();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,6 +50,18 @@ xform(const LMatrix4f &mat) {
|
|||
_lod.xform(mat);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: LODNode::output
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void LODNode::
|
||||
output(ostream &out) const {
|
||||
NamedNode::output(out);
|
||||
out << " ";
|
||||
_lod.output(out);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: sub_render
|
||||
// Access:
|
||||
|
|
|
|||
|
|
@ -39,6 +39,12 @@ public:
|
|||
INLINE bool set_switch(int index, float in, float out);
|
||||
INLINE void clear_switches(void);
|
||||
|
||||
INLINE int get_num_switches() const;
|
||||
INLINE float get_in(int index) const;
|
||||
INLINE float get_out(int index) const;
|
||||
|
||||
virtual void output(ostream &out) const;
|
||||
|
||||
virtual bool sub_render(const AllAttributesWrapper &attrib,
|
||||
AllTransitionsWrapper &trans,
|
||||
GraphicsStateGuardianBase *gsgbase);
|
||||
|
|
|
|||
Loading…
Reference in New Issue