home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Simple Slideshow / JFIF-PICT.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-10-29  |  19.4 KB  |  824 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        JPEGtoPICT.c
  3.  
  4.     Written by:    Mark Krueger, Apple Computer, Inc.
  5.  
  6.     Contains:    Converts JPEG interchange files to JPEG PICT files, which can be used by any application.
  7.     
  8.     
  9.                 The JPEG File  Interchange Format ( JFIF) is a cross platform standard file format for
  10.                 storing JPEG compressed image files. This application shows you how you can easily convert
  11.                 these to QuickTime PICT format, or vice-verse. 
  12.                 
  13.                 You can use this in your application to open JFIF files directly or put a user interface 
  14.                 ( Drag and Drop would be cool ) on it to make a conversion program ). When files are to 
  15.                 be used on the Mac it is best to keep them in QTPict format so they can be easily copied
  16.                 and pasted, but JFIF format is useful for transfering data to other platforms that cannot
  17.                 use PICT formated JPEG images. 
  18.                 
  19.                 NOTE: the PICT to JFIF format translator is incomplete in that it only converts PICT
  20.                 files which are already in QuickTIme JPEG format and it does not handle banded JPEG
  21.                 Picts ( which may be commonly created by QuickTime applications which call 
  22.                 CompressPictureFile in low memory conditions or which create their own banded picts)
  23.                 To fully handle these images, the individual bands would have to be converted into a 
  24.                 single JPEG stream when put into JFIF format, and this code does not show you how
  25.                 to do that. 
  26.             
  27.  
  28.  
  29.  
  30. */
  31.  
  32.  
  33.  
  34. #include    <Types.h>
  35. #include    <Files.h>
  36. #include    <Quickdraw.h>
  37. #include    <GestaltEqu.h>
  38. #include    <Packages.h>
  39. #include    <Memory.h>
  40. #include    <Fonts.h>
  41. #include    <Events.h>
  42. #include    <OSUtils.h>
  43. #include    <ToolUtils.h>
  44. #include    <Menus.h>
  45. #include    <Dialogs.h>
  46. #include    <stdio.h>
  47. //#include    <Errors.h>
  48. #include    <string.h>
  49. #include    <StandardFile.h>
  50. #include    "Progress.h"
  51.  
  52.  
  53. #include    <ImageCompression.h>
  54. #include    <QDOffscreen.h>
  55. #include    "JFIFFile.h"
  56.  
  57. /************************************************
  58.  *
  59.  *    Make a new name for the compressed file ( illustrative only, this is not the recommended method ).
  60.  *
  61.  ************************************************/
  62.  
  63. void
  64. GetNewName(StringPtr newName,StringPtr oldName,StringPtr ext) 
  65. {
  66.     long    olen = oldName[0];
  67.  
  68.     if ( olen > (31-ext[0])  )
  69.         olen = 31-ext[0];
  70.     BlockMoveData(oldName+1,newName+1,olen);
  71.     BlockMoveData(ext+1,newName+1+olen,ext[0]);
  72.     newName[0] = olen + ext[0];
  73. }
  74.  
  75. /************************************************
  76.  *
  77.  *    Convert a JFIF file to a PICT .
  78.  *
  79.  ************************************************/
  80.  
  81.  
  82.  
  83. OSErr   ConvertFromJFIF(StringPtr name,short originalFile,PicHandle *thePicture)
  84. {
  85.     OSErr                    result = noErr;
  86.     short                     compressedFile = 0;
  87.     OpenCPicParams            header;
  88.     Str31                    newName;
  89.     CWindowPtr                window = nil;
  90.     Rect                    windRect;
  91.     long                    l;
  92.     short                    i;
  93.     char                    zero = 0;
  94.     MatrixRecord             matrix;
  95.  
  96.     Ptr                        data = nil;
  97.     ImageDescriptionHandle    desc = nil;
  98.     PicHandle                originalPicture = nil;
  99.     SFReply                    sfr;    
  100.     Point                    pt = {100,100};
  101.     
  102.     ICMProgressProcRecord    iProgRec = {NULL,0};
  103.     
  104.     /************************************************
  105.      *
  106.      *    Extract the JPEG data if possible and create Image Description.
  107.      *
  108.      ************************************************/
  109.  
  110.     if ((desc = ScanJPEG(originalFile,&data,&header)) == nil)
  111.     {
  112.         result = -50;
  113.         goto done;
  114.     }
  115.  
  116.     windRect = header.srcRect;
  117.     OffsetRect(&windRect,40,40);
  118.     
  119.     /************************************************
  120.      *
  121.      *    Create a window the size of the picture, and set our port to it.
  122.      *
  123.      ************************************************/
  124.     
  125. #ifdef    SHOW_IT        // make it visible if we want to see it before conversion
  126.  
  127.     if ((window = (CWindowPtr) NewCWindow(nil,&windRect,sfr.fName,true,0,(WindowPtr) -1L,false,0)) == nil)
  128.     {
  129.         result = -108;
  130.         goto done;
  131.     }
  132. #else    
  133.     if ((window = (CWindowPtr) NewCWindow(nil,&windRect,sfr.fName,false,0,(WindowPtr) -1L,false,0)) == nil)
  134.     {
  135.         result = -108;
  136.         goto done;
  137.     }
  138. #endif
  139.     SetPort((GrafPtr) window);
  140.         
  141.     originalPicture = OpenCPicture(&header);
  142.     
  143.     if (originalPicture == nil)
  144.     {
  145.         result = memFullErr;
  146.         goto done;    
  147.     }
  148.         
  149.     /************************************************
  150.      *
  151.      * we have to use the FDecompressImage call to make sure that the accuracy
  152.      * param gets set to highQuality which ensures a better quality decode
  153.      * and real dithering when going to 8-bit screens.
  154.      *
  155.      ************************************************/
  156.     /*
  157.     iProgRec.progressProc = NewICMProgressProc((ProcPtr) StdDecompressionProgressProc);
  158.     iProgRec.progressRefCon = 'open';    
  159.     */    
  160.     SetIdentityMatrix(&matrix);
  161.     
  162.     if ((result = FDecompressImage( data,desc,((CGrafPtr)qd.thePort)->portPixMap,
  163.                                     &header.srcRect,&matrix,ditherCopy,(RgnHandle)nil,
  164.                                     (PixMapHandle)nil,(Rect *)nil,codecMaxQuality,anyCodec,0,
  165.                                     (ICMDataProcRecordPtr)nil,(ICMProgressProcRecordPtr) NULL)))
  166.     {
  167.         ClosePicture();
  168.         KillPicture((PicHandle) originalPicture);
  169.         originalPicture = nil;
  170.         goto done;
  171.     }
  172.     ClosePicture();
  173.     if ( GetHandleSize((Handle)originalPicture) == sizeof(Picture) )
  174.     {
  175.         KillPicture((PicHandle)originalPicture);
  176.         originalPicture = nil;
  177.         result = memFullErr;
  178.         goto done;
  179.     }
  180.  
  181. #ifdef    SHOW_IT
  182.         
  183.     /************************************************
  184.      *
  185.      *        Draw the picture in the window, slid up to the top left corner.
  186.      *
  187.      ************************************************/
  188.     
  189.     DrawPicture(originalPicture,(*originalPicture)->pictureFrame);
  190. #endif
  191.  
  192.     if ( originalPicture )
  193.         *thePicture = originalPicture;
  194.     else
  195.         *thePicture = nil;
  196. done:
  197.     if (iProgRec.progressProc)
  198.         DisposeRoutineDescriptor(iProgRec.progressProc);
  199.     if ( data )
  200.         DisposPtr(data);
  201.     if ( desc ) 
  202.         DisposHandle((Handle)desc);
  203.     if ( window )
  204.         CloseWindow((WindowPtr)window);
  205.     return result;
  206. }
  207.  
  208. //#define    USE_DATA_LOADER
  209. #define    kDefaultBufferSize    (64L * 1024L)    // 64K buffer size
  210.  
  211.  
  212. OSErr    ReadJFIFToGWorld(short refNum,GWorldPtr*    theGWorld)
  213. {
  214.     // simpler and more robust function for reading JFIF images. Because this does not go through the step of
  215.     // decompressing the image to a picture, it requires less memory than the above function. It resizes the
  216.     // GWorld to the size of the image. This may alter the GWorld ptr value, so be sure to copy it back to any
  217.     // data structures that have reference to it- e.g. layers. 
  218.  
  219.     OSErr                    result = noErr;
  220.     OpenCPicParams            header;
  221.     Ptr                        data = NULL;
  222.     Handle                    tempBuffer = NULL;
  223.     ImageDescriptionHandle    desc = NULL;
  224.     GWorldFlags                flags;
  225.     PixMapHandle            ppix;
  226.     CGrafPtr                savePort;
  227.     GDHandle                saveDevice;
  228.     ICMProgressProcRecord    iProgRec = {NULL,0};
  229.     ICMDataProcRecord        dLoadProc = {NULL,0};
  230.     
  231.     #ifdef USE_DATA_LOADER
  232.         if ((desc = ScanJPEG(refNum,NULL,&header)) == NULL)
  233.         {
  234.             result = -50;
  235.             goto done;
  236.         }
  237.         (*desc)->dataSize = 0;
  238.     #else
  239.         if ((desc = ScanJPEG(refNum,&data,&header)) == NULL)
  240.         {
  241.             result = -50;
  242.             goto done;
  243.         }
  244.     #endif
  245.     // we have a description of the image. Now resize the GWorld and set its depth. Note that we do not
  246.     // call UpdateGWorld, but simply get rid of the existing one and reallocate it. This requires half the
  247.     // memory it otherwise would because no copy is required. This is ok because we are not attempting to keep
  248.     // the existing image anyway.
  249.     
  250.     if (*theGWorld)
  251.         DisposeGWorld(*theGWorld);
  252.     
  253.     result = NewImageGWorld(theGWorld,desc,0);
  254.     
  255.     if (result)
  256.         goto done;
  257.         
  258.     // we succeeded in changing the GWorld to the size we desire, now we simply decompress the data into
  259.     // the GWorld's pixmap. We load the JPEG data using a small buffer to save memory, so set this up here
  260.     
  261.     #ifdef USE_DATA_LOADER
  262.         dLoadProc.dataProc = NewICMDataProc((ProcPtr) JPEGDataLoader);
  263.         dLoadProc.dataRefCon = refNum;
  264.         result = SetFPos(refNum,fsFromStart,0);
  265.  
  266.         tempBuffer = NewHandleClear(kDefaultBufferSize);
  267.         if (tempBuffer == NULL)
  268.         {
  269.             result = memFullErr;
  270.             goto done;
  271.         }
  272.         else
  273.         {
  274.             MoveHHi(tempBuffer);
  275.             HLock(tempBuffer);
  276.         
  277.             data = StripAddress(*tempBuffer);
  278.         }
  279.     #endif
  280.  
  281.     iProgRec.progressProc = NewICMProgressProc((ProcPtr) StdDecompressionProgressProc);
  282.     iProgRec.progressRefCon = 'open';    
  283.     
  284.     if (LockPixels(ppix = GetGWorldPixMap(*theGWorld)))
  285.     {
  286.         GetGWorld(&savePort,&saveDevice);    
  287.         SetGWorld(*theGWorld,NULL);
  288.         
  289.     #ifdef USE_DATA_LOADER
  290.         result = FDecompressImage(  data,desc,ppix,
  291.                                     NULL,NULL,srcCopy + ditherCopy,(RgnHandle) NULL,
  292.                                     NULL,(Rect *) NULL,codecHighQuality,anyCodec,kDefaultBufferSize,
  293.                                     (ICMDataProcRecordPtr) &dLoadProc,
  294.                                     (ICMProgressProcRecordPtr) &iProgRec);
  295.     #else
  296.         result = FDecompressImage(  data,desc,ppix,
  297.                                     NULL,NULL,srcCopy + ditherCopy,(RgnHandle) NULL,
  298.                                     NULL,(Rect *) NULL,codecHighQuality,anyCodec,0,
  299.                                     (ICMDataProcRecordPtr) NULL,
  300.                                     (ICMProgressProcRecordPtr) &iProgRec);
  301.     #endif
  302.         SetGWorld(savePort,saveDevice);
  303.         UnlockPixels(ppix);
  304.     }
  305.     else
  306.         result = -50;
  307. done:
  308.     if (tempBuffer)
  309.     {
  310.         HUnlock(tempBuffer);
  311.         DisposHandle(tempBuffer);
  312.     }
  313.     if (desc) 
  314.         DisposHandle((Handle) desc);
  315.     if (iProgRec.progressProc)
  316.         DisposeRoutineDescriptor(iProgRec.progressProc);
  317.     if (dLoadProc.dataProc)
  318.         DisposeRoutineDescriptor(dLoadProc.dataProc);
  319.     return result;
  320. }
  321.  
  322.  
  323.  
  324. pascal OSErr    JPEGDataLoader(Ptr *dataP,long bytesNeeded,long refCon)
  325. {
  326.     OSErr    theErr = noErr;
  327.     short    fileRefNum = LoWord(refCon);
  328.     
  329.     if (dataP)
  330.         theErr = FSRead(fileRefNum,&bytesNeeded,*dataP);
  331.     else
  332.         theErr = SetFPos(fileRefNum,fsFromMark,bytesNeeded);
  333.     return theErr;
  334. }
  335.  
  336.  
  337. /************************************************
  338.  
  339.     Scan a file for valid JPEG data, and fill in a picture header and ImageDescription
  340.     for it.
  341.  
  342. *************************************************/
  343.  
  344. ImageDescriptionHandle    ScanJPEG(short originalFile,Ptr *data,OpenCPicParams *pictureHeader)
  345. {
  346.     short                     w,h;
  347.     ImageDescriptionHandle     desc;
  348.     long                    l;
  349.     char                    *bitStream,*scanData,*buffer;
  350.     long                    hRes = 72L<<16,vRes = 72L<<16;
  351.     short                    depth = 32;
  352.     
  353.     // this creates a buffer which holds the whole image. This is not very efficient. Instead we will spool
  354.     // the data in using a data loading procedure.
  355.     
  356.     
  357.     GetEOF(originalFile,&l);
  358.     if ((buffer = NewPtr(l)) == nil)
  359.         return(nil);
  360.  
  361.     FSRead(originalFile,&l,buffer);
  362.     bitStream = buffer;
  363.     
  364.     if ( (desc = (ImageDescriptionHandle) NewHandle(sizeof(ImageDescription))) == nil )
  365.         return(nil);
  366.  
  367.     if ( (scanData = MarkerDetect(bitStream,&w,&h,&hRes,&vRes,&depth)) == 0 )
  368.         return(nil);
  369.  
  370.     (*desc)->idSize = sizeof(ImageDescription);
  371.     (*desc)->width = w;
  372.     (*desc)->height = h;
  373.     (*desc)->temporalQuality = 0;
  374.     (*desc)->spatialQuality = codecNormalQuality;
  375.     (*desc)->dataSize = l;
  376.     (*desc)->cType = 'jpeg';
  377.     (*desc)->version = 0;
  378.     (*desc)->revisionLevel = 0;
  379.     (*desc)->vendor = 0;
  380.     (*desc)->hRes = hRes;
  381.     (*desc)->vRes = vRes;
  382.     (*desc)->depth = depth;
  383.     (*desc)->clutID = -1;
  384.     BlockMoveData("\pPhoto",(*desc)->name,6);
  385.     SetRect(&pictureHeader->srcRect,0,0,w,h);
  386.     pictureHeader->version = -2;
  387.     pictureHeader->reserved1 = 0;
  388.     pictureHeader->reserved2 = 0;
  389.     pictureHeader->hRes = hRes;
  390.     pictureHeader->vRes = vRes;
  391.     
  392.     if (data == NULL)
  393.     {
  394.         // get rid of this buffer- we are going to load the image in small pieces
  395.     
  396.         DisposePtr(buffer);
  397.     }
  398.     else
  399.         *data = buffer;
  400.         
  401.     return(desc);
  402. }
  403.  
  404.  
  405.  
  406. /**********************************************************************
  407.  
  408.     JPEG specific stuff.
  409.     
  410. ***********************************************************************/
  411.  
  412. /*
  413.  
  414.     JPEG Marker code definitions.
  415.     
  416. */
  417.  
  418. #define    MARKER_PREFIX    0xff
  419. #define    MARKER_SOI    0xd8        /* start of image */
  420. #define    MARKER_SOF    0xc0        /* start of frame */
  421. #define    MARKER_DHT    0xc4        /* define Huffman table */
  422. #define    MARKER_EOI    0xd9        /* end of image */
  423. #define    MARKER_SOS    0xda        /* start of scan */
  424. #define    MARKER_DQT    0xdb        /* define quantization tables */
  425. #define    MARKER_DNL    0xdc        /* define quantization tables */
  426. #define    MARKER_DRI    0xdd        /* define Huffman table */
  427. #define    MARKER_COM    0xfe        /* comment */
  428. #define MARKER_APP0    0xe0        
  429.  
  430.  
  431. /**********************************************************************
  432.  
  433.     Read the quantization table from the JPEG bitstream.
  434.     
  435. ***********************************************************************/
  436.  
  437. void 
  438. SwallowQuantTable(char *data)
  439. {
  440.     long    i;
  441.     long    length,pm,nm;
  442.  
  443.     length = *(short *)data;            /* read length */
  444.     length -= 2;
  445.     data += 2;
  446.     while ( length ) {
  447.         nm= *data++;                    /* read precision and number */
  448.         pm = nm>>4;    
  449.         nm &= 0xf;
  450.         length--;
  451.         if ( pm ) {
  452.             for(i=0;i<64;i++) {
  453.                 length -= 2;
  454.                 data += 2;
  455.             }
  456.         } else {
  457.             for(i=0;i<64;i++) {
  458.                 length--;
  459.                 data++;
  460.             }
  461.         }
  462.     }    
  463. }
  464.  
  465. /**********************************************************************
  466.  
  467.     Read the huffman table from the JPEG bitstream.
  468.     
  469. ***********************************************************************/
  470.  
  471. void 
  472. SwallowHuffTable(char *data)
  473. {
  474.     short    i,tc,id;
  475.     long    length;
  476.     
  477.     unsigned char    bin[17];
  478.     unsigned char    val[256];
  479.  
  480.     bin[0] = 0;
  481.     length = *(short *)data;            /* read length */
  482.     data += 2;
  483.     length -= 2;
  484.     while ( length ) {
  485.         id=*data++;                /* read id */
  486.         length--;
  487.         if ( id != 0 && id != 1 && id != 0x10 && id != 0x11) {
  488.             return;
  489.         }
  490.         tc = 0;
  491.         for(i=0;i<16;i++) {
  492.             length--;
  493.             tc += (bin[i+1] = *data++);
  494.         }
  495.         for (i=0; i < tc; i++ ) {
  496.             length--;
  497.             val[i] = *data++;
  498.         }
  499.     }
  500. }
  501.     
  502.     
  503.     
  504. /**********************************************************************
  505.  
  506.     Scan the JPEG stream for the proper markers and fill in the image parameters
  507.     
  508.     returns nil if it cant comprehend the data, otherwise a pointer to the start
  509.     of the JPEG data.
  510.     
  511.     
  512.     It does a cursory check on the JPEG data to see if it's reasonable.
  513.     Check out the ISO JPEG spec if you really want to know what's going on here.
  514.     
  515. ***********************************************************************/
  516.  
  517. char *
  518. MarkerDetect(char *data,short *width,short *height,long *hRes,long *vRes,short *depth)
  519. {
  520.     short    frame_field_length;
  521.     short    data_precision;
  522.     short    scan_field_length;
  523.     short    number_component,scan_components;
  524.     short    c1,hv1,q1,c2,hv2,q2,c3,hv3,q3;
  525.     short    dac_t1, dac_t2, dac_t3;
  526.     unsigned char    c;
  527.     short    qtabledefn;
  528.     short    htabledefn;
  529.     short    status;
  530.     short    length;
  531.     short    i;
  532.     
  533.     c = *data++;
  534.     qtabledefn = 0;
  535.     htabledefn = 0;
  536.     status = 0;
  537.     while (c != (unsigned char)MARKER_SOS) {
  538.         while (c != (unsigned char)MARKER_PREFIX)
  539.             c = *data++;                        /* looking for marker prefix bytes */
  540.         while (c == (unsigned char)MARKER_PREFIX)
  541.             c = *data++;                        /* (multiple?) marker prefix bytes */
  542.         if (c == 0)
  543.             continue;                                    /* 0 is never a marker code */
  544.  
  545.         if (c == (unsigned char)MARKER_SOF) {
  546.  
  547.             frame_field_length = *(short *)data;
  548.             data += 2;
  549.             data_precision = *data++;
  550.             
  551.             if ( data_precision != 8 ) { 
  552.                 status = 2;
  553.             }
  554.  
  555.             *height = *(short *)data;
  556.             data += 2;
  557.             *width = *(short *)data;
  558.             data += 2;
  559.                         
  560.             number_component = *data++;
  561.             
  562.             switch ( number_component  ) {
  563.             case 3:
  564.                 c1 = *data++;
  565.                 hv1 = *data++;
  566.                 q1 = *data++;
  567.                 c2 = *data++;
  568.                 hv2 = *data++;
  569.                 q2 = *data++;
  570.                 c3 = *data++;
  571.                 hv3 = *data++;
  572.                 q3 = *data++;
  573.                 *depth = 32;
  574.                 break;
  575.             case 1:        
  576.                 c1 = *data++;
  577.                 hv1 = *data++;
  578.                 q1 = *data++;
  579.                 *depth = 40;
  580.                 break;
  581.             default:
  582.                 status = 3;
  583.                 break;
  584.             }
  585.             continue;
  586.         }
  587.     
  588.         if (c == (unsigned char)MARKER_SOS) {
  589.             short tn;
  590.             scan_field_length = *(short *)data;
  591.             data += 2;
  592.             scan_components = *data++;
  593.             for ( i=0; i < scan_components; i++ ) {
  594.                 unsigned char cn,dac_t;
  595.                 
  596.                 cn = *data++;
  597.                 dac_t = *data++;
  598.                 if ( cn == c1 ) {
  599.                     dac_t1 = dac_t;
  600.                 } else if ( cn == c2 ) {
  601.                     dac_t2 = dac_t;
  602.                 } else if ( cn == c3 ) {
  603.                     dac_t3 = dac_t;
  604.                 } else {    
  605.                     status = 29;
  606.                     break;
  607.                 }
  608.             }
  609.             switch ( tn=(dac_t1 & 0xf) )  {
  610.             case 0:
  611.             case 1:
  612.                 break;
  613.             case 0xf:
  614.                 break;
  615.             default:
  616.                 status = 33;
  617.                 break;
  618.             }
  619.             switch (  tn=(dac_t2 & 0xf) )  {
  620.             case 0:
  621.             case 1:
  622.                 break;
  623.             case 0xf:
  624.                 break;
  625.             default:
  626.                 status = 33;
  627.                 break;
  628.             }
  629.             switch (  tn=(dac_t3 & 0xf) )  {
  630.             case 0:
  631.             case 1:
  632.                 break;
  633.             case 0xf:
  634.                 break;
  635.             default:
  636.                 status = 33;
  637.                 break;
  638.             }
  639.  
  640.  
  641.             /*  Initialize the DC tables */
  642.             
  643.             switch (  tn=dac_t1 & 0xf0 )  {
  644.             case 0:
  645.             case 0x10:
  646.                 break;
  647.             case 0xf0:
  648.                 break;
  649.             default:
  650.                 status = 34;
  651.                 break;
  652.             }
  653.             switch (  tn=dac_t2 & 0xf0 )  {
  654.             case 0:
  655.             case 0x10:
  656.                 break;
  657.             case 0xf0:
  658.                 break;
  659.             default:
  660.                 status = 34;
  661.                 break;
  662.             }
  663.             switch (  tn=dac_t3 & 0xf0 )  {
  664.             case 0:
  665.             case 0x10:
  666.                 break;
  667.             case 0xf0:
  668.                 break;
  669.             default:
  670.                 status = 34;
  671.                 break;
  672.             }
  673.             if ( *data++ != 0 )  {
  674. //                status = 18;
  675.             }
  676.             if ( *data++ != 63 )  {
  677. //                status = 19;
  678.             }
  679.             if ( *data++ != 0 ) {
  680. //                status = 20;
  681.             }
  682.             if ( status )
  683.                 return(0);
  684.             else
  685.                 return(data);
  686.         }
  687.  
  688.         if (c == (unsigned char)MARKER_DQT) {
  689.             scan_field_length = *(short *)data;
  690.             SwallowQuantTable(data);
  691.             data += scan_field_length;
  692.             continue;
  693.         }
  694.         if (c == (unsigned char)MARKER_DHT) {
  695.             scan_field_length = *(short *)data;
  696.             SwallowHuffTable(data);
  697.             continue;
  698.         }
  699.         if (c == (unsigned char)MARKER_DRI) {
  700.             length = *(short *)data;            /* read length */
  701.             data += 2;
  702.             length = *(short *)data;            
  703.             data += 2;
  704.             continue;
  705.         }
  706.         if (c == (unsigned char)MARKER_DNL) {
  707.             length = *(short *)data;            /* read length */
  708.             data += 2;
  709.             length = *(short *)data;            
  710.             data += 2;
  711.             continue;
  712.         }
  713.         if (c >= (unsigned char)0xD0 && c <= (unsigned char)0xD7) {
  714.             continue;
  715.         }
  716.  
  717.         if (c == (unsigned char)MARKER_SOI || c == (unsigned char)MARKER_EOI)    /* image start, end marker */
  718.             continue;
  719.  
  720.         if ( (c >= (unsigned char)0xC1 && c <= (unsigned char)0xcF) || (c == (unsigned char)0xde) || (c == (unsigned char)0xdf) ) {
  721.             status = 12;
  722.             length = *(short *)data;            /* read length */
  723.             data += length;
  724.             continue;
  725.         }
  726.         if (c >= (unsigned char)MARKER_APP0 && c <= (unsigned char)0xEF) {
  727.             length = *(short *)data;            /* read length */
  728.             data += 2;
  729.             length -= 2;
  730.             if ( (c == (unsigned char)MARKER_APP0) && length > 5 ) { /* check for JFIF marker */
  731.                 char buf[5];
  732.                 buf[0] = *data++;
  733.                 buf[1] = *data++;
  734.                 buf[2] = *data++;
  735.                 buf[3] = *data++;
  736.                 buf[4] = *data++;
  737.                 length -= 5;
  738.                 
  739.                 if ( buf[0] == 'J' && buf[1] == 'F'  && buf[2] == 'I'  && buf[3] == 'F' ) {
  740.                     short    units;
  741.                     long    xres,yres;
  742.                     short    version;
  743.                     
  744.                     
  745.                     version = *(short *)data; data += 2;length -= 2;
  746.                     if ( version != 0x100 && version != 0x101 && version != 0x102) {
  747.                         status = 44;        // unknown JFIF version
  748.                         break;
  749.                     }
  750.                     units = *data++; length--;
  751.                     xres = *(short *)data; data += 2; length -= 2;
  752.                     yres = *(short *)data; data += 2; length -= 2;
  753.  
  754.                     switch ( units ) {
  755.                     case 0:            // no res, just aspect ratio
  756.                         // some files will have bad res data here. In this case, xRes & yRes will
  757.                         // be zero. This really means that they should be 1! This allows some dodgy
  758.                         // JPEGs created by some crappy PC software to be opened
  759.                         
  760.                         if (xres == 0)
  761.                             xres = 1;
  762.                         if (yres == 0)
  763.                             yres = 1;
  764.                     
  765.                         *hRes = FixMul(72L<<16,xres<<16);
  766.                         *vRes = FixMul(72L<<16,yres<<16);
  767.                         break;
  768.                     case 1:            // dots per inch
  769.                         *hRes = xres<<16;
  770.                         *vRes = yres<<16;
  771.                         break;
  772.                     case 2:            // dots per centimeter (we convert to dpi )
  773.                         *hRes = FixMul(0x28a3d,xres<<16);
  774.                         *vRes = FixMul(0x28a3d,xres<<16);
  775.                         break;    
  776.                     default:
  777.                         break;
  778.                     }
  779.                     xres = *data++; length--;
  780.                     yres = *data++; length--;
  781.                     
  782.                     /* skip JFIF thumbnail */
  783.                     
  784.                     xres *= yres;
  785.                     data += xres*3; length -= xres*3;
  786.                     
  787.                     if (  length != 0 ) {
  788.                         status = 44;        // bad jfif marker
  789.                         break;
  790.                     }
  791.                 }
  792.             }
  793.             data += length;
  794.             continue;
  795.         }
  796.         if (c == (unsigned char)MARKER_COM) {
  797.             length = *(short *)data;            /* read length */
  798.             data += length;
  799.             continue;
  800.         }
  801.         if (c >= (unsigned char)0xf0 && c <= (unsigned char)0xfd) {
  802.             length = *(short *)data;            /* read length */
  803.             data += length;
  804.             continue;
  805.         }
  806.         if ( c == 0x1 )
  807.             continue;
  808.         if ( (c >= (unsigned char)0x2 && c <= (unsigned char)0xbF) ) {
  809.             length = *(short *)data;            /* read length */
  810.             status = 13;
  811.             data += length;
  812.             continue;
  813.         }
  814.     }
  815.     return(0);
  816. }
  817.  
  818.  
  819.     
  820.  
  821.  
  822.  
  823.  
  824.