home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 January: Mac OS SDK / Dev.CD Jan 97 SDK2.toast / Development Kits (Disc 2) / OpenDoc Development Framework / ODFDev / Bitmap / Sources / odfjpeg.cpp < prev    next >
Encoding:
Text File  |  1996-09-17  |  9.5 KB  |  311 lines  |  [TEXT/MPS ]

  1. //========================================================================================
  2. //
  3. //    File:                odfjpeg.cpp
  4. //    Release Version:    $ ODF 2 $
  5. //
  6. //    Author:                Mark Lanett
  7. //
  8. //    Copyright:    (c) 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  9. //
  10. //========================================================================================
  11. //
  12. //    Reads a JPEG using the Independent JPEG Group's free JPEG library.
  13. //    Returns an FW_CBitmap.
  14. //    Note: the returned bitmap is 16-bit and is not dithered.
  15. //    
  16. //    6/3/96 mlanett Checked in. Derived from example.c from the JPEG library.
  17. //    
  18.  
  19. #include "FWOS.hpp"
  20. #include "odfjpeg.h"
  21.  
  22. #ifndef FWMEMMGR_H
  23. #include "FWMemMgr.h"
  24. #endif
  25.  
  26. #ifndef FWRECSHP_H
  27. #include "FWRecShp.h"
  28. #endif
  29.  
  30. // Why does everyone insist on defining boolean themselves?
  31. // Something wrong with "char" or "int" or "ijg_boolean"?
  32.  
  33. #define boolean yet_another_conflicting_boolean_type
  34.  
  35. extern "C" {
  36. #include "jinclude.h"
  37. #include "jpeglib.h"
  38. #include "jerror.h"
  39. }
  40.  
  41. #include <setjmp.h>
  42. #include "SLASinks.xh"
  43.  
  44. #pragma segment odfjpeg
  45.  
  46. /*-----------------------------------------------------------------------------
  47.     Prototypes
  48.     
  49. -----------------------------------------------------------------------------*/
  50.  
  51. extern "C" {
  52. void ODF_JPEG_DecodeRow (JOCTET* samples, int inbytes, Ptr base, int outbytes);
  53.  
  54.     // The following prototypes are necessary for compilers that treat pointers
  55.     // to static methods of a class as different from extern "C" functions. [sfu]
  56.     
  57.     typedef void (*t_jpegemPtr)(j_common_ptr cinfo);
  58.     typedef void (*t_jpegcm1Ptr)(jpeg_decompress_struct *);
  59.     typedef int (*t_jpegcm2Ptr)(jpeg_decompress_struct *);
  60.     typedef void (*t_jpegcm3Ptr)(jpeg_decompress_struct *, long);
  61. }
  62.  
  63. /*-----------------------------------------------------------------------------
  64.     Utilities
  65. -----------------------------------------------------------------------------*/
  66.  
  67. class TempMacLockedPixels {
  68. public:
  69.     FW_DECLARE_AUTO (TempMacLockedPixels)
  70.                     TempMacLockedPixels (PixMapHandle lockedPixMap);
  71.                     ~TempMacLockedPixels ();
  72. private:
  73.     PixMapHandle     fPixMap;
  74. };
  75.  
  76. FW_DEFINE_AUTO (TempMacLockedPixels)
  77.  
  78. TempMacLockedPixels::TempMacLockedPixels (PixMapHandle lockedPixMap)
  79. :    fPixMap (lockedPixMap)
  80. {
  81. }
  82.  
  83. TempMacLockedPixels::~TempMacLockedPixels ()
  84. {
  85.     ::UnlockPixels (fPixMap);
  86. }
  87.  
  88. /*-----------------------------------------------------------------------------
  89.     ODF_JPEG_ErrorManager
  90. -----------------------------------------------------------------------------*/
  91.  
  92. struct ODF_JPEG_ErrorManager: public jpeg_error_mgr {
  93.     jmp_buf         fExitBuffer;
  94.     static void     ErrorExit (j_common_ptr cinfo);
  95. };
  96.  
  97. void ODF_JPEG_ErrorManager::ErrorExit (j_common_ptr cinfo)
  98. {
  99.     ODF_JPEG_ErrorManager* self = (ODF_JPEG_ErrorManager*) cinfo->err;
  100.     // (cinfo->err->output_message) (cinfo);
  101.     longjmp (self->fExitBuffer, 1);
  102. }
  103.  
  104. /*-----------------------------------------------------------------------------
  105.     ODF_JPEG_SourceManager
  106. -----------------------------------------------------------------------------*/
  107.  
  108. struct ODF_JPEG_SourceManager: public jpeg_source_mgr {
  109.                     FW_DECLARE_AUTO(ODF_JPEG_SourceManager)
  110.                     ODF_JPEG_SourceManager     (Environment* ev, FW_OSink* sink, size_t bufferSize = 1000);
  111.                     ~ODF_JPEG_SourceManager ();
  112.                     
  113.     static void     InitSource            (j_decompress_ptr cinfo);
  114.     static boolean     FillInputBuffer        (j_decompress_ptr cinfo);
  115.     static void     SkipInputData        (j_decompress_ptr cinfo, long num_bytes);
  116.     static void     TermSource            (j_decompress_ptr cinfo);
  117. private:
  118.     Environment*     fEv;
  119.     FW_OSink*         fSink;
  120.     size_t             fBufferSize;
  121.     JOCTET*         fBuffer;
  122.     FW_Boolean         fStartOfFile;
  123. };
  124.  
  125. FW_DEFINE_AUTO(ODF_JPEG_SourceManager)
  126.  
  127. ODF_JPEG_SourceManager::ODF_JPEG_SourceManager (Environment* ev, FW_OSink* sink, size_t bufferSize)
  128. :    fEv (ev)
  129. ,    fSink (sink)
  130. ,    fBufferSize (bufferSize)
  131. {
  132.     fBuffer = (JOCTET*) FW_CMemoryManager::AllocateBlock (fBufferSize);
  133. }
  134.  
  135. ODF_JPEG_SourceManager::~ODF_JPEG_SourceManager ()
  136. {
  137.     FW_CMemoryManager::FreeBlock (fBuffer);
  138. }
  139.  
  140. void ODF_JPEG_SourceManager::InitSource (j_decompress_ptr cinfo)
  141. {
  142.     ODF_JPEG_SourceManager* self = (ODF_JPEG_SourceManager*) cinfo->src;
  143.     self->fStartOfFile = true;
  144. }
  145.  
  146. boolean ODF_JPEG_SourceManager::FillInputBuffer (j_decompress_ptr cinfo)
  147. {
  148.     ODF_JPEG_SourceManager* self = (ODF_JPEG_SourceManager*) cinfo->src;
  149.     
  150.     size_t available = self->fSink->GetReadableBytes (self->fEv);
  151.     if (available == 0) {
  152.         // Is it an empty data set?
  153.         if (self->fStartOfFile)
  154.             ERREXIT (cinfo, JERR_INPUT_EMPTY);
  155.         // If it's just a truncated dataset, terminate it (and return a warning?)
  156.         WARNMS (cinfo, JWRN_JPEG_EOF);
  157.         self->fBuffer[0] = 0xFF;
  158.         self->fBuffer[1] = JPEG_EOI;
  159.         available = 2;
  160.     }
  161.     else {
  162.         if (self->fBufferSize < available)
  163.             available = self->fBufferSize;
  164.         self->fSink->Read (self->fEv, self->fBuffer, available);
  165.     }
  166.     
  167.     self->next_input_byte = self->fBuffer;
  168.     self->bytes_in_buffer = available;
  169.     self->fStartOfFile = false;
  170.     
  171.     return true;
  172. }
  173.  
  174. void ODF_JPEG_SourceManager::SkipInputData (j_decompress_ptr cinfo, long num_bytes)
  175. {
  176.     ODF_JPEG_SourceManager* self = (ODF_JPEG_SourceManager*) cinfo->src;
  177.     
  178.     while (self->bytes_in_buffer < num_bytes) {
  179.         num_bytes -= self->bytes_in_buffer;
  180.         FillInputBuffer (cinfo);
  181.     }
  182.     
  183.     self->next_input_byte += num_bytes;
  184.     self->bytes_in_buffer -= num_bytes;
  185. }
  186.  
  187. void ODF_JPEG_SourceManager::TermSource (j_decompress_ptr cinfo)
  188. {
  189. FW_UNUSED(cinfo);
  190. }
  191.  
  192. /*-----------------------------------------------------------------------------
  193.     ODF_JPEG_DecodeRow
  194. -----------------------------------------------------------------------------*/
  195.  
  196. void ODF_JPEG_DecodeRow (JOCTET* samples, int inbytes, Ptr base, int outbytes)
  197. {
  198. /*
  199.     Now that we have a row of samples, rewrite them into a 16-bit Mac pixmap.
  200. */
  201.     while (3 <= inbytes && 2 <= outbytes)  {
  202.         // Input from samples
  203.         JOCTET red = *samples++;
  204.         JOCTET green = *samples++;
  205.         JOCTET blue = *samples++;
  206.         inbytes -= 3;
  207.         // Output to pixmap
  208.         unsigned short rgb16 = ((red >> 3) << 10) | ((green >> 3) << 5) | (blue >> 3);
  209.         *((unsigned short*)base) = rgb16;
  210.         base += 2;
  211.         outbytes -= 2;
  212.     }
  213. }
  214.  
  215. /*-----------------------------------------------------------------------------
  216.     ODF_JPEG_Read
  217. -----------------------------------------------------------------------------*/
  218.  
  219. FW_CBitmap ODF_JPEG_Read (Environment* ev, FW_OSink* sink)
  220. {
  221.     jpeg_decompress_struct cinfo;
  222.     ODF_JPEG_ErrorManager     jerr;
  223.     ODF_JPEG_SourceManager     src (ev, sink);
  224.     
  225.     // Initialize error handling first
  226.     cinfo.err = jpeg_std_error (&jerr);
  227.     jerr.error_exit = (t_jpegemPtr)ODF_JPEG_ErrorManager::ErrorExit;
  228.     if (setjmp (jerr.fExitBuffer)) {
  229.         jpeg_destroy_decompress (&cinfo);
  230.         FW_Failure (FW_xReadableStream);
  231.     }
  232.     
  233.     // Initialize rest of JPEG library
  234.     jpeg_create_decompress (&cinfo);
  235.     src.init_source =         (t_jpegcm1Ptr)ODF_JPEG_SourceManager::InitSource;
  236.     src.fill_input_buffer = (t_jpegcm2Ptr)ODF_JPEG_SourceManager::FillInputBuffer;
  237.     src.skip_input_data =     (t_jpegcm3Ptr)ODF_JPEG_SourceManager::SkipInputData;
  238.     src.resync_to_restart = jpeg_resync_to_restart;
  239.     src.term_source =         (t_jpegcm1Ptr)ODF_JPEG_SourceManager::TermSource;
  240.     src.bytes_in_buffer =     0;
  241.     src.next_input_byte =     nil;
  242.     cinfo.src =             &src;
  243.     
  244.     // Calling C++ code (FW_OSink, FW_CBitmap, etc) can result in exceptions being
  245.     // thrown. Must protect the jpeg_decompress_struct from not being
  246.     // deleted properly. An alternative way to do that would be to subclass
  247.     // it and give it a destructor (and make it an AUTO(destruct) object).
  248.     FW_CBitmap bitmap;
  249.     
  250.     FW_TRY {
  251.     
  252.     // Start reading data
  253.     jpeg_read_header (&cinfo, TRUE);
  254.     jpeg_start_decompress (&cinfo);
  255.     
  256.     // Ok, now we have anything we could possibly need (including the colormap if
  257.     // we asked for color quantization).
  258.     // (1) Create the ODF bitmap object (16-bits deep)
  259.     // (2) Create a work buffer (using the jpeglib's auto-deleting memory manager)
  260.     bitmap = FW_CBitmap (cinfo.output_width, cinfo.output_height, 16);
  261.         //.ChangeBitmap (cinfo.output_width, cinfo.output_height, 16, false);
  262.     if (0) // XXX we don't really need to do this
  263.     {
  264.     // Erase the bitmap; use nested scope to avoid context lifetime/thread 
  265.     // problems. That is, if I didn't use a nested scope then the context (bc) 
  266.     // would stay alive until the end of this function. Since we will be 
  267.     // yielding to other threads during the call to jpeg_read_scanlines below, 
  268.     // other threads could create contexts as well. The ODF graphics layer is 
  269.     // not thread-safe and can't deal with contexts in multiple threads, so we 
  270.     // must force this context to be destroyed ASAP.
  271.     
  272.     FW_CBitmapContext bc (ev, bitmap);
  273.     FW_CMapping mapping (FW_kDevice);
  274.     bc.SetMapping (mapping);
  275.     FW_CPlatformRect bounds (0, 0, cinfo.output_width, cinfo.output_height);
  276.     FW_CRectShape::RenderRect (bc, bounds, FW_kFill, FW_kWhiteEraseInk);
  277.     }
  278.     int bytes = cinfo.output_width * cinfo.output_components;
  279.     JOCTET** buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE, bytes, 1);
  280.     
  281.     // Prepare for decoding the samples
  282.     short width, height, rowBytes, depth;
  283.     bitmap.GetBitmapInfo (width, height, rowBytes, depth); // All I *want* is rowBytes
  284.     FW_PlatformBitmap pb = bitmap.GetPlatformBitmap();
  285.     PixMapHandle pm = ::GetGWorldPixMap (pb);
  286.     Boolean locked = ::LockPixels (pm);
  287.     TempMacLockedPixels unlock (pm);
  288.     Ptr base = ::GetPixBaseAddr (pm);
  289.     
  290.     // Decode each row as it comes in. If we run ahead of the network, the sink object
  291.     // will automatically sleep, so we never need to worry about suspension.
  292.     while (cinfo.output_scanline < cinfo.output_height) {
  293.         jpeg_read_scanlines (&cinfo, buffer, 1);
  294.         ODF_JPEG_DecodeRow (buffer[0], bytes, base, rowBytes);
  295.         base += rowBytes;
  296.     }
  297.     
  298.     jpeg_finish_decompress(&cinfo);
  299.     jpeg_destroy_decompress(&cinfo);
  300.     }
  301.     FW_CATCH_BEGIN
  302.     FW_CATCH_EVERYTHING() {
  303.         jpeg_destroy_decompress(&cinfo);
  304.         FW_THROW_SAME();
  305.     }
  306.     FW_CATCH_END
  307.     
  308.     return bitmap;
  309. }
  310.  
  311.