/************************************************/ /* */ /* Filter.c - Image Filter routines. */ /* */ /* Revised 7/6/94 by RMR */ /* */ /************************************************/ #include #include "Snakes.h" /************************************************/ /* Filter "Undo" Routine */ /************************************************/ void UndoFilter(void) { short x, y; ValPtr sptr, dptr; if (!gTempArray.valid) { SysBeep(10); return; } SetCursor(*gWatchCursor); sptr = (ValPtr)LockArray(&gTempArray); dptr = (ValPtr)LockArray(&gPictArray); /* Transfer temp array to picture array. */ for (y = 0; y < gPictHeight; y++) for (x = 0; x < gPictWidth; x++) *dptr++ = *sptr++; UnlockArray(&gPictArray); UnlockArray(&gTempArray); CopyArray2GWorld(&gPictArray, gPictWorld, &gPictRect); gPictArray.valid = true; gHistArray.valid = false; KickPictWindow(); SetCursor(&arrow); } /************************************************/ /* Smoothing Filter Routine */ /************************************************/ void DoSmoothingFilter(void) { short ksize, koffs, sum, scale, x, y, j, k; ValPtr sptr, dptr, pptr; if (!gPictArray.valid) DoError("\pPict Array not valid!"); DisplayString("\pSmoothing Filter.\r"); InitProgressBar("\pSmoothing Filter."); sptr = (ValPtr)LockArray(&gPictArray); dptr = (ValPtr)LockArray(&gTempArray); /* Transfer picture array to temp array. */ for (y = 0; y < gPictHeight; y++) for (x = 0; x < gPictWidth; x++) *dptr++ = *sptr++; gTempArray.valid = true; /* Filter from temp array back to filter array. */ sptr = (ValPtr)LockArray(&gTempArray); dptr = (ValPtr)LockArray(&gPictArray); switch (gGlobalParams->smoothKernSize) { case i9x9: ksize = 9; break; case i7x7: ksize = 7; break; case i5x5: ksize = 5; break; default: ksize = 3; } koffs = (ksize - 1) / 2; scale = ksize * ksize; for (y = 0; y < gPictHeight; y++) { if (y < koffs || y >= gPictHeight - koffs) for (x = 0; x < gPictWidth; x++, sptr++, dptr++) *dptr = *sptr; else for (x = 0; x < gPictWidth; x++, sptr++, dptr++) { if (x < koffs || x >= gPictWidth - koffs) *dptr = *sptr; else { sum = 0; for (k = 0; k < ksize; k++) for (j = 0; j < ksize; j++) { pptr = sptr + (k - koffs) * gPictWidth + (j - koffs); sum += (short)(*pptr); } *dptr = (Value)(sum / scale); } } if (y % UpdateLines == 0) { DrawProgressBar(y, gPictHeight); SkelDoEvents(everyEvent); if (gTerminateFlag) break; } } UnlockArray(&gPictArray); UnlockArray(&gTempArray); CopyArray2GWorld(&gPictArray, gPictWorld, &gPictRect); KillProgressBar(); gHistArray.valid = false; KickPictWindow(); } /************************************************/ /* Noise (Median) Filter Routines */ /************************************************/ static void SortNine(ValPtr v) { Value temp; short i, j; for (i = 0; i < 8; i++) for (j = i + 1; j < 9; j++) if (v[j] < v[i]) { temp = v[j]; v[j] = v[i]; v[i] = temp; } } void DoNoiseFilter(void) { short x, y; ValPtr sptr, dptr; Value v[9]; if (!gPictArray.valid) DoError("\pPict Array not valid!"); DisplayString("\pNoise (Median) Filter.\r"); InitProgressBar("\pNoise (Median) Filter."); sptr = (ValPtr)LockArray(&gPictArray); dptr = (ValPtr)LockArray(&gTempArray); /* Transfer picture array to temp array... */ for (y = 0; y < gPictHeight; y++) for (x = 0; x < gPictWidth; x++) *dptr++ = *sptr++; gTempArray.valid = true; /* Filter from temp array back to filter array... */ sptr = (ValPtr)LockArray(&gTempArray); dptr = (ValPtr)LockArray(&gPictArray); for (y = 0; y < gPictHeight; y++) { if (y < 1 || y >= gPictHeight - 1) for (x = 0; x < gPictWidth; x++, sptr++, dptr++) *dptr = *sptr; else for (x = 0; x < gPictWidth; x++, sptr++, dptr++) { if (x < 1 || x >= gPictWidth - 1) *dptr = *sptr; else { v[0] = *(sptr - gPictWidth - 1); v[1] = *(sptr - gPictWidth); v[2] = *(sptr - gPictWidth + 1); v[3] = *(sptr - 1); v[4] = *(sptr); v[5] = *(sptr + 1); v[6] = *(sptr + gPictWidth - 1); v[7] = *(sptr + gPictWidth); v[8] = *(sptr + gPictWidth + 1); SortNine(v); *dptr = v[4]; } } if (y % UpdateLines == 0) { DrawProgressBar(y, gPictHeight); SkelDoEvents(everyEvent); if (gTerminateFlag) break; } } UnlockArray(&gPictArray); UnlockArray(&gTempArray); CopyArray2GWorld(&gPictArray, gPictWorld, &gPictRect); KillProgressBar(); gHistArray.valid = false; KickPictWindow(); } /************************************************/ /* Histogram & Equalizing Routines */ /************************************************/ void DoHistogram(void) { short x, y; ValPtr sptr; long *hist; if (!gPictArray.valid) DoError("\pPict Array not valid!"); DisplayString("\pPerforming Histogram.\r"); sptr = (ValPtr)LockArray(&gPictArray); hist = (long *)LockArray(&gHistArray); for (y = 0; y < 256; y++) hist[y] = 0L; for (y = 0; y < gPictHeight; y++) for (x = 0; x < gPictWidth; x++) hist[(*sptr++) & 0xff] += 1L; gHistMax = 0L; for (y = 0; y < 256; y++) if (hist[y] > gHistMax) gHistMax = hist[y]; UnlockArray(&gHistArray); UnlockArray(&gPictArray); gHistArray.valid = true; } void DoEqualizeFilter(void) { short x, y; long *hist, sum, bigN; ValPtr sptr, dptr; Value map[256]; if (!gPictArray.valid) DoError("\pPict Array not valid!"); DisplayString("\pComputing equalization map.\r"); SetCursor(*gWatchCursor); if (!gHistArray.valid) DoHistogram(); bigN = (long)gPictHeight * (long)gPictWidth; hist = (long *)LockArray(&gHistArray); for (sum = 0L, x = 0; x < 255; x++) { map[x] = (Value)((sum * 255) / bigN); sum += hist[x]; } UnlockArray(&gHistArray); DisplayString("\pHistogram Equalize Filter.\r"); sptr = (ValPtr)LockArray(&gPictArray); dptr = (ValPtr)LockArray(&gTempArray); /* Transfer picture array to temp array... */ for (y = 0; y < gPictHeight; y++) for (x = 0; x < gPictWidth; x++) *dptr++ = *sptr++; gTempArray.valid = true; /* Filter from temp array back to filter array... */ sptr = (ValPtr)LockArray(&gTempArray); dptr = (ValPtr)LockArray(&gPictArray); for (y = 0; y < gPictHeight; y++) for (x = 0; x < gPictWidth; x++, sptr++, dptr++) *dptr = map[*sptr]; UnlockArray(&gPictArray); UnlockArray(&gTempArray); CopyArray2GWorld(&gPictArray, gPictWorld, &gPictRect); gHistArray.valid = false; KickPictWindow(); SetCursor(&arrow); } /************************************************/ /* Histogram Dialog Routines */ /************************************************/ void DrawHistDialog(void) { GrafPtr temp; Rect r; short i; long *hist, num; if (!gHistArray.valid) DoHistogram(); hist = (long *)LockArray(&gHistArray); GetPort(&temp); SetPort(gHistDialog); RGBForeColor(&kBlack); RGBBackColor(&kWhite); SkelGetDlogRect(gHistDialog, iHistRect, &r); EraseRect(&r); FrameRect(&r); RGBForeColor(&kRed); for (i = 1; i <= 256; i++) { num = (hist[i] * 100L) / gHistMax; if (num > 100L) num = 100L; if (num < 0) num = 0; MoveTo(r.left + i, r.bottom - 2); LineTo(r.left + i, r.bottom - 2 - (short)num); } RGBForeColor(&kBlack); SkelDrawButtonOutline(SkelGetDlogCtl(gHistDialog, iHistClose)); UnlockArray(&gHistArray); gHistArray.valid = true; SetPort(temp); } static pascal Boolean HistDlogFilter(DialogPtr dlog, EventRecord *evt, short *item) { if (dlog == gHistDialog && evt->what == updateEvt) { DrawHistDialog(); return false; } return SkelDlogMapKeyToButton(dlog, evt, item, iHistClose, iHistClose); } static pascal void HistDlogSelect(DialogPtr dlog, short item) { if (dlog == gHistDialog) { switch (item) { case iHistClose: CloseHistDialog(); return; } DrawHistDialog(); } } static pascal void HistDlogClobber(void) { DisposeDialog(gHistDialog); } Boolean InitHistDialog(void) { return SkelDialog(gHistDialog, HistDlogFilter, HistDlogSelect, nil, HistDlogClobber); } void OpenHistDialog(void) { ShowWindow(gHistDialog); SelectWindow(gHistDialog); DrawHistDialog(); } void CloseHistDialog(void) { if (((WindowPeek)gHistDialog)->visible) { HideWindow(gHistDialog); gModelStatus = sIdle; } AdjustMenus(true); } /************************************************/ /* Specular Reflection Fill Routine */ /************************************************/ void DoFillFilter(void) { short x, y, sum, neighbors; ValPtr sptr, dptr; Boolean done; if (!gPictArray.valid) DoError("\pPict Array not valid!"); if (!((WindowPeek)gThrsWindow)->visible) OpenThrsWindow(); SetCursor(*gWatchCursor); DisplayString("\pSpecular Reflection Fill.\r"); /* Transfer picture array to temp array... */ sptr = (ValPtr)LockArray(&gPictArray); dptr = (ValPtr)LockArray(&gTempArray); for (y = 0; y < gPictHeight; y++) for (x = 0; x < gPictWidth; x++) *dptr++ = *sptr++; gTempArray.valid = true; UnlockArray(&gTempArray); UnlockArray(&gPictArray); /* Perform operation on picture array... */ for (done = false; !done; ) { sptr = (ValPtr)LockArray(&gThrsArray); dptr = (ValPtr)LockArray(&gPictArray); for (y = 0; y < gPictHeight; y++) for (x = 0; x < gPictWidth; x++, sptr++, dptr++) { if (*sptr != MINVALUE) { sum = neighbors = 0; if (x > 0 && y > 0 && *(sptr-gPictWidth-1) == MINVALUE) { sum += *(dptr-gPictWidth-1); neighbors++; } if (x > 0 && *(sptr-1) == MINVALUE) { sum += *(dptr-1); neighbors++; } if (x > 0 && y < gPictHeight-1 && *(sptr+gPictWidth-1) == MINVALUE) { sum += *(dptr+gPictWidth-1); neighbors++; } if (y > 0 && *(sptr-gPictWidth) == MINVALUE) { sum += *(dptr-gPictWidth); neighbors++; } if (y < gPictHeight-1 && *(sptr+gPictWidth) == MINVALUE) { sum += *(dptr+gPictWidth); neighbors++; } if (x < gPictWidth-1 && y > 0 && *(sptr-gPictWidth+1) == MINVALUE) { sum += *(dptr-gPictWidth+1); neighbors++; } if (x < gPictWidth-1 && *(sptr+1) == MINVALUE) { sum += *(dptr+1); neighbors++; } if (x < gPictWidth-1 && y < gPictHeight-1 && *(sptr+gPictWidth+1) == MINVALUE) { sum += *(dptr+gPictWidth+1); neighbors++; } if (neighbors > 0) { *dptr = sum / neighbors; *sptr = MIDVALUE; } } } done = true; sptr = (ValPtr)LockArray(&gThrsArray); for (y = 0; y < gPictHeight; y++) for (x = 0; x < gPictWidth; x++, sptr++) if (*sptr == MIDVALUE) { *sptr = MINVALUE; done = false; } CopyArray2GWorld(&gPictArray, gPictWorld, &gPictRect); SetPort(gPictWindow); ShowPictWindow(); CopyArray2GWorld(&gThrsArray, gThrsWorld, &gPictRect); ShowThrsWindow(); SkelDoEvents(everyEvent); } UnlockArray(&gPictArray); UnlockArray(&gThrsArray); CopyArray2GWorld(&gPictArray, gPictWorld, &gPictRect); gHistArray.valid = false; KickPictWindow(); SetCursor(&arrow); } /************************************************/ /* Expand Threshold Blob Routine */ /************************************************/ void ExpandBlobs(void) { short x, y; ValPtr sptr; if (!gPictArray.valid) DoError("\pPict Array not valid!"); if (!((WindowPeek)gThrsWindow)->visible) OpenThrsWindow(); SetCursor(*gWatchCursor); DisplayString("\pExpand Threshold Blobs.\r"); sptr = (ValPtr)LockArray(&gThrsArray); for (y = 0; y < gPictHeight; y++) for (x = 0; x < gPictWidth; x++, sptr++) if (*sptr == MINVALUE) { if (x > 0 && y > 0 && *(sptr-gPictWidth-1) == MAXVALUE) *sptr = MIDVALUE; if (x > 0 && *(sptr-1) == MAXVALUE) *sptr = MIDVALUE; if (x > 0 && y < gPictHeight-1 && *(sptr+gPictWidth-1) == MAXVALUE) *sptr = MIDVALUE; if (y > 0 && *(sptr-gPictWidth) == MAXVALUE) *sptr = MIDVALUE; if (y < gPictHeight-1 && *(sptr+gPictWidth) == MAXVALUE) *sptr = MIDVALUE; if (x < gPictWidth-1 && y > 0 && *(sptr-gPictWidth+1) == MAXVALUE) *sptr = MIDVALUE; if (x < gPictWidth-1 && *(sptr+1) == MAXVALUE) *sptr = MIDVALUE; if (x < gPictWidth-1 && y < gPictHeight-1 && *(sptr+gPictWidth+1) == MAXVALUE) *sptr = MIDVALUE; } sptr = (ValPtr)LockArray(&gThrsArray); for (y = 0; y < gPictHeight; y++) for (x = 0; x < gPictWidth; x++, sptr++) if (*sptr == MIDVALUE) *sptr = MAXVALUE; CopyArray2GWorld(&gThrsArray, gThrsWorld, &gPictRect); ShowThrsWindow(); UnlockArray(&gThrsArray); SetCursor(&arrow); } /************************************************/ /* Gradient Filter Routines */ /************************************************/ int H9x9Sobel[81] = { -1, -2, -3, -5, 0, 5, 3, 2, 1, -2, -3, -5, -8, 0, 8, 5, 3, 2, -3, -5, -8, -13, 0, 13, 8, 5, 3, -5, -8, -13, -21, 0, 21, 13, 8, 5, -8, -13, -21, -34, 0, 34, 21, 13, 8, -5, -8, -13, -21, 0, 21, 13, 8, 5, -3, -5, -8, -13, 0, 13, 8, 5, 3, -2, -3, -5, -8, 0, 8, 5, 3, 2, -1, -2, -3, -5, 0, 5, 3, 2, 1 }; int V9x9Sobel[81] = { -1, -2, -3, -5, -8, -5, -3, -2, -1, -2, -3, -5, -8, -13, -8, -5, -3, -2, -3, -5, -8, -13, -21, -13, -8, -5, -3, -5, -8, -13, -21, -34, -21, -13, -8, -5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 8, 13, 21, 34, 21, 13, 8, 5, 3, 5, 8, 13, 21, 13, 8, 5, 3, 2, 3, 5, 8, 13, 8, 5, 3, 2, 1, 2, 3, 5, 8, 5, 3, 2, 1 }; int H7x7Sobel[49] = { -1, -2, -3, 0, 3, 2, 1, -2, -3, -5, 0, 5, 3, 2, -3, -5, -8, 0, 8, 5, 3, -5, -8, -13, 0, 13, 8, 5, -3, -5, -8, 0, 8, 5, 3, -2, -3, -5, 0, 5, 3, 2, -1, -2, -3, 0, 3, 2, 1 }; int V7x7Sobel[49] = { -1, -2, -3, -5, -3, -2, -1, -2, -3, -5, -8, -5, -3, -2, -3, -5, -8, -13, -8, -5, -3, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 13, 8, 5, 3, 2, 3, 5, 8, 5, 3, 2, 1, 2, 3, 5, 3, 2, 1 }; int H5x5Sobel[25] = { -1, -2, 0, 2, 1, -2, -3, 0, 3, 2, -3, -5, 0, 5, 3, -2, -3, 0, 3, 2, -1, -2, 0, 2, 1 }; int V5x5Sobel[25] = { -1, -2, -3, -2, -1, -2, -3, -5, -3, -2, 0, 0, 0, 0, 0, 2, 3, 5, 3, 2, 1, 2, 3, 2, 1 }; int H3x3Sobel[9] = { -1, 0, 1, -2, 0, 2, -1, -0, 1 }; int V3x3Sobel[9] = { -1, -2, -1, 0, 0, 0, 1, 2, 1 }; static void DoGradient(Array *src, Array *dest) { short ksize, koffs, x, y, j, k; ValPtr sptr, dptr, pptr; int *hkern, *vkern, hsum, vsum; long hsumsq, vsumsq, magn; double scale; if (!gPictArray.valid) DoError("\pPict Array not valid!"); InitProgressBar("\pComputing Gradient."); sptr = (ValPtr)LockArray(src); dptr = (ValPtr)LockArray(dest); switch (gGlobalParams->smoothKernSize) { case i9x9: ksize = 9; scale = (double)gGlobalParams->gradientScale / 40447.0; hkern = H9x9Sobel; vkern = V9x9Sobel; break; case i7x7: ksize = 7; scale = (double)gGlobalParams->gradientScale / 12728.0; hkern = H7x7Sobel; vkern = V7x7Sobel; break; case i5x5: ksize = 5; scale = (double)gGlobalParams->gradientScale / 3394.0; hkern = H5x5Sobel; vkern = V5x5Sobel; break; default: ksize = 3; scale = (double)gGlobalParams->gradientScale / 566.0; hkern = H3x3Sobel; vkern = V3x3Sobel; } koffs = (ksize - 1) / 2; for (y = 0; y < gPictHeight; y++) { if (y < koffs || y >= gPictHeight - koffs) for (x = 0; x < gPictWidth; x++, sptr++, dptr++) *dptr = 0; else for (x = 0; x < gPictWidth; x++, sptr++, dptr++) { if (x < koffs || x >= gPictWidth - koffs) *dptr = 0; else { hsum = vsum = 0; for (k = 0; k < ksize; k++) for (j = 0; j < ksize; j++) { pptr = sptr + (k - koffs) * gPictWidth + (j - koffs); hsum += hkern[ksize * k + j] * (int)(*pptr); vsum += vkern[ksize * k + j] * (int)(*pptr); } hsumsq = (long)hsum * (long)hsum; vsumsq = (long)vsum * (long)vsum; magn = (long)(sqrt((double)(hsumsq + vsumsq)) * scale); if (magn > (long)MAXVALUE) *dptr = MAXVALUE; else *dptr = (Value)(magn); } } if (y % UpdateLines == 0) { DrawProgressBar(y, gPictHeight); SkelDoEvents(everyEvent); if (gTerminateFlag) break; } } UnlockArray(src); UnlockArray(dest); KillProgressBar(); gGradArray.valid = true; } void ShowGradWindow(void) { GrafPtr temp; GetPort(&temp); SetPort(gGradWindow); CopyGWorld2Window(gGradWorld, gGradWindow, &gPictRect); if (gOptions->showGradientModels) { DrawModel(gRefModel, gGradWindow); DrawModel(gTestModel, gGradWindow); } SetPort(temp); } static pascal void GradMouse(Point where, long when, short modifiers) { if (gOptions->showGradientModels) { PictPoint(where, gGradWindow); KickPictWindow(); } } static pascal void GradKey(short c, short code, short modifiers) { if (gOptions->showGradientModels) { if (((WindowPeek)gExecDialog)->visible) { if (c == 0x1b) CloseExecDialog(); else if (c == ' ' && gModelStatus == sPaused) ExecuteOneCycle(); } else if (((WindowPeek)gPlaceDialog)->visible) { switch (c) { case '\n': case '\r': SetPlaceDone(); DrawPlaceDialog(); BuildSpringsFromParticles(gRefModel); BuildSpringsFromParticles(gTestModel); KickPictWindow(); break; case 0x08: case 0x7f: PlaceDelOne(); DrawPlaceDialog(); BuildSpringsFromParticles(gRefModel); BuildSpringsFromParticles(gTestModel); KickPictWindow(); break; case ' ': switch (gModelStatus) { case sPlaceRefA: gModelStatus = sPlaceRefB; break; case sPlaceRefB: gModelStatus = sPlaceTestA; break; case sPlaceTestA: gModelStatus = sPlaceTestB; break; case sPlaceTestB: gModelStatus = sPlaceRefA; } DrawPlaceDialog(); break; case 0x1b: ClosePlaceDialog(); } } else SysBeep(10); } } static pascal void GradUpdate(Boolean resized) { ShowGradWindow(); } static pascal void GradActivate(Boolean active) { if (active) ShowGradWindow(); AdjustMenus(true); } void CloseGradWindow(void) { gModelStatus = sIdle; CloseExecDialog(); if (((WindowPeek)gGradWindow)->visible) { HideWindow(gGradWindow); DisposeGWorld(gGradWorld); CloseArray(&gGradArray); } if (((WindowPeek)gExecDialog)->visible) CloseExecDialog(); AdjustMenus(true); } static pascal void GradClose(void) { CloseGradWindow(); } static pascal void GradClobber(void) { DisposeWindow(gGradWindow); } static pascal void GradIdle(void) { if (gOptions->showGradientModels && gModelStatus == sRunning) ExecuteOneCycle(); } Boolean InitGradWindow(void) { return SkelWindow(gGradWindow, GradMouse, GradKey, GradUpdate, GradActivate, GradClose, GradClobber, GradIdle, true); } void OpenGradWindow(void) { DisplayString("\pComputing Gradient.\r"); OpenArray(&gGradArray, sizeof(Value), (Size)gPictHeight * gPictWidth); DoGradient(&gPictArray, &gGradArray); if (gTerminateFlag) { CloseArray(&gGradArray); DisplayString("\pCancelled!\r\r"); return; } if (NewGWorld(&gGradWorld, 8, &gPictRect, GetCTable(GRAY_RAMP + 8), nil, 0) != noErr) DoError( "\pCannot create new gradient GWorld!"); CopyArray2GWorld(&gGradArray, gGradWorld, &gPictRect); SetPort(gGradWindow); PortSize(gPictWidth, gPictHeight); SetPort(gGradWindow); ClipRect(&gPictRect); ShowWindow(gGradWindow); SelectWindow(gGradWindow); ShowGradWindow(); } /************************************************/ /* Threshold Filter Routines */ /************************************************/ static void DoThreshold(Array *src, Array *dest, Value percent) { short x, y; Value thresh; ValPtr sptr, dptr; if (!gPictArray.valid) DoError("\pPict Array not valid!"); InitProgressBar("\pComputing Threshold."); thresh = (Value)(((int)percent * MAXVALUE) / 100 ); sptr = (ValPtr)LockArray(src); dptr = (ValPtr)LockArray(dest); for (y = 0; y < gPictHeight; y++) { for (x = 0; x < gPictWidth; x++, sptr++, dptr++) *dptr = (*sptr > thresh) ? MINVALUE : MAXVALUE; if (y % UpdateLines == 0) { DrawProgressBar(y, gPictHeight); SkelDoEvents(everyEvent); if (gTerminateFlag) break; } } UnlockArray(src); UnlockArray(dest); KillProgressBar(); gThrsArray.valid = true; } void ShowThrsWindow(void) { CopyGWorld2Window(gThrsWorld, gThrsWindow, &gPictRect); } static pascal void ThrsUpdate(Boolean resized) { ShowThrsWindow(); } static pascal void ThrsActivate(Boolean active) { if (active) ShowThrsWindow(); AdjustMenus(true); } void CloseThrsWindow(void) { if (((WindowPeek)gThrsWindow)->visible) { HideWindow(gThrsWindow); DisposeGWorld(gThrsWorld); CloseArray(&gThrsArray); } } static pascal void ThrsClose(void) { CloseThrsWindow(); } static pascal void ThrsClobber(void) { DisposeWindow(gThrsWindow); } Boolean InitThrsWindow(void) { return SkelWindow(gThrsWindow, nil, nil, ThrsUpdate, ThrsActivate, ThrsClose, ThrsClobber, nil, true); } void OpenThrsWindow(void) { DisplayString("\pComputing Threshold.\r"); OpenArray(&gThrsArray, sizeof(Value), (Size)gPictHeight * gPictWidth); DoThreshold(&gPictArray, &gThrsArray, gGlobalParams->threshold); if (gTerminateFlag) { CloseArray(&gThrsArray); DisplayString("\pCancelled!\r\r"); return; } if (NewGWorld(&gThrsWorld, 8, &gPictRect, GetCTable(GRAY_RAMP + 8), nil, 0) != noErr) DoError( "\pCannot create new threshold GWorld!"); CopyArray2GWorld(&gThrsArray, gThrsWorld, &gPictRect); SetPort(gThrsWindow); ClipRect(&gPictRect); PortSize(gPictWidth, gPictHeight); ShowWindow(gThrsWindow); SelectWindow(gThrsWindow); } /************************************************/ /* Threshold Dialog Routines */ /************************************************/ static pascal Boolean ThrsDlogFilter(DialogPtr dlog, EventRecord *evt, short *item) { return SkelDlogMapKeyToButton(dlog, evt, item, iThrsOK, iThrsCancel); } static pascal void ThrsDlogSelect(DialogPtr dlog, short item) { long num; if (dlog == gThresholdDialog) switch (item) { case iThrsCancel: HideWindow(gThresholdDialog); AdjustMenus(true); break; case iThrsOK: SkelGetDlogStr(gThresholdDialog, iThrsText, gTempStr); StringToNum(gTempStr, &num); if (num > 100) num = 100L; else if (num < 0) num = 0L; gGlobalParams->threshold = (Value)num; HideWindow(gThresholdDialog); OpenThrsWindow(); } } static pascal void ThrsDlogClobber(void) { DisposeDialog(gThresholdDialog); } Boolean InitThresholdDialog(void) { return SkelDialog(gThresholdDialog, ThrsDlogFilter, ThrsDlogSelect, nil, ThrsDlogClobber); } void OpenThresholdDialog(void) { NumToString((long)(gGlobalParams->threshold), gTempStr); SkelSetDlogStr(gThresholdDialog, iThrsText, gTempStr); ShowWindow(gThresholdDialog); SetPort(gThresholdDialog); RGBForeColor(&kBlack); RGBBackColor(&kWhite); SelectWindow(gThresholdDialog); SkelDlogTracksCursor(true); SkelDrawButtonOutline(SkelGetDlogCtl(gThresholdDialog, iThrsOK)); }