diff options
| author | Matthias Melcher <fltk@matthiasm.com> | 2010-02-18 11:38:42 +0000 |
|---|---|---|
| committer | Matthias Melcher <fltk@matthiasm.com> | 2010-02-18 11:38:42 +0000 |
| commit | 795b2c6356af2ef7e26c39faa309d566c4bf62f6 (patch) | |
| tree | de516e395ea1cb66f4c204792d12666b52c801c7 | |
| parent | b434df6061c5436685d2fd6f24e8ebeaf619311f (diff) | |
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
| -rw-r--r-- | CHANGES | 2 | ||||
| -rw-r--r-- | FL/Fl_JPEG_Image.H | 5 | ||||
| -rw-r--r-- | fluid/Fluid_Image.cxx | 32 | ||||
| -rw-r--r-- | src/Fl_JPEG_Image.cxx | 227 |
4 files changed, 238 insertions, 28 deletions
@@ -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 diff --git a/FL/Fl_JPEG_Image.H b/FL/Fl_JPEG_Image.H index 3a34bcf75..40bf1b7f8 100644 --- a/FL/Fl_JPEG_Image.H +++ b/FL/Fl_JPEG_Image.H @@ -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 diff --git a/fluid/Fluid_Image.cxx b/fluid/Fluid_Image.cxx index e421a6e42..afd959c4d 100644 --- a/fluid/Fluid_Image.cxx +++ b/fluid/Fluid_Image.cxx @@ -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"); diff --git a/src/Fl_JPEG_Image.cxx b/src/Fl_JPEG_Image.cxx index 050847a92..c4e450c64 100644 --- a/src/Fl_JPEG_Image.cxx +++ b/src/Fl_JPEG_Image.cxx @@ -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$". // |
