home *** CD-ROM | disk | FTP | other *** search
/ Info-Mac 3 / Info_Mac_1994-01.iso / HyperCard / TIFFWindow1.1 / tiffinfo.c < prev    next >
Text File  |  1993-06-12  |  27KB  |  1,160 lines

  1. /*
  2.  * This software is copyright 1992 by Robert Morris.
  3.  * You may freely redistribute this software as shareware
  4.  * if you do so in the same form as you got it. If you find
  5.  * this software useful, please send $12 to:
  6.  *   Robert Morris
  7.  *   P.O. Box 1044
  8.  *   Harvard Square Station
  9.  *   Cambridge, MA 02238
  10.  *   ecognome@aol.com
  11.  * If you incorporate any of this software in any kind of
  12.  * commercial product, please send $2 per copy distributed
  13.  * to the above address.
  14.  */
  15.  
  16. /*
  17.  * manipulate TIFF files.
  18.  */
  19. #include "tiffinfo.h"
  20. #include "string.h"
  21.  
  22. #ifdef TIFF_PRINTFS
  23. #include <stdio.h>
  24. #endif
  25.  
  26. void TIFFError(TIFFPtr, OSErr, StringPtr);
  27. long ttohs(TIFFPtr, short);
  28. long ttohl(TIFFPtr, long);
  29. OSErr tiff_read(TIFFPtr, unsigned long, void *, long);
  30. OSErr ScanTIFFDirectory(TIFFPtr);
  31. OSErr ReadTIFFEntry(TIFFPtr, long offset, struct TIFFEntry *);
  32. long ParseScalar(TIFFPtr, struct TIFFEntry *);
  33. long *ParseArray(TIFFPtr, struct TIFFEntry *);
  34. CTabHandle TranslateColorMap(long *colorMap, int ncolors);
  35. CTabHandle MakeGrayTable(int depth, int zeroIsWhite);
  36. Ptr ThreeToFour(Ptr in, long nPixels);
  37. long RowBytes(TIFFPtr);
  38. void CopyPMStrip(PixMapHandle pm, Rect sr, Rect dr, int dither);
  39. void CopyBMStrip(BitMap *, Rect sr, Rect dr, int inv);
  40. void UnDifference(Ptr p, long rowbytes, long nrows, long span);
  41.  
  42. /*
  43.  * Scan a TIFF file's fields to ferret out interesting information.
  44.  * Returns a TIFFPtr whether it succeeded or failed; the caller must
  45.  * call GetTIFFError() to distinguish.
  46.  */
  47. TIFFPtr
  48. ScanTIFF(int ref)
  49. {
  50.     struct TIFFHeader header;
  51.     TIFFPtr ti;
  52.     
  53.     ti = (TIFFPtr) NewPtr(sizeof(*ti));
  54.     if(ti == 0)
  55.         return(0);
  56.     memset(ti, 0, sizeof(*ti)); /* clear the record */
  57.     
  58.     ti->ref = ref;
  59.     
  60.     if(tiff_read(ti, 0L, &header, sizeof(header)) != 0)
  61.         return(ti);
  62.     
  63.     ti->byteOrder = header.byteOrder;
  64.     if((ti->byteOrder != BigEndian && ti->byteOrder != LittleEndian) ||
  65.        ttohs(ti, header.versionNumber) != 42){
  66.            TIFFError(ti, -1, "\pNot a TIFF file.");
  67.         return(ti);
  68.     }
  69.     
  70.     ti->offset = ttohl(ti, header.offset);
  71.     ScanTIFFDirectory(ti);
  72.     
  73.     return(ti);
  74. }
  75.  
  76. void
  77. DisposeTIFF(TIFFPtr ti)
  78. {
  79.     if(ti){
  80.         if(ti->bitsPerSample)
  81.             DisposPtr(ti->bitsPerSample);
  82.         ti->bitsPerSample = 0;
  83.         if(ti->colorMap)
  84.             DisposCTable(ti->colorMap);
  85.         ti->colorMap = 0;
  86.         if(ti->stripOffsets)
  87.             DisposPtr(ti->stripOffsets);
  88.         ti->stripOffsets = 0;
  89.         if(ti->stripByteCounts)
  90.             DisposPtr(ti->stripByteCounts);
  91.         ti->stripByteCounts = 0;
  92.         DisposPtr(ti);
  93.     }
  94. }
  95.  
  96. OSErr
  97. ScanTIFFDirectory(TIFFPtr ti)
  98. {
  99.     unsigned short nentries, entryno;
  100.     struct TIFFEntry entry;
  101.     long nextoffset, n, i, offset, *colorMap = 0;
  102.     OSErr err;
  103.     
  104.     offset = ti->offset;
  105.     ti->err = 0;
  106.     
  107.     /* assign default values */
  108.     ti->bitsPerSample = (long *) NewPtr(sizeof(long));
  109.     if(ti->bitsPerSample == 0){
  110.         TIFFError(ti, err = MemError(), "\pOut of memory");
  111.         return(err);
  112.     }
  113.     ti->bitsPerSample[0] = 1;
  114.     ti->colorMap = 0;
  115.     ti->compression = NoCompression;
  116.     ti->predictor = NoPredictor;
  117.     ti->imageLength = -1;
  118.     ti->imageWidth = -1;
  119.     ti->photometricInterpretation = -1;
  120.     ti->planarConfiguration = PCContiguous;
  121.     ti->rowsPerStrip = 0x7fffffff;
  122.     ti->samplesPerPixel = 1;
  123.     ti->stripByteCounts = 0;
  124.     ti->stripOffsets = 0;
  125.     ti->t6Options = 0;
  126.     ti->fillOrder = 1;
  127.     
  128.     if((err = tiff_read(ti, ti->offset, &nentries, sizeof(nentries))) != 0)
  129.         return(err);
  130.     offset += sizeof(nentries);
  131.     nentries = ttohs(ti, nentries);
  132.     
  133. #define ZAP(x) {if(x){DisposPtr(x);} x = 0;} 
  134.     
  135.     for(entryno = 0; entryno < nentries; entryno++){
  136.         if((err = ReadTIFFEntry(ti, offset, &entry)) != 0)
  137.             return(err);
  138.         offset += sizeof(entry);
  139.         
  140.         switch(entry.tag){
  141.         case ImageWidth:
  142.             ti->imageWidth = ParseScalar(ti, &entry);
  143.             break;
  144.         case ImageLength:
  145.             ti->imageLength = ParseScalar(ti, &entry);
  146.             break;
  147.         case BitsPerSample:
  148.             ZAP(ti->bitsPerSample);
  149.             ti->bitsPerSample = ParseArray(ti, &entry);
  150.             break;
  151.         case ColorMap:
  152.             if(ti->colorMap)
  153.                 DisposCTable(ti->colorMap);
  154.             ti->colorMap = 0;
  155.             colorMap = ParseArray(ti, &entry);
  156.             if(colorMap){
  157.                 ti->colorMap = TranslateColorMap(colorMap, entry.length / 3);
  158.                 DisposPtr(colorMap);
  159.                 colorMap = 0;
  160.                 if(ti->colorMap == 0)
  161.                     TIFFError(ti, -1, "\pCould not make color map.");
  162.             }
  163.             break;
  164.         case Compression:
  165.             ti->compression = ParseScalar(ti, &entry);
  166.             break;
  167.         case Predictor:
  168.             ti->predictor = ParseScalar(ti, &entry);
  169.             break;
  170.         case PhotometricInterpretation:
  171.             ti->photometricInterpretation = ParseScalar(ti, &entry);
  172.             break;
  173.         case StripByteCounts:
  174.             ZAP(ti->stripByteCounts);
  175.             ti->stripByteCounts = ParseArray(ti, &entry);
  176.             break;
  177.         case StripOffsets:
  178.             ZAP(ti->stripOffsets);
  179.             ti->stripOffsets = ParseArray(ti, &entry);
  180.             break;
  181.         case SamplesPerPixel:
  182.             ti->samplesPerPixel = ParseScalar(ti, &entry);
  183.             break;
  184.         case RowsPerStrip:
  185.             ti->rowsPerStrip = ParseScalar(ti, &entry);
  186.             break;
  187.         case PlanarConfiguration:
  188.             ti->planarConfiguration = ParseScalar(ti, &entry);
  189.             break;
  190.         case FillOrder:
  191.             ti->fillOrder = ParseScalar(ti, &entry);
  192.             break;
  193.         case T6Options:
  194.             ti->t6Options = ParseScalar(ti, &entry);
  195.             break;
  196. #ifdef TIFF_PRINTFS
  197.         default:
  198.             printf("tag %d, type %d, length %ld, value %ld/0x%lx\n",
  199.                 entry.tag, entry.type, entry.length, entry.offset, entry.offset);
  200. #endif
  201.         }
  202.     }
  203.     
  204.     /* Some NeXT program generates bogus PlanarConfigurations of 2. */
  205.     if(ti->samplesPerPixel == 1 && ti->planarConfiguration == 2)
  206.         ti->planarConfiguration = 1;
  207.     
  208.     if(ti->rowsPerStrip > ti->imageLength)
  209.         ti->rowsPerStrip = ti->imageLength;
  210.     ti->stripsPerImage = (ti->imageLength + ti->rowsPerStrip - 1) / ti->rowsPerStrip;
  211.  
  212.     /*
  213.      * We need a color map for gray-scale images deeper than one bit.
  214.      */
  215.     if(ti->colorMap == 0 &&
  216.        ti->samplesPerPixel == 1 &&
  217.        ti->bitsPerSample[0] <= 8 &&
  218.        ti->bitsPerSample[0] > 1 &&
  219.        (ti->photometricInterpretation == PIZeroIsWhite ||
  220.         ti->photometricInterpretation == PIZeroIsBlack)){
  221.         ti->colorMap = MakeGrayTable(ti->bitsPerSample[0],
  222.                                      ti->photometricInterpretation == PIZeroIsWhite);
  223.         if(ti->colorMap == 0)
  224.             TIFFError(ti, -1, "\pCould not make gray-scale color map.");
  225.     }
  226.         
  227.     tiff_read(ti, offset, &nextoffset, sizeof(nextoffset));
  228.     ti->nextOffset = ttohl(ti, nextoffset);
  229.     
  230.     return(0);
  231. }
  232.  
  233. /*
  234.  * returns 0 if OK, or a negative error #.
  235.  */
  236. OSErr
  237. ReadTIFFEntry(TIFFPtr ti, long offset, struct TIFFEntry *ep)
  238. {
  239.     OSErr err;
  240.     
  241.     if((err = tiff_read(ti, offset, ep, sizeof(struct TIFFEntry))) != 0)
  242.         return(err);
  243.     ep->tag = ttohs(ti, ep->tag);
  244.     ep->type = ttohs(ti, ep->type);
  245.     ep->length = ttohl(ti, ep->length);
  246.     return(0);
  247. }
  248.  
  249. /*
  250.  * tries to interpret an entry as a single 32-bit integer value.
  251.  * can handle either TIFF_SHORT or TIFF_LONG.
  252.  * assumes ReadTIFFEntry() has already adjusted byte order of tag, type, and length.
  253.  * returns 0 if OK, or a negative error #.
  254.  * On the Mac, values appear in the highest bits of offset.
  255.  */
  256. long
  257. ParseScalar(TIFFPtr ti, struct TIFFEntry *ep)
  258. {
  259.     if(ep->length != 1)
  260.         return(-1);
  261.     if(ep->type == TIFF_BYTE){
  262.         return((ep->offset >> 24) & 0xff);
  263.     } else if(ep->type == TIFF_SHORT){
  264.         return(ttohs(ti, (ep->offset >> 16) & 0xffff));
  265.     } else if(ep->type == TIFF_LONG){
  266.         return(ttohl(ti, ep->offset));
  267.     } else {
  268.         TIFFError(ti, -1, "\pUnknown value type.");
  269.         return(-1);
  270.     }
  271. }
  272.  
  273. /*
  274.  * Returns an array of longs, no matter what the size of the array element.
  275.  * Note that if the array fits in the offset field, it will be there, in the
  276.  * high-order bits, with element zero highest.
  277.  */
  278. long *
  279. ParseArray(TIFFPtr ti, struct TIFFEntry *ep)
  280. {
  281.     long nbytes, i;
  282.     unsigned char *cp = 0;
  283.     unsigned short *sp = 0;
  284.     long *lp = 0;
  285.     
  286.     if(ep->length < 0)
  287.         goto bad;
  288.         
  289.     lp = (long *) NewPtr(ep->length * sizeof(long));
  290.     if(lp == 0)
  291.         goto bad;
  292.         
  293.     if(ep->type == TIFF_BYTE){
  294.         nbytes = ep->length;
  295.         if(nbytes <= 4){
  296.             for(i = 0; i < ep->length; i++)
  297.                 lp[i] = (ep->offset >> (24 - (i * 8))) & 0xff;
  298.         } else {
  299.             cp = (unsigned char *) NewPtr(nbytes);
  300.             if(cp == 0)
  301.                 goto bad;
  302.             if(tiff_read(ti, ttohl(ti, ep->offset), (char *)cp, nbytes) != 0)
  303.                 goto bad;
  304.             for(i = 0; i < ep->length; i++)
  305.                 lp[i] = cp[i];
  306.         }
  307.     } else if(ep->type == TIFF_SHORT){
  308.         nbytes = ep->length * 2;
  309.         if(nbytes <= 4){
  310.             for(i = 0; i < ep->length; i++)
  311.                 lp[i] = ttohs(ti, ep->offset >> (16 - (i * 16)));
  312.         } else {
  313.             sp = (unsigned short *) NewPtr(nbytes);
  314.             if(sp == 0)
  315.                 goto bad;
  316.             if(tiff_read(ti, ttohl(ti, ep->offset), (char *)sp, nbytes) != 0)
  317.                 goto bad;
  318.             for(i = 0; i < ep->length; i++)
  319.                 lp[i] = ttohs(ti, sp[i]);
  320.         }
  321.     } else if(ep->type == TIFF_LONG){
  322.         nbytes = ep->length * 4;
  323.         if(nbytes <= 4){
  324.             lp[0] = ttohl(ti, ep->offset);
  325.         } else {
  326.             if(tiff_read(ti, ttohl(ti, ep->offset), (char *)lp, nbytes) != 0)
  327.                 goto bad;
  328.             for(i = 0; i < ep->length; i++)
  329.                 lp[i] = ttohl(ti, lp[i]);
  330.         }
  331.     } else {
  332.         goto bad;
  333.     }
  334.     
  335.     if(cp)
  336.         DisposPtr(cp);
  337.     if(sp)
  338.         DisposPtr(sp);
  339.     return(lp);
  340.     
  341. bad:
  342.     TIFFError(ti, -1, "\pInvalid array field.");
  343.     if(cp)
  344.         DisposPtr(cp);
  345.     if(sp)
  346.         DisposPtr(sp);
  347.     if(lp)
  348.         DisposPtr(lp);
  349.     return(0);
  350. }
  351.  
  352. /* convert depth (<= 8) to # of colors */
  353. int ColorsOfDepth[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256 };
  354.  
  355. /*
  356.  * return a color map with ngrays shades of gray in it.
  357.  */
  358. CTabHandle
  359. MakeGrayTable(int depth, int zeroIsWhite)
  360. {
  361.     int i, ncolors;
  362.     CTabHandle cth;
  363.     RGBColor rgb;
  364.     
  365.     if(HasColorQD() == 0)
  366.         return(0);
  367.         
  368.     if(depth >= 1 && depth <= 8)
  369.         ncolors = ColorsOfDepth[depth];
  370.     else
  371.         return(0);
  372.         
  373.     cth = (CTabHandle) NewHandle((ncolors * sizeof(ColorSpec)) + 10);
  374.     if(cth == 0)
  375.         return(0);
  376.         
  377.     (*cth)->ctSeed = GetCTSeed();
  378.     (*cth)->ctFlags = 0;
  379.     (*cth)->ctSize = ncolors - 1;
  380.     
  381.     if(zeroIsWhite){
  382.         for(i = 0; i < ncolors; i++){
  383.             rgb.red = rgb.green = rgb.blue = (65535 / (ncolors - 1)) * (ncolors - i - 1);
  384.             (*cth)->ctTable[i].value = i; /* this must be filled in... */
  385.             (*cth)->ctTable[i].rgb = rgb;
  386.         }
  387.     } else {
  388.         /* this doesn't work so hot on the Mac */
  389.         for(i = 0; i < ncolors; i++){
  390.             rgb.red = rgb.green = rgb.blue = (65535 / (ncolors - 1)) * i;
  391.             (*cth)->ctTable[i].value = i; /* this must be filled in... */
  392.             (*cth)->ctTable[i].rgb = rgb;
  393.         }
  394.     }
  395.     
  396.     return(cth);
  397. }
  398.  
  399. /*
  400.  * Turn a TIFF color table, which has red values, then green values, then blue values,
  401.  * into a QuickDraw ColorTable.
  402.  */
  403. CTabHandle
  404. TranslateColorMap(long *colorMap, int ncolors)
  405. {
  406.     int i;
  407.     CTabHandle cth;
  408.     RGBColor rgb;
  409.     
  410.     if(HasColorQD() == 0)
  411.         return(0);
  412.         
  413.     if(colorMap == 0 || ncolors <= 0 || ncolors > 256)
  414.         return(0);
  415.         
  416.     cth = (CTabHandle) NewHandle((ncolors * sizeof(ColorSpec)) + 10);
  417.     if(cth == 0)
  418.         return(0);
  419.         
  420.     (*cth)->ctSeed = GetCTSeed();
  421.     (*cth)->ctFlags = 0;
  422.     (*cth)->ctSize = ncolors - 1;
  423.     
  424.     for(i = 0; i < ncolors; i++){
  425.         rgb.red = colorMap[i];
  426.         rgb.green = colorMap[i + ncolors];
  427.         rgb.blue = colorMap[i + ncolors + ncolors];
  428.         (*cth)->ctTable[i].value = i; /* this must be filled in... */
  429.         (*cth)->ctTable[i].rgb = rgb;
  430.     }
  431.     
  432.     return(cth);
  433.  
  434. }
  435.  
  436. long
  437. ttohs(TIFFPtr ti, short s)
  438. {
  439.     long s1;
  440.     
  441.     if(ti->byteOrder == BigEndian){
  442.         /* Mac-order */
  443.         return(s & 0xffff);
  444.     } else {
  445.         s1 = (s >> 8) & 0xff;
  446.         s1 |= (s & 0xff) << 8;
  447.         return(s1);
  448.     }
  449. }
  450.  
  451. long
  452. ttohl(TIFFPtr ti, long l)
  453. {
  454.     long l1;
  455.     int i;
  456.     
  457.     if(ti->byteOrder == BigEndian){
  458.         /* Mac-order */
  459.         return(l);
  460.     } else {
  461.         l1 = 0;
  462.         for(i = 0; i < 4; i++){
  463.             l1 <<= 8;
  464.             l1 |= (l & 0xff);
  465.             l >>= 8;
  466.         }
  467.         return(l1);
  468.     }
  469. }
  470.  
  471. OSErr
  472. tiff_read(TIFFPtr ti, unsigned long offset, void *buf, long n)
  473. {
  474.     int err;
  475.     long count;
  476.     
  477.     err = SetFPos(ti->ref, fsFromStart, offset);
  478.     if(err < 0){
  479.         TIFFError(ti, err, "\pSeek failed.");
  480.         return(err);
  481.     }
  482.         
  483.     count = n;
  484.     err = FSRead(ti->ref, &count, buf);
  485.     if(err < 0 && err != eofErr){
  486.         TIFFError(ti, err, "\pRead failed.");
  487.         return(err);
  488.     }
  489.     if(count != n){
  490.         TIFFError(ti, -1, "\pRead returned too little data.");
  491.         return(eofErr);
  492.     }
  493.         
  494.     return(0);
  495. }
  496.  
  497. PixMapHandle
  498. PalettePixMap(short depth, CTabHandle cth, long x, long y, long width, long height,
  499.               Ptr data, long row)
  500. {
  501.     PixMapHandle pm;
  502.     
  503.     if(HasColorQD() == 0)
  504.         return(0);
  505.         
  506.     /* Enforce restrictions. */
  507.     if((row & 1) != 0 ||
  508.        (((long) data) & 1) != 0 ||
  509.        (depth != 1 && depth != 2 && depth != 4 && depth != 8) ||
  510.        cth == 0){
  511.            return(0);
  512.     }
  513.     
  514.     pm = NewPixMap();
  515.     if(pm == 0)
  516.         return(0);
  517.         
  518.     (*pm)->pmVersion = 0; /* this is crucial */
  519.     (*pm)->pmReserved = 0;
  520.     (*pm)->packType = 0;
  521.     (*pm)->packSize = 0;
  522.     (*pm)->pixelType = 0; /* chunky */
  523.     (*pm)->pixelSize = depth; /* bits per pixel */
  524.     (*pm)->cmpCount = 1; /* 1 component per pixel */
  525.     (*pm)->cmpSize = depth; /* bits per component */
  526.     (*pm)->planeBytes = 0;
  527.     
  528.     (*pm)->bounds.left = x;
  529.     (*pm)->bounds.right = x + width;
  530.     (*pm)->bounds.top = y;
  531.     (*pm)->bounds.bottom = y + height;
  532.     
  533.     (*pm)->baseAddr = data;
  534.     (*pm)->rowBytes = row | 0x8000; /* the 0x8000 marks this as a Pixmap, not Bitmap */
  535.     
  536.     if((*pm)->pmTable == 0){
  537.         DisposPixMap(pm);
  538.         return(0);
  539.     }
  540.         
  541.     /*
  542.      * Give the PixMap its own color table, which DisposPixMap() frees.
  543.      */
  544.     MoveHHi(cth);
  545.     HLock(cth);
  546.     PtrToXHand(*cth, (*pm)->pmTable, GetHandleSize(cth));
  547.     HUnlock(cth);
  548.     
  549.     return(pm);
  550. }
  551.  
  552. PixMapHandle
  553. RGBPixMap(short depth, long x, long y, long width, long height,
  554.           Ptr data, long rowbytes)
  555. {
  556.     PixMapHandle pm;
  557.     
  558.     if(HasQD32() == 0)
  559.         return(0);
  560.         
  561.     /* Enforce restrictions. */
  562.     if((rowbytes & 1) != 0 ||
  563.        (((long) data) & 1) != 0 ||
  564.        (depth != 16 && depth != 32)){
  565.            return(0);
  566.     }
  567.     
  568.     pm = NewPixMap();
  569.     if(pm == 0)
  570.         return(0);
  571.         
  572.     (*pm)->pmVersion = 0; /* this is crucial */
  573.     (*pm)->pmReserved = 0;
  574.     (*pm)->packType = 0;
  575.     (*pm)->packSize = 0;
  576.     (*pm)->pixelType = 16; /* RGBDirect */
  577.     (*pm)->pixelSize = depth; /* bits per pixel */
  578.     (*pm)->cmpCount = 3; /* 1 component per pixel */
  579.     (*pm)->cmpSize = (depth == 32 ? 8 : 5); /* bits per component */
  580.     (*pm)->planeBytes = 0;
  581.     
  582.     (*pm)->bounds.left = x;
  583.     (*pm)->bounds.right = x + width;
  584.     (*pm)->bounds.top = y;
  585.     (*pm)->bounds.bottom = y + height;
  586.     
  587.     (*pm)->baseAddr = data;
  588.     (*pm)->rowBytes = rowbytes | 0x8000; /* the 0x8000 marks this as a Pixmap, not Bitmap */
  589.     
  590.     return(pm);
  591. }
  592.  
  593. /*
  594.  * Return (a*b)/c. Try to minimize the error.
  595.  */
  596. #define MulDiv(a, b, c) (((a) * (b)) / (c))
  597.  
  598. /*
  599.  * Convert a from coordinate world aref to world bref. Result in b.
  600.  * Optimized for aref and bref the same size.
  601.  */
  602. void
  603. ScaleRect(Rect *aref, Rect *a, Rect *bref, Rect *b)
  604. {
  605.     long hmul, hdiv, hoff;
  606.     long vmul, vdiv, voff;
  607.     
  608.     hmul = bref->right - bref->left;
  609.     hdiv = aref->right - aref->left;
  610.     
  611.     hoff = bref->left - MulDiv(aref->left, hmul, hdiv);
  612.     
  613.     vmul = bref->bottom - bref->top;
  614.     vdiv = aref->bottom - aref->top;
  615.     
  616.     voff = bref->top - MulDiv(aref->top, vmul, vdiv);
  617.     
  618.     b->left = MulDiv(a->left, hmul, hdiv) + hoff;
  619.     b->right = MulDiv(a->right, hmul, hdiv) + hoff;
  620.     b->top = MulDiv(a->top, vmul, vdiv) + voff;
  621.     b->bottom = MulDiv(a->bottom, vmul, vdiv) + voff;
  622. }
  623.  
  624. /*
  625.  * Calculate how many (uncompressed) bytes in a scanline.
  626.  * Doesn't work for separated planes.
  627.  * Returns -1 on error.
  628.  */
  629. long
  630. RowBytes(TIFFPtr ti)
  631. {
  632.     long rowbytes;
  633.     
  634.     if(ti->planarConfiguration != PCContiguous){
  635.         TIFFError(ti, -1, "\pCannot understand planar data.");
  636.         return(-1);
  637.     }
  638.         
  639.     rowbytes = (ti->bitsPerSample[0] * ti->samplesPerPixel * ti->imageWidth + 7) / 8;
  640.     
  641.     return(rowbytes);
  642. }
  643.  
  644. /*
  645.  * Read a reasonable number of scan lines from an image, uncompress them if
  646.  * necessary, and return a new pointer to the data. For compressed images,
  647.  * this routine always reads exactly one strip. Since some applications write
  648.  * large uncompressed images as a single strip, this routine tries to read
  649.  * only about 64K at a time. ReadStrip() returns the number of lines actually
  650.  * read in *linesread, and the first line actually read in *firstread. The
  651.  * latter will always be <= startline.
  652.  */
  653. Ptr
  654. ReadStrip(TIFFPtr ti, long startline, long *firstread, long *linesread)
  655. {
  656.     long count, rowbytes, offset, uncount, i, nrows, strip;
  657.     long skip, suboffset;
  658.     Ptr p = 0, p1 = 0;
  659.     Ptr srcPtr, dstPtr;
  660.     
  661.     /*
  662.      * Decide which strip to read.
  663.      */
  664.     for(strip = 0; strip < ti->stripsPerImage; strip++)
  665.         if(startline >= strip*ti->rowsPerStrip && startline < (strip+1)*ti->rowsPerStrip)
  666.             break;
  667.     if(strip >= ti->stripsPerImage){
  668.         TIFFError(ti, -1, "\pBad arg to ReadStrip()");
  669.         return(0);
  670.     }
  671.     
  672.     /*
  673.      * Decide how many rows in this strip; the last strip might have
  674.      * fewer than the others.
  675.      */
  676.     nrows = ti->rowsPerStrip;
  677.     if((strip * ti->rowsPerStrip) + nrows > ti->imageLength)
  678.         nrows = ti->imageLength - (strip * ti->rowsPerStrip);
  679.     
  680.     if(ti->stripOffsets == 0){
  681.         TIFFError(ti, -1, "\pNo strip offsets.");
  682.         return(0);
  683.     }
  684.     offset = ti->stripOffsets[strip];
  685.     
  686.     if(ti->compression == NoCompression){
  687.         /*
  688.          * Just read part of a strip.
  689.          */
  690.         if((rowbytes = RowBytes(ti)) == -1)
  691.             return(0);
  692.         skip = startline - (strip * ti->rowsPerStrip);
  693.         suboffset = offset + (skip * rowbytes);
  694.         nrows -= skip;
  695. #define BUFSIZE 64000L
  696.         if(rowbytes >= BUFSIZE){
  697.             nrows = 1;
  698.         } else if((nrows * rowbytes) > BUFSIZE){
  699.             nrows = BUFSIZE / rowbytes;
  700.         }
  701.         count = rowbytes * nrows;
  702.     
  703.         p = NewPtr(count);
  704.         if(p == 0){
  705.             TIFFError(ti, MemError(), "\pOut of memory.");
  706.             return(0);
  707.         }
  708.     
  709.         if(tiff_read(ti, suboffset, p, count) != 0)
  710.             goto bad;
  711.             
  712.         *firstread = startline;
  713.         *linesread = nrows;
  714.         
  715.         return(p);
  716.     }
  717.         
  718.     if(ti->stripByteCounts){
  719.         count = ti->stripByteCounts[strip];
  720.     } else {
  721.         /* cannot guess strip length */
  722.         return(0);
  723.     }        
  724.     
  725.     p = NewPtr(count);
  726.     if(p == 0){
  727.         TIFFError(ti, MemError(), "\pOut of memory.");
  728.         return(0);
  729.     }
  730.  
  731.     if(tiff_read(ti, offset, p, count) != 0)
  732.         goto bad;
  733.     
  734.     if(ti->compression == T6Compression){
  735.         rowbytes = RowBytes(ti);
  736.         if(rowbytes == -1)
  737.             goto bad;
  738.         uncount = rowbytes * ti->rowsPerStrip;
  739.         p1 = NewPtr(uncount);
  740.         if(p1 == 0){
  741.             TIFFError(ti, MemError(), "\pOut of memory.");
  742.             goto bad;
  743.         }
  744.         if(DecodeT6(ti, p, count, p1, uncount) != 0)
  745.             goto bad;
  746.         DisposPtr(p);
  747.         p = p1;
  748.         p1 = 0;
  749.     } else if(ti->compression == LZWCompression){
  750.         rowbytes = RowBytes(ti);
  751.         if(rowbytes == -1)
  752.             goto bad;
  753.         uncount = rowbytes * ti->rowsPerStrip;
  754.         p1 = NewPtr(uncount);
  755.         if(p1 == 0){
  756.             TIFFError(ti, MemError(), "\pOut of memory.");
  757.             goto bad;
  758.         }
  759.         
  760.         if(UnLZW(p, count, p1, uncount) != 0){
  761.             TIFFError(ti, -1, "\pLZW decompression failed.");
  762.             goto bad;
  763.         }
  764.         DisposPtr(p);
  765.         p = p1;
  766.         p1 = 0;
  767.         
  768.         if(ti->predictor == HDPredictor &&
  769.            ti->bitsPerSample[0] == 8 &&
  770.            ti->planarConfiguration == PCContiguous){
  771.             /* horizontal differencing */
  772.             for(i = 0; i < ti->samplesPerPixel; i++)
  773.                 UnDifference(p+i, rowbytes, ti->rowsPerStrip, ti->samplesPerPixel);
  774.         } else if(ti->predictor != NoPredictor){
  775.             TIFFError(ti, -1, "\pUnimplemented LZW prediction type.");
  776.             goto bad;
  777.         }
  778.     } else if(ti->compression == PackCompression){
  779.         rowbytes = RowBytes(ti);
  780.         if(rowbytes == -1)
  781.             goto bad;
  782.         if(rowbytes > 32767){
  783.             TIFFError(ti, -1, "\pRow too long for UnpackBits.");
  784.             goto bad;
  785.         }
  786.         uncount = rowbytes * ti->rowsPerStrip;
  787.         p1 = NewPtr(uncount);
  788.         if(p1 == 0){
  789.             TIFFError(ti, MemError(), "\pOut of memory.");
  790.             goto bad;
  791.         }
  792.         srcPtr = p;
  793.         for(i = 0; i < nrows; i++){
  794.             dstPtr = p1 + (i * rowbytes);
  795.             /* does UnpackBits restrict the size of rowbytes? */
  796.             UnpackBits(&srcPtr, &dstPtr, (int)rowbytes);
  797.         }
  798.         DisposPtr(p);
  799.         p = p1;
  800.         p1 = 0;
  801.     } else {
  802.         TIFFError(ti, -1, "\pUnimplemented compression type.");
  803.         goto bad;
  804.     }
  805.     
  806.     *firstread = strip * ti->rowsPerStrip;
  807.     *linesread = nrows;
  808.     
  809.     return(p);
  810.     
  811. bad:
  812.     if(p)
  813.         DisposPtr(p);
  814.     if(p1)
  815.         DisposPtr(p1);
  816.     return(0);
  817. }
  818.  
  819. /*
  820.  * Draw a tiff file image in the current QuickDraw port.
  821.  * The idea is to read each strip, convert into a form
  822.  * that's usable as a QuickDraw PixMap, and copy it to the
  823.  * current port. As an optimization, don't bother reading
  824.  * strips that won't be visible.
  825.  */
  826. OSErr
  827. DrawTIFF(int ref, TIFFPtr ti, Rect sr, Rect dr, int dither)
  828. {
  829.     long y, stripHeight, dstStripHeight, i, rowbytes;
  830.     Ptr p = 0, p1;
  831.     PixMapHandle pm = 0;
  832.     Rect visr, portr;
  833.     GrafPtr port;
  834.     int ppb, inv;
  835.     BitMap bm;
  836.     
  837.     GetPort(&port);
  838.     
  839.     /*
  840.      * Make sure we know how many bits there are per sample, and that
  841.      * the Red, Green, and Blue channels are the same size for RGB images.
  842.      */
  843.     if(ti->bitsPerSample == 0){
  844.         TIFFError(ti, -1, "\pNo bits-per-sample given.");
  845.         return(-1);
  846.     }
  847.     for(i = 1; i < ti->samplesPerPixel; i++){
  848.         if(ti->bitsPerSample[i] != ti->bitsPerSample[i-1]){
  849.             TIFFError(ti, -1, "\pBits-per-sample are different.");
  850.             return(-1);
  851.         }
  852.     }
  853.     
  854.     ti->ref = ref;
  855.     
  856.     /*
  857.      * The destination rectangle may not be totally visible. As an optimization,
  858.      * translate the bounding box of the visible area into the source image
  859.      * space, and only copy the relevant strips.
  860.      */
  861.     portr = (*(port->visRgn))->rgnBBox;
  862.     ScaleRect(&dr, &portr, &sr, &visr);
  863.     y = visr.top;
  864.     stripHeight = 0;
  865.  
  866.     for( ; y < visr.bottom && y < ti->imageLength; y += stripHeight){
  867.         p = ReadStrip(ti, y, &y, &stripHeight);
  868.         if(p == 0)
  869.             goto bad;
  870.          
  871.         /*
  872.          * Find a way to draw the strip.
  873.          */
  874.         if(ti->samplesPerPixel == 1 &&
  875.            ti->bitsPerSample[0] == 1 &&
  876.            (ti->photometricInterpretation == PIZeroIsBlack ||
  877.             ti->photometricInterpretation == PIZeroIsWhite)){
  878.             rowbytes = (ti->bitsPerSample[0] * ti->imageWidth + 7) / 8;
  879.             inv = ti->photometricInterpretation == PIZeroIsBlack;
  880.             if(rowbytes & 1){
  881.                 bm.bounds.right = ti->imageWidth;
  882.                 bm.rowBytes = rowbytes + 1;
  883.                 for(i = 0; i < stripHeight; i++){
  884.                     p1 = p + (i * rowbytes);
  885.                     bm.bounds.top = y + i;
  886.                     bm.bounds.bottom = y + i + 1;
  887.                     if((long)p1 & 1){
  888.                         bm.bounds.left = -8;
  889.                         bm.baseAddr = p1 - 1;
  890.                     } else {
  891.                         bm.bounds.left = 0;
  892.                         bm.baseAddr = p1;
  893.                     }
  894.                     CopyBMStrip(&bm, sr, dr, inv);
  895.                 }
  896.             } else {
  897.                 bm.baseAddr = p;
  898.                 bm.rowBytes = rowbytes;
  899.                 bm.bounds.left = 0;
  900.                 bm.bounds.right = ti->imageWidth;
  901.                 bm.bounds.top = y;
  902.                 bm.bounds.bottom = y + stripHeight;
  903.                 CopyBMStrip(&bm, sr, dr, inv);
  904.             }            
  905.         } else if(ti->samplesPerPixel == 3 &&
  906.            ti->bitsPerSample[0] == 8 &&
  907.            ti->planarConfiguration == PCContiguous &&
  908.            ti->photometricInterpretation == PIRGB){
  909.             /* convert from 3 to 4 bytes per pixel */
  910.             p1 = ThreeToFour(p, ti->imageWidth * stripHeight);
  911.             if(p1 == 0){
  912.                 TIFFError(ti, -1, "\pOut of memory.");
  913.                 goto bad;
  914.             }
  915.             rowbytes = 4 * ti->imageWidth;
  916.             pm = RGBPixMap(32, 0, y, ti->imageWidth, stripHeight, p1, rowbytes);
  917.             if(pm == 0){
  918.                 DisposPtr(p1);
  919.                 TIFFError(ti, -1, "\pCould not allocate PixMap.");
  920.                 goto bad;
  921.             }
  922.             CopyPMStrip(pm, sr, dr, dither);
  923.             DisposPixMap(pm);
  924.             pm = 0;
  925.             DisposPtr(p1);
  926.         } else if(ti->samplesPerPixel == 1 &&
  927.            (ti->bitsPerSample[0] == 1 || ti->bitsPerSample[0] == 2 ||
  928.             ti->bitsPerSample[0] == 4 || ti->bitsPerSample[0] == 8) &&
  929.            (ti->photometricInterpretation == PIPalette ||
  930.             ti->photometricInterpretation == PIZeroIsBlack ||
  931.             ti->photometricInterpretation == PIZeroIsWhite)){
  932.             rowbytes = (ti->bitsPerSample[0] * ti->imageWidth + 7) / 8;
  933.             if(rowbytes & 1){
  934.                 /* must copy odd widths a line at a time */
  935.                 ppb = 8 / ti->bitsPerSample[0];
  936.                 pm = PalettePixMap(ti->bitsPerSample[0], ti->colorMap,
  937.                                    0, 0,
  938.                                    ti->imageWidth, 1,
  939.                                    0, rowbytes + 1);
  940.                 if(pm == 0){
  941.                     TIFFError(ti, -1, "\pCould not allocate PixMap.");
  942.                     goto bad;
  943.                 }
  944.                 for(i = 0; i < stripHeight; i++){
  945.                     p1 = p + (i * rowbytes);
  946.                     (*pm)->bounds.top = y + i;
  947.                     (*pm)->bounds.bottom = y + i + 1;
  948.                     if((long)p1 & 1){
  949.                         (*pm)->bounds.left = -ppb;
  950.                         (*pm)->baseAddr = p1 - 1;
  951.                     } else {
  952.                         (*pm)->bounds.left = 0;
  953.                         (*pm)->baseAddr = p1;
  954.                     }
  955.                     CopyPMStrip(pm, sr, dr, dither);
  956.                 }
  957.                 DisposPixMap(pm);
  958.                 pm = 0;
  959.             } else {
  960.                 pm = PalettePixMap(ti->bitsPerSample[0], ti->colorMap,
  961.                                    0, y,
  962.                                    ti->imageWidth, stripHeight,
  963.                                    p, rowbytes);
  964.                 if(pm == 0){
  965.                     TIFFError(ti, -1, "\pCould not allocate PixMap.");
  966.                     goto bad;
  967.                 }
  968.                 CopyPMStrip(pm, sr, dr, dither);
  969.                 DisposPixMap(pm);
  970.                 pm = 0;
  971.             }
  972.         } else {
  973.             TIFFError(ti, -1, "\pUnimplemented image representation.");
  974.             goto bad;
  975.         }        
  976.             
  977.         DisposPtr(p);
  978.         p = 0;
  979.     }
  980.     
  981.     return(0);
  982.     
  983. bad:
  984.     if(p)
  985.         DisposPtr(p);
  986.     if(pm)
  987.         DisposPixMap(pm);
  988.     return(-1);
  989. }
  990.  
  991. /*
  992.  * Copy a pixmap of a strip to the right place.
  993.  */
  994. void
  995. CopyPMStrip(PixMapHandle pm, Rect sr, Rect dr, int dither)
  996. {
  997.     Rect sr1, dr1;
  998.     GrafPtr port;
  999.  
  1000.     sr1 = (*pm)->bounds;
  1001.     sr1.left = sr.left;
  1002.     sr1.right = sr.right;
  1003.     if(sr1.top < sr.top)
  1004.         sr1.top = sr.top;
  1005.     if(sr1.bottom > sr.bottom)
  1006.         sr1.bottom = sr.bottom;
  1007.         
  1008.     ScaleRect(&sr, &sr1, &dr, &dr1);
  1009.     
  1010.     GetPort(&port);
  1011.     
  1012.     MoveHHi(pm);
  1013.     HLock(pm);
  1014.     CopyBits(*pm, &(port->portBits), &sr1, &dr1, dither ? 64 : srcCopy, 0L);
  1015.     HUnlock(pm);
  1016. }
  1017.  
  1018. /*
  1019.  * Copy a bitmap of a strip to the right place.
  1020.  * Optionally invert black and white.
  1021.  */
  1022. void
  1023. CopyBMStrip(BitMap *bm, Rect sr, Rect dr, int inv)
  1024. {
  1025.     Rect sr1, dr1;
  1026.     GrafPtr port;
  1027.  
  1028.     sr1 = bm->bounds;
  1029.     sr1.left = sr.left;
  1030.     sr1.right = sr.right;
  1031.     if(sr1.top < sr.top)
  1032.         sr1.top = sr.top;
  1033.     if(sr1.bottom > sr.bottom)
  1034.         sr1.bottom = sr.bottom;
  1035.         
  1036.     ScaleRect(&sr, &sr1, &dr, &dr1);
  1037.     
  1038.     GetPort(&port);
  1039.     
  1040.     CopyBits(bm, &(port->portBits), &sr1, &dr1, inv ? notSrcCopy : srcCopy, 0L);
  1041. }
  1042.  
  1043.  
  1044. /*
  1045.  * Convert 3-bytes-per-pixel RGB data to 4-bytes-per-pixel, as required
  1046.  * for QuickDraw 32-bit Pix Maps. inLen is the number of bytes.
  1047.  */
  1048. Ptr
  1049. ThreeToFour(Ptr in, long nPixels)
  1050. {
  1051.     Ptr out;
  1052.     register unsigned long *inp, *outp;
  1053.     register unsigned long in1, in2, in3;
  1054.     char *ip, *op;
  1055.     
  1056.     out = NewPtr(4 * nPixels);
  1057.     if(out == 0)
  1058.         return(0);
  1059.         
  1060.     inp = (unsigned long *) in;
  1061.     outp = (unsigned long *) out;
  1062.     
  1063.     for( ; nPixels >= 4; nPixels -= 4){
  1064.         /* read 4 pixels worth of data in 4 longs: RGBR GBRG BRGB */
  1065.         in1 = *inp++;
  1066.         in2 = *inp++;
  1067.         in3 = *inp++;
  1068.         
  1069.         /* write the 4 pixels as 4 longs */
  1070.         *outp++ = in1 >> 8;
  1071.         *outp++ = ((in1 & 0xff) << 16) | ((in2 >> 16) & 0xffff);
  1072.         *outp++ = ((in2 & 0xffff) << 8) | (in3 >> 24);
  1073.         *outp++ = in3 & 0xffffff;
  1074.     }
  1075.     
  1076.     /* take care of last 1, 2 or 3 pixels one byte at a time */
  1077.     ip = (char *) inp;
  1078.     op = (char *) outp;
  1079.     for( ; nPixels > 0; --nPixels){
  1080.         *op++ = 0;
  1081.         *op++ = *ip++;
  1082.         *op++ = *ip++;
  1083.         *op++ = *ip++;
  1084.     }
  1085.     
  1086.     return(out);
  1087. }
  1088.  
  1089. /*
  1090.  * Un-difference a strip of image. Must be 8-bit samples.
  1091.  * Span indicates how many bytes to skip (for interleaved RGB).
  1092.  * Modifies the data in place.
  1093.  */
  1094. void
  1095. UnDifference(Ptr p, long rowbytes, long nrows, long span)
  1096. {
  1097.     long row, col, off;
  1098.     
  1099.     for(row = 0; row < nrows; row++){
  1100.         off = row * rowbytes;
  1101.         for(col = span; col < rowbytes; col += span){
  1102.             p[off + col] += p[off + col - span];
  1103.         }
  1104.     }
  1105. }
  1106.  
  1107. /*
  1108.  * Register an error with a TIFF record, for later retrieval with GetTIFFError().
  1109.  */
  1110. void
  1111. TIFFError(TIFFPtr ti, OSErr err, StringPtr p)
  1112. {
  1113.     int i;
  1114.     
  1115.     if(ti && ti->err == 0){
  1116.         if(err == 0)
  1117.             err = -1;
  1118.         ti->err = err;
  1119.         for(i = 0; i < p[0] && i < 255; i++)
  1120.             ti->errStr[i+1] = p[i+1];
  1121.         ti->errStr[0] = p[0];
  1122.     }
  1123. }
  1124.  
  1125. /*
  1126.  * Return and clear the error associated with a TIFF record.
  1127.  */
  1128. OSErr
  1129. GetTIFFError(TIFFPtr ti, StringPtr p)
  1130. {
  1131.     int i;
  1132.     OSErr err;
  1133.     
  1134.     p[0] = 0;
  1135.     if(ti == 0)
  1136.         return(-1);
  1137.         
  1138.     p[0] = ti->errStr[0];
  1139.     for(i = 0; i < p[0] && i < 255; i++)
  1140.         p[i+1] = ti->errStr[i+1];
  1141.         
  1142.     err = ti->err;
  1143.     ti->err = 0;
  1144.     ti->errStr[0] = 0;
  1145.     
  1146.     return(err);
  1147. }
  1148.  
  1149. /*
  1150.  * Can a TIFF image be drawn with this system's version of QuickDraw?
  1151.  */
  1152. Boolean
  1153. TIFFDrawable(TIFFPtr ti)
  1154. {
  1155.     if(ti->samplesPerPixel > 1)
  1156.         return(HasQD32());
  1157.     if(ti->bitsPerSample[0] > 1)
  1158.         return(HasColorQD());
  1159.     return(TRUE);
  1160. }