mirror of
https://github.com/aaronsgiles/JPEGView.git
synced 2024-06-14 12:29:33 +00:00
These are the sources for the final official release of JPEGView for the Mac, back in 1994.
1 line
17 KiB
C
1 line
17 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
|
|
|
|
/*
|
|
* DrawingAreaAccessor(classWanted, container, containerClass, keyForm, keyData,
|
|
* resultToken, theRefCon)
|
|
*
|
|
* Purpose: Finds a drawing area according to the specified keyForm and returns the
|
|
* corresponding drawing area token
|
|
* Inputs: classWanted = the element class desired (cDrawingArea)
|
|
* container = token for this element's container
|
|
* containerClass = class of this element's container (cWindow)
|
|
* keyForm = the search key type
|
|
* keyData = descriptor containing search key data
|
|
* resultToken = descriptor containing the resulting token
|
|
* theRefCon = reference constant
|
|
* Returns: an OSErr describing the result
|
|
*
|
|
*/
|
|
|
|
pascal OSErr DrawingAreaAccessor(DescType classWanted, AEDesc *container,
|
|
DescType containerClass, DescType keyForm, AEDesc *keyData,
|
|
AEDesc *resultToken, long theRefCon)
|
|
{
|
|
#if applec
|
|
#pragma unused (classWanted, containerClass, theRefCon)
|
|
#endif
|
|
ObjectTokenHandle theList = (ObjectTokenHandle)container->dataHandle;
|
|
OSErr theErr = noErr;
|
|
|
|
if (IsValidForOne(keyForm, keyData)) {
|
|
if ((theErr = HandToHand((Handle *)&theList)) != noErr) return theErr;
|
|
PurgeNonDocuments(theList);
|
|
} else return errAENoSuchObject;
|
|
if (!theList || !(*theList)->count || (theErr != noErr)) {
|
|
DisposeHandle((Handle)theList);
|
|
if (theErr == noErr) theErr = errAENoSuchObject;
|
|
} else {
|
|
theErr = AECreateHandleDesc(cDrawingArea, (Handle)theList, resultToken);
|
|
DisposeHandle((Handle)theList);
|
|
}
|
|
return theErr;
|
|
}
|
|
|
|
/*
|
|
* DrawPropertyAccessor(classWanted, container, containerClass, keyForm, keyData,
|
|
* resultToken, theRefCon)
|
|
*
|
|
* Purpose: Finds a drawing area property and returns the corresponding property token
|
|
* Inputs: classWanted = the element class desired (typeProperty)
|
|
* container = token for this element's container
|
|
* containerClass = class of this element's container (cDrawingArea)
|
|
* keyForm = the search key type
|
|
* keyData = descriptor containing search key data
|
|
* resultToken = descriptor containing the resulting token
|
|
* theRefCon = reference constant
|
|
* Returns: an OSErr describing the result
|
|
*
|
|
*/
|
|
|
|
pascal OSErr DrawPropertyAccessor(DescType classWanted, AEDesc *container,
|
|
DescType containerClass, DescType keyForm, AEDesc *keyData,
|
|
AEDesc *resultToken, long theRefCon)
|
|
{
|
|
#if applec
|
|
#pragma unused (classWanted, containerClass, theRefCon)
|
|
#endif
|
|
ObjectTokenHandle theList = (ObjectTokenHandle)container->dataHandle;
|
|
DescType propertyType;
|
|
OSErr theErr;
|
|
|
|
if ((keyForm != formPropertyID) || (keyData->descriptorType != typeType))
|
|
return errAECantSupplyType;
|
|
propertyType = *(DescType *)*keyData->dataHandle;
|
|
switch (propertyType) {
|
|
// Non-modifiable properties
|
|
case pBestType:
|
|
case pClass:
|
|
case pDefaultType:
|
|
// Modifiable properties
|
|
case pBounds:
|
|
case pColorTable:
|
|
case pDrawQuality:
|
|
case pScale:
|
|
case pPalette:
|
|
case pTransferMode:
|
|
break;
|
|
default:
|
|
return errAEEventNotHandled;
|
|
}
|
|
theErr = HandToHand((Handle *)&theList);
|
|
if (theErr != noErr) return theErr;
|
|
(*theList)->property = propertyType;
|
|
(*theList)->objclass = cDrawingArea;
|
|
theErr = AECreateHandleDesc(typeProperty, (Handle)theList, resultToken);
|
|
DisposeHandle((Handle)theList);
|
|
return theErr;
|
|
}
|
|
|
|
/*
|
|
* GetDrawingAreaData(theWindow, typeWanted, theData)
|
|
*
|
|
* Purpose: Extracts the data from the drawing area
|
|
* Inputs: theWindow = the window associated with this object
|
|
* typeWanted = the type we're asking for
|
|
* theData = the data we save
|
|
* Returns: an OSErr describing the result
|
|
*
|
|
*/
|
|
|
|
OSErr GetDrawingAreaData(WindowPtr theWindow, DescType typeWanted, AEDesc *theData)
|
|
{
|
|
if (typeWanted == typeWildCard) typeWanted = typeObjectSpecifier;
|
|
if (typeWanted == typeBest) typeWanted = typeObjectSpecifier;
|
|
if (typeWanted != typeObjectSpecifier) return errAECantSupplyType;
|
|
return MakeDrawingAreaObject(theWindow, theData);
|
|
}
|
|
|
|
/*
|
|
* GetDrawPropertyData(theWindow, theProperty, typeWanted, theData)
|
|
*
|
|
* Purpose: Extracts the data from the drawing area's properties
|
|
* Inputs: theWindow = the window associated with this object
|
|
* theProperty = the property wanted
|
|
* typeWanted = the type we're asking for
|
|
* theData = the data we save
|
|
* Returns: an OSErr describing the result
|
|
*
|
|
*/
|
|
|
|
OSErr GetDrawPropertyData(WindowPtr theWindow, DescType theProperty, DescType typeWanted,
|
|
AEDesc *theData)
|
|
{
|
|
ImageHandle theImage = FindImage(theWindow);
|
|
Boolean theBoolean = true;
|
|
Point thePoint = { 0, 0 };
|
|
CTabHandle theColors;
|
|
DescType theType;
|
|
AEDesc bestData;
|
|
short theShort;
|
|
Rect theRect;
|
|
OSErr theErr;
|
|
|
|
if (!theImage) return errAEReadDenied;
|
|
switch (theProperty) {
|
|
case pBestType:
|
|
case pDefaultType:
|
|
theType = typeObjectSpecifier;
|
|
theErr = AECreateDesc(typeType, (void *)&theType, sizeof(DescType), &bestData);
|
|
break;
|
|
case pBounds:
|
|
theRect = (*theImage)->wrect;
|
|
theErr = AECreateDesc(typeQDRectangle, (void *)&theRect, sizeof(Rect), &bestData);
|
|
break;
|
|
case pClass:
|
|
theType = cDrawingArea;
|
|
theErr = AECreateDesc(typeType, (void *)&theType, sizeof(DescType), &bestData);
|
|
break;
|
|
case pColorTable:
|
|
theColors = (CTabHandle)NewHandle(4);
|
|
if (theColors) Palette2CTab((*theImage)->palette, theColors);
|
|
theErr = AECreateHandleDesc(typeColorTable, (Handle)theColors, &bestData);
|
|
DisposeHandle((Handle)theColors);
|
|
break;
|
|
case pDrawQuality:
|
|
if ((*theImage)->quality == iqVHigh) theType = kAEDQVeryHigh;
|
|
else if ((*theImage)->quality == iqHigh) theType = kAEDQHigh;
|
|
else if ((*theImage)->quality == iqMedium) theType = kAEDQNormal;
|
|
theErr = AECreateDesc(typeEnumerated, (void *)&theType, sizeof(DescType), &bestData);
|
|
break;
|
|
case pScale:
|
|
theShort = ((long)Width(&(*theImage)->wrect) * 100) / Width(&(*theImage)->crect);
|
|
theShort += ((long)Height(&(*theImage)->wrect) * 100) / Height(&(*theImage)->crect);
|
|
theShort >>= 1;
|
|
theErr = AECreateDesc(typeShortInteger, (void *)&theShort, sizeof(short), &bestData);
|
|
break;
|
|
case pPalette:
|
|
switch ((*theImage)->npalette) {
|
|
case plSys: theType = kAEPSystem; break;
|
|
case plGrey: theType = kAEPGrayscale; break;
|
|
case plImage: theType = kAEPImage; break;
|
|
case plQuant: theType = kAEPQuantized; break;
|
|
default: theType = typeWildCard; break;
|
|
}
|
|
theErr = AECreateDesc(typeEnumerated, (void *)&theType, sizeof(DescType), &bestData);
|
|
break;
|
|
case pTransferMode:
|
|
theType = Dithered(theImage) ? kAEQDDitherCopy : kAEQDCopy;
|
|
theErr = AECreateDesc(typeEnumerated, (void *)&theType, sizeof(DescType), &bestData);
|
|
break;
|
|
default:
|
|
theErr = errAETypeError;
|
|
break;
|
|
}
|
|
if (theErr != noErr) return theErr;
|
|
if ((bestData.descriptorType == typeWanted) ||
|
|
(typeWanted == typeWildCard) || (typeWanted == typeBest))
|
|
theErr = AEDuplicateDesc(&bestData, theData);
|
|
else theErr = AECoerceDesc(&bestData, typeWanted, theData);
|
|
AEDisposeDesc(&bestData);
|
|
return theErr;
|
|
}
|
|
|
|
/*
|
|
* SetDrawPropertyData(theWindow, theProperty, theData)
|
|
*
|
|
* Purpose: Sets the data for the drawing area's properties
|
|
* Inputs: theWindow = the associated window
|
|
* theProperty = the property wanted
|
|
* theData = the data to set it to
|
|
* Returns: an OSErr describing the result
|
|
*
|
|
*/
|
|
|
|
OSErr SetDrawPropertyData(WindowPtr theWindow, DescType theProperty, AEDesc *theData)
|
|
{
|
|
ImageHandle theImage = FindImage(theWindow);
|
|
Rect theRect, oldRect;
|
|
CTabHandle theColors;
|
|
DescType theMode;
|
|
short theShort;
|
|
Fixed theFixed;
|
|
OSErr theErr;
|
|
|
|
if (!theImage) return errAEWriteDenied;
|
|
switch (theProperty) {
|
|
case pBounds:
|
|
theErr = AEExtractQDRectangle(theData, 0, &theRect);
|
|
if (theErr == noErr) theErr = DoSetDrawBounds(theImage, &theRect);
|
|
break;
|
|
case pColorTable:
|
|
if (theData->descriptorType == typeColorTable) {
|
|
theColors = (CTabHandle)theData->dataHandle;
|
|
theErr = DoSetColorTable(theWindow, theColors);
|
|
} else theErr = errAETypeError;
|
|
break;
|
|
case pDrawQuality:
|
|
theErr = AEExtractEnumerated(theData, 0, &theMode);
|
|
if (theErr == noErr) theErr = DoSetImageQuality(theImage, theMode);
|
|
break;
|
|
case pPalette:
|
|
theErr = AEExtractEnumerated(theData, 0, &theMode);
|
|
if (theErr == noErr) theErr = DoSetPalette(theWindow, theMode);
|
|
break;
|
|
case pScale:
|
|
theErr = AEExtractShort(theData, 0, &theShort);
|
|
if (theErr == noErr) {
|
|
Rect monRect;
|
|
theRect = (*theImage)->crect;
|
|
theRect.right = theRect.left + ((theShort * Width(&theRect)) / 100);
|
|
theRect.bottom = theRect.top + ((theShort * Height(&theRect)) / 100);
|
|
OffsetRect(&theRect, -theRect.left, -theRect.top);
|
|
GetActiveRect((*theImage)->dmon, &monRect);
|
|
if (!Full(theImage)) monRect.top += gTitleBarHeight;
|
|
if (Height(&theRect) > Height(&monRect)) {
|
|
theRect.right = (long)theRect.right * (long)Height(&monRect) / (long)theRect.bottom;
|
|
theRect.bottom = Height(&monRect);
|
|
}
|
|
if (Width(&theRect) > Width(&monRect)) {
|
|
theRect.bottom = (long)theRect.bottom * (long)Width(&monRect) / (long)theRect.right;
|
|
theRect.right = Width(&monRect);
|
|
}
|
|
oldRect = (*theImage)->wrect;
|
|
(*theImage)->wrect = theRect;
|
|
ResizeWindow(theImage);
|
|
}
|
|
break;
|
|
case pTransferMode:
|
|
theErr = AEExtractEnumerated(theData, 0, &theMode);
|
|
if (theMode == kAEQDDitherCopy) theErr = DoSetImageDither(theImage, true);
|
|
else if (theMode == kAEQDCopy) theErr = DoSetImageDither(theImage, false);
|
|
else theErr = errAETypeError;
|
|
break;
|
|
default:
|
|
theErr = errAEWriteDenied;
|
|
break;
|
|
}
|
|
return theErr;
|
|
}
|
|
|
|
/*
|
|
* MakeDrawingAreaObject(theWindow, theObject)
|
|
*
|
|
* Purpose: Creates a drawing area object descriptor for the given window
|
|
* Inputs: theWindow = pointer to the window, or nil for all windows
|
|
* theObject = pointer to an AEDesc to store the result
|
|
* Returns: an OSErr describing what went wrong
|
|
*
|
|
*/
|
|
|
|
OSErr MakeDrawingAreaObject(WindowPtr theWindow, AEDesc *theObject)
|
|
{
|
|
AEDesc theKey, theContainer;
|
|
long index = kAEFirst;
|
|
OSErr theErr = noErr;
|
|
|
|
theErr = MakeWindowObject(theWindow, &theContainer);
|
|
if (theErr == noErr) {
|
|
theErr = AECreateDesc(typeAbsoluteOrdinal, (void *)&index, sizeof(long), &theKey);
|
|
if (theErr == noErr) {
|
|
theErr = CreateObjSpecifier(cDrawingArea, &theContainer, formAbsolutePosition,
|
|
&theKey, false, theObject);
|
|
AEDisposeDesc(&theKey);
|
|
}
|
|
AEDisposeDesc(&theContainer);
|
|
}
|
|
return theErr;
|
|
}
|
|
|
|
/*
|
|
* MakeDrawPropertyObject(theWindow, theProperty, theObject)
|
|
*
|
|
* Purpose: Creates a property object descriptor for the given drawing area's property
|
|
* Inputs: theWindow = pointer to the window, or nil for all windows
|
|
* theObject = pointer to an AEDesc to store the result
|
|
* Returns: an OSErr describing what went wrong
|
|
*
|
|
*/
|
|
|
|
OSErr MakeDrawPropertyObject(WindowPtr theWindow, DescType theProperty, AEDesc *theObject)
|
|
{
|
|
AEDesc theKey, theContainer;
|
|
OSErr theErr = noErr;
|
|
|
|
theErr = MakeDrawingAreaObject(theWindow, &theContainer);
|
|
if (theErr == noErr) {
|
|
theErr = AECreateDesc(typeType, (void *)&theProperty, sizeof(DescType), &theKey);
|
|
if (theErr == noErr) {
|
|
theErr = CreateObjSpecifier(typeProperty, &theContainer, formPropertyID,
|
|
&theKey, false, theObject);
|
|
AEDisposeDesc(&theKey);
|
|
}
|
|
AEDisposeDesc(&theContainer);
|
|
}
|
|
return theErr;
|
|
}
|
|
|
|
/*
|
|
* DoSetColorTable(theWindow, theColors)
|
|
*
|
|
* Purpose: Sets the palette of the given window to the given set of colors
|
|
* Inputs: theWindow = pointer to the window
|
|
* theColors = a handle to the color table
|
|
* Returns: an OSErr describing what went wrong
|
|
*
|
|
*/
|
|
|
|
OSErr DoSetColorTable(WindowPtr theWindow, CTabHandle theColors)
|
|
{
|
|
ImageHandle theImage = FindImage(theWindow);
|
|
PaletteHandle thePalette;
|
|
|
|
if (!theImage) return errAEWriteDenied;
|
|
if (thePalette = NewPalette((*theColors)->ctSize + 1, theColors, pmTolerant, 0)) {
|
|
if ((*theImage)->palette) DisposePalette((*theImage)->palette);
|
|
(*theImage)->palette = thePalette;
|
|
SetPalette(theWindow, (*theImage)->palette, true);
|
|
ActivatePalette(theWindow);
|
|
if (theWindow == FWFrontWindow()) FWSelectWindow(theWindow);
|
|
if (!GWOrigSize(theImage)) KillGWorld(theImage);
|
|
(*theImage)->npalette = plNone;
|
|
} else return memFullErr;
|
|
return noErr;
|
|
}
|
|
|
|
/*
|
|
* DoSetPalette(theWindow, thePalette)
|
|
*
|
|
* Purpose: Sets the palette of the given window to the given palette,
|
|
* via DoSetColorTable
|
|
* Inputs: theWindow = pointer to the window
|
|
* thePalette = a constant specifying which palette to use
|
|
* Returns: an OSErr describing what went wrong
|
|
*
|
|
*/
|
|
|
|
OSErr DoSetPalette(WindowPtr theWindow, DescType thePalette)
|
|
{
|
|
ImageHandle theImage = FindImage(theWindow);
|
|
PaletteHandle newPalette = nil, copyPalette;
|
|
OSErr theErr = noErr;
|
|
Boolean hadGWorld;
|
|
short depth;
|
|
|
|
if (!theImage) return errAENoSuchObject;
|
|
hadGWorld = ((*theImage)->gworld != nil);
|
|
depth = (*(*theImage)->dmon)->depth;
|
|
switch (thePalette) {
|
|
case kAEPSystem:
|
|
newPalette = SystemPalette(depth);
|
|
(*theImage)->npalette = plSys;
|
|
break;
|
|
case kAEPGrayscale:
|
|
newPalette = GreyPalette(depth);
|
|
(*theImage)->npalette = plGrey;
|
|
break;
|
|
case kAEPImage:
|
|
newPalette = (*theImage)->ipalette;
|
|
if (newPalette) (*theImage)->npalette = plImage;
|
|
break;
|
|
case kAEPQuantized:
|
|
if ((*theImage)->depth < 16) break;
|
|
if (depth > 8) depth = 8;
|
|
if (!(*theImage)->qpalette ||
|
|
((*(*theImage)->qpalette)->pmEntries != (1L << depth))) {
|
|
theErr = DoQuantize(theImage, 1L << depth, &newPalette, nil);
|
|
if ((theErr == noErr) && newPalette) {
|
|
if ((*theImage)->qpalette) DisposePalette((*theImage)->qpalette);
|
|
(*theImage)->qpalette = newPalette;
|
|
}
|
|
}
|
|
newPalette = (*theImage)->qpalette;
|
|
if (newPalette) (*theImage)->npalette = plQuant;
|
|
break;
|
|
default:
|
|
return errAETypeError;
|
|
}
|
|
if (!newPalette && !(*theImage)->palette)
|
|
newPalette = SystemPalette(depth), (*theImage)->npalette = plSys;
|
|
if (newPalette) {
|
|
copyPalette = NewPalette((*newPalette)->pmEntries, nil, pmTolerant, 0);
|
|
if (copyPalette) {
|
|
CopyPalette(newPalette, copyPalette, 0, 0, (*newPalette)->pmEntries);
|
|
if ((*theImage)->palette) DisposePalette((*theImage)->palette);
|
|
(*theImage)->palette = copyPalette;
|
|
SetPalette(theWindow, (*theImage)->palette, true);
|
|
ActivatePalette(theWindow);
|
|
if (theWindow == FWFrontWindow()) FWSelectWindow(theWindow);
|
|
if (hadGWorld && !GWOrigSize(theImage)) KillGWorld(theImage);
|
|
} else theErr = memFullErr;
|
|
}
|
|
if (theErr == noErr && (*theImage)->npalette == plQuant && (*theImage)->gworld &&
|
|
!gThePrefs.origSize && (*(*theImage)->gworld->portPixMap)->pixelSize == (*theImage)->depth)
|
|
theErr = ShrinkGWorld(theImage);
|
|
return theErr;
|
|
}
|
|
|
|
/*
|
|
* DoSetImageDither(theWindow, dither)
|
|
*
|
|
* Purpose: Sets the dither flag of the given image to the specified value
|
|
* Inputs: theWindow = pointer to the window
|
|
* dither = flag: true to dither the image; false otherwise
|
|
* Returns: an OSErr describing what went wrong
|
|
*
|
|
*/
|
|
|
|
OSErr DoSetImageDither(ImageHandle theImage, Boolean dither)
|
|
{
|
|
Rect theRect = (*theImage)->wrect;
|
|
|
|
if (dither) (*theImage)->flags |= ifDithered;
|
|
else (*theImage)->flags &= ~ifDithered;
|
|
PushPort();
|
|
MySetPort((CGrafPtr)(*theImage)->window);
|
|
InvalRect(&theRect);
|
|
PopPort();
|
|
if ((*theImage)->gworld && !GWOrigSize(theImage))
|
|
KillGWorld(theImage);
|
|
return noErr;
|
|
}
|
|
|
|
/*
|
|
* DoSetImageQuality(theWindow, dither)
|
|
*
|
|
* Purpose: Sets the quality of the given image to the specified value
|
|
* Inputs: theWindow = pointer to the window
|
|
* dither = flag: true to dither the image; false otherwise
|
|
* Returns: an OSErr describing what went wrong
|
|
*
|
|
*/
|
|
|
|
OSErr DoSetImageQuality(ImageHandle theImage, DescType theQuality)
|
|
{
|
|
Rect theRect = (*theImage)->wrect;
|
|
|
|
switch (theQuality) {
|
|
case kAEDQVeryHigh:
|
|
(*theImage)->quality = iqVHigh;
|
|
break;
|
|
case kAEDQHigh:
|
|
(*theImage)->quality = iqHigh;
|
|
break;
|
|
case kAEDQNormal:
|
|
(*theImage)->quality = iqMedium;
|
|
break;
|
|
default:
|
|
return errAETypeError;
|
|
}
|
|
if (Dithered(theImage)) {
|
|
PushPort();
|
|
MySetPort((CGrafPtr)(*theImage)->window);
|
|
InvalRect(&theRect);
|
|
PopPort();
|
|
if ((*theImage)->gworld)
|
|
if (!GWOrigSize(theImage) || ((*(*theImage)->gworld->portPixMap)->pixelSize <= 8))
|
|
KillGWorld(theImage);
|
|
}
|
|
return noErr;
|
|
}
|
|
|
|
extern OSErr DoSetDrawBounds(ImageHandle theImage, Rect *theRect)
|
|
{
|
|
Rect oldRect = (*theImage)->wrect;
|
|
(*theImage)->wrect = *theRect;
|
|
ResizeWindow(theImage);
|
|
if (!EqualSizeRect(&(*theImage)->wrect, &oldRect)) {
|
|
PushPort();
|
|
MySetPort((CGrafPtr)(*theImage)->window);
|
|
InvalRect(&(*theImage)->window->portRect);
|
|
PopPort();
|
|
}
|
|
return noErr;
|
|
}
|