Skip to content

Commit

Permalink
Added jpeg loading from memory. Added jpeg Fl_Widget->image() support…
Browse files Browse the repository at this point in the history
… 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
  • Loading branch information
Matthias Melcher committed Feb 18, 2010
1 parent b434df6 commit 795b2c6
Show file tree
Hide file tree
Showing 4 changed files with 238 additions and 28 deletions.
2 changes: 2 additions & 0 deletions CHANGES
@@ -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
Expand Down
5 changes: 3 additions & 2 deletions FL/Fl_JPEG_Image.H
Expand Up @@ -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
Expand Down
32 changes: 32 additions & 0 deletions fluid/Fluid_Image.cxx
Expand Up @@ -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;
Expand Down Expand Up @@ -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");
Expand Down
227 changes: 201 additions & 26 deletions src/Fl_JPEG_Image.cxx
Expand Up @@ -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...
Expand All @@ -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$".
//

0 comments on commit 795b2c6

Please sign in to comment.