mirror of
https://github.com/aaronsgiles/JPEGView.git
synced 2024-06-01 03:41:27 +00:00
92bdb55672
These are the sources for the final official release of JPEGView for the Mac, back in 1994.
1 line
16 KiB
C
1 line
16 KiB
C
/*********************************************************/
|
|
/* This source code copyright (c) 1991-2001, Aaron Giles */
|
|
/* See the Read Me file for licensing information. */
|
|
/* Contact email: mac@aarongiles.com */
|
|
/*********************************************************/
|
|
|
|
//=====================================================================================
|
|
// Generic includes for Macintosh headers
|
|
//=====================================================================================
|
|
|
|
#if THINK_C
|
|
#include "THINK.Header"
|
|
#elif applec
|
|
#pragma load ":Headers:MPW.Header"
|
|
#elif __MWERKS__
|
|
//#include "MW.Header"
|
|
#else
|
|
#include "JPEGView.h"
|
|
#endif
|
|
|
|
//=====================================================================================
|
|
// Includes specific to this module
|
|
//=====================================================================================
|
|
|
|
#include "JPEGViewEventHandlers.h"
|
|
|
|
//=====================================================================================
|
|
// Prototypes for functions local to this module
|
|
//=====================================================================================
|
|
|
|
static OSErr DrawToDummyPort(ImageHandle theImage, Rect *srcRect, Rect *dstRect);
|
|
static PicHandle MyOpenCPicture(Rect *dstRect, ImageHandle theImage);
|
|
static Boolean WasDesktop(FSSpec *spec, Boolean recursive, ICMProgressProcRecordPtr theProg,
|
|
OSErr *theErr);
|
|
|
|
//=====================================================================================
|
|
// pascal OSErr HandleQuantize(AppleEvent *theEvent, AppleEvent *reply, long refCon)
|
|
//=====================================================================================
|
|
// Handles the quantize image AppleEvent, from the JPEGView suite.
|
|
//=====================================================================================
|
|
|
|
extern pascal OSErr HandleQuantize(AppleEvent *theEvent, AppleEvent *reply, long refCon)
|
|
{
|
|
#if applec
|
|
#pragma unused(refCon)
|
|
#endif
|
|
ObjectTokenHandle theToken;
|
|
PaletteHandle thePalette;
|
|
CTabHandle theColors;
|
|
ImageHandle theImage;
|
|
OSErr theErr = noErr;
|
|
AEDesc theObject;
|
|
long numColors;
|
|
|
|
AEBegin();
|
|
theErr = AEExtractObject(theEvent, keyDirectObject, &theObject);
|
|
if (theErr == noErr) {
|
|
theErr = AEExtractLong(theEvent, keyColorCount, &numColors);
|
|
if (theErr == noErr) {
|
|
theToken = (ObjectTokenHandle)theObject.dataHandle;
|
|
if (theObject.descriptorType == cImage) {
|
|
if ((*theToken)->count == 1) {
|
|
theImage = FindImage((WindowPtr)(*theToken)->object[0]);
|
|
StartSpinning();
|
|
theErr = DoQuantize(theImage, numColors, &thePalette, nil);
|
|
StopSpinning(&qd.arrow);
|
|
if (theErr == noErr) {
|
|
if (theColors = (CTabHandle)NewHandle(4)) {
|
|
Palette2CTab(thePalette, theColors);
|
|
HLock((Handle)theColors);
|
|
if (reply->dataHandle)
|
|
theErr = AEPutParamPtr(reply, keyAEResult, typeColorTable, (void *)*theColors, GetHandleSize((Handle)theColors));
|
|
DisposeHandle((Handle)theColors);
|
|
} else theErr = memFullErr;
|
|
DisposePalette(thePalette);
|
|
}
|
|
} else theErr = errAENotASingleObject;
|
|
} else theErr = errAECantHandleClass;
|
|
}
|
|
AEDisposeDesc(&theObject);
|
|
}
|
|
AEEnd();
|
|
return theErr;
|
|
}
|
|
|
|
//=====================================================================================
|
|
// pascal OSErr HandleSlideShow(AppleEvent *theEvent, AppleEvent *reply, long refCon)
|
|
//=====================================================================================
|
|
// Handles the JPEGView slide show AppleEvent, from the JPEGView suite.
|
|
//=====================================================================================
|
|
|
|
extern pascal OSErr HandleSlideShow(AppleEvent *theEvent, AppleEvent *reply, long refCon)
|
|
{
|
|
#if applec
|
|
#pragma unused(reply, refCon)
|
|
#endif
|
|
long theLong, theCount, theIndex, actualSize;
|
|
DescType theType, theKey;
|
|
NestedProgress theProc = { { nil, 0 }, 0, 0L, 0L, false };
|
|
ICMProgressProcRecordPtr progPtr = (ICMProgressProcRecordPtr)&theProc;
|
|
OSErr theErr = noErr;
|
|
Boolean theBoolean;
|
|
FSSpec theFile;
|
|
AEDesc theList;
|
|
|
|
theProc.prog.progressProc = gGenericProgress;
|
|
theProc.prog.progressRefCon = (long)&theProc;
|
|
if (gSlideShow) return noErr;
|
|
AEBegin();
|
|
theErr = AEExtractLong(theEvent, keyDelay, &theLong);
|
|
if (theErr == noErr) (*gSlideOptions)->delay = theLong;
|
|
theErr = AEExtractBoolean(theEvent, keyFilenames, &theBoolean);
|
|
if (theErr == noErr) (*gSlideOptions)->fileNames = theBoolean;
|
|
theErr = AEExtractBoolean(theEvent, keyFromDisk, &theBoolean);
|
|
if (theErr == noErr) (*gSlideOptions)->fromMemory = !theBoolean;
|
|
theErr = AEExtractBoolean(theEvent, keyIgnoreErrors, &theBoolean);
|
|
if (theErr == noErr) (*gSlideOptions)->noErrors = theBoolean;
|
|
theErr = AEExtractBoolean(theEvent, keyImportFiles, &theBoolean);
|
|
if (theErr == noErr) (*gSlideOptions)->allFiles = theBoolean;
|
|
theErr = AEExtractBoolean(theEvent, keyRandom, &theBoolean);
|
|
if (theErr == noErr) (*gSlideOptions)->random = theBoolean;
|
|
theErr = AEExtractBoolean(theEvent, keyRepeat, &theBoolean);
|
|
if (theErr == noErr) (*gSlideOptions)->repeat = theBoolean;
|
|
theErr = AEExtractBoolean(theEvent, keyScanRecursive, &theBoolean);
|
|
if (theErr == noErr) (*gSlideOptions)->recursive = theBoolean;
|
|
theErr = AEExtractBoolean(theEvent, keyUserControl, &theBoolean);
|
|
if (theErr == noErr) (*gSlideOptions)->userControl = theBoolean;
|
|
theErr = AEExtractBoolean(theEvent, keyOffscreen, &theBoolean);
|
|
if (theErr == noErr) (*gSlideOptions)->offscreen = theBoolean;
|
|
theErr = AEExtractBoolean(theEvent, keyAutoComments, &theBoolean);
|
|
if (theErr == noErr) (*gSlideOptions)->autoComments = theBoolean;
|
|
theErr = AEExtractBoolean(theEvent, keyHideWindoids, &theBoolean);
|
|
if (theErr == noErr) (*gSlideOptions)->hideWindoids = theBoolean;
|
|
theErr = AEExtractBoolean(theEvent, keyHideControls, &theBoolean);
|
|
if (theErr == noErr) (*gSlideOptions)->hideControls = theBoolean;
|
|
theErr = AEExtractBoolean(theEvent, keyScreenSaver, &theBoolean);
|
|
if (theErr == noErr) gScreenSaver = theBoolean;
|
|
else gScreenSaver = false;
|
|
if (gScreenSaver) gScreenSaverPoint = GlobalMouse();
|
|
theErr = AEGetParamDesc(theEvent, keyDirectObject, typeAEList, &theList);
|
|
if (theErr == noErr) {
|
|
if (!(*gSlideOptions)->fromMemory) {
|
|
StartSpinning();
|
|
theErr = AECountItems(&theList, &theCount);
|
|
if (theErr == noErr) {
|
|
ParamText(gString[strScanningDirectory], gNullString, gNullString, gNullString);
|
|
if (progPtr)
|
|
CallICMProgressProc(progPtr->progressProc, codecProgressOpen, kIndefProgress, progPtr->progressRefCon);
|
|
for (theIndex = 1; theIndex <= theCount; theIndex++) {
|
|
if (theErr != noErr) break;
|
|
theErr = AEGetNthPtr(&theList, theIndex, typeFSS, &theKey, &theType, (void *)&theFile, sizeof(FSSpec), &actualSize);
|
|
if (theErr == noErr) {
|
|
if (gScreenSaver) gSlideShow = true;
|
|
if (!WasDesktop(&theFile, (*gSlideOptions)->recursive, progPtr, &theErr))
|
|
theErr = AddSlideDir(&theFile, (*gSlideOptions)->recursive, progPtr, nil);
|
|
if (gScreenSaver) gSlideShow = false;
|
|
} else theErr = errAEBadListItem;
|
|
}
|
|
if (progPtr)
|
|
CallICMProgressProc(progPtr->progressProc, codecProgressClose, kIndefProgress, progPtr->progressRefCon);
|
|
} else theErr = errAEWrongDataType;
|
|
}
|
|
if (theErr == noErr) {
|
|
InitSlideShow();
|
|
gIntError = noErr;
|
|
} else CleanUpSlideShow();
|
|
AEDisposeDesc(&theList);
|
|
StopSpinning(&qd.arrow);
|
|
}
|
|
AEEnd();
|
|
return theErr;
|
|
}
|
|
|
|
//=====================================================================================
|
|
// pascal OSErr HandleCopy(AppleEvent *theEvent, AppleEvent *reply, long refCon)
|
|
//=====================================================================================
|
|
// Handles the Copy AppleEvent, from the Miscellaneous Events suite.
|
|
//=====================================================================================
|
|
|
|
extern pascal OSErr HandleCopy(AppleEvent *theEvent, AppleEvent *reply, long refCon)
|
|
{
|
|
#if applec
|
|
#pragma unused(theEvent, reply, refCon)
|
|
#endif
|
|
OSErr theErr;
|
|
|
|
AEBegin();
|
|
theErr = DoCopy();
|
|
AEEnd();
|
|
return theErr;
|
|
}
|
|
|
|
extern OSErr DoCopy(void)
|
|
{
|
|
ImageHandle theImage = FrontImage();
|
|
Boolean dontDispose = false;
|
|
OSErr theErr = noErr;
|
|
PicHandle thePict;
|
|
|
|
if (theImage) {
|
|
theErr = GetSelectedPICT(theImage, &thePict);
|
|
if (theErr == noErr) {
|
|
if (!thePict) {
|
|
thePict = (PicHandle)(*theImage)->data;
|
|
dontDispose = true;
|
|
}
|
|
ZeroScrap();
|
|
UnloadScrap();
|
|
HLock((Handle)thePict);
|
|
PutScrap(GetHandleSize((Handle)thePict), kPICTType, StripAddress((Ptr)*thePict));
|
|
if (!dontDispose) DisposeHandle((Handle)thePict);
|
|
} else if (theErr == codecAbortErr) theErr = noErr;
|
|
} else theErr = errAEEventFailed;
|
|
return theErr;
|
|
}
|
|
|
|
extern OSErr GetSelectedPICT(ImageHandle theImage, PicHandle *thePicture)
|
|
{
|
|
Rect srcRect, dstRect;
|
|
OSErr theErr = noErr;
|
|
CGrafPort dummyPort;
|
|
|
|
if (AntsHaveSelection((*theImage)->ants)) SelRectToCropRect(theImage, &srcRect);
|
|
else srcRect = (*theImage)->crect;
|
|
if (EqualRect(&srcRect, &(*theImage)->grect) && (*theImage)->format->inType == kPICTType) {
|
|
*thePicture = nil;
|
|
return noErr;
|
|
}
|
|
dstRect = srcRect;
|
|
OffsetRect(&dstRect, -dstRect.left, -dstRect.top);
|
|
OpenCPort(&dummyPort);
|
|
RectRgn(dummyPort.visRgn, &dstRect);
|
|
ClipRect(&dstRect);
|
|
PushPort();
|
|
MySetPort(&dummyPort);
|
|
*thePicture = MyOpenCPicture(&dstRect, theImage);
|
|
if (*thePicture) {
|
|
theErr = DrawToDummyPort(theImage, &srcRect, &dstRect);
|
|
ClosePicture();
|
|
if (!Width(&(**thePicture)->picFrame) && !Height(&(**thePicture)->picFrame)) theErr = memFullErr;
|
|
if (theErr != noErr) DisposeHandle((Handle)*thePicture), *thePicture = nil;
|
|
} else theErr = memFullErr;
|
|
PopPort();
|
|
CloseCPort(&dummyPort);
|
|
return theErr;
|
|
}
|
|
|
|
//=====================================================================================
|
|
// PicHandle MyOpenCPicture(Rect *dstRect, ImageHandle theImage)
|
|
//=====================================================================================
|
|
// Opens up a color picture, in preparation for copying. We use a simple algorithm to
|
|
// figure out whether to use application or temporary memory, in order to maximize the
|
|
// likelihood that we'll be able to succeed.
|
|
//=====================================================================================
|
|
|
|
static PicHandle MyOpenCPicture(Rect *dstRect, ImageHandle theImage)
|
|
{
|
|
Size estSize = (((long)Height(&(*theImage)->grect) * (long)Width(&(*theImage)->grect) * (long)(*theImage)->depth) >> 3) * 3L / 4L;
|
|
Size grow, tempMax = TempMaxMem(&grow), appMax = MaxMem(&grow);
|
|
THz oldZone = GetZone(), tempZone;
|
|
Boolean inTempMem = true;
|
|
OpenCPicParams theParams;
|
|
OSErr theErr = noErr;
|
|
PicHandle thePict;
|
|
|
|
// set up the OpenCPicture parameters
|
|
theParams.srcRect = *dstRect;
|
|
theParams.hRes = theParams.vRes = 0x480000L;
|
|
theParams.version = -2;
|
|
theParams.reserved1 = theParams.reserved2 = 0;
|
|
|
|
// allocate a handle in temp memory, and retrieve the temporary zone from that
|
|
thePict = (PicHandle)TempNewHandle(4, &theErr);
|
|
if (thePict) {
|
|
tempZone = HandleZone((Handle)thePict);
|
|
DisposeHandle((Handle)thePict);
|
|
}
|
|
|
|
// some simple logic to determine if we should use app or temp memory
|
|
if (!HasVirtualMemory() && (estSize < appMax || estSize > tempMax)) inTempMem = false;
|
|
|
|
// open the picture
|
|
if (inTempMem) SetZone(tempZone);
|
|
thePict = OpenCPicture(&theParams);
|
|
SetZone(oldZone);
|
|
return thePict;
|
|
}
|
|
|
|
//=====================================================================================
|
|
// OSErr DrawToDummyPort(ImageHandle theImage, Rect *srcRect, Rect *dstRect)
|
|
//=====================================================================================
|
|
// Actually does the drawing of the image to the dummy port. Of course, the dummy port
|
|
// has been set up to bottleneck all the drawing into a picture, so nothing actually
|
|
// gets drawn.
|
|
//=====================================================================================
|
|
|
|
static OSErr DrawToDummyPort(ImageHandle theImage, Rect *srcRect, Rect *dstRect)
|
|
{
|
|
NestedProgress progProc = { { nil, 0 }, 0, 0L, 0x10000L, false };
|
|
short oldBackgroundTime = gThePrefs.backgroundTime;
|
|
Rect boundsRect = (*theImage)->grect;
|
|
JVDrawParamsHandle theParams;
|
|
OSErr theErr = noErr;
|
|
|
|
progProc.prog.progressProc = gGenericProgress;
|
|
|
|
// hack: Finder doesn't seem to like it if we give any apps time during
|
|
// the drag process, so we force 0 sleep time and checking with
|
|
// EventAvail
|
|
gThePrefs.backgroundTime = bgMinimal;
|
|
|
|
// allocate and initialize the drawing parameters
|
|
if (theParams = NewDrawParams(&boundsRect, iqMedium, false, &progProc, (*theImage)->privateData)) {
|
|
SetUpDrawPort(theParams, kOnscreenPort, (CGrafPtr)qd.thePort, srcRect, dstRect, false);
|
|
|
|
// preflight the drawing here and save the port
|
|
KeepSpinning();
|
|
theErr = PreflightDrawing(theParams);
|
|
PushPort();
|
|
if (theErr == noErr) {
|
|
|
|
// point to the dummy drawing port and start the inner progress proc
|
|
MySetPort((*theParams)->dummy);
|
|
UpdateParamText(gString[strCopying], gNullString, gNullString, (*theImage)->file.name);
|
|
CallICMProgressProc((*theParams)->progress.prog.progressProc, codecProgressOpen, 0L,
|
|
(*theParams)->progress.prog.progressRefCon);
|
|
|
|
// now do the drawing, 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);
|
|
|
|
// clean up our drawing, checking for missed aborts
|
|
if (theErr == noErr) theErr = PostflightDrawing(theParams);
|
|
else PostflightDrawing(theParams);
|
|
|
|
// if we were aborted, tell the printer so, and close the inner prog.
|
|
CallICMProgressProc((*theParams)->progress.prog.progressProc, codecProgressClose, 0L,
|
|
(*theParams)->progress.prog.progressRefCon);
|
|
KeepSpinning();
|
|
}
|
|
PopPort();
|
|
DisposeHandle((Handle)theParams);
|
|
}
|
|
gThePrefs.backgroundTime = oldBackgroundTime;
|
|
return theErr;
|
|
}
|
|
|
|
extern OSErr DoSlideShow(void)
|
|
{
|
|
NestedProgress theProg = { { nil, 0 }, 0, 0L, 0L, false };
|
|
ICMProgressProcRecordPtr progPtr = (ICMProgressProcRecordPtr)&theProg;
|
|
OSErr theErr = noErr;
|
|
FSSpec theSpec;
|
|
|
|
if (!(*gSlideOptions)->fromMemory) {
|
|
theProg.prog.progressProc = gGenericProgress;
|
|
theProg.prog.progressRefCon = (long)&theProg;
|
|
UpdateParamText(gString[strScanningDirectory], gNullString, gNullString, gNullString);
|
|
CallICMProgressProc(theProg.prog.progressProc, codecProgressOpen, kIndefProgress, theProg.prog.progressRefCon);
|
|
theErr = GetSlideSpec(&theSpec);
|
|
if (theErr == noErr)
|
|
if (!WasDesktop(&theSpec, (*gSlideOptions)->recursive, progPtr, &theErr))
|
|
theErr = AddSlideDir(&theSpec, (*gSlideOptions)->recursive, progPtr, nil);
|
|
CallICMProgressProc(theProg.prog.progressProc, codecProgressClose, kIndefProgress, theProg.prog.progressRefCon);
|
|
}
|
|
if (theErr == noErr) InitSlideShow();
|
|
else {
|
|
CleanUpSlideShow();
|
|
if (theErr == noErr) MinorError(errNoMemory);
|
|
}
|
|
return theErr;
|
|
}
|
|
|
|
static Boolean WasDesktop(FSSpec *spec, Boolean recursive, ICMProgressProcRecordPtr theProg,
|
|
OSErr *theErr)
|
|
{
|
|
HParamBlockRec params;
|
|
FSSpec theSpec;
|
|
OSErr err;
|
|
|
|
err = GetDeskFolderSpec(&theSpec, spec->vRefNum);
|
|
if (err != noErr || !SameFile(&theSpec, spec)) return false;
|
|
params.volumeParam.ioVolIndex = 1;
|
|
params.volumeParam.ioCompletion = nil;
|
|
params.volumeParam.ioNamePtr = theSpec.name;
|
|
while (PBHGetVInfo(¶ms, false) == noErr && *theErr == noErr) {
|
|
if (recursive) err = FSMakeFSSpec(params.ioParam.ioVRefNum, 2, "\p", &theSpec);
|
|
else err = GetDeskFolderSpec(&theSpec, params.volumeParam.ioVRefNum);
|
|
if (err == noErr) err = AddSlideDir(&theSpec, recursive, theProg, nil);
|
|
if (err == memFullErr || err == codecAbortErr) *theErr = err;
|
|
params.volumeParam.ioVolIndex++;
|
|
}
|
|
}
|