JPEGView/Source/C/SaveOpen.c
Aaron Giles 92bdb55672 JPEGView 3.3 for Macintosh
These are the sources for the final official release of JPEGView for the
Mac, back in 1994.
2015-02-05 00:18:10 -08:00

1 line
33 KiB
C

/*********************************************************/
/* This source code copyright (c) 1991-2001, Aaron Giles */
/* See the Read Me file for licensing information. */
/* Contact email: mac@aarongiles.com */
/*********************************************************/
#if THINK_C
#include "THINK.Header"
#elif applec
#pragma load ":Headers:MPW.Header"
#elif __MWERKS__
//#include "MW.Header"
#else
#include "JPEGView.h"
#endif
static OSErr MakePreviewAndIcons(Handle theHandle, ImageHandle theImage, Boolean preview,
Boolean icons, NestedProgressPtr progProc, short cropWhat);
static OSErr AddQuickTimePreview(FSSpec *theFile, GWorldPtr thePreview, Rect *theRect);
static OSErr MakeIcons(FSSpec *theSpec, ImageHandle theImage);
static OSErr MakeOneIcon(short theFile, OSType theType, GWorldPtr src, GWorldPtr dst,
Rect *srcRect, Rect *dstRect);
static void TrimIcon(Rect *theRect);
static OSErr PixMapToHandle(PixMapHandle theMap, Rect *theRect, Rect *maskRect, Handle *theHandle);
static Rect gPreviewRect, gIconRect;
/*
* DoSaveDocument(theImage, theSpec, theType, preview, palette)
*
* Purpose: Oversees the saving of a JPEG image file
* Inputs: theImage = the image to be saved
* theSpec = pointer to the destination file spec
* theType = the destination type
* preview = flag: true to create and save a preview image
* palette = flag: true to save the palette with the image
* Returns: an OSErr describing the result
*
*/
OSErr DoSaveDocument(ImageHandle theImage, FSSpec *theSpec, OSType theType, Boolean preview,
Boolean palette, Boolean icons, short cropWhat)
{
short total = (preview || icons) ? 1 : 0, i, theFile;
NestedProgress theProc = { { nil, 0 }, 0, 0L, 0L };
FSSpec tempSpec, oldSpec = (*theImage)->file;
Handle finalData = (*theImage)->data;
ImageFormatPtr theAction = nil;
OSErr theErr = noErr;
// see if we can find the destination type in the type list
for (i = 0; i < kFileFormats; i++)
if (theType == gFormat[i]->outType) {
if (((*theImage)->compression == kJPEGCompression && !gFormat[i]->fix) ||
((*theImage)->compression != kJPEGCompression && gFormat[i]->save != (*theImage)->format->save)) continue;
theAction = gFormat[i];
break;
}
if (!theAction) return errAETypeError;
// ensure that we can actually save the current image in the requested format
if (Banded(theImage) && !theAction->doesBanded) return errAETypeError;
// adjust parameters to match the output format's limitations
palette = palette && theAction->doesColors && (*theImage)->depth > 8;
// initialize the progress proc, and open it right away
theProc.prog.progressProc = gGenericProgress;
theProc.prog.progressRefCon = (long)&theProc;
UpdateParamText(gString[strPreparing], gNullString, gNullString, (*theImage)->file.name);
CallICMProgressProc(theProc.prog.progressProc, codecProgressOpen, 0L,
theProc.prog.progressRefCon);
// determine the temporary file name
(*theImage)->file = *theSpec;
FSMakeFSSpec(theSpec->vRefNum, theSpec->parID, gString[strJPEGViewTempFile], &tempSpec);
// if we want to save a palette, and we haven't calculated it yet, do it now
if (palette && !(*theImage)->qpalette) {
short depth = (*(*theImage)->dmon)->depth;
PaletteHandle thePalette;
if (depth < 4 || depth > 8) depth = 8;
total++;
theProc.end = 0x0000F000 / total;
theErr = DoQuantize(theImage, 1L << depth, &thePalette, &theProc);
theProc.prog.progressRefCon = (long)&theProc;
if (theErr == noErr) (*theImage)->qpalette = thePalette;
}
if (theErr == noErr) {
// update the progress, and do any internal JPEG conversions that are necessary
theProc.begin = theProc.end;
theProc.end += total ? (0x0000F000 / total) : 0L;
KeepSpinning();
if ((*theImage)->compression == kJPEGCompression && theAction->fix)
theErr = theAction->fix(theImage, &finalData, palette);
// if everything's ok, create previews and icons
if (theErr == noErr) theErr = MakePreviewAndIcons((*theImage)->data, theImage,
preview, icons, &theProc, cropWhat);
theProc.prog.progressRefCon = (long)&theProc;
KeepSpinning();
// now, do the actual saving of the image
if (theErr == noErr)
UpdateParamText(gString[strSaving], gNullString, gNullString, (*theImage)->file.name);
if (theErr == noErr)
if (theAction->save) theErr = theAction->save(&tempSpec, finalData,
preview ? gPreviewGWorld : nil, &gPreviewRect, (*theImage)->privateData);
else theErr = DefaultSave(&tempSpec, finalData, nil, nil, theAction->outType);
if (theErr == noErr && preview && !theAction->customPreviews)
theErr = AddQuickTimePreview(&tempSpec, gPreviewGWorld, &gPreviewRect);
KeepSpinning();
// if everything's still ok, we actually add the icons to the new file
if (theErr == noErr && icons) {
FSpCreateResFile(&tempSpec, kCreator, theType, 0);
theErr = MakeIcons(&tempSpec, theImage);
}
// if things are still going well, we save the cropping rectangle as well
if (theErr == noErr && (Cropped(theImage) || cropWhat == kCropImage)) {
Rect **theRect = (Rect **)NewHandle(sizeof(Rect));
if (theRect) {
if (cropWhat == kCropImage) SelRectToCropRect(theImage, *theRect);
else **theRect = (*theImage)->crect;
FSpCreateResFile(&tempSpec, kCreator, theType, 0);
if (theFile = FSpOpenResFile(&tempSpec, fsRdWrPerm)) {
AddResource((Handle)theRect, 'RECT', 0, gNullString);
if ((theErr = ResError()) == noErr) WriteResource((Handle)theRect);
else gIntError = errCantWriteFile;
CloseResFile(theFile);
} else theErr = ResError(), gIntError = errCantWriteFile;
if (theErr != noErr) DisposeHandle((Handle)theRect);
} else theErr = memFullErr, gIntError = errNoSaveMemory;
}
if (finalData && finalData != (*theImage)->data) DisposeHandle(finalData);
KeepSpinning();
// finally, if nothing bad happened, exchange the temp file for the real file
if (theErr == noErr) {
theErr = FSpExchangeFiles(theSpec, &tempSpec);
if (theErr == fnfErr) theErr = FSpRename(&tempSpec, theSpec->name);
if (theErr == noErr) {
FInfo theInfo;
theErr = FSpGetFInfo(theSpec, &theInfo);
if (theErr == noErr) {
if (icons) theInfo.fdFlags |= kHasCustomIcon;
theInfo.fdFlags &= ~kHasBeenInited;
theInfo.fdCreator = kCreator;
theInfo.fdType = theType;
theErr = FSpSetFInfo(theSpec, &theInfo);
}
}
}
}
// clean up and get outta here
FSpDelete(&tempSpec);
KeepSpinning();
ForceFolderUpdate(theSpec->parID, theSpec->vRefNum);
theProc.end = 0x00010000;
CallICMProgressProc(theProc.prog.progressProc, codecProgressClose, 0L,
theProc.prog.progressRefCon);
(*theImage)->file = oldSpec;
return theErr;
}
extern OSErr DefaultSave(FSSpec *theSpec, Handle theHandle, GWorldPtr thePreview,
Rect *theRect, OSType theType)
{
#if applec
#pragma unused(thePreview, theRect)
#endif
long theSize = GetHandleSize(theHandle);
char hState = HGetState(theHandle);
short theFile;
OSErr theErr;
KeepSpinning();
theErr = FSpCreate(theSpec, kCreator, theType, 0);
if (theErr == noErr) {
KeepSpinning();
theErr = FSpOpenDF(theSpec, fsWrPerm, &theFile);
if (theErr == noErr) {
HLock(theHandle);
SpinIndef();
theErr = FSWrite(theFile, &theSize, *theHandle);
KeepSpinning();
if (theErr == noErr) {
HSetState(theHandle, hState);
if (theErr == noErr) {
FSClose(theFile);
return theErr;
}
} else gIntError = errCantWriteFile;
HSetState(theHandle, hState);
FSClose(theFile);
} else gIntError = errCantOpenFile;
FSpDelete(theSpec);
} else gIntError = errCantCreateFile;
return theErr;
}
static OSErr MakePreviewAndIcons(Handle theHandle, ImageHandle theImage, Boolean preview,
Boolean icons, NestedProgressPtr progProc, short cropWhat)
{
#if applec
#pragma unused(theHandle)
#endif
Rect prevSrcRect, iconSrcRect, prevDstRect, iconDstRect = { 0, 0, 32, 32 }, tmpRect;
PixMapHandle dstPixMap = GetGWorldPixMap(gPreviewGWorld);
short prevPort = -1, iconPort = -1;
JVDrawParamsHandle theParams;
StringPtr progressString;
OSErr theErr = noErr;
if (!preview && !icons) return noErr;
// calculate the appropriate source/destination rectangles
if (cropWhat != kCropImage) prevSrcRect = (*theImage)->crect;
else SelRectToCropRect(theImage, &prevSrcRect);
if (gThePrefs.iconStyle == isProportional || gThePrefs.iconStyle == isProportionalDog) {
if (cropWhat == kCropNothing) iconSrcRect = (*theImage)->crect;
else SelRectToCropRect(theImage, &iconSrcRect);
MaxRect(&iconSrcRect, &gIconGWorld->portRect, &iconDstRect);
} else {
if (cropWhat == kCropNothing) MaxSquare(&prevSrcRect, &iconSrcRect);
else {
SelRectToCropRect(theImage, &tmpRect);
MaxSquare(&tmpRect, &iconSrcRect);
}
}
MaxRect(&prevSrcRect, &gPreviewGWorld->portRect, &prevDstRect);
InsetRect(&iconDstRect, 1, 1);
// set up the progress procedure
if (preview && icons) progressString = gString[strCreatingPreviewIcons];
else if (preview) progressString = gString[strCreatingPreview];
else progressString = gString[strCreatingIcons];
UpdateParamText(progressString, gNullString, gNullString, (*theImage)->file.name);
// allocate and initialize the drawing parameters
tmpRect = (*theImage)->grect;
if (theParams = NewDrawParams(&tmpRect, iqVHigh, false, progProc, (*theImage)->privateData)) {
if (preview) SetUpDrawPort(theParams, kOffscreenPort1, gPreviewGWorld,
&prevSrcRect, &prevDstRect, true);
if (icons) SetUpDrawPort(theParams, preview ? kOffscreenPort2 : kOffscreenPort1,
gIconGWorld, &iconSrcRect, &iconDstRect, true);
// create the icons and preview
KeepSpinning();
theErr = PreflightDrawing(theParams);
PushPort();
if (theErr == noErr) {
// lock down the pixels and erase the GWorlds
LockPixels(GetGWorldPixMap(gPreviewGWorld));
MySetPort(gPreviewGWorld);
ClipRect(&gPreviewGWorld->portRect);
RGBForeColor(&gBlack);
RGBBackColor(&gWhite);
if (NeedsWhiteBG(theImage)) EraseRect(&gPreviewGWorld->portRect);
else PaintRect(&gPreviewGWorld->portRect);
LockPixels(GetGWorldPixMap(gIconGWorld));
MySetPort(gIconGWorld);
ClipRect(&gPreviewGWorld->portRect);
RGBForeColor(&gBlack);
RGBBackColor(&gWhite);
if (NeedsWhiteBG(theImage)) EraseRect(&gIconGWorld->portRect);
else PaintRect(&gIconGWorld->portRect);
// now get the ball rolling
MySetPort((*theParams)->dummy);
CallICMProgressProc((*theParams)->progress.prog.progressProc,
codecProgressOpen, 0L,
(*theParams)->progress.prog.progressRefCon);
// Either from the offscreen GWorld ...
if ((*theImage)->gworld && GWOrigSize(theImage))
CopyGWorldToGWorld((*theImage)->gworld, (*theParams)->dummy,
&(*theImage)->gworld->portRect, &(*theImage)->gworld->portRect,
srcCopy, nil);
// or from the image directly!
else theErr = (*theImage)->format->draw((*theImage)->data, theParams);
CallICMProgressProc((*theParams)->progress.prog.progressProc,
codecProgressClose, 0L,
(*theParams)->progress.prog.progressRefCon);
UnlockPixels(GetGWorldPixMap(gPreviewGWorld));
UnlockPixels(GetGWorldPixMap(gIconGWorld));
KeepSpinning();
if (theErr == noErr) theErr = PostflightDrawing(theParams);
else PostflightDrawing(theParams);
}
PopPort();
DisposeHandle((Handle)theParams);
}
gPreviewRect = prevDstRect;
gIconRect = iconDstRect;
return theErr;
}
/*
* AddQuickTimePreview(theFile)
*
* Purpose: Adds the preview PICT to the newly-created PICT file
* Inputs: theFile = pointer to a file spec
* Returns: an OSErr describing what went wrong
*
*/
static OSErr AddQuickTimePreview(FSSpec *theFile, GWorldPtr thePreview, Rect *theRect)
{
PixMapHandle dstPixMap = GetGWorldPixMap(thePreview);
PicHandle previewData;
short resRef;
OSErr theErr;
if (previewData = (PicHandle)NewHandle(4)) {
KeepSpinning();
LockPixels(dstPixMap);
theErr = MakeThumbnailFromPixMap(dstPixMap, theRect, 32, (PicHandle)previewData,
(ICMProgressProcRecordPtr)&gDummyProg);
UnlockPixels(dstPixMap);
KeepSpinning();
if (theErr == noErr) {
FSpCreateResFile(theFile, kCreator, kPICTType, 0);
KeepSpinning();
if (resRef = FSpOpenResFile(theFile, fsRdWrPerm)) {
KeepSpinning();
theErr = AddFilePreview(resRef, kPICTType, (Handle)previewData);
KeepSpinning();
CloseResFile(resRef);
} else gIntError = errCantWriteFile, theErr = fnfErr;
}
} else gIntError = errCantMakePreview, theErr = memFullErr;
return theErr;
}
/*
* MakeIcons(theSpec, theImage)
*
* Purpose: Handles the creation of icons for theImage
* Inputs: theSpec = pointer to the destination file spec
* theImage = handle to the image to make icons for
* Returns: an OSErr describing the result
*
*/
static OSErr MakeIcons(FSSpec *theSpec, ImageHandle theImage)
{
#if applec
#pragma unused(theImage)
#endif
Rect bigRect = { 0, 0, 32, 32 }, smallRect = { 0, 0, 16, 16 };
OSErr theErr = noErr;
GWorldPtr theGWorld;
short theFile;
if (!(theFile = FSpOpenResFile(theSpec, fsRdWrPerm)))
return gIntError = errCantCreateIcons, ResError();
while (true) {
if (!(theGWorld = MyNewGWorld(&bigRect, 8, nil, nil, true, false)))
if (!(theGWorld = MyNewGWorld(&bigRect, 8, nil, nil, true, true))) {
theErr = memFullErr;
break;
}
theErr = MakeOneIcon(theFile, large8BitData, gIconGWorld, theGWorld, &gIconRect, &bigRect);
if (theErr != noErr) break;
theErr = MakeOneIcon(theFile, small8BitData, gIconGWorld, theGWorld, &gIconRect, &smallRect);
if (theErr != noErr) break;
DisposeGWorld(theGWorld);
theGWorld = nil;
if (!(theGWorld = MyNewGWorld(&bigRect, 4, nil, nil, true, false)))
if (!(theGWorld = MyNewGWorld(&bigRect, 4, nil, nil, true, true))) {
theErr = memFullErr;
break;
}
theErr = MakeOneIcon(theFile, large4BitData, gIconGWorld, theGWorld, &gIconRect, &bigRect);
if (theErr != noErr) break;
theErr = MakeOneIcon(theFile, small4BitData, gIconGWorld, theGWorld, &gIconRect, &smallRect);
if (theErr != noErr) break;
DisposeGWorld(theGWorld);
theGWorld = nil;
if (!(theGWorld = MyNewGWorld(&bigRect, 1, nil, nil, true, false)))
if (!(theGWorld = MyNewGWorld(&bigRect, 1, nil, nil, true, true))) {
theErr = memFullErr;
break;
}
theErr = MakeOneIcon(theFile, large1BitMask, gIconGWorld, theGWorld, &gIconRect, &bigRect);
if (theErr != noErr) break;
theErr = MakeOneIcon(theFile, small1BitMask, gIconGWorld, theGWorld, &gIconRect, &smallRect);
break;
}
if (theGWorld) DisposeGWorld(theGWorld);
if (theFile) CloseResFile(theFile);
if (theErr != noErr) gIntError = errCantCreateIcons;
return theErr;
}
/*
* MakeOneIcon(theFile, theType, src, dst, srcRect, dstRect)
*
* Purpose: Creates and adds a single icon resource to theFile
* Inputs: theFile = path number of the destination file's resource fork
* theType = the type of icon to create
* src = pointer to the source GWorld
* dst = pointer to a properly-sized destination GWorld
* srcRect = pointer to the source image's rectangle
* dstRect = pointer to the destination icon's rectangle
* Returns: an OSErr describing the result
*
*/
static OSErr MakeOneIcon(short theFile, OSType theType, GWorldPtr src, GWorldPtr dst,
Rect *srcRect, Rect *dstRect)
{
#if applec
#pragma unused(theFile)
#endif
PixMapHandle srcMap = GetGWorldPixMap(src), dstMap = GetGWorldPixMap(dst);
Rect realDstRect = *srcRect;
Handle theHandle;
short offset;
OSErr theErr;
MapRect(&realDstRect, &src->portRect, dstRect);
if (Width(&realDstRect) < Height(&realDstRect)) {
offset = (Height(&realDstRect) - Width(&realDstRect)) >> 1;
realDstRect.left += offset;
realDstRect.right += offset;
} else {
offset = (Width(&realDstRect) - Height(&realDstRect)) >> 1;
realDstRect.top += offset;
realDstRect.bottom += offset;
}
PushPort();
MySetPort(dst);
HLock((Handle)srcMap);
HLock((Handle)dstMap);
LockPixels(srcMap);
LockPixels(dstMap);
EraseRect(dstRect);
CopyBits((BitMap *)*srcMap, (BitMap *)*dstMap, srcRect, &realDstRect, srcCopy + ditherCopy, nil);
UnlockPixels(srcMap);
HUnlock((Handle)srcMap);
TrimIcon(&realDstRect);
if ((theErr = PixMapToHandle(dstMap, dstRect, &realDstRect, &theHandle)) != noErr) {
PopPort();
return theErr;
}
UnlockPixels(dstMap);
HUnlock((Handle)dstMap);
PopPort();
AddResource(theHandle, theType, kCustomIconResource, gNullString);
if ((theErr = ResError()) == noErr) {
WriteResource(theHandle);
KeepSpinning();
ReleaseResource(theHandle);
return noErr;
};
DisposeHandle(theHandle);
return theErr;
}
/*
* TrimIcon(theRect)
*
* Purpose: Trims the appropriate icon by folding over the upper-right corner
* Inputs: theRect = pointer to the icon's rectangle
* Returns: nothing
*
*/
static void TrimIcon(Rect *theRect)
{
short offset = (Height(theRect) > 16 || Width(theRect) > 16) ? 6 : 4;
Rect cornerRect;
RGBForeColor(&gBlack);
RGBBackColor(&gWhite);
FrameRect(theRect);
if (gThePrefs.iconStyle != isSquareDog && gThePrefs.iconStyle != isProportionalDog) return;
MySetRect(&cornerRect, theRect->right - offset - 1, theRect->top, theRect->right, theRect->top + offset);
EraseRect(&cornerRect);
cornerRect.right--;
MoveTo(cornerRect.left, cornerRect.top);
LineTo(cornerRect.right, cornerRect.bottom);
LineTo(cornerRect.left, cornerRect.bottom);
LineTo(cornerRect.left, cornerRect.top);
}
/*
* PixMapToHandle(theMap, theRect, theHandle)
*
* Purpose: Takes the icon image in theMap and makes an icon handle from it
* Inputs: theMap = handle to the icon's pixmap
* theRect = pointer to the icon's rectangle
* theHandle = pointer to a place to receive the new handle
* Returns: an OSErr describing the result
*
*/
static OSErr PixMapToHandle(PixMapHandle theMap, Rect *theRect, Rect *maskRect, Handle *theHandle)
{
long theSize = (Height(theRect) * Width(theRect) * (*theMap)->pixelSize) >> 3;
long r, c, words, rowBytes = (*theMap)->rowBytes & 0x3fff;
char mode = true32b;
ushort *s, *d;
if ((*theMap)->pixelSize == 1) theSize <<= 1;
if (*theHandle = NewHandle(theSize)) {
words = (Width(theRect) * (*theMap)->pixelSize) >> 4;
s = (ushort *)GetPixBaseAddr(theMap);
d = (ushort *)StripAddress(**theHandle);
SwapMMUMode(&mode);
for (r = 0; r < Height(theRect); r++) {
for (c = 0; c < words; c++) *d++ = s[c];
s += rowBytes >> 1;
}
SwapMMUMode(&mode);
} else return memFullErr;
if ((*theMap)->pixelSize == 1) {
short offset = (Height(theRect) > 16 || Width(theRect) > 16) ? 6 : 4;
Rect cornerRect;
EraseRect(theRect);
PaintRect(maskRect);
if (gThePrefs.iconStyle == isSquareDog || gThePrefs.iconStyle == isProportionalDog) {
MySetRect(&cornerRect, maskRect->right - offset - 1, maskRect->top, maskRect->right, maskRect->top + offset);
EraseRect(&cornerRect);
cornerRect.right--;
MoveTo(cornerRect.left, cornerRect.top);
LineTo(cornerRect.right, cornerRect.bottom);
while (++cornerRect.top != cornerRect.bottom) {
MoveTo(cornerRect.left, cornerRect.top);
LineTo(cornerRect.left + cornerRect.top - maskRect->top, cornerRect.top);
}
}
s = (ushort *)GetPixBaseAddr(theMap);
SwapMMUMode(&mode);
for (r = 0; r < Height(theRect); r++) {
for (c = 0; c < words; c++) *d++ = s[c];
s += rowBytes >> 1;
}
SwapMMUMode(&mode);
}
return noErr;
}
/*
* DoOpenDocument(theSpec, first)
*
* Purpose: Calls the appropriate routines to open an new image
* Inputs: theSpec = the file specification for the new input file
* first = flag: true if this is the first image in a series
* Returns: an OSErr describing the result
*
*/
OSErr DoOpenDocument(FSSpec *theFile, Boolean first, DescType openScreen, DescType openFull,
Boolean autoExpand, Boolean openVisible, DescType openPalette, DescType drawQuality,
Boolean openBitmaps, Boolean autoComments, Boolean fixTypes, Boolean fixCreator)
{
OSErr theErr = noErr;
ImageHandle theImage;
LMSetSFSaveDisk(-theFile->vRefNum);
LMSetCurDirStore(theFile->parID);
if (theImage = NewImage()) {
(*theImage)->file = *theFile;
if ((theErr = ReadFile(theImage, fixTypes, fixCreator)) == noErr) {
if ((theErr = InitImage(theImage, openScreen, openFull, drawQuality, openVisible)) == noErr) {
if ((theErr = MakeNewWindow(theImage, first, autoExpand)) == noErr) {
MySetPort((CGrafPtr)(*theImage)->window);
if (gSlideShow) SlideProgress(codecProgressRealOpen, 0, 0);
AddWindowItem(theImage);
if ((theErr = PickFirstPalette(theImage, openPalette)) == noErr) {
if ((theErr = RenderOffscreen(theImage, openBitmaps)) == noErr) {
if (gSlideShow) SlideProgress(codecProgressRealClose, 0, 0);
if (openVisible) {
if (!gSlideShow && first) ChangeActive((*theImage)->window);
else FWShowWindow((*theImage)->window);
if (autoComments && (*theImage)->comments &&
((*theImage)->window == FWFrontWindow())) {
if (OpenComments() == noErr)
ChangeActive(GetCommentsWindow());
}
SetStatistics();
AdjustMenus();
}
return noErr;
}
}
if (gSlideShow) SlideProgress(codecProgressRealClose, 0, 0);
} else gIntError = errCantOpenWindow;
}
}
} else gIntError = errNoLoadMemory, theErr = memFullErr;
if ((theErr != codecAbortErr || gSlideShow) && theImage) {
if ((*theImage)->window) DoCloseWindow((*theImage)->window, gThePrefs.restoreColors);
else DisposeImage(theImage);
}
if (theErr == errBadJPEG) theErr = codecBadDataErr;
return theErr;
}
/*
* ReadFile(theImage)
*
* Purpose: Opens the input file, figures its type, and dispatches the read operation
* to the appropriate routine
* Inputs: theImage = the destination image record for the new image
* Returns: an OSErr describing the problem
*
*/
OSErr ReadFile(ImageHandle theImage, Boolean fixTypes, Boolean fixCreator)
{
FSSpec theSpec = (*theImage)->file;
short theFile, theType;
OSErr theErr = noErr;
if (gGetAbout) {
(*theImage)->format = &gPICTFormat;
(*theImage)->data = GetResource(kPICTType, rAboutPict);
if (!(*theImage)->data) theErr = ResError();
else DetachResource((*theImage)->data);
(*theImage)->flags |= ifIsAboutBox;
gGetAbout = false;
return theErr;
}
if ((theErr = FSpOpenDF(&theSpec, fsRdPerm, &theFile)) != noErr)
theFile = -1;
if ((theType = IDImage(theFile, &theSpec)) != kInvalidType) {
if (fixTypes) {
FInfo theInfo;
FSpGetFInfo(&theSpec, &theInfo);
if (theInfo.fdType != gFormat[theType]->inType &&
theInfo.fdType != gFormat[theType]->altInType) {
theInfo.fdType = gFormat[theType]->inType;
if (fixCreator) theInfo.fdCreator = kCreator;
FSpSetFInfo(&theSpec, &theInfo);
FSClose(theFile);
theErr = FSpOpenDF(&theSpec, fsRdPerm, &theFile);
}
}
if (theErr == noErr) {
(*theImage)->format = gFormat[theType];
if ((*theImage)->format->load)
theErr = (*theImage)->format->load(theFile, theImage);
else theErr = DefaultLoad(theFile, theImage);
}
} else {
if (gIntError != errHSIFile) gIntError = errInvalidFile;
theErr = errAETypeError;
}
if (theFile != -1) FSClose(theFile);
return theErr;
}
//=====================================================================================
// OSErr DefaultLoad(short theFile, ImageHandle theImage)
//=====================================================================================
// Performs a generic load of an image into memory, with no special processing.
//=====================================================================================
extern OSErr DefaultLoad(short theFile, ImageHandle theImage)
{
OSErr theErr = noErr;
long theSize;
KeepSpinning();
GetEOF(theFile, &theSize);
if (!MakeMemAvailable(theSize)) return gIntError = errNoLoadMemory, memFullErr;
if ((*theImage)->data = NewHandle(theSize)) {
HLock((*theImage)->data);
SpinIndef();
theErr = FSRead(theFile, &theSize, *(*theImage)->data);
KeepSpinning();
HUnlock((*theImage)->data);
if (theErr == noErr) return theErr;
else DisposeHandle((*theImage)->data);
gIntError = errCantReadFile;
} else gIntError = errNoLoadMemory, theErr = memFullErr;
return theErr;
}
/*
* IDImage(theFile, theSpec)
*
* Purpose: Determines the image type by loading in a little and examining the header
* Inputs: theFile = a pointer to the file number
* theSpec = the original file specification
* Returns: the index of the file type, or -1 if not a valid type
*
*/
short IDImage(short theFile, FSSpec *theSpec)
{
uchar theBuffer[kHeaderSize + 64];
long theSize = kHeaderSize + 64;
OSErr theErr = noErr;
FInfo theInfo;
short i;
if (theFile != -1) {
SetFPos(theFile, fsFromStart, 0);
theErr = FSRead(theFile, &theSize, theBuffer);
if (theErr != noErr && theErr != eofErr) theSize = 0;
SetFPos(theFile, fsFromStart, 0);
} else theSize = 0;
if (FSpGetFInfo(theSpec, &theInfo) == noErr) {
for (i = 0; i < kFileFormats; i++)
if (gFormat[i]->id) {
Boolean valid = gFormat[i]->id(theBuffer, theSize, theFile, theSpec);
if (valid && (gFormat[i]->positiveID ||
gFormat[i]->inType == theInfo.fdType ||
gFormat[i]->altInType == theInfo.fdType)) return i;
}
}
if (theBuffer[0] == 'h' && theBuffer[1] == 's' && theBuffer[2] == 'i' && theBuffer[3] == '1') gIntError = errHSIFile;
/*
#define errBinHexData 26
#define errUUEncodeData 27
*/
return kInvalidType;
}
/*
* InitImage(theImage, openScreen, openFull, drawQuality)
*
* Purpose: Initializes the fields in the image record
* Inputs: theImage = the destination image record
* openScreen = AE enum describing which screen to open up on
* openFull = AE enum describing how to use full screen windows
* drawQuality = AE enum describing the default drawing quality
* visible = flag: true if the image is to be made visible
* Returns: an OSErr describing what went wrong
*
*/
OSErr InitImage(ImageHandle theImage, DescType openScreen, DescType openFull,
DescType drawQuality, Boolean visible)
{
FSSpec theSpec = (*theImage)->file;
short choice, refNum;
OSErr theErr, AEErr;
switch (openScreen) {
case kAEOSDeepestColor: (*theImage)->dmon = GetDeepMonitor(true); break;
case kAEOSDeepestGray: (*theImage)->dmon = GetDeepMonitor(false); break;
case kAEOSLargestColor: (*theImage)->dmon = GetBigMonitor(true); break;
case kAEOSLargestGray: (*theImage)->dmon = GetBigMonitor(false); break;
case kAEOSMain: (*theImage)->dmon = gMainMonitor; break;
}
(*theImage)->smon = (*theImage)->dmon;
theErr = (*theImage)->format->open(theImage);
if (Height(&(*theImage)->grect) <= 0 || Width(&(*theImage)->grect) <= 0)
gIntError = errCorruptImage, theErr = codecBadDataErr;
if (theErr == errBadJPEG && (!gSlideShow || !(*gSlideOptions)->noErrors) &&
(gThePrefs.useQuickTime && gQTVersion)) {
if (gInAppleEvent) {
AEErr = AEInteractWithUser(kAEDefaultTimeout, &gTheNotification,
gAEIdleProc);
if (AEErr == errAENoUserInteraction) return codecBadDataErr;
}
StopSpinning(&qd.arrow);
ParamText(gNullString, (*theImage)->file.name, gNullString, gNullString);
choice = FWCautionAlert(CenterAlert(rBadJPEGAlert), gGenericFilter);
if (choice == 3 || choice == kDialogCancel) return theErr;
else gIntError = noErr, theErr = noErr;
(*theImage)->flags |= ifCorrupt;
StartSpinning();
}
if (UseFullScreen(theImage, openFull, visible)) (*theImage)->flags |= ifFull;
if (gSlideShow && (*gSlideOptions)->fileNames) (*theImage)->flags |= ifFilename;
switch (drawQuality) {
case kAEDQVeryHigh: (*theImage)->quality = iqVHigh; break;
case kAEDQHigh: (*theImage)->quality = iqHigh; break;
case kAEDQNormal: (*theImage)->quality = iqMedium; break;
}
if ((*theImage)->comments) {
Size oldLength = GetHandleSize((*theImage)->comments), length = 0, i;
uchar *src = (uchar *)*(*theImage)->comments, *dst = src;
for (i = 0; i < oldLength; i++)
if (*src >= 0x20) break;
else src++;
for ( ; i < oldLength; i++)
if ((*src == 0x0d) || (*src >= 0x20)) *dst++ = *src++, length++;
else src++;
while ((length > 0) && (*--dst < 0x20)) length--;
if (length > 0) SetHandleSize((*theImage)->comments, length);
else DisposeHandle((*theImage)->comments), (*theImage)->comments = nil;
}
if (refNum = FSpOpenResFile(&theSpec, fsRdPerm)) {
Rect **theRect;
if (theRect = (Rect **)Get1Resource('RECT', 0)) {
(*theImage)->crect = **theRect;
(*theImage)->flags |= ifCropped;
}
CloseResFile(refNum);
}
return theErr;
}
/*
* UseFullScreen(theImage, openFull, visible)
*
* Purpose: Determines whether the new image should be opened in full screen mode
* Inputs: theImage = the image record for the image in question
* openFull = AE enum describing how to use full screen windows
* visible = flag: true if the image is to be made visible
* Returns: nothing
*
*/
Boolean UseFullScreen(ImageHandle theImage, DescType openFull, Boolean visible)
{
Rect screenRect, theRect;
Boolean result;
short choice;
OSErr AEErr;
if (openFull == kAEOFAlways) return true;
else if (openFull == kAEOFNever) return false;
GetActiveRect((*theImage)->dmon, &screenRect);
screenRect.top += gTitleBarHeight;
theRect = (*theImage)->crect;
OffsetRect(&theRect, -theRect.left, -theRect.top);
if (Width(&theRect) > Width(&screenRect))
theRect.bottom = (long)theRect.bottom * (long)Width(&screenRect) / (long)Width(&theRect);
if (Height(&theRect) <= Height(&screenRect)) return false;
if (openFull == kAEOFAlwaysIfLarge) return true;
if (!visible) return false;
if (gInAppleEvent) {
AEErr = AEInteractWithUser(kAEDefaultTimeout, &gTheNotification,
gAEIdleProc);
if (AEErr == errAENoUserInteraction) return false;
}
StopSpinning(&qd.arrow);
ParamText(gNullString, (*theImage)->file.name, gNullString, gNullString);
choice = FWAlert(CenterAlert(rTooBigAlert), gGenericFilter);
result = (choice == 1 || choice == kDialogOK);
StartSpinning();
return result;
}
/*
* PickFirstPalette(theImage, openPalette)
*
* Purpose: Determines which palette we should use for the given image
* Inputs: theImage = the image record for the image in question
* openFull = AE enum describing palette preferences
* Returns: an OSErr describing what went wrong
*
*/
OSErr PickFirstPalette(ImageHandle theImage, DescType openPalette)
{
short depth = (*(*theImage)->dmon)->depth;
Boolean image = (*theImage)->ipalette && ((*(*theImage)->ipalette)->pmEntries <= (1L << depth));
Boolean quantize = ((*theImage)->depth >= 16);
short palette = plNone;
OSErr theErr = noErr;
DescType thePalette;
while (true) {
if (!(*(*theImage)->dmon)->color && (depth <= 8)) {
palette = plGrey;
break;
} else if (depth <= 2) {
palette = plGrey;
break;
} else if (depth > 8) {
palette = plSys;
break;
}
switch (openPalette) {
case kAEOPQuantImageScrn:
case kAEOPQuantScrn:
if (quantize) palette = plQuant;
if ((openPalette != kAEOPQuantScrn) && image && (palette == plNone))
palette = plImage;
if (palette == plNone) palette = plSys;
break;
case kAEOPImageQuantScrn:
case kAEOPImageScrn:
if (image) palette = plImage;
if ((openPalette != kAEOPImageScrn) && quantize && (palette == plNone))
palette = plQuant;
if (palette == plNone) palette = plSys;
break;
case kAEOPScrn:
palette = plSys;
break;
}
break;
}
switch (palette) {
case plGrey: thePalette = kAEPGrayscale; break;
case plImage: thePalette = kAEPImage; break;
case plQuant: thePalette = kAEPQuantized; break;
case plSys:
default: thePalette = kAEPSystem; break;
}
if (!gThePrefs.ditherQuant && (palette == plQuant ||
(palette == plImage && (*theImage)->depth >= 16)))
(*theImage)->flags &= ~ifDithered;
else (*theImage)->flags |= ifDithered;
if (theErr == noErr) theErr = DoSetPalette((*theImage)->window, thePalette);
if (palette == plQuant && (*theImage)->npalette != plQuant) (*theImage)->flags |= ifDithered;
if (theErr == codecAbortErr && !gSlideShow) {
theErr = noErr;
gIntError = 0;
}
return theErr;
}
/*
* RenderOffscreen(theImage, openBitmaps)
*
* Purpose: Renders the given image into an offscreen buffer, if appropriate
* Inputs: theImage = a pointer to the image in question
* openBitmaps = flag: true if we should force an offscreen bitmap
* Returns: an OSErr describing the problem, if any
*
*/
OSErr RenderOffscreen(ImageHandle theImage, Boolean openBitmaps)
{
short flags = bfOffscreen + bfForceFull;
OSErr theErr = noErr;
ImageHandle image;
Boolean itWorked;
if ((*theImage)->gworld) return noErr;
if (openBitmaps) {
itWorked = MakeImageGWorld(theImage, false);
if (!itWorked && gSlideShow)
for (image = gImageRoot; image; image = (*image)->next) KillGWorld(image);
if (itWorked || MakeImageGWorld(theImage, false)) {
if (!gSlideShow) {
ChangeActive((*theImage)->window);
flags |= bfOnscreen;
}
if (!(flags & bfOnscreen) && gSlideShow) flags |= bfUseSlideProgress;
SetSlideControlsText(gString[strSlideRendering], (*theImage)->file.name, gNullString, gNullString);
theErr = DrawImage(theImage, flags, nil);
} else if (!gSlideShow && ((*theImage)->compression || !gThePrefs.noUncomp))
gIntError = errNoOffscreenMemory, theErr = memFullErr;
}
return theErr;
}