home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
drdobbs
/
1988
/
05
/
meadows
/
rwtiff.c
Wrap
Text File
|
1988-03-15
|
15KB
|
537 lines
/* Primary Interface Files */
#include "Types.h"
#include "Quickdraw.h"
#include "Windows.h"
/* Other Interface files */
#include "Errors.h"
#include "Files.h"
#include "Memory.h"
#include "Packages.h"
#include "Scrap.h"
/* Application-specific Include files */
#include "::TiffLibrary:TIFFLib.h"
#include "sample.h"
#include "messages.h"
static Ptr SetIDPtr();
static void CleanUp();
static void InitID();
#define MAXIMAGESIZE 0x8000 /* Limit images to 32K for now */
#define INFINITY 0x4000000 /* TIFF Spec says 2**32-1 but this is big enough */
/* Read in an image from a TIFF format file. As the code demonstrates, we
* do not read in very complicated images. We read in a number of tags,
* and reject the image as an unsuitable tiff file if any of several
* conditions exist. We do not read in images that have more than one bit
* of image data per pixel. Of those simple images that we do read, we
* will only read the first 32k of that image.
*/
Boolean ReadTiff(refNum, myBitMapPtr)
Int16 refNum;
BitMap *myBitMapPtr;
{
Handle listH;
Boolean oddRowBytes;
Int8 dummy;
Int16 byteOrder,
rowBytes,
scrnHRes,
scrnVRes;
Int32 tagOffset,
nextDirOffset,
nextFileFree, /* next free location in output file */
dirOffset,
rowsPerImage,
count,
size;
Rational xRes,
yRes;
Rect imageRect;
TiffDirEntry tagDirEntry;
id id; /* image description */
InitID(&id);
ScreenRes(&scrnHRes, &scrnVRes); /* if needed for defaults */
/*
* Read in header and Tags
*/
if (TReadHeader(refNum, &dirOffset, &byteOrder) != noErr) {
ErrorMessage(BADREADHEADER);
return(false);
}
if(TReadTags(refNum, byteOrder,
&listH, dirOffset, &nextDirOffset) != noErr) {
ErrorMessage(BADREADTAGS);
return(false);
}
/* Get tags values.
*/
/* SUBFILE_TYPE_TAG */
if (TFindTag(listH, &tagOffset, SUBFILE_TYPE_TAG))
TGetTag(listH, tagOffset, &id.subfileType, sizeof(id.subfileType));
else {
ErrorMessage(BADTIFF);
CleanUp(listH, &id);
return(false);
}
/* IMAGE_WIDTH_TAG */
if (TFindTag(listH, &tagOffset, IMAGE_WIDTH_TAG))
TGetTag(listH, tagOffset, &id.imageWidth, sizeof(id.imageWidth));
else {
ErrorMessage(BADTIFF);
CleanUp(listH, &id);
return(false);
}
/* IMAGE_LENGTH_TAG */
if (TFindTag(listH, &tagOffset, IMAGE_LENGTH_TAG))
TGetTag(listH, tagOffset, &id.imageLength, sizeof(id.imageLength));
else {
ErrorMessage(BADTIFF);
CleanUp(listH, &id);
return(false);
}
/* ROWS_PER_STRIP_TAG */
if (TFindTag(listH, &tagOffset, ROWS_PER_STRIP_TAG)) {
TGetTag(listH, tagOffset, &id.rowsPerStrip, sizeof(id.rowsPerStrip));
tagDirEntry = GetDirEntry(listH, tagOffset);
switch(tagDirEntry.type) {
case LONG:
break;
case SHORT: /* ok, but convert returned value */
id.rowsPerStrip = (long)( *((Int16 *)(&id.rowsPerStrip)) );
break;
default:
ErrorMessage(BADTIFF);
CleanUp(listH, &id);
return(false);
}
}
else {
id.rowsPerStrip = INFINITY;
}
/* SAMPLES_PER_PIXEL_TAG */
if (TFindTag(listH, &tagOffset, SAMPLES_PER_PIXEL_TAG))
TGetTag(listH, tagOffset, &id.samplesPerPixel, sizeof(id.samplesPerPixel));
else {
id.samplesPerPixel = 1;
}
/* BITS_PER_SAMPLE_TAG */
id.bitsPerSample = SetIDPtr(listH, BITS_PER_SAMPLE_TAG, 1L, SHORT);
if (id.bitsPerSample == nil) {
CleanUp(listH, &id);
return(false);
}
/* PLANAR_CONFIG_TAG */
if (TFindTag(listH, &tagOffset, PLANAR_CONFIG_TAG))
TGetTag(listH, tagOffset, &id.planarConfig, sizeof(id.planarConfig));
else
id.planarConfig = 1;
/* COMPRESSION_TAG */
id.compression = SetIDPtr(listH, COMPRESSION_TAG, 1L, SHORT);
if (id.compression == nil) {
CleanUp(listH, &id);
return(false);
}
/* MIN_SAMPLE_VALUE_TAG */
id.minSampleValue = SetIDPtr(listH, MIN_SAMPLE_VALUE_TAG, 0L, SHORT);
if (id.minSampleValue == nil) {
CleanUp(listH, &id);
return(false);
}
/* MAX_SAMPLE_VALUE_TAG */
id.maxSampleValue = SetIDPtr(listH, MAX_SAMPLE_VALUE_TAG,
(Int32)((1 << *id.bitsPerSample) - 1), SHORT);
if (id.maxSampleValue == nil) {
CleanUp(listH, &id);
return(false);
}
/* PHOTOMETRIC_INTERP_TAG */
if (TFindTag(listH, &tagOffset, PHOTOMETRIC_INTERP_TAG))
TGetTag(listH, tagOffset, &id.photoInterp, sizeof(id.photoInterp));
else {
id.photoInterp = 0; /* assume mac photometric interpretation */
}
/* FILL_ORDER_TAG */
if (TFindTag(listH, &tagOffset, FILL_ORDER_TAG))
TGetTag(listH, tagOffset, &id.fillOrder, sizeof(id.fillOrder));
else
id.fillOrder = 1;
/* ORIENTATION_TAG */
if (TFindTag(listH, &tagOffset, ORIENTATION_TAG))
TGetTag(listH, tagOffset, &id.orientation, sizeof(id.orientation));
else
id.orientation = 1;
/* X_RESOLUTION_TAG */
if (TFindTag(listH, &tagOffset, X_RESOLUTION_TAG))
TGetTag(listH, tagOffset, &id.xResolution, sizeof(id.xResolution));
else {
id.xResolution.numerator = (Int32)scrnHRes;
id.xResolution.denominator = 1;
}
/* Y_RESOLUTION_TAG */
if (TFindTag(listH, &tagOffset, Y_RESOLUTION_TAG))
TGetTag(listH, tagOffset, &id.yResolution, sizeof(id.yResolution));
else {
id.yResolution.numerator = (Int32)scrnVRes;
id.yResolution.denominator = 1;
}
/* Initialize of non-tag values.
*/
oddRowBytes = (((id.imageWidth * (*id.bitsPerSample)) + 7) / 8) % 2 != 0;
id.stripsPerImage =
(id.imageLength + id.rowsPerStrip - 1) / id.rowsPerStrip;
/* Check Tag Values to see if we can read this TIFF file.
*
* NOTE: Although the majority of the tag were read, all the values
* obtained are not used in displaying the image in THIS PROGRAM.
* Those not used were read in simply to provide the example.
*/
if ( (id.samplesPerPixel != 1) ||
(*id.bitsPerSample != 1) ||
(id.planarConfig != 1 && id.planarConfig != 2) ) {
ErrorMessage(BADTIFF);
CleanUp(listH, &id);
return(false);
}
if (id.photoInterp != 0) /* We don't translate yet so let 'em know */
ErrorMessage(BADPHOTOINTERP);
rowBytes = (((id.imageWidth - 1) / (2 * 8)) + 1) * 2;
/* only make image as much as will fit in MAXIMAGESIZE for now */
size = id.imageLength * rowBytes;
if (size > MAXIMAGESIZE) {
ErrorMessage(IMAGECROPWARN);
size = MAXIMAGESIZE;
}
rowsPerImage = size / rowBytes;
/* Prepare bitmap.
*/
if (myBitMapPtr->baseAddr != nil)
DisposPtr(myBitMapPtr->baseAddr);
if ((myBitMapPtr->baseAddr = MyNewPtr(size)) == nil) {
CleanUp(listH, &id);
return(false);
}
myBitMapPtr->rowBytes = rowBytes;
myBitMapPtr->bounds.top = 0;
myBitMapPtr->bounds.left = 0;
myBitMapPtr->bounds.bottom = rowsPerImage;
myBitMapPtr->bounds.right = id.imageWidth;
/* Read in image.
*/
if (TReadImage(refNum, listH,
0L, myBitMapPtr->baseAddr, rowsPerImage, -1) != noErr) {
CleanUp(listH, &id);
return(false);
}
if (oddRowBytes)
TFixOddRowBytes(myBitMapPtr);
DisplayImage(FrontWindow(), myBitMapPtr);
CleanUp(listH, &id);
return(true);
}
void WriteTiff(refNum, myBitMapPtr)
Int16 refNum;
BitMap *myBitMapPtr;
{
Handle listH;
Ptr bufferPtr;
Boolean oddRowBytes;
Int8 dummy;
Int16 byteOrder,
subfileType,
imageWidth,
imageLength,
fillOrder,
compressType,
photoInterp,
bitsPerPixel,
minSampleValue,
maxSampleValue,
orientation,
tiffRowBytes, /* number of bytes per row in TIFF format */
plane, /* dummy parameter for TWriteImageStrip */
scrnHRes,
scrnVRes;
Int32 rowsPerStrip,
nextFileFree, /* next free location in output file */
startLine,
numLines,
dirOffset,
count;
Rational xRes,
yRes;
Rect imageRect;
/* get a handle for the in memory tag list */
listH = NewHandle(0);
if (MemError() != noErr) {
ErrorMessage(BADMEMORY);
return;
}
ScreenRes(&scrnHRes, &scrnVRes);
imageRect = myBitMapPtr->bounds;
/* write out 8 rows per strip - 8 is an arbitrary number */
rowsPerStrip = MIN(imageRect.bottom - imageRect.top, 8);
/* initialize tag values */
byteOrder = MOTOROLA;
subfileType = 1;
imageWidth = imageRect.right;
imageLength = imageRect.bottom;
bitsPerPixel = 1;
fillOrder = 1;
compressType = 1;
photoInterp = 0;
minSampleValue = 0;
maxSampleValue = (1 << bitsPerPixel) - 1;
orientation = 1;
xRes.numerator = (Int32)scrnHRes;
xRes.denominator = 1;
yRes.numerator = (Int32)scrnVRes;
yRes.denominator = 1;
tiffRowBytes = (imageRect.right * bitsPerPixel + 7) / 8;
oddRowBytes = (tiffRowBytes % 2) != 0;
/* Put tags in memory list.
* The order tags are put in the list with TPutPtrTag is NOT important.
*/
if ( TPutPtrTag(listH, SUBFILE_TYPE_TAG, SHORT,
1L, &subfileType) != noErr ||
TPutPtrTag(listH, IMAGE_WIDTH_TAG, SHORT,
1L, &imageWidth) != noErr ||
TPutPtrTag(listH, IMAGE_LENGTH_TAG, SHORT,
1L, &imageLength) != noErr ||
TPutPtrTag(listH, ROWS_PER_STRIP_TAG, LONG,
1L, &rowsPerStrip) != noErr ||
TPutPtrTag(listH, X_RESOLUTION_TAG, RATIONAL,
1L, &xRes) != noErr ||
TPutPtrTag(listH, Y_RESOLUTION_TAG, RATIONAL,
1L, &yRes) != noErr ||
TPutPtrTag(listH, BITS_PER_SAMPLE_TAG, SHORT,
1L,&bitsPerPixel) != noErr ||
TPutPtrTag(listH, COMPRESSION_TAG, SHORT,
1L, &compressType) != noErr ||
TPutPtrTag(listH, FILL_ORDER_TAG, SHORT,
1L, &fillOrder) != noErr ||
TPutPtrTag(listH, ORIENTATION_TAG, SHORT,
1L, &orientation) != noErr ||
TPutPtrTag(listH, PHOTOMETRIC_INTERP_TAG, SHORT,
1L, &photoInterp) != noErr ) {
ErrorMessage(BADPUTTAGS);
return;
}
/* leave room for header in output file */
SetEOF(refNum, (Int32)sizeof(TiffHeader));
nextFileFree = sizeof(TiffHeader);
/* Write out image to file, fixing from Macintosh rounding of rows to the
* nearest 2 bytes, to the TIFF rounding of rows to the nearest byte.
*/
if (oddRowBytes)
TUnfixOddRowBytes(myBitMapPtr); /* round rows to nearest byte */
startLine = 0;
bufferPtr = myBitMapPtr->baseAddr;
while (startLine < imageLength) {
numLines = MIN(imageLength - startLine, rowsPerStrip);
if (TWriteImageStrip(refNum, &nextFileFree, listH,
startLine, numLines, bufferPtr, plane) != noErr) {
ErrorMessage(BADWRITEIMAGE);
return;
}
startLine += numLines;
bufferPtr += numLines * tiffRowBytes;
}
if (oddRowBytes)
TFixOddRowBytes(myBitMapPtr); /* round rows to nearest word */
/* directory must be on word boundary */
if (nextFileFree % 2 != 0) {
/* add filler byte */
count = 1;
if (FSWrite(refNum, &count, &dummy) != noErr) {
ErrorMessage(BADWRITE);
return;
}
nextFileFree++;
}
dirOffset = nextFileFree;
if (TWriteTags(refNum, byteOrder, &nextFileFree, listH, 0L) != noErr) {
ErrorMessage(BADWRITETAGS);
return;
}
if (TWriteHeader(refNum, dirOffset, byteOrder) != noErr) {
ErrorMessage(BADWRITEHEADER);
}
}
/* Free the list handle and any memory allocated to image description structure.
*/
static void CleanUp(listHandle, idPtr)
Handle listHandle;
id *idPtr;
{
MyDisposPtr(&idPtr->bitsPerSample);
MyDisposPtr(&idPtr->compression);
MyDisposPtr(&idPtr->docName);
MyDisposPtr(&idPtr->imageDescription);
MyDisposPtr(&idPtr->make);
MyDisposPtr(&idPtr->model);
MyDisposPtr(&idPtr->stripOffsets);
MyDisposPtr(&idPtr->stripByteCounts);
MyDisposPtr(&idPtr->minSampleValue);
MyDisposPtr(&idPtr->maxSampleValue);
MyDisposPtr(&idPtr->pageName);
MyDisposPtr(&idPtr->freeOffsets);
MyDisposPtr(&idPtr->freeByteCounts);
MyDisposPtr(&idPtr->grayResponseCurve);
MyDisposPtr(&idPtr->colorResponseCurves);
DisposHandle(listHandle);
}
void InitID(idPtr)
id *idPtr;
{
idPtr->subfileType = -1;
idPtr->imageWidth = 0;
idPtr->imageLength = 0;
idPtr->bitsPerSample = nil;
idPtr->compression = nil;
idPtr->photoInterp = -1;
idPtr->threshholding = -1;
idPtr->cellWidth = -1;
idPtr->cellLength = -1;
idPtr->fillOrder = 0;
idPtr->docName = nil;
idPtr->imageDescription = nil;
idPtr->make = nil;
idPtr->model = nil;
idPtr->stripOffsets = nil;
idPtr->orientation = -1;
idPtr->samplesPerPixel = 0;
idPtr->rowsPerStrip = 0;
idPtr->stripsPerImage = 0;
idPtr->stripByteCounts = nil;
idPtr->minSampleValue = nil;
idPtr->maxSampleValue = nil;
idPtr->xResolution.numerator = 0;
idPtr->xResolution.denominator = 0;
idPtr->yResolution.numerator = 0;
idPtr->yResolution.denominator = 0;
idPtr->planarConfig = -1;
idPtr->pageName = nil;
idPtr->xPosition.numerator = 0;
idPtr->xPosition.denominator = 0;
idPtr->yPosition.numerator = 0;
idPtr->yPosition.denominator = 0;
idPtr->freeOffsets = nil;
idPtr->freeByteCounts = nil;
idPtr->grayResponseUnit = -1;
idPtr->grayResponseCurve = nil;
idPtr->group3Options = 0;
idPtr->group4Options = 0;
idPtr->resolutionUnit = -1;
idPtr->pageNumber[0] = 0;
idPtr->pageNumber[1] = 0;
idPtr->colorResponseUnit = -1;
idPtr->colorResponseCurves = nil;
}
TiffDirEntry GetDirEntry(listHandle, tagOffset)
Handle listHandle;
Int32 tagOffset;
{
Ptr p;
/* get pointer to tag list */
p = &(**listHandle); /* HANDLE DEREFERENCE */
/* get pointer to our tag's directory entry */
p += tagOffset;
/* return the whole Directory Entry Structure, not a pointer to it */
return(*((TiffDirEntry *)p));
}
Int16 TypeSize(type)
Int16 type;
{
switch (type) {
case BYTE:
return(BYTESIZE);
case ASCII:
return(ASCIISIZE);
case SHORT:
return(SHORTSIZE);
case LONG:
return(LONGSIZE);
case RATSIZE:
return(RATSIZE);
}
}
Ptr SetIDPtr(listHandle, tag, defaultValue, defaultType)
Handle listHandle;
Int16 tag;
Int32 defaultValue; /* won't handle defaults larger than 4 bytes */
Int32 defaultType;
{
TiffDirEntry tagDE;
Ptr p;
Int32 tagOffset,
size,
nvals;
if (TFindTag(listHandle, &tagOffset, tag)) {
tagDE = GetDirEntry(listHandle, tagOffset);
size = TypeSize(tagDE.type) * tagDE.length;
if ((p = MyNewPtr(size)) != nil)
TGetTag(listHandle, tagOffset, p, size);
}
else if (defaultType != 0) {
if ((p = MyNewPtr(defaultType)) != nil) {
switch (defaultType) {
case BYTE:
*(unsigned char *)p = defaultValue;
break;
case ASCII:
*(unsigned char *)p = defaultValue;
break;
case SHORT:
*(unsigned short *)p = defaultValue;
break;
case LONG:
*(unsigned long *)p = defaultValue;
break;
case RATIONAL:
((Rational *)p)->numerator = defaultValue;
((Rational *)p)->denominator = 1;
break;
}
}
}
else
p = nil;
return(p);
}