home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Pascal / Applications / NIH Image 1.55 / Source / Lut.p < prev    next >
Encoding:
Text File  |  1994-04-20  |  51.7 KB  |  1,860 lines  |  [TEXT/PJMM]

  1. unit Lut;
  2. {This file contains routines that deal with the video Look-Up Table(LUT).}
  3.  
  4. interface
  5.  
  6.     uses
  7.         QuickDraw, Palettes, Picker, PrintTraps, globals, Utilities, Graphics;
  8.  
  9.     function GetPseudoColorIndex: integer;
  10.     function isGrayScaleLUT: boolean;
  11.     procedure DoMouseDownInLUT (event: EventRecord);
  12.     procedure DoCopyColor;
  13.     procedure PasteColor;
  14.     procedure ShowRGBValues (index: integer);
  15.     procedure InvertPalette;
  16.     procedure FindPoints (var x1, y1, x2, y2: integer);
  17.     procedure UpdateMap;
  18.     procedure ResetGraymap;
  19.     procedure DrawMap;
  20.     procedure DoMouseDownInMap;
  21.     procedure EnableThresholding (level: integer);
  22.     procedure DisableThresholding;
  23.     procedure DrawLUT;
  24.     procedure UpdateLUT;
  25.     procedure LoadColorTable (theColorTable: CTabHandle);
  26.     function LoadCLUTResource (id: integer): boolean;
  27.     procedure GetLookupTable (var table: LookupTable);
  28.     procedure RedrawLUTWindow;
  29.     procedure DrawDensitySlice (OptionKey: boolean);
  30.     procedure SelectLutTool;
  31.     procedure EnableDensitySlice;
  32.     procedure SetupPseudocolor;
  33.     procedure DoImportLut (fname: str255; vnum: integer);
  34.     procedure OpenOldPalette (fname: str255; RefNum: integer);
  35.     procedure OpenNewPalette (fname: str255; RefNum: integer);
  36.     procedure OpenColorTable (fname: str255; RefNum: integer);
  37.     procedure ImportPalette (FileType: OSType; fname: str255; vnum: integer);
  38.     procedure GetColorTable (id: integer);
  39.     procedure GetLutResource (id: integer);
  40.     procedure DrawScale;
  41.     procedure MakeSpectrum;
  42.     function GetColorTableItem (ctab: ColorTableType): integer;
  43.     procedure SwitchColorTables (item: integer; update: boolean);
  44.     procedure InitPaletteHeader (var hdr: PaletteHeader);
  45.     procedure ResetMap;
  46.     procedure DoLutOptions;
  47.     function SetupMask: boolean;
  48.     procedure PutLineUsingMask (h, v, count: integer; var line: LineType);
  49.     procedure ApplyTable (var table: LookupTable);
  50.     procedure FixColors;
  51.  
  52.  
  53.  
  54. implementation
  55.  
  56.  
  57.     function GetPseudoColorIndex: integer;
  58.         var
  59.             index: integer;
  60.     begin
  61.         with info^ do begin
  62.                 index := trunc((nColors) * (ForegroundIndex - ColorStart) / (ColorEnd - ColorStart + 1));
  63.                 if index < 0 then
  64.                     index := 0;
  65.                 if index > (nColors - 1) then
  66.                     index := nColors - 1;
  67.                 GetPseudoColorIndex := index;
  68.             end;
  69.     end;
  70.  
  71.  
  72.     procedure UpdateLUT;
  73.         var
  74.             MaxStart, i, v, index, last: integer;
  75.             inc, sIndex: LongInt;
  76.     begin
  77.         with info^ do begin
  78.                 sIndex := 0;
  79.                 if ColorEnd > ColorStart then
  80.                     inc := LongInt(nColors) * 10000 div (ColorEnd - ColorStart)
  81.                 else
  82.                     inc := 2560000;
  83.                 if ColorStart < 0 then
  84.                     sIndex := -ColorStart * Inc
  85.                 else
  86.                     sIndex := 0;
  87.                 last := nColors - 1;
  88.                 for i := 0 to 255 do
  89.                     with cTable[i].rgb do begin
  90.                             if (i < ColorStart) or (i > ColorEnd) then begin
  91.                                     if i < ColorStart then
  92.                                         cTable[i].rgb := FillColor1
  93.                                     else
  94.                                         cTable[i].rgb := FillColor2;
  95.                                 end
  96.                             else begin
  97.                                     index := sIndex div 10000;
  98.                                     if index > last then
  99.                                         index := last;
  100.                                     Red := bsl(RedLUT[index], 8);
  101.                                     Green := bsl(GreenLUT[index], 8);
  102.                                     Blue := bsl(BlueLUT[index], 8);
  103.                                     sIndex := sIndex + inc;
  104.                                 end;
  105.                         end; {for}
  106.                 if ColorStart = ColorEnd then
  107.                     cTable[ColorStart].rgb := FillColor2
  108.                 else
  109.                     Thresholding := false;
  110.                 LoadLUT(cTable);
  111.                 IdentityFunction := false;
  112.             end;
  113.     end;
  114.  
  115.  
  116.     function GetVLoc: integer;
  117.         var
  118.             loc: point;
  119.             vloc: integer;
  120.     begin
  121.         GetMouse(loc);
  122.         vloc := loc.v;
  123.         if vloc > 255 then
  124.             vloc := 255;
  125.         if vloc <= 0 then
  126.             vloc := 0;
  127.         GetVLoc := vloc;
  128.     end;
  129.  
  130.  
  131.     procedure GetNewColor (var color: RGBColor);
  132.         var
  133.             where: point;
  134.             inRGBColor, OutRGBColor: RGBColor;
  135.     begin
  136.         inRGBColor := color;
  137.         outRGBColor := color;
  138.         where.h := 0;
  139.         where.v := 0;
  140.         InitCursor;
  141.         if GetColor(where, 'Pick a new color...', inRGBColor, outRGBColor) then
  142.             color := outRGBColor;
  143.     end;
  144.  
  145.  
  146.     procedure EditPseudoColors;
  147.         var
  148.             where: point;
  149.             inRGBColor, OutRGBColor: RGBColor;
  150.             index, mloc: integer;
  151.     begin
  152.         SetupLUTUndo;
  153.         with info^ do begin
  154.                 SetPort(LUTWindow);
  155.                 mloc := getvloc;
  156.                 if mloc < ColorStart then begin
  157.                         GetNewColor(FillColor1);
  158.                         UpdateLUT;
  159.                         exit(EditPseudoColors);
  160.                     end;
  161.                 if mloc > ColorEnd then begin
  162.                         GetNewColor(FillColor2);
  163.                         UpdateLUT;
  164.                         exit(EditPseudoColors);
  165.                     end;
  166.                 index := GetPseudoColorIndex;
  167.                 with inRGBColor do begin
  168.                         red := bsl(RedLUT[index], 8);
  169.                         green := bsl(GreenLUT[index], 8);
  170.                         blue := bsl(BlueLUT[index], 8);
  171.                     end;
  172.                 outRGBColor := inRGBColor;
  173.                 where.h := 0;
  174.                 where.v := 0;
  175.                 InitCursor;
  176.                 if GetColor(where, 'Pick a color, any color...', inRGBColor, outRGBColor) then begin
  177.                         with outRGBColor do begin
  178.                                 RedLUT[index] := bsr(red, 8);
  179.                                 GreenLUT[index] := bsr(green, 8);
  180.                                 BlueLUT[index] := bsr(blue, 8);
  181.                             end;
  182.                         changes := true;
  183.                     end;
  184.                 ColorTable := CustomTable;
  185.                 LutMode := PseudoColor;
  186.                 UpdateLUT;
  187.             end; {with}
  188.     end;
  189.  
  190.  
  191.     function EditSliceColor: boolean;
  192.         var
  193.             where: point;
  194.             inRGBColor, OutRGBColor: RGBColor;
  195.             vloc: integer;
  196.     begin
  197.         SetPort(LUTWindow);
  198.         vloc := getvloc;
  199.         if (vloc >= SliceStart) and (vloc <= SliceEnd) then begin
  200.                 GetNewColor(SliceColor);
  201.                 DrawDensitySlice(false);
  202.                 EditSliceColor := true
  203.             end
  204.         else
  205.             EditSliceColor := false;
  206.     end;
  207.  
  208.  
  209.     procedure ShowLUTValues (tStart, tEnd: integer);
  210.         var
  211.             tPort: GrafPtr;
  212.             value: extended;
  213.             range, NewMin, NewMax: LongInt;
  214.     begin
  215.         with info^ do begin
  216.                 GetPort(tPort);
  217.                 SetPort(InfoWindow);
  218.                 TextSize(9);
  219.                 TextFont(Monaco);
  220.                 TextMode(SrcCopy);
  221.                 MoveTo(xValueLoc, InfoVStart);
  222.                 if DataType <> EightBits then begin
  223.                         range := CurrentMax - CurrentMin;
  224.                         if tEnd < 255 then
  225.                             NewMin := CurrentMin + round(((255 - tEnd) / 255) * range)
  226.                         else
  227.                             NewMin := CurrentMin;
  228.                         DrawLong(NewMin);
  229.                         DrawString('    ');
  230.                         MoveTo(xValueLoc, InfoVStart + 10);
  231.                         if tStart > 0 then
  232.                             NewMax := CurrentMax - round((tStart / 255) * range)
  233.                         else
  234.                             NewMax := CurrentMax;
  235.                         DrawLong(NewMax);
  236.                         DrawString('    ');
  237.                         SetPort(tPort);
  238.                         exit(ShowLUTValues);
  239.                     end;
  240.                 if DensityCalibrated then begin
  241.                         if tStart >= 0 then
  242.                             value := cvalue[tStart]
  243.                         else
  244.                             value := cvalue[0];
  245.                         DrawReal(value, 5, 2);
  246.                         DrawString(' (');
  247.                         DrawReal(tStart, 3, 0);
  248.                         DrawString(')');
  249.                     end
  250.                 else
  251.                     DrawReal(tStart, 3, 0);
  252.                 DrawString('    ');
  253.                 MoveTo(xValueLoc, InfoVStart + 10);
  254.                 if DensityCalibrated then begin
  255.                         if tEnd <= 255 then
  256.                             value := cvalue[tEnd]
  257.                         else
  258.                             value := cvalue[255];
  259.                         DrawReal(value, 5, 2);
  260.                         DrawString(' (');
  261.                         DrawReal(tEnd, 3, 0);
  262.                         DrawString(')');
  263.                     end
  264.                 else
  265.                     DrawReal(tEnd, 3, 0);
  266.                 DrawString('    ');
  267.                 SetPort(tPort);
  268.             end;
  269.     end;
  270.  
  271.  
  272.     procedure ShowRGBValues (index: integer);
  273.         var
  274.             tPort: GrafPtr;
  275.             vloc: integer;
  276.     begin
  277.         with info^ do begin
  278.                 GetPort(tPort);
  279.                 SetPort(InfoWindow);
  280.                 TextSize(9);
  281.                 TextFont(Monaco);
  282.                 TextMode(SrcCopy);
  283.                 vloc := InfoVStart;
  284.                 MoveTo(xValueLoc, vloc);
  285.                 DrawLong(index);
  286.                 DrawString('    ');
  287.                 if Info^.DensityCalibrated then begin
  288.                         vloc := vloc + 10;
  289.                         MoveTo(xValueLoc, vloc);
  290.                         DrawReal(cvalue[index], 1, precision);
  291.                         DrawString('    ');
  292.                     end;
  293.                 vloc := vloc + 10;
  294.                 MoveTo(xValueLoc, vloc);
  295.                 DrawRGB(index);
  296.                 DrawString('    ');
  297.                 SetPort(tPort);
  298.             end;
  299.     end;
  300.  
  301.  
  302.     procedure FindPoints (var x1, y1, x2, y2: integer);
  303.     begin
  304.         with info^ do begin
  305.                 if ColorStart >= 0 then begin
  306.                         x1 := ColorStart;
  307.                         y1 := 0;
  308.                     end
  309.                 else begin
  310.                         x1 := 0;
  311.                         if ColorEnd > ColorStart then
  312.                             y1 := -ColorStart * 255 div (ColorEnd - ColorStart)
  313.                         else
  314.                             y1 := 0;
  315.                     end;
  316.                 if ColorEnd <= 255 then begin
  317.                         x2 := ColorEnd;
  318.                         y2 := 255;
  319.                     end
  320.                 else begin
  321.                         x2 := 255;
  322.                         if ColorEnd > ColorStart then
  323.                             y2 := 255 * (255 - ColorStart) div (ColorEnd - ColorStart)
  324.                         else
  325.                             y2 := 255;
  326.                     end;
  327.             end;
  328.     end;
  329.  
  330.  
  331.     procedure UpdateMap;
  332.         var
  333.             r: rect;
  334.             x, y, i, h1, h2, h3, v1, v2, v3, dx, dy: integer;
  335.             xcenter, ycenter, brightness, islope, thumb: integer;
  336.             width, max: integer;
  337.             table: LookupTable;
  338.             hrect: rect;
  339.             slope: extended;
  340.             area, value, sum: LongInt;
  341.             p1x, p1y, p2x, p2y: integer;
  342.     begin
  343.         with info^ do begin
  344.                 FindPoints(p1x, p1y, p2x, p2y);
  345.                 SetPort(MapWindow);
  346.                 PenNormal;
  347.                 EraseRect(MapRect2);
  348.                 FrameRect(MapRect1);
  349.                 if LutMode = CustomGrayscale then begin
  350.                         GetLookupTable(table);
  351.                         MoveTo(gmRectLeft, gmRectBottom - 1);
  352.                         for i := 0 to 63 do begin
  353.                                 x := gmRectLeft + i;
  354.                                 y := gmRectBottom - table[i * 4] div 4 - 1;
  355.                                 LineTo(x, y);
  356.                             end;
  357.                         EraseRect(gmSlide1i);
  358.                         EraseRect(gmSlide2i);
  359.                         exit(UpdateMap);
  360.                     end;
  361.                 h1 := gmRectLeft + p1x div 4;
  362.                 v1 := gmRectBottom - 1 - (p1y div 4);
  363.                 h2 := gmRectLeft + p2x div 4;
  364.                 v2 := gmRectBottom - 1 - (p2y div 4);
  365.                 MoveTo(gmRectLeft, gmRectBottom - 1);
  366.                 LineTo(h1, v1);
  367.                 LineTo(h2, v2);
  368.                 LineTo(gmRectRight - 1, gmRectTop);
  369.                 SetRect(hrect, h1 - 1, v1 - 1, h1 + 2, v1 + 2);
  370.                 PaintRect(hrect); {First handle}
  371.                 SetRect(hrect, h2 - 1, v2 - 1, h2 + 2, v2 + 2);
  372.                 PaintRect(hrect); {Last handle}
  373.                 dx := p2x - p1x;
  374.                 dy := p2y - p1y;
  375.                 xcenter := p1x + dx div 2;
  376.                 ycenter := p1y + dy div 2;
  377.                 h3 := gmRectLeft + xcenter div 4;
  378.                 v3 := gmRectBottom - 1 - (ycenter div 4);
  379.                 SetRect(hrect, h3 - 1, v3 - 1, h3 + 2, v3 + 2);
  380.                 PaintRect(hrect); {Center handle}
  381.                 thumb := gmSlideHeight - 2;
  382.                 max := gmSlideWidth - thumb - 2;
  383.                 width := ColorEnd - ColorStart;
  384.                 brightness := trunc(max * ((ColorStart + width) / (width + 255)));
  385.                 with gmSlide1 do
  386.                     SetRect(hrect, left + brightness + 1, top + 1, left + brightness + thumb + 1, top + thumb + 1);
  387.                 EraseRect(gmSlide1i);
  388.                 PaintRect(hrect);  {Thumb for contrast control}
  389.                 if dx <> 0 then
  390.                     slope := dy / dx
  391.                 else
  392.                     slope := 1000.0;
  393.                 if slope > 1.0 then begin
  394.                         if dy <> 0 then
  395.                             slope := 2.0 - dx / dy
  396.                         else
  397.                             slope := 2.0;
  398.                     end;
  399.                 islope := trunc(slope * 0.5 * (gmSlideWidth - thumb - 2.0));
  400.                 with gmSlide2 do
  401.                     SetRect(hrect, left + islope + 1, top + 1, left + islope + thumb + 1, top + thumb + 1);
  402.                 EraseRect(gmSlide2i);
  403.                 PaintRect(hrect);  {Thumb for contrast control}
  404.                 if ScreenDepth <> 8 then begin
  405.                         if ScreenDepth > 2 then
  406.                             DrawLut;
  407.                         UpdatePicWindow;
  408.                     end;
  409.             end;
  410.     end;
  411.  
  412.  
  413.     procedure UpdateThreshold;
  414.         var
  415.             level: integer;
  416.     begin
  417.         DrawLabels('Thresh:', '', '');
  418.         ShowMessage('');
  419.         with info^ do
  420.             repeat
  421.                 SetPort(LUTWindow);
  422.                 level := GetVLoc;
  423.                 if level <= 255 then begin
  424.                         ColorStart := level;
  425.                         ColorEnd := level;
  426.                         UpdateLUT;
  427.                         UpdateMap;
  428.                     end;
  429.                 Show1Value(level, NoValue);
  430.             until not Button;
  431.     end;
  432.  
  433.  
  434.     procedure UpdateDensitySlice;
  435.         var
  436.             mloc, saveloc, width, delta: integer;
  437.             adjust: (lower, upper, both);
  438.     begin
  439.         DrawLabels('Lower:', 'Upper:', '');
  440.         SetPort(LUTWindow);
  441.         mloc := getvloc;
  442.         saveloc := mloc;
  443.         width := SliceEnd - SliceStart + 1;
  444.         adjust := lower;
  445.         if mloc > (SliceStart + width div 4) then
  446.             adjust := both;
  447.         if mloc > (SliceEnd - width div 4) then
  448.             adjust := upper;
  449.         if (SliceStart = SliceEnd) and (abs(mloc - SliceStart) <= 2) and (SliceStart > 1) and (SliceEnd < 254) then
  450.             adjust := both;
  451.         while button do begin
  452.                 width := SliceEnd - SliceStart + 1;
  453.                 mloc := getvloc;
  454.                 delta := mloc - saveloc;
  455.                 saveloc := mloc;
  456.                 case adjust of
  457.                     lower:  begin
  458.                             SliceStart := mloc;
  459.                             if SliceStart < 1 then
  460.                                 SliceStart := 1;
  461.                             if SliceStart > SliceEnd then
  462.                                 SliceStart := SliceEnd;
  463.                         end;
  464.                     upper:  begin
  465.                             SliceEnd := mloc;
  466.                             if SliceEnd > 254 then
  467.                                 SliceEnd := 254;
  468.                             if SliceEnd < SliceStart then
  469.                                 SliceEnd := SliceStart;
  470.                         end;
  471.                     both:  begin
  472.                             if mloc <= 1 then begin
  473.                                     SliceStart := 1;
  474.                                     SliceEnd := width;
  475.                                 end
  476.                             else if mloc >= 254 then begin
  477.                                     SliceEnd := 254;
  478.                                     SliceStart := 254 - width + 1;
  479.                                 end
  480.                             else if ((SliceStart + delta) >= 1) and ((SliceEnd + delta) <= 254) then begin
  481.                                     SliceStart := SliceStart + delta;
  482.                                     SliceEnd := SliceEnd + delta;
  483.                                 end;
  484.                         end;
  485.                 end; {case}
  486.                 DrawDensitySlice(OptionKeyDown);
  487.                 ShowLUTValues(SliceStart, SliceEnd);
  488.             end; {while}
  489.         DrawDensitySlice(false)
  490.     end;
  491.  
  492.  
  493.     procedure EditExtraColors (entry: integer);
  494.         var
  495.             where: point;
  496.             inRGBColor, OutRGBColor: RGBColor;
  497.     begin
  498.         if (entry <> WhiteIndex) and (entry <> BlackIndex) then begin
  499.                 inRGBColor := ExtraColors[entry];
  500.                 outRGBColor := inRGBColor;
  501.                 where.h := 0;
  502.                 where.v := 0;
  503.                 InitCursor;
  504.                 if GetColor(where, 'Pick a color, any color...', inRGBColor, outRGBColor) then
  505.                     with info^ do begin
  506.                             ExtraColors[entry] := OutRGBColor;
  507.                             changes := true;
  508.                             LoadLUT(cTable);
  509.                         end
  510.             end
  511.         else
  512.             PutMessage('Sorry, but you can not edit white or black.');
  513.     end;
  514.  
  515.  
  516.     function GetColorFromLUT (DoubleClick: boolean): integer;
  517.         var
  518.             mloc, color, i: integer;
  519.             loc: point;
  520.     begin
  521.         SetPort(LUTWindow);
  522.         GetMouse(loc);
  523.         if loc.v > 255 then begin
  524.                 color := 0;
  525.                 for i := 1 to nExtraColors + 2 do
  526.                     if PtInRect(loc, ExtraColorsRect[i]) then
  527.                         Color := ExtraColorsEntry[i];
  528.                 if DoubleClick then
  529.                     EditExtraColors(color);
  530.                 GetColorFromLUT := color;
  531.             end
  532.         else
  533.             GetColorFromLUT := loc.v;
  534.     end;
  535.  
  536.  
  537.     function isGrayScaleLUT: boolean;
  538.         var
  539.             i: integer;
  540.             GrayScaleLUT: boolean;
  541.     begin
  542.         with info^ do begin
  543.                 GrayscaleLUT := true;
  544.                 i := 0;
  545.                 repeat
  546.                     with cTable[i].rgb do
  547.                         GrayscaleLUT := GrayscaleLUT and (red = green) and (green = blue);
  548.                     i := i + 1;
  549.                 until (i = 256) or not GrayscaleLUT;
  550.                 isGrayScaleLUT := GrayScaleLUT;
  551.             end;
  552.     end;
  553.  
  554.  
  555.     procedure SetupPseudocolor;
  556.         var
  557.             i: integer;
  558.     begin
  559.         with info^ do begin
  560.                 DisableDensitySlice;
  561.                 Thresholding := false;
  562.                 for i := 1 to 254 do
  563.                     with cTable[i].rgb do begin
  564.                             RedLUT[i] := band(bsr(red, 8), 255);
  565.                             GreenLUT[i] := band(bsr(green, 8), 255);
  566.                             BlueLUT[i] := band(bsr(blue, 8), 255);
  567.                         end;
  568.                 RedLUT[0] := RedLUT[1];
  569.                 GreenLUT[0] := GreenLUT[1];
  570.                 BlueLUT[0] := BlueLUT[1];
  571.                 RedLUT[255] := RedLUT[254];
  572.                 GreenLUT[255] := GreenLUT[254];
  573.                 BlueLUT[255] := BlueLUT[254];
  574.                 nColors := 256;
  575.                 ColorStart := 0;
  576.                 ColorEnd := 255;
  577.                 FillColor1 := ctable[1].rgb;
  578.                 FillColor2 := ctable[254].rgb;
  579.                 InvertedColorTable := false;
  580.             end;
  581.     end;
  582.  
  583.  
  584.     procedure ShowLabels;
  585.     begin
  586.         with info^ do
  587.             if DataType <> EightBits then
  588.                 DrawLabels('Min:', 'Max:', '')
  589.             else
  590.                 DrawLabels('Lower:', 'Upper:', '');
  591.     end;
  592.  
  593.  
  594.     procedure AdjustLUT;
  595.         const
  596.             MinWidth = 8;
  597.         var
  598.             mloc, saveloc, width, delta, cstart, cend: integer;
  599.             adjust: (lower, upper, both);
  600.             loc: point;
  601.     begin
  602.         with info^ do begin
  603.                 SetPort(LUTWindow);
  604.                 SetupLutUndo;
  605.                 ShowLabels;
  606.                 mloc := getvloc;
  607.                 saveloc := mloc;
  608.                 cstart := ColorStart;
  609.                 if cstart < 0 then
  610.                     cstart := 0;
  611.                 cend := ColorEnd;
  612.                 if cend > 255 then
  613.                     cend := 255;
  614.                 width := cend - cstart + 1;
  615.                 adjust := lower;
  616.                 if mloc > (cstart + width div 4) then
  617.                     adjust := both;
  618.                 if mloc > (cend - width div 4) then
  619.                     adjust := upper;
  620.                 while button do begin
  621.                         SetPort(LUTWindow);
  622.                         GetMouse(loc);
  623.                         mloc := loc.v;
  624.                         delta := mloc - saveloc;
  625.                         saveloc := mloc;
  626.                         case adjust of
  627.                             lower:  begin
  628.                                     ColorStart := mloc;
  629.                                     cend := ColorEnd;
  630.                                     if cend > 255 then
  631.                                         cend := 255;
  632.                                     if ColorStart > (cend - MinWidth) then
  633.                                         ColorStart := cend - MinWidth;
  634.                                 end;
  635.                             upper:  begin
  636.                                     ColorEnd := mloc;
  637.                                     cstart := ColorStart;
  638.                                     if cstart < 0 then
  639.                                         cstart := 0;
  640.                                     if ColorEnd < (cstart + MinWidth) then
  641.                                         ColorEnd := cstart + MinWidth;
  642.                                 end;
  643.                             both: 
  644.                                 if (mloc >= 0) and (mloc <= 255) then begin
  645.                                         ColorStart := ColorStart + delta;
  646.                                         ColorEnd := ColorEnd + delta;
  647.                                     end;
  648.                         end;
  649.                         UpdateLUT;
  650.                         UpdateMap;
  651.                         ShowLUTValues(ColorStart, ColorEnd);
  652.                     end;
  653.             end; {with info}
  654.     end;
  655.  
  656.  
  657.     procedure RotateLUT;
  658.         var
  659.             vstart, i, j, delta: integer;
  660.             loc: point;
  661.             TempTable: MyCSpecArray;
  662.     begin
  663.         with info^ do begin
  664.                 SetPort(LUTWindow);
  665.                 GetMouse(loc);
  666.                 vstart := loc.v;
  667.                 repeat
  668.                     GetMouse(loc);
  669.                     delta := vstart - loc.v;
  670.                     for i := 1 to 254 do begin {0 is resevred for white and 255 for black}
  671.                             j := i + delta;
  672.                             if j > 254 then
  673.                                 j := j - 254;
  674.                             if j > 254 then
  675.                                 j := 254;
  676.                             if j < 1 then
  677.                                 j := j + 254;
  678.                             if j < 1 then
  679.                                 j := 1;
  680.                             TempTable[i] := cTable[j]
  681.                         end;
  682.                     cTable := TempTable;
  683.                     LoadLUT(cTable);
  684.                     vstart := loc.v;
  685.                 until not button;
  686.                 SetupPseudocolor;
  687.                 ColorTable := CustomTable;
  688.             end;
  689.     end;
  690.  
  691.  
  692.     procedure DoMouseDownInLUT (event: EventRecord);
  693.         var
  694.             color: integer;
  695.             DoubleClick: boolean;
  696.     begin
  697.         with info^ do begin
  698.                 if CurrentTool = PickerTool then
  699.                     DoubleClick := (TickCount - LutTime) < GetDblTime
  700.                 else
  701.                     DoubleClick := false;
  702.                 LutTime := TickCount;
  703.                 if (CurrentTool <> LutTool) and (CurrentTool <> Wand) then begin
  704.                         color := GetColorFromLUT(DoubleClick);
  705.                         if (CurrentTool = eraser) or OptionKeyDown then
  706.                             SetBackgroundColor(color)
  707.                         else
  708.                             SetForegroundColor(color);
  709.                         if not DoubleClick then
  710.                             exit(DoMouseDownInLUT);
  711.                     end;
  712.                 if Thresholding then begin
  713.                         UpdateThreshold;
  714.                         exit(DoMouseDownInLUT)
  715.                     end;
  716.                 if DoubleClick then begin
  717.                         if DensitySlicing and (CurrentTool = PickerTool) then begin
  718.                                 if EditSliceColor then
  719.                                     exit(DoMouseDownInLUT);
  720.                             end;
  721.                         if CurrentTool = PickerTool then begin
  722.                                 EditPseudoColors;
  723.                                 exit(DoMouseDownInLUT)
  724.                             end;
  725.                     end; {if DoubleClick}
  726.                 if ((CurrentTool = LutTool) or (CurrentTool = Wand)) and DensitySlicing then begin
  727.                         UpdateDensitySlice;
  728.                         exit(DoMouseDownInLUT);
  729.                     end;
  730.                 if OptionKeyDown then
  731.                     RotateLUT
  732.                 else
  733.                     AdjustLUT;
  734.             end; {with}
  735.     end;
  736.  
  737.  
  738.     procedure DoCopyColor;
  739.     begin
  740.         with info^ do begin
  741.                 if ForegroundIndex = WhiteIndex then begin
  742.                         ClipboardColor := WhiteRGB;
  743.                         exit(DoCopyColor);
  744.                     end;
  745.                 if ForegroundIndex = BlackIndex then begin
  746.                         ClipboardColor := BlackRGB;
  747.                         exit(DoCopyColor);
  748.                     end;
  749.                 with cTable[ForegroundIndex].rgb do begin
  750.                         ClipboardColor.red := red;
  751.                         ClipboardColor.green := green;
  752.                         ClipboardColor.blue := blue;
  753.                     end;
  754.                 WhatsOnClip := AColor;
  755.                 ClipTextInBuffer := false;
  756.             end;
  757.     end;
  758.  
  759.  
  760.     procedure PasteColor;
  761.         var
  762.             CurrentColorIndex: integer;
  763.     begin
  764.         with info^ do begin
  765.                 if CurrentTool = PickerTool then begin
  766.                         if ForegroundIndex < ColorStart then begin
  767.                                 FillColor1 := ClipboardColor;
  768.                                 UpdateLUT;
  769.                                 exit(PasteColor);
  770.                             end;
  771.                         if ForegroundIndex > ColorEnd then begin
  772.                                 FillColor2 := ClipboardColor;
  773.                                 UpdateLUT;
  774.                                 exit(PasteColor);
  775.                             end;
  776.                         CurrentColorIndex := GetPseudoColorIndex;
  777.                         with ClipboardColor do begin
  778.                                 RedLUT[CurrentColorIndex] := bsr(red, 8);
  779.                                 GreenLUT[CurrentColorIndex] := bsr(green, 8);
  780.                                 BlueLUT[CurrentColorIndex] := bsr(blue, 8);
  781.                             end;
  782.                         ColorTable := CustomTable;
  783.                         UpdateLUT;
  784.                     end
  785.                 else
  786.                     beep;
  787.             end;
  788.     end;
  789.  
  790.  
  791.     procedure InvertPalette;
  792.         var
  793.             TempRed, TempGreen, TempBlue: LutArray;
  794.             i, LastColor: integer;
  795.             TempTable: MyCSpecArray;
  796.             TempFill: rgbColor;
  797.     begin
  798.         DisableDensitySlice;
  799.         DisableThresholding;
  800.         with info^ do begin
  801.                 TempRed := RedLUT;
  802.                 TempGreen := GreenLUT;
  803.                 TempBlue := BlueLUT;
  804.                 LastColor := ncolors - 1;
  805.                 for i := 0 to LastColor do begin
  806.                         RedLUT[i] := TempRed[LastColor - i];
  807.                         GreenLUT[i] := TempGreen[LastColor - i];
  808.                         BlueLUT[i] := TempBlue[LastColor - i];
  809.                     end;
  810.                 TempFill := FillColor1;
  811.                 FillColor1 := FillColor2;
  812.                 FillColor2 := TempFill;
  813.                 InvertedColorTable := not InvertedColorTable;
  814.                 IdentityFunction := false;
  815.             end;
  816.     end;
  817.  
  818.  
  819.     procedure DrawMap;
  820.         var
  821.             x, y, i: integer;
  822.             table: LookupTable;
  823.     begin
  824.         SetPort(MapWindow);
  825.         PenNormal;
  826.         TextFont(ApplFont);
  827.         TextSize(9);
  828.         with gmSlide1 do
  829.             MoveTo(left - 6, bottom);
  830.         DrawChar('B');
  831.         with gmSlide2 do
  832.             MoveTo(left - 6, bottom);
  833.         DrawChar('C');
  834.         FrameRect(gmSlide1);
  835.         FrameRect(gmSlide2);
  836.         FrameRect(gmIcon1);
  837.         FrameRect(gmIcon2);
  838.         with gmIcon1 do begin
  839.                 MoveTo(left, top + 10);
  840.                 LineTo(left + 5, top + 10);
  841.                 LineTo(left + 12, top + 3);
  842.                 LineTo(left + gmIconWidth - 1, top + 3);
  843.             end;
  844.         with gmIcon2 do begin
  845.                 MoveTo(left, top + 10);
  846.                 LineTo(left + gmIconWidth div 2, top + 10);
  847.                 LineTo(left + gmIconWidth div 2, top + 3);
  848.                 LineTo(left + gmIconWidth - 1, top + 3);
  849.             end;
  850.         UpdateMap;
  851.         GrayMapReady := true;
  852.     end;
  853.  
  854.  
  855.     procedure ResetGrayMap;
  856.         var
  857.             i: integer;
  858.     begin
  859.         with info^ do begin
  860.                 DisableDensitySlice;
  861.                 for i := 0 to 255 do begin
  862.                         RedLut[i] := 255 - i;
  863.                         GreenLut[i] := 255 - i;
  864.                         BlueLut[i] := 255 - i;
  865.                     end;
  866.                 FillColor1 := WhiteRGB;
  867.                 FillColor2 := BlackRGB;
  868.                 ColorStart := 0;
  869.                 ColorEnd := 255;
  870.                 nColors := 256;
  871.                 ColorTable := CustomTable;
  872.                 LUTMode := Grayscale;
  873.                 UpdateLUT;
  874.                 if GrayMapReady then
  875.                     UpdateMap;
  876.                 IdentityFunction := true;
  877.                 InvertedColorTable := false;
  878.             end;
  879.     end;
  880.  
  881.  
  882.     procedure AdjustBrightness;
  883.         var
  884.             loc, max, thumb, xcenter, ycenter, width: integer;
  885.             p: point;
  886.     begin
  887.         with info^ do begin
  888.                 thumb := gmSlideHeight - 2;
  889.                 max := gmSlideWidth - thumb - 2;
  890.                 width := ColorEnd - ColorStart;
  891.                 ShowLabels;
  892.                 repeat
  893.                     GetMouse(p);
  894.                     loc := p.h - gmSlide1.left - 2;
  895.                     if loc < 0 then
  896.                         loc := 0;
  897.                     if loc > max then
  898.                         loc := max;
  899.                     ColorStart := -width + round((width + 255) * (loc / max));
  900.                     ColorEnd := ColorStart + width;
  901.                     UpdateLUT;
  902.                     UpdateMap;
  903.                     ShowLUTValues(ColorStart, ColorEnd);
  904.                 until not button;
  905.                 IdentityFunction := false;
  906.             end; {with}
  907.     end;
  908.  
  909.  
  910.     procedure AdjustContrast;
  911.         var
  912.             p: point;
  913.             loc, max, HalfMax, thumb: integer;
  914.             slope, center: extended;
  915.     begin
  916.         with info^ do begin
  917.                 thumb := gmSlideHeight - 2;
  918.                 max := gmSlideWidth - thumb - 2;
  919.                 HalfMax := max div 2;
  920.                 center := ColorStart + (ColorEnd - ColorStart) / 2.0;
  921.                 ShowLabels;
  922.                 repeat
  923.                     GetMouse(p);
  924.                     loc := p.h - gmSlide2.left - 2;
  925.                     if loc < 0 then
  926.                         loc := 0;
  927.                     if loc > max then
  928.                         loc := max;
  929.                     if loc <= HalfMax then
  930.                         slope := loc / HalfMax
  931.                     else if loc < max then
  932.                         slope := HalfMax / (max - loc)
  933.                     else
  934.                         slope := 1000.0;
  935.                     if slope > 0.0 then begin
  936.                             ColorStart := round(center - 127.5 / slope);
  937.                             ColorEnd := round(center + 127.5 / slope);
  938.                         end
  939.                     else begin
  940.                             ColorStart := round(center - MaxColor);
  941.                             ColorEnd := round(center + MaxColor);
  942.                         end;
  943.                     if ColorEnd < 0 then
  944.                         ColorEnd := 0;
  945.                     if ColorStart > 255 then
  946.                         ColorStart := 255;
  947.                     UpdateLUT;
  948.                     UpdateMap;
  949.                     ShowLUTValues(ColorStart, ColorEnd);
  950.                 until not button;
  951.                 IdentityFunction := false;
  952.             end; {with}
  953.     end;
  954.  
  955.  
  956.     procedure ConvertMouseToXY (p: point; var x, y: integer);
  957.     begin
  958.         x := (p.h - gmRectLeft) * 4;
  959.         if x < 0 then
  960.             x := 0;
  961.         if x > 255 then
  962.             x := 255;
  963.         y := (gmRectBottom - p.v) * 4;
  964.         if y < 0 then
  965.             y := 0;
  966.         if y > 255 then
  967.             y := 255;
  968.     end;
  969.  
  970.  
  971.     procedure DoFreehandEditing;
  972.         var
  973.             p: point;
  974.             x1, x2, y, i: integer;
  975.             FirstTime: boolean;
  976.     begin
  977.         with info^ do begin
  978.                 LUTMode := CustomGrayscale;
  979.                 SetPort(MapWindow);
  980.                 FirstTime := true;
  981.                 while button do begin
  982.                         x1 := x2;
  983.                         GetMouse(p);
  984.                         ConvertMouseToXY(p, x2, y);
  985.                         if x2 > 252 then
  986.                             x2 := 252;
  987.                         if FirstTime then begin
  988.                                 x1 := x2;
  989.                                 FirstTime := false;
  990.                             end;
  991.                         if x2 >= x1 then
  992.                             for i := x1 to x2 + 3 do
  993.                                 with cTable[i].rgb do begin
  994.                                         red := bsl(255 - y, 8);
  995.                                         green := bsl(255 - y, 8);
  996.                                         blue := bsl(255 - y, 8);
  997.                                     end
  998.                         else
  999.                             for i := x1 + 3 downto x2 do
  1000.                                 with cTable[i].rgb do begin
  1001.                                         red := bsl(255 - y, 8);
  1002.                                         green := bsl(255 - y, 8);
  1003.                                         blue := bsl(255 - y, 8);
  1004.                                     end;
  1005.                         DrawMap;
  1006.                         LoadLUT(cTable);
  1007.                     end;
  1008.                 if not isGrayscaleLut then
  1009.                     LutMode := ColorLut;
  1010.             end;
  1011.     end;
  1012.  
  1013.  
  1014.     procedure DisableThresholding;
  1015.     begin
  1016.         with info^ do
  1017.             if thresholding then begin
  1018.                     ColorStart := SaveColorStart;
  1019.                     ColorEnd := SaveColorEnd;
  1020.                     FillColor1 := SaveFill1;
  1021.                     FillColor2 := SaveFill2;
  1022.                     UpdateLut;
  1023.                     UpdateMap;
  1024.                     Thresholding := false;
  1025.                 end;
  1026.     end;
  1027.  
  1028.  
  1029.     procedure EnableThresholding (level: integer);
  1030.     begin
  1031.         with info^ do begin
  1032.                 if thresholding then
  1033.                     DisableThresholding;
  1034.                 SaveColorStart := ColorStart;
  1035.                 SaveColorEnd := ColorEnd;
  1036.                 ColorStart := level;
  1037.                 ColorEnd := level;
  1038.                 SaveFill1 := FillColor1;
  1039.                 SaveFill2 := FillColor2;
  1040.                 FillColor1 := WhiteRGB;
  1041.                 FillColor2 := BlackRGB;
  1042.                 UpdateLut;
  1043.                 UpdateMap;
  1044.                 Thresholding := true;
  1045.                 if not macro then
  1046.                     SelectLutTool;
  1047.             end;
  1048.     end;
  1049.  
  1050.  
  1051.     procedure ResetMap;
  1052.     begin
  1053.         with info^ do begin
  1054.                 ColorStart := 0;
  1055.                 ColorEnd := 255;
  1056.                 if Thresholding then begin
  1057.                         FillColor1 := SaveFill1;
  1058.                         FillColor2 := SaveFill2;
  1059.                     end;
  1060.                 IdentityFunction := LutMode = Grayscale;
  1061.                 UpdateLUT;
  1062.                 UpdateMap;
  1063.             end;
  1064.     end;
  1065.  
  1066.  
  1067.     procedure DoMouseDownInMap;
  1068.         var
  1069.             r: rect;
  1070.             x, y, p1Dist, p2Dist: integer;
  1071.             mode: (StartPoint, EndPoint, Brightness, AdjustThreshold);
  1072.             p: point;
  1073.             pressed: boolean;
  1074.             x1, y1, x2, y2: integer;
  1075.             xintercept: integer;
  1076.             deltax, deltay: LongInt;
  1077.  
  1078.         procedure DoFixup;
  1079.         begin
  1080.             with info^ do
  1081.                 if ((x1 = 0) and (x2 = 0)) or ((x1 = 255) and (x2 = 255)) then begin
  1082.                         y1 := 0;
  1083.                         y2 := 255;
  1084.                     end;
  1085.         end;
  1086.  
  1087.     begin
  1088.         with info^ do begin
  1089.                 DisableDensitySlice;
  1090.                 if OptionKeyDown then begin
  1091.                         DoFreehandEditing;
  1092.                         exit(DoMouseDownInMap);
  1093.                     end;
  1094.                 if LUTMode = CustomGrayscale then
  1095.                     ResetGrayMap;
  1096.                 FindPoints(x1, y1, x2, y2);
  1097.                 SetPort(MapWindow);
  1098.                 GetMouse(p);
  1099.                 if PtInRect(p, gmIcon1) then begin
  1100.                         InvertRect(gmIcon1);
  1101.                         pressed := true;
  1102.                         while Button and pressed do begin
  1103.                                 GetMouse(p);
  1104.                                 if not PtInRect(p, gmIcon1) then begin
  1105.                                         InvertRect(gmIcon1);
  1106.                                         pressed := false;
  1107.                                     end;
  1108.                             end;
  1109.                         repeat
  1110.                         until not button;
  1111.                         if pressed then begin
  1112.                                 InvertRect(gmIcon1);
  1113.                                 ResetMap;
  1114.                                 exit(DoMouseDownInMap)
  1115.                             end;
  1116.                     end;
  1117.                 if PtInRect(p, gmIcon2) then begin
  1118.                         InvertRect(gmIcon2);
  1119.                         pressed := true;
  1120.                         while Button and pressed do begin
  1121.                                 GetMouse(p);
  1122.                                 if not PtInRect(p, gmIcon2) then begin
  1123.                                         InvertRect(gmIcon2);
  1124.                                         pressed := false;
  1125.                                     end;
  1126.                             end;
  1127.                         repeat
  1128.                         until not button;
  1129.                         if pressed then begin
  1130.                                 InvertRect(gmIcon2);
  1131.                                 if Thresholding then
  1132.                                     DisableThresholding
  1133.                                 else
  1134.                                     EnableThresholding(128);
  1135.                                 exit(DoMouseDownInMap)
  1136.                             end;
  1137.                     end;
  1138.                 if PtInRect(p, gmSlide1) then
  1139.                     AdjustBrightness;
  1140.                 if PtInRect(p, gmSlide2) then
  1141.                     AdjustContrast;
  1142.                 if p.v > (gmRectBottom + 4) then begin
  1143.                         if not thresholding and ((x2 - x1) <= 1) then begin
  1144.                                 thresholding := true;
  1145.                                 SaveFill1 := FillColor1;
  1146.                                 SaveFill2 := FillColor2;
  1147.                             end;
  1148.                         exit(DoMouseDownInMap);
  1149.                     end;
  1150.                 if LutMode = CustomGrayscale then
  1151.                     LutMode := Grayscale;
  1152.                 GetMouse(p);
  1153.                 ConvertMouseToXY(p, x, y);
  1154.                 if (x <= 24) or (y <= 32) then
  1155.                     mode := StartPoint
  1156.                 else if (x >= 224) or (y >= 232) then
  1157.                     mode := EndPoint
  1158.                 else if thresholding then
  1159.                     mode := AdjustThreshold
  1160.                 else
  1161.                     mode := brightness;
  1162.                 if mode = AdjustThreshold then
  1163.                     DrawLabels('Thresh:', '', '')
  1164.                 else
  1165.                     ShowLabels;
  1166.                 repeat
  1167.                     case mode of
  1168.                         StartPoint:  begin
  1169.                                 if thresholding then begin
  1170.                                         FillColor1 := SaveFill1;
  1171.                                         FillColor2 := SaveFill2;
  1172.                                     end;
  1173.                                 if x > y then
  1174.                                     y := 0
  1175.                                 else
  1176.                                     x := 0;
  1177.                                 x1 := x;
  1178.                                 if x1 > x2 then
  1179.                                     x2 := x1;
  1180.                                 y1 := y;
  1181.                                 if y1 > y2 then
  1182.                                     y2 := y1;
  1183.                                 DoFixUp;
  1184.                             end;
  1185.                         EndPoint:  begin
  1186.                                 if thresholding then begin
  1187.                                         FillColor1 := SaveFill1;
  1188.                                         FillColor2 := SaveFill2;
  1189.                                     end;
  1190.                                 if x > y then
  1191.                                     x := 255
  1192.                                 else
  1193.                                     y := 255;
  1194.                                 x2 := x;
  1195.                                 if x2 < x1 then
  1196.                                     x1 := x2;
  1197.                                 y2 := y;
  1198.                                 if y2 < y1 then
  1199.                                     y1 := y2;
  1200.                                 DoFixUp;
  1201.                             end;
  1202.                         Brightness:  begin
  1203.                                 deltax := x2 - x1;
  1204.                                 deltay := y2 - y1;
  1205.                                 if deltax = 0 then begin
  1206.                                         x1 := x;
  1207.                                         y1 := 0;
  1208.                                         x2 := x;
  1209.                                         y2 := 255;
  1210.                                     end
  1211.                                 else if deltay = 0 then begin
  1212.                                         x1 := 0;
  1213.                                         y1 := y;
  1214.                                         x2 := 255;
  1215.                                         y2 := y;
  1216.                                     end
  1217.                                 else begin
  1218.                                         x1 := x - y * deltax div deltay;
  1219.                                         xIntercept := x1;
  1220.                                         y1 := 0;
  1221.                                         if x1 < 0 then begin
  1222.                                                 y1 := -deltay * x1 div deltaX;
  1223.                                                 x1 := 0;
  1224.                                             end;
  1225.                                         y2 := 255;
  1226.                                         x2 := 255 * deltax div deltay;
  1227.                                         if xIntercept < 0 then
  1228.                                             x2 := x2 + xIntercept
  1229.                                         else
  1230.                                             x2 := x2 + x1;
  1231.                                         if x2 > 255 then begin
  1232.                                                 y2 := 255 - (x2 - 255) * deltay div deltax;
  1233.                                                 x2 := 255;
  1234.                                             end;
  1235.                                     end;
  1236.                                 if x2 < 1 then
  1237.                                     x2 := 1;
  1238.                                 if y2 < 1 then
  1239.                                     y2 := 1;
  1240.                                 if x1 > 254 then
  1241.                                     x1 := 254;
  1242.                                 if y1 > 254 then
  1243.                                     y1 := 254;
  1244.                             end;
  1245.                         AdjustThreshold:  begin
  1246.                                 x1 := x;
  1247.                                 y1 := 0;
  1248.                                 x2 := x;
  1249.                                 y2 := 255;
  1250.                             end;
  1251.                     end; {case}
  1252. {showmessage(concat(long2str(x1), '  ', long2str(y1), '  ', long2str(x2), '  ', long2str(y2), cr, long2str(ColorStart), '  ', long2str(ColorEnd)));}
  1253.                     if y1 = 0 then
  1254.                         ColorStart := x1
  1255.                     else begin
  1256.                             if (y2 > y1) then
  1257.                                 ColorStart := -LongInt(x2 - x1) * y1 div (y2 - y1)
  1258.                             else
  1259.                                 ColorStart := -MaxColor;
  1260.                         end;
  1261.                     if y2 = 255 then
  1262.                         ColorEnd := x2
  1263.                     else begin
  1264.                             if (y2 > y1) then
  1265.                                 ColorEnd := 255 + LongInt(x2 - x1) * (255 - y2) div ((y2 - y1))
  1266.                             else
  1267.                                 ColorEnd := MaxColor;
  1268.                         end;
  1269.                     UpdateLUT;
  1270.                     UpdateMap;
  1271.                     if thresholding then
  1272.                         Show1Value(ColorStart, NoValue)
  1273.                     else
  1274.                         ShowLUTValues(ColorStart, ColorEnd);
  1275.                     GetMouse(p);
  1276.                     ConvertMouseToXY(p, x, y);
  1277.                 until not Button;
  1278.                 IdentityFunction := false;
  1279.                 if not thresholding and ((x2 - x1) <= 1) then begin
  1280.                         thresholding := true;
  1281.                         SaveFill1 := FillColor1;
  1282.                         SaveFill2 := FillColor2;
  1283.                     end;
  1284.             end; {with info}
  1285.     end;
  1286.  
  1287.  
  1288.     procedure DrawLUT;
  1289.         var
  1290.             tPort: GrafPtr;
  1291.             h, v, i: integer;
  1292.     begin
  1293.         GetPort(tPort);
  1294.         SetPort(LUTWindow);
  1295.         with LutWindow^ do begin
  1296.                 for v := 0 to 255 do begin
  1297.                         SetFColor(v);
  1298.                         MoveTo(0, v);
  1299.                         LineTo(cwidth, v)
  1300.                     end;
  1301.                 for i := 1 to nExtraColors + 2 do begin
  1302.                         SetFColor(ExtraColorsEntry[i]);
  1303.                         PaintRect(ExtraColorsRect[i]);
  1304.                     end;
  1305.                 TextFont(ApplFont);
  1306.                 TextSize(9);
  1307.                 with ExtraColorsRect[1] do
  1308.                     MoveTo(left + 3, bottom - 1);
  1309.                 SetFColor(BlackIndex);
  1310.                 DrawString('white');
  1311.                 with ExtraColorsRect[2] do
  1312.                     MoveTo(left + 4, bottom - 1);
  1313.                 InvertRect(ExtraColorsRect[2]);
  1314.                 DrawString('black');
  1315.                 InvertRect(ExtraColorsRect[2]);
  1316.             end;
  1317.         SetPort(tPort);
  1318.     end;
  1319.  
  1320.  
  1321.     function LoadPP2Palette: boolean;
  1322. {Loads COLR resource from PixelPaint 2.0 palette file.}
  1323.         var
  1324.             i: integer;
  1325.             size: LongInt;
  1326.             h: Handle;
  1327.             PPColorTable: record
  1328.                     ctSize: INTEGER;
  1329.                     table: array[0..255] of RGBColor;
  1330.                 end;
  1331.     begin
  1332.         h := GetResource('COLR', 999);
  1333.         size := GetHandleSize(handle(h));
  1334.         if (ResError = NoErr) and (size = 1538) then
  1335.             with info^ do begin
  1336.                     BlockMove(handle(h)^, @PPColorTable, SizeOf(PPColorTable));
  1337.                     with PPColorTable do begin
  1338.                             for i := 0 to 255 do
  1339.                                 cTable[i].rgb := table[i];
  1340.                         end;
  1341.                     LoadLUT(cTable);
  1342.                     LutMode := ColorLut;
  1343.                     SetupPseudocolor;
  1344.                     IdentityFunction := false;
  1345.                     LoadPP2Palette := true;
  1346.                 end
  1347.         else
  1348.             LoadPP2Palette := false;
  1349.         if h <> nil then
  1350.             DisposHandle(h);
  1351.     end;
  1352.  
  1353.  
  1354.     procedure LoadColorTable (theColorTable: CTabHandle);
  1355.         const
  1356.             ExpectedSize = 2056;
  1357.         var
  1358.             size: LongInt;
  1359.             MyColorTable: record
  1360.                     ctSeed: LONGINT;
  1361.                     transIndex: INTEGER;
  1362.                     ctSize: INTEGER;
  1363.                     ctTable: MyCSpecArray;
  1364.                 end;
  1365.     begin
  1366.         size := GetHandleSize(handle(theColorTable));
  1367.         if size < ExpectedSize then
  1368.             exit(LoadColorTable);
  1369.         if size > ExpectedSize then
  1370.             Size := ExpectedSize;
  1371.         BlockMove(handle(theColorTable)^, @MyColorTable, size);
  1372.         LoadLUT(MyColorTable.ctTable);
  1373.         with info^ do begin
  1374.                 cTable := MyColorTable.ctTable;
  1375.                 LutMode := ColorLut;
  1376.                 IdentityFunction := false;
  1377.             end;
  1378.         SetupPseudocolor;
  1379.     end;
  1380.  
  1381.  
  1382.     function LoadCLUTResource;{(id:integer):boolean}
  1383.         const
  1384.             ExpectedSize = 2056;
  1385.         var
  1386.             Size: LongInt;
  1387.             h: cTabHandle;
  1388.     begin
  1389.         DisableDensitySlice;
  1390.         h := GetCTable(id);
  1391.         size := GetHandleSize(handle(h));
  1392.         if (ResError <> NoErr) or (size < ExpectedSize) then begin
  1393.                 LoadCLUTResource := false;
  1394.                 if id = PixelpaintID then begin
  1395.                         if LoadPP2Palette then
  1396.                             LoadCLUTResource := true;
  1397.                     end;
  1398.                 if h <> nil then
  1399.                     DisposCTable(h);
  1400.                 exit(LoadCLUTResource)
  1401.             end;
  1402.         LoadColorTable(h);
  1403.         DisposCTable(h);
  1404.         LoadCLUTResource := true;
  1405.     end;
  1406.  
  1407.  
  1408.     procedure GetLookupTable;{(VAR table:LookupTable)}
  1409.         var
  1410.             i, r, g, b: integer;
  1411.             GrayscaleImage: boolean;
  1412.     begin
  1413.         with info^ do begin
  1414.                 if DensitySlicing then begin
  1415.                         for i := 0 to 255 do
  1416.                             if (i >= SliceStart) and (i <= SliceEnd) then begin
  1417.                                     if ThresholdToForeground then
  1418.                                         table[i] := ForegroundIndex
  1419.                                     else
  1420.                                         table[i] := i
  1421.                                 end
  1422.                             else begin
  1423.                                     if NonThresholdToBackground then
  1424.                                         table[i] := BackgroundIndex
  1425.                                     else
  1426.                                         table[i] := i
  1427.                                 end;
  1428.                         DisableDensitySlice;
  1429.                         exit(GetLookupTable);
  1430.                     end;
  1431.                 if (LutMode = GrayScale) or (LutMode = CustomGrayscale) then
  1432.                     for i := 0 to 255 do
  1433.                         table[i] := 255 - BSR(cTable[i].RGB.red, 8)
  1434.                 else begin
  1435.                         table[0] := 0;
  1436.                         for i := 1 to 254 do
  1437.                             with cTable[i].RGB do
  1438.                                 table[i] := 255 - trunc(band(bsr(red, 8), 255) * 0.3 + band(bsr(green, 8), 255) * 0.59 + band(bsr(blue, 8), 255) * 0.11);
  1439.                         table[255] := 255;
  1440.                     end;
  1441.             end; {with}
  1442.     end;
  1443.  
  1444.  
  1445.     procedure RedrawLUTWindow;
  1446.     begin
  1447.         LoadLUT(info^.cTable);
  1448.         cheight := 256 + (2 + nExtraColors) * ExtraColorsHeight;
  1449.         SizeWindow(LUTWindow, cwidth, cheight, true);
  1450.     end;
  1451.  
  1452.  
  1453.     procedure DrawDensitySlice (OptionKey: boolean);
  1454.         var
  1455.             i, tRed: integer;
  1456.     begin
  1457.         with info^ do begin
  1458.                 if OptionKey then begin
  1459.                         UndoLutChange;
  1460.                         exit(DrawDensitySlice);
  1461.                     end
  1462.                 else
  1463.                     for i := 0 to 255 do
  1464.                         if (i >= SliceStart) and (i <= SliceEnd) then
  1465.                             cTable[i].rgb := SliceColor
  1466.                         else
  1467.                             ctable[i].rgb := UndoInfo^.cTable[i].rgb;
  1468.                 LoadLUT(cTable);
  1469.                 if ScreenDepth <> 8 then begin
  1470.                         if ScreenDepth > 2 then
  1471.                             DrawLut;
  1472.                         UpdatePicWindow;
  1473.                     end;
  1474.             end;
  1475.     end;
  1476.  
  1477.  
  1478.     procedure SelectLutTool;
  1479.         var
  1480.             tPort: GrafPtr;
  1481.     begin
  1482.         if (CurrentTool <> LutTool) and (CurrentTool <> Wand) then begin
  1483.                 GetPort(tPort);
  1484.                 SetPort(ToolWindow);
  1485.                 InvalRect(ToolRect[CurrentTool]);
  1486.                 InvalRect(ToolRect[LutTool]);
  1487.                 CurrentTool := LutTool;
  1488.                 isSelectionTool := false;
  1489.                 SetPort(tPort);
  1490.             end;
  1491.     end;
  1492.  
  1493.  
  1494.     procedure EnableDensitySlice;
  1495.     begin
  1496.         if not DensitySlicing then begin
  1497.                 SetupLutUndo;
  1498.                 DrawDensitySlice(false);
  1499.                 DensitySlicing := true;
  1500.                 SelectLUTTool;
  1501.             end;
  1502.     end;
  1503.  
  1504.  
  1505.     procedure DoImportLut (fname: str255; vnum: integer);
  1506.         var
  1507.             err: OSErr;
  1508.             f, i: integer;
  1509.             ByteCount: LongInt;
  1510.             ImportedLUT: array[1..3] of packed array[0..255] of byte;
  1511.     begin
  1512.         DisableDensitySlice;
  1513.         err := fsopen(fname, vNum, f);
  1514.         ByteCount := 768;
  1515.         err := fsRead(f, ByteCount, @ImportedLUT);
  1516.         if err = NoErr then
  1517.             with info^ do begin
  1518.                     for i := 0 to 255 do
  1519.                         with cTable[i], cTable[i].rgb do begin
  1520.                                 value := 0;
  1521.                                 red := bsl(ImportedLUT[1, i], 8);
  1522.                                 green := bsl(ImportedLUT[2, i], 8);
  1523.                                 blue := bsl(ImportedLUT[3, i], 8);
  1524.                             end;
  1525.                     LoadLUT(cTable);
  1526.                     SetupPseudocolor;
  1527.                     LutMode := PseudoColor;
  1528.                     IdentityFunction := false;
  1529.                     if isGrayScaleLUT then
  1530.                         info^.LutMode := CustomGrayScale;
  1531.                     UpdateMap;
  1532.                 end
  1533.         else
  1534.             beep;
  1535.         err := fsClose(f);
  1536.     end;
  1537.  
  1538.  
  1539.     procedure OpenOldPalette (fname: str255; RefNum: integer);
  1540. {Opens palette files created by versions NIH Image earlier than 1.42.}
  1541.         var
  1542.             PaletteHeader: ColorArray;
  1543.             err, f, ColorWidth: integer;
  1544.             size: LongInt;
  1545.     begin
  1546.         DisableDensitySlice;
  1547.         err := fsopen(fname, RefNum, f);
  1548.         with info^ do begin
  1549.                 size := SizeOf(ColorArray);
  1550.                 err := fsread(f, size, @PaletteHeader);
  1551.                 nColors := PaletteHeader[0];
  1552.                 if nColors > MaxPseudocolors then
  1553.                     nColors := MaxPseudoColors;
  1554.                 ColorEnd := 255 - PaletteHeader[1];
  1555.                 ColorWidth := PaletteHeader[2];
  1556.                 ColorStart := ColorEnd - nColors * ColorWidth + 1;
  1557.                 if ColorStart < 0 then
  1558.                     ColorStart := 0;
  1559.                 FillColor1 := BlackRGB;
  1560.                 FillColor2 := BlackRGB;
  1561.                 err := fsread(f, size, @RedLut);
  1562.                 err := fsread(f, size, @GreenLut);
  1563.                 err := fsread(f, size, @BlueLut);
  1564.                 LutMode := PseudoColor;
  1565.                 InvertedColorTable := false;
  1566.             end;
  1567.         err := fsclose(f);
  1568.         UpdateLUT;
  1569.     end;
  1570.  
  1571.  
  1572.     procedure OpenNewPalette (fname: str255; RefNum: integer);
  1573. {Opens palette files created by versions of NIH Image later than 1.41.}
  1574.         var
  1575.             err, f: integer;
  1576.             count: LongInt;
  1577.             hdr: PaletteHeader;
  1578.     begin
  1579.         DisableDensitySlice;
  1580.         err := fsopen(fname, RefNum, f);
  1581.         with info^ do begin
  1582.                 count := SizeOf(PaletteHeader);
  1583.                 err := fsread(f, count, @hdr);
  1584.                 with hdr do begin
  1585.                         nColors := pnColors;
  1586.                         if nColors > 256 then
  1587.                             nColors := 256;
  1588.                         ColorStart := pColorStart;
  1589.                         ColorEnd := pColorEnd;
  1590.                         FillColor1 := pFill1;
  1591.                         FillColor2 := pFill2;
  1592.                         InvertedColorTable := false;
  1593.                     end;
  1594.                 count := nColors;
  1595.                 err := fsread(f, count, @RedLut);
  1596.                 count := nColors;
  1597.                 err := fsread(f, count, @GreenLut);
  1598.                 count := nColors;
  1599.                 err := fsread(f, count, @BlueLut);
  1600.                 LutMode := PseudoColor;
  1601.             end;
  1602.         err := fsclose(f);
  1603.         UpdateLUT;
  1604.     end;
  1605.  
  1606.  
  1607.     procedure OpenColorTable (fname: str255; RefNum: integer);
  1608.         var
  1609.             err: OSErr;
  1610.             f: integer;
  1611.             FileSize, count: LongInt;
  1612.             id: packed array[1..4] of char;
  1613.     begin
  1614.         err := fsopen(fname, RefNum, f);
  1615.         err := GetEOF(f, FileSize);
  1616.         count := SizeOf(id);
  1617.         err := fsread(f, count, @id);
  1618.         err := fsclose(f);
  1619.         if FileSize = 768 then
  1620.             DoImportLut(fname, RefNum)
  1621.         else if id = 'ICOL' then
  1622.             OpenNewPalette(fname, RefNum)
  1623.         else
  1624.             OpenOldPalette(fname, RefNum);
  1625.     end;
  1626.  
  1627.  
  1628.     procedure ImportPalette (FileType: OSType; fname: str255; vnum: integer);
  1629.         var
  1630.             RefNum: integer;
  1631.             ok: boolean;
  1632.             err: OSErr;
  1633.     begin
  1634.         err := SetVol(nil, vnum);
  1635.         refNum := OpenResFile(fname);
  1636.         if RefNum <> -1 then begin
  1637.                 if FileType = 'CLUT' then
  1638.                     ok := LoadClutResource(KlutzID)
  1639.                 else
  1640.                     ok := LoadClutResource(PixelPaintID); {Load PixelPaint or Canvas palette}
  1641.                 CloseResFile(RefNum);
  1642.                 if isGrayScaleLUT then begin
  1643.                         info^.LutMode := CustomGrayScale;
  1644.                         DrawMap;
  1645.                     end;
  1646.             end;
  1647.     end;
  1648.  
  1649.  
  1650.     procedure InitPaletteHeader (var hdr: PaletteHeader);
  1651.         var
  1652.             i: integer;
  1653.     begin
  1654.         with hdr, info^ do begin
  1655.                 pID := 'ICOL';
  1656.                 pVersion := version;
  1657.                 pnColors := nColors;
  1658.                 pColorStart := ColorStart;
  1659.                 pColorEnd := ColorEnd;
  1660.                 pFill1 := FillColor1;
  1661.                 pFill2 := FillColor2;
  1662.                 for i := 1 to 4 do
  1663.                     pUnused[i] := 0;
  1664.             end;
  1665.     end;
  1666.  
  1667.  
  1668.     procedure SaveLutResource;
  1669. {Saves the current color table as  a CPAL resource}
  1670.         var
  1671.             id: integer;
  1672.             canceled: boolean;
  1673.             PalH: handle;
  1674.             hdr: PaletteHeader;
  1675.             p: ptr;
  1676.     begin
  1677.         with info^ do begin
  1678.                 id := GetInt('Resource ID', 1000, canceled);
  1679.                 if canceled then
  1680.                     exit(SaveLutResource);
  1681.                 PalH := GetResource('CPAL', id);
  1682.                 if GetHandleSize(PalH) > 0 then begin
  1683.                         RmveResource(PalH);
  1684.                         DisposHandle(PalH);
  1685.                     end;
  1686.                 InitPaletteHeader(hdr);
  1687.                 PalH := NewHandle(SizeOF(PaletteHeader) + nColors * 3);
  1688.                 p := PalH^;
  1689.                 BlockMove(@hdr, p, SizeOf(PaletteHeader));
  1690.                 p := ptr(ord4(p) + SizeOf(PaletteHeader));
  1691.                 BlockMove(@RedLut, p, nColors);
  1692.                 p := ptr(ord4(p) + nColors);
  1693.                 BlockMove(@GreenLut, p, nColors);
  1694.                 p := ptr(ord4(p) + nColors);
  1695.                 BlockMove(@BlueLut, p, nColors);
  1696.                 AddResource(PalH, 'CPAL', id, '');
  1697.                 WriteResource(PalH);
  1698.                 if ResError <> NoErr then
  1699.                     SysBeep(1);
  1700.                 DisposHandle(PalH);
  1701.             end;
  1702.     end;
  1703.  
  1704.  
  1705.     procedure GetLutResource (id: integer);
  1706.         var
  1707.             LutH: handle;
  1708.             hdr: PaletteHEader;
  1709.             p: ptr;
  1710.     begin
  1711.         with info^ do begin
  1712.                 LutH := GetResource('CPAL', id);
  1713.                 if (ResError <> noErr) or (LutH = nil) then begin
  1714.                         beep;
  1715.                         if LutH <> nil then
  1716.                             ReleaseResource(LutH);
  1717.                         exit(GetLutResource)
  1718.                     end;
  1719.                 p := LutH^;
  1720.                 BlockMove(p, @hdr, SizeOf(PaletteHeader));
  1721.                 with hdr do begin
  1722.                         if pID <> 'ICOL' then begin
  1723.                                 beep;
  1724.                                 ReleaseResource(LutH);
  1725.                                 exit(GetLutResource);
  1726.     $0004, {  move.l 4(a6),d0}
  1727.     $5380,       {  subq.l #1,d0}
  1728.     $4281,       {  clr.l d1}
  1729.     $1210,       {L move.b (a0),d1}
  1730.     $10F1, $1000, {  move.b 0(a1,d1.w),(a0)+}
  1731.     $51C8, $FFF8, {  dbra d0,L}
  1732.     $4CDF, $0303, {  movem.l (sp)+,a0-a1/d0-d1}
  1733.     $4E5E,       {  unlk a6}
  1734.     $DEFC, $000C; {  add.w #12,sp}
  1735.  
  1736.  
  1737. procedure PutLineUsingMask (h, v, count: integer; var line: LineType);
  1738.     var
  1739.         aLine, MaskLine: LineType;
  1740.         i: integer;
  1741.         SaveInfo: InfoPtr;
  1742. begin
  1743.     if count > MaxLine then
  1744.         count := MaxLine;
  1745.     GetLine(h, v, count, aline);
  1746.     SaveInfo := Info;
  1747.     Info := UndoInfo;
  1748.     GetLine(h, v, count, MaskLine);
  1749.     for i := 0 to count - 1 do
  1750.         if MaskLine[i] = BlackIndex then
  1751.             aLine[i] := line[i];
  1752.     info := SaveInfo;
  1753.     PutLine(h, v, count, aLine);
  1754. end;
  1755.  
  1756.  
  1757. procedure ApplyTable; {(var table: LookupTable)}
  1758.     var
  1759.         width, NumberOfLines, i, hloc, vloc: integer;
  1760.         offset: LongInt;
  1761.         p: ptr;
  1762.         UseMask: boolean;
  1763.         TempLine: LineType;
  1764.         AutoSelectAll: boolean;
  1765. begin
  1766.     if NotInBounds then
  1767.         exit(ApplyTable);
  1768.     AutoSelectAll := not Info^.RoiShowing;
  1769.     if AutoSelectAll then
  1770.         SelectAll(false);
  1771.     if TooWide then
  1772.         exit(ApplyTable);
  1773.     ShowWatch;
  1774.     with info^.RoiRect, info^ do begin
  1775.             if RoiType <> RectRoi then
  1776.                 UseMask := SetupMask
  1777.             else
  1778.                 UseMask := false;
  1779.             SetupUndoFromClip;
  1780.             WhatToUndo := UndoTransform;
  1781.             offset := LongInt(top) * BytesPerRow + left;
  1782.             if UseMask then
  1783.                 p := @TempLine
  1784.             else
  1785.                 p := ptr(ord4(PicBaseAddr) + offset);
  1786.             width := right - left;
  1787.             NumberOfLines := bottom - top;
  1788.             hloc := left;
  1789.             vloc := top;
  1790.         end;
  1791.     if width > 0 then
  1792.         for i := 1 to NumberOfLines do
  1793.             if UseMask then begin
  1794.                     GetLine(hloc, vloc, width, TempLine);
  1795.                     ApplyTableToLine(p, table, width);
  1796.                     PutLineUsingMask(hloc, vloc, width, TempLine);
  1797.                     vloc := vloc + 1
  1798.                 end
  1799.             else begin
  1800.                     ApplyTableToLine(p, table, width);
  1801.                     p := ptr(ord4(p) + info^.BytesPerRow);
  1802.                 end;
  1803.     with info^ do begin
  1804.             UpdateScreen(RoiRect);
  1805.             Info^.changes := true;
  1806.         end;
  1807.     SetupRoiRect;
  1808.     if AutoSelectAll then
  1809.         KillRoi;
  1810. end;
  1811.  
  1812.  
  1813. procedure FixColors;
  1814.     {Because NIH Image always sets LUT entries 0 and 255 to white and black respectively we need to map}
  1815.     {pixels with values of 0 or 255 to the nearest matching color in the other 254  LUT entries.}
  1816.     var
  1817.         i, index2, match0, match255: integer;
  1818.         table: LookupTable;
  1819.  
  1820.     procedure BestMatch (index1: integer; var match: integer);
  1821.         var
  1822.             i: integer;
  1823.             rdiff, gdiff, bdiff: LongInt;
  1824.             diff, mindiff: extended;
  1825.     begin
  1826.         match := index1;
  1827.         mindiff := 10e10;
  1828.         if index1 = 0 then
  1829.             index2 := 1
  1830.         else
  1831.             index2 := 254;
  1832.         with info^ do
  1833.             for i := 1 to 254 do begin
  1834.                     rdiff := bsr(cTable[index1].rgb.red, 8) - bsr(cTable[index2].rgb.red, 8);
  1835.                     gdiff := bsr(cTable[index1].rgb.green, 8) - bsr(cTable[index2].rgb.green, 8);
  1836.                     bdiff := bsr(cTable[index1].rgb.blue, 8) - bsr(cTable[index2].rgb.blue, 8);
  1837.                     diff := sqrt(sqr(rdiff) + sqr(gdiff) + sqr(bdiff));
  1838.                     if diff < mindiff then begin
  1839.                             match := index2;
  1840.                             mindiff := diff;
  1841.                         end;
  1842.                     if index1 = 0 then
  1843.                         index2 := index2 + 1
  1844.                     else
  1845.                         index2 := index2 - 1;
  1846.                 end;
  1847.     end;
  1848.  
  1849. begin
  1850.     BestMatch(0, match0);
  1851.     BestMatch(255, match255);
  1852.     table[0] := match0;
  1853.     for i := 1 to 254 do
  1854.         table[i] := i;
  1855.     table[255] := match255;
  1856.     ApplyTable(table);
  1857. end;
  1858.  
  1859.  
  1860. end.