home *** CD-ROM | disk | FTP | other *** search
/ Carousel Volume 2 #1 / carousel.iso / mactosh / lang / p_image1.sit / LSP Source / Functions.p < prev    next >
Encoding:
Text File  |  1989-07-27  |  33.2 KB  |  1,365 lines

  1. unit Functions;
  2.  
  3. {}
  4.  
  5. interface
  6.  
  7.  
  8.     uses
  9.         QuickDraw, OSIntf, PickerIntf, ToolIntf, PrintTraps, globals, Utilities, Graphics, FileUnit, Analysis, Camera;
  10.  
  11.  
  12.     procedure ApplyTable (var table: LookupTable);
  13.     procedure ApplyLookupTable;
  14.     procedure MakeBinary;
  15.     procedure Filter (ftype: FilterType; FirstPass: boolean);
  16.     procedure PhotoMode;
  17.     procedure Animate;
  18.     procedure EnhanceContrast;
  19.     procedure EqualizeHistogram;
  20.     procedure SortPalette;
  21.     procedure Convolve;
  22.     procedure Do3DPlot;
  23.     procedure MakeSkeleton;
  24.  
  25.  
  26. implementation
  27.  
  28.     const
  29.         MaxW = 4000;
  30.  
  31.     type
  32.         ktype = array[0..MaxW] of integer;
  33.  
  34.     var
  35.         PixelsRemoved: LongInt;
  36.  
  37.     procedure ApplyTableToLine (data: ptr; var table: LookupTable; width: LongInt);
  38. {$IFC false}
  39.         type
  40.             lptr = ^LineType;
  41.         var
  42.             line: lptr;
  43.             i: integer;
  44.     begin
  45.         line := lptr(data);
  46.         for i := 0 to width - 1 do
  47.             Line^[i] := table[Line^[i]];
  48.     end;
  49. {$ENDC}
  50.  
  51. {a0 = data}
  52. {a1 = lookup table}
  53. {d0 = width }
  54. {d1 = pixel value}
  55. inline
  56.     $4E56, $0000, {  link a6,#0}
  57.     $48E7, $C0C0, {  movem.l a0-a1/d0-d1,-(sp)}
  58.     $206E, $000C, {  move.l 12(a6),a0}
  59.     $226E, $0008, {  move.l 8(a6),a1}
  60.     $202E, $0004, {  move.l 4(a6),d0}
  61.     $5380,       {  subq.l #1,d0}
  62.     $4281,       {  clr.l d1}
  63.     $1210,       {L move.b (a0),d1}
  64.     $10F1, $1000, {  move.b 0(a1,d1.w),(a0)+}
  65.     $51C8, $FFF8, {  dbra d0,L}
  66.     $4CDF, $0303, {  movem.l (sp)+,a0-a1/d0-d1}
  67.     $4E5E,       {  unlk a6}
  68.     $DEFC, $000C; {  add.w #12,sp}
  69.  
  70.  
  71. function SetupMask: boolean;
  72. {Creates a mask in the undo buffer for operating on non-rectangular}
  73. {selections . Assumes SetupUndoFromClip has been called . }
  74.     var
  75.         tPort: GrafPtr;
  76. begin
  77.     if info^.PicSize > UndoBufSize then begin
  78.             SetupMask := false;
  79.             exit(SetupMask)
  80.         end;
  81.     GetPort(tPort);
  82.     with Info^ do begin
  83.             SetPort(GrafPtr(osPort));
  84.             with osPort^ do
  85.                 if fgcolor = bkcolor then
  86.                     bkColor := 255 - ForegroundColor;
  87.             PenNormal;
  88.             EraseRect(osroiRect);
  89.             PaintRgn(osroiRgn);
  90.             osPort^.bkColor := BackgroundColor;
  91.         end;
  92.     SetPort(tPort);
  93.     SetupUndo; {Copy mask to undo buffer.}
  94.     if info^.PicSize <= ClipBufSize then begin
  95.             UndoFromClip := true;
  96.             RestoreUndoBuf := false;
  97.             undo;
  98.             RestoreUndoBuf := true;
  99.         end;
  100.     UndoInfoRec := info^;
  101.     UndoInfo := @UndoInfoRec;
  102.     with UndoInfo^ do begin
  103.             PicBaseAddr := UndoBuf;
  104.             BytesPerRow := PixelsPerLine;
  105.         end;
  106.     SaveInfo := Info;
  107.     SetupMask := true;
  108. end;
  109.  
  110.  
  111. procedure PutLineUsingMask (h, v, count: integer; var line: LineType);
  112.     var
  113.         aLine, MaskLine: LineType;
  114.         i: integer;
  115. begin
  116.     GetLine(h, v, count, aline);
  117.     Info := UndoInfo;
  118.     GetLine(h, v, count, MaskLine);
  119.     for i := 0 to count - 1 do
  120.         if MaskLine[i] = ForegroundColor then
  121.             aLine[i] := line[i];
  122.     info := SaveInfo;
  123.     PutLine(h, v, count, aLine);
  124. end;
  125.  
  126.  
  127. procedure ApplyTable; {(var table: LookupTable)}
  128.     var
  129.         width, NumberOfLines, i, hloc, vloc: integer;
  130.         offset: LongInt;
  131.         p: ptr;
  132.         UseMask: boolean;
  133.         TempLine: LineType;
  134.         AutoSelectAll: boolean;
  135. begin
  136.     if NotInBounds then
  137.         exit(ApplyTable);
  138.     if RunningOn030 and (info^.PictureType = Camera) then begin
  139.             PutMessage('Apply LUT is not allowed in the Camera window on 68030 CPUs.', '', '');
  140.             exit(ApplyTable);
  141.         end;
  142.     StopDigitizing;
  143.     AutoSelectAll := not Info^.RoiShowing;
  144.     if AutoSelectAll then
  145.         SelectAll(false);
  146.     ShowWatch;
  147.     WhatToUndo := UndoTransform;
  148.     SetupUndoFromClip;
  149.     with info^.osroiRect, info^ do begin
  150.             if RoiType <> RectRoi then
  151.                 UseMask := SetupMask
  152.             else
  153.                 UseMask := false;
  154.             offset := LongInt(top) * BytesPerRow + left;
  155.             if UseMask then
  156.                 p := @TempLine
  157.             else
  158.                 p := ptr(ord4(PicBaseAddr) + offset);
  159.             width := right - left;
  160.             NumberOfLines := bottom - top;
  161.             hloc := left;
  162.             vloc := top;
  163.         end;
  164.     if width > 0 then
  165.         for i := 1 to NumberOfLines do
  166.             if UseMask then begin
  167.                     GetLine(hloc, vloc, width, TempLine);
  168.                     ApplyTableToLine(p, table, width);
  169.                     PutLineUsingMask(hloc, vloc, width, TempLine);
  170.                     vloc := vloc + 1
  171.                 end
  172.             else begin
  173.                     ApplyTableToLine(p, table, width);
  174.                     p := ptr(ord4(p) + info^.BytesPerRow);
  175.                 end;
  176.     with info^ do begin
  177.             UpdateScreen(roiRect);
  178.             Info^.changes := true;
  179.         end;
  180.     SetupRoiRect;
  181.     if AutoSelectAll then
  182.         KillRoi;
  183. end;
  184.  
  185.  
  186. procedure DoApplyTableDialogBox;
  187.     const
  188.         Button1 = 3;
  189.         Button2 = 4;
  190.         Button3 = 5;
  191.         Button4 = 6;
  192.     var
  193.         mylog: DialogPtr;
  194.         item: integer;
  195.         SaveA, SaveB: boolean;
  196.  
  197.     procedure SetButtons;
  198.     begin
  199.         SetDialogItem(mylog, Button1, ord(ThresholdToForeground));
  200.         SetDialogItem(mylog, Button2, ord(not ThresholdToForeground));
  201.         SetDialogItem(mylog, Button3, ord(NonThresholdToBackground));
  202.         SetDialogItem(mylog, Button4, ord(not NonThresholdToBackground));
  203.     end;
  204.  
  205. begin
  206.     InitCursor;
  207.     SaveA := ThresholdToForeground;
  208.     SaveB := NonThresholdToBackground;
  209.     mylog := GetNewDialog(40, nil, pointer(-1));
  210.     SetButtons;
  211.     OutlineButton(MyLog, ok, 16);
  212.     repeat
  213.         ModalDialog(nil, item);
  214.         if (item = Button1) or (item = button2) then begin
  215.                 ThresholdToForeground := not ThresholdToForeground;
  216.                 SetButtons;
  217.             end;
  218.         if (item = Button3) or (item = button4) then begin
  219.                 NonThresholdToBackground := not NonThresholdToBackground;
  220.                 SetButtons;
  221.             end;
  222.     until (item = ok) or (item = cancel);
  223.     DisposDialog(mylog);
  224.     if item = cancel then begin
  225.             ThresholdToForeground := SaveA;
  226.             NonThresholdToBackground := SaveB;
  227.         end;
  228. end;
  229.  
  230.  
  231. procedure ApplyLookupTable;
  232.     var
  233.         table: LookupTable;
  234.         ConvertingColorPic: boolean;
  235. begin
  236.     with info^ do
  237.         ConvertingColorPic := not ((LUTMode = Grayscale) or (LUTMode = CustomGrayscale));
  238.     if thresholding then
  239.         DoApplyTableDialogBox;
  240.     GetLookupTable(table);
  241.     ResetGrayMap;
  242.     ApplyTable(table);
  243.     if ConvertingColorPic then
  244.         WhatToUndo := NothingToUndo;
  245. end;
  246.  
  247.  
  248. procedure MakeBinary;
  249.     var
  250.         table: LookupTable;
  251.         SaveBackground, SaveForeground: integer;
  252. begin
  253.     if not thresholding and (info^.deltax > 1) then
  254.         PutMessage('Sorry, but you must be thresholding to use Make Binary.', '', '')
  255.     else begin
  256.             ThresholdToForeground := true;
  257.             NonThresholdToBackground := true;
  258.             SaveBackground := BackgroundColor;
  259.             SaveForeground := ForegroundColor;
  260.             BackgroundColor := WhiteC;
  261.             ForegroundColor := BlackC;
  262.             GetLookupTable(table);
  263.             ResetGrayMap;
  264.             ApplyTable(table);
  265.             BackgroundColor := SaveBackground;
  266.             ForegroundColor := SaveForeground;
  267.             info^.BinaryPic := true;
  268.         end;
  269. end;
  270.  
  271.  
  272. procedure Filter (ftype: FilterType; FirstPass: boolean);
  273.     const
  274.         PixelsPerUpdate = 5000;
  275.     var
  276.         row, width, r1, r2, r3, c, value, error, sum, center: integer;
  277.         tmp, mark, NewMark, LinesPerUpdate, LineCount: integer;
  278.         t1, t2, t3, t4: integer;
  279.         MaskRect, frame: rect;
  280.         L1, L2, L3, result: LineType;
  281.         tPort: GrafPtr;
  282.         pt: point;
  283.         a: SortArray;
  284.         AutoSelectAll, UseMask: boolean;
  285.         OptionKeyWasDown: boolean;
  286.         L, T, R, B: integer;
  287. begin
  288.     if NotinBounds then
  289.         exit(Filter);
  290.     OptionKeyWasDown := OptionKeyDown;
  291.     StopDigitizing;
  292.     AutoSelectAll := not Info^.RoiShowing;
  293.     if AutoSelectAll then begin
  294.             SelectAll(false);
  295.             PenNormal;
  296.             PenPat(pat[PatIndex]);
  297.             FrameRect(info^.wrect);
  298.         end;
  299.     ShowWatch;
  300.     WhatToUndo := UndoFilter;
  301.     if FirstPass then
  302.         SetupUndoFromClip;
  303.     if info^.RoiType <> RectRoi then
  304.         UseMask := SetupMask
  305.     else
  306.         UseMask := false;
  307.     with info^ do
  308.         if ((LutMode = GrayScale) or (LutMode = CustomGrayscale)) and (not IdentityFunction) then
  309.             ApplyLookupTable;
  310.     frame := info^.osroiRect;
  311.     with frame, Info^ do begin
  312.             changes := true;
  313.             RoiShowing := false;
  314.             if left > 0 then
  315.                 left := left - 1;
  316.             if right < PicRect.right then
  317.                 right := right + 1;
  318.             width := right - left;
  319.             LinesPerUpdate := PixelsPerUpdate div width;
  320.             if ftype = ReduceNoise then
  321.                 LinesPerUpdate := LinesPerUpdate div 3;
  322.             GetLine(left, top, width, L2);
  323.             GetLine(left, top + 1, width, L3);
  324.             Mark := roiRect.top;
  325.             LineCount := 0;
  326.             for row := top + 1 to bottom - 1 do begin
  327.        {Move Convolution Window Down}
  328.                     BlockMove(@L2, @L1, width);
  329.                     BlockMove(@L3, @L2, width);
  330.                     GetLine(left, row + 1, width, L3);
  331.        {Process One Row}
  332.                     case ftype of
  333.                         EdgeDetect: 
  334.                             for c := 1 to width - 2 do begin
  335.                                     t1 := L1[c] + L1[c + 1] + L1[c + 2] - L3[c] - L3[c + 1] - L3[c + 2];
  336.                                     t1 := abs(t1);
  337.                                     t2 := L1[c + 2] + L2[c + 2] + L3[c + 2] - L1[c] - L2[c] - L3[c];
  338.                                     t2 := abs(t2);
  339.                                     if t1 > t2 then
  340.                                         tmp := t1
  341.                                     else
  342.                                         tmp := t2;
  343.                                     if OptionKeyWasDown then begin
  344.                                             if tmp > 255 then
  345.                                                 tmp := 255;
  346.                                             if tmp < 0 then
  347.                                                 tmp := 0;
  348.                                         end
  349.                                     else if tmp > 35 then
  350.                                         tmp := 255
  351.                                     else
  352.                                         tmp := 0;
  353.                                     result[c - 1] := tmp;
  354.                                 end;
  355.                         ReduceNoise:  {Median Filter}
  356.                             for c := 1 to width - 2 do begin
  357.                                     a[1] := L1[c];
  358.                                     a[2] := L1[c + 1];
  359.                                     a[3] := L1[c + 2];
  360.                                     a[4] := L2[c];
  361.                                     a[5] := L2[c + 1];
  362.                                     a[6] := L2[c + 2];
  363.                                     a[7] := L3[c];
  364.                                     a[8] := L3[c + 1];
  365.                                     a[9] := L3[c + 2];
  366.                                     result[c - 1] := FindMedian(a);
  367.                                 end;
  368.                         Dither:  {Floyd-Steinberg Algorithm}
  369.                             for c := 1 to width - 2 do begin
  370.                                     value := L2[c + 1];
  371.                                     if value < 128 then begin
  372.                                             result[c - 1] := 0;
  373.                                             error := -value;
  374.                                         end
  375.                                     else begin
  376.                                             result[c - 1] := 255;
  377.                                             error := 255 - value
  378.                                         end;
  379.                                     tmp := L2[c + 2];              {A}
  380.                                     tmp := tmp - (7 * error) div 16;
  381.                                     if tmp < 0 then
  382.                                         tmp := 0;
  383.                                     if tmp > 255 then
  384.                                         tmp := 255;
  385.                                     L2[c + 2] := tmp;
  386.                                     tmp := L3[c + 2];              {B}
  387.                                     tmp := tmp - error div 16;
  388.                                     if tmp < 0 then
  389.                                         tmp := 0;
  390.                                     if tmp > 255 then
  391.                                         tmp := 255;
  392.                                     L3[c + 2] := tmp;
  393.                                     tmp := L3[c + 1];              {C}
  394.                                     tmp := tmp - (5 * error) div 16;
  395.                                     if tmp < 0 then
  396.                                         tmp := 0;
  397.                                     if tmp > 255 then
  398.                                         tmp := 255;
  399.                                     L3[c + 1] := tmp;
  400.                                     tmp := L3[c];                {D}
  401.                                     tmp := tmp - (3 * error) div 16;
  402.                                     if tmp < 0 then
  403.                                         tmp := 0;
  404.                                     if tmp > 255 then
  405.                                         tmp := 255;
  406.                                     L3[c] := tmp;
  407.                                 end;
  408.                         UnweightedAvg: 
  409.                             for c := 1 to width - 2 do begin
  410.                                     tmp := (L1[c] + L1[c + 1] + L1[c + 2] + L2[c] + L2[c + 1] + L2[c + 2] + L3[c] + L3[c + 1] + L3[c + 2]) div 9;
  411.                                     if tmp > 255 then
  412.                                         tmp := 255;
  413.                                     if tmp < 0 then
  414.                                         tmp := 0;
  415.                                     result[c - 1] := tmp;
  416.                                 end;
  417.                         WeightedAvg: 
  418.                             for c := 1 to width - 2 do begin
  419.                                     tmp := (L1[c] + L1[c + 1] + L1[c + 2] + L2[c] + L2[c + 1] * 4 + L2[c + 2] + L3[c] + L3[c + 1] + L3[c + 2]) div 12;
  420.                                     if tmp > 255 then
  421.                                         tmp := 255;
  422.                                     if tmp < 0 then
  423.                                         tmp := 0;
  424.                                     result[c - 1] := tmp;
  425.                                 end;
  426.                         fsharpen: 
  427.                             for c := 1 to width - 2 do begin
  428.                                     if OptionKeyWasDown then
  429.                                         tmp := L2[c + 1] * 9 - L1[c] - L1[c + 1] - L1[c + 2] - L2[c] - L2[c + 2] - L3[c] - L3[c + 1] - L3[c + 2]
  430.                                     else begin
  431.                                             tmp := L2[c + 1] * 12 - L1[c] - L1[c + 1] - L1[c + 2] - L2[c] - L2[c + 2] - L3[c] - L3[c + 1] - L3[c + 2];
  432.                                             tmp := tmp div 4;
  433.                                         end;
  434.                                     if tmp > 255 then
  435.                                         tmp := 255;
  436.                                     if tmp < 0 then
  437.                                         tmp := 0;
  438.                                     result[c - 1] := tmp;
  439.                                 end;
  440.                         Erosion: 
  441.                             for c := 1 to width - 2 do begin
  442.                                     center := L2[c + 1];
  443.                                     if center = BlackC then begin
  444.                                             sum := L1[c] + L1[c + 1] + L1[c + 2] + L2[c] + L2[c + 2] + L3[c] + L3[c + 1] + L3[c + 2];
  445.                                             if sum < 1275 then
  446.                                                 center := WhiteC;
  447.                                         end;
  448.                                     result[c - 1] := center;
  449.                                 end;
  450.                         Dilation: 
  451.                             for c := 1 to width - 2 do begin
  452.                                     center := L2[c + 1];
  453.                                     if center = WhiteC then begin
  454.                                             sum := L1[c] + L1[c + 1] + L1[c + 2] + L2[c] + L2[c + 2] + L3[c] + L3[c + 1] + L3[c + 2];
  455.                                             if sum > 765 then
  456.                                                 center := BlackC;
  457.                                         end;
  458.                                     result[c - 1] := center;
  459.                                 end;
  460.                         OutlineFilter: 
  461.                             for c := 1 to width - 2 do begin
  462.                                     center := L2[c + 1];
  463.                                     if center = BlackC then begin
  464.                                             if (L2[c] = WhiteC) or (L1[c + 1] = WhiteC) or (L2[c + 2] = WhiteC) or (L3[c + 1] = WhiteC) then
  465.                                                 center := BlackC
  466.                                             else
  467.                                                 center := WhiteC;
  468.                                         end;
  469.                                     result[c - 1] := center;
  470.                                 end;
  471.                         Skeletonize: 
  472.                             for c := 1 to width - 2 do begin
  473.                                     center := L2[c + 1];
  474.                                     if center = BlackC then begin
  475.                                             L := L2[c];
  476.                                             T := L1[c + 1];
  477.                                             R := L2[c + 2];
  478.                                             B := L3[c + 1];
  479.                                             sum := L1[c] + T + L1[c + 2] + L + R + L3[c] + B + L3[c + 2];
  480.                                             if sum < 1275 then
  481.                                                 if not (((L <> BlackC) and (R <> BlackC)) or ((T <> BlackC) and (B <> BlackC))) then begin
  482.                                                         center := WhiteC;
  483.                                                         L2[c + 1] := 128;
  484.                                                         PixelsRemoved := PixelsRemoved + 1;
  485.                                                     end;
  486.                                         end;
  487.                                     result[c - 1] := center;
  488.                                 end;
  489.                     end; {case}
  490.                     if UseMask then
  491.                         PutLineUsingMask(left + 2, row, width - 3, result)
  492.                     else
  493.                         PutLine(left + 2, row, width - 3, result);
  494.                     LineCount := LineCount + 1;
  495.                     if LineCount = LinesPerUpdate then begin
  496.                             pt.h := roiRect.left;
  497.                             pt.v := row + 1;
  498.                             OffscreenToScreen(pt);
  499.                             NewMark := pt.v;
  500.                             with roiRect do
  501.                                 SetRect(MaskRect, left, mark, right, NewMark);
  502.                             UpdateScreen(MaskRect);
  503.                             LineCount := 0;
  504.                             Mark := NewMark;
  505.                             if magnification > 1.0 then
  506.                                 Mark := Mark - 1;
  507.                             if CommandPeriod then begin
  508.                                     UpdatePicWindow;
  509.                                     beep;
  510.                                     PixelsRemoved := 0;
  511.                                     exit(filter)
  512.                                 end;
  513.                         end;
  514.                 end; {for row:=...}
  515.         end; {with}
  516.     if LineCount > 0 then begin
  517.             with frame do
  518.                 SetRect(MaskRect, left, mark, right, bottom);
  519.             UpdateScreen(MaskRect)
  520.         end;
  521.     SetupRoiRect;
  522.     if AutoSelectAll then
  523.         KillRoi;
  524. end;
  525.  
  526.  
  527. procedure PhotoMode;
  528. {Erases the screen to black and then redraws the contents of the}
  529. {active picture window . Thanks to Matthew Russotto}
  530. {for the tip about using PaintBehind to restore the screen . }
  531.     var
  532.         tPort: GrafPtr;
  533.         event: EventRecord;
  534.         WinRect: rect;
  535.         SaveVisRgn: rgnHandle;
  536. begin
  537.     if info <> NoInfo then
  538.         with info^ do begin
  539.                 if OptionKeyDown then begin {Move window up to top of screen.}
  540.                         GetWindowRect(wptr, WinRect);
  541.                         MoveWindow(wptr, WinRect.left, 0, false);
  542.                     end;
  543.                 with wptr^ do begin
  544.                         SaveVisRgn := visRgn;
  545.                         visRgn := NewRgn;
  546.                         RectRgn(visRgn, ScreenBits.Bounds);
  547.                     end;
  548.                 FlushEvents(EveryEvent, 0);
  549.                 GetPort(tPort);
  550.                 EraseScreen;
  551.                 UpdatePicWindow;
  552.                 repeat
  553.                 until GetNextEvent(mDownMask + KeyDownMask, Event);
  554.                 with wptr^ do begin
  555.                         DisposeRgn(visRgn);
  556.                         visRgn := SaveVisRgn;
  557.                     end;
  558.                 RestoreScreen;
  559.                 SetPort(tPort);
  560.                 FlushEvents(EveryEvent, 0);
  561.             end
  562.     else
  563.         beep;
  564. end;
  565.  
  566.  
  567. procedure Animate;
  568.     var
  569.         TempInfo: InfoPtr;
  570.         n, last, DelayTicks: integer;
  571.         tPort: GrafPtr;
  572.         Event: EventRecord;
  573.         ch: char;
  574.         b: boolean;
  575.         SourceRect, DestRect: rect;
  576.         SingleStep, GoForward, NewKeyDown: boolean;
  577.         SaveLUTMode: LUTModeType;
  578.         SaveVisRgn: RgnHandle;
  579. begin
  580.     if nPics < 2 then begin
  581.             PutMessage('There must be at least two picture windows open in order to do animation.', '', '');
  582.             exit(Animate)
  583.         end;
  584.     SaveLutMode := info^.LutMode;
  585.     last := nPics;
  586.     getPort(tPort);
  587.     EraseScreen;
  588.     SetPort(info^.wptr);
  589.     FlushEvents(EveryEvent, 0);
  590.     DelayTicks := 0;
  591.     n := 1;
  592.     GoForward := true;
  593.     SingleStep := false;
  594.     with info^ do begin
  595.             SetPort(wptr);
  596.             with wptr^ do begin
  597.                     SaveVisRgn := visRgn;
  598.                     visRgn := NewRgn;
  599.                     RectRgn(visRgn, ScreenBits.Bounds);
  600.                 end;
  601.         end;
  602.     repeat
  603.         repeat
  604.             b := GetNextEvent(EveryEvent, Event);
  605.             NewKeyDown := event.what = KeyDown;
  606.         until (not SingleStep) or NewKeyDown or (event.what = MouseDown);
  607.         if NewKeyDown then begin
  608.                 Ch := chr(BitAnd(Event.message, 127));
  609.                 SingleStep := false;
  610.                 case ord(ch) of
  611.                     28: 
  612.                         begin
  613.                             SingleStep := true;
  614.                             GoForward := false;
  615.                             DelayTicks := 0
  616.                         end; {left}
  617.                     29: 
  618.                         begin
  619.                             SingleStep := true;
  620.                             GoForward := true;
  621.                             DelayTicks := 0
  622.                         end;  {right}
  623.                     57: 
  624.                         DelayTicks := 0;  {9}
  625.                     56: 
  626.                         DelayTicks := 1;  {8}
  627.                     55: 
  628.                         DelayTicks := 3;  {7}
  629.                     54: 
  630.                         DelayTicks := 5;  {6}
  631.                     53: 
  632.                         DelayTicks := 8;  {5}
  633.                     52: 
  634.                         DelayTicks := 12; {4}
  635.                     51: 
  636.                         DelayTicks := 18; {3}
  637.                     50: 
  638.                         DelayTicks := 30; {2}
  639.                     49: 
  640.                         DelayTicks := 60; {1}
  641.                     otherwise
  642.                         ;
  643.                 end;
  644.             end;
  645.         if DelayTicks <> 0 then
  646.             delay(DelayTicks, ticks);
  647.         if GoForward then begin
  648.                 n := n + 1;
  649.                 if n > last then
  650.                     n := 1
  651.             end
  652.         else begin
  653.                 n := n - 1;
  654.                 if n < 1 then
  655.                     n := last
  656.             end;
  657.         TempInfo := pointer(WindowPeek(PicWindow[n])^.RefCon);
  658.         with TempInfo^ do begin
  659.                 if (LutMode <> SaveLutMode) or (LutMode = Custom) or (LutMode = CustomGrayscale) or SingleStep then
  660.                     LoadLut(cTable);
  661.                 SaveLutMode := LutMode;
  662.                 with TempInfo^ do begin
  663.                         hlock(handle(osPort^.portPixMap));
  664.                         hlock(handle(CGrafPort(ThePort^).PortPixMap));
  665.                         CopyBits(BitMapHandle(osPort^.portPixMap)^^, BitMapHandle(CGrafPort(ThePort^).PortPixMap)^^, SrcRect, wrect, SrcCopy, nil);
  666.                         hunlock(handle(osPort^.portPixMap));
  667.                         hunlock(handle(CGrafPort(ThePort^).PortPixMap));
  668.                     end;
  669.             end; {with}
  670.     until event.what = MouseDown;
  671.     RestoreScreen;
  672.     SetPort(tPort);
  673.     with info^.wptr^ do begin
  674.             DisposeRgn(visRgn);
  675.             visRgn := SaveVisRgn;
  676.         end;
  677.     UpdatePicWindow;
  678.     ShowCursor;
  679.     FlushEvents(EveryEvent, 0);
  680. end;
  681.  
  682.  
  683. procedure EnhanceContrast;
  684.     var
  685.         AutoSelectAll: boolean;
  686.         min, max, i, threshold: integer;
  687.         found: boolean;
  688.         sum: LongInt;
  689. begin
  690.     with info^ do
  691.         if (LUTMode <> GrayScale) and (LUTMode <> CustomGrayscale) then begin
  692.                 PutMessage('Sorry, but you can only contrast enhance grayscale images.', '', '');
  693.                 exit(EnhanceContrast)
  694.             end;
  695.     if NotInBounds or (ClipBuf = nil) then
  696.         exit(EnhanceContrast);
  697.     StopDigitizing;
  698.     AutoSelectAll := not Info^.RoiShowing;
  699.     if AutoSelectAll then
  700.         SelectAll(false);
  701.     if info^.RoiType = RectRoi then
  702.         GetRectHistogram
  703.     else
  704.         GetNonRectHistogram;
  705.     sum := 0;
  706.     for i := 0 to 255 do
  707.         sum := sum + histogram[i];
  708.     threshold := sum div 5000;
  709.     i := -1;
  710.     repeat
  711.         i := i + 1;
  712.         found := histogram[i] > threshold;
  713.     until found or (i = 255);
  714.     min := i;
  715.     i := 256;
  716.     repeat
  717.         i := i - 1;
  718.         found := histogram[i] > threshold;
  719.     until found or (i = 0);
  720.     max := i;
  721.     if max > min then
  722.         with info^ do begin
  723.                 p1x := 255 - max;
  724.                 p1y := 0;
  725.                 p2x := 255 - min;
  726.                 p2y := 255;
  727.                 SetGrayScaleLUT;
  728.                 DrawGrayMap;
  729.                 WhatToUndo := UndoContrastEnhancement;
  730.             end;
  731.     info^.changes := true;
  732.     IdentityFunction := false;
  733.     if AutoSelectAll then
  734.         KillRoi;
  735. end;
  736.  
  737.  
  738. procedure EqualizeHistogram;
  739.     var
  740.         AutoSelectAll: boolean;
  741.         i, sum, v: integer;
  742.         isum: LongInt;
  743.         ScaleFactor: extended;
  744. begin
  745.     with info^ do
  746.         if (LUTMode <> GrayScale) and (LutMode <> CustomGrayscale) then begin
  747.                 PutMessage('Sorry, but you can only do histogram equalization on grayscale images.', '', '');
  748.                 exit(EqualizeHistogram)
  749.             end;
  750.     if NotInBounds or (ClipBuf = nil) then
  751.         exit(EqualizeHistogram);
  752.     StopDigitizing;
  753.     AutoSelectAll := not Info^.RoiShowing;
  754.     if AutoSelectAll then
  755.         SelectAll(false);
  756.     if info^.RoiType = RectRoi then
  757.         GetRectHistogram
  758.     else
  759.         GetNonRectHistogram;
  760.     ComputeResults;
  761.     isum := 0;
  762.     for i := 0 to 255 do
  763.         isum := isum + histogram[i];
  764.     ScaleFactor := 255.0 / isum;
  765.     sum := 0;
  766.     with info^ do begin
  767.             for i := 255 downto 0 do
  768.                 with cTable[i].rgb do begin
  769.                         sum := round(sum + histogram[i] * ScaleFactor);
  770.                         if sum > 255 then
  771.                             sum := 255;
  772.                         v := sum * 256;
  773.                         red := v;
  774.                         green := v;
  775.                         blue := v;
  776.                     end;
  777.             LoadLUT(cTable);
  778.             LUTMode := CustomGrayscale;
  779.             changes := true;
  780.         end;
  781.     DrawGrayMap;
  782.     WhatToUndo := UndoEqualization;
  783.     IdentityFunction := false;
  784.     if AutoSelectAll then
  785.         KillRoi;
  786. end;
  787.  
  788.  
  789. procedure SortPalette;
  790.     type
  791.         MyHSVColor = record
  792.                 lHue, lSaturation, lValue: LongInt;
  793.             end;
  794.         HSVRec = record
  795.                 index: integer;
  796.                 hsv: MyHSVColor;
  797.             end;
  798.         HSVArrayType = array[0..255] of HSVRec;
  799.     var
  800.         TempTable: MyCSpecArray;
  801.         i: integer;
  802.         HSVArray: HSVArrayType;
  803.         h, s, v: LongInt;
  804.         fHue, fSaturation, fValue: fixed;
  805.         TempHSV: HSVColor;
  806.         table: LookupTable;
  807.  
  808.     procedure SortByHue;
  809.         var
  810.             i, j: integer;
  811.             x: HSVRec;
  812.     begin
  813.         for i := 2 to 254 do begin
  814.                 for j := 254 downto i do
  815.                     if HSVArray[j - 1].hsv.lHue > HSVArray[j].hsv.lHue then begin
  816.                             x := HSVArray[j - 1];
  817.                             HSVArray[j - 1] := HSVArray[j];
  818.                             HSVArray[j] := x;
  819.                         end;
  820.             end;
  821.     end;
  822.  
  823.     procedure SortBySaturation;
  824.         var
  825.             i, j: integer;
  826.             x: HSVRec;
  827.     begin
  828.         for i := 2 to 254 do begin
  829.                 for j := 254 downto i do
  830.                     if HSVArray[j - 1].hsv.lSaturation > HSVArray[j].hsv.lSaturation then begin
  831.                             x := HSVArray[j - 1];
  832.                             HSVArray[j - 1] := HSVArray[j];
  833.                             HSVArray[j] := x;
  834.                         end;
  835.             end;
  836.     end;
  837.  
  838.     procedure SortByValue;
  839.         var
  840.             i, j: integer;
  841.             x: HSVRec;
  842.     begin
  843.         for i := 2 to 254 do begin
  844.                 for j := 254 downto i do
  845.                     if HSVArray[j - 1].hsv.lValue > HSVArray[j].hsv.lValue then begin
  846.                             x := HSVArray[j - 1];
  847.                             HSVArray[j - 1] := HSVArray[j];
  848.                             HSVArray[j] := x;
  849.                         end;
  850.             end;
  851.     end;
  852.  
  853. begin
  854.     ShowWatch;
  855.     StopThresholding;
  856.     with info^ do begin
  857.             for i := 1 to 254 do begin
  858.                     HSVArray[i].index := i;
  859.                     rgb2hsv(cTable[i].rgb, TempHSV);
  860.                     with TempHSV do begin
  861.                             fHue := SmallFract2Fix(hue);
  862.                             fSaturation := SmallFract2Fix(saturation);
  863.                             fValue := SmallFract2Fix(value);
  864.                         end;
  865.                     with HSVArray[i].hsv do begin
  866.                             lHue := LongInt(band(fHue, $ffff));
  867.                             lSaturation := LongInt(band(fSaturation, $ffff));
  868.                             lValue := LongInt(band(fValue, $ffff));
  869.                         end;
  870.                 end;
  871. {SortBySaturation;}
  872.             SortByValue;
  873.             SortByHue;
  874.             for i := 1 to 254 do begin
  875.                     with HSVArray[i].hsv do begin
  876.                             TempHSV.hue := Fix2SmallFract(fixed(lHue));
  877.                             TempHSV.saturation := Fix2SmallFract(fixed(lSaturation));
  878.                             TempHSV.value := Fix2SmallFract(fixed(lValue));
  879.                         end;
  880.                     hsv2rgb(TempHSV, cTable[i].rgb);
  881.                 end;
  882.             LoadLUT(cTable);
  883.             if info <> NoInfo then begin
  884.                     table[0] := 0;
  885.                     table[255] := 255;
  886.                     for i := 1 to 254 do
  887.                         table[HSVArray[i].index] := i;
  888.                     ApplyTable(table);
  889.                 end;
  890.             WhatToUndo := NothingToUndo;
  891.         end; {with}
  892. end;
  893.  
  894.  
  895. function GetNum (f: integer; var EndOfLine, done: boolean): integer;
  896.     var
  897.         err: osErr;
  898.         a: packed array[1..2] of char;
  899.         c: char;
  900.         ByteCount, L: LongInt;
  901.         str: str255;
  902. begin
  903.     str := '';
  904.     EndOfLine := false;
  905.     repeat
  906.         ByteCount := 1;
  907.         err := fsRead(f, ByteCount, @a);
  908.         c := a[1];
  909.         done := err <> NoErr;
  910.     until ((c >= '0') and (c <= '9')) or (c = '-') or done;
  911.     if not done then begin
  912.             str := concat(str, c);
  913.             repeat
  914.                 ByteCount := 1;
  915.                 err := fsRead(f, ByteCount, @a);
  916.                 c := a[1];
  917.                 EndOfLine := c = return;
  918.                 done := err <> NoErr;
  919.                 if not done and (c >= '0') and (c <= '9') then
  920.                     str := concat(str, c);
  921.             until (c < '0') or (c > '9') or done;
  922.             StringToNum(str, L);
  923.             GetNum := L;
  924.         end
  925.     else
  926.         GetNum := -MaxInt;
  927. end;
  928.  
  929.  
  930. function GetKernel (var kernel: ktype; var n, count: integer; var name: str255): boolean;
  931.     var
  932.         where: Point;
  933.         typeList: SFTypeList;
  934.         reply: SFReply;
  935.         err: OSErr;
  936.         f, i, w, max: integer;
  937.         EndOfLine, done: boolean;
  938. begin
  939.     where.v := 120;
  940.     where.h := 120;
  941.     typeList[0] := 'TEXT';
  942.     SFGetFile(Where, '', nil, 1, typeList, nil, reply);
  943.     i := 0;
  944.     if reply.good then
  945.         with reply do begin
  946.                 ShowWatch;
  947.                 err := FSOpen(fname, vRefNum, f);
  948.                 err := SetFPos(f, fsFromStart, 0);
  949.                 n := 0;
  950.                 max := MaxW;
  951.                 repeat
  952.                     w := GetNum(f, EndOfLine, done);
  953.                     if (n = 0) and EndOfLine then begin
  954.                             n := i + 1;
  955.                             max := n * n;
  956.                         end;
  957.                     if i < max then
  958.                         kernel[i] := w
  959.                     else
  960.                         done := true;
  961.                     if w <> -MaxInt then
  962.                         i := i + 1;
  963.                 until done;
  964.                 err := fsclose(f);
  965.                 count := i;
  966.                 name := fname;
  967.                 GetKernel := true;
  968.             end
  969.     else
  970.         GetKernel := false;
  971. end;
  972.  
  973.  
  974. procedure DoOnePixel (nLess1, PixelsPerLine: integer; corner: LongInt; var sum: LongInt; var kernel: ktype);
  975. {$IFC false}
  976.     var
  977.         row, column, k: integer;
  978.         pp: ptr;
  979. begin
  980.     k := 0;
  981.     sum := 0;
  982.     for row := 0 to nless1 do begin
  983.             corner := corner + PixelsPerLine;
  984.             pp := ptr(corner);
  985.             for column := 0 to nless1 do begin
  986.                     sum := sum + band(pp^, 255) * kernel[k];
  987.                     k := k + 1;
  988.                     pp := ptr(ord(pp) + 1);
  989.                 end;
  990.         end;
  991. end;
  992. {$ENDC}
  993.  
  994. {a0=^corner/^sum}
  995. {a1=^kernel}
  996. {a2=^pixels}
  997.  
  998. {d0=n-1}
  999. {d1=PixelsPerLine}
  1000. {d2=sum}
  1001. {d3=n-1(outer loop)}
  1002. {d4=n-1(inner loop)}
  1003. {d5=temp}
  1004.  
  1005. inline
  1006.     $4E56, $0000, {  link    a6,#0}
  1007.     $48E7, $FCE0,  {  movem.l    a0-a2/d0-d5,-(sp)}
  1008.     $4280,              {  clr.l    d0}
  1009.     $302E, $0012, {  move.w    18(a6),d0}
  1010.     $4281,              {  clr.l    d1}
  1011.     $322E, $0010, {  move.w    16(a6),d1}
  1012.     $206E, $000C, {  movea.l    12(a6),a0}
  1013.     $226E, $0004, {  movea.l    4(a6),a1}
  1014.  
  1015.     $4282,             {  clr.l    d2}
  1016.     $2600,             {  move.l    d0,d3}
  1017.  
  1018.     $D1C1,             {A adda.l    d1,a0}
  1019.     $2448,            {  move.l    a0,a2}
  1020.     $2800,            {  move.l    d0,d4}
  1021.     $4285,            {B clr.l    d5                   (2)}
  1022.     $1A1A,             {  move.b    (a2)+,d5    (6) }
  1023.     $CBD9,             {  muls    (a1)+,d5     (29!)}
  1024.     $D485,             {  add.l    d5,d2          (2)}
  1025.     $51CC, $FFF6, {  dbra    d4,B                (6)}
  1026.     $51CB, $FFEC, {  dbra    d3,A}
  1027.  
  1028.     $206E, $0008, {  move.l    8(a6),a0}
  1029.     $2082,              {  move.l    d2,(a0)}
  1030.     $4CDF, $073F, {  movem.l    (sp)+,a0-a2/d0-d5}
  1031.     $4E5E,              {  unlk    a6}
  1032.     $DEFC, $0010; {  add.w    #16,sp}
  1033.  
  1034.  
  1035.  
  1036. procedure DoConvolution (var kernel: ktype; n: integer);
  1037.     var
  1038.         row, width, column, value, error: integer;
  1039.         margin, i, nless1: integer;
  1040.         frame, MaskRect, tRect: rect;
  1041.         AutoSelectAll: boolean;
  1042.         SrcCenter, DstCenter, sum, max, offset, wsum, cscale: LongInt;
  1043.         p: ptr;
  1044.         str: str255;
  1045. begin
  1046.     if NotinBounds or NotRectangular then
  1047.         exit(DoConvolution);
  1048.     StopDigitizing;
  1049.     AutoSelectAll := not Info^.RoiShowing;
  1050.     if AutoSelectAll then
  1051.         SelectAll(false);
  1052.     SetupUndoFromClip;
  1053.     WhatToUndo := UndoFilter;
  1054.     frame := info^.osroiRect;
  1055.     with frame, Info^ do begin
  1056.             if ((LutMode = GrayScale) or (LutMode = CustomGrayscale)) and (not IdentityFunction) then
  1057.                 ApplyLookupTable;
  1058.             changes := true;
  1059.             margin := n div 2;
  1060.             if left < margin then
  1061.                 left := left + margin;
  1062.             if right > (PicRect.right - margin) then
  1063.                 right := right - margin;
  1064.             if top < margin then
  1065.                 top := top + margin;
  1066.             if bottom > (PicRect.bottom - margin) then
  1067.                 bottom := bottom - margin;
  1068.             PenNormal;
  1069.             PenPat(pat[PatIndex]);
  1070.             tRect := frame;
  1071.             OffscreenToScreenRect(tRect);
  1072.             FrameRect(tRect);
  1073.             width := right - left;
  1074.             max := n * n - 1;
  1075.             wsum := 0;
  1076.             for i := 0 to max do
  1077.                 wsum := wsum + kernel[i];
  1078.             NumToString(n, str);
  1079.             str := Concat(str, 'x', str, ' kernel');
  1080.             PutRMessage(1, str, MaxInt);
  1081.             PutRMessage(2, 'Sum= ', wsum);
  1082.             if wsum <> 0 then
  1083.                 cscale := wsum
  1084.             else
  1085.                 cscale := 1;
  1086.             offset := -(n div 2) * PixelsPerLine - PixelsPerLine - n div 2;
  1087.             nless1 := n - 1;
  1088.             for row := top to bottom - 1 do begin
  1089.                     SrcCenter := ord4(ClipBufInfo^.PicBaseAddr) + LongInt(row) * PixelsPerLine + left;
  1090.                     DstCenter := ord4(PicBaseAddr) + LongInt(row) * BytesPerRow + left;
  1091.                     for column := left to left + width - 1 do begin
  1092.                             DoOnePixel(nless1, PixelsPerLine, SrcCenter + offset, sum, kernel);
  1093.                             value := sum div cscale;
  1094.                             if value > 255 then
  1095.                                 value := 255;
  1096.                             if value < 0 then
  1097.                                 value := 0;
  1098.                             p := ptr(DstCenter);
  1099.                             p^ := BAND(value, 255);
  1100.                             SrcCenter := SrcCenter + 1;
  1101.                             DstCenter := DstCenter + 1;
  1102.                         end; {for column:=}
  1103.                     SetRect(MaskRect, left, row, right, row + 1);
  1104.                     OffscreenToScreenRect(MaskRect);
  1105.                     UpdateScreen(MaskRect);
  1106.                     if CommandPeriod then begin
  1107.                             UpdatePicWindow;
  1108.                             beep;
  1109.                             exit(DoConvolution)
  1110.                         end;
  1111.                 end; {for row:=...}
  1112.         end; {with}
  1113.     UpdatePicWindow;
  1114.     SetupRoiRect;
  1115.     if AutoSelectAll then
  1116.         KillRoi;
  1117. end;
  1118.  
  1119.  
  1120. procedure MakeWindowFromKernel (var kernel: ktype; n: integer; name: str255);
  1121.     var
  1122.         h, v, value, i, min, offset: integer;
  1123. begin
  1124.     if NewPicWindow(name, 256, 256) then begin
  1125.             SelectAll(true);
  1126.             DoOperation(eraseOp);
  1127.             KillRoi;
  1128.             min := 9999;
  1129.             for i := 0 to n * n - 1 do
  1130.                 if kernel[i] < min then
  1131.                     min := kernel[i];
  1132.             if min < 0 then
  1133.                 offset := -min
  1134.             else
  1135.                 offset := 0;
  1136.             i := 0;
  1137.             for v := 0 to n - 1 do
  1138.                 for h := 0 to n - 1 do begin
  1139.                         value := kernel[i] + offset;
  1140.                         PutPixel(h, v, value);
  1141.                         i := i + 1;
  1142.                     end;
  1143.         end;
  1144. end;
  1145.  
  1146.  
  1147. procedure Convolve;
  1148.     var
  1149.         kernel: ktype;
  1150.         n, count: integer;
  1151.         error: boolean;
  1152.         str1, str2, name: str255;
  1153.         ok: boolean;
  1154.         OptionKeyWasDown: boolean;
  1155. begin
  1156.     OptionKeyWasDown := OptionKeyDown;
  1157.     ok := GetKernel(kernel, n, count, name);
  1158.     if not ok then
  1159.         exit(convolve);
  1160.     error := false;
  1161.     if n > 63 then begin
  1162.             error := true;
  1163.             str1 := 'Kernel size must be <= 63.';
  1164.         end;
  1165.     if count < (n * n) then begin
  1166.             error := true;
  1167.             str1 := 'Not enough kernel coefficients.';
  1168.         end;
  1169.     if OptionKeyWasDown then begin
  1170.             MakeWindowFromKernel(kernel, n, name);
  1171.             exit(convolve);
  1172.         end;
  1173.     if not error then begin
  1174.             UpdatePicWindow;
  1175.             DoConvolution(kernel, n);
  1176.         end
  1177.     else
  1178.         PutMessage(str1, '', '');
  1179. end;
  1180.  
  1181.  
  1182. procedure Do3DPlot;
  1183.     var
  1184.         hend, vend, h, v, DataWidth, DataHeight, i: integer;
  1185.         htemp, vtemp, MinValue, MaxValue, value: integer;
  1186.         SaveForeground, SaveBackground, skip: integer;
  1187.         hLoc, vLoc, hMin, hMax, vMin, vMax: integer;
  1188.         hstart, vstart, dh, dv, hbase, vbase, vscale, nPlotLines: extended;
  1189.         peak, MaxPeak, hinc, vinc, nLines: extended;
  1190.         tPort: GrafPtr;
  1191.         poly: PolyHandle;
  1192.         SaveInfo: InfoPtr;
  1193.         aLine: LineType;
  1194.         MaskRect: rect;
  1195.         AutoSelectAll, ApplyLUT: boolean;
  1196.         table: LookupTable;
  1197.  
  1198.     procedure FindVinc;
  1199.     begin
  1200.         with info^.PicRect do begin
  1201.                 vstart := 5.0 + vscale * (MaxPeak - MinValue) - dv * DataWidth;
  1202.                 skip := round(DataHeight / ((bottom - vstart - 5.0) / vinc));
  1203.                 if skip = 0 then
  1204.                     skip := 1;
  1205.                 nPlotLines := DataHeight / skip;
  1206.                 vinc := (bottom - vstart - 5.0) / nPlotLines;
  1207.                 vinc := vinc / 0.95;
  1208.                 repeat
  1209.                     vinc := vinc * 0.95;
  1210.                     hinc := vinc / 2.0;
  1211.                 until (5.0 + hinc * nPlotLines + dh * DataWidth) < right;
  1212.             end;
  1213.     end;
  1214.  
  1215. begin
  1216.     if NotRectangular or NotInBounds then
  1217.         exit(Do3DPlot);
  1218.     if RunningOn030 and (info^.PictureType = Camera) then begin
  1219.             PutMessage('3D Plotting is not allowed in the Camera window on 68030 CPUs.', '', '');
  1220.             exit(Do3DPlot);
  1221.         end;
  1222.     StopDigitizing;
  1223.     StopThresholding;
  1224.     AutoSelectAll := not Info^.RoiShowing;
  1225.     ShowWatch;
  1226.     if AutoSelectAll then
  1227.         SelectAll(true);
  1228.     Measure;
  1229.     UndoLastMeasurement;
  1230.     with results do begin
  1231.             MinValue := round(min);
  1232.             MaxValue := round(max)
  1233.         end;
  1234.     with info^ do
  1235.         if ScaleToFitWindow or (magnification <> 1.0) then
  1236.             UnZoom;
  1237.     with info^ do
  1238.         ApplyLUT := ((LutMode = GrayScale) or (LutMode = CustomGrayscale)) and (not IdentityFunction);
  1239.     if ApplyLUT then
  1240.         GetLookupTable(table);
  1241.     if ApplyLUT then begin
  1242.             MinValue := table[MinValue];
  1243.             MaxValue := table[MaxValue];
  1244.         end;
  1245.     KillRoi;
  1246.     SetupUndo;
  1247.     if not AutoSelectAll then
  1248.         RedoSelection := true;
  1249.     WhatToUndo := UndoPlot;
  1250.     UndoInfoRec := info^;
  1251.     UndoInfo := @UndoInfoRec;
  1252.     with UndoInfo^ do begin
  1253.             PicBaseAddr := UndoBuf;
  1254.             BytesPerRow := PixelsPerLine;
  1255.         end;
  1256.     SaveInfo := Info;
  1257.     GetPort(tPort);
  1258.     with Info^, info^.osroiRect do begin
  1259.             SaveForeground := ForegroundColor;
  1260.             SaveBackground := BackgroundColor;
  1261.             SetForegroundColor(BlackC);
  1262.             SetBackgroundColor(WhiteC);
  1263.             changes := true;
  1264.             SetPort(GrafPtr(osPort));
  1265.             PenNormal;
  1266.             EraseRect(PicRect);
  1267.             UpdatePicWindow;
  1268.             vscale := 0.5;
  1269.             DataWidth := right - left;
  1270.             DataHeight := bottom - top;
  1271.             dh := (0.65 * PicRect.right) / DataWidth;
  1272.             dv := -0.4 * dh;
  1273.             hstart := 5.0;
  1274.             vinc := 2.0;
  1275.             MaxPeak := (MaxValue - MinValue) * vscale;
  1276.             MaxPeak := MaxPeak * 0.5;
  1277.             FindVinc; {First estamate}
  1278.             MaxPeak := MaxPeak * 2.0;
  1279.             hmin := right + round(MaxPeak / dv);
  1280.             if hmin < 0 then
  1281.                 hmin := 0;
  1282.             vmax := top + round(MaxPeak / vinc);
  1283.             if vmax > bottom then
  1284.                 vmax := bottom;
  1285.             MaxValue := 0;
  1286.             MaxPeak := 0.0;
  1287.             vloc := top;
  1288.             Info := UndoInfo;
  1289.             skip := 3;
  1290.             repeat
  1291.                 hloc := hmin;
  1292.                 repeat
  1293.                     value := MyGetPixel(hloc, vloc);
  1294.                     if ApplyLUT then
  1295.                         value := table[value];
  1296.                     peak := value + (right - hloc) * dv - (vloc - top) * vinc;
  1297.                     if peak > MaxPeak then
  1298.                         MaxPeak := peak;
  1299.                     hloc := hloc + skip;
  1300.                 until hloc > right;
  1301.                 vloc := vloc + skip;
  1302.             until vloc > vmax;
  1303.             FindVinc;
  1304.             v := top;
  1305.             repeat
  1306.                 hmax := 0;
  1307.                 vmin := 9999;
  1308.                 Info := UndoInfo;
  1309.                 poly := OpenPoly;
  1310.                 hbase := hstart;
  1311.                 vbase := vstart;
  1312.                 GetLine(left, v, DataWidth, aLine);
  1313.                 if ApplyLUT then
  1314.                     ApplyTableToLine(@aLine, table, DataWidth);
  1315.                 MoveTo(round(hbase), round(vbase - vscale * (aLine[0] - MinValue)));
  1316.                 for i := 0 to DataWidth - 1 do begin
  1317.                         hbase := hbase + dh;
  1318.                         vbase := vbase + dv;
  1319.                         hLoc := round(hbase);
  1320.                         vLoc := round(vbase - vscale * (aLine[i] - MinValue));
  1321.                         LineTo(hloc, vloc);
  1322.                         if hloc > hmax then
  1323.                             hmax := hloc;
  1324.                         if vloc < vmin then
  1325.                             vmin := vloc;
  1326.                     end;
  1327.                 LineTo(round(hbase), round(vbase));
  1328.                 LineTo(round(hstart), round(vstart));
  1329.                 LineTo(round(hstart), round(vstart - vscale * (aLine[0] - MinValue)));
  1330.                 hmin := round(hstart);
  1331.                 vmax := round(vstart);
  1332.                 ClosePoly;
  1333.                 ErasePoly(poly);
  1334.                 FramePoly(poly);
  1335.                 KillPoly(poly);
  1336.                 info := SaveInfo;
  1337.                 SetRect(MaskRect, hmin, vmin, hmax, vmax);
  1338.                 OffscreenToScreenRect(MaskRect);
  1339.                 UpdateScreen(MaskRect);
  1340.                 hstart := hstart + hinc;
  1341.                 vstart := vstart + vinc;
  1342.                 v := v + skip;
  1343.             until (v >= bottom) or CommandPeriod;
  1344.         end; {with}
  1345.     if CommandPeriod then
  1346.         beep;
  1347.     SetForegroundColor(SaveForeground);
  1348.     SetBackgroundColor(SaveBackground);
  1349.     SetPort(tPort);
  1350. end;
  1351.  
  1352.  
  1353. procedure MakeSkeleton;
  1354. begin
  1355.     PixelsRemoved := 0;
  1356.     filter(skeletonize, true);
  1357.     if PixelsRemoved <> 0 then
  1358.         repeat
  1359.             PixelsRemoved := 0;
  1360.             filter(skeletonize, false);
  1361.         until PixelsRemoved = 0;
  1362. end;
  1363.  
  1364.  
  1365. end.