/* File: LYNXX.c Portions copyright 1990 by Thomas Knoll. LYNXX image acquisition by Scott Wurcer 10/93 (public domain) */ #include #include "LYNXX.h" #include "LYNXXfiles.h" TPermanent gPermanent; short gResult; AcquireRecordPtr gStuff; SFReply reply; short gNextRow; short gNextPlane; /*****************************************************************************/ /* Calls the host's TestAbort function */ Boolean TestAbort (void) { return CallPascalB (gStuff->abortProc); } /*****************************************************************************/ /* Calls the host's UpdateProgress procedure */ void UpdateProgress (done, total) long done; long total; { CallPascal (done, total, gStuff->progressProc); } /*****************************************************************************/ /* Sets the global variables to their default values. */ void InitGlobals (void) { gPermanent.lastRows = NUMROW; /* We only want 192 X 165 grayscale image */ gPermanent.lastCols = NUMCOL; gPermanent.lastMode = acquireModeGrayScale; gPermanent.MyImageHandle = (short_H)NewHandle(NUMROW*NUMCOL*sizeof(short)); } /*****************************************************************************/ /* Centers a dialog template 1/3 of the way down on the main screen. */ void CenterDialog (dt) DialogTHndl dt; #define menuHeight 20 { Rect r; short width; short height; width = screenBits.bounds.right; height = screenBits.bounds.bottom; r = (**dt).boundsRect; OffsetRect (&r, -r.left, -r.top); OffsetRect (&r, (width - r.right) / 2, (height - r.bottom - menuHeight) / 3 + menuHeight); (**dt).boundsRect = r; } #undef menuHeight /*****************************************************************************/ /* Displays the about dialog box for the plug-in module. */ void DoAbout (void) #define dialogID 16000 { short item; DialogPtr dp; DialogTHndl dt; dt = (DialogTHndl) GetResource ('DLOG', dialogID); HNoPurge ((Handle) dt); CenterDialog (dt); dp = GetNewDialog (dialogID, nil, (WindowPtr) -1); ModalDialog (nil, &item); DisposDialog (dp); HPurge ((Handle) dt); } #undef dialogID /*****************************************************************************/ /* Prepare to acquire an image. If the plug-in module needs only a limited amount of memory, it can lower the value of the 'maxData' field. */ void DoPrepare (void) { if (gStuff->maxData > 0x80000) gStuff->maxData = 0x80000; } /*****************************************************************************/ /* UserItem to outline the OK button in a dialog box. */ pascal void OutlineOK (dp, item) DialogPtr dp; short item; { Rect r; Handle h; short itemType; SetUpA4 (); item = OK; GetDItem (dp, item, &itemType, &h, &r); PenNormal (); PenSize (3, 3); InsetRect (&r, -4, -4); FrameRoundRect (&r, 16, 16); PenNormal (); RestoreA4 (); } /*****************************************************************************/ /* Converts a string to a number between 1 and 30000. Returns false if not a valid number or out of range. */ Boolean ConvertString (s, n) Str255 s; short *n; { long x; short j; for (j = 1; j <= Length (s); j++) if (s [j] < '0' || s [j] > '9') return false; StringToNum (s, &x); if (x < 1 || x > 30000) return false; *n = x; return true; } /*****************************************************************************/ /*****************************************************************************/ /* Prompt the user for the image parameters. Returns false if the user cancels. */ Boolean GetParameters (max, min, mode) short *max; short *min; short *mode; #define dialogID 16001 #define hookItem 3 #define maxItem 4 #define minItem 5 { Rect r; Str255 s; Handle h; short item; DialogPtr dp; DialogTHndl dt; short itemType; Handle maxText; Handle minText; dt = (DialogTHndl) GetResource ('DLOG', dialogID); HNoPurge ((Handle) dt); CenterDialog (dt); dp = GetNewDialog (dialogID, nil, (WindowPtr) -1); RememberA4 (); GetDItem (dp, hookItem, &itemType, &h , &r); SetDItem (dp, hookItem, itemType, (Handle) &OutlineOK, &r); GetDItem (dp, maxItem, &itemType, &maxText, &r); GetDItem (dp, minItem, &itemType, &minText, &r); NumToString (*max, s); SetIText (maxText, s); NumToString (*min, s); SetIText (minText, s); SelIText (dp, maxItem, 0, 32767); do { ModalDialog (nil, &item); if (item == OK) { GetIText (maxText, s); if (!ConvertString (s, max)) { SelIText (dp, maxItem, 0, 32767); SysBeep (1); item = 0; } } if (item == OK) { GetIText (minText, s); if (!ConvertString (s, min)) { SelIText (dp, minItem, 0, 32767); SysBeep (1); item = 0; } } if (item == OK) { if ((*min >= *max)||(*max >= 4096)||(*min <= 0)) { SysBeep (1); item = 0; } } } while (item != OK && item != Cancel); DisposDialog (dp); HPurge ((Handle) dt); return item == OK; } #undef dialogID #undef hookItem #undef maxItem #undef minItem /*****************************************************************************/ /* Asks the user and the returns to the calling program the image parmaters. */ void DoStart (void) { short j; short_H TheImage; TheImage = (short_H)gPermanent.MyImageHandle; GetRawImage(TheImage); gStuff->imageSize.v = gPermanent.lastRows; gStuff->imageSize.h = gPermanent.lastCols; gStuff->imageMode = gPermanent.lastMode; if (!GetParameters (&gPermanent.maxImageValue, &gPermanent.minImageValue, &gStuff->imageMode)) { gResult = 1; return; } gPermanent.lastRows = gStuff->imageSize.v; gPermanent.lastCols = gStuff->imageSize.h; gPermanent.lastMode = gStuff->imageMode; gNextRow = 0; gNextPlane = 0; gStuff->depth = 8; gStuff->planes = 1; gStuff->imageHRes = FixRatio (72, 1); gStuff->imageVRes = FixRatio (72, 1); gStuff->data = nil; } /*****************************************************************************/ /* Returns the next hunk of the image to the calling program. */ void DoContinue (void) { Ptr p; short row; short col; long count; long tempvalue; short **TheImage; TheImage = gPermanent.MyImageHandle; if (gStuff->data) { DisposPtr (gStuff->data); gStuff->data = nil; } if (gNextPlane != gStuff->planes) { gStuff->colBytes = 1; gStuff->rowBytes = gStuff->imageSize.h; gStuff->loPlane = gNextPlane; gStuff->hiPlane = gNextPlane; count = gStuff->maxData / gStuff->rowBytes; if (count < 1) { gResult = memFullErr; return; } if (count > gStuff->imageSize.v - gNextRow) count = gStuff->imageSize.v - gNextRow; gStuff->data = NewPtr (count * gStuff->rowBytes); if (!gStuff->data) { gResult = memFullErr; return; } SetRect (&gStuff->theRect, 0, gNextRow, gStuff->imageSize.h, gNextRow + count); p = gStuff->data; for (row = gNextRow; row < gNextRow + count; row++) { if (TestAbort ()) { gResult = 1; return; } UpdateProgress (gNextPlane * ((long) gStuff->imageSize.v) + row, gStuff->planes * ((long) gStuff->imageSize.v)); for (col = 0; col < gStuff->rowBytes; col++) { tempvalue = *((*TheImage)+NUMCOL*row+col); /* pointer arithmatic is cool */ *(p++) = (tempvalue - gPermanent.minImageValue)*255/(gPermanent.maxImageValue - gPermanent.minImageValue); } } gNextRow = gNextRow + count; if (gNextRow == gStuff->imageSize.v) { gNextRow = 0; gNextPlane = gNextPlane + 1; } } } /*****************************************************************************/ /* This routine will always be called if DoStart does not return an error (even if DoContinue returns an error or the user aborts the operation). This allows the module to perform any needed cleanup. */ void DoFinish (void) { if (gStuff->data) { DisposPtr (gStuff->data); gStuff->data = nil; DisposHandle(gPermanent.MyImageHandle); } } /*****************************************************************************/ /* Main dispatching routine. Initializes and sets up the global variables, and performs the operation specified by the selector. */ pascal void main (selector, stuff, data, result) short selector; AcquireRecordPtr stuff; long *data; short *result; { Boolean firstTime; /* Allow access to global variables */ RememberA0 (); SetUpA4 (); /* Copy the current quickdraw globals into the plug-in local copy */ asm { MOVE.L (A5),A0 ; Get address of real quickdraw globals SUB.L #126,A0 ; Move to start LEA randSeed,A1 ; Get address of local copy MOVE.W #64,D0 ; Globals are 65 words long @1 MOVE.W (A0)+,(A1)+ ; Copy a word DBF D0,@1 ; Move to next word } /* See if this is the first time called */ if (!*data) { /* Allocate a handle to hold permanent values */ *data = (long) NewHandle ((long) sizeof (TPermanent)); if (!*data) { *result = memFullErr; RestoreA4 (); return; } /* Initialize the permanent values */ InitGlobals (); } /* Else restore permanent values */ else BlockMove (*((Handle) *data), (Ptr) &gPermanent, (long) sizeof (TPermanent)); /* Perform the requested operation */ gStuff = stuff; gResult = noErr; switch (selector) { case acquireSelectorAbout: DoAbout (); break; case acquireSelectorPrepare: DoPrepare (); break; case acquireSelectorStart: DoStart (); break; case acquireSelectorContinue: DoContinue (); break; case acquireSelectorFinish: DoFinish (); break; default: gResult = acquireBadParameters; } *result = gResult; /* Save permanent values */ BlockMove ((Ptr) &gPermanent, *((Handle) *data), (long) sizeof (TPermanent)); /* Restore the application's A4 register */ RestoreA4 (); }