home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1988 / 05 / meadows / rwtiff.c
Text File  |  1988-03-15  |  15KB  |  537 lines

  1. /* Primary Interface Files */
  2. #include "Types.h"
  3. #include "Quickdraw.h"
  4. #include "Windows.h"
  5.  
  6. /* Other Interface files */
  7. #include "Errors.h"
  8. #include "Files.h"
  9. #include "Memory.h"
  10. #include "Packages.h"
  11. #include "Scrap.h"
  12.  
  13. /* Application-specific Include files */
  14. #include "::TiffLibrary:TIFFLib.h"
  15. #include "sample.h"
  16. #include "messages.h"
  17.  
  18. static Ptr    SetIDPtr();
  19. static void    CleanUp();
  20. static void    InitID();
  21.  
  22. #define    MAXIMAGESIZE    0x8000        /* Limit images to 32K for now */
  23. #define    INFINITY        0x4000000    /* TIFF Spec says 2**32-1 but this is big enough */
  24.  
  25. /* Read in an image from a TIFF format file.  As the code demonstrates, we
  26.  * do not read in very complicated images.  We read in a number of tags,
  27.  * and reject the image as an unsuitable tiff file if any of several
  28.  * conditions exist.  We do not read in images that have more than one bit
  29.  * of image data per pixel.  Of those simple images that we do read, we
  30.  * will only read the first 32k of that image.
  31.  */
  32. Boolean ReadTiff(refNum, myBitMapPtr)
  33. Int16 refNum;
  34. BitMap *myBitMapPtr;
  35. {
  36.     Handle            listH;
  37.     Boolean            oddRowBytes;
  38.     Int8            dummy;
  39.     Int16            byteOrder,
  40.                     rowBytes,
  41.                     scrnHRes,
  42.                     scrnVRes;
  43.     Int32            tagOffset,
  44.                     nextDirOffset,
  45.                     nextFileFree,    /* next free location in output file */
  46.                     dirOffset,
  47.                     rowsPerImage,
  48.                     count,
  49.                     size;
  50.     Rational        xRes,
  51.                     yRes;
  52.     Rect            imageRect;
  53.     TiffDirEntry    tagDirEntry;
  54.     id                id;                /* image description */
  55.  
  56.     InitID(&id);    
  57.     ScreenRes(&scrnHRes, &scrnVRes);    /* if needed for defaults */
  58.     
  59.     /*
  60.      * Read in header and Tags
  61.      */
  62.  
  63.     if (TReadHeader(refNum, &dirOffset, &byteOrder) != noErr) {
  64.         ErrorMessage(BADREADHEADER);
  65.         return(false);
  66.     }
  67.  
  68.     if(TReadTags(refNum, byteOrder,
  69.                 &listH, dirOffset, &nextDirOffset) != noErr) {
  70.         ErrorMessage(BADREADTAGS);
  71.         return(false);
  72.     }
  73.     
  74.     /* Get tags values.
  75.      */
  76.     /* SUBFILE_TYPE_TAG */
  77.     if (TFindTag(listH, &tagOffset, SUBFILE_TYPE_TAG))
  78.         TGetTag(listH, tagOffset, &id.subfileType, sizeof(id.subfileType));
  79.     else {
  80.         ErrorMessage(BADTIFF);
  81.         CleanUp(listH, &id);
  82.         return(false);
  83.     }
  84.     /* IMAGE_WIDTH_TAG */
  85.     if (TFindTag(listH, &tagOffset, IMAGE_WIDTH_TAG))
  86.         TGetTag(listH, tagOffset, &id.imageWidth, sizeof(id.imageWidth));
  87.     else {
  88.         ErrorMessage(BADTIFF);
  89.         CleanUp(listH, &id);
  90.         return(false);
  91.     }
  92.     /* IMAGE_LENGTH_TAG */
  93.     if (TFindTag(listH, &tagOffset, IMAGE_LENGTH_TAG))
  94.         TGetTag(listH, tagOffset, &id.imageLength, sizeof(id.imageLength));
  95.     else {
  96.         ErrorMessage(BADTIFF);
  97.         CleanUp(listH, &id);
  98.         return(false);
  99.     }
  100.     /* ROWS_PER_STRIP_TAG */
  101.     if (TFindTag(listH, &tagOffset, ROWS_PER_STRIP_TAG)) {
  102.         TGetTag(listH, tagOffset, &id.rowsPerStrip, sizeof(id.rowsPerStrip));
  103.         tagDirEntry = GetDirEntry(listH, tagOffset);
  104.         switch(tagDirEntry.type) {
  105.         case LONG:
  106.             break;
  107.         case SHORT:    /* ok, but convert returned value */
  108.             id.rowsPerStrip = (long)( *((Int16 *)(&id.rowsPerStrip)) );
  109.             break;
  110.         default:
  111.             ErrorMessage(BADTIFF);
  112.             CleanUp(listH, &id);
  113.             return(false);
  114.         }
  115.     }
  116.     else {
  117.         id.rowsPerStrip = INFINITY;
  118.     }
  119.     /* SAMPLES_PER_PIXEL_TAG */
  120.     if (TFindTag(listH, &tagOffset, SAMPLES_PER_PIXEL_TAG))
  121.         TGetTag(listH, tagOffset, &id.samplesPerPixel, sizeof(id.samplesPerPixel));
  122.     else {
  123.         id.samplesPerPixel = 1;
  124.     }
  125.     /* BITS_PER_SAMPLE_TAG */
  126.     id.bitsPerSample = SetIDPtr(listH, BITS_PER_SAMPLE_TAG, 1L, SHORT);
  127.     if (id.bitsPerSample == nil) {
  128.             CleanUp(listH, &id);
  129.             return(false);
  130.     }
  131.     /* PLANAR_CONFIG_TAG */
  132.     if (TFindTag(listH, &tagOffset, PLANAR_CONFIG_TAG))
  133.         TGetTag(listH, tagOffset, &id.planarConfig, sizeof(id.planarConfig));
  134.     else
  135.         id.planarConfig = 1;
  136.     /* COMPRESSION_TAG */
  137.     id.compression = SetIDPtr(listH, COMPRESSION_TAG, 1L, SHORT);
  138.     if (id.compression == nil) {
  139.             CleanUp(listH, &id);
  140.             return(false);
  141.     }
  142.     /* MIN_SAMPLE_VALUE_TAG */
  143.     id.minSampleValue = SetIDPtr(listH, MIN_SAMPLE_VALUE_TAG, 0L, SHORT);
  144.     if (id.minSampleValue == nil) {
  145.             CleanUp(listH, &id);
  146.             return(false);
  147.     }
  148.     /* MAX_SAMPLE_VALUE_TAG */
  149.     id.maxSampleValue = SetIDPtr(listH, MAX_SAMPLE_VALUE_TAG,
  150.                             (Int32)((1 << *id.bitsPerSample) - 1), SHORT);
  151.     if (id.maxSampleValue == nil) {
  152.             CleanUp(listH, &id);
  153.             return(false);
  154.     }
  155.     /* PHOTOMETRIC_INTERP_TAG */
  156.     if (TFindTag(listH, &tagOffset, PHOTOMETRIC_INTERP_TAG))
  157.         TGetTag(listH, tagOffset, &id.photoInterp, sizeof(id.photoInterp));
  158.     else {
  159.         id.photoInterp = 0;    /* assume mac photometric interpretation */
  160.     }
  161.     /* FILL_ORDER_TAG */
  162.     if (TFindTag(listH, &tagOffset, FILL_ORDER_TAG))
  163.         TGetTag(listH, tagOffset, &id.fillOrder, sizeof(id.fillOrder));
  164.     else
  165.         id.fillOrder = 1;
  166.     /* ORIENTATION_TAG */
  167.     if (TFindTag(listH, &tagOffset, ORIENTATION_TAG))
  168.         TGetTag(listH, tagOffset, &id.orientation, sizeof(id.orientation));
  169.     else
  170.         id.orientation = 1;
  171.     /* X_RESOLUTION_TAG */
  172.     if (TFindTag(listH, &tagOffset, X_RESOLUTION_TAG))
  173.         TGetTag(listH, tagOffset, &id.xResolution, sizeof(id.xResolution));
  174.     else {
  175.         id.xResolution.numerator = (Int32)scrnHRes;
  176.         id.xResolution.denominator = 1;
  177.     }
  178.     /* Y_RESOLUTION_TAG */
  179.     if (TFindTag(listH, &tagOffset, Y_RESOLUTION_TAG))
  180.         TGetTag(listH, tagOffset, &id.yResolution, sizeof(id.yResolution));
  181.     else {
  182.         id.yResolution.numerator = (Int32)scrnVRes;
  183.         id.yResolution.denominator = 1;
  184.     }
  185.     
  186.     /* Initialize of non-tag values.
  187.      */
  188.     oddRowBytes = (((id.imageWidth * (*id.bitsPerSample)) + 7) / 8) % 2 != 0;
  189.     id.stripsPerImage =
  190.                     (id.imageLength + id.rowsPerStrip - 1) / id.rowsPerStrip;
  191.  
  192.     /*    Check Tag Values to see if we can read this TIFF file.
  193.      *    
  194.      *    NOTE: Although the majority of the tag were read, all the values
  195.      *    obtained are not used in displaying the image in THIS PROGRAM.
  196.      *    Those not used were read in simply to provide the example.
  197.      */
  198.     if ( (id.samplesPerPixel != 1)                        ||
  199.          (*id.bitsPerSample != 1)                        ||
  200.          (id.planarConfig != 1 && id.planarConfig != 2) )    {
  201.         ErrorMessage(BADTIFF);
  202.         CleanUp(listH, &id);
  203.         return(false);
  204.     }
  205.     if (id.photoInterp != 0)    /* We don't translate yet so let 'em know */
  206.         ErrorMessage(BADPHOTOINTERP);
  207.         
  208.     rowBytes = (((id.imageWidth - 1) / (2 * 8)) + 1) * 2;
  209.     /* only make image as much as will fit in MAXIMAGESIZE for now */
  210.     size = id.imageLength * rowBytes;
  211.     if (size > MAXIMAGESIZE) {
  212.         ErrorMessage(IMAGECROPWARN);
  213.         size = MAXIMAGESIZE;
  214.     }
  215.     rowsPerImage = size / rowBytes;
  216.  
  217.     /* Prepare bitmap.
  218.      */
  219.     if (myBitMapPtr->baseAddr != nil)
  220.         DisposPtr(myBitMapPtr->baseAddr);
  221.     if ((myBitMapPtr->baseAddr = MyNewPtr(size)) == nil) {
  222.         CleanUp(listH, &id);
  223.         return(false);
  224.     }
  225.     myBitMapPtr->rowBytes = rowBytes;
  226.     myBitMapPtr->bounds.top = 0;
  227.     myBitMapPtr->bounds.left = 0;
  228.     myBitMapPtr->bounds.bottom = rowsPerImage;
  229.     myBitMapPtr->bounds.right = id.imageWidth;
  230.  
  231.      
  232.     /* Read in image.
  233.      */
  234.     if (TReadImage(refNum, listH,
  235.                     0L, myBitMapPtr->baseAddr, rowsPerImage, -1) != noErr) {
  236.         CleanUp(listH, &id);                        
  237.         return(false);
  238.     }
  239.     if (oddRowBytes)
  240.         TFixOddRowBytes(myBitMapPtr);
  241.     DisplayImage(FrontWindow(), myBitMapPtr);
  242.  
  243.     CleanUp(listH, &id);                        
  244.     return(true);
  245. }
  246.  
  247. void WriteTiff(refNum, myBitMapPtr)
  248. Int16 refNum;
  249. BitMap *myBitMapPtr;
  250. {
  251.     Handle        listH;
  252.     Ptr            bufferPtr;
  253.     Boolean        oddRowBytes;
  254.     Int8        dummy;
  255.     Int16        byteOrder,
  256.                 subfileType,
  257.                 imageWidth,
  258.                 imageLength,
  259.                 fillOrder,
  260.                 compressType,
  261.                 photoInterp,
  262.                 bitsPerPixel,
  263.                 minSampleValue,
  264.                 maxSampleValue,
  265.                 orientation,
  266.                 tiffRowBytes,    /* number of bytes per row in TIFF format */
  267.                 plane,            /* dummy parameter for TWriteImageStrip */
  268.                 scrnHRes,
  269.                 scrnVRes;
  270.     Int32        rowsPerStrip,
  271.                 nextFileFree,    /* next free location in output file */
  272.                 startLine,
  273.                 numLines,
  274.                 dirOffset,
  275.                 count;
  276.     Rational    xRes,
  277.                 yRes;
  278.     Rect        imageRect;
  279.     
  280.     /* get a handle for the in memory tag list */
  281.     listH = NewHandle(0);
  282.     if (MemError() != noErr) {
  283.         ErrorMessage(BADMEMORY);
  284.         return;
  285.     }
  286.  
  287.     ScreenRes(&scrnHRes, &scrnVRes);
  288.     imageRect = myBitMapPtr->bounds;
  289.     /* write out 8 rows per strip - 8 is an arbitrary number */
  290.     rowsPerStrip = MIN(imageRect.bottom - imageRect.top, 8);
  291.  
  292.     /* initialize tag values */
  293.     byteOrder = MOTOROLA;
  294.     subfileType = 1;
  295.     imageWidth = imageRect.right;
  296.     imageLength = imageRect.bottom;
  297.     bitsPerPixel = 1;
  298.     fillOrder = 1;
  299.     compressType = 1;
  300.     photoInterp = 0;
  301.     minSampleValue = 0;
  302.     maxSampleValue = (1 << bitsPerPixel) - 1;
  303.     orientation = 1;
  304.     xRes.numerator = (Int32)scrnHRes;
  305.     xRes.denominator = 1;
  306.     yRes.numerator = (Int32)scrnVRes;
  307.     yRes.denominator = 1;
  308.      
  309.     tiffRowBytes = (imageRect.right * bitsPerPixel + 7) / 8;
  310.     oddRowBytes = (tiffRowBytes % 2) != 0;
  311.  
  312.     /* Put tags in memory list.
  313.      * The order tags are put in the list with TPutPtrTag is NOT important.
  314.      */
  315.     if (    TPutPtrTag(listH, SUBFILE_TYPE_TAG, SHORT,
  316.                                     1L,    &subfileType)    != noErr    ||
  317.             TPutPtrTag(listH, IMAGE_WIDTH_TAG,    SHORT,
  318.                                     1L, &imageWidth)     != noErr    ||
  319.             TPutPtrTag(listH, IMAGE_LENGTH_TAG, SHORT,
  320.                                     1L, &imageLength)    != noErr    ||
  321.             TPutPtrTag(listH, ROWS_PER_STRIP_TAG, LONG,
  322.                                     1L, &rowsPerStrip)    != noErr    ||
  323.             TPutPtrTag(listH, X_RESOLUTION_TAG, RATIONAL,
  324.                                     1L, &xRes)            != noErr    ||
  325.             TPutPtrTag(listH, Y_RESOLUTION_TAG, RATIONAL,
  326.                                     1L, &yRes)            != noErr    ||
  327.             TPutPtrTag(listH, BITS_PER_SAMPLE_TAG, SHORT,
  328.                                     1L,&bitsPerPixel)    != noErr    ||
  329.             TPutPtrTag(listH, COMPRESSION_TAG, SHORT,
  330.                                     1L, &compressType)    != noErr    ||
  331.             TPutPtrTag(listH, FILL_ORDER_TAG, SHORT,
  332.                                     1L, &fillOrder)        != noErr    ||
  333.             TPutPtrTag(listH, ORIENTATION_TAG, SHORT,
  334.                                     1L, &orientation)    != noErr    ||
  335.             TPutPtrTag(listH, PHOTOMETRIC_INTERP_TAG, SHORT,
  336.                                     1L, &photoInterp)    != noErr    ) {
  337.         ErrorMessage(BADPUTTAGS);
  338.         return;
  339.     }
  340.     
  341.     /* leave room for header in output file */
  342.     SetEOF(refNum, (Int32)sizeof(TiffHeader));
  343.     nextFileFree = sizeof(TiffHeader);
  344.     
  345.     /* Write out image to file, fixing from Macintosh rounding of rows to the
  346.      * nearest 2 bytes, to the TIFF rounding of rows to the nearest byte.
  347.      */
  348.     if (oddRowBytes)
  349.         TUnfixOddRowBytes(myBitMapPtr);        /* round rows to nearest byte */
  350.  
  351.     startLine = 0;
  352.     bufferPtr = myBitMapPtr->baseAddr;
  353.     while  (startLine < imageLength) {
  354.         numLines = MIN(imageLength - startLine, rowsPerStrip);
  355.         if (TWriteImageStrip(refNum, &nextFileFree, listH,
  356.                         startLine, numLines, bufferPtr, plane) != noErr) {
  357.             ErrorMessage(BADWRITEIMAGE);
  358.             return;
  359.         }
  360.         startLine += numLines;
  361.         bufferPtr += numLines * tiffRowBytes;
  362.     }
  363.     
  364.     if (oddRowBytes)
  365.         TFixOddRowBytes(myBitMapPtr);        /* round rows to nearest word */
  366.  
  367.     /* directory must be on word boundary */
  368.     if (nextFileFree % 2 != 0) {
  369.         /* add filler byte */
  370.         count = 1;
  371.         if (FSWrite(refNum, &count, &dummy) != noErr) {
  372.             ErrorMessage(BADWRITE);
  373.             return;
  374.         }
  375.         nextFileFree++;
  376.     }
  377.  
  378.     dirOffset = nextFileFree;
  379.     
  380.     if (TWriteTags(refNum, byteOrder, &nextFileFree, listH, 0L) != noErr) {
  381.         ErrorMessage(BADWRITETAGS);
  382.         return;
  383.     }
  384.     if (TWriteHeader(refNum, dirOffset, byteOrder) != noErr) {
  385.         ErrorMessage(BADWRITEHEADER);
  386.     }
  387. }
  388.  
  389. /* Free the list handle and any memory allocated to image description structure.
  390.  */
  391. static void CleanUp(listHandle, idPtr)
  392. Handle listHandle;
  393. id *idPtr;
  394. {
  395.     MyDisposPtr(&idPtr->bitsPerSample);
  396.     MyDisposPtr(&idPtr->compression);
  397.     MyDisposPtr(&idPtr->docName);
  398.     MyDisposPtr(&idPtr->imageDescription);
  399.     MyDisposPtr(&idPtr->make);
  400.     MyDisposPtr(&idPtr->model);
  401.     MyDisposPtr(&idPtr->stripOffsets);
  402.     MyDisposPtr(&idPtr->stripByteCounts);
  403.     MyDisposPtr(&idPtr->minSampleValue);
  404.     MyDisposPtr(&idPtr->maxSampleValue);
  405.     MyDisposPtr(&idPtr->pageName);
  406.     MyDisposPtr(&idPtr->freeOffsets);
  407.     MyDisposPtr(&idPtr->freeByteCounts);
  408.     MyDisposPtr(&idPtr->grayResponseCurve);
  409.     MyDisposPtr(&idPtr->colorResponseCurves);
  410.     DisposHandle(listHandle);
  411. }
  412.  
  413. void InitID(idPtr)
  414. id *idPtr;
  415. {
  416.     idPtr->subfileType = -1;
  417.     idPtr->imageWidth = 0;
  418.     idPtr->imageLength = 0;
  419.     idPtr->bitsPerSample = nil;
  420.     idPtr->compression = nil;
  421.     idPtr->photoInterp = -1;
  422.     idPtr->threshholding = -1;
  423.     idPtr->cellWidth = -1;
  424.     idPtr->cellLength = -1;
  425.     idPtr->fillOrder = 0;
  426.     idPtr->docName = nil;
  427.     idPtr->imageDescription = nil;
  428.     idPtr->make = nil;
  429.     idPtr->model = nil;
  430.     idPtr->stripOffsets = nil;
  431.     idPtr->orientation = -1;
  432.     idPtr->samplesPerPixel = 0;
  433.     idPtr->rowsPerStrip = 0;
  434.     idPtr->stripsPerImage = 0;
  435.     idPtr->stripByteCounts = nil;
  436.     idPtr->minSampleValue = nil;
  437.     idPtr->maxSampleValue = nil;
  438.     idPtr->xResolution.numerator = 0;
  439.     idPtr->xResolution.denominator = 0;
  440.     idPtr->yResolution.numerator = 0;
  441.     idPtr->yResolution.denominator = 0;
  442.     idPtr->planarConfig = -1;
  443.     idPtr->pageName = nil;
  444.     idPtr->xPosition.numerator = 0;
  445.     idPtr->xPosition.denominator = 0;
  446.     idPtr->yPosition.numerator = 0;
  447.     idPtr->yPosition.denominator = 0;
  448.     idPtr->freeOffsets = nil;
  449.     idPtr->freeByteCounts = nil;
  450.     idPtr->grayResponseUnit = -1;
  451.     idPtr->grayResponseCurve = nil;
  452.     idPtr->group3Options = 0;
  453.     idPtr->group4Options = 0;
  454.     idPtr->resolutionUnit = -1;
  455.     idPtr->pageNumber[0] = 0;
  456.     idPtr->pageNumber[1] = 0;
  457.     idPtr->colorResponseUnit = -1;
  458.     idPtr->colorResponseCurves = nil;
  459. }
  460.  
  461. TiffDirEntry GetDirEntry(listHandle, tagOffset)
  462. Handle    listHandle;
  463. Int32    tagOffset;
  464. {
  465.     Ptr                p;
  466.     
  467.     
  468.     /* get pointer to tag list */
  469.     p = &(**listHandle);    /* HANDLE DEREFERENCE */
  470.     /* get pointer to our tag's directory entry */
  471.     p += tagOffset;
  472.     /* return the whole Directory Entry Structure, not a pointer to it */
  473.     return(*((TiffDirEntry *)p));
  474. }
  475.  
  476.  
  477. Int16 TypeSize(type)
  478. Int16 type;
  479. {
  480.     switch (type) {
  481.         case BYTE:
  482.             return(BYTESIZE);
  483.         case ASCII:
  484.             return(ASCIISIZE);
  485.         case SHORT:
  486.             return(SHORTSIZE);
  487.         case LONG:
  488.             return(LONGSIZE);
  489.         case RATSIZE:
  490.             return(RATSIZE);
  491.     }
  492. }
  493.  
  494. Ptr SetIDPtr(listHandle, tag, defaultValue, defaultType)
  495. Handle listHandle;
  496. Int16 tag;
  497. Int32 defaultValue;        /* won't handle defaults larger than 4 bytes */
  498. Int32 defaultType;
  499. {
  500.     TiffDirEntry    tagDE;
  501.     Ptr                p;
  502.     Int32            tagOffset,
  503.                     size,
  504.                     nvals;
  505.     
  506.     if (TFindTag(listHandle, &tagOffset, tag)) {
  507.         tagDE = GetDirEntry(listHandle, tagOffset);
  508.         size = TypeSize(tagDE.type) * tagDE.length;
  509.         if ((p = MyNewPtr(size)) != nil)
  510.             TGetTag(listHandle, tagOffset, p, size);
  511.     }
  512.     else if (defaultType != 0) {
  513.         if ((p = MyNewPtr(defaultType)) != nil) {
  514.             switch (defaultType) {
  515.                 case BYTE:
  516.                     *(unsigned char *)p = defaultValue;
  517.                     break;
  518.                 case ASCII:
  519.                     *(unsigned char *)p = defaultValue;
  520.                     break;
  521.                 case SHORT:
  522.                     *(unsigned short *)p = defaultValue;
  523.                     break;
  524.                 case LONG:
  525.                     *(unsigned long *)p = defaultValue;
  526.                     break;
  527.                 case RATIONAL:
  528.                     ((Rational *)p)->numerator = defaultValue;
  529.                     ((Rational *)p)->denominator = 1;
  530.                     break;
  531.             }
  532.         }
  533.     }
  534.     else
  535.         p = nil;
  536.     return(p);
  537. }