Added jpeg loading from memory. Added jpeg Fl_Widget->image() support for Fluid - but linking to fltk_images is required if this feature is used!

git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@7092 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
Matthias Melcher 2010-02-18 11:38:42 +00:00
parent b434df6061
commit 795b2c6356
4 changed files with 238 additions and 28 deletions

View File

@ -1,5 +1,7 @@
CHANGES IN FLTK 1.3.0
- Added jpeg support to Fluid image() element
- Added loading jpeg images from memory
- Added binary data type to Fluid
- File chosser preview would hang if a device was choosen
- Replaced _WIN32 symbols that had come with UTF-8 and the

View File

@ -40,9 +40,10 @@
*/
class FL_EXPORT Fl_JPEG_Image : public Fl_RGB_Image {
public:
public:
Fl_JPEG_Image(const char* filename);
Fl_JPEG_Image(const char *filename);
Fl_JPEG_Image(const char *name, const unsigned char *data);
};
#endif

View File

@ -49,6 +49,7 @@ void Fluid_Image::deimage(Fl_Widget *o) {
static int pixmap_header_written = 0;
static int bitmap_header_written = 0;
static int image_header_written = 0;
static int jpeg_header_written = 0;
void Fluid_Image::write_static() {
if (!img) return;
@ -100,6 +101,37 @@ void Fluid_Image::write_static() {
unique_id(this, "image", fl_filename_name(name()), 0),
unique_id(this, "idata", fl_filename_name(name()), 0),
img->w(), img->h());
} else if (strcmp(fl_filename_ext(name()), ".jpg")==0) {
// Write jpeg image data...
write_c("\n");
if (jpeg_header_written != write_number) {
write_c("#include <FL/Fl_JPEG_Image.H>\n");
jpeg_header_written = write_number;
}
write_c("static unsigned char %s[] =\n",
unique_id(this, "idata", fl_filename_name(name()), 0));
FILE *f = fopen(name(), "rb");
if (!f) {
// message = "Can't include binary file. Can't open";
} else {
fseek(f, 0, SEEK_END);
size_t nData = ftell(f);
fseek(f, 0, SEEK_SET);
if (nData) {
char *data = (char*)calloc(nData, 1);
fread(data, nData, 1, f);
write_cdata(data, nData);
free(data);
}
fclose(f);
}
write_c(";\n");
write_c("static Fl_JPEG_Image %s(\"%s\", %s);\n",
unique_id(this, "image", fl_filename_name(name()), 0),
fl_filename_name(name()),
unique_id(this, "idata", fl_filename_name(name()), 0));
} else {
// Write image data...
write_c("\n");

View File

@ -89,40 +89,47 @@ extern "C" {
/**
The constructor loads the JPEG image from the given jpeg filename.
<P>The inherited destructor free all memory and server resources that are used by the image.
*/
Fl_JPEG_Image::Fl_JPEG_Image(const char *jpeg) // I - File to load
: Fl_RGB_Image(0,0,0) {
\brief The constructor loads the JPEG image from the given jpeg filename.
The inherited destructor frees all memory and server resources that are used
by the image.
There is no error function in this class. If the image has loaded correctly,
w(), h(), and d() should return values greater zero.
\param filename a full path and name pointing to a valid jpeg file.
*/
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 = fopen(jpeg, "rb")) == NULL) return;
if ((fp = fopen(filename, "rb")) == NULL) 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...
@ -132,62 +139,230 @@ Fl_JPEG_Image::Fl_JPEG_Image(const char *jpeg) // I - File to load
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);
return;
}
jpeg_create_decompress(&dinfo);
jpeg_stdio_src(&dinfo, fp);
jpeg_read_header(&dinfo, 1);
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);
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
}
// data source manager for reading jpegs from memory
// init_source (j_decompress_ptr cinfo)
// fill_input_buffer (j_decompress_ptr cinfo)
// skip_input_data (j_decompress_ptr cinfo, long num_bytes)
// resync_to_restart (j_decompress_ptr cinfo, int desired)
// term_source (j_decompress_ptr cinfo)
// JOCTET * next_output_byte; /* => next byte to write in buffer */
// size_t free_in_buffer; /* # of byte spaces remaining in buffer */
typedef struct {
struct jpeg_source_mgr pub;
const unsigned char *data, *s;
// JOCTET * buffer; /* start of buffer */
// boolean start_of_file; /* have we gotten any data yet? */
} my_source_mgr;
typedef my_source_mgr *my_src_ptr;
void init_source (j_decompress_ptr cinfo) {
my_src_ptr src = (my_src_ptr)cinfo->src;
src->s = src->data;
}
boolean fill_input_buffer(j_decompress_ptr cinfo) {
my_src_ptr src = (my_src_ptr)cinfo->src;
size_t nbytes = 4096;
src->pub.next_input_byte = src->s;
src->pub.bytes_in_buffer = nbytes;
src->s += nbytes;
return TRUE;
}
void term_source(j_decompress_ptr cinfo)
{
}
void skip_input_data(j_decompress_ptr cinfo, long num_bytes) {
my_src_ptr src = (my_src_ptr)cinfo->src;
if (num_bytes > 0) {
while (num_bytes > (long)src->pub.bytes_in_buffer) {
num_bytes -= (long)src->pub.bytes_in_buffer;
fill_input_buffer(cinfo);
}
src->pub.next_input_byte += (size_t) num_bytes;
src->pub.bytes_in_buffer -= (size_t) num_bytes;
}
}
static void jpeg_mem_src(j_decompress_ptr cinfo, const unsigned char *data)
{
my_src_ptr src;
cinfo->src = (struct jpeg_source_mgr *)malloc(sizeof(my_source_mgr));
src = (my_src_ptr)cinfo->src;
src->pub.init_source = init_source;
src->pub.fill_input_buffer = fill_input_buffer;
src->pub.skip_input_data = skip_input_data;
src->pub.resync_to_restart = jpeg_resync_to_restart;
src->pub.term_source = term_source;
src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
src->pub.next_input_byte = NULL; /* until buffer loaded */
src->data = data;
src->s = data;
}
/**
\brief The constructor loads the JPEG image from memory.
The inherited destructor frees all memory and server resources that are used
by the image.
There is no error function in this class. If the image has loaded correctly,
w(), h(), and d() should return values greater zero.
\param name developer shoud provide a unique name for this image
\param data a pointer to the memorry location of the jpeg image
*/
Fl_JPEG_Image::Fl_JPEG_Image(const char *name, const unsigned char *data)
: Fl_RGB_Image(0,0,0) {
#ifdef HAVE_LIBJPEG
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;
// 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...
// 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);
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);
return;
}
jpeg_create_decompress(&dinfo);
jpeg_mem_src(&dinfo, data);
jpeg_read_header(&dinfo, 1);
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);
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);
#endif // HAVE_LIBJPEG
}
//
// End of "$Id$".
//