mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-02 18:03:56 -04:00
support writing png images
This commit is contained in:
parent
d49685c9a9
commit
a2772d745a
@ -24,7 +24,6 @@
|
|||||||
|
|
||||||
#include "pnmFileTypeRegistry.h"
|
#include "pnmFileTypeRegistry.h"
|
||||||
#include "bamReader.h"
|
#include "bamReader.h"
|
||||||
#include "ppmcmap.h"
|
|
||||||
|
|
||||||
static const char * const extensions_png[] = {
|
static const char * const extensions_png[] = {
|
||||||
"png"
|
"png"
|
||||||
@ -33,6 +32,21 @@ static const int num_extensions_png = sizeof(extensions_png) / sizeof(const char
|
|||||||
|
|
||||||
TypeHandle PNMFileTypePNG::_type_handle;
|
TypeHandle PNMFileTypePNG::_type_handle;
|
||||||
|
|
||||||
|
static const int png_max_palette = 256;
|
||||||
|
|
||||||
|
// This STL comparison functor is used in write_data(), below. It
|
||||||
|
// sorts the non-maxval alpha pixels to the front of the list.
|
||||||
|
class LowAlphaCompare {
|
||||||
|
public:
|
||||||
|
bool operator() (const PNMImageHeader::PixelSpec &a,
|
||||||
|
const PNMImageHeader::PixelSpec &b) {
|
||||||
|
if (a._alpha != b._alpha) {
|
||||||
|
return a._alpha < b._alpha;
|
||||||
|
}
|
||||||
|
return a < b;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: PNMFileTypePNG::Constructor
|
// Function: PNMFileTypePNG::Constructor
|
||||||
// Access: Public
|
// Access: Public
|
||||||
@ -126,6 +140,7 @@ matches_magic_number(const string &magic_number) const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
PNMReader *PNMFileTypePNG::
|
PNMReader *PNMFileTypePNG::
|
||||||
make_reader(istream *file, bool owns_file, const string &magic_number) {
|
make_reader(istream *file, bool owns_file, const string &magic_number) {
|
||||||
|
init_pnm();
|
||||||
return new Reader(this, file, owns_file, magic_number);
|
return new Reader(this, file, owns_file, magic_number);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,8 +153,8 @@ make_reader(istream *file, bool owns_file, const string &magic_number) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
PNMWriter *PNMFileTypePNG::
|
PNMWriter *PNMFileTypePNG::
|
||||||
make_writer(ostream *file, bool owns_file) {
|
make_writer(ostream *file, bool owns_file) {
|
||||||
// return new Writer(this, file, owns_file);
|
init_pnm();
|
||||||
return NULL;
|
return new Writer(this, file, owns_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -358,18 +373,18 @@ read_data(xel *array, xelval *alpha_data) {
|
|||||||
|
|
||||||
if (_maxval > 255) {
|
if (_maxval > 255) {
|
||||||
if (get_color) {
|
if (get_color) {
|
||||||
red = (source[0] << 16) | source[1];
|
red = (source[0] << 8) | source[1];
|
||||||
source += 2;
|
source += 2;
|
||||||
|
|
||||||
green = (source[0] << 16) | source[1];
|
green = (source[0] << 8) | source[1];
|
||||||
source += 2;
|
source += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
blue = (source[0] << 16) | source[1];
|
blue = (source[0] << 8) | source[1];
|
||||||
source += 2;
|
source += 2;
|
||||||
|
|
||||||
if (get_alpha) {
|
if (get_alpha) {
|
||||||
alpha = (source[0] << 16) | source[1];
|
alpha = (source[0] << 8) | source[1];
|
||||||
source += 2;
|
source += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -477,5 +492,407 @@ png_error(png_structp png_ptr, png_const_charp error_msg) {
|
|||||||
longjmp(self->_jmpbuf, true);
|
longjmp(self->_jmpbuf, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PNMFileTypePNG::Writer::Constructor
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
PNMFileTypePNG::Writer::
|
||||||
|
Writer(PNMFileType *type, ostream *file, bool owns_file) :
|
||||||
|
PNMWriter(type, file, owns_file)
|
||||||
|
{
|
||||||
|
_png = NULL;
|
||||||
|
_info = NULL;
|
||||||
|
_is_valid = false;
|
||||||
|
|
||||||
|
_png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,
|
||||||
|
png_error, png_warning);
|
||||||
|
if (_png == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_info = png_create_info_struct(_png);
|
||||||
|
if (_info == NULL) {
|
||||||
|
png_destroy_write_struct(&_png, NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_is_valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PNMFileTypePNG::Writer::Destructor
|
||||||
|
// Access: Public, Virtual
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
PNMFileTypePNG::Writer::
|
||||||
|
~Writer() {
|
||||||
|
free_png();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PNMFileTypePNG::Writer::write_data
|
||||||
|
// Access: Public, Virtual
|
||||||
|
// Description: Writes in an entire image all at once, storing it in
|
||||||
|
// the pre-allocated _x_size * _y_size array and alpha
|
||||||
|
// pointers. (If the image type has no alpha channel,
|
||||||
|
// alpha is ignored.) Returns the number of rows
|
||||||
|
// correctly write.
|
||||||
|
//
|
||||||
|
// Derived classes need not override this if they
|
||||||
|
// instead provide supports_write_row() and write_row(),
|
||||||
|
// below.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
int PNMFileTypePNG::Writer::
|
||||||
|
write_data(xel *array, xelval *alpha_data) {
|
||||||
|
if (!is_valid()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setjmp(_jmpbuf)) {
|
||||||
|
// This is the ANSI C way to handle exceptions. If setjmp(),
|
||||||
|
// above, returns true, it means that libpng detected an exception
|
||||||
|
// while executing the code that writes the image, below.
|
||||||
|
free_png();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
png_set_write_fn(_png, (void *)this, png_write_data, png_flush_data);
|
||||||
|
|
||||||
|
// First, write the header.
|
||||||
|
|
||||||
|
int true_bit_depth = pm_maxvaltobits(_maxval);
|
||||||
|
int png_bit_depth = make_png_bit_depth(true_bit_depth);
|
||||||
|
|
||||||
|
png_color_8 sig_bit;
|
||||||
|
sig_bit.red = true_bit_depth;
|
||||||
|
sig_bit.green = true_bit_depth;
|
||||||
|
sig_bit.blue = true_bit_depth;
|
||||||
|
sig_bit.gray = true_bit_depth;
|
||||||
|
sig_bit.alpha = true_bit_depth;
|
||||||
|
|
||||||
|
int color_type = 0;
|
||||||
|
|
||||||
|
if (!is_grayscale()) {
|
||||||
|
color_type |= PNG_COLOR_MASK_COLOR;
|
||||||
|
}
|
||||||
|
if (has_alpha()) {
|
||||||
|
color_type |= PNG_COLOR_MASK_ALPHA;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine if we should make a palettized image out of this. In
|
||||||
|
// order for this to be possible and effective, we must have no more
|
||||||
|
// than 256 unique color/alpha combinations for a color image, and
|
||||||
|
// the resulting bitdepth should be smaller than what we would have
|
||||||
|
// otherwise.
|
||||||
|
Palette palette;
|
||||||
|
Histogram palette_lookup;
|
||||||
|
png_color png_palette[png_max_palette];
|
||||||
|
png_byte png_trans[png_max_palette];
|
||||||
|
|
||||||
|
if (png_bit_depth <= 8) {
|
||||||
|
if (compute_palette(palette, array, alpha_data, png_max_palette)) {
|
||||||
|
pnmimage_png_cat.debug()
|
||||||
|
<< palette.size() << " colors found.\n";
|
||||||
|
|
||||||
|
int palette_bit_depth = make_png_bit_depth(pm_maxvaltobits(palette.size() - 1));
|
||||||
|
|
||||||
|
int total_bits = png_bit_depth;
|
||||||
|
if (!is_grayscale()) {
|
||||||
|
total_bits *= 3;
|
||||||
|
}
|
||||||
|
if (has_alpha()) {
|
||||||
|
total_bits += png_bit_depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (palette_bit_depth < total_bits) {
|
||||||
|
pnmimage_png_cat.debug()
|
||||||
|
<< "palette bit depth of " << palette_bit_depth
|
||||||
|
<< " improves on bit depth of " << total_bits
|
||||||
|
<< "; making a palette image.\n";
|
||||||
|
|
||||||
|
color_type = PNG_COLOR_TYPE_PALETTE;
|
||||||
|
|
||||||
|
// Re-sort the palette to put the semitransparent pixels at the
|
||||||
|
// beginning.
|
||||||
|
sort(palette.begin(), palette.end(), LowAlphaCompare());
|
||||||
|
|
||||||
|
int num_alpha = 0;
|
||||||
|
for (int i = 0; i < (int)palette.size(); i++) {
|
||||||
|
png_palette[i].red = palette[i]._red;
|
||||||
|
png_palette[i].green = palette[i]._green;
|
||||||
|
png_palette[i].blue = palette[i]._blue;
|
||||||
|
png_trans[i] = palette[i]._alpha;
|
||||||
|
if (palette[i]._alpha != _maxval) {
|
||||||
|
num_alpha = i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also build a reverse-lookup from color to palette index in
|
||||||
|
// the "histogram" structure.
|
||||||
|
palette_lookup[palette[i]] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
png_set_PLTE(_png, _info, png_palette, palette.size());
|
||||||
|
if (has_alpha()) {
|
||||||
|
pnmimage_png_cat.debug()
|
||||||
|
<< "palette contains " << num_alpha << " transparent entries.\n";
|
||||||
|
png_set_tRNS(_png, _info, png_trans, num_alpha, NULL);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pnmimage_png_cat.debug()
|
||||||
|
<< "palette bit depth of " << palette_bit_depth
|
||||||
|
<< " does not improve on bit depth of " << total_bits
|
||||||
|
<< "; not making a palette image.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
pnmimage_png_cat.debug()
|
||||||
|
<< "more than " << png_max_palette
|
||||||
|
<< " colors found; not making a palette image.\n";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pnmimage_png_cat.debug()
|
||||||
|
<< "maxval exceeds 255; not making a palette image.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pnmimage_png_cat.debug()
|
||||||
|
<< "width = " << _x_size << " height = " << _y_size
|
||||||
|
<< " maxval = " << _maxval << " bit_depth = "
|
||||||
|
<< png_bit_depth << " color_type = " << color_type << "\n";
|
||||||
|
|
||||||
|
png_set_IHDR(_png, _info, _x_size, _y_size, png_bit_depth,
|
||||||
|
color_type, PNG_INTERLACE_NONE,
|
||||||
|
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
||||||
|
|
||||||
|
// Set the true bit depth of the image data.
|
||||||
|
if (png_bit_depth != true_bit_depth || color_type == PNG_COLOR_TYPE_PALETTE) {
|
||||||
|
png_set_sBIT(_png, _info, &sig_bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
png_write_info(_png, _info);
|
||||||
|
|
||||||
|
|
||||||
|
// Now set up the transformations to write the image data.
|
||||||
|
if (png_bit_depth < 8) {
|
||||||
|
png_set_packing(_png);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (png_bit_depth != true_bit_depth && color_type != PNG_COLOR_TYPE_PALETTE) {
|
||||||
|
// This does assume that _maxval is one less than a power of 2.
|
||||||
|
// If it is not, the PNG image will be written as if it were the
|
||||||
|
// next-higher power of 2, darkening the image.
|
||||||
|
png_set_shift(_png, &sig_bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
int row_byte_length = _x_size * _num_channels;
|
||||||
|
if (png_bit_depth > 8) {
|
||||||
|
row_byte_length *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int num_rows = _y_size;
|
||||||
|
|
||||||
|
if (pnmimage_png_cat.is_debug()) {
|
||||||
|
pnmimage_png_cat.debug()
|
||||||
|
<< "Allocating one row of " << row_byte_length
|
||||||
|
<< " bytes.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// When writing, we only need to copy the image out one row at a
|
||||||
|
// time, because we don't mess around with writing interlaced files.
|
||||||
|
// If we were writing an interlaced file, we'd have to copy the
|
||||||
|
// whole image first.
|
||||||
|
|
||||||
|
png_bytep row = new png_byte[row_byte_length];
|
||||||
|
|
||||||
|
bool save_color = !is_grayscale();
|
||||||
|
bool save_alpha = has_alpha();
|
||||||
|
|
||||||
|
int pi = 0;
|
||||||
|
for (int yi = 0; yi < num_rows; yi++) {
|
||||||
|
png_bytep dest = row;
|
||||||
|
|
||||||
|
if (color_type == PNG_COLOR_TYPE_PALETTE) {
|
||||||
|
for (int xi = 0; xi < _x_size; xi++) {
|
||||||
|
int index;
|
||||||
|
|
||||||
|
if (save_color) {
|
||||||
|
if (save_alpha) {
|
||||||
|
index = palette_lookup[PixelSpec(PPM_GETR(array[pi]), PPM_GETG(array[pi]), PPM_GETB(array[pi]), alpha_data[pi])];
|
||||||
|
} else {
|
||||||
|
index = palette_lookup[PixelSpec(PPM_GETR(array[pi]), PPM_GETG(array[pi]), PPM_GETB(array[pi]))];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (save_alpha) {
|
||||||
|
index = palette_lookup[PixelSpec(PPM_GETB(array[pi]), alpha_data[pi])];
|
||||||
|
} else {
|
||||||
|
index = palette_lookup[PixelSpec(PPM_GETB(array[pi]))];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*dest++ = index;
|
||||||
|
pi++;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (png_bit_depth > 255) {
|
||||||
|
for (int xi = 0; xi < _x_size; xi++) {
|
||||||
|
if (save_color) {
|
||||||
|
xelval red = PPM_GETR(array[pi]);
|
||||||
|
*dest++ = (red >> 8) & 0xff;
|
||||||
|
*dest++ = red & 0xff;
|
||||||
|
xelval green = PPM_GETG(array[pi]);
|
||||||
|
*dest++ = (green >> 8) & 0xff;
|
||||||
|
*dest++ = green & 0xff;
|
||||||
|
}
|
||||||
|
xelval blue = PPM_GETB(array[pi]);
|
||||||
|
*dest++ = (blue >> 8) & 0xff;
|
||||||
|
*dest++ = blue & 0xff;
|
||||||
|
|
||||||
|
if (save_alpha) {
|
||||||
|
xelval alpha = alpha_data[pi];
|
||||||
|
*dest++ = (alpha >> 8) & 0xff;
|
||||||
|
*dest++ = alpha & 0xff;
|
||||||
|
}
|
||||||
|
pi++;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
for (int xi = 0; xi < _x_size; xi++) {
|
||||||
|
if (save_color) {
|
||||||
|
*dest++ = PPM_GETR(array[pi]);
|
||||||
|
*dest++ = PPM_GETG(array[pi]);
|
||||||
|
}
|
||||||
|
|
||||||
|
*dest++ = PPM_GETB(array[pi]);
|
||||||
|
|
||||||
|
if (save_alpha) {
|
||||||
|
*dest++ = alpha_data[pi];
|
||||||
|
}
|
||||||
|
pi++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nassertr(dest <= row + row_byte_length, yi);
|
||||||
|
png_write_row(_png, row);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] row;
|
||||||
|
|
||||||
|
png_write_end(_png, NULL);
|
||||||
|
|
||||||
|
return _y_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PNMFileTypePNG::Writer::free_png
|
||||||
|
// Access: Private
|
||||||
|
// Description: Releases the internal PNG structures and marks the
|
||||||
|
// writer invalid.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void PNMFileTypePNG::Writer::
|
||||||
|
free_png() {
|
||||||
|
if (_is_valid) {
|
||||||
|
png_destroy_write_struct(&_png, &_info);
|
||||||
|
_is_valid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PNMFileTypePNG::Writer::make_png_bit_depth
|
||||||
|
// Access: Private, Static
|
||||||
|
// Description: Elevates the indicated bit depth to one of the legal
|
||||||
|
// PNG bit depths: 1, 2, 4, 8, or 16.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
int PNMFileTypePNG::Writer::
|
||||||
|
make_png_bit_depth(int bit_depth) {
|
||||||
|
switch (bit_depth) {
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
case 4:
|
||||||
|
return 4;
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
case 6:
|
||||||
|
case 7:
|
||||||
|
case 8:
|
||||||
|
return 8;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PNMFileTypePNG::Writer::png_write_data
|
||||||
|
// Access: Private, Static
|
||||||
|
// Description: A callback handler that PNG uses to write data from
|
||||||
|
// the iostream.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void PNMFileTypePNG::Writer::
|
||||||
|
png_write_data(png_structp png_ptr, png_bytep data, png_size_t length) {
|
||||||
|
Writer *self = (Writer *)png_get_io_ptr(png_ptr);
|
||||||
|
self->_file->write((char *)data, length);
|
||||||
|
if (self->_file->fail()) {
|
||||||
|
pnmimage_png_cat.error()
|
||||||
|
<< "Unable to write to the iostream.\n";
|
||||||
|
// Is there no way to indicate a write failure to libpng?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PNMFileTypePNG::Writer::png_flush_data
|
||||||
|
// Access: Private, Static
|
||||||
|
// Description: A callback handler that PNG uses to write data from
|
||||||
|
// the iostream.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void PNMFileTypePNG::Writer::
|
||||||
|
png_flush_data(png_structp png_ptr) {
|
||||||
|
Writer *self = (Writer *)png_get_io_ptr(png_ptr);
|
||||||
|
self->_file->flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PNMFileTypePNG::Writer::png_warning
|
||||||
|
// Access: Private, Static
|
||||||
|
// Description: This is our own warning handler. It is called by the
|
||||||
|
// png library to issue a warning message.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void PNMFileTypePNG::Writer::
|
||||||
|
png_warning(png_structp, png_const_charp warning_msg) {
|
||||||
|
pnmimage_png_cat.warning()
|
||||||
|
<< warning_msg << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PNMFileTypePNG::Writer::png_error
|
||||||
|
// Access: Private, Static
|
||||||
|
// Description: This is our own error handler. It is called by the
|
||||||
|
// png library to issue a fatal error message.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void PNMFileTypePNG::Writer::
|
||||||
|
png_error(png_structp png_ptr, png_const_charp error_msg) {
|
||||||
|
pnmimage_png_cat.error()
|
||||||
|
<< error_msg << "\n";
|
||||||
|
|
||||||
|
// The PNG library insists we should not return, so instead of
|
||||||
|
// returning, we will do a longjmp out of the png code.
|
||||||
|
Writer *self = (Writer *)png_get_io_ptr(png_ptr);
|
||||||
|
if (self == (Writer *)NULL) {
|
||||||
|
// Oops, we haven't got a self pointer yet. Return anyway and
|
||||||
|
// hope we'll be ok.
|
||||||
|
pnmimage_png_cat.error()
|
||||||
|
<< "Returning before opening file.\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
longjmp(self->_jmpbuf, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif // HAVE_PNG
|
#endif // HAVE_PNG
|
||||||
|
@ -75,19 +75,31 @@ public:
|
|||||||
jmp_buf _jmpbuf;
|
jmp_buf _jmpbuf;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
class Writer : public PNMWriter {
|
class Writer : public PNMWriter {
|
||||||
public:
|
public:
|
||||||
Writer(PNMFileType *type, ostream *file, bool owns_file);
|
Writer(PNMFileType *type, ostream *file, bool owns_file);
|
||||||
|
virtual ~Writer();
|
||||||
|
|
||||||
virtual int write_data(xel *array, xelval *alpha);
|
virtual int write_data(xel *array, xelval *alpha);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void free_png();
|
||||||
|
static int make_png_bit_depth(int bit_depth);
|
||||||
static void png_write_data(png_structp png_ptr, png_bytep data,
|
static void png_write_data(png_structp png_ptr, png_bytep data,
|
||||||
png_size_t length);
|
png_size_t length);
|
||||||
static void png_flush_data(png_structp png_ptr);
|
static void png_flush_data(png_structp png_ptr);
|
||||||
|
|
||||||
|
static void png_error(png_structp png_ptr, png_const_charp error_msg);
|
||||||
|
static void png_warning(png_structp png_ptr, png_const_charp warning_msg);
|
||||||
|
|
||||||
|
png_structp _png;
|
||||||
|
png_infop _info;
|
||||||
|
|
||||||
|
// We need a jmp_buf to support libpng's fatal error handling, in
|
||||||
|
// which the error handler must not immediately leave libpng code,
|
||||||
|
// but must return to the caller in Panda.
|
||||||
|
jmp_buf _jmpbuf;
|
||||||
};
|
};
|
||||||
*/
|
|
||||||
|
|
||||||
// The TypedWritable interface follows.
|
// The TypedWritable interface follows.
|
||||||
public:
|
public:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user