mirror of
https://github.com/aaronsgiles/JPEGView.git
synced 2024-06-06 21:29:27 +00:00
92bdb55672
These are the sources for the final official release of JPEGView for the Mac, back in 1994.
1 line
28 KiB
C
1 line
28 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
|
|
|
|
typedef struct PICTPrivates {
|
|
Rect qdRect;
|
|
long totalLines;
|
|
} PICTPrivates, *PICTPrivatesPtr, **PICTPrivatesHandle;
|
|
|
|
/*
|
|
* Local variables:
|
|
* lPICTImage = pointer to the image for use when extracting PICT information
|
|
* lPICTPreview = handle to the preview image, if one was requested for saving
|
|
*
|
|
*/
|
|
|
|
static Handle gPICTComments;
|
|
static Rect gPICTSrcRect, gPICTDstRect;
|
|
static ImageHandle gPICTImage;
|
|
static JVDrawParamsHandle gPICTParams;
|
|
static long gTotalLines, gCurrentLines;
|
|
static Boolean gHasObjects;
|
|
static StdPixUPP gProgressPixProc = nil, gAddColorsPixProc, gInitPixProc;
|
|
static QDBitsUPP gDummyBitsProc, gInitBitsProc;
|
|
static QDTextUPP gDummyTextProc, gInitTextProc;
|
|
static QDLineUPP gDummyLineProc, gInitLineProc;
|
|
static QDRectUPP gDummyRectProc, gInitRectProc;
|
|
static QDRRectUPP gDummyRRectProc, gInitRRectProc;
|
|
static QDOvalUPP gDummyOvalProc, gInitOvalProc;
|
|
static QDArcUPP gDummyArcProc, gInitArcProc;
|
|
static QDPolyUPP gDummyPolyProc, gInitPolyProc;
|
|
static QDRgnUPP gDummyRgnProc, gInitRgnProc;
|
|
|
|
static void InitPICTUPPs(void);
|
|
static pascal void ProgressPixProc(PixMap *src, Rect *srcRect, MatrixRecord *matrix, short mode,
|
|
RgnHandle mask, PixMap *matte, Rect *matteRect, short flags);
|
|
static pascal void AddColorsPixProc(PixMap *src, Rect *srcRect, MatrixRecord *matrix, short mode,
|
|
RgnHandle mask, PixMap *matte, Rect *matteRect, short flags);
|
|
static pascal void InitPixProc(PixMap *src, Rect *srcRect, MatrixRecord *matrix, short mode,
|
|
RgnHandle mask, PixMap *matte, Rect *matteRect, short callOldBits);
|
|
static pascal void InitBitsProc(PixMap *src, Rect *srcRect, Rect *dstRect, short mode,
|
|
RgnHandle mask);
|
|
static pascal void InitTextProc(short count, const void *textAddr, Point numer, Point denom);
|
|
static pascal void InitLineProc(Point newPt);
|
|
static pascal void InitRectProc(GrafVerb verb, const Rect *r);
|
|
static pascal void InitRRectProc(GrafVerb verb, const Rect *r, short ovalWidth,
|
|
short ovalHeight);
|
|
static pascal void InitOvalProc(GrafVerb verb, const Rect *r);
|
|
static pascal void InitArcProc(GrafVerb verb, const Rect *r, short startAngle, short arcAngle);
|
|
static pascal void InitPolyProc(GrafVerb verb, PolyHandle poly);
|
|
static pascal void InitRgnProc(GrafVerb verb, RgnHandle rgn);
|
|
static pascal void DummyBitsProc(PixMap *src, Rect *srcRect, Rect *dstRect, short mode,
|
|
RgnHandle mask);
|
|
static pascal void DummyTextProc(short count, const void *textAddr, Point numer, Point denom);
|
|
static pascal void DummyLineProc(Point newPt);
|
|
static pascal void DummyRectProc(GrafVerb verb, const Rect *r);
|
|
static pascal void DummyRRectProc(GrafVerb verb, const Rect *r, short ovalWidth,
|
|
short ovalHeight);
|
|
static pascal void DummyOvalProc(GrafVerb verb, const Rect *r);
|
|
static pascal void DummyArcProc(GrafVerb verb, const Rect *r, short startAngle, short arcAngle);
|
|
static pascal void DummyPolyProc(GrafVerb verb, PolyHandle poly);
|
|
static pascal void DummyRgnProc(GrafVerb verb, RgnHandle rgn);
|
|
|
|
/*
|
|
* idPICT(theData, theSize)
|
|
*
|
|
* Purpose: Attempts to identify an image as a PICT
|
|
* Inputs: theData = pointer to the loaded data
|
|
* theSize = size of the loaded data
|
|
* Returns: true for a positive PICT ID
|
|
*
|
|
*/
|
|
|
|
Boolean idPICT(uchar *theData, long theSize, short refNum, FSSpec *theSpec)
|
|
{
|
|
#if applec
|
|
#pragma unused(refNum, theSpec)
|
|
#endif
|
|
ushort *theShort = (ushort *)(theData + kHeaderSize + 10);
|
|
PicPtr thePicture = (PicPtr)(theData + kHeaderSize);
|
|
|
|
if (theSize < kHeaderSize + 12) return false;
|
|
if (Width(&thePicture->picFrame) > 0 && Height(&thePicture->picFrame) > 0) {
|
|
while (!*theShort) theShort++;
|
|
if (*theShort == 0x0011 || *theShort == 0x1101) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
* OpenPICT(theImage)
|
|
*
|
|
* Purpose: Initializes the image record for a PICT image
|
|
* Inputs: theImage = image record for the PICT image
|
|
* Returns: nothing
|
|
*
|
|
*/
|
|
|
|
OSErr OpenPICT(ImageHandle theImage)
|
|
{
|
|
Fixed hRes = 0x480000L, vRes = 0x480000L;
|
|
Rect *theRect, fullQRect;
|
|
OSErr theErr = noErr;
|
|
ushort *theShort;
|
|
uchar *theData;
|
|
Str63 theDesc;
|
|
|
|
if (!((*theImage)->privateData = NewHandleClear(sizeof(PICTPrivates))))
|
|
return memFullErr;
|
|
theData = (uchar *)*(*theImage)->data;
|
|
theShort = (ushort *)(theData + 10);
|
|
theRect = (Rect *)(theData + 2);
|
|
(*(PICTPrivatesHandle)(*theImage)->privateData)->qdRect = (*theImage)->qrect = *theRect;
|
|
while (!*theShort) theShort++;
|
|
if (*theShort == 0x0011 && theShort[2] == 0x0c00 && theShort[3] == 0xfffe) {
|
|
theRect = (Rect *)(theShort + 9);
|
|
hRes = *(long *)(theShort + 5);
|
|
vRes = *(long *)(theShort + 7);
|
|
}
|
|
(*theImage)->grect = *theRect;
|
|
if (Width(&(*theImage)->grect) <= 0 || Height(&(*theImage)->grect) <= 0 ||
|
|
Width(&(*theImage)->qrect) <= 0 || Height(&(*theImage)->qrect) <= 0)
|
|
return gIntError = errCorruptImage, codecBadDataErr;
|
|
GetImageInfo(theImage);
|
|
fullQRect = (*theImage)->grect;
|
|
fullQRect.left = Fix2Long(FixMul(FixDiv(0x480000L, hRes), Long2Fix(fullQRect.left)));
|
|
fullQRect.right = Fix2Long(FixMul(FixDiv(0x480000L, hRes), Long2Fix(fullQRect.right)));
|
|
fullQRect.top = Fix2Long(FixMul(FixDiv(0x480000L, vRes), Long2Fix(fullQRect.top)));
|
|
fullQRect.bottom = Fix2Long(FixMul(FixDiv(0x480000L, vRes), Long2Fix(fullQRect.bottom)));
|
|
(*theImage)->crect = (*theImage)->qrect;
|
|
MapRect(&(*theImage)->crect, &fullQRect, &(*theImage)->grect);
|
|
(*theImage)->compression = (*theImage)->desc.cType;
|
|
if ((*theImage)->desc.height)
|
|
if (Height(&(*theImage)->crect) > (*theImage)->desc.height)
|
|
(*theImage)->flags |= ifBanded;
|
|
if ((*theImage)->crect.right < ((*theImage)->grect.right - 5) ||
|
|
(*theImage)->crect.left > ((*theImage)->grect.left + 5) ||
|
|
(*theImage)->crect.bottom < ((*theImage)->grect.bottom - 5) ||
|
|
(*theImage)->crect.top > ((*theImage)->grect.top + 5))
|
|
(*theImage)->flags |= ifCropped;
|
|
/* if ((*theImage)->compression == kJPEGCompression && !gHasObjects) {
|
|
if (Height(&(*theImage)->crect) > (*theImage)->desc.height)
|
|
(*theImage)->flags |= ifBanded;
|
|
if ((Width(&(*theImage)->crect) < (*theImage)->desc.width) ||
|
|
(Height(&(*theImage)->crect) < (*theImage)->desc.height))
|
|
(*theImage)->flags |= ifCropped;
|
|
}*/
|
|
/*
|
|
Old mechanism for detecting cropping vs. scaled DPI
|
|
|
|
//--- deal with cropped images??
|
|
if ((*theData)->compressionType == 'jpeg' && !gHasObjects) {
|
|
if (Height(&(*theImage)->crect) > (*theImage)->desc.height)
|
|
(*theImage)->flags |= ifBanded;
|
|
if ((Width(&(*theImage)->crect) < (*theImage)->desc.width) ||
|
|
(Height(&(*theImage)->crect) < (*theImage)->desc.height))
|
|
(*theImage)->flags |= ifCropped;
|
|
if (Cropped(theImage) && !Banded(theImage)) {
|
|
Rect crect = (*theImage)->crect, grect;
|
|
MySetRect(&grect, 0, 0, (*theImage)->desc.width, (*theImage)->desc.height);
|
|
MapRect(&crect, &(*theImage)->grect, &(*theImage)->qrect);
|
|
MapRect(&crect, &lPICTDstRect, &lPICTSrcRect);
|
|
if (crect.right > grect.right) crect.right = grect.right;
|
|
if (crect.left < grect.left) crect.left = grect.left;
|
|
if (crect.bottom > grect.bottom) crect.bottom = grect.bottom;
|
|
if (crect.top < grect.top) crect.top = grect.top;
|
|
(*theImage)->grect = grect;
|
|
theErr = DoSetImageBounds(theImage, &grect);
|
|
(*theImage)->crect = crect;
|
|
if (EqualSizeRect(&crect, &grect)) (*theImage)->flags &= ~ifCropped;
|
|
}
|
|
}
|
|
*/
|
|
if (!(*theImage)->ipalette &&
|
|
((*theImage)->depth == 36 || (*theImage)->depth == 40)) {
|
|
(*theImage)->ipalette = NewPalette(1L << ((*theImage)->depth - 32), nil, pmTolerant, 0);
|
|
if ((*theImage)->ipalette)
|
|
CopyPalette(GreyPalette((*theImage)->depth - 32), (*theImage)->ipalette, 0, 0, 256);
|
|
}
|
|
if ((*theImage)->compression == 'raw ') (*theImage)->compression = 0L;
|
|
if ((*theImage)->compression) {
|
|
BlockMove((*theImage)->desc.name, theDesc, *(*theImage)->desc.name + 1);
|
|
AddString(theDesc, gString[strQuality]);
|
|
StuffNumber(theDesc, 1, (*theImage)->desc.spatialQuality >> 8);
|
|
StuffNumber0(theDesc, 2, (((*theImage)->desc.spatialQuality & 0xff) * 100) >> 8, 2);
|
|
} else BlockMove(gString[strUncompressed], theDesc, *gString[strUncompressed] + 1);
|
|
BlockMove(theDesc, (*theImage)->compressionDesc, *theDesc + 1);
|
|
return theErr;
|
|
}
|
|
|
|
/*
|
|
* DrawPICT(theImage, theGWorld, srcRect, dstRect, dither, progProc)
|
|
*
|
|
* Purpose: Draws the PICT image within its cropping rectange in the proper window
|
|
* Inputs: theImage = image record for the PICT image
|
|
* theGWorld = the destination GWorld to draw into
|
|
* srcRect = the source rectangle
|
|
* dstRect = the destination rectangle
|
|
* dstRgn = the destination clipping region
|
|
* dither = flag: true if we should dither this guy
|
|
* progProc = the progress procedure record to be used
|
|
* Returns: nothing
|
|
*
|
|
*/
|
|
|
|
OSErr DrawPICT(Handle theHandle, JVDrawParamsHandle theParams)
|
|
{
|
|
Rect globRect = (*theParams)->bounds;
|
|
char hState = HGetState(theHandle);
|
|
OSErr theErr;
|
|
|
|
if (!gProgressPixProc) InitPICTUPPs();
|
|
((CGrafPtr)qd.thePort)->grafProcs->newProc1 = (UniversalProcPtr)gProgressPixProc;
|
|
gPICTParams = theParams;
|
|
gTotalLines = (*(PICTPrivatesHandle)(*theParams)->privateData)->totalLines;
|
|
gCurrentLines = 0;
|
|
PushPort();
|
|
ClipRect(&globRect);
|
|
RGBForeColor(&gBlack);
|
|
RGBBackColor(&gWhite);
|
|
HLock(theHandle);
|
|
KeepSpinning();
|
|
if (gQTVersion) theErr = DrawTrimmedPicture((PicHandle)theHandle, &globRect,
|
|
qd.thePort->visRgn, false, nil);
|
|
else DrawPicture((PicHandle)theHandle, &globRect), theErr = noErr;
|
|
if ((*theParams)->progress.aborted) theErr = codecAbortErr;
|
|
KeepSpinning();
|
|
HSetState(theHandle, hState);
|
|
PopPort();
|
|
return theErr;
|
|
}
|
|
|
|
/*
|
|
* ProgressPixProc(src, srcRect, matrix, mode, mask, matte, matteRect, callOldBits)
|
|
*
|
|
* Purpose: Routine called when a compressed PixMap is found in a PICT; we
|
|
* intercept it and call FDecompressImage, making the progress updates
|
|
* work to some extent....
|
|
* Inputs: src = the compressed PixMap
|
|
* srcRect = the rectangle of the image in the source coordinates
|
|
* matrix = the transformation matrix
|
|
* mode = the drawing mode
|
|
* mask = the output masking region
|
|
* matte = the output matte, described as a PixMap
|
|
* matteRect = the bounding rectangle for the output matte
|
|
* callOldBits = flag saying if we should call the old routine
|
|
* Returns: nothing
|
|
*
|
|
*/
|
|
|
|
pascal void ProgressPixProc(PixMap *src, Rect *srcRect, MatrixRecord *matrix, short mode,
|
|
RgnHandle mask, PixMap *matte, Rect *matteRect, short flags)
|
|
{
|
|
PixMapHandle dst = GetGWorldPixMap((CGrafPtr)qd.thePort);
|
|
NestedProgress theProc = (*gPICTParams)->progress;
|
|
ImageDescriptionHandle theDesc;
|
|
ICMProgressProcRecord progProc;
|
|
ICMDataProcRecord dataProc;
|
|
OSErr theErr;
|
|
long bufSize;
|
|
Ptr theData;
|
|
|
|
if ((*gPICTParams)->progress.aborted || ((*gPICTParams)->progress.aborted = CheckAbort(gPICTParams)))
|
|
return;
|
|
theErr = GetCompressedPixMapInfo(src, &theDesc, &theData, &bufSize, &dataProc,
|
|
&progProc);
|
|
if (theErr == noErr) {
|
|
KeepSpinning();
|
|
(*gPICTParams)->progress.begin = FixRatio(gCurrentLines, gTotalLines);
|
|
(*gPICTParams)->progress.begin = theProc.begin +
|
|
FixMul((*gPICTParams)->progress.begin, theProc.end - theProc.begin);
|
|
(*gPICTParams)->progress.end = FixRatio(gCurrentLines + Height(srcRect), gTotalLines);
|
|
(*gPICTParams)->progress.end = theProc.begin +
|
|
FixMul((*gPICTParams)->progress.end, theProc.end - theProc.begin);
|
|
if ((*gPICTParams)->progress.prog.progressProc)
|
|
CallICMProgressProc((*gPICTParams)->progress.prog.progressProc,
|
|
codecProgressUpdatePercent, 0x00000000L,
|
|
(*gPICTParams)->progress.prog.progressRefCon);
|
|
FixBits((CGrafPtr)qd.thePort, true);
|
|
InstallQDxDispatchPatch(true);
|
|
FDecompressImage(StripAddress(theData), theDesc, dst, srcRect, matrix, mode,
|
|
mask, &matte, matteRect, codecHighQuality, anyCodec, bufSize, &dataProc,
|
|
(ICMProgressProcRecordPtr)&theProc);
|
|
RemoveQDxDispatchPatch();
|
|
FixBits((CGrafPtr)qd.thePort, false);
|
|
if ((*gPICTParams)->progress.prog.progressProc && !(*gPICTParams)->progress.aborted)
|
|
CallICMProgressProc((*gPICTParams)->progress.prog.progressProc,
|
|
codecProgressUpdatePercent, 0x00010000L,
|
|
(*gPICTParams)->progress.prog.progressRefCon);
|
|
KeepSpinning();
|
|
(*gPICTParams)->progress.begin = theProc.begin;
|
|
(*gPICTParams)->progress.end = theProc.end;
|
|
gCurrentLines += Height(srcRect);
|
|
} else StdPix(src, srcRect, matrix, mode | 0x80, mask, matte, matteRect, flags);
|
|
if (gSlideShow && !(*gPICTParams)->progress.aborted)
|
|
(*gPICTParams)->progress.aborted = CheckAbort(gPICTParams);
|
|
}
|
|
|
|
/*
|
|
* LoadPICT(theFile, theImage)
|
|
*
|
|
* Purpose: Allocates memory and loads the PICT image in
|
|
* Inputs: theFile = the input file
|
|
* theImage = image record
|
|
* Returns: nothing
|
|
*
|
|
*/
|
|
|
|
OSErr LoadPICT(short theFile, ImageHandle theImage)
|
|
{
|
|
OSErr theErr = noErr;
|
|
long theSize;
|
|
|
|
KeepSpinning();
|
|
GetEOF(theFile, &theSize);
|
|
if ((theSize -= kHeaderSize) < 0) return errCorruptImage, codecBadDataErr;
|
|
if (!MakeMemAvailable(theSize)) return gIntError = errNoLoadMemory, memFullErr;
|
|
if ((*theImage)->data = NewHandle(theSize)) {
|
|
SetFPos(theFile, fsFromStart, kHeaderSize);
|
|
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;
|
|
}
|
|
|
|
static void InitPICTUPPs(void)
|
|
{
|
|
gProgressPixProc = NewStdPixProc((ProcPtr)ProgressPixProc);
|
|
gAddColorsPixProc = NewStdPixProc((ProcPtr)AddColorsPixProc);
|
|
gInitPixProc = NewStdPixProc((ProcPtr)InitPixProc);
|
|
gInitBitsProc = NewQDBitsProc((ProcPtr)InitBitsProc);
|
|
gInitTextProc = NewQDTextProc((ProcPtr)InitTextProc);
|
|
gInitLineProc = NewQDLineProc((ProcPtr)InitLineProc);
|
|
gInitRectProc = NewQDRectProc((ProcPtr)InitRectProc);
|
|
gInitRRectProc = NewQDRRectProc((ProcPtr)InitRRectProc);
|
|
gInitOvalProc = NewQDOvalProc((ProcPtr)InitOvalProc);
|
|
gInitArcProc = NewQDArcProc((ProcPtr)InitArcProc);
|
|
gInitPolyProc = NewQDPolyProc((ProcPtr)InitPolyProc);
|
|
gInitRgnProc = NewQDRgnProc((ProcPtr)InitRgnProc);
|
|
gDummyBitsProc = NewQDBitsProc((ProcPtr)DummyBitsProc);
|
|
gDummyTextProc = NewQDTextProc((ProcPtr)DummyTextProc);
|
|
gDummyLineProc = NewQDLineProc((ProcPtr)DummyLineProc);
|
|
gDummyRectProc = NewQDRectProc((ProcPtr)DummyRectProc);
|
|
gDummyRRectProc = NewQDRRectProc((ProcPtr)DummyRRectProc);
|
|
gDummyOvalProc = NewQDOvalProc((ProcPtr)DummyOvalProc);
|
|
gDummyArcProc = NewQDArcProc((ProcPtr)DummyArcProc);
|
|
gDummyPolyProc = NewQDPolyProc((ProcPtr)DummyPolyProc);
|
|
gDummyRgnProc = NewQDRgnProc((ProcPtr)DummyRgnProc);
|
|
}
|
|
|
|
/*
|
|
* GetImageInfo(theImage)
|
|
*
|
|
* Purpose: Retrieves the image description and CLUT from a given PICT
|
|
* Inputs: theImage = image record for the PICT image
|
|
* Returns: nothing
|
|
*
|
|
*/
|
|
|
|
void GetImageInfo(ImageHandle theImage)
|
|
{
|
|
char hState = HGetState((*theImage)->data);
|
|
Rect theRect = (*theImage)->qrect;
|
|
CQDProcs theProcs, *oldProcs;
|
|
|
|
gPICTImage = theImage;
|
|
gPICTComments = nil;
|
|
gTotalLines = 0;
|
|
gHasObjects = false;
|
|
PushPort();
|
|
MySetPort(gGenericGWorld);
|
|
SetStdCProcs(&theProcs);
|
|
if (!gProgressPixProc) InitPICTUPPs();
|
|
theProcs.newProc1 = (UniversalProcPtr)gInitPixProc;
|
|
theProcs.bitsProc = gInitBitsProc;
|
|
theProcs.textProc = gInitTextProc;
|
|
theProcs.lineProc = gInitLineProc;
|
|
theProcs.rectProc = gInitRectProc;
|
|
theProcs.rRectProc = gInitRRectProc;
|
|
theProcs.ovalProc = gInitOvalProc;
|
|
theProcs.arcProc = gInitArcProc;
|
|
theProcs.polyProc = gInitPolyProc;
|
|
theProcs.rgnProc = gInitRgnProc;
|
|
oldProcs = gGenericGWorld->grafProcs;
|
|
gGenericGWorld->grafProcs = &theProcs;
|
|
HLock((*theImage)->data);
|
|
KeepSpinning();
|
|
if (gQTVersion) DrawTrimmedPicture((PicHandle)(*theImage)->data, &theRect, nil, false, nil);
|
|
else DrawPicture((PicHandle)(*theImage)->data, &theRect);
|
|
KeepSpinning();
|
|
HSetState((*theImage)->data, hState);
|
|
gGenericGWorld->grafProcs = oldProcs;
|
|
PopPort();
|
|
if (!(*theImage)->depth) (*theImage)->depth = 1;
|
|
if (gHasObjects) (*theImage)->flags |= ifNeedsWhiteBG + ifNoOnscreenProg;
|
|
(*theImage)->comments = gPICTComments;
|
|
(*(PICTPrivatesHandle)(*theImage)->privateData)->totalLines = gTotalLines;
|
|
}
|
|
|
|
/*
|
|
* SavePICTFile(theSpec, theHandle)
|
|
*
|
|
* Purpose: Writes the PICT image out to the specified file
|
|
* Inputs: theSpec = a pointer to the output file spec
|
|
* theHandle = the handle of the data to be written
|
|
* Returns: an OSErr describing what went wrong
|
|
*
|
|
*/
|
|
|
|
OSErr SavePICT(FSSpec *theSpec, Handle theHandle, GWorldPtr thePreview, Rect *theRect, Handle privates)
|
|
{
|
|
#if applec
|
|
#pragma unused(thePreview, theRect, privates)
|
|
#endif
|
|
long theSize = GetHandleSize(theHandle);
|
|
char hState = HGetState(theHandle);
|
|
uchar *theHeader[kHeaderSize];
|
|
short theFile;
|
|
OSErr theErr;
|
|
long i;
|
|
|
|
for (i = 0; i < kHeaderSize; theHeader[i++] = 0);
|
|
KeepSpinning();
|
|
theErr = FSpCreate(theSpec, kCreator, kPICTType, 0);
|
|
if (theErr == noErr) {
|
|
KeepSpinning();
|
|
theErr = FSpOpenDF(theSpec, fsWrPerm, &theFile);
|
|
if (theErr == noErr) {
|
|
KeepSpinning();
|
|
theErr = FSWrite(theFile, &i, theHeader);
|
|
if (theErr == noErr) {
|
|
HLock(theHandle);
|
|
SpinIndef();
|
|
theErr = FSWrite(theFile, &theSize, *theHandle);
|
|
KeepSpinning();
|
|
if (theErr == noErr) {
|
|
HSetState(theHandle, hState);
|
|
FSClose(theFile);
|
|
return theErr;
|
|
} else gIntError = errCantWriteFile;
|
|
HSetState(theHandle, hState);
|
|
} else gIntError = errCantWriteFile;
|
|
FSClose(theFile);
|
|
} else gIntError = errCantOpenFile;
|
|
FSpDelete(theSpec);
|
|
} else gIntError = errCantCreateFile;
|
|
return theErr;
|
|
}
|
|
|
|
/*
|
|
* FixPICT(addPreview)
|
|
*
|
|
* Purpose: Performs the JFIF->PICT conversion on the active image, add the color
|
|
* table, crops it, and creates a preview if requested
|
|
* Inputs: addPreview = flag: true if we should add a preview image
|
|
* theSize = pointer to a long where we will return the size
|
|
* Returns: an OSErr describing what went wrong
|
|
*
|
|
*/
|
|
|
|
OSErr FixPICT(ImageHandle theImage, Handle *finalData, Boolean palette)
|
|
{
|
|
OSErr theErr = noErr;
|
|
Handle oldData;
|
|
|
|
if ((*theImage)->format->inType != kPICTType &&
|
|
(*theImage)->format->inType != kSCRNType &&
|
|
(*theImage)->format->inType != kJPEGType)
|
|
return errAETypeError;
|
|
oldData = *finalData = (*theImage)->data;
|
|
if ((*theImage)->format->inType == kJPEGType) {
|
|
KeepSpinning();
|
|
*finalData = WrapJPEG(oldData, (*theImage)->depth);
|
|
if ((*theImage)->data != oldData) DisposeHandle(oldData);
|
|
if (!*finalData) return memFullErr;
|
|
oldData = *finalData;
|
|
}
|
|
if (palette) {
|
|
KeepSpinning();
|
|
*finalData = AddColors(oldData, theImage);
|
|
if ((*theImage)->data != oldData) DisposeHandle(oldData);
|
|
if (!*finalData) return gIntError = errNoColorsMemory, memFullErr;
|
|
oldData = *finalData;
|
|
}
|
|
return theErr;
|
|
}
|
|
|
|
/*
|
|
* AddColors(theHandle, theImage)
|
|
*
|
|
* Purpose: Adds the image's palette to the image description of the PICT
|
|
* Inputs: theHandle = handle to the image data
|
|
* theImage = handle to the associated image
|
|
* Returns: a handle to the cropped image
|
|
*
|
|
*/
|
|
|
|
Handle AddColors(Handle theHandle, ImageHandle theImage)
|
|
{
|
|
PixMapHandle thePixMap = GetGWorldPixMap(gGenericGWorld);
|
|
CQDProcs theProcs, *oldProcs = gGenericGWorld->grafProcs;
|
|
long theSize = GetHandleSize(theHandle);
|
|
char hState = HGetState(theHandle);
|
|
Rect theRect = (*theImage)->qrect;
|
|
OpenCPicParams theParams;
|
|
Handle dstHandle;
|
|
OSErr theErr;
|
|
|
|
if (!(*theImage)->qpalette) return theHandle;
|
|
if (MakeMemAvailable(theSize + 16384L)) {
|
|
theParams.srcRect = theRect;
|
|
theParams.hRes = theParams.vRes = 0x480000L;
|
|
theParams.version = -2;
|
|
theParams.reserved1 = theParams.reserved2 = 0;
|
|
SetStdCProcs(&theProcs);
|
|
if (!gProgressPixProc) InitPICTUPPs();
|
|
theProcs.newProc1 = (UniversalProcPtr)gAddColorsPixProc;
|
|
theProcs.bitsProc = gDummyBitsProc;
|
|
theProcs.textProc = gDummyTextProc;
|
|
theProcs.lineProc = gDummyLineProc;
|
|
theProcs.rectProc = gDummyRectProc;
|
|
theProcs.rRectProc = gDummyRRectProc;
|
|
theProcs.ovalProc = gDummyOvalProc;
|
|
theProcs.arcProc = gDummyArcProc;
|
|
theProcs.polyProc = gDummyPolyProc;
|
|
theProcs.rgnProc = gDummyRgnProc;
|
|
gGenericGWorld->grafProcs = &theProcs;
|
|
PushPort();
|
|
MySetPort(gGenericGWorld);
|
|
ClipRect(&theParams.srcRect);
|
|
if (dstHandle = (Handle)OpenCPicture(&theParams)) {
|
|
LockPixels(thePixMap);
|
|
HLock(theHandle);
|
|
gPICTImage = theImage;
|
|
KeepSpinning();
|
|
theErr = DrawTrimmedPicture((PicHandle)theHandle, &theParams.srcRect, nil,
|
|
false, (ICMProgressProcRecordPtr)&gDummyProg);
|
|
KeepSpinning();
|
|
HSetState(theHandle, hState);
|
|
UnlockPixels(thePixMap);
|
|
ClosePicture();
|
|
gGenericGWorld->grafProcs = oldProcs;
|
|
if ((theErr == noErr) && !EmptyRect(&(*(PicHandle)dstHandle)->picFrame)) {
|
|
PopPort();
|
|
return dstHandle;
|
|
}
|
|
DisposeHandle(dstHandle);
|
|
} else theErr = memFullErr;
|
|
gGenericGWorld->grafProcs = oldProcs;
|
|
PopPort();
|
|
} else theErr = memFullErr;
|
|
return nil;
|
|
}
|
|
|
|
/*
|
|
* AddColorsPixProc(src, srcRect, matrix, mode, mask, matte, matteRect, callOldBits)
|
|
*
|
|
* Purpose: Dummy routine called when a compressed PixMap is found in a PICT; we just
|
|
* add a color table to the ImageDescription
|
|
* Inputs: src = the compressed PixMap
|
|
* srcRect = the rectangle of the image in the source coordinates
|
|
* matrix = the transformation matrix
|
|
* mode = the drawing mode
|
|
* mask = the output masking region
|
|
* matte = the output matte, described as a PixMap
|
|
* matteRect = the bounding rectangle for the output matte
|
|
* callOldBits = flag saying if we should call the old routine
|
|
* Returns: nothing
|
|
*
|
|
*/
|
|
|
|
pascal void AddColorsPixProc(PixMap *src, Rect *srcRect, MatrixRecord *matrix, short mode,
|
|
RgnHandle mask, PixMap *matte, Rect *matteRect, short flags)
|
|
{
|
|
#if applec
|
|
#pragma unused(flags)
|
|
#endif
|
|
PixMapHandle dst = GetGWorldPixMap((CGrafPtr)qd.thePort);
|
|
ImageDescriptionHandle theDesc;
|
|
ICMProgressProcRecord progProc;
|
|
CTabHandle theColors = nil;
|
|
ICMDataProcRecord dataProc;
|
|
OSErr theError;
|
|
long bufSize;
|
|
Ptr theData;
|
|
|
|
KeepSpinning();
|
|
if (GetCompressedPixMapInfo(src, &theDesc, &theData, &bufSize, &dataProc, &progProc)
|
|
== noErr) {
|
|
if (theColors = (CTabHandle)AnyNewHandle(sizeof(ColorTable))) {
|
|
Palette2CTab((*gPICTImage)->qpalette, theColors);
|
|
(*theColors)->ctSeed = GetCTSeed();
|
|
SetImageDescriptionCTable(theDesc, theColors);
|
|
DisposeHandle((Handle)theColors);
|
|
theError = SetCompressedPixMapInfo(src, theDesc, theData, bufSize,
|
|
&dataProc, &progProc);
|
|
}
|
|
}
|
|
StdPix(src, srcRect, matrix, mode, mask, matte, matteRect, 0);
|
|
}
|
|
|
|
//=====================================================================================
|
|
// Dummy QuickDraw bottlenecks to filter out non-PixMaps within PICTs
|
|
//=====================================================================================
|
|
|
|
/*
|
|
* InitPixProc(src, srcRect, matrix, mode, mask, matte, matteRect, callOldBits)
|
|
*
|
|
* Purpose: Dummy routine called when a compressed PixMap is found in a PICT; we just
|
|
* copy the image description to a handle lPICTDesc
|
|
* Inputs: src = the compressed PixMap
|
|
* srcRect = the rectangle of the image in the source coordinates
|
|
* matrix = the transformation matrix
|
|
* mode = the drawing mode
|
|
* mask = the output masking region
|
|
* matte = the output matte, described as a PixMap
|
|
* matteRect = the bounding rectangle for the output matte
|
|
* callOldBits = flag saying if we should call the old routine
|
|
* Returns: nothing
|
|
*
|
|
*/
|
|
|
|
pascal void InitPixProc(PixMap *src, Rect *srcRect, MatrixRecord *matrix, short mode,
|
|
RgnHandle mask, PixMap *matte, Rect *matteRect, short callOldBits)
|
|
{
|
|
#if applec
|
|
#pragma unused(mode, mask, matte, matteRect, callOldBits)
|
|
#endif
|
|
ImageDescriptionHandle theDesc;
|
|
ICMProgressProcRecord progProc;
|
|
CTabHandle theColors = nil;
|
|
ICMDataProcRecord dataProc;
|
|
long bufSize;
|
|
Ptr theData;
|
|
|
|
gTotalLines += Height(srcRect);
|
|
gPICTSrcRect = *srcRect;
|
|
gPICTDstRect = *srcRect;
|
|
TransformRect(matrix, &gPICTDstRect, nil);
|
|
if (!GetCompressedPixMapInfo(src, &theDesc, &theData, &bufSize, &dataProc, &progProc)) {
|
|
if ((*theDesc)->cType == kJPEGCompression) {
|
|
if (!VerifyJPEGData((uchar *)theData, bufSize)) gIntError = errBadJPEG;
|
|
ExtractComments(theData, bufSize, &gPICTComments);
|
|
}
|
|
BlockMove(*theDesc, &(*gPICTImage)->desc, sizeof(ImageDescription));
|
|
(*gPICTImage)->depth = (*theDesc)->depth;
|
|
if ((*theDesc)->clutID != -1) {
|
|
GetImageDescriptionCTable(theDesc, &theColors);
|
|
if (theColors) {
|
|
(*gPICTImage)->ipalette = NewPalette((*theColors)->ctSize + 1, theColors,
|
|
pmTolerant, 0);
|
|
DisposeHandle((Handle)theColors);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* InitBitsProc(src, srcRect, dstRect, mode, mask)
|
|
*
|
|
* Purpose: Routine called in place of CopyBits for our images; here we check for a
|
|
* custom color table
|
|
* Inputs: src = the compressed PixMap
|
|
* srcRect = the rectangle of the image in the source coordinates
|
|
* dstRect = the destination rectangle
|
|
* mode = the drawing mode
|
|
* mask = the output masking region
|
|
* Returns: nothing
|
|
*
|
|
*/
|
|
|
|
pascal void InitBitsProc(PixMap *src, Rect *srcRect, Rect *dstRect, short mode,
|
|
RgnHandle mask)
|
|
{
|
|
#if applec
|
|
#pragma unused(srcRect, dstRect, mode, mask)
|
|
#endif
|
|
if (!(*gPICTImage)->depth) {
|
|
if (src->rowBytes & 0x8000) {
|
|
(*gPICTImage)->depth = src->pixelSize;
|
|
if ((src->pixelSize <= 8) && src->pmTable)
|
|
(*gPICTImage)->ipalette = NewPalette((*src->pmTable)->ctSize + 1,
|
|
src->pmTable, pmTolerant, 0);
|
|
} else (*gPICTImage)->depth = 1;
|
|
}
|
|
}
|
|
|
|
pascal void InitTextProc(short count, const void *textAddr, Point numer, Point denom)
|
|
{
|
|
#if applec
|
|
#pragma unused(count, textAddr, numer, denom)
|
|
#endif
|
|
gHasObjects = true;
|
|
}
|
|
|
|
pascal void InitLineProc(Point newPt)
|
|
{
|
|
#if applec
|
|
#pragma unused(newPt)
|
|
#endif
|
|
gHasObjects = true;
|
|
}
|
|
|
|
pascal void InitRectProc(GrafVerb verb, const Rect *r)
|
|
{
|
|
#if applec
|
|
#pragma unused(verb, r)
|
|
#endif
|
|
gHasObjects = true;
|
|
}
|
|
|
|
pascal void InitRRectProc(GrafVerb verb, const Rect *r, short ovalWidth,
|
|
short ovalHeight)
|
|
{
|
|
#if applec
|
|
#pragma unused(verb, r, ovalWidth, ovalHeight)
|
|
#endif
|
|
gHasObjects = true;
|
|
}
|
|
|
|
pascal void InitOvalProc(GrafVerb verb, const Rect *r)
|
|
{
|
|
#if applec
|
|
#pragma unused(verb, r)
|
|
#endif
|
|
gHasObjects = true;
|
|
}
|
|
|
|
pascal void InitArcProc(GrafVerb verb, const Rect *r, short startAngle, short arcAngle)
|
|
{
|
|
#if applec
|
|
#pragma unused(verb, r, startAngle, arcAngle)
|
|
#endif
|
|
gHasObjects = true;
|
|
}
|
|
|
|
pascal void InitPolyProc(GrafVerb verb, PolyHandle poly)
|
|
{
|
|
#if applec
|
|
#pragma unused(verb, poly)
|
|
#endif
|
|
gHasObjects = true;
|
|
}
|
|
|
|
pascal void InitRgnProc(GrafVerb verb, RgnHandle rgn)
|
|
{
|
|
#if applec
|
|
#pragma unused(verb, rgn)
|
|
#endif
|
|
gHasObjects = true;
|
|
}
|
|
|
|
//=====================================================================================
|
|
// Dummy QuickDraw bottlenecks to filter out non-PixMaps within PICTs
|
|
//=====================================================================================
|
|
|
|
pascal void DummyBitsProc(PixMap *src, Rect *srcRect, Rect *dstRect, short mode,
|
|
RgnHandle mask)
|
|
{
|
|
#if applec
|
|
#pragma unused(src, srcRect, dstRect, mode, mask)
|
|
#endif
|
|
}
|
|
|
|
pascal void DummyTextProc(short count, const void *textAddr, Point numer, Point denom)
|
|
{
|
|
#if applec
|
|
#pragma unused(count, textAddr, numer, denom)
|
|
#endif
|
|
}
|
|
|
|
pascal void DummyLineProc(Point newPt)
|
|
{
|
|
#if applec
|
|
#pragma unused(newPt)
|
|
#endif
|
|
}
|
|
|
|
pascal void DummyRectProc(GrafVerb verb, const Rect *r)
|
|
{
|
|
#if applec
|
|
#pragma unused(verb, r)
|
|
#endif
|
|
}
|
|
|
|
pascal void DummyRRectProc(GrafVerb verb, const Rect *r, short ovalWidth,
|
|
short ovalHeight)
|
|
{
|
|
#if applec
|
|
#pragma unused(verb, r, ovalWidth, ovalHeight)
|
|
#endif
|
|
}
|
|
|
|
pascal void DummyOvalProc(GrafVerb verb, const Rect *r)
|
|
{
|
|
#if applec
|
|
#pragma unused(verb, r)
|
|
#endif
|
|
}
|
|
|
|
pascal void DummyArcProc(GrafVerb verb, const Rect *r, short startAngle, short arcAngle)
|
|
{
|
|
#if applec
|
|
#pragma unused(verb, r, startAngle, arcAngle)
|
|
#endif
|
|
}
|
|
|
|
pascal void DummyPolyProc(GrafVerb verb, PolyHandle poly)
|
|
{
|
|
#if applec
|
|
#pragma unused(verb, poly)
|
|
#endif
|
|
}
|
|
|
|
pascal void DummyRgnProc(GrafVerb verb, RgnHandle rgn)
|
|
{
|
|
#if applec
|
|
#pragma unused(verb, rgn)
|
|
#endif
|
|
}
|