home *** CD-ROM | disk | FTP | other *** search
/ QuickTime 2.0 Developer Kit / QuickTime 2.0 Developer Kit.iso / mac / MAC / Programming Stuff / Sample Code / Movie Data Exchange / JPEG File Interchange Format / JFIF Translator / JFIF-PICT.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-21  |  26.0 KB  |  1,200 lines  |  [TEXT/MPS ]

  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.  
  51.  
  52.  
  53. #include    <ImageCompression.h>
  54.  
  55. /************************************************
  56.  *
  57.  *    Function prototypes.
  58.  *
  59.  ************************************************/
  60.  
  61.  
  62.  
  63.  
  64. void
  65. Initialize();
  66.  
  67. char *
  68. MarkerDetect(char *data,short *width,short *height,long *hRes,long *vRes,short *depth);
  69.  
  70. void 
  71. SwallowHuffTable(char *data);
  72.  
  73. void 
  74. SwallowQuantTable(char *data);
  75.  
  76. void
  77. GetNewName(StringPtr newName,StringPtr oldName,StringPtr ext);
  78.  
  79. ImageDescriptionHandle
  80. ScanJPEG(short originalFile,Ptr *data,OpenCPicParams *pictureHeader);
  81.  
  82. OSErr
  83. ConvertFromJFIF(StringPtr name,short originalFile);
  84.  
  85. OSErr
  86. ConvertToJFIF(StringPtr name,short originalFile);
  87.  
  88.  
  89. pascal void
  90. StdPixExtract(PixMap *src,Rect *srcRect,MatrixRecord matrix,short mode,RgnHandle mask,PixMap *matte,
  91.     Rect *matteRect,short flags);
  92.     
  93.     
  94.  
  95. /************************************************
  96.  *
  97.  *    Set up application environment.
  98.  *
  99.  ************************************************/
  100.  
  101.  
  102. void
  103. Initialize()
  104.  
  105. {
  106.     long    resp;
  107.     
  108.     
  109.     MaxApplZone();
  110.     InitGraf(&qd.thePort);
  111.     InitFonts();
  112.     InitWindows();
  113.     InitMenus();
  114.     InitDialogs(nil);
  115.     InitCursor();
  116.     if ( Gestalt(gestaltCompressionMgr, &resp) != noErr || resp < 15 ) {
  117.         SysBeep(1);
  118.         ExitToShell();
  119.     }
  120.     
  121. }
  122.  
  123.  
  124. /************************************************
  125.  *
  126.  *    Make a new name for the compressed file ( illustrative only, this is not the recommended method ).
  127.  *
  128.  ************************************************/
  129.  
  130. void
  131. GetNewName(StringPtr newName,StringPtr oldName,StringPtr ext) 
  132. {
  133.     long    olen = oldName[0];
  134.  
  135.     if ( olen > (31-ext[0])  )
  136.         olen = 31-ext[0];
  137.     BlockMove(oldName+1,newName+1,olen);
  138.     BlockMove(ext+1,newName+1+olen,ext[0]);
  139.     newName[0] = olen + ext[0];
  140. }
  141.  
  142.  
  143.     
  144.  
  145. /************************************************
  146.  *
  147.  *    Our program.
  148.  *
  149.  ************************************************/
  150.  
  151.  
  152. main()
  153.  
  154. {
  155.  
  156.     short        originalFile;
  157.     Point        pt = {100,100};
  158.     SFReply        sfr;    
  159.     SFTypeList     types = { 'JFIF','JPEG','????','PICT' };
  160.     OSErr        result = 0;
  161.  
  162.     /************************************************
  163.      *
  164.      *    Initialize everything, and then do it. Notice
  165.      *    the wonderful HIG conformant user interface.
  166.      *
  167.      ************************************************/
  168.  
  169.     
  170.     Initialize();
  171.  
  172.  
  173.     while ( 1 ) {
  174.     
  175.  
  176.  
  177.     /************************************************
  178.      *
  179.      *    Ask for a input file
  180.      *
  181.      ************************************************/
  182.         
  183.         SFGetFilePreview(pt,nil,nil,4,types,nil,&sfr);
  184.         if ( !sfr.good  )
  185.             break;
  186.  
  187.  
  188.  
  189.     /************************************************
  190.      *
  191.      *    Open the file, if we can.
  192.      *
  193.      ************************************************/
  194.     
  195.         if ( (result=FSOpen(sfr.fName,sfr.vRefNum,&originalFile)) != noErr ) {
  196.             break;
  197.         }
  198.  
  199.  
  200.         if ( sfr.fType == 'PICT' ) {
  201.         
  202.             if ( result=ConvertToJFIF(sfr.fName,originalFile) )
  203.                 break;
  204.             
  205.         } else {
  206.             
  207.             if ( result=ConvertFromJFIF(sfr.fName,originalFile) )
  208.                 break;
  209.         
  210.         }
  211.     }
  212.     if ( result )
  213.         SysBeep(1);
  214. }
  215.  
  216.  
  217. /************************************************
  218.  *
  219.  *    Convert a JFIF file to a PICT file.
  220.  *
  221.  ************************************************/
  222.  
  223.  
  224.  
  225. OSErr
  226. ConvertFromJFIF(StringPtr name,short originalFile)
  227. {
  228.     OSErr    result = 0;
  229.     short compressedFile = 0;
  230.     OpenCPicParams    header;
  231.     Str31        newName;
  232.     CWindowPtr    window = nil;
  233.     Rect        windRect;
  234.     long        l;
  235.     short        i;
  236.     char        zero=0;
  237.     MatrixRecord matrix;
  238.  
  239.     Ptr            data = nil;
  240.     ImageDescriptionHandle    desc = nil;
  241.     PicHandle    originalPicture = nil;
  242.     SFReply        sfr;    
  243.     Point        pt = {100,100};
  244.     
  245.     
  246.     
  247.     /************************************************
  248.      *
  249.      *    Extract the JPEG data if possible and create Image Description.
  250.      *
  251.      ************************************************/
  252.  
  253.     if ( (desc=ScanJPEG(originalFile,&data,&header)) == 0 ) {
  254.         result = -50;
  255.         goto done;
  256.     }
  257.  
  258.  
  259.  
  260.     windRect = header.srcRect;
  261.     OffsetRect(&windRect,40,40);
  262.     
  263.  
  264.     /************************************************
  265.      *
  266.      *    Create a window the size of the picture, and set our port to it.
  267.      *
  268.      ************************************************/
  269.     
  270. #ifdef    SHOW_IT        // make it visible if we want to see it before conversion
  271.  
  272.     if ( (window = (CWindowPtr)NewCWindow(nil,&windRect,sfr.fName,true,0,(WindowPtr)-1,false,0)) == nil ) {
  273.         result = -108;
  274.         goto done;
  275.     }
  276. #else    
  277.  
  278.     if ( (window = (CWindowPtr)NewCWindow(nil,&windRect,sfr.fName,false,0,(WindowPtr)-1,false,0)) == nil ) {
  279.         result = -108;
  280.         goto done;
  281.     }
  282. #endif
  283.     SetPort((GrafPtr)window);
  284.         
  285.     originalPicture = OpenCPicture(&header);
  286.         
  287.         
  288.     /************************************************
  289.      *
  290.      * we have to use the FDecompressImage call to make sure that the accuracy
  291.      * param gets set to highQuality which ensures a better quality decode
  292.      * and real dithering when going to 8-bit screens.
  293.      *
  294.      ************************************************/
  295.         
  296.         
  297.     SetIdentityMatrix(&matrix);
  298.     
  299.     if ( (result=FDecompressImage(data,desc,((CGrafPtr)qd.thePort)->portPixMap,
  300.             &header.srcRect,&matrix,ditherCopy,(RgnHandle)nil,
  301.             (PixMapHandle)nil,(Rect *)nil,codecHighQuality,anyCodec,0,
  302.             (DataProcRecordPtr)nil,(ProgressProcRecordPtr)nil)) ){
  303.         ClosePicture();
  304.         KillPicture((PicHandle)originalPicture);
  305.         originalPicture = nil;
  306.         goto done;
  307.     }
  308.     ClosePicture();
  309.     if ( GetHandleSize((Handle)originalPicture) == sizeof(Picture) ) {
  310.         KillPicture((PicHandle)originalPicture);
  311.         originalPicture = nil;
  312.         goto done;
  313.     }
  314.  
  315. #ifdef    SHOW_IT
  316.         
  317.     /************************************************
  318.      *
  319.      *        Draw the picture in the window, slid up to the top left corner.
  320.      *
  321.      ************************************************/
  322.     
  323.     DrawPicture(originalPicture,(*originalPicture)->pictureFrame);
  324.  
  325.  
  326. #endif
  327.  
  328.     /************************************************
  329.      *
  330.      *        Ask her for the name of the new file.
  331.      *
  332.      ************************************************/
  333.  
  334.     
  335.     GetNewName(newName,name,"\p Pict");
  336.     SFPutFile(pt,nil,newName,NULL,&sfr);
  337.     if ( !sfr.good )  {
  338.         goto done;
  339.     }
  340.     BlockMove(sfr.fName,newName,32);
  341.     
  342.     /************************************************
  343.      *
  344.      *    Create the new file, if we can.
  345.      *
  346.      ************************************************/
  347.     
  348.     FSDelete(sfr.fName,sfr.vRefNum);
  349.     if ( (result=Create(sfr.fName,sfr.vRefNum,'ppxi','PICT')) != noErr ) {
  350.         goto done;
  351.     }
  352.     if ( (result=FSOpen(sfr.fName,sfr.vRefNum,&compressedFile)) != noErr ) {
  353.         goto done;
  354.     }
  355.         
  356.     /************************************************
  357.      *
  358.      * write the silly 512 bytes of zero needed at the start of a PICT file
  359.      *
  360.      ************************************************/
  361.         
  362.     SetFPos(compressedFile,fsFromStart,512);
  363.     l = 1;
  364.     for ( i=0; i < 512; i++) {
  365.         if ( (result=FSWrite(compressedFile,&l,&zero)) )
  366.             break;
  367.     }
  368.     
  369.     /************************************************
  370.      *
  371.      * write the QuickTime picture data.
  372.      *
  373.      ************************************************/
  374.  
  375.     l = GetHandleSize((Handle)originalPicture);
  376.         
  377.     HLock((Handle)originalPicture);
  378.     result=FSWrite(compressedFile,&l,*originalPicture);
  379.     
  380.  
  381. done:    
  382.     FSClose(originalFile);
  383.     if ( compressedFile )  {
  384.         FSClose(compressedFile);
  385.         if ( result != noErr )
  386.             FSDelete(sfr.fName,sfr.vRefNum);
  387.         FlushVol(nil,sfr.vRefNum);
  388.     }
  389.     if ( originalPicture )
  390.         KillPicture(originalPicture);
  391.     if ( data )
  392.         DisposPtr(data);
  393.     if ( desc ) 
  394.         DisposHandle((Handle)desc);
  395.     if ( window )
  396.         CloseWindow((WindowPtr)window);
  397.     return result;
  398. }
  399.  
  400.  
  401. /************************************************
  402.  
  403.     Scan a file for valid JPEG data, and fill in a picture header and ImageDescription
  404.     for it.
  405.  
  406. *************************************************/
  407.  
  408. ImageDescriptionHandle
  409. ScanJPEG(short originalFile,Ptr *data,OpenCPicParams *pictureHeader)
  410.  
  411. {
  412.     short w,h;
  413.     ImageDescriptionHandle desc;
  414.     long    l;
  415.     char    *bitStream,*scanData,*buffer;
  416.     long    hRes = 72L<<16,vRes = 72L<<16;
  417.     short    depth = 32;
  418.     
  419.     GetEOF(originalFile,&l);
  420.     if ( (buffer= NewPtr(l)) == nil ) {
  421.         return(0);
  422.     }
  423.     FSRead(originalFile,&l,buffer);
  424.     bitStream = buffer;
  425.     
  426.     if ( (desc = (ImageDescriptionHandle)NewHandle(sizeof(ImageDescription))) == nil ) {
  427.         return(0);
  428.     }
  429.     if ( (scanData=MarkerDetect(bitStream,&w,&h,&hRes,&vRes,&depth)) == 0 ) {
  430.         return(0);
  431.     }
  432.     (*desc)->idSize = sizeof(ImageDescription);
  433.     (*desc)->width = w;
  434.     (*desc)->height = h;
  435.     (*desc)->temporalQuality = 0;
  436.     (*desc)->spatialQuality = codecNormalQuality;
  437.     (*desc)->dataSize = l;
  438.     (*desc)->cType = 'jpeg';
  439.     (*desc)->version = 0;
  440.     (*desc)->revisionLevel = 0;
  441.     (*desc)->vendor = 0;
  442.     (*desc)->hRes = hRes;
  443.     (*desc)->vRes = vRes;
  444.     (*desc)->depth = depth;
  445.     (*desc)->clutID = -1;
  446.     BlockMove("\pPhoto",(*desc)->name,6);
  447.     SetRect(&pictureHeader->srcRect,0,0,w,h);
  448.     pictureHeader->version = -2;
  449.     pictureHeader->reserved1 = 0;
  450.     pictureHeader->reserved2 = 0;
  451.     pictureHeader->hRes = hRes;
  452.     pictureHeader->vRes = vRes;
  453.     *data = bitStream;
  454.     return(desc);
  455. }
  456.  
  457.  
  458.  
  459. /**********************************************************************
  460.  
  461.     JPEG specific stuff.
  462.     
  463. ***********************************************************************/
  464.  
  465. /*
  466.  
  467.     JPEG Marker code definitions.
  468.     
  469. */
  470.  
  471. #define    MARKER_PREFIX    0xff
  472. #define    MARKER_SOI    0xd8        /* start of image */
  473. #define    MARKER_SOF    0xc0        /* start of frame */
  474. #define    MARKER_DHT    0xc4        /* define Huffman table */
  475. #define    MARKER_EOI    0xd9        /* end of image */
  476. #define    MARKER_SOS    0xda        /* start of scan */
  477. #define    MARKER_DQT    0xdb        /* define quantization tables */
  478. #define    MARKER_DNL    0xdc        /* define quantization tables */
  479. #define    MARKER_DRI    0xdd        /* define Huffman table */
  480. #define    MARKER_COM    0xfe        /* comment */
  481. #define MARKER_APP0    0xe0        
  482.  
  483.  
  484. /**********************************************************************
  485.  
  486.     Read the quantization table from the JPEG bitstream.
  487.     
  488. ***********************************************************************/
  489.  
  490. void 
  491. SwallowQuantTable(char *data)
  492. {
  493.     long    i;
  494.     long    length,pm,nm;
  495.  
  496.     length = *(short *)data;            /* read length */
  497.     length -= 2;
  498.     data += 2;
  499.     while ( length ) {
  500.         nm= *data++;                    /* read precision and number */
  501.         pm = nm>>4;    
  502.         nm &= 0xf;
  503.         length--;
  504.         if ( pm ) {
  505.             for(i=0;i<64;i++) {
  506.                 length -= 2;
  507.                 data += 2;
  508.             }
  509.         } else {
  510.             for(i=0;i<64;i++) {
  511.                 length--;
  512.                 data++;
  513.             }
  514.         }
  515.     }    
  516. }
  517.  
  518. /**********************************************************************
  519.  
  520.     Read the huffman table from the JPEG bitstream.
  521.     
  522. ***********************************************************************/
  523.  
  524. void 
  525. SwallowHuffTable(char *data)
  526. {
  527.     short    i,tc,id;
  528.     long    length;
  529.     
  530.     unsigned char    bin[17];
  531.     unsigned char    val[256];
  532.  
  533.     bin[0] = 0;
  534.     length = *(short *)data;            /* read length */
  535.     data += 2;
  536.     length -= 2;
  537.     while ( length ) {
  538.         id=*data++;                /* read id */
  539.         length--;
  540.         if ( id != 0 && id != 1 && id != 0x10 && id != 0x11) {
  541.             return;
  542.         }
  543.         tc = 0;
  544.         for(i=0;i<16;i++) {
  545.             length--;
  546.             tc += (bin[i+1] = *data++);
  547.         }
  548.         for (i=0; i < tc; i++ ) {
  549.             length--;
  550.             val[i] = *data++;
  551.         }
  552.     }
  553. }
  554.     
  555.     
  556.     
  557. /**********************************************************************
  558.  
  559.     Scan the JPEG stream for the proper markers and fill in the image parameters
  560.     
  561.     returns nil if it cant comprehend the data, otherwise a pointer to the start
  562.     of the JPEG data.
  563.     
  564.     
  565.     It does a cursory check on the JPEG data to see if it's reasonable.
  566.     Check out the ISO JPEG spec if you really want to know what's going on here.
  567.     
  568. ***********************************************************************/
  569.  
  570. char *
  571. MarkerDetect(char *data,short *width,short *height,long *hRes,long *vRes,short *depth)
  572. {
  573.     short    frame_field_length;
  574.     short    data_precision;
  575.     short    scan_field_length;
  576.     short    number_component,scan_components;
  577.     short    c1,hv1,q1,c2,hv2,q2,c3,hv3,q3;
  578.     short    dac_t1, dac_t2, dac_t3;
  579.     unsigned char    c;
  580.     short    qtabledefn;
  581.     short    htabledefn;
  582.     short    status;
  583.     short    length;
  584.     short    i;
  585.     
  586.     c = *data++;
  587.     qtabledefn = 0;
  588.     htabledefn = 0;
  589.     status = 0;
  590.     while (c != (unsigned char)MARKER_SOS) {
  591.         while (c != (unsigned char)MARKER_PREFIX)
  592.             c = *data++;                        /* looking for marker prefix bytes */
  593.         while (c == (unsigned char)MARKER_PREFIX)
  594.             c = *data++;                        /* (multiple?) marker prefix bytes */
  595.         if (c == 0)
  596.             continue;                                    /* 0 is never a marker code */
  597.  
  598.         if (c == (unsigned char)MARKER_SOF) {
  599.  
  600.             frame_field_length = *(short *)data;
  601.             data += 2;
  602.             data_precision = *data++;
  603.             
  604.             if ( data_precision != 8 ) { 
  605.                 status = 2;
  606.             }
  607.  
  608.             *height = *(short *)data;
  609.             data += 2;
  610.             *width = *(short *)data;
  611.             data += 2;
  612.                         
  613.             number_component = *data++;
  614.             
  615.             switch ( number_component  ) {
  616.             case 3:
  617.                 c1 = *data++;
  618.                 hv1 = *data++;
  619.                 q1 = *data++;
  620.                 c2 = *data++;
  621.                 hv2 = *data++;
  622.                 q2 = *data++;
  623.                 c3 = *data++;
  624.                 hv3 = *data++;
  625.                 q3 = *data++;
  626.                 *depth = 32;
  627.                 break;
  628.             case 1:        
  629.                 c1 = *data++;
  630.                 hv1 = *data++;
  631.                 q1 = *data++;
  632.                 *depth = 40;
  633.                 break;
  634.             default:
  635.                 status = 3;
  636.                 break;
  637.             }
  638.             continue;
  639.         }
  640.     
  641.         if (c == (unsigned char)MARKER_SOS) {
  642.             short tn;
  643.             scan_field_length = *(short *)data;
  644.             data += 2;
  645.             scan_components = *data++;
  646.             for ( i=0; i < scan_components; i++ ) {
  647.                 unsigned char cn,dac_t;
  648.                 
  649.                 cn = *data++;
  650.                 dac_t = *data++;
  651.                 if ( cn == c1 ) {
  652.                     dac_t1 = dac_t;
  653.                 } else if ( cn == c2 ) {
  654.                     dac_t2 = dac_t;
  655.                 } else if ( cn == c3 ) {
  656.                     dac_t3 = dac_t;
  657.                 } else {    
  658.                     status = 29;
  659.                     break;
  660.                 }
  661.             }
  662.             switch ( tn=(dac_t1 & 0xf) )  {
  663.             case 0:
  664.             case 1:
  665.                 break;
  666.             case 0xf:
  667.                 break;
  668.             default:
  669.                 status = 33;
  670.                 break;
  671.             }
  672.             switch (  tn=(dac_t2 & 0xf) )  {
  673.             case 0:
  674.             case 1:
  675.                 break;
  676.             case 0xf:
  677.                 break;
  678.             default:
  679.                 status = 33;
  680.                 break;
  681.             }
  682.             switch (  tn=(dac_t3 & 0xf) )  {
  683.             case 0:
  684.             case 1:
  685.                 break;
  686.             case 0xf:
  687.                 break;
  688.             default:
  689.                 status = 33;
  690.                 break;
  691.             }
  692.  
  693.  
  694.             /*  Initialize the DC tables */
  695.             
  696.             switch (  tn=dac_t1 & 0xf0 )  {
  697.             case 0:
  698.             case 0x10:
  699.                 break;
  700.             case 0xf0:
  701.                 break;
  702.             default:
  703.                 status = 34;
  704.                 break;
  705.             }
  706.             switch (  tn=dac_t2 & 0xf0 )  {
  707.             case 0:
  708.             case 0x10:
  709.                 break;
  710.             case 0xf0:
  711.                 break;
  712.             default:
  713.                 status = 34;
  714.                 break;
  715.             }
  716.             switch (  tn=dac_t3 & 0xf0 )  {
  717.             case 0:
  718.             case 0x10:
  719.                 break;
  720.             case 0xf0:
  721.                 break;
  722.             default:
  723.                 status = 34;
  724.                 break;
  725.             }
  726.             if ( *data++ != 0 )  {
  727. //                status = 18;
  728.             }
  729.             if ( *data++ != 63 )  {
  730. //                status = 19;
  731.             }
  732.             if ( *data++ != 0 ) {
  733. //                status = 20;
  734.             }
  735.             if ( status )
  736.                 return(0);
  737.             else
  738.                 return(data);
  739.         }
  740.  
  741.         if (c == (unsigned char)MARKER_DQT) {
  742.             scan_field_length = *(short *)data;
  743.             SwallowQuantTable(data);
  744.             data += scan_field_length;
  745.             continue;
  746.         }
  747.         if (c == (unsigned char)MARKER_DHT) {
  748.             scan_field_length = *(short *)data;
  749.             SwallowHuffTable(data);
  750.             continue;
  751.         }
  752.         if (c == (unsigned char)MARKER_DRI) {
  753.             length = *(short *)data;            /* read length */
  754.             data += 2;
  755.             length = *(short *)data;            
  756.             data += 2;
  757.             continue;
  758.         }
  759.         if (c == (unsigned char)MARKER_DNL) {
  760.             length = *(short *)data;            /* read length */
  761.             data += 2;
  762.             length = *(short *)data;            
  763.             data += 2;
  764.             continue;
  765.         }
  766.         if (c >= (unsigned char)0xD0 && c <= (unsigned char)0xD7) {
  767.             continue;
  768.         }
  769.  
  770.         if (c == (unsigned char)MARKER_SOI || c == (unsigned char)MARKER_EOI)    /* image start, end marker */
  771.             continue;
  772.  
  773.         if ( (c >= (unsigned char)0xC1 && c <= (unsigned char)0xcF) || (c == (unsigned char)0xde) || (c == (unsigned char)0xdf) ) {
  774.             status = 12;
  775.             length = *(short *)data;            /* read length */
  776.             data += length;
  777.             continue;
  778.         }
  779.         if (c >= (unsigned char)MARKER_APP0 && c <= (unsigned char)0xEF) {
  780.             length = *(short *)data;            /* read length */
  781.             data += 2;
  782.             length -= 2;
  783.             if ( (c == (unsigned char)MARKER_APP0) && length > 5 ) { /* check for JFIF marker */
  784.                 char buf[5];
  785.                 buf[0] = *data++;
  786.                 buf[1] = *data++;
  787.                 buf[2] = *data++;
  788.                 buf[3] = *data++;
  789.                 buf[4] = *data++;
  790.                 length -= 5;
  791.                 
  792.                 if ( buf[0] == 'J' && buf[1] == 'F'  && buf[2] == 'I'  && buf[3] == 'F' ) {
  793.                     short    units;
  794.                     long    xres,yres;
  795.                     short    version;
  796.                     
  797.                     
  798.                     version = *(short *)data; data += 2;length -= 2;
  799.                     if ( version != 0x100 && version != 0x101 ) {
  800.                         status = 44;        // unknown JFIF version
  801.                         break;
  802.                     }
  803.                     units = *data++; length--;
  804.                     xres = *(short *)data; data += 2; length -= 2;
  805.                     yres = *(short *)data; data += 2; length -= 2;
  806.  
  807.                     switch ( units ) {
  808.                     case 0:            // no res, just aspect ratio
  809.                         *hRes = FixMul(72L<<16,xres<<16);
  810.                         *vRes = FixMul(72L<<16,yres<<16);
  811.                         break;
  812.                     case 1:            // dots per inch
  813.                         *hRes = xres<<16;
  814.                         *vRes = yres<<16;
  815.                         break;
  816.                     case 2:            // dots per centimeter (we convert to dpi )
  817.                         *hRes = FixMul(0x28a3d,xres<<16);
  818.                         *vRes = FixMul(0x28a3d,xres<<16);
  819.                         break;    
  820.                     default:
  821.                         break;
  822.                     }
  823.                     xres = *data++; length--;
  824.                     yres = *data++; length--;
  825.                     
  826.                     /* skip JFIF thumbnail */
  827.                     
  828.                     xres *= yres;
  829.                     data += xres*3; length -= xres*3;
  830.                     
  831.                     if (  length != 0 ) {
  832.                         status = 44;        // bad jfif marker
  833.                         break;
  834.                     }
  835.                 }
  836.             }
  837.             data += length;
  838.             continue;
  839.         }
  840.         if (c == (unsigned char)MARKER_COM) {
  841.             length = *(short *)data;            /* read length */
  842.             data += length;
  843.             continue;
  844.         }
  845.         if (c >= (unsigned char)0xf0 && c <= (unsigned char)0xfd) {
  846.             length = *(short *)data;            /* read length */
  847.             data += length;
  848.             continue;
  849.         }
  850.         if ( c == 0x1 )
  851.             continue;
  852.         if ( (c >= (unsigned char)0x2 && c <= (unsigned char)0xbF) ) {
  853.             length = *(short *)data;            /* read length */
  854.             status = 13;
  855.             data += length;
  856.             continue;
  857.         }
  858.     }
  859.     return(0);
  860. }
  861.  
  862.  
  863.     
  864. /************************************************
  865.  
  866.         Convert a JPEG pict file to a JFIF file.
  867.  
  868. ************************************************/
  869.  
  870.  
  871. short extractionFile;
  872. OSErr extractionErr;
  873.  
  874.  
  875. OSErr
  876. ConvertToJFIF(StringPtr name,short originalFile)
  877. {
  878.  
  879.     /************************************************************ 
  880.  
  881.     This only works if the original file is a JPEG compressed file.
  882.     
  883.     If it were not compressed with JPEG we could check and compress it
  884.     for the user, but then we would have to have a user interface for
  885.     selecting the quality. We could use the StdCompression dialog, but we
  886.     would have to restrict the user to choosing JPEG compression.
  887.     
  888.  
  889.  
  890.     Also if the original image is banded or is a PICT with other opcodes 
  891.     beside the JPEG QuickTime opcode, the JFIF file will only contain the first
  892.     JPEG opcode in the PICT. For the banded case, we could seam together the
  893.     individual bands into a single JPEG stream, but that is kind of hard, so 
  894.     we leave that to you. For a mixed kind of picture, we could draw the whole
  895.     thing in a GWorld and then compress that with JPEG and use that for the JFIF 
  896.     data.
  897.     
  898.     
  899.     ************************************************************/
  900.  
  901.     CQDProcs    cprocs;
  902.     GWorldPtr    gw = nil;
  903.     CGrafPtr    savePort;
  904.     GDHandle    saveGD;
  905.     OSErr        result = 0;
  906.     Rect        rect = {0,0,1,1};
  907.     Str31        newName;
  908.     Point        pt = {100,100};
  909.     SFReply        sfr;
  910.     short        compressedFile = 0;
  911.     
  912.     /************************************************
  913.      *
  914.      *        Ask her for the name of the new file.
  915.      *
  916.      ************************************************/
  917.  
  918.         
  919.     GetGWorld(&savePort,&saveGD);
  920.     GetNewName(newName,name,"\p JFIF");
  921.     SFPutFile(pt,nil,newName,NULL,&sfr);
  922.     if ( !sfr.good )  {
  923.         goto done;
  924.     }
  925.     BlockMove(sfr.fName,newName,32);
  926.     
  927.     /************************************************
  928.      *
  929.      *    Create the new file, if we can.
  930.      *
  931.      ************************************************/
  932.     
  933.     FSDelete(sfr.fName,sfr.vRefNum);
  934.     if ( (result=Create(sfr.fName,sfr.vRefNum,'ppxi','JFIF')) != noErr ) {
  935.         goto done;
  936.     }
  937.     if ( (result=FSOpen(sfr.fName,sfr.vRefNum,&compressedFile)) != noErr ) {
  938.         goto done;
  939.     }
  940.  
  941.     /*************************************************
  942.  
  943.      set globals used by extraction function
  944.      
  945.     *************************************************/
  946.  
  947.     extractionFile = compressedFile;
  948.     extractionErr = -1;        // our own error in case there is no data in pict
  949.     
  950.  
  951.     
  952.     /*************************************************
  953.     
  954.      make a temporary buffer to draw into - small as possible since it's not used 
  955.      
  956.      and draw the image into it while intercepting the QT bottleneck proc.
  957.      
  958.      *************************************************/
  959.     
  960.     if ( (result =  NewGWorld(&gw,1,&rect,0,0,0)) == noErr ) {
  961.         SetGWorld(gw,nil);
  962.         
  963.         /* get std bottlenecks and grab the one we want */
  964.         
  965.         SetStdCProcs(&cprocs);
  966.         cprocs.newProc1 = (Ptr)StdPixExtract;
  967.         gw->grafProcs = &cprocs;
  968.         
  969.         /* draw the picture - grab data with bottleneck */
  970.         
  971.         result = DrawPictureFile(originalFile,&gw->portRect,nil);
  972.  
  973.         if ( result == 0 )
  974.             result = extractionErr;
  975.     }
  976.     
  977. done:
  978.     
  979.     /************************************************
  980.     
  981.     clean up and go home.
  982.     
  983.     ************************************************/
  984.     
  985.     if ( gw ) 
  986.         DisposeGWorld(gw);
  987.     FSClose(originalFile);
  988.     if ( compressedFile )  {
  989.         FSClose(compressedFile);
  990.         if ( result != noErr )
  991.             FSDelete(sfr.fName,sfr.vRefNum);
  992.         FlushVol(nil,sfr.vRefNum);
  993.     }
  994.  
  995.     SetGWorld(savePort,saveGD);
  996.     return(result);
  997.  
  998. }
  999.  
  1000.  
  1001.  
  1002.  
  1003. /************************************************************************************
  1004.  
  1005.     bottle neck proc to extract data from quicktime pict
  1006.     
  1007. *************************************************************************************/
  1008.  
  1009.  
  1010. pascal void
  1011. StdPixExtract(PixMap *src,Rect *srcRect,MatrixRecord matrix,short mode,RgnHandle mask,PixMap *matte,
  1012.     Rect *matteRect,short flags) 
  1013. {
  1014.  
  1015.  
  1016. #pragma    unused(srcRect,matrix,matte,matteRect,flags,mode,mask)
  1017.  
  1018.     ImageDescriptionHandle    idh;
  1019.     long buffSize;
  1020.     DataProcRecord dataProc;
  1021.     ProgressProcRecord progressProc;
  1022.     Ptr    data;
  1023.     
  1024.     long        lb,l;
  1025.     short        i,m;
  1026.     char         *buf,*abuf,tbuf[32];
  1027.  
  1028.     
  1029.     
  1030.     /************************************************************
  1031.     
  1032.      first check to see if it's a compressed pict opcode  
  1033.      
  1034.     ************************************************************/
  1035.     
  1036.     if ( GetCompressedPixMapInfo(src,&idh,&data,&buffSize,&dataProc,&progressProc) == 0 ) {
  1037.     
  1038.     
  1039.         /*******************************
  1040.         
  1041.          verify compression type 
  1042.          
  1043.          ********************************/
  1044.         
  1045.         
  1046.         if (  (*idh)->cType != 'jpeg' ) {
  1047.             extractionErr = paramErr;        // we only wanted jpeg
  1048.             return;
  1049.         }
  1050.  
  1051.  
  1052.         l = (*idh)->dataSize;
  1053.     
  1054.  
  1055.         /********************************
  1056.         
  1057.            make a JFIF header opcode in case the data doesn't have one -
  1058.            QT JPEG always includes one but other JPEG compressors may not 
  1059.            
  1060.         ********************************/
  1061.           
  1062.     
  1063.         {
  1064.             buf = tbuf;
  1065.             m = 0;
  1066.             buf[m++] = MARKER_PREFIX;                // marker prefix
  1067.             buf[m++] = MARKER_APP0;                // APP0 marker
  1068.             buf[m++] = 0;                    // size word ( filled in later )
  1069.             buf[m++] = 0;
  1070.             buf[m++] = 'J';                    // tag 5 bytes
  1071.             buf[m++] = 'F';
  1072.             buf[m++] = 'I';
  1073.             buf[m++] = 'F';
  1074.             buf[m++] = 0;        
  1075.             buf[m++] = 1;                    // version word
  1076.             buf[m++] = 1;
  1077.             buf[m++] = 1;                    // specify dpi
  1078.             buf[m++] = (*idh)->hRes>>24;    // hres word
  1079.             buf[m++] = (*idh)->hRes>>16;
  1080.             buf[m++] = (*idh)->vRes>>24;    // vres word
  1081.             buf[m++] = (*idh)->vRes>>16;
  1082.             buf[m++] = 0;                    // thumbnail x 
  1083.             buf[m++] = 0;                    // thumbnail y 
  1084.         }
  1085.         buf[2] = (m-2)>>8;                    // fill in size
  1086.         buf[3] = (m-2);
  1087.         i = 0;
  1088.         
  1089.         /********************************
  1090.         
  1091.         Scan the JPEG data till we get to the start of image marker.
  1092.         
  1093.         ********************************/
  1094.         
  1095.         
  1096.         while ( data[i] == (char)MARKER_PREFIX ) {
  1097.             if ( i++ > 1024 ) {
  1098.                 extractionErr = -1;
  1099.                 if ( abuf )
  1100.                     DisposPtr(abuf);
  1101.                 return;
  1102.             }
  1103.         }
  1104.         if ( data[i++] != (char)MARKER_SOI ) { 
  1105.             extractionErr = -1;
  1106.             if ( abuf )
  1107.                 DisposPtr(abuf);
  1108.             return;
  1109.         }
  1110.         
  1111.         /*******************************
  1112.         
  1113.         Write out all the data up to and including the start of image marker
  1114.         
  1115.         *******************************/
  1116.         
  1117.         lb = i;
  1118.         if ( dataProc.dataProc ) {
  1119.             if ( extractionErr = dataProc.dataProc(&data,lb,dataProc.dataRefCon))
  1120.                 return;
  1121.         }
  1122.         if ( extractionErr = FSWrite(extractionFile,&lb,data))  {
  1123.             if ( abuf )
  1124.                 DisposPtr(abuf);
  1125.             return;
  1126.         }
  1127.         
  1128.         /*******************************
  1129.         
  1130.         Check to see if there is a JFIF marker in the data already
  1131.         
  1132.         *******************************/
  1133.     
  1134.         
  1135.         if ( data[i] == (char)MARKER_PREFIX &&  data[i+1] == (char)MARKER_APP0 ) {    // already have JFIF marker in stream
  1136.             data += i;
  1137.             l -= i;
  1138.             goto no_jfif_marker;
  1139.         } else {
  1140.             data += i;
  1141.             l -= i;
  1142.         }
  1143.     
  1144.         lb = m;
  1145.         if ( extractionErr = FSWrite(extractionFile,&lb,buf))  {
  1146.             if ( abuf )
  1147.                 DisposPtr(abuf);
  1148.             return;
  1149.         }
  1150. no_jfif_marker:
  1151.         if ( abuf )
  1152.             DisposPtr(abuf);
  1153.     
  1154.         /*******************************
  1155.         
  1156.         Read the rest of the JPEG data and write it into the output file.
  1157.         
  1158.         *******************************/
  1159.     
  1160.     
  1161.         if (  dataProc.dataProc ) {
  1162.             lb = buffSize;
  1163.             while ( l > buffSize ) {
  1164.                 if ( extractionErr = dataProc.dataProc(&data,lb,dataProc.dataRefCon))  {
  1165.                     return;
  1166.                 }
  1167.                 if ( extractionErr = FSWrite(extractionFile,&lb,data)) {
  1168.                     return;
  1169.                 }
  1170.                 data += lb;
  1171.                 l -= lb;
  1172.             }
  1173.             if ( extractionErr = dataProc.dataProc(&data,l,dataProc.dataRefCon)) {
  1174.                 return;
  1175.             }
  1176.             if ( extractionErr = FSWrite(extractionFile,&l,data)) {
  1177.                 return;
  1178.             }
  1179.         } else {
  1180.             if ( extractionErr = FSWrite(extractionFile,&l,data))
  1181.                 return;
  1182.         }
  1183.     
  1184.         
  1185.  
  1186.     } else {
  1187.     
  1188.         /*******************************
  1189.         
  1190.         Not compressed data - return error.
  1191.         
  1192.         *******************************/
  1193.     
  1194.  
  1195.         extractionErr = paramErr;
  1196.     }
  1197. }
  1198.  
  1199.  
  1200.