Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
source/fileIO.c
/****************************************************/ |
/* */ |
/* File: fileIO.c */ |
/* */ |
/* Program: Imageer */ |
/* */ |
/* By: Jason Hodges-Harris */ |
/* */ |
/* Created: 26/10/95 00:00:00 AM */ |
/* */ |
/* Version: 1.0.0d3 */ |
/* */ |
/* Copyright: © 1995-96 Apple Computer, Inc., */ |
/* all rights reserved. */ |
/* */ |
/****************************************************/ |
/**** Macintosh Toolbox Headers *****/ |
#ifndef __COMPONENTS__ |
#include <Components.h> |
#endif |
#ifndef __CONTROLS__ |
#include <Controls.h> |
#endif |
#ifndef __CURSORCTL__ |
#include <CursorCtl.h> |
#endif |
#ifndef __DIALOGS__ |
#include <Dialogs.h> |
#endif |
#ifndef __FILES__ |
#include <Files.h> |
#endif |
#ifndef __GXGRAPHICS__ |
#include <GXGraphics.h> |
#endif |
#ifndef __GXMATH__ |
#include <GXMath.h> |
#endif |
#ifndef __IMAGECOMPRESSION__ |
#include <ImageCompression.h> |
#endif |
#ifndef __MEMORY__ |
#include <Memory.h> |
#endif |
#ifndef __PICTUTILS__ |
#include <PictUtils.h> |
#endif |
#ifndef __QUICKTIMECOMPONENTS__ |
#include <QuickTimeComponents.h> |
#endif |
#ifndef __STANDARDFILE__ |
#include <StandardFile.h> |
#endif |
#ifndef __STRING__ |
#include <string.h> |
#endif |
#ifndef __STRINGS__ |
#include <Strings.h> |
#endif |
#ifndef __TOOLUTILS__ |
#include <ToolUtils.h> |
#endif |
#ifndef __TYPES__ |
#include <Types.h> |
#endif |
/**** Application headers and prototypes ****/ |
#ifndef __IMAGEERAPPHEADER__ |
#include "Imageer.app.h" |
#endif |
#ifndef __IMAGEERPROTOSHEADER__ |
#include "Imageer.protos.h" |
#endif |
/**** Global variables ****/ |
extern OSType gLoadFileType; |
static OSType gSaveFileType; |
/**** Default RGB Colors ****/ |
static const RGBColor kRGBBlack = {0x0000, 0x0000, 0x0000}; |
static const RGBColor kRGBWhite = {0xFFFF, 0xFFFF, 0xFFFF}; |
/**** Load supported image file type ****/ |
// Main function which is called when 'Open' is selected in the file menu. |
// Displays the custom get file dialog, which supports a pop up menu |
// to filter out unwanted/unwanted file types. Creates and initialises the |
// image window document structure dependent of the file type loaded. |
#pragma segment fileSys |
OSErr LoadSupportedImage(void) |
{ |
ImageDocHndl theDocHndl = nil; |
PicHandle thePictHndl = nil; |
DlgHookYDUPP theDialogHookUPP; |
FileFilterYDUPP theDialogFileFilterUPP; |
PictInfo thePictInfo; |
StandardFileReply theSFReply; |
TiffInfo theTiffStruct; |
SFTypeList fileTypes; |
Point dlogPosition = {-1,-1}; |
OSErr error = noErr; |
// Create Universal Proc Ptrs for custom Dialog functions |
theDialogHookUPP = NewDlgHookYDProc(CustomGetFileHook); |
theDialogFileFilterUPP = NewFileFilterYDProc(CustomFileDlogFilter); |
CustomGetFile (theDialogFileFilterUPP,-1, |
fileTypes,&theSFReply,rCustomOpenDialog, |
dlogPosition,theDialogHookUPP,nil,nil,nil,nil); |
DisposeRoutineDescriptor((UniversalProcPtr)theDialogHookUPP); |
DisposeRoutineDescriptor((UniversalProcPtr)theDialogFileFilterUPP); |
if (theSFReply.sfGood == true) |
{ |
theDocHndl = (ImageDocHndl)NewHandle(sizeof(ImageDoc)); // create new image document |
if (!theDocHndl) |
{ |
DisplayAlert (rGenWarning,rErrMessages,iFailAllocMem); |
return kFailAllocDocHndl; |
} |
if (theSFReply.sfType == 'qdgx') |
(**theDocHndl).isUsingQDGX = true; |
else |
(**theDocHndl).isUsingQDGX = false; |
(**theDocHndl).theImageFileReply = theSFReply; // copy SFReply to window Doc structure |
switch (theSFReply.sfType) |
{ |
case ('TIFF'): // TIFF file type |
// Set up document structure to defaults for image type |
(**theDocHndl).theFileType = TiffType; |
(**theDocHndl).theImageChanged = false; |
(**theDocHndl).theColorsPalette = nil; |
(**theDocHndl).theImageWorld = nil; |
(**theDocHndl).theVScrollBar = nil; |
(**theDocHndl).theHScrollBar = nil; |
(**theDocHndl).theUndoState = kCannotUndo; |
(**theDocHndl).hasUndoTemp = false; |
(**theDocHndl).hasRedoTemp = false; |
theTiffStruct.tiffCTabHndl = nil; // set to nil as Color table not always created |
GetTIFFHdrInfo(theDocHndl,&theTiffStruct); |
error = GetTIFFIFDirectory(theDocHndl,&theTiffStruct); |
if (error == kTIFFNotSupported) |
{ |
if (theTiffStruct.tiffCTabHndl) |
DisposeHandle((Handle)theTiffStruct.tiffCTabHndl); |
CleanLoadAbort(theDocHndl); |
DisplayAlert (rGenWarning, rFileIOMessages, iTiffNotSupported); |
return error; |
} |
// cannot at present support TIFF files that aren't 8 or 32 bit |
switch (theTiffStruct.bitDepth) |
{ |
case 8: |
(**theDocHndl).theImageWorld = |
CreateOffscreen(theTiffStruct.tiffCTabHndl, |
theTiffStruct.xImageSize, |
theTiffStruct.yImageSize, |
theTiffStruct.bitDepth,kNoFlags); |
if ((**theDocHndl).theImageWorld == nil) |
{ |
DisposeHandle((Handle)theDocHndl); |
return kFailMakeGWorld; |
} |
break; |
case 32: |
(**theDocHndl).theImageWorld = |
CreateOffscreen(nil, |
theTiffStruct.xImageSize, |
theTiffStruct.yImageSize, |
theTiffStruct.bitDepth,kNoFlags); |
if ((**theDocHndl).theImageWorld == nil) |
{ |
DisposeHandle((Handle)theDocHndl); |
return kFailMakeGWorld; |
} |
break; |
default: |
DisplayAlert (rGenWarning,rErrMessages,iNoSupportBitDepth); |
return kBitDepthErr; |
break; |
} |
// Fill in image coord sizes and bit depth to document structure |
(**theDocHndl).theImageXSize = theTiffStruct.xImageSize; |
(**theDocHndl).theImageYSize = theTiffStruct.yImageSize; |
(**theDocHndl).theImageDepth = theTiffStruct.bitDepth; |
// Perform TIFF file parse directly into GWorld referenced from document structure |
error = LoadTiffToGWorld (theDocHndl,&theTiffStruct,theTiffStruct.bitDepth); |
if (error) |
{ |
DisplayAlert (rGenAlert,0,0); |
return error; |
} |
SetUndoItemText(kCannotUndo); |
error = CreateImageWindow (theDocHndl); |
if (error == kDefaultAppError) |
{ |
DisplayAlert (rGenAlert,0,0); |
return error; |
} |
// Dispose of Tiff struct color table handle |
if (theTiffStruct.tiffCTabHndl) |
DisposeHandle((Handle)theTiffStruct.tiffCTabHndl); |
error = AddDocNameToMenu(theDocHndl); |
if (error) |
DisplayAlert (rGenAlert,0,0); |
else |
return noErr; |
break; |
case ('PICT'): // PICT type |
// Set up document structure to defaults for image type |
(**theDocHndl).theFileType = PictType; |
(**theDocHndl).theImageChanged = false; |
(**theDocHndl).theColorsPalette = nil; |
(**theDocHndl).theImageWorld = nil; |
(**theDocHndl).theVScrollBar = nil; |
(**theDocHndl).theHScrollBar = nil; |
(**theDocHndl).theUndoState = kCannotUndo; |
(**theDocHndl).hasUndoTemp = false; |
(**theDocHndl).hasRedoTemp = false; |
// Load PICT file into PicHandle structure before placing in GWorld |
thePictHndl = LoadPictImageFile(theDocHndl); |
if (!thePictHndl) |
{ |
DisposeHandle((Handle)theDocHndl); |
return kDefaultAppError; |
} |
// test if minimal temp memory free available. If none available GetPictInfo() fails. |
if (TempFreeMem() < kMinLowMem) |
{ |
DisplayAlert(rGenWarning,rErrMessages,iLowTempMem); |
DisposeHandle((Handle)theDocHndl); |
return kLowMemWarning; |
} |
error = GetPictInfo (thePictHndl, &thePictInfo, returnColorTable,256,systemMethod,0); |
// Fill in image coord sizes and bit depth to document structure |
(**theDocHndl).theImageXSize = thePictInfo.sourceRect.right - thePictInfo.sourceRect.left; |
(**theDocHndl).theImageYSize = thePictInfo.sourceRect.bottom - thePictInfo.sourceRect.top; |
(**theDocHndl).theImageDepth = thePictInfo.depth; |
// Create window document's GWorld structure and draw loaded Pict image into it. |
if (!error && thePictInfo.depth <= 8) |
(**theDocHndl).theImageWorld = |
CreateOffscreen(thePictInfo.theColorTable, |
(**theDocHndl).theImageXSize, |
(**theDocHndl).theImageYSize, |
(**theDocHndl).theImageDepth,kNoFlags); |
else |
(**theDocHndl).theImageWorld = |
CreateOffscreen(nil, |
(**theDocHndl).theImageXSize, |
(**theDocHndl).theImageYSize, |
(**theDocHndl).theImageDepth,kNoFlags); |
if ((**theDocHndl).theImageWorld == nil) |
{ |
DisposeHandle((Handle)theDocHndl); // dispose image document |
DisposeHandle((Handle)thePictHndl); // dispose picHandle |
return kFailMakeGWorld; |
} |
error = DrawPictToGWorld (theDocHndl,thePictHndl); |
SetUndoItemText(kCannotUndo); |
error = CreateImageWindow (theDocHndl); |
if (error == kDefaultAppError) |
{ |
DisplayAlert (rGenAlert,0,0); |
return error; |
} |
error = AddDocNameToMenu(theDocHndl); |
if (error) |
DisplayAlert (rGenAlert,0,0); |
else |
return noErr; |
break; |
case ('qdgx'): |
// QuickDraw GX file load function is not yet supported in this release. |
// It will be included in a future release. |
SetUndoItemText(kCannotUndo); |
DisplayAlert (rGenAlert,rErrMessages,iNotImplemented); |
return kNotSupported; |
break; |
} |
} |
return kFileLoadAbortErr; |
} |
/**** CustomGetFile dialog file hook func ****/ |
// This function handles user interaction of the custom dialog items added to the |
// CustomGetFile dialog and ignores all other items which are returned and processed |
// by the standard internal function. |
#pragma segment fileSys |
pascal short CustomGetFileHook(short item,DialogPtr theDlogPtr,void* theData) |
{ |
Handle theHandle; |
Rect theRect; |
short theType, |
ignored; |
switch (item) |
{ |
case sfHookFirstCall: |
GetDItem(theDlogPtr,kLoadFilePopUpItem,&theType,&theHandle,&theRect); |
switch (gLoadFileType) |
{ |
case 'TIFF': |
theType = iTiffType; |
break; |
case 'PICT': |
theType = iPictType; |
break; |
case 'qdgx': |
theType = iGXType; |
break; |
default: |
theType = iAllFiles; |
break; |
} |
SetCtlValue((ControlHandle)theHandle,theType); |
return sfHookNullEvent; |
break; |
case kLoadFilePopUpItem: |
GetDItem(theDlogPtr,item,&ignored,&theHandle,&theRect); |
theType = GetCtlValue((ControlHandle)theHandle); |
switch (theType) |
{ |
case iTiffType: |
gLoadFileType = 'TIFF'; |
item = sfHookRebuildList; |
break; |
case iPictType: |
gLoadFileType = 'PICT'; |
item = sfHookRebuildList; |
break; |
case iGXType: |
gLoadFileType = 'qdgx'; |
item = sfHookRebuildList; |
break; |
case iAllFiles: |
gLoadFileType = '????'; |
item = sfHookRebuildList; |
break; |
} |
return item; |
break; |
} |
return item; |
} |
/**** basic CustomGetFile filter function ****/ |
// File filter function is used by CustomGetFile() to restrict the |
// display of files and folders to supported image file types and visible folders. |
#pragma segment fileSys |
pascal Boolean CustomFileDlogFilter(CInfoPBPtr theParamBlok, Ptr theDataPtr) |
{ |
Boolean notDisplayed = true; |
switch (theParamBlok->hFileInfo.ioFlFndrInfo.fdType) |
{ |
case 'TIFF': |
if (gLoadFileType == 'TIFF' || gLoadFileType == '????') |
notDisplayed = false; |
break; |
case 'PICT': |
if (gLoadFileType == 'PICT' || gLoadFileType == '????') |
notDisplayed = false; |
break; |
case 'qdgx': |
if (gLoadFileType == 'qdgx' || gLoadFileType == '????') |
notDisplayed = false; |
break; |
default: |
if ((theParamBlok->dirInfo.ioFlAttrib & kFolderBit) && |
!(theParamBlok->hFileInfo.ioFlFndrInfo.fdFlags & kFileVisibleBit)) |
notDisplayed = false; |
break; |
} |
return notDisplayed; |
} |
/**** retrieve TIFF image header information ****/ |
// Retrieve TIFF file header information and parse. Used to calculate file information |
// when reading in TIFF directory data. |
#pragma segment fileSys |
void GetTIFFHdrInfo(ImageDocHndl theDocHndl, TiffInfo *theTiffHeader) |
{ |
long fileLen; |
StandardFileReply theFileSpec = (**theDocHndl).theImageFileReply; // use local as FSpOpenDF returns param in spec |
char headerStore[8]; |
FSpOpenDF(&theFileSpec.sfFile,fsRdPerm,&theFileSpec.sfFile.vRefNum); // open file |
// Get size of file storage of TIFF header and read in TIFF header info |
fileLen = sizeof(headerStore); |
FSRead(theFileSpec.sfFile.vRefNum,&fileLen,headerStore); |
FSClose(theFileSpec.sfFile.vRefNum); |
// copy header information to data structure |
BlockMoveData(headerStore,&theTiffHeader->byteOrder,2); |
BlockMoveData(&headerStore[2],&theTiffHeader->version,2); |
if (theTiffHeader->byteOrder == IntlFormat) |
theTiffHeader->version = SwapByteOrder(theTiffHeader->version,2); |
BlockMoveData(&headerStore[4],&theTiffHeader->offsetToIFD,4); |
if (theTiffHeader->byteOrder == IntlFormat) |
theTiffHeader->offsetToIFD = SwapByteOrder(theTiffHeader->offsetToIFD,4); |
return; |
} |
/**** Retrieve TIFF format image file directory info ****/ |
// Function to parse the TIFF image file and load the image |
// data directly into a previously created GWorld PixMap. |
// If the TIFF file is an indexed image the color table information |
// is used to manually create a Color Table |
#pragma segment fileSys |
OSErr GetTIFFIFDirectory(ImageDocHndl theDocHndl, TiffInfo *theTiffHeader) |
{ |
long fileLen, |
tempDecode, // temporary decoder storage |
myOldFilePos, |
cTabSize; |
StandardFileReply theFileSpec = (**theDocHndl).theImageFileReply; // use local as FSpOpen returns param in spec |
char iFDcounter[2], // number of IFD entries |
iFDStore[12], // IFD field entry |
iFDOffset[4]; // offset to next IFD |
short entriesLeft, // IFD's to process |
numberColors, |
colorValue, |
countStep, |
count; |
OSErr error = noErr, |
myFileErr; |
Boolean isIntFormat = false; |
if (theTiffHeader->byteOrder == IntlFormat) |
isIntFormat = true; |
FSpOpenDF(&theFileSpec.sfFile,fsRdPerm,&theFileSpec.sfFile.vRefNum); |
SetFPos(theFileSpec.sfFile.vRefNum,fsFromStart,theTiffHeader->offsetToIFD); |
fileLen = sizeof(iFDcounter); |
FSRead(theFileSpec.sfFile.vRefNum,&fileLen,iFDcounter); |
BlockMoveData(iFDcounter,&entriesLeft,2); |
if (isIntFormat) |
entriesLeft = SwapByteOrder(entriesLeft,2); |
fileLen = sizeof(iFDStore); |
do{ |
do{ |
myFileErr = FSRead(theFileSpec.sfFile.vRefNum,&fileLen,iFDStore); // get pattern header info |
if (myFileErr) |
DebugStr("\pError in reading IFDirectory"); |
BlockMoveData(iFDStore,&tempDecode,2); |
tempDecode=tempDecode>>16; |
if (isIntFormat) |
tempDecode = SwapByteOrder(tempDecode,2); |
switch (tempDecode) |
{ |
case 0xFE: // get image subfile type |
BlockMoveData(&iFDStore[8],&tempDecode,4); |
if (tempDecode!=0) |
DebugStr("\pIFD new subfile type not supported"); |
break; |
case 0x100: // image width |
BlockMoveData(&iFDStore[2],&tempDecode,2); |
tempDecode=tempDecode>>16; |
if (isIntFormat) |
tempDecode = SwapByteOrder(tempDecode,2); |
if (tempDecode==3) |
{ |
BlockMoveData(&iFDStore[8],&tempDecode,2); |
tempDecode=tempDecode>>16; |
if (isIntFormat) |
tempDecode = SwapByteOrder(tempDecode,2); |
} |
else |
{ |
BlockMoveData(&iFDStore[8],&tempDecode,4); |
if (isIntFormat) |
tempDecode = SwapByteOrder(tempDecode,4); |
} |
theTiffHeader->xImageSize = tempDecode; |
break; |
case 0x101: // image length |
BlockMoveData(&iFDStore[2],&tempDecode,2); |
tempDecode=tempDecode>>16; |
if (isIntFormat) |
tempDecode = SwapByteOrder(tempDecode,2); |
if (tempDecode==3) |
{ |
BlockMoveData(&iFDStore[8],&tempDecode,2); |
tempDecode=tempDecode>>16; |
if (isIntFormat) |
tempDecode = SwapByteOrder(tempDecode,2); |
} |
else |
{ |
BlockMoveData(&iFDStore[8],&tempDecode,4); |
if (isIntFormat) |
tempDecode = SwapByteOrder(tempDecode,4); |
} |
theTiffHeader->yImageSize = tempDecode; |
break; |
case 0x102: // bits per sample |
BlockMoveData(&iFDStore[8],&tempDecode,2); |
tempDecode=tempDecode>>16; |
if (isIntFormat) |
tempDecode = SwapByteOrder(tempDecode,2); |
theTiffHeader->bitDepth = tempDecode; |
break; |
case 0x103: // image compression NOT SUPPORTED YET!! |
BlockMoveData(&iFDStore[8],&tempDecode,2); |
tempDecode=tempDecode>>16; |
if (isIntFormat) |
tempDecode = SwapByteOrder(tempDecode,2); |
theTiffHeader->compressionType = tempDecode; |
if (tempDecode != 1) |
return kTIFFNotSupported; |
break; |
case 0x106: // Photometricinterpretation |
BlockMoveData(&iFDStore[8],&tempDecode,2); |
tempDecode=tempDecode>>16; |
if (isIntFormat) |
tempDecode = SwapByteOrder(tempDecode,2); |
theTiffHeader->PhotoInterpret = tempDecode; |
if (tempDecode > 3) |
return kTIFFNotSupported; |
break; |
case 0x111: // strip offsets for one strip. Is offset to data |
BlockMoveData(&iFDStore[2],&tempDecode,2); |
tempDecode=tempDecode>>16; |
if (tempDecode==3) |
{ |
BlockMoveData(&iFDStore[8],&tempDecode,2); |
tempDecode=tempDecode>>16; |
if (isIntFormat) |
tempDecode = SwapByteOrder(tempDecode,2); |
} |
else |
{ |
BlockMoveData(&iFDStore[8],&tempDecode,4); |
if (isIntFormat) |
tempDecode = SwapByteOrder(tempDecode,4); |
} |
theTiffHeader->imageOffset = tempDecode; // offset to image strip |
break; |
case 0x115: // samples per pixel 1 for palette, 3 for direct |
BlockMoveData(&iFDStore[8],&tempDecode,2); |
tempDecode=tempDecode>>16; |
if (isIntFormat) |
tempDecode = SwapByteOrder(tempDecode,2); |
theTiffHeader->bitDepth = tempDecode*8; |
if (theTiffHeader->bitDepth == 24) |
theTiffHeader->bitDepth = 32; // amend to 32 bpp to correctly create GWorld |
if (theTiffHeader->PhotoInterpret < 2) |
{ |
if (theTiffHeader->bitDepth == 8) // 8 Bit Greyscale image |
{ |
numberColors = 256; // number of entries in palette |
countStep = 1; |
} |
if (theTiffHeader->bitDepth == 4) // 4 Bit Greyscale image |
{ |
numberColors = 16; |
countStep = 16; |
} |
// Manually create the Color Table from TIFF file information |
cTabSize = sizeof(ColorTable)+(sizeof(ColorSpec)*(numberColors-1)); |
theTiffHeader->tiffCTabHndl = (CTabHandle) NewHandle(cTabSize); |
if (theTiffHeader->tiffCTabHndl == nil || MemError()) |
{ |
return kDefaultAppError; |
} |
(**theTiffHeader->tiffCTabHndl).ctFlags = 0; |
(**theTiffHeader->tiffCTabHndl).ctSize = numberColors-1; |
switch (theTiffHeader->PhotoInterpret) |
{ |
case 0: |
for (count=0;count<numberColors;count+=countStep) |
{ |
colorValue = (255 - count) << 8; |
(**theTiffHeader->tiffCTabHndl).ctTable[count].value = count; |
(**theTiffHeader->tiffCTabHndl).ctTable[count].rgb.red = colorValue; // red component |
(**theTiffHeader->tiffCTabHndl).ctTable[count].rgb.green = colorValue; // green component |
(**theTiffHeader->tiffCTabHndl).ctTable[count].rgb.blue = colorValue; // blue component |
} |
break; |
case 1: |
for (count=0;count<numberColors;count+=countStep) |
{ |
colorValue = count << 8; |
(**theTiffHeader->tiffCTabHndl).ctTable[count].value = count; |
(**theTiffHeader->tiffCTabHndl).ctTable[count].rgb.red = colorValue; // red component |
(**theTiffHeader->tiffCTabHndl).ctTable[count].rgb.green = colorValue; // green component |
(**theTiffHeader->tiffCTabHndl).ctTable[count].rgb.blue = colorValue; // blue component |
} |
break; |
} |
CTabChanged(theTiffHeader->tiffCTabHndl); |
} |
break; |
case 0x116: // number of rows per image strip |
BlockMoveData(&iFDStore[2],&tempDecode,2); |
tempDecode = tempDecode>>16; |
if (isIntFormat) |
tempDecode = SwapByteOrder(tempDecode,2); |
if (tempDecode == 3) |
{ |
BlockMoveData(&iFDStore[8],&tempDecode,2); |
tempDecode=tempDecode>>16; |
if (isIntFormat) |
tempDecode = SwapByteOrder(tempDecode,2); |
} |
else |
{ |
BlockMoveData(&iFDStore[8],&tempDecode,4); |
if (isIntFormat) |
tempDecode = SwapByteOrder(tempDecode,4); |
} |
theTiffHeader->rowStrip = tempDecode; |
break; |
case 0x11C: |
BlockMoveData(&iFDStore[8],&tempDecode,2); |
if (isIntFormat) |
tempDecode = SwapByteOrder(tempDecode,2); |
theTiffHeader->PlanarConfig = tempDecode>>16; |
break; |
case 0x140: // image clut for palette images |
if (theTiffHeader->bitDepth == 8) // 8 Bit palette image |
numberColors = 256; // number of entries in palette |
if (theTiffHeader->bitDepth == 4) // 4 Bit palette image |
numberColors = 16; |
cTabSize = sizeof(ColorTable)+(sizeof(ColorSpec)*(numberColors-1)); |
theTiffHeader->tiffCTabHndl = (CTabHandle) NewHandle(cTabSize); |
if (theTiffHeader->tiffCTabHndl==nil) |
{ |
return kDefaultAppError; |
} |
(**theTiffHeader->tiffCTabHndl).ctFlags = 0; |
(**theTiffHeader->tiffCTabHndl).ctSize = numberColors-1; |
BlockMoveData(&iFDStore[8],&tempDecode,4); |
if (isIntFormat) |
tempDecode = SwapByteOrder(tempDecode,4); |
GetFPos(theFileSpec.sfFile.vRefNum,&myOldFilePos); // get old file position |
SetFPos(theFileSpec.sfFile.vRefNum,fsFromStart,tempDecode); // set new file pos |
fileLen = sizeof(short); |
for (count=0;count<numberColors;count++) |
{ |
(**theTiffHeader->tiffCTabHndl).ctTable[count].value = count; |
FSRead(theFileSpec.sfFile.vRefNum,&fileLen,&tempDecode); |
tempDecode = tempDecode>>16; |
if (isIntFormat) |
tempDecode = SwapByteOrder(tempDecode,2); |
(**theTiffHeader->tiffCTabHndl).ctTable[count].rgb.red = tempDecode; // red component |
} |
for (count=0;count<numberColors;count++) |
{ |
FSRead(theFileSpec.sfFile.vRefNum,&fileLen,&tempDecode); |
tempDecode = tempDecode>>16; |
if (isIntFormat) |
tempDecode = SwapByteOrder(tempDecode,2); |
(**theTiffHeader->tiffCTabHndl).ctTable[count].rgb.green = tempDecode; // green component |
} |
for (count=0;count<numberColors;count++) |
{ |
FSRead(theFileSpec.sfFile.vRefNum,&fileLen,&tempDecode); |
tempDecode = tempDecode>>16; |
if (isIntFormat) |
tempDecode = SwapByteOrder(tempDecode,2); |
(**theTiffHeader->tiffCTabHndl).ctTable[count].rgb.blue = tempDecode; // blue component |
} |
CTabChanged(theTiffHeader->tiffCTabHndl); |
SetFPos(theFileSpec.sfFile.vRefNum,fsFromStart,myOldFilePos); |
break; |
case 0x153: // Sample Format tag |
BlockMoveData(&iFDStore[8],&tempDecode,2); |
tempDecode=tempDecode>>16; |
if (isIntFormat) |
tempDecode = SwapByteOrder(tempDecode,2); |
if (tempDecode != 1) |
return kTIFFNotSupported; |
break; |
case 0x142: // handle unsupported tags which could cause incorrect image display |
case 0x143: |
case 0x152: |
return kTIFFNotSupported; |
break; |
} |
entriesLeft--; |
} while (entriesLeft!=0); // read all tags |
// multi IFD stuff Needs to be expanded to support |
fileLen = sizeof(iFDOffset); |
FSRead(theFileSpec.sfFile.vRefNum,&fileLen,iFDOffset);// get pattern header info |
BlockMoveData(iFDOffset,&theTiffHeader->offsetToIFD,4); |
if (isIntFormat) |
tempDecode = SwapByteOrder(tempDecode,4); |
SetFPos(theFileSpec.sfFile.vRefNum,fsFromStart,theTiffHeader->offsetToIFD); |
theTiffHeader->offsetToIFD = 0; // force to zero as don't support multiple images in file |
} while (theTiffHeader->offsetToIFD!=0); // read next IFD if present |
FSClose(theFileSpec.sfFile.vRefNum); // close open file |
return error; |
} |
/**** Draw the TIFF image data directly into the offscreen pixmap ****/ |
#pragma segment fileSys |
OSErr LoadTiffToGWorld (ImageDocHndl theImageDocHndl, TiffInfoPtr theTiffInfo, short bitDepth) |
{ |
PixMapHandle thePixMapHndl = nil; |
CursHandle watchCrsr; |
Ptr imageLinePtr = nil, |
theLinePosPtr; |
float theBarStepValue, |
theBarValue; |
long theFileLen, |
imageLeft = theTiffInfo->rowStrip, |
imageLineStart, |
spinCounter = 0; |
StandardFileReply theFileSpec = (**theImageDocHndl).theImageFileReply; // use local as FSpOpen returns param in spec |
OSErr error = noErr; |
short theGWrowBytes, |
xCount, |
imageWidth; |
thePixMapHndl = GetGWorldPixMap((*theImageDocHndl)->theImageWorld); |
if (PixMap32Bit(thePixMapHndl)) |
SaveSetMMUMode(true); |
if (!LockPixels(thePixMapHndl)) |
error = kFailedLockPixels; |
if (!error) |
{ |
theBarStepValue = (float)kProgressSteps/(*theImageDocHndl)->theImageYSize; |
theBarValue = theBarStepValue; // intialise progress bar value |
error = FSpOpenDF(&theFileSpec.sfFile,fsRdPerm,&theFileSpec.sfFile.vRefNum); |
error |= SetFPos(theFileSpec.sfFile.vRefNum,fsFromStart,theTiffInfo->imageOffset); |
if (!error) |
{ |
imageLinePtr = GetPixBaseAddr(thePixMapHndl); // base addr of GWorld |
imageLineStart = (long)imageLinePtr; |
theGWrowBytes = (**thePixMapHndl).rowBytes & 0x3FFF; |
// Display the progress bar dialog to provide feedback on load operation. |
DisplayProgressBarDlog(kDisplayProgressWindow, 0 , rProgressMessages, iLoading); |
// Read in imaga data from file into Pixmap |
switch (bitDepth) |
{ |
case 8: |
theFileLen = (**thePixMapHndl).bounds.right - (**thePixMapHndl).bounds.left; |
watchCrsr = GetCursor(watchCursor); |
SetCursor(*watchCrsr); |
do{ |
FSRead(theFileSpec.sfFile.vRefNum,&theFileLen,imageLinePtr); // get count |
imageLinePtr+=theGWrowBytes; |
imageLeft--; |
theBarValue += theBarStepValue; |
DisplayProgressBarDlog(kUpdateProgressWindow, (short)theBarValue, 0, 0); |
RotateCursor(spinCounter+=8); |
} while (imageLeft); |
SetCursor(&qd.arrow); |
break; |
case 16: |
DebugStr("\p16 bit color depth not supported"); |
break; |
case 32: |
theFileLen = 3; |
imageWidth = (**thePixMapHndl).bounds.right - (**thePixMapHndl).bounds.left; |
watchCrsr = GetCursor(watchCursor); |
SetCursor(*watchCrsr); |
do{ |
theLinePosPtr = imageLinePtr; |
theLinePosPtr++; |
for (xCount = 0;xCount<imageWidth;xCount++) |
{ |
FSRead(theFileSpec.sfFile.vRefNum,&theFileLen,theLinePosPtr); |
theLinePosPtr+=4; |
} |
imageLinePtr+=theGWrowBytes; |
imageLeft--; |
theBarValue += theBarStepValue; |
DisplayProgressBarDlog(kUpdateProgressWindow, (short)theBarValue, 0, 0); |
RotateCursor(spinCounter+=8); |
} while (imageLeft); |
SetCursor(&qd.arrow); |
break; |
} |
UnlockPixels(thePixMapHndl); |
DisplayProgressBarDlog(kDisposeProgressWindow,0,0,0); |
} |
else |
DebugStr("\pError opening and setting file offset in LoadTiffToGWorld"); |
} |
SaveSetMMUMode(false); |
return error; |
} |
/**** Swap the byte order between little and big endian formats ****/ |
#pragma segment fileSys |
long SwapByteOrder(long theData,short theDataLength) |
{ |
long tempStore, |
tempStore2, |
tempStore3, |
tempStore4; |
switch(theDataLength) |
{ |
case (2): |
tempStore = theData << 8; |
tempStore = tempStore & 0x0000FF00; |
tempStore2 = theData >> 8; |
tempStore2 = tempStore2 & 0x000000FF; |
theData = tempStore + tempStore2; |
break; |
case (4): |
tempStore = theData << 24; |
tempStore = tempStore & 0xFF000000; |
tempStore2 = theData << 8; |
tempStore2 = tempStore2 & 0x00FF0000; |
tempStore3 = theData >> 8; |
tempStore3 = tempStore3 & 0x0000FF00; |
tempStore4 = theData >> 24; |
tempStore4 = tempStore4 & 0x000000FF; |
theData = tempStore + tempStore2 + tempStore3 + tempStore4; |
break; |
} |
return theData; |
} |
/**** Load PICT file into PicHandle ****/ |
// Basic PICT file load function that takes a PICT file |
// and returns the loaded image in a PicHandle structure. |
// If an error occurs nil is returned to indicate load problem. |
#pragma segment fileSys |
PicHandle LoadPictImageFile(ImageDocHndl theDocHndl) |
{ |
PicHandle thePictHndl; |
long thePictFileSize; |
StandardFileReply theFileSpec = (**theDocHndl).theImageFileReply; |
short theFileRef; |
OSErr error = noErr; |
error = FSpOpenDF(&theFileSpec.sfFile, fsRdPerm, &theFileRef); |
if (!error) |
{ |
error = GetEOF(theFileRef, &thePictFileSize); |
if(error) |
{ |
FSClose(theFileSpec.sfFile.vRefNum); |
return nil; |
} |
if(SetFPos(theFileRef,fsFromStart,512)) |
{ |
FSClose(theFileRef); |
return nil; |
} |
thePictFileSize -= 512; // Remove unwanted 512 byte header |
thePictHndl = (PicHandle)NewHandle(thePictFileSize); |
if(thePictHndl == nil) |
{ |
FSClose(theFileRef); |
return nil; |
} |
HLock((Handle)thePictHndl); |
error = FSRead(theFileRef,&thePictFileSize,(Ptr)*thePictHndl); |
HUnlock((Handle)thePictHndl); |
FSClose(theFileRef); |
if(error) |
return nil; |
return thePictHndl; |
} |
return nil; |
} |
/**** Draw PicHandle into GWorld PixMap ****/ |
// Draw a PICT contained in a PicHandle into a GWorld |
// attached to the passed document structure parameter |
#pragma segment fileSys |
OSErr DrawPictToGWorld (ImageDocHndl theDocHndl,PicHandle thePictHndl) |
{ |
PixMapHandle theGWorldPMHndl; |
GDHandle oldGDHndl; |
CGrafPtr oldGWorld; |
OSErr error = noErr; |
GetGWorld(&oldGWorld, &oldGDHndl); |
SetGWorld((**theDocHndl).theImageWorld, nil); |
// Reset foreground and background colors to black and white |
// so no colorisation effects occur. |
RGBForeColor(&kRGBBlack); |
RGBBackColor(&kRGBWhite); |
theGWorldPMHndl = GetGWorldPixMap((**theDocHndl).theImageWorld); |
LockPixels(theGWorldPMHndl); |
EraseRect(&(**theDocHndl).theImageWorld->portRect); |
// Reset the transfer mode |
PenMode(srcCopy); |
// render the image into the offscreen buffer |
DrawPicture(thePictHndl, &(**theDocHndl).theImageWorld->portRect); |
UnlockPixels(theGWorldPMHndl); |
SetGWorld(oldGWorld, oldGDHndl); |
// dispose of unwanted picHandle structure |
DisposeHandle((Handle)thePictHndl); |
return error; |
} |
/**** Save supported file types ****/ |
// Main function to perform the saving of supported image file types. |
#pragma segment fileSys |
OSErr SaveSupportedImageFile(ImageDocHndl theDocHndl) |
{ |
StandardFileReply theSFReply; |
DlgHookYDUPP theDialogHookUPP; |
Point dlogPosition = {-1,-1}; |
OSErr error = noErr; |
gSaveFileType = (*theDocHndl)->theFileType; |
theDialogHookUPP = NewDlgHookYDProc(CustomPutFileHook); |
CustomPutFile((ConstStr255Param)kNull_Str, (**theDocHndl).theImageFileReply.sfFile.name, |
&theSFReply, rCustomSaveDialog,dlogPosition, theDialogHookUPP, |
nil, nil, nil, nil); |
DisposeRoutineDescriptor((UniversalProcPtr)theDialogHookUPP); |
if (theSFReply.sfGood) |
{ |
/**** Dispose Temp file if present ****/ |
if ((*theDocHndl)->hasUndoTemp || (*theDocHndl)->hasRedoTemp) |
RemoveTempFile(theDocHndl, true, true); |
switch (gSaveFileType) |
{ |
case TiffType: |
break; |
case PictType: |
if ( !(*theDocHndl)->isUsingQDGX ) |
{ |
error = SavePictImage(theDocHndl, &theSFReply); |
switch (error) |
{ |
case kFailPictCompSave: |
DisplayAlert(rGenAlert,rFileIOMessages,iSaveCompPICTErr); |
break; |
case kFailPictUnCompSave: |
DisplayAlert(rGenAlert,rFileIOMessages,iSaveUnCompPICTErr); |
break; |
case kFailedLockPixels: |
DisplayAlert(rGenAlert,rQDMessages,iFailLockPixmap); |
break; |
} |
} |
break; |
case GXType: |
if ( (*theDocHndl)->isUsingQDGX ) |
{ |
error = SaveQdGxShape(theDocHndl, &theSFReply); |
if (error) |
DisplayAlert(rGenAlert,rFileIOMessages,iSaveQDGXErr); |
} |
break; |
} |
} |
return error; |
} |
/**** CustomPutFile dialog file hook function ****/ |
#pragma segment fileSys |
pascal short CustomPutFileHook(short item,DialogPtr theDlogPtr,void* theData) |
{ |
Handle theHandle; |
Rect theRect; |
short theType, |
ignored; |
if (GetWRefCon((WindowPtr)theDlogPtr) != sfMainDialogRefCon) |
return item; |
switch (item) |
{ |
case sfHookFirstCall: |
GetDItem(theDlogPtr,kSaveFilePopUpItem,&theType,&theHandle,&theRect); |
switch (gSaveFileType) |
{ |
case TiffType: |
theType = iSaveTiffType; |
break; |
case PictType: |
theType = iSavePictType; |
break; |
case GXType: |
theType = iSaveGXType; |
break; |
} |
SetCtlValue((ControlHandle)theHandle,theType); |
return sfHookNullEvent; |
break; |
case kSaveFilePopUpItem: |
GetDItem(theDlogPtr,item,&ignored,&theHandle,&theRect); |
theType = GetCtlValue((ControlHandle)theHandle); |
switch (theType) |
{ |
case iSaveTiffType: |
gSaveFileType = TiffType; |
break; |
case iSavePictType: |
gSaveFileType = PictType; |
break; |
case iSaveGXType: |
gSaveFileType = GXType; |
break; |
} |
return sfHookNullEvent; |
break; |
} |
return item; |
} |
/**** Save image as PICT file ****/ |
#pragma segment fileSys |
OSErr SavePictImage(ImageDocHndl theDocHndl, StandardFileReply* thePictFile) |
{ |
Handle compDataHndl; |
Ptr compDataPtr; |
ImageDescriptionHandle compImageDescHndl = nil; |
PicHandle theSavePict = nil; |
GDHandle theGDevHndl; |
PixMapHandle theSavePictPixMapHndl = nil; |
GWorldPtr oldPort; |
long thePictLen, |
emptyDataSize = 4, |
emptyData = 0x00000000, |
maxCompSize = 0; |
CodecQ compQuality; |
Rect thePortRect; |
OpenCPicParams thePictParams; |
OSErr error = noErr, |
fileErr = noErr; |
short fileRefNum, |
compressionSetting, |
count; |
GetGWorld(&oldPort,&theGDevHndl); |
thePortRect = (**theDocHndl).theImageWorld->portRect; |
theSavePictPixMapHndl = GetGWorldPixMap((**theDocHndl).theImageWorld); |
if (PixMap32Bit(theSavePictPixMapHndl)) |
SaveSetMMUMode(true); |
if (LockPixels(theSavePictPixMapHndl)) |
{ |
/**** setup Color PICT paramaters ****/ |
thePictParams.srcRect = thePortRect; |
thePictParams.hRes = ff(72); |
thePictParams.vRes = ff(72); |
thePictParams.version = -2; |
thePictParams.reserved1 = 0; |
thePictParams.reserved2 = 0; |
// Display PICT compression setting dialog box |
compressionSetting = ProcessPictCompDlog(); |
if (compressionSetting == kNoCompression) |
{ |
// Create uncompressed PicHandle ready to save to disk. |
SetGWorld((**theDocHndl).theImageWorld,nil); |
theSavePict = OpenCPicture(&thePictParams); |
ClipRect (&thePortRect); |
CopyBits((BitMap*)(*theSavePictPixMapHndl), |
(BitMap*)(*theSavePictPixMapHndl), |
&thePortRect, |
&thePortRect,srcCopy,nil); |
ClosePicture(); |
SetGWorld(oldPort,theGDevHndl); |
UnlockPixels(theSavePictPixMapHndl); |
} |
else |
{ |
// Image compression selected. Compress image using chosen setting |
// and create PicHandle containing the compressed image ready to save to disk |
switch (compressionSetting) |
{ |
case kHighQuality: |
compQuality = codecHighQuality; |
break; |
case kMediumQuality: |
compQuality = codecNormalQuality; |
break; |
case kLowQuality: |
compQuality = codecLowQuality; |
break; |
} |
error = GetMaxCompressionSize(theSavePictPixMapHndl, |
&thePortRect,0,compQuality, |
'jpeg',anyCodec,&maxCompSize); |
if (error != noErr || maxCompSize == 0) |
{ |
UnlockPixels(theSavePictPixMapHndl); |
SaveSetMMUMode(false); |
return kDefaultAppError; |
} |
compImageDescHndl = (ImageDescriptionHandle) NewHandle(4); |
compDataHndl = NewHandle(maxCompSize); |
if (compImageDescHndl != nil && compDataHndl != nil) |
{ |
HLock(compDataHndl); |
compDataPtr = StripAddress(*compDataHndl); |
error = CompressImage (theSavePictPixMapHndl,&thePortRect, |
compQuality,'jpeg',compImageDescHndl,compDataPtr); |
if (error != noErr) |
{ |
RemoveOldSaveData(compImageDescHndl,compDataHndl,theSavePictPixMapHndl); |
SaveSetMMUMode(false); |
return kFailPictCompSave; |
} |
SetGWorld((**theDocHndl).theImageWorld,nil); |
theSavePict = OpenCPicture(&thePictParams); |
ClipRect (&thePortRect); |
error = DecompressImage(compDataPtr, compImageDescHndl, |
theSavePictPixMapHndl,&thePortRect, |
&thePortRect, srcCopy, nil); |
ClosePicture(); |
SetGWorld(oldPort,theGDevHndl); |
RemoveOldSaveData(compImageDescHndl,compDataHndl,theSavePictPixMapHndl); |
if (error) |
{ |
if (theSavePict) |
DisposeHandle((Handle)theSavePict); |
SaveSetMMUMode(false); |
return kFailPictCompSave; |
} |
} |
else |
{ |
RemoveOldSaveData(compImageDescHndl,compDataHndl,theSavePictPixMapHndl); |
SaveSetMMUMode(false); |
return kFailPictCompSave; |
} |
} |
} |
else |
return kFailedLockPixels; |
// Save image conatined in PicHandle structure to disk |
fileErr = FSpCreate(&thePictFile->sfFile,'ttxt','PICT',smSystemScript); |
if (!fileErr) |
fileErr = FSpOpenDF(&thePictFile->sfFile,fsRdWrPerm,&fileRefNum); |
if (!fileErr) |
{ |
for (count = 0;count<128;count++) |
FSWrite(fileRefNum,&emptyDataSize,&emptyData); |
thePictLen = GetHandleSize((Handle)theSavePict); |
HLock((Handle)theSavePict); |
fileErr = FSWrite(fileRefNum,&thePictLen,*theSavePict); |
fileErr |= FSClose(fileRefNum); |
HUnlock((Handle)theSavePict); |
if (fileErr) |
{ |
switch (compressionSetting) |
{ |
case kNoCompression: |
error = kFailPictUnCompSave; |
break; |
default: |
error = kFailPictCompSave; |
break; |
} |
} |
} |
SaveSetMMUMode(false); |
if (theSavePict) |
DisposeHandle((Handle)theSavePict); |
return error; |
} |
/**** handle processing of the PICT file settings dialog ****/ |
#pragma segment fileSys |
short ProcessPictCompDlog(void) |
{ |
Handle theItemHandle; |
DialogPtr theDialog = nil; |
ModalFilterUPP theFilter = nil; |
GrafPtr oldPort; |
Rect theRect; |
short theCompSetting = kNoCompression; |
short theItem, |
theNextItem, |
theItemType, |
count; |
GetPort(&oldPort); |
theDialog = GetNewDialog(rPictCompDialog,nil,((WindowPtr)-1L)); |
SetPort(theDialog); |
if (!GetStdFilterProc(&theFilter)) |
SetDialogDefaultItem(theDialog,1); |
GetDialogItem(theDialog,theCompSetting,&theItemType,&theItemHandle,&theRect); |
SetControlValue((ControlHandle)theItemHandle,1); |
do{ |
ModalDialog(nil,&theItem); |
GetDialogItem(theDialog,theItem,&theItemType,&theItemHandle,&theRect); |
if (theItemType == kRadioButton) |
{ |
for (count = kNoCompression; count<=kLowQuality; count++) |
{ |
GetDialogItem(theDialog,count,&theItemType,&theItemHandle,&theRect); |
if (count == theItem) |
{ |
SetControlValue((ControlHandle)theItemHandle,1); |
theCompSetting = count; |
} |
else |
SetControlValue((ControlHandle)theItemHandle,0); |
} |
} |
} while (theItem != kOkButton); |
DisposeDialog(theDialog); |
SetPort(oldPort); |
return theCompSetting; |
} |
/**** Clean up after save file ****/ |
#pragma segment fileSys |
void RemoveOldSaveData(ImageDescriptionHandle theImageDescH, Handle theDataH, PixMapHandle thePixMapHndl) |
{ |
UnlockPixels(thePixMapHndl); |
if (theImageDescH) |
DisposeHandle((Handle)theImageDescH); |
if (theDataH) |
{ |
HUnlock(theDataH); |
DisposeHandle(theDataH); |
} |
} |
/**** convert QuickDraw GX shape to handle for saving to disk ****/ |
#pragma segment fileSys |
void SaveGXShapeToFile(gxShape theShape, gxFlattenFlag theFlags, short fileRefNum) |
{ |
UserGXSpool dataBlock; |
dataBlock.spool.spoolProcedure = NewgxSpoolProc(FileSpoolProc); |
dataBlock.reference = fileRefNum; |
dataBlock.spool.buffer = nil; |
dataBlock.spool.bufferSize = 0; |
GXFlattenShape(theShape, theFlags, &dataBlock.spool); |
DisposeRoutineDescriptor(dataBlock.spool.spoolProcedure); |
} |
/**** Save flatten QD GX shape to disk ****/ |
#pragma segment fileSys |
OSErr SaveQdGxShape(ImageDocHndl theDocHndl, StandardFileReply* thePictFile) |
{ |
OSErr fileErr = noErr; |
short theRefNum; |
if ((*theDocHndl)->theGXImageShape == nil) |
return kFailQDGXSave; |
fileErr = FSpCreate(&thePictFile->sfFile,(OSType)AppCreator,'qdgx',smSystemScript); |
if (!fileErr) |
fileErr = FSpOpenDF(&thePictFile->sfFile,fsRdWrPerm,&theRefNum); |
if (fileErr) |
DebugStr("\pFile error creating QDGX file for save operation"); |
SaveGXShapeToFile((*theDocHndl)->theGXImageShape, 0,theRefNum); |
fileErr |= FSClose(theRefNum); |
if (fileErr) |
fileErr = kFailQDGXSave; |
return fileErr; |
} |
/**** QuickDraw GX shape to file Spooling function ****/ |
#pragma segment fileSys |
static long FileSpoolProc(gxSpoolCommand command, UserGXSpool *block) |
{ |
OSErr error = noErr; |
switch (command) |
{ |
case gxOpenReadSpool: |
break; |
case gxOpenWriteSpool: |
break; |
case gxReadSpool: |
break; |
case gxWriteSpool: |
{ |
long count = block->spool.count; |
error = FSWrite(block->reference, &count, block->spool.buffer); |
if (error) |
DebugStr("\pFSWrite failed"); |
} |
break; |
case gxCloseSpool: |
break; |
default: |
DebugStr("\punexpected spool command"); |
break; |
} |
return noErr; |
} |
/**** Revert image to last saved image ****/ |
#pragma segment fileSys |
OSErr RevertToSavedFile(ImageDocHndl theDocHndl, WindowPtr theWindow) |
{ |
PicHandle thePictHndl = nil; |
PictInfo thePictInfo; |
GrafPtr oldPort; |
TiffInfo theTiffStruct; |
OSErr error = noErr; |
(**theDocHndl).theImageChanged = false; |
if ((**theDocHndl).hasUndoTemp) |
{ |
RemoveTempFile(theDocHndl, true, false); |
(**theDocHndl).hasUndoTemp = false; |
} |
if ((**theDocHndl).hasRedoTemp) |
{ |
RemoveTempFile(theDocHndl, false, true); |
(**theDocHndl).hasRedoTemp = false; |
} |
(**theDocHndl).theUndoState = kCannotUndo; |
if ((**theDocHndl).theImageWorld) |
DisposeGWorld((**theDocHndl).theImageWorld); |
if ((**theDocHndl).theColorsPalette) |
DisposePalette((**theDocHndl).theColorsPalette); |
if ((**theDocHndl).isUsingQDGX) |
{ |
GXDisposeShape((**theDocHndl).theGXImageShape); |
GXDisposeInk((**theDocHndl).theInkShape); |
GXDisposeViewPort((**theDocHndl).theGxChildView); |
GXDisposeViewPort((**theDocHndl).theGXview); |
} |
switch ((*theDocHndl)->theFileType) |
{ |
case TiffType: |
theTiffStruct.tiffCTabHndl = nil; // set to nil as Color table not always created |
GetTIFFHdrInfo(theDocHndl,&theTiffStruct); |
GetTIFFIFDirectory(theDocHndl,&theTiffStruct); |
switch (theTiffStruct.bitDepth) |
{ |
case 8: |
(**theDocHndl).theImageWorld = |
CreateOffscreen(theTiffStruct.tiffCTabHndl, |
theTiffStruct.xImageSize, |
theTiffStruct.yImageSize, |
theTiffStruct.bitDepth,kNoFlags); |
if ((**theDocHndl).theImageWorld == nil) |
{ |
DisposeHandle((Handle)theDocHndl); |
return kFailMakeGWorld; |
} |
break; |
case 32: |
(**theDocHndl).theImageWorld = |
CreateOffscreen(nil, |
theTiffStruct.xImageSize, |
theTiffStruct.yImageSize, |
theTiffStruct.bitDepth,kNoFlags); |
if ((**theDocHndl).theImageWorld == nil) |
{ |
DisposeHandle((Handle)theDocHndl); |
return kFailMakeGWorld; |
} |
break; |
default: |
DisplayAlert (rGenWarning,rErrMessages,iNoSupportBitDepth); |
return kBitDepthErr; |
break; |
} |
error = LoadTiffToGWorld (theDocHndl,&theTiffStruct,theTiffStruct.bitDepth); |
if (error) |
{ |
DisplayAlert (rGenAlert,0,0); |
return error; |
} |
SetUndoItemText((*theDocHndl)->theUndoState); |
break; |
case PictType: |
thePictHndl = LoadPictImageFile(theDocHndl); |
if (!thePictHndl) |
{ |
DisposeHandle((Handle)theDocHndl); |
return kDefaultAppError; |
} |
// test if minimal temp memory free available. If none available GetPictInfo() fails. |
if (TempFreeMem() < kMinLowMem) |
{ |
DisplayAlert(rGenWarning,rErrMessages,iLowTempMem); |
DisposeHandle((Handle)theDocHndl); |
return kLowMemWarning; |
} |
error = GetPictInfo (thePictHndl, &thePictInfo, returnColorTable,256,systemMethod,0); |
if (!error && thePictInfo.depth <= 8) |
(**theDocHndl).theImageWorld = |
CreateOffscreen(thePictInfo.theColorTable, |
(**theDocHndl).theImageXSize, |
(**theDocHndl).theImageYSize, |
(**theDocHndl).theImageDepth,kNoFlags); |
else |
(**theDocHndl).theImageWorld = |
CreateOffscreen(nil, |
(**theDocHndl).theImageXSize, |
(**theDocHndl).theImageYSize, |
(**theDocHndl).theImageDepth,kNoFlags); |
if ((**theDocHndl).theImageWorld == nil) |
{ |
DisposeHandle((Handle)theDocHndl); // dispose image document |
DisposeHandle((Handle)thePictHndl); // dispose picHandle |
return kFailMakeGWorld; |
} |
error = DrawPictToGWorld (theDocHndl,thePictHndl); |
SetUndoItemText((*theDocHndl)->theUndoState); |
break; |
case GXType: |
DisplayAlert(rGenWarning,rErrMessages,iNotImplemented); |
return noErr; |
break; |
} |
GetPort(&oldPort); |
SetPort(theWindow); |
InvalRect(&theWindow->portRect); |
SetPort(oldPort); |
return error; |
} |
/**** Clean up after abort TIFF load ****/ |
#pragma segment fileSys |
void CleanLoadAbort(ImageDocHndl theDocHndl) |
{ |
if ((**theDocHndl).theColorsPalette) |
DisposePalette((**theDocHndl).theColorsPalette); |
DisposeHandle((Handle)theDocHndl); |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14