/* File: DummyScan.c Copyright 1990 by Thomas Knoll. Copyright 1993 by Adobe Systems, Inc. C source file for DummyScan example. */ #include #include #include #include #include #include #include #include #include #include "PITypes.h" #include "PIGeneral.h" #include "PIAcquire.h" #include "DialogUtilities.h" #include "PIUtilities.h" #ifdef THINK_C #define ENTRYPOINT main #endif /*****************************************************************************/ typedef struct Globals { short result; AcquireRecord *stuff; short lastImages; short lastRows; short lastCols; short lastMode; short nextImage; short nextRow; short nextPlane; short chunkRows; long rowBytes; long done; long total; BufferID buffer; Boolean postProcessing; } Globals, *GPtr, **GHdl; #define gResult ((**globals).result) #define gStuff ((**globals).stuff) #define gLastImages ((**globals).lastImages) #define gLastRows ((**globals).lastRows) #define gLastCols ((**globals).lastCols) #define gLastMode ((**globals).lastMode) #define gNextImage ((**globals).nextImage) #define gNextRow ((**globals).nextRow) #define gNextPlane ((**globals).nextPlane) #define gChunkRows ((**globals).chunkRows) #define gRowBytes ((**globals).rowBytes) #define gDone ((**globals).done) #define gTotal ((**globals).total) #define gBuffer ((**globals).buffer) #define gPostProcessing ((**globals).postProcessing) /*****************************************************************************/ void InitGlobals (GHdl globals); void DoAbout (GHdl globals); void DoPrepare (GHdl globals); void DoStart (GHdl globals); void DoContinue (GHdl globals); void DoFinish (GHdl globals); /*****************************************************************************/ /* All calls to the plug-in module come through this routine. It must be placed first in the resource. To achieve this, most development systems require that this be the first routine in the source. */ pascal void ENTRYPOINT (short selector, AcquireRecord *stuff, long *data, short *result) { GHdl globals; if (!*data) { *data = (long) NewHandle (sizeof (Globals)); if (!*data) { *result = memFullErr; return; } InitGlobals ((GHdl) *data); } globals = (GHdl) *data; gStuff = stuff; gResult = noErr; switch (selector) { case acquireSelectorAbout: DoAbout (globals); break; case acquireSelectorPrepare: DoPrepare (globals); break; case acquireSelectorStart: DoStart (globals); break; case acquireSelectorContinue: DoContinue (globals); break; case acquireSelectorFinish: DoFinish (globals); break; default: gResult = acquireBadParameters; } *result = gResult; } /*****************************************************************************/ void InitGlobals (GHdl globals) { gLastImages = 1; gLastRows = 256; gLastCols = 256; gLastMode = plugInModeRGBColor; gBuffer = 0; } /*****************************************************************************/ /* Displays the about dialog box for the plug-in module. */ void DoAbout (GHdl globals) { #pragma unused (globals) #define dialogID 16000 ShowAbout (dialogID); #undef dialogID } /*****************************************************************************/ /* Prepare to acquire an image. If the plug-in module needs a large amount of buffer memory, this routine should set the maxData field to the number of bytes required. Since we are going to use the bufferProcs, we simply set maxData to zero. */ void DoPrepare (GHdl globals) { gStuff->maxData = 0; if (!WarnBufferProcsAvailable ()) gResult = 1; /* Prepare is called before we bring up the dialog but not on subsequent acquires so this is a good place to detect the beginning of an acquisition sequence. */ gNextImage = 0; } /*****************************************************************************/ Boolean GetParameters (GHdl globals); /*****************************************************************************/ void DoStart (GHdl globals) { short j; /* Insist on having the buffer procs. if (!WarnBufferProcsAvailable ()) { gResult = 1; return; } /* If this is the first image in a sequence, then we need to query the user for the parameters. We could also write this so that it queries on each iteration. */ if (gNextImage == 0) { if (GetParameters (globals)) ++gNextImage; /* Advance to the first image. */ else { gResult = 1; return; } } /* Fill in the parameters for the document. */ gStuff->imageSize.v = gLastRows; gStuff->imageSize.h = gLastCols; gStuff->imageMode = gLastMode; if (gStuff->imageMode == plugInModeBitmap) gStuff->depth = 1; else gStuff->depth = 8; if (gStuff->imageMode == plugInModeRGBColor) gStuff->planes = 3; else gStuff->planes = 1; if (gStuff->depth == 1) { gStuff->imageHRes = FixRatio (300, 1); gStuff->imageVRes = FixRatio (300, 1); } else { gStuff->imageHRes = FixRatio (72, 1); gStuff->imageVRes = FixRatio (72, 1); } if (gStuff->imageMode == plugInModeIndexedColor) for (j = 0; j < 256; j++) { gStuff->redLUT [j] = j; gStuff->greenLUT [j] = 255 - j; gStuff->blueLUT [j] = j; } gStuff->data = nil; gBuffer = 0; gDone = 0; gTotal = (long) gStuff->imageSize.v * (long) gStuff->planes; /* Scale total for post-processing. */ if (gStuff->imageMode != plugInModeBitmap && gStuff->canReadBack) gTotal *= 3; } /*****************************************************************************/ void DoContinue (GHdl globals) { long bottom; /* Allocate the buffer and start acquisition. */ if (!gBuffer) { int16 actualHeight; BufferID buffer; if (gStuff->depth == 8) gRowBytes = gStuff->imageSize.h; else gRowBytes = (gStuff->imageSize.h + 7) >> 3; gResult = AllocateStripBuffer (gRowBytes, 1, gStuff->imageSize.v, 1, &actualHeight, &buffer); gChunkRows = actualHeight; gBuffer = buffer; if (gResult != noErr) return; gStuff->data = LockBuffer (gBuffer, FALSE); gPostProcessing = FALSE; gStuff->wantReadBack = FALSE; gNextPlane = 0; gNextRow = 0; } /* Determine whether to advance to the next plane. */ if (gNextRow >= gStuff->imageSize.v) { ++gNextPlane; gNextRow = 0; } /* Determine whether to advance to the next stage. */ if (gNextPlane >= gStuff->planes) { if (gPostProcessing || gStuff->imageMode == plugInModeBitmap || !gStuff->canReadBack) { gStuff->data = nil; SetRect (&gStuff->theRect, 0, 0, 0, 0); return; } else { gPostProcessing = TRUE; gNextPlane = 0; gNextRow = 0; } } /* Set up the rectangle to process. */ gStuff->loPlane = gNextPlane; gStuff->hiPlane = gNextPlane; bottom = gNextRow + (long) gChunkRows; if (bottom > gStuff->imageSize.v) bottom = gStuff->imageSize.v; gStuff->theRect.top = gNextRow; gStuff->theRect.bottom = bottom; gStuff->theRect.left = 0; gStuff->theRect.right = gStuff->imageSize.v; gStuff->rowBytes = gRowBytes; gStuff->colBytes = 1; /* If we are not post-processing, then store the data. */ if (!gPostProcessing) { int16 row; Ptr p; for (row = gStuff->theRect.top, p = gStuff->data; row < gStuff->theRect.bottom; ++row, p += gRowBytes) { int16 col; Ptr q; if (TestAbort ()) { gResult = 1; return; } UpdateProgress (gDone++, gTotal); for (col = 0, q = p; col < gRowBytes; ++col, ++q) { if (gStuff->depth == 1) *q = 0xFF << (row & 7); else if (gStuff->planes == 1) *q = row + col; else if (gNextPlane == 0) *q = col; else if (gNextPlane == 1) *q = row; else *q = row + col; } } gNextRow = gStuff->theRect.bottom; } /* Else if the last operation was not a read, then read. */ else if (!gStuff->wantReadBack) { /* We know that we can read back because we only set gPostProcessing true if gStuff->canReadBack is true. */ gStuff->wantReadBack = TRUE; gDone += gStuff->theRect.bottom - gStuff->theRect.top; } /* Otherwise, do the post-processing. */ else { int16 row; Ptr p; for (row = gStuff->theRect.top, p = gStuff->data; row < gStuff->theRect.bottom; ++row, p += gRowBytes) { int16 col; Ptr q; if (TestAbort ()) { gResult = 1; return; } UpdateProgress (gDone++, gTotal); for (col = gStuff->theRect.left, q = p; col < gStuff->theRect.right; ++col, ++q) { short value = *q & 0x00FF; value /= gNextImage; *q = value; } } gStuff->wantReadBack = FALSE; gNextRow = gStuff->theRect.bottom; } } /*****************************************************************************/ /* 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 (GHdl globals) { if (gBuffer) FreeBuffer (gBuffer); gBuffer = 0; ++gNextImage; gStuff->acquireAgain = gNextImage <= gLastImages; } /*****************************************************************************/ /* Prompt the user for the image parameters. Returns false if the user cancels. */ Boolean GetParameters (GHdl globals) { #define dialogID 16001 #define hookItem 3 #define imagesItem 4 #define rowsItem 5 #define colsItem 6 #define firstModeItem 7 #define lastModeItem 10 DialogPtr dp; DialogTHndl dt; short item; long xImages = gLastImages; long xRows = gLastRows; long xCols = gLastCols; short modeItem = gLastMode - plugInModeBitmap + firstModeItem; dt = (DialogTHndl) GetResource ('DLOG', dialogID); HNoPurge ((Handle) dt); CenterDialog (dt); SetUpMoveableModal (dt, gStuff->hostSig); dp = GetNewDialog (dialogID, nil, (WindowPtr) -1); SetOutlineOKHook (dp, hookItem); StuffNumber (dp, imagesItem, xImages); StuffNumber (dp, rowsItem, xRows); StuffNumber (dp, colsItem, xCols); SetRadioGroupState (dp, firstModeItem, lastModeItem, modeItem); SelectTextItem (dp, imagesItem); do { MoveableModalDialog (dp, gStuff->processEvent, nil, &item); if (item >= firstModeItem && item <= lastModeItem) SetRadioGroupState (dp, firstModeItem, lastModeItem, item); else if (item == ok) { modeItem = GetRadioGroupState (dp, firstModeItem, lastModeItem); if (modeItem == 0 || !FetchNumber (dp, imagesItem, 1, 10, &xImages) || !FetchNumber (dp, rowsItem, 1, 30000, &xRows) || !FetchNumber (dp, colsItem, 1, 30000, &xCols)) { item = 0; } } } while (item != ok && item != cancel); DisposDialog (dp); HPurge ((Handle) dt); if (item == ok) { gLastImages = (short) xImages; gLastRows = (short) xRows; gLastCols = (short) xCols; gLastMode = modeItem - firstModeItem + plugInModeBitmap; } return item == ok; #undef dialogID #undef hookItem #undef rowsItem #undef colsItem #undef firstModeItem #undef lastModeItem } /*****************************************************************************/