home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / src / common / imagjpeg.cpp < prev    next >
C/C++ Source or Header  |  2002-05-23  |  12KB  |  396 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        imagjpeg.cpp
  3. // Purpose:     wxImage JPEG handler
  4. // Author:      Vaclav Slavik
  5. // RCS-ID:      $Id: imagjpeg.cpp,v 1.30 2002/05/22 23:14:47 VZ Exp $
  6. // Copyright:   (c) Vaclav Slavik
  7. // Licence:     wxWindows licence
  8. /////////////////////////////////////////////////////////////////////////////
  9.  
  10. #ifdef __GNUG__
  11. #pragma implementation "imagjpeg.h"
  12. #endif
  13.  
  14. // For compilers that support precompilation, includes "wx.h".
  15. #include "wx/wxprec.h"
  16.  
  17. #ifdef __BORLANDC__
  18. #pragma hdrstop
  19. #endif
  20.  
  21. #include "wx/defs.h"
  22.  
  23. #if wxUSE_IMAGE && wxUSE_LIBJPEG
  24.  
  25. #include "wx/imagjpeg.h"
  26. #include "wx/bitmap.h"
  27. #include "wx/debug.h"
  28. #include "wx/log.h"
  29. #include "wx/app.h"
  30.  
  31. // NB: Some compilers define boolean type in Windows headers (e.g. Watcom C++).
  32. //     This causes a conflict with jmorecfg.h header from libjpeg, so we have
  33. //     to make sure libjpeg won't try to define boolean itself. This is done by
  34. //     defining HAVE_BOOLEAN.
  35. #if defined(__WXMSW__) && (defined(__MWERKS__) || defined(__WATCOMC__))
  36.     #define HAVE_BOOLEAN
  37.     #include <windows.h>
  38. #endif
  39.  
  40. extern "C"
  41. {
  42.     #include "jpeglib.h"
  43. }
  44.  
  45. #include "wx/filefn.h"
  46. #include "wx/wfstream.h"
  47. #include "wx/intl.h"
  48. #include "wx/module.h"
  49.  
  50. // For memcpy
  51. #include <string.h>
  52. // For JPEG library error handling
  53. #include <setjmp.h>
  54.  
  55. #ifdef __SALFORDC__
  56. #undef FAR
  57. #endif
  58.  
  59. // ----------------------------------------------------------------------------
  60. // types
  61. // ----------------------------------------------------------------------------
  62.  
  63. // the standard definition of METHODDEF(type) from jmorecfg.h is "static type"
  64. // which means that we can't declare the method functions as extern "C" - the
  65. // compiler (rightfully) complains about the multiple storage classes in
  66. // declaration
  67. //
  68. // so we only add extern "C" when using our own, modified, jmorecfg.h - and use
  69. // whatever we have in the system headers if this is what we use hoping that it
  70. // should be ok (can't do anything else)
  71. #ifdef JPEG_METHOD_LINKAGE
  72.     #define CPP_METHODDEF(type) extern "C" METHODDEF(type)
  73. #else // not using our jmorecfg.h header
  74.     #define CPP_METHODDEF(type) METHODDEF(type)
  75. #endif
  76.  
  77. //-----------------------------------------------------------------------------
  78. // wxJPEGHandler
  79. //-----------------------------------------------------------------------------
  80.  
  81. IMPLEMENT_DYNAMIC_CLASS(wxJPEGHandler,wxImageHandler)
  82.  
  83. #if wxUSE_STREAMS
  84.  
  85. //------------- JPEG Data Source Manager
  86.  
  87. #define JPEG_IO_BUFFER_SIZE   2048
  88.  
  89. typedef struct {
  90.     struct jpeg_source_mgr pub;   /* public fields */
  91.  
  92.     JOCTET* buffer;               /* start of buffer */
  93.     wxInputStream *stream;
  94. } my_source_mgr;
  95.  
  96. typedef my_source_mgr * my_src_ptr;
  97.  
  98. CPP_METHODDEF(void) my_init_source ( j_decompress_ptr WXUNUSED(cinfo) )
  99. {
  100. }
  101.  
  102. CPP_METHODDEF(boolean) my_fill_input_buffer ( j_decompress_ptr cinfo )
  103. {
  104.     my_src_ptr src = (my_src_ptr) cinfo->src;
  105.  
  106.     src->pub.next_input_byte = src->buffer;
  107.     src->pub.bytes_in_buffer = src->stream->Read(src->buffer, JPEG_IO_BUFFER_SIZE).LastRead();
  108.  
  109.     if (src->pub.bytes_in_buffer == 0) // check for end-of-stream
  110.     {
  111.         // Insert a fake EOI marker
  112.         src->buffer[0] = 0xFF;
  113.         src->buffer[1] = JPEG_EOI;
  114.         src->pub.bytes_in_buffer = 2;
  115.     }
  116.     return TRUE;
  117. }
  118.  
  119. CPP_METHODDEF(void) my_skip_input_data ( j_decompress_ptr cinfo, long num_bytes )
  120. {
  121.     if (num_bytes > 0)
  122.     {
  123.         my_src_ptr src = (my_src_ptr) cinfo->src;
  124.  
  125.         while (num_bytes > (long)src->pub.bytes_in_buffer)
  126.         {
  127.             num_bytes -= (long) src->pub.bytes_in_buffer;
  128.             src->pub.fill_input_buffer(cinfo);
  129.         }
  130.         src->pub.next_input_byte += (size_t) num_bytes;
  131.         src->pub.bytes_in_buffer -= (size_t) num_bytes;
  132.     }
  133. }
  134.  
  135. CPP_METHODDEF(void) my_term_source ( j_decompress_ptr cinfo )
  136. {
  137.     my_src_ptr src = (my_src_ptr) cinfo->src;
  138.  
  139.     if (src->pub.bytes_in_buffer > 0)
  140.         src->stream->SeekI(-(long)src->pub.bytes_in_buffer, wxFromCurrent);
  141.     delete[] src->buffer;
  142. }
  143.  
  144.  
  145. // JPEG error manager:
  146.  
  147. struct my_error_mgr {
  148.   struct jpeg_error_mgr pub;    /* "public" fields */
  149.  
  150.   jmp_buf setjmp_buffer;    /* for return to caller */
  151. };
  152.  
  153. typedef struct my_error_mgr * my_error_ptr;
  154.  
  155. /*
  156.  * Here's the routine that will replace the standard error_exit method:
  157.  */
  158.  
  159. CPP_METHODDEF(void) my_error_exit (j_common_ptr cinfo)
  160. {
  161.   /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
  162.   my_error_ptr myerr = (my_error_ptr) cinfo->err;
  163.  
  164.   /* Always display the message. */
  165.   /* We could postpone this until after returning, if we chose. */
  166.   if (cinfo->err->output_message) (*cinfo->err->output_message) (cinfo);
  167.  
  168.   /* Return control to the setjmp point */
  169.   longjmp(myerr->setjmp_buffer, 1);
  170. }
  171.  
  172. void jpeg_wxio_src( j_decompress_ptr cinfo, wxInputStream& infile )
  173. {
  174.     my_src_ptr src;
  175.  
  176.     if (cinfo->src == NULL) {    /* first time for this JPEG object? */
  177.         cinfo->src = (struct jpeg_source_mgr *)
  178.             (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
  179.             sizeof(my_source_mgr));
  180.         src = (my_src_ptr) cinfo->src;
  181.     }
  182.     src = (my_src_ptr) cinfo->src;
  183.     src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
  184.     src->buffer = new JOCTET[JPEG_IO_BUFFER_SIZE];
  185.     src->pub.next_input_byte = NULL; /* until buffer loaded */
  186.     src->stream = &infile;
  187.  
  188.     src->pub.init_source = my_init_source;
  189.     src->pub.fill_input_buffer = my_fill_input_buffer;
  190.     src->pub.skip_input_data = my_skip_input_data;
  191.     src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
  192.     src->pub.term_source = my_term_source;
  193. }
  194.  
  195.  
  196. // temporarily disable the warning C4611 (interaction between '_setjmp' and
  197. // C++ object destruction is non-portable) - I don't see any dtors here
  198. #ifdef __VISUALC__
  199.     #pragma warning(disable:4611)
  200. #endif /* VC++ */
  201.  
  202. bool wxJPEGHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose, int WXUNUSED(index) )
  203. {
  204.     struct jpeg_decompress_struct cinfo;
  205.     struct my_error_mgr jerr;
  206.     JSAMPARRAY tempbuf;
  207.     unsigned char *ptr;
  208.     unsigned stride;
  209.  
  210.     image->Destroy();
  211.     cinfo.err = jpeg_std_error( &jerr.pub );
  212.     jerr.pub.error_exit = my_error_exit;
  213.  
  214.     if (!verbose) cinfo.err->output_message=NULL;
  215.  
  216.     /* Establish the setjmp return context for my_error_exit to use. */
  217.     if (setjmp(jerr.setjmp_buffer)) {
  218.       /* If we get here, the JPEG code has signaled an error.
  219.        * We need to clean up the JPEG object, close the input file, and return.
  220.        */
  221.       if (verbose)
  222.         wxLogError(_("JPEG: Couldn't load - file is probably corrupted."));
  223.       (cinfo.src->term_source)(&cinfo);
  224.       jpeg_destroy_decompress(&cinfo);
  225.       if (image->Ok()) image->Destroy();
  226.       return FALSE;
  227.     }
  228.  
  229.     jpeg_create_decompress( &cinfo );
  230.     jpeg_wxio_src( &cinfo, stream );
  231.     jpeg_read_header( &cinfo, TRUE );
  232.     cinfo.out_color_space = JCS_RGB;
  233.     jpeg_start_decompress( &cinfo );
  234.  
  235.     image->Create( cinfo.image_width, cinfo.image_height );
  236.     if (!image->Ok()) {
  237.         jpeg_finish_decompress( &cinfo );
  238.         jpeg_destroy_decompress( &cinfo );
  239.         return FALSE;
  240.     }
  241.     image->SetMask( FALSE );
  242.     ptr = image->GetData();
  243.     stride = cinfo.output_width * 3;
  244.     tempbuf = (*cinfo.mem->alloc_sarray)
  245.         ((j_common_ptr) &cinfo, JPOOL_IMAGE, stride, 1 );
  246.  
  247.     while ( cinfo.output_scanline < cinfo.output_height ) {
  248.         jpeg_read_scanlines( &cinfo, tempbuf, 1 );
  249.         memcpy( ptr, tempbuf[0], stride );
  250.         ptr += stride;
  251.     }
  252.     jpeg_finish_decompress( &cinfo );
  253.     jpeg_destroy_decompress( &cinfo );
  254.     return TRUE;
  255. }
  256.  
  257. typedef struct {
  258.     struct jpeg_destination_mgr pub;
  259.  
  260.     wxOutputStream *stream;
  261.     JOCTET * buffer;
  262. } my_destination_mgr;
  263.  
  264. typedef my_destination_mgr * my_dest_ptr;
  265.  
  266. #define OUTPUT_BUF_SIZE  4096    /* choose an efficiently fwrite'able size */
  267.  
  268. CPP_METHODDEF(void) init_destination (j_compress_ptr cinfo)
  269. {
  270.     my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
  271.  
  272.     /* Allocate the output buffer --- it will be released when done with image */
  273.     dest->buffer = (JOCTET *)
  274.         (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE,
  275.         OUTPUT_BUF_SIZE * sizeof(JOCTET));
  276.     dest->pub.next_output_byte = dest->buffer;
  277.     dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
  278. }
  279.  
  280. CPP_METHODDEF(boolean) empty_output_buffer (j_compress_ptr cinfo)
  281. {
  282.     my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
  283.  
  284.     dest->stream->Write(dest->buffer, OUTPUT_BUF_SIZE);
  285.     dest->pub.next_output_byte = dest->buffer;
  286.     dest->pub.free_in_buffer = OUTPUT_BUF_SIZE;
  287.     return TRUE;
  288. }
  289.  
  290. CPP_METHODDEF(void) term_destination (j_compress_ptr cinfo)
  291. {
  292.     my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
  293.     size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer;
  294.     /* Write any data remaining in the buffer */
  295.     if (datacount > 0)
  296.         dest->stream->Write(dest->buffer, datacount);
  297. }
  298.  
  299. GLOBAL(void) jpeg_wxio_dest (j_compress_ptr cinfo, wxOutputStream& outfile)
  300. {
  301.     my_dest_ptr dest;
  302.  
  303.     if (cinfo->dest == NULL) {    /* first time for this JPEG object? */
  304.         cinfo->dest = (struct jpeg_destination_mgr *)
  305.             (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
  306.             sizeof(my_destination_mgr));
  307.     }
  308.  
  309.     dest = (my_dest_ptr) cinfo->dest;
  310.     dest->pub.init_destination = init_destination;
  311.     dest->pub.empty_output_buffer = empty_output_buffer;
  312.     dest->pub.term_destination = term_destination;
  313.     dest->stream = &outfile;
  314. }
  315.  
  316. bool wxJPEGHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose )
  317. {
  318.     struct jpeg_compress_struct cinfo;
  319.     struct my_error_mgr jerr;
  320.     JSAMPROW row_pointer[1];    /* pointer to JSAMPLE row[s] */
  321.     JSAMPLE *image_buffer;
  322.     int stride;                /* physical row width in image buffer */
  323.  
  324.     cinfo.err = jpeg_std_error(&jerr.pub);
  325.     jerr.pub.error_exit = my_error_exit;
  326.  
  327.     if (!verbose) cinfo.err->output_message=NULL;
  328.  
  329.     /* Establish the setjmp return context for my_error_exit to use. */
  330.     if (setjmp(jerr.setjmp_buffer))
  331.     {
  332.         /* If we get here, the JPEG code has signaled an error.
  333.          * We need to clean up the JPEG object, close the input file, and return.
  334.          */
  335.          if (verbose)
  336.             wxLogError(_("JPEG: Couldn't save image."));
  337.          jpeg_destroy_compress(&cinfo);
  338.          return FALSE;
  339.     }
  340.  
  341.     jpeg_create_compress(&cinfo);
  342.     jpeg_wxio_dest(&cinfo, stream);
  343.  
  344.     cinfo.image_width = image->GetWidth();
  345.     cinfo.image_height = image->GetHeight();
  346.     cinfo.input_components = 3;
  347.     cinfo.in_color_space = JCS_RGB;
  348.     jpeg_set_defaults(&cinfo);
  349.  
  350.     // TODO: 3rd parameter is force_baseline, what value should this be?
  351.     // Code says: "If force_baseline is TRUE, the computed quantization table entries
  352.     // are limited to 1..255 for JPEG baseline compatibility."
  353.     // 'Quality' is a number between 0 (terrible) and 100 (very good).
  354.     // The default (in jcparam.c, jpeg_set_defaults) is 75,
  355.     // and force_baseline is TRUE.
  356.     if (image->HasOption(wxT("quality")))
  357.         jpeg_set_quality(&cinfo, image->GetOptionInt(wxT("quality")), TRUE);
  358.  
  359.     jpeg_start_compress(&cinfo, TRUE);
  360.  
  361.     stride = cinfo.image_width * 3;    /* JSAMPLEs per row in image_buffer */
  362.     image_buffer = image->GetData();
  363.     while (cinfo.next_scanline < cinfo.image_height) {
  364.         row_pointer[0] = &image_buffer[cinfo.next_scanline * stride];
  365.         jpeg_write_scanlines( &cinfo, row_pointer, 1 );
  366.     }
  367.     jpeg_finish_compress(&cinfo);
  368.     jpeg_destroy_compress(&cinfo);
  369.  
  370.     return TRUE;
  371. }
  372.  
  373. #ifdef __VISUALC__
  374.     #pragma warning(default:4611)
  375. #endif /* VC++ */
  376.  
  377. bool wxJPEGHandler::DoCanRead( wxInputStream& stream )
  378. {
  379.     unsigned char hdr[2];
  380.  
  381.     if ( !stream.Read(hdr, WXSIZEOF(hdr)) )
  382.         return FALSE;
  383.  
  384.     return hdr[0] == 0xFF && hdr[1] == 0xD8;
  385. }
  386.  
  387. #endif   // wxUSE_STREAMS
  388.  
  389. #endif   // wxUSE_LIBJPEG
  390.  
  391.  
  392.  
  393.  
  394.  
  395.  
  396.