Updated image readers.
Removed duplicate code from Fl_JPEG_Image, updated and unified Doxygen comments. Avoiding name conflict in new protected functions.
This commit is contained in:
parent
82d279c234
commit
7e0c82637d
@ -36,7 +36,7 @@ class FL_EXPORT Fl_BMP_Image : public Fl_RGB_Image {
|
||||
|
||||
protected:
|
||||
|
||||
void read(class BMPReader &rdr);
|
||||
void load_bmp_(class BMPReader &rdr);
|
||||
|
||||
};
|
||||
|
||||
|
@ -37,7 +37,7 @@ public:
|
||||
|
||||
protected:
|
||||
|
||||
void read(class GIFReader &rdr);
|
||||
void load_gif_(class GIFReader &rdr);
|
||||
|
||||
};
|
||||
|
||||
|
@ -35,6 +35,11 @@ public:
|
||||
|
||||
Fl_JPEG_Image(const char *filename);
|
||||
Fl_JPEG_Image(const char *name, const unsigned char *data);
|
||||
|
||||
protected:
|
||||
|
||||
void load_jpg_(const char *filename, const char *sharename, const unsigned char *data);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -48,24 +48,35 @@
|
||||
// Local reader class...
|
||||
//
|
||||
|
||||
/*
|
||||
This class reads data chunks from a file or from memory in LSB-first
|
||||
byte order.
|
||||
|
||||
TODO: GIFReader and BMPReader are very similar and should be combined to avoid
|
||||
code duplication.
|
||||
*/
|
||||
class BMPReader
|
||||
{
|
||||
public:
|
||||
// Create the reader.
|
||||
BMPReader() :
|
||||
pIsFile(0), pIsData(0),
|
||||
pFile(0L), pData(0L), pStart(0L),
|
||||
pName(0L)
|
||||
{ }
|
||||
// Initialize the reader to access the file system, filename is copied
|
||||
// and stored.
|
||||
int open(const char *filename) {
|
||||
if (filename)
|
||||
pName = strdup(filename);
|
||||
if ((pFile = fl_fopen(filename, "rb")) == NULL) {
|
||||
if (!filename)
|
||||
return -1;
|
||||
pName = strdup(filename);
|
||||
if ( (pFile = fl_fopen(filename, "rb")) == NULL ) {
|
||||
return -1;
|
||||
} else {
|
||||
pIsFile = 1;
|
||||
return 0;
|
||||
}
|
||||
pIsFile = 1;
|
||||
return 0;
|
||||
}
|
||||
// Initialize the reader for memory access, name is copied and stored
|
||||
int open(const char *imagename, const unsigned char *data) {
|
||||
if (imagename)
|
||||
pName = strdup(imagename);
|
||||
@ -77,6 +88,7 @@ public:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
// Close and destroy the reader
|
||||
~BMPReader() {
|
||||
if (pIsFile && pFile) {
|
||||
fclose(pFile);
|
||||
@ -84,6 +96,7 @@ public:
|
||||
if (pName)
|
||||
::free(pName);
|
||||
}
|
||||
// Read a single byte form memory or a file
|
||||
uchar read_byte() {
|
||||
if (pIsFile) {
|
||||
return getc(pFile);
|
||||
@ -93,7 +106,7 @@ public:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// 'read_word()' - Read a 16-bit unsigned integer.
|
||||
// Read a 16-bit unsigned integer, LSB-first
|
||||
unsigned short read_word() {
|
||||
unsigned char b0, b1; // Bytes from file
|
||||
if (pIsFile) {
|
||||
@ -108,7 +121,7 @@ public:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// 'read_dword()' - Read a 32-bit unsigned integer.
|
||||
// Read a 32-bit unsigned integer, LSB-first
|
||||
unsigned int read_dword() {
|
||||
unsigned char b0, b1, b2, b3; // Bytes from file
|
||||
if (pIsFile) {
|
||||
@ -127,10 +140,12 @@ public:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// 'read_long()' - Read a 32-bit signed integer.
|
||||
// Read a 32-bit signed integer, LSB-first
|
||||
int read_long() {
|
||||
return (int)read_dword();
|
||||
};
|
||||
// Move the current read position to a byte offset fro the beginning of the
|
||||
// file or the original start address in memory
|
||||
void seek(unsigned int n) {
|
||||
if (pIsFile) {
|
||||
fseek(pFile, n , SEEK_SET);
|
||||
@ -138,19 +153,26 @@ public:
|
||||
pData = pStart + n;
|
||||
}
|
||||
}
|
||||
// return the name or filename for this reader
|
||||
const char *name() { return pName; }
|
||||
private:
|
||||
// open() sets this if we read form a file
|
||||
char pIsFile;
|
||||
// open() sets this if we read form memory
|
||||
char pIsData;
|
||||
// a pointer to the opened file
|
||||
FILE *pFile;
|
||||
// a pointer to the current byte in memory
|
||||
const unsigned char *pData;
|
||||
// a pointer to the start of the image data
|
||||
const unsigned char *pStart;
|
||||
// a copy of the name associated with this reader
|
||||
char *pName;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
The constructor loads the named BMP image from the given bmp filename.
|
||||
\brief The constructor loads the named BMP image from the given bmp filename.
|
||||
|
||||
The destructor frees all memory and server resources that are used by
|
||||
the image.
|
||||
@ -159,39 +181,58 @@ private:
|
||||
ERR_FILE_ACCESS if the file could not be opened or read, ERR_FORMAT if the
|
||||
BMP format could not be decoded, and ERR_NO_IMAGE if the image could not
|
||||
be loaded for another reason.
|
||||
|
||||
\param[in] filename a full path and name pointing to a valid BMP file.
|
||||
|
||||
\see Fl_BMP_Image::Fl_BMP_Image(const char *imagename, const unsigned char *data)
|
||||
*/
|
||||
Fl_BMP_Image::Fl_BMP_Image(const char *filename) // I - File to read
|
||||
: Fl_RGB_Image(0,0,0)
|
||||
{
|
||||
BMPReader f;
|
||||
if (f.open(filename)==-1) {
|
||||
ld(ERR_FORMAT);
|
||||
ld(ERR_FILE_ACCESS);
|
||||
} else {
|
||||
read(f);
|
||||
load_bmp_(f);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
The constructor loads the named BMP image from the given memory address.
|
||||
\brief Read a BMP image from memory.
|
||||
|
||||
\param[in] imagename the name of the bitmap
|
||||
\param[in] data a pointer to the BMP data in memory. There is no checking for buffer overruns
|
||||
Construct an image from a block of memory inside the application. Fluid offers
|
||||
"binary Data" chunks as a great way to add image data into the C++ source code.
|
||||
imagename can be NULL. If a name is given, the image is added to the list of
|
||||
shared images and will be available by that name.
|
||||
|
||||
Use Fl_Image::fail() to check if Fl_BMP_Image failed to load. fail() returns
|
||||
ERR_FILE_ACCESS if the file could not be opened or read, ERR_FORMAT if the
|
||||
BMP format could not be decoded, and ERR_NO_IMAGE if the image could not
|
||||
be loaded for another reason.
|
||||
|
||||
\param[in] imagename A name given to this image or NULL
|
||||
\param[in] data Pointer to the start of the BMP image in memory. This code will not check for buffer overruns.
|
||||
|
||||
\see Fl_BMP_Image::Fl_BMP_Image(const char *filename)
|
||||
\see Fl_Shared_Image
|
||||
*/
|
||||
Fl_BMP_Image::Fl_BMP_Image(const char *imagename, const unsigned char *data)
|
||||
: Fl_RGB_Image(0,0,0)
|
||||
{
|
||||
BMPReader d;
|
||||
if (d.open(imagename, data)==-1) {
|
||||
ld(ERR_FORMAT);
|
||||
ld(ERR_FILE_ACCESS);
|
||||
} else {
|
||||
read(d);
|
||||
load_bmp_(d);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Fl_BMP_Image::read(class BMPReader &rdr)
|
||||
/*
|
||||
This method reads BMP image data and creates an RGB or RGBA image. The BMP
|
||||
format supports only 1 bit for alpha. To avoid code duplication, we use
|
||||
a BMPReader that reads data from either a file or from memory.
|
||||
*/
|
||||
void Fl_BMP_Image::load_bmp_(class BMPReader &rdr)
|
||||
{
|
||||
int info_size, // Size of info header
|
||||
depth, // Depth of image (bits)
|
||||
|
@ -81,35 +81,47 @@ typedef unsigned char uchar;
|
||||
// Local reader class...
|
||||
//
|
||||
|
||||
/*
|
||||
This class reads data chunks from a file or from memory in LSB-first
|
||||
byte order.
|
||||
|
||||
TODO: GIFReader and BMPReader are very similar and should be combined to avoid
|
||||
code duplication.
|
||||
*/
|
||||
class GIFReader
|
||||
{
|
||||
public:
|
||||
// Create the reader.
|
||||
GIFReader() :
|
||||
pIsFile(0), pIsData(0),
|
||||
pFile(0L), pData(0L), pStart(0L),
|
||||
pFile(0L), pData(0L),
|
||||
pName(0L)
|
||||
{ }
|
||||
// Initialize the reader to access the file system, filename is copied
|
||||
// and stored.
|
||||
int open(const char *filename) {
|
||||
if (filename)
|
||||
pName = strdup(filename);
|
||||
if ((pFile = fl_fopen(filename, "rb")) == NULL) {
|
||||
if (!filename)
|
||||
return -1;
|
||||
pName = strdup(filename);
|
||||
if ( (pFile = fl_fopen(filename, "rb")) == NULL ) {
|
||||
return -1;
|
||||
} else {
|
||||
pIsFile = 1;
|
||||
return 0;
|
||||
}
|
||||
pIsFile = 1;
|
||||
return 0;
|
||||
}
|
||||
// Initialize the reader for memory access, name is copied and stored
|
||||
int open(const char *imagename, const unsigned char *data) {
|
||||
if (imagename)
|
||||
pName = strdup(imagename);
|
||||
if (data) {
|
||||
pStart = pData = data;
|
||||
pData = data;
|
||||
pIsData = 1;
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
// Close and destroy the reader
|
||||
~GIFReader() {
|
||||
if (pIsFile && pFile) {
|
||||
fclose(pFile);
|
||||
@ -117,6 +129,7 @@ public:
|
||||
if (pName)
|
||||
::free(pName);
|
||||
}
|
||||
// Read a single byte form memory or a file
|
||||
uchar read_byte() {
|
||||
if (pIsFile) {
|
||||
return getc(pFile);
|
||||
@ -126,7 +139,7 @@ public:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// 'read_word()' - Read a 16-bit unsigned integer.
|
||||
// Read a 16-bit unsigned integer, LSB-first
|
||||
unsigned short read_word() {
|
||||
unsigned char b0, b1; // Bytes from file
|
||||
if (pIsFile) {
|
||||
@ -141,19 +154,27 @@ public:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// return the name or filename for this reader
|
||||
const char *name() { return pName; }
|
||||
private:
|
||||
// open() sets this if we read form a file
|
||||
char pIsFile;
|
||||
// open() sets this if we read form memory
|
||||
char pIsData;
|
||||
// a pointer to the opened file
|
||||
FILE *pFile;
|
||||
// a pointer to the current byte in memory
|
||||
const unsigned char *pData;
|
||||
const unsigned char *pStart;
|
||||
// a copy of the name associated with this reader
|
||||
char *pName;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
The constructor loads the named GIF image.
|
||||
\brief The constructor loads the named GIF image.
|
||||
|
||||
IF a GIF is animated, Fl_GIF_Image will only read and display the first frame
|
||||
of the animation.
|
||||
|
||||
The destructor frees all memory and server resources that are used by
|
||||
the image.
|
||||
@ -162,6 +183,10 @@ private:
|
||||
ERR_FILE_ACCESS if the file could not be opened or read, ERR_FORMAT if the
|
||||
GIF format could not be decoded, and ERR_NO_IMAGE if the image could not
|
||||
be loaded for another reason.
|
||||
|
||||
\param[in] filename a full path and name pointing to a valid GIF file.
|
||||
|
||||
\see Fl_GIF_Image::Fl_GIF_Image(const char *imagename, const unsigned char *data)
|
||||
*/
|
||||
Fl_GIF_Image::Fl_GIF_Image(const char *filename) :
|
||||
Fl_Pixmap((char *const*)0)
|
||||
@ -171,32 +196,50 @@ Fl_GIF_Image::Fl_GIF_Image(const char *filename) :
|
||||
Fl::error("Fl_GIF_Image: Unable to open %s!", filename);
|
||||
ld(ERR_FILE_ACCESS);
|
||||
} else {
|
||||
read(f);
|
||||
load_gif_(f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
The constructor loads the named GIF image.
|
||||
\brief The constructor loads a GIF image from memory.
|
||||
|
||||
\param[in] imagename the name of the GIF image
|
||||
\param[in] data a pointer to the GIF data in memory. There is no checking for buffer overruns
|
||||
Construct an image from a block of memory inside the application. Fluid offers
|
||||
"binary Data" chunks as a great way to add image data into the C++ source code.
|
||||
imagename can be NULL. If a name is given, the image is added to the list of
|
||||
shared images and will be available by that name.
|
||||
|
||||
IF a GIF is animated, Fl_GIF_Image will only read and display the first frame
|
||||
of the animation.
|
||||
|
||||
Use Fl_Image::fail() to check if Fl_GIF_Image failed to load. fail() returns
|
||||
ERR_FILE_ACCESS if the file could not be opened or read, ERR_FORMAT if the
|
||||
GIF format could not be decoded, and ERR_NO_IMAGE if the image could not
|
||||
be loaded for another reason.
|
||||
|
||||
\param[in] imagename A name given to this image or NULL
|
||||
\param[in] data Pointer to the start of the GIF image in memory. This code will not check for buffer overruns.
|
||||
|
||||
\see Fl_GIF_Image::Fl_GIF_Image(const char *filename)
|
||||
\see Fl_Shared_Image
|
||||
*/
|
||||
Fl_GIF_Image::Fl_GIF_Image(const char *imagename, const unsigned char *data) :
|
||||
Fl_Pixmap((char *const*)0)
|
||||
{
|
||||
GIFReader d;
|
||||
if (d.open(imagename, data)==-1) {
|
||||
ld(ERR_FORMAT);
|
||||
ld(ERR_FILE_ACCESS);
|
||||
} else {
|
||||
read(d);
|
||||
load_gif_(d);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Fl_GIF_Image::read(GIFReader &rdr)
|
||||
/*
|
||||
This method reads GIF image data and creates an RGB or RGBA image. The GIF
|
||||
format supports only 1 bit for alpha. To avoid code duplication, we use
|
||||
a GIFReader that reads data from either a file or from memory.
|
||||
*/
|
||||
void Fl_GIF_Image::load_gif_(GIFReader &rdr)
|
||||
{
|
||||
char **new_data; // Data array
|
||||
|
||||
|
@ -95,107 +95,42 @@ extern "C" {
|
||||
w(), h(), and d() should return values greater than zero.
|
||||
|
||||
\param[in] filename a full path and name pointing to a valid jpeg file.
|
||||
|
||||
\see Fl_JPEG_Image::Fl_JPEG_Image(const char *imagename, const unsigned char *data)
|
||||
*/
|
||||
Fl_JPEG_Image::Fl_JPEG_Image(const char *filename) // I - File to load
|
||||
: Fl_RGB_Image(0,0,0) {
|
||||
#ifdef HAVE_LIBJPEG
|
||||
FILE *fp; // File pointer
|
||||
jpeg_decompress_struct dinfo; // Decompressor info
|
||||
fl_jpeg_error_mgr jerr; // Error handler info
|
||||
JSAMPROW row; // Sample row pointer
|
||||
|
||||
// the following variables are pointers allocating some private space that
|
||||
// is not reset by 'setjmp()'
|
||||
char* max_finish_decompress_err; // count errors and give up afer a while
|
||||
char* max_destroy_decompress_err; // to avoid recusion and deadlock
|
||||
|
||||
// Clear data...
|
||||
alloc_array = 0;
|
||||
array = (uchar *)0;
|
||||
|
||||
// Open the image file...
|
||||
if ((fp = fl_fopen(filename, "rb")) == NULL) {
|
||||
ld(ERR_FILE_ACCESS);
|
||||
return;
|
||||
}
|
||||
|
||||
// Setup the decompressor info and read the header...
|
||||
dinfo.err = jpeg_std_error((jpeg_error_mgr *)&jerr);
|
||||
jerr.pub_.error_exit = fl_jpeg_error_handler;
|
||||
jerr.pub_.output_message = fl_jpeg_output_handler;
|
||||
|
||||
// Setup error loop variables
|
||||
max_finish_decompress_err = (char*)malloc(1); // allocate space on the frame for error counters
|
||||
max_destroy_decompress_err = (char*)malloc(1); // otherwise, the variables are reset on the longjmp
|
||||
*max_finish_decompress_err=10;
|
||||
*max_destroy_decompress_err=10;
|
||||
|
||||
if (setjmp(jerr.errhand_))
|
||||
{
|
||||
// JPEG error handling...
|
||||
Fl::warning("JPEG file \"%s\" is too large or contains errors!\n", filename);
|
||||
// if any of the cleanup routines hits another error, we would end up
|
||||
// in a loop. So instead, we decrement max_err for some upper cleanup limit.
|
||||
if ( ((*max_finish_decompress_err)-- > 0) && array)
|
||||
jpeg_finish_decompress(&dinfo);
|
||||
if ( (*max_destroy_decompress_err)-- > 0)
|
||||
jpeg_destroy_decompress(&dinfo);
|
||||
|
||||
fclose(fp);
|
||||
|
||||
w(0);
|
||||
h(0);
|
||||
d(0);
|
||||
|
||||
if (array) {
|
||||
delete[] (uchar *)array;
|
||||
array = 0;
|
||||
alloc_array = 0;
|
||||
}
|
||||
|
||||
free(max_destroy_decompress_err);
|
||||
free(max_finish_decompress_err);
|
||||
|
||||
ld(ERR_FORMAT);
|
||||
return;
|
||||
}
|
||||
|
||||
jpeg_create_decompress(&dinfo);
|
||||
jpeg_stdio_src(&dinfo, fp);
|
||||
jpeg_read_header(&dinfo, TRUE);
|
||||
|
||||
dinfo.quantize_colors = (boolean)FALSE;
|
||||
dinfo.out_color_space = JCS_RGB;
|
||||
dinfo.out_color_components = 3;
|
||||
dinfo.output_components = 3;
|
||||
|
||||
jpeg_calc_output_dimensions(&dinfo);
|
||||
|
||||
w(dinfo.output_width);
|
||||
h(dinfo.output_height);
|
||||
d(dinfo.output_components);
|
||||
|
||||
if (((size_t)w()) * h() * d() > max_size() ) longjmp(jerr.errhand_, 1);
|
||||
array = new uchar[w() * h() * d()];
|
||||
alloc_array = 1;
|
||||
|
||||
jpeg_start_decompress(&dinfo);
|
||||
|
||||
while (dinfo.output_scanline < dinfo.output_height) {
|
||||
row = (JSAMPROW)(array +
|
||||
dinfo.output_scanline * dinfo.output_width *
|
||||
dinfo.output_components);
|
||||
jpeg_read_scanlines(&dinfo, &row, (JDIMENSION)1);
|
||||
}
|
||||
|
||||
jpeg_finish_decompress(&dinfo);
|
||||
jpeg_destroy_decompress(&dinfo);
|
||||
|
||||
free(max_destroy_decompress_err);
|
||||
free(max_finish_decompress_err);
|
||||
|
||||
fclose(fp);
|
||||
#endif // HAVE_LIBJPEG
|
||||
Fl_JPEG_Image::Fl_JPEG_Image(const char *filename)
|
||||
: Fl_RGB_Image(0,0,0)
|
||||
{
|
||||
load_jpg_(filename, 0L, 0L);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief The constructor loads the JPEG image from memory.
|
||||
|
||||
Construct an image from a block of memory inside the application. Fluid offers
|
||||
"binary Data" chunks as a great way to add image data into the C++ source code.
|
||||
name_png can be NULL. If a name is given, the image is added to the list of
|
||||
shared images (see: Fl_Shared_Image) and will be available by that name.
|
||||
|
||||
The inherited destructor frees all memory and server resources that are used
|
||||
by the image.
|
||||
|
||||
Use Fl_Image::fail() to check if Fl_JPEG_Image failed to load. fail() returns
|
||||
ERR_FILE_ACCESS if the file could not be opened or read, ERR_FORMAT if the
|
||||
JPEG format could not be decoded, and ERR_NO_IMAGE if the image could not
|
||||
be loaded for another reason. If the image has loaded correctly,
|
||||
w(), h(), and d() should return values greater than zero.
|
||||
|
||||
\param name A unique name or NULL
|
||||
\param data A pointer to the memory location of the JPEG image
|
||||
|
||||
\see Fl_JPEG_Image::Fl_JPEG_Image(const char *filename)
|
||||
\see Fl_Shared_Image
|
||||
*/
|
||||
Fl_JPEG_Image::Fl_JPEG_Image(const char *name, const unsigned char *data)
|
||||
: Fl_RGB_Image(0,0,0)
|
||||
{
|
||||
load_jpg_(0L, name, data);
|
||||
}
|
||||
|
||||
|
||||
@ -270,121 +205,136 @@ static void jpeg_mem_src(j_decompress_ptr cinfo, const unsigned char *data)
|
||||
#endif // HAVE_LIBJPEG
|
||||
|
||||
|
||||
/**
|
||||
\brief The constructor loads the JPEG image from memory.
|
||||
|
||||
Construct an image from a block of memory inside the application. Fluid offers
|
||||
"binary Data" chunks as a great way to add image data into the C++ source code.
|
||||
name_png can be NULL. If a name is given, the image is added to the list of
|
||||
shared images (see: Fl_Shared_Image) and will be available by that name.
|
||||
|
||||
The inherited destructor frees all memory and server resources that are used
|
||||
by the image.
|
||||
|
||||
Use Fl_Image::fail() to check if Fl_JPEG_Image failed to load. fail() returns
|
||||
ERR_FILE_ACCESS if the file could not be opened or read, ERR_FORMAT if the
|
||||
JPEG format could not be decoded, and ERR_NO_IMAGE if the image could not
|
||||
be loaded for another reason. If the image has loaded correctly,
|
||||
w(), h(), and d() should return values greater than zero.
|
||||
|
||||
\param name A unique name or NULL
|
||||
\param data A pointer to the memory location of the JPEG image
|
||||
/*
|
||||
This method reads JPEG image data and creates an RGB or grayscale image.
|
||||
To avoid code duplication, we set filename if we want to read form a file or
|
||||
data to read from memory instead. Sharename can be set if the image is
|
||||
supposed to be added to teh Fl_Shared_Image list.
|
||||
*/
|
||||
Fl_JPEG_Image::Fl_JPEG_Image(const char *name, const unsigned char *data)
|
||||
: Fl_RGB_Image(0,0,0) {
|
||||
void Fl_JPEG_Image::load_jpg_(const char *filename, const char *sharename, const unsigned char *data)
|
||||
{
|
||||
#ifdef HAVE_LIBJPEG
|
||||
jpeg_decompress_struct dinfo; // Decompressor info
|
||||
fl_jpeg_error_mgr jerr; // Error handler info
|
||||
JSAMPROW row; // Sample row pointer
|
||||
|
||||
FILE *fp = 0L; // File pointer
|
||||
jpeg_decompress_struct dinfo; // Decompressor info
|
||||
fl_jpeg_error_mgr jerr; // Error handler info
|
||||
JSAMPROW row; // Sample row pointer
|
||||
|
||||
// the following variables are pointers allocating some private space that
|
||||
// is not reset by 'setjmp()'
|
||||
char* max_finish_decompress_err; // count errors and give up afer a while
|
||||
char* max_destroy_decompress_err; // to avoid recusion and deadlock
|
||||
|
||||
|
||||
// Clear data...
|
||||
alloc_array = 0;
|
||||
array = (uchar *)0;
|
||||
|
||||
|
||||
// Open the image file if we read from the file system
|
||||
if (filename) {
|
||||
if ((fp = fl_fopen(filename, "rb")) == NULL) {
|
||||
ld(ERR_FILE_ACCESS);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (data==0L) {
|
||||
ld(ERR_FILE_ACCESS);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Setup the decompressor info and read the header...
|
||||
dinfo.err = jpeg_std_error((jpeg_error_mgr *)&jerr);
|
||||
jerr.pub_.error_exit = fl_jpeg_error_handler;
|
||||
jerr.pub_.output_message = fl_jpeg_output_handler;
|
||||
|
||||
|
||||
// Setup error loop variables
|
||||
max_finish_decompress_err = (char*)malloc(1); // allocate space on the frame for error counters
|
||||
max_destroy_decompress_err = (char*)malloc(1); // otherwise, the variables are reset on the longjmp
|
||||
*max_finish_decompress_err=10;
|
||||
*max_destroy_decompress_err=10;
|
||||
|
||||
|
||||
if (setjmp(jerr.errhand_))
|
||||
{
|
||||
// JPEG error handling...
|
||||
Fl::warning("JPEG data is too large or contains errors!\n");
|
||||
// if any of the cleanup routines hits another error, we would end up
|
||||
const char *name = "<unnamed>";
|
||||
if (filename) name = filename;
|
||||
else if (sharename) name = sharename;
|
||||
Fl::warning("JPEG file \"%s\" is too large or contains errors!\n", name);
|
||||
// if any of the cleanup routines hits another error, we would end up
|
||||
// in a loop. So instead, we decrement max_err for some upper cleanup limit.
|
||||
if ( ((*max_finish_decompress_err)-- > 0) && array)
|
||||
jpeg_finish_decompress(&dinfo);
|
||||
if ( (*max_destroy_decompress_err)-- > 0)
|
||||
jpeg_destroy_decompress(&dinfo);
|
||||
|
||||
|
||||
if (fp)
|
||||
fclose(fp);
|
||||
|
||||
w(0);
|
||||
h(0);
|
||||
d(0);
|
||||
|
||||
|
||||
if (array) {
|
||||
delete[] (uchar *)array;
|
||||
array = 0;
|
||||
alloc_array = 0;
|
||||
}
|
||||
|
||||
|
||||
free(max_destroy_decompress_err);
|
||||
free(max_finish_decompress_err);
|
||||
|
||||
|
||||
ld(ERR_FORMAT);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
jpeg_create_decompress(&dinfo);
|
||||
jpeg_mem_src(&dinfo, data);
|
||||
if (fp) {
|
||||
jpeg_stdio_src(&dinfo, fp);
|
||||
} else {
|
||||
jpeg_mem_src(&dinfo, data);
|
||||
}
|
||||
jpeg_read_header(&dinfo, TRUE);
|
||||
|
||||
|
||||
dinfo.quantize_colors = (boolean)FALSE;
|
||||
dinfo.out_color_space = JCS_RGB;
|
||||
dinfo.out_color_components = 3;
|
||||
dinfo.output_components = 3;
|
||||
|
||||
|
||||
jpeg_calc_output_dimensions(&dinfo);
|
||||
|
||||
w(dinfo.output_width);
|
||||
|
||||
w(dinfo.output_width);
|
||||
h(dinfo.output_height);
|
||||
d(dinfo.output_components);
|
||||
|
||||
|
||||
if (((size_t)w()) * h() * d() > max_size() ) longjmp(jerr.errhand_, 1);
|
||||
array = new uchar[w() * h() * d()];
|
||||
alloc_array = 1;
|
||||
|
||||
|
||||
jpeg_start_decompress(&dinfo);
|
||||
|
||||
|
||||
while (dinfo.output_scanline < dinfo.output_height) {
|
||||
row = (JSAMPROW)(array +
|
||||
dinfo.output_scanline * dinfo.output_width *
|
||||
dinfo.output_components);
|
||||
jpeg_read_scanlines(&dinfo, &row, (JDIMENSION)1);
|
||||
}
|
||||
|
||||
|
||||
jpeg_finish_decompress(&dinfo);
|
||||
jpeg_destroy_decompress(&dinfo);
|
||||
|
||||
|
||||
free(max_destroy_decompress_err);
|
||||
free(max_finish_decompress_err);
|
||||
|
||||
if (w() && h() && name) {
|
||||
Fl_Shared_Image *si = new Fl_Shared_Image(name, this);
|
||||
if (fp)
|
||||
fclose(fp);
|
||||
|
||||
if (sharename && w() && h()) {
|
||||
Fl_Shared_Image *si = new Fl_Shared_Image(sharename, this);
|
||||
si->add();
|
||||
}
|
||||
#endif // HAVE_LIBJPEG
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// End of "$Id$".
|
||||
//
|
||||
|
@ -48,8 +48,10 @@
|
||||
ERR_FILE_ACCESS if the file could not be opened or read, ERR_FORMAT if the
|
||||
PNM format could not be decoded, and ERR_NO_IMAGE if the image could not
|
||||
be loaded for another reason.
|
||||
|
||||
\param[in] filename a full path and name pointing to a valid jpeg file.
|
||||
*/
|
||||
Fl_PNM_Image::Fl_PNM_Image(const char *name) // I - File to read
|
||||
Fl_PNM_Image::Fl_PNM_Image(const char *filename) // I - File to read
|
||||
: Fl_RGB_Image(0,0,0) {
|
||||
FILE *fp; // File pointer
|
||||
int x, y; // Looping vars
|
||||
@ -63,7 +65,7 @@ Fl_PNM_Image::Fl_PNM_Image(const char *name) // I - File to read
|
||||
maxval; // Maximum pixel value
|
||||
|
||||
|
||||
if ((fp = fl_fopen(name, "rb")) == NULL) {
|
||||
if ((fp = fl_fopen(filename, "rb")) == NULL) {
|
||||
ld(ERR_FILE_ACCESS);
|
||||
return;
|
||||
}
|
||||
@ -84,7 +86,7 @@ Fl_PNM_Image::Fl_PNM_Image(const char *name) // I - File to read
|
||||
lineptr = fgets(line, sizeof(line), fp);
|
||||
if (!lineptr) {
|
||||
fclose(fp);
|
||||
Fl::error("Early end-of-file in PNM file \"%s\"!", name);
|
||||
Fl::error("Early end-of-file in PNM file \"%s\"!", filename);
|
||||
ld(ERR_FILE_ACCESS);
|
||||
return;
|
||||
}
|
||||
@ -128,10 +130,10 @@ Fl_PNM_Image::Fl_PNM_Image(const char *name) // I - File to read
|
||||
if (format == 1 || format == 2 || format == 4 || format == 5) d(1);
|
||||
else d(3);
|
||||
|
||||
// printf("%s = %dx%dx%d\n", name, w(), h(), d());
|
||||
// printf("%s = %dx%dx%d\n", filename, w(), h(), d());
|
||||
|
||||
if (((size_t)w()) * h() * d() > max_size() ) {
|
||||
Fl::warning("PNM file \"%s\" is too large!\n", name);
|
||||
Fl::warning("PNM file \"%s\" is too large!\n", filename);
|
||||
fclose(fp);
|
||||
w(0); h(0); d(0); ld(ERR_FORMAT);
|
||||
return;
|
||||
|
Loading…
Reference in New Issue
Block a user