home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Libraries / JPEG Library / JPEGUtilities.c < prev    next >
Encoding:
Text File  |  1994-07-12  |  16.2 KB  |  432 lines  |  [TEXT/MPCC]

  1. //=====================================================================================
  2. // JPEGUtilities.c -- written by Aaron Giles
  3. // Last update: 7/7/94
  4. //=====================================================================================
  5. // A source code library for performing very simple operations (drawing, embedding into
  6. // PICTs, and extracting from PICTs) on JPEG-compressed images using QuickTime.
  7. //=====================================================================================
  8. // This code has been successfully compiled under Metrowerks C/C++ 1.0a4, under
  9. // THINK C 7.0, and under MPW C 3.3.
  10. //=====================================================================================
  11. // If you find any bugs in this source code, please email me and I will attempt to fix
  12. // them.  If you have any additions/modifications that you think would be generally
  13. // useful, email those to me as well, and I will consider incorporating them into the
  14. // next release.  My email address is giles@med.cornell.edu.
  15. //=====================================================================================
  16. // This source code is copyright © 1994, Aaron Giles.  Permission to use this code in
  17. // your product is freely granted, provided that you credit me appropriately in your
  18. // application's About box/credits *and* documentation.  If you ship an application
  19. // which uses this code, I would also like to request that you provide me with one
  20. // complimentary copy of the application.
  21. //=====================================================================================
  22.  
  23. //=====================================================================================
  24. // Generic includes for Macintosh headers
  25. //=====================================================================================
  26.  
  27. #include <Errors.h>
  28.  
  29. //=====================================================================================
  30. // Includes specific to this module
  31. //=====================================================================================
  32.  
  33. #include "JPEGUtilities.h"
  34.  
  35. //=====================================================================================
  36. // Global variables local to this module
  37. //=====================================================================================
  38.  
  39. static Handle gJPEGDestHandle;
  40. static StdPixUPP gUnwrapPixProc = nil;
  41. static QDBitsUPP gDummyBitsProc;
  42. static QDTextUPP gDummyTextProc;
  43. static QDLineUPP gDummyLineProc;
  44. static QDRectUPP gDummyRectProc;
  45. static QDRRectUPP gDummyRRectProc;
  46. static QDOvalUPP gDummyOvalProc;
  47. static QDArcUPP gDummyArcProc;
  48. static QDPolyUPP gDummyPolyProc;
  49. static QDRgnUPP gDummyRgnProc;
  50.  
  51. //=====================================================================================
  52. // Prototypes for functions local to this module
  53. //=====================================================================================
  54.  
  55. static void InitJPEGUPPs(void);
  56. static unsigned char *GetJPEGData(unsigned char *theAdr, long theLen, unsigned char theCode);
  57. static OSErr MakeJPEGImageDesc(Handle theHandle, ImageDescriptionHandle theDesc);
  58. static pascal void UnwrapPixProc(PixMap *src, Rect *srcRect, MatrixRecord *matrix,
  59.             short mode, RgnHandle mask, PixMap *matte, Rect *matteRect, 
  60.             short callOldBits);
  61. static pascal void DummyBitsProc(PixMap *src, Rect *srcRect, Rect *dstRect, short mode, 
  62.             RgnHandle mask);
  63. static pascal void DummyTextProc(short count, const void *textAddr, Point numer,
  64.             Point denom);
  65. static pascal void DummyLineProc(Point newPt);
  66. static pascal void DummyRectProc(GrafVerb verb, const Rect *r);
  67. static pascal void DummyRRectProc(GrafVerb verb, const Rect *r, short ovalWidth, 
  68.             short ovalHeight);
  69. static pascal void DummyOvalProc(GrafVerb verb, const Rect *r);
  70. static pascal void DummyArcProc(GrafVerb verb, const Rect *r, short startAngle,
  71.             short arcAngle);
  72. static pascal void DummyPolyProc(GrafVerb verb, PolyHandle poly);
  73. static pascal void DummyRgnProc(GrafVerb verb, RgnHandle rgn);
  74.  
  75. //=====================================================================================
  76. // OSErr GetJPEGBounds(Handle theHandle, Rect *theBounds)
  77. //=====================================================================================
  78. // Scans the JPEG image data in theHandle for the bounding rectangle, and returns the
  79. // result in theBounds.  If the code specifying the bounds of the image was not found,
  80. // this function returns codecBadDataErr.
  81. //=====================================================================================
  82.  
  83. extern OSErr GetJPEGBounds(Handle theHandle, Rect *theBounds)
  84. {
  85.     long theLen = GetHandleSize(theHandle);
  86.     unsigned char *theData;
  87.     short theCode;
  88.     
  89.     for (theCode = 0xc0; theCode < 0xd0; theCode++)
  90.         if (theData = GetJPEGData((unsigned char *)*theHandle, theLen, theCode)) break;
  91.     if (theCode == 0xd0) return codecBadDataErr;
  92.     theBounds->top = theBounds->left = 0;
  93.     theBounds->right = (theData[3] << 8) + theData[4];
  94.     theBounds->bottom = (theData[1] << 8) + theData[2];
  95.     return noErr;
  96. }
  97.  
  98. //=====================================================================================
  99. // OSErr DrawJPEG(Handle theHandle, Rect *srcRect, Rect *dstRect, short tMode)
  100. //=====================================================================================
  101. // Draws a JPEG image, whose data is in theHandle, to the current port.  The portion of
  102. // the image to be drawn is specified in srcRect, and any scaling or translation can be
  103. // specified through dstRect.  The transfer mode for drawing is given in the tMode
  104. // parameter.
  105. //=====================================================================================
  106.  
  107. extern OSErr DrawJPEG(Handle theHandle, Rect *srcRect, Rect *dstRect, short tMode)
  108. {
  109.     PixMapHandle dPixMap = GetGWorldPixMap((CGrafPtr)qd.thePort);
  110.     long theSize = GetHandleSize(theHandle);
  111.     char hState = HGetState(theHandle);
  112.     ImageDescriptionHandle theDesc;
  113.     MatrixRecord theMatrix;
  114.     OSErr theErr;
  115.  
  116.     if (theDesc = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription))) {
  117.         HLock((Handle)theDesc);
  118.         theErr = MakeJPEGImageDesc(theHandle, theDesc);
  119.         if (theErr == noErr) {
  120.             SetIdentityMatrix(&theMatrix);
  121.             MapMatrix(&theMatrix, srcRect, dstRect);
  122.             HLock(theHandle);
  123.             theErr = FDecompressImage(StripAddress(*theHandle), theDesc, dPixMap,
  124.                         srcRect, &theMatrix, tMode, qd.thePort->visRgn, nil, nil,
  125.                         codecMaxQuality, anyCodec, theSize, nil, nil);
  126.             HSetState(theHandle, hState);
  127.         }
  128.         DisposeHandle((Handle)theDesc);
  129.     } else theErr = memFullErr;
  130.     return theErr;
  131. }
  132.  
  133. //=====================================================================================
  134. // Handle UnwrapJPEG(Handle srcHandle)
  135. //=====================================================================================
  136. // Extracts (unwraps) the original JPEG data from a JPEG PICT image specified in
  137. // srcHandle.  If this function fails, it returns a nil handle.
  138. //=====================================================================================
  139.  
  140. extern Handle UnwrapJPEG(PicHandle srcHandle)
  141. {
  142.     long theSize = GetHandleSize((Handle)srcHandle);
  143.     char hState = HGetState((Handle)srcHandle);
  144.     Rect bounds = (*srcHandle)->picFrame;
  145.     CGrafPort tempPort;
  146.     CQDProcs theProcs;
  147.     GrafPtr oldPort;
  148.  
  149.     gJPEGDestHandle = nil;
  150.     HLockHi((Handle)srcHandle);
  151.     GetPort(&oldPort);
  152.     OpenCPort(&tempPort);
  153.     SetPort((GrafPtr)&tempPort);
  154.     SetStdCProcs(&theProcs);
  155.     if (!gUnwrapPixProc) InitJPEGUPPs();
  156.     theProcs.newProc1 = (UniversalProcPtr)gUnwrapPixProc;
  157.     theProcs.bitsProc = gDummyBitsProc;
  158.     theProcs.textProc = gDummyTextProc;
  159.     theProcs.lineProc = gDummyLineProc;
  160.     theProcs.rectProc = gDummyRectProc;
  161.     theProcs.rRectProc = gDummyRRectProc;
  162.     theProcs.ovalProc = gDummyOvalProc;
  163.     theProcs.arcProc = gDummyArcProc;
  164.     theProcs.polyProc = gDummyPolyProc;
  165.     theProcs.rgnProc = gDummyRgnProc;
  166.     tempPort.grafProcs = &theProcs;
  167.     DrawPicture(srcHandle, &bounds);
  168.     SetPort(oldPort);
  169.     CloseCPort(&tempPort);
  170.     HSetState((Handle)srcHandle, hState);
  171.     return gJPEGDestHandle;
  172. }
  173.  
  174. //=====================================================================================
  175. // Handle WrapJPEG(Handle srcHandle)
  176. //=====================================================================================
  177. // Wraps a JPEG image into a PICT.  If this function fails, it returns a nil handle.
  178. //=====================================================================================
  179.  
  180. extern PicHandle WrapJPEG(Handle srcHandle)
  181. {
  182.     long theSize = GetHandleSize(srcHandle);
  183.     char hState = HGetState(srcHandle);
  184.     ImageDescriptionHandle theDesc;
  185.     OpenCPicParams theParams;
  186.     PicHandle theHandle;
  187.     CGrafPort tempPort;
  188.     GrafPtr oldPort;
  189.     OSErr theErr;
  190.  
  191.     HLock(srcHandle);
  192.     if (theDesc = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription))) {
  193.         theErr = MakeJPEGImageDesc(srcHandle, theDesc);
  194.         if (theErr == noErr) {
  195.             theParams.srcRect.top = theParams.srcRect.left = 0;
  196.             theParams.srcRect.right = (*theDesc)->width;
  197.             theParams.srcRect.bottom = (*theDesc)->height;
  198.             theParams.hRes = (*theDesc)->hRes;
  199.             theParams.vRes = (*theDesc)->vRes;
  200.             theParams.version = -2;
  201.             theParams.reserved1 = theParams.reserved2 = 0;
  202.             GetPort(&oldPort);
  203.             OpenCPort(&tempPort);
  204.             SetPort((GrafPtr)&tempPort);
  205.             ClipRect(&theParams.srcRect);
  206.             if (theHandle = OpenCPicture(&theParams)) {
  207.                 theErr = FDecompressImage(StripAddress(*srcHandle), theDesc, 
  208.                             GetGWorldPixMap(&tempPort), &theParams.srcRect, nil, ditherCopy,
  209.                             nil, nil, nil, codecMaxQuality, anyCodec, theSize, nil, nil);
  210.                 ClosePicture();
  211.                 if (theErr == noErr && !EmptyRect(&(*(PicHandle)theHandle)->picFrame)) {
  212.                     CloseCPort(&tempPort);
  213.                     SetPort(oldPort);
  214.                     DisposeHandle((Handle)theDesc);
  215.                     HSetState(srcHandle, hState);
  216.                     return theHandle;
  217.                 }
  218.                 DisposeHandle((Handle)theHandle);
  219.             } else theErr = memFullErr;
  220.             CloseCPort(&tempPort);
  221.             SetPort(oldPort);
  222.         }
  223.         DisposeHandle((Handle)theDesc);
  224.     } else theErr = memFullErr;
  225.     HSetState(srcHandle, hState);
  226.     return nil;
  227. }
  228.  
  229. //=====================================================================================
  230. // void InitJPEGUPPs(void)
  231. //=====================================================================================
  232. // Initializes all the local UPPs for the JPEG callbacks.
  233. //=====================================================================================
  234.  
  235. static void InitJPEGUPPs(void)
  236. {
  237.     gUnwrapPixProc = NewStdPixProc((ProcPtr)UnwrapPixProc);
  238.     gDummyBitsProc = NewQDBitsProc((ProcPtr)DummyBitsProc);
  239.     gDummyTextProc = NewQDTextProc((ProcPtr)DummyTextProc);
  240.     gDummyLineProc = NewQDLineProc((ProcPtr)DummyLineProc);
  241.     gDummyRectProc = NewQDRectProc((ProcPtr)DummyRectProc);
  242.     gDummyRRectProc = NewQDRRectProc((ProcPtr)DummyRRectProc);
  243.     gDummyOvalProc = NewQDOvalProc((ProcPtr)DummyOvalProc);
  244.     gDummyArcProc = NewQDArcProc((ProcPtr)DummyArcProc);
  245.     gDummyPolyProc = NewQDPolyProc((ProcPtr)DummyPolyProc);
  246.     gDummyRgnProc = NewQDRgnProc((ProcPtr)DummyRgnProc);
  247. }
  248.  
  249. //=====================================================================================
  250. // unsigned char *GetJPEGData(unsigned char *theAdr, long theLen, unsigned char theCode)
  251. //=====================================================================================
  252. // Returns the address of the specified marker within the JPEG data stream.
  253. //=====================================================================================
  254.  
  255. static unsigned char *GetJPEGData(unsigned char *theAdr, long theLen, unsigned char theCode) 
  256. {
  257.     unsigned char *theEnd = theAdr + theLen;
  258.     long theSize;
  259.     
  260.     while (true) {
  261.         while (*theAdr++ != 0xff && theAdr < theEnd);
  262.         if (theAdr >= theEnd) return nil;
  263.         while (*theAdr == 0xff) theAdr++;
  264.         if (theAdr >= theEnd) return nil;
  265.         if (*theAdr == theCode) break;
  266.         else if (*theAdr == 0xd9) return nil;
  267.         else if (*theAdr <= 0x01 || (*theAdr >= 0xd0 && *theAdr <= 0xd8)) {
  268.             theAdr++;
  269.             continue;
  270.         }
  271.         theAdr++;
  272.         if ((theSize = (*theAdr << 8) + *(theAdr + 1)) < 0) return nil;
  273.         if ((theAdr + theSize) >= theEnd) {
  274.             *(theAdr - 1) = 0xd9;
  275.             return nil;
  276.         } else theAdr += theSize;
  277.     }
  278.     theAdr += 3;
  279.     return theAdr;
  280. }
  281.  
  282. //=====================================================================================
  283. // OSErr MakeJPEGImageDesc(Handle theHandle, ImageDescriptionHandle theDesc)
  284. //=====================================================================================
  285. // Creates a QuickTime image description record based on JPEG data.
  286. //=====================================================================================
  287.  
  288. static OSErr MakeJPEGImageDesc(Handle theHandle, ImageDescriptionHandle theDesc) 
  289. {
  290.     CodecInfo theInfo;
  291.     OSErr theErr;
  292.     Rect bounds;
  293.     
  294.     theErr = GetCodecInfo(&theInfo, 'jpeg', anyCodec);
  295.     if (theErr != noErr) return theErr;
  296.     theErr = GetJPEGBounds(theHandle, &bounds);
  297.     if (theErr != noErr) return theErr;
  298.     (*theDesc)->idSize = sizeof(ImageDescription);
  299.     (*theDesc)->cType = 'jpeg';
  300.     (*theDesc)->resvd1 = (*theDesc)->resvd2 = (*theDesc)->dataRefIndex = 0;
  301.     BlockMove(theInfo.typeName, (*theDesc)->name, 32);
  302.     (*theDesc)->version = theInfo.version;
  303.     (*theDesc)->revisionLevel = theInfo.revisionLevel;
  304.     (*theDesc)->vendor = theInfo.vendor;
  305.     (*theDesc)->temporalQuality = 0;
  306.     (*theDesc)->spatialQuality = 0x200L;
  307.     (*theDesc)->width = bounds.right;
  308.     (*theDesc)->height = bounds.bottom;
  309.     (*theDesc)->hRes = (*theDesc)->vRes = 0x480000L;
  310.     (*theDesc)->dataSize = GetHandleSize(theHandle);
  311.     (*theDesc)->frameCount = 1;
  312.     (*theDesc)->depth = 32;
  313.     (*theDesc)->clutID = -1;
  314.     return theErr;
  315. }
  316.  
  317. //=====================================================================================
  318. // pascal void UnwrapPixProc(PixMap *src, Rect *srcRect, MatrixRecord *matrix,
  319. //            short mode, RgnHandle mask, PixMap *matte, Rect *matteRect,
  320. //            short callOldBits)
  321. //=====================================================================================
  322. // Bottleneck function called to extract raw JPEG data from an image.
  323. //=====================================================================================
  324.  
  325. static pascal void UnwrapPixProc(PixMap *src, Rect *srcRect, MatrixRecord *matrix,
  326.             short mode, RgnHandle mask, PixMap *matte, Rect *matteRect,
  327.             short callOldBits)
  328. {
  329. #if applec
  330. #pragma unused(srcRect, matrix, mode, mask, matte, matteRect, callOldBits)
  331. #endif
  332.     long bufSize, left, offset = 0;
  333.     ImageDescriptionHandle theDesc;
  334.     ICMProgressProcRecord progProc;
  335.     ICMDataProcRecord dataProc;
  336.     Ptr theData, destAdr;
  337.     
  338.     if (!GetCompressedPixMapInfo(src, &theDesc, &theData, &bufSize, &dataProc, &progProc)) {
  339.         if ((*theDesc)->cType == 'jpeg' && !gJPEGDestHandle) {
  340.             if (gJPEGDestHandle = NewHandle((*theDesc)->dataSize)) {
  341.                 HLock(gJPEGDestHandle);
  342.                 destAdr = (Ptr)*gJPEGDestHandle;
  343.                 left = (*theDesc)->dataSize;
  344.                 if (dataProc.dataProc) {
  345.                     while (left > bufSize) {
  346.                         BlockMove(theData, &destAdr[offset], bufSize);
  347.                         offset += bufSize;
  348.                         left -= bufSize;
  349.                         theData += bufSize;
  350.                         if (CallICMDataProc(dataProc.dataProc, &theData, 
  351.                                     (left > bufSize) ? bufSize : left, 
  352.                                     dataProc.dataRefCon)) return;
  353.                     }
  354.                 }
  355.                 BlockMove(theData, &destAdr[offset], left);
  356.                 HUnlock(gJPEGDestHandle);
  357.             }
  358.         }
  359.     }
  360. }
  361.  
  362. //=====================================================================================
  363. // Dummy QuickDraw bottlenecks to filter out non-PixMaps within PICTs
  364. //=====================================================================================
  365.  
  366. static pascal void DummyBitsProc(PixMap *src, Rect *srcRect, Rect *dstRect, short mode, 
  367.             RgnHandle mask) 
  368. {
  369. #if applec
  370. #pragma unused(src, srcRect, dstRect, mode, mask)
  371. #endif
  372. }
  373.  
  374. static pascal void DummyTextProc(short count, const void *textAddr, Point numer,
  375.             Point denom) 
  376. {
  377. #if applec
  378. #pragma unused(count, textAddr, numer, denom)
  379. #endif
  380. }
  381.  
  382. static pascal void DummyLineProc(Point newPt)
  383. {
  384. #if applec
  385. #pragma unused(newPt)
  386. #endif
  387. }
  388.  
  389. static pascal void DummyRectProc(GrafVerb verb, const Rect *r)
  390. {
  391. #if applec
  392. #pragma unused(verb, r)
  393. #endif
  394. }
  395.  
  396. static pascal void DummyRRectProc(GrafVerb verb, const Rect *r, short ovalWidth, 
  397.     short ovalHeight)
  398. {
  399. #if applec
  400. #pragma unused(verb, r, ovalWidth, ovalHeight)
  401. #endif
  402. }
  403.  
  404. static pascal void DummyOvalProc(GrafVerb verb, const Rect *r)
  405. {
  406. #if applec
  407. #pragma unused(verb, r)
  408. #endif
  409. }
  410.  
  411. static pascal void DummyArcProc(GrafVerb verb, const Rect *r, short startAngle,
  412.             short arcAngle)
  413. {
  414. #if applec
  415. #pragma unused(verb, r, startAngle, arcAngle)
  416. #endif
  417. }
  418.  
  419. static pascal void DummyPolyProc(GrafVerb verb, PolyHandle poly)
  420. {
  421. #if applec
  422. #pragma unused(verb, poly)
  423. #endif
  424. }
  425.  
  426. static pascal void DummyRgnProc(GrafVerb verb, RgnHandle rgn)
  427. {
  428. #if applec
  429. #pragma unused(verb, rgn)
  430. #endif
  431. }
  432.