home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Pascal / Applications / NIH Image 1.59 / 1.59 Source / File1.p < prev    next >
Encoding:
Text File  |  1995-10-23  |  94.9 KB  |  3,309 lines  |  [TEXT/PJMM]

  1. unit File1;
  2.  
  3. {Routines used by NIH Image for implementing File Menu commands.}
  4.  
  5. interface
  6.  
  7.  
  8.     uses
  9.         Memory, QuickDraw, Packages, Menus, Events, Fonts, Scrap, ToolUtils, Resources, Errors, Palettes, StandardFile, SegLoad, Processes, globals, Utilities, Graphics, file2, Dicom, sound, Lut, Text;
  10.  
  11.  
  12.     function CloseAWindow (WhichWindow: WindowPtr): integer;
  13.     procedure DoClose;
  14.     function OpenFile (fname: str255; vnum: integer): boolean;
  15.     function OpenPict (fname: str255; vnum: integer; Reverting: boolean): boolean;
  16.     procedure SaveFile;
  17.     function DoOpen (FileName: str255; RefNum: integer): boolean;
  18.     function ImportFile (FileName: str255; RefNum: integer): boolean;
  19.     procedure RevertToSaved;
  20.     procedure SaveAs (name: str255; RefNum: integer);
  21.     procedure Export (name: str255; RefNum: integer);
  22.     procedure FindWhatToPrint;
  23.     procedure UpdateFileMenu;
  24.     procedure SaveAsText (fname: str255; RefNum: integer);
  25.     procedure SaveAll;
  26.     function OpenPICS (name: str255; fRefNum: integer): boolean;
  27.     procedure RescaleToEightBits;
  28.  
  29.  
  30. implementation
  31.  
  32.     var
  33.         OpenAllFiles, UseExistingLUT, PICTReadErr: boolean;
  34.         SaveRefNum: integer;
  35.         TempStackInfo: StackInfoRec;
  36.         PictSrcRect: rect;
  37.  
  38. {$PUSH}
  39. {$D-}
  40.  
  41.     procedure LookForCluts (fname: str255; vnum: integer);
  42.         var
  43.             RefNum: integer;
  44.             err: OSErr;
  45.             ok1, ok2: boolean;
  46.     begin
  47.         if not UseExistingLUT then begin
  48.                 err := SetVol(nil, vnum);
  49.                 refNum := OpenResFile(fname);
  50.                 if RefNum <> -1 then begin
  51.                         ok1 := LoadCLUTResource(KlutzID);
  52.                         if not ok1 then
  53.                             ok2 := LoadCLUTResource(PixelPaintID);
  54.                         CloseResFile(refNum);
  55.                     end;
  56.             end;
  57.     end;
  58.  
  59.  
  60.  
  61.     function OpenImageHeader (f: integer; fname: str255; vnum: integer): boolean;
  62.         var
  63.             ByteCount: LongInt;
  64.             err: OSErr;
  65.             TempHdr: PicHeader;
  66.             i, OldNExtra, p1x, p2x: integer;
  67.             ok: boolean;
  68.             hUnitsKind: UnitsType;
  69.     begin
  70.         if SizeOf(PicHeader)<>HeaderSize then begin
  71.             PutError(StringOf('Internal error (size= ', SizeOf(PicHeader):1,')'));
  72.             OpenImageHeader := false;
  73.             exit(OpenImageHeader);
  74.         end;
  75.         ByteCount := HeaderSize;
  76.         err := SetFPos(f, fsFromStart, info^.HeaderOffset);
  77.         err := fsread(f, ByteCount, @TempHdr);
  78.         if CheckIO(err) <> NoErr then begin
  79.                 OpenImageHeader := false;
  80.                 exit(OpenImageHeader);
  81.             end;
  82.         with info^, TempHdr do begin
  83.                 if PictureType <> TiffFile then begin
  84.                         nlines := hnlines;
  85.                         PixelsPerLine := hPixelsPerLine;
  86.                     end;
  87.                 if (hversion > 54) and not UseExistingLUT then begin
  88.                         OldNExtra := nExtraColors;
  89.                         nExtraColors := hnExtraColors;
  90.                         ExtraColors := hExtraColors;
  91.                         if (nExtraColors > 0) or (OldNExtra <> nExtraColors) then
  92.                             RedrawLUTWindow;
  93.                     end;
  94.                 if (hversion >= 42) and not UseExistingLUT then begin
  95.                         if hversion < 142 then begin
  96.                                 LUTMode := hOldLUTMode;
  97.                                 if (LutMode = OldAppleDefault) or (LutMode = OldSpectrum) then
  98.                                     LutMode := ColorLut;
  99.                             end
  100.                         else begin
  101.                                 LUTMode := hLUTMode;
  102.                                 if LutMode = Pseudocolor then begin
  103.                                         if ((hnColors > 32) and (hTable = CustomTable)) or (hTable > spectrum) then
  104.                                             LutMode := ColorLut;
  105.                                     end;
  106.                             end;
  107.                         case LUTMode of
  108.                             PseudoColor: 
  109.                                 if hversion < 142 then begin
  110.                                         nColors := hOldnColors;
  111.                                         for i := 0 to ncolors - 1 do begin
  112.                                                 RedLUT[i] := hr[i];
  113.                                                 GreenLUT[i] := hg[i];
  114.                                                 BlueLUT[i] := hb[i];
  115.                                             end;
  116.                                         ColorEnd := 255 - hOldColorStart;
  117.                                         ColorStart := ColorEnd - nColors * hColorWidth + 1;
  118.                                         if ColorStart < 0 then
  119.                                             ColorStart := 0;
  120.                                         InvertPalette;
  121.                                         FillColor1 := BlackRGB;
  122.                                         FillColor2 := BlackRGB;
  123.                                         ColorTable := CustomTable;
  124.                                         UpdateLUT;
  125.                                     end
  126.                                 else begin {V1.42 or later}
  127.                                         if (hTable <> CustomTable) and (hTable <= spectrum) then begin
  128.                                                 SwitchColorTables(GetColorTableItem(hTable), false);
  129.                                                 if hInvertedTable then
  130.                                                     InvertPalette;
  131.                                             end
  132.                                         else begin
  133.                                                 nColors := hnColors;
  134.                                                 ColorTable := CustomTable;
  135.                                                 if nColors <= 32 then
  136.                                                     for i := 0 to ncolors - 1 do begin
  137.                                                             RedLUT[i] := hr[i];
  138.                                                             GreenLUT[i] := hg[i];
  139.                                                             BlueLUT[i] := hb[i];
  140.                                                         end;
  141.                                             end;
  142.                                         ColorStart := hColorStart;
  143.                                         ColorEnd := hColorEnd;
  144.                                         FillColor1 := hFill1;
  145.                                         FillColor2 := hFill2;
  146.                                         UpdateLUT;
  147.                                         UpdateMap;
  148.                                     end; {v1.42 or later}
  149.                             GrayScale: 
  150.                                 ResetGrayMap;
  151.                             ColorLut, CustomGrayscale: 
  152.                                 if PictureType <> PictFile then begin
  153.                                         if ColorMapOffset > 0 then
  154.                                             GetTiffColorMap(f)
  155.                                         else
  156.                                             LookForCluts(fname, vnum);
  157.                                     end;
  158.                             otherwise
  159.                         end; {case}
  160.                         if hLutMode = CustomGrayscale then
  161.                             LutMode := CustomGrayscale;
  162.                     end;{if}
  163.                 if (hversion >= 65) and ((ForegroundIndex <> hForegroundIndex) or (BackgroundIndex <> hBackgroundIndex)) then begin
  164.                         SetForegroundColor(hForegroundIndex);
  165.                         SetBackgroundColor(hBackgroundIndex);
  166.                     end;
  167.                 if (hversion > 88) and (LUTMode = GrayScale) and not UseExistingLUT then begin
  168.                         if hversion < 138 then begin
  169.                                 p1x := 255 - hp2x;
  170.                                 p2x := 255 - hp1x;
  171.                             end
  172.                         else begin
  173.                                 p1x := hp1x;
  174.                                 p2x := hp2x
  175.                             end;
  176.                         nColors := 256;
  177.                         ColorStart := p1x;
  178.                         ColorEnd := p2x;
  179.                         UpdateLUT;
  180.                     end;
  181.                 if hversion > 106 then begin
  182.                         {xScale := hXScale;} {68k-bug}
  183.                         xScale := DoubleToReal(hXScale);
  184.                         yScale := xScale;
  185.                         PixelAspectRatio := 1.0;
  186.                         SpatiallyCalibrated := xScale <> 0.0;
  187.                     end;
  188.                 if hversion > 140 then begin
  189.                         PixelAspectRatio := hPixelAspectRatio;
  190.                         yScale := xScale / PixelAspectRatio;
  191.                     end;
  192.                 if hversion > 153 then
  193.                     xUnit := hXUnit
  194.                 else begin
  195.                         hUnitsKind := UnitsType(hUnitsID - 5);
  196.                         GetXUnits(hUnitsKind);
  197.                     end;
  198.                 if xUnit = 'pixel' then
  199.                     SpatiallyCalibrated := false;
  200.                 if ((hnCoefficients > 0) and (hfit < Uncalibrated)) or (hfit = UncalibratedOD) then begin
  201.                         if hfit = SpareFit1 then begin
  202.                                 fit := uncalibrated;
  203.                                 DrawLabels('', '', '');
  204.                             end
  205.                         else begin
  206.                                 fit := hfit;
  207.                                 if hfit <> UncalibratedOD then begin
  208.                                         nCoefficients := hnCoefficients;
  209.                                         for i:=1 to maxCoeff do
  210.                                             {Coefficient[i] := hCoeff[i];} {68k-bug}
  211.                                             Coefficient[i]:=DoubleToReal(hCoeff[i]);
  212.                                         nKnownValues := 0;
  213.                                     end;
  214.                                 UnitOfMeasure := hUM;
  215.                                 if hversion >= 144 then
  216.                                     ZeroClip := hZeroClip
  217.                                 else
  218.                                     ZeroClip := false;
  219.                             end;
  220.                     end
  221.                 else begin
  222.                         fit := uncalibrated;
  223.                         DrawLabels('', '', '');
  224.                     end;
  225.                 BinaryPic := hBinaryPic;
  226.                 if hSliceEnd > 1 then begin
  227.                         SliceStart := hSliceStart;
  228.                         SliceEnd := hSliceEnd;
  229.                         if SliceEnd > 254 then
  230.                             SliceEnd := 254;
  231.                     end;
  232.                 if hNSlices > 1 then begin
  233.                         with TempStackInfo do begin
  234.                                 nSlices := hNSlices;
  235.                                 if nSlices > MaxSlices then
  236.                                     nSlices := MaxSlices;
  237.                                 CurrentSlice := hCurrentSlice;
  238.                                 if (hCurrentSlice < 1) or (hCurrentSlice > nSlices) then
  239.                                     CurrentSlice := 1;
  240.                                 SliceSpacing := hSliceSpacing;
  241.                                 FrameInterval := hFrameInterval;
  242.                                 StackType := VolumeStack;
  243.                                 if hVersion >= 158 then
  244.                                     StackType := hStackType;
  245.                             end;
  246.                     end;
  247.                 FileVersion := hVersion;
  248.                 OpenImageHeader := true
  249.             end;
  250.     end;
  251.  
  252.  
  253.     function OpenHeader (f: integer; fname: str255; vnum: integer; var TiffInfo: TiffInfoRec): boolean;
  254.         var
  255.             ByteCount, FileSize, DirOffset, MaxImages: LongInt;
  256.             hdr: packed array[1..512] of byte;
  257.             err: OSErr;
  258.             TempHdr: PicHeader;
  259.     begin
  260.         with info^ do begin
  261.                 if (WhatToOpen = OpenUnknown) or (WhatToOpen = OpenImported) then begin
  262.                         err := SetFPos(f, fsFromStart, 0);
  263.                         ByteCount := 8;
  264.                         err := fsread(f, ByteCount, @hdr);
  265.                         if ((hdr[1] = 73) and (hdr[2] = 73)) or ((hdr[1] = 77) and (hdr[2] = 77)) then
  266.                             WhatToOpen := OpenTIFF
  267.                         else if WhatToOpen = OpenUnknown then
  268.                             WhatToOpen := OpenImage
  269.                         else
  270.                             WhatToOpen := OpenMCID;
  271.                     end;
  272.                 StackInfo := nil;
  273.                 with TempStackInfo do begin
  274.                         nSlices := 0;
  275.                         CurrentSlice := 1;
  276.                         SliceSpacing := 0.0;
  277.                         FrameInterval := 0.0;
  278.                     end;
  279.                 fileVersion := 0;
  280.                 case WhatToOpen of
  281.                     OpenImage:  begin
  282.                             err := SetFPos(f, fsFromStart, 0);
  283.                             ByteCount := 8;
  284.                             err := fsread(f, ByteCount, @TempHdr);
  285.                             if TempHdr.FileID = FileID8 then begin
  286.                                     HeaderOffset := 0;
  287.                                     PictureType := normal
  288.                                 end
  289.                             else begin
  290.                                     HeaderOffset := -1;
  291.                                     BlockMove(@TempHdr, @hdr, 8);
  292.                                     nlines := hdr[1] + hdr[2] * 256;
  293.                                     PixelsPerLine := hdr[3] + hdr[4] * 256;
  294.                                     PictureType := Imported;
  295.                                     InvertedImage := true;
  296.                                 end;
  297.                             ImageDataOffset := 512;
  298.                         end;
  299.                     OpenMCID:  begin
  300.                             err := SetFPos(f, fsFromStart, 0);
  301.                             ByteCount := 4;
  302.                             err := fsread(f, ByteCount, @hdr);
  303.                             PixelsPerLine := hdr[1] + hdr[2] * 256 + 1;
  304.                             if PixelsPerLine > MaxLine then begin
  305.                                     beep;
  306.                                     PixelsPerLine := MaxLine;
  307.                                 end;
  308.                             nlines := hdr[3] + hdr[4] * 256 + 1;
  309.                             PictureType := imported;
  310.                             LUTMode := grayscale;
  311.                             HeaderOffset := -1;
  312.                             ImageDataOffset := 4;
  313.                         end;
  314.                     OpenCustom:  begin
  315.                             err := GetEof(f, FileSize);
  316.                             if macro then begin
  317.                                     if (ImportCustomOffset + ImportCustomWidth * ImportCustomHeight) > FileSize then begin
  318.                                             AbortMacro;
  319.                                             OpenHeader := false;
  320.                                             exit(OpenHeader)
  321.                                         end;
  322.                                 end;
  323.                             PixelsPerLine := ImportCustomWidth;
  324.                             nlines := ImportCustomHeight;
  325.                             PictureType := imported;
  326.                             HeaderOffset := -1;
  327.                             ImageDataOffset := ImportCustomOffset;
  328.                             if ImportCustomSlices > 1 then
  329.                                 with TempStackInfo do begin
  330.                                         nSlices := ImportCustomSlices;
  331.                                         MaxImages := (FileSize - ImportCustomOffset) div (ImportCustomWidth * ImportCustomHeight);
  332.                                         if nSlices > MaxImages then
  333.                                             nSlices := MaxImages;
  334.                                         if nSlices < 2 then
  335.                                             nSlices := 0;
  336.                                     end;
  337.                         end;
  338.                     OpenPICT2:  begin
  339.                             err := SetFPos(f, fsFromStart, 0);
  340.                             ByteCount := 8;
  341.                             err := fsread(f, ByteCount, @TempHdr);
  342.                             if TempHdr.FileID = FileID8 then
  343.                                 HeaderOffset := 0
  344.                             else
  345.                                 HeaderOffset := -1;
  346.                             PictureType := PictFile;
  347.                             if not UseExistingLUT then
  348.                                 LutMode := ColorLut;
  349.                             ImageDataOffset := 512;
  350.                         end;
  351.                     OpenTIFF:  begin
  352.                             if not OpenTiffHeader(f, DirOffset) then begin
  353.                                     OpenHeader := false;
  354.                                     exit(OpenHeader)
  355.                                 end;
  356.                             if not OpenTiffDirectory(f, DirOffset, TiffInfo, false) then begin
  357.                                     OpenHeader := false;
  358.                                     exit(OpenHeader)
  359.                                 end;
  360.                             with TiffInfo do begin
  361.                                     PictureType := TiffFile;
  362.                                     PixelsPerLine := width;
  363.                                     nlines := height;
  364.                                     if BitsPerPixel = 4 then
  365.                                         PictureType := FourBitTiff;
  366.                                     ImageDataOffset := OffsetToData;
  367.                                     InvertedImage := ZeroIsBlack and (PictureType <> FourBitTIFF);
  368.                                     if resolution > 0.0 then begin
  369.                                             case ResUnits of
  370.                                                 tNoUnits: 
  371.                                                     xUnit := 'pixel';
  372.                                                 tCentimeters: 
  373.                                                     xUnit := 'cm';
  374.                                                 tInches: 
  375.                                                     xUnit := 'inch';
  376.                                             end;
  377.                                             xScale := resolution;
  378.                                             yScale := resolution;
  379.                                             PixelAspectRatio := 1.0;
  380.                                             if xUnit <> 'pixel' then
  381.                                                 SpatiallyCalibrated := true;
  382.                                         end;
  383.                                     ColorMapOffset := OffsetToColorMap;
  384.                                     HeaderOffset := OffsetToImageHeader;
  385.                                 end;
  386.                             if not UseExistingLUT then
  387.                                 LutMode := Grayscale;
  388.                         end;
  389.                 end; {case}
  390.                 if HeaderOffset <> -1 then begin
  391.                         if not OpenImageHeader(f, fname, vnum) then begin
  392.                                 OpenHeader := false;
  393.                                 exit(OpenHeader)
  394.                             end
  395.                     end
  396.                 else if (ColorMapOffset > 0) and not UseExistingLUT then
  397.                     GetTiffColorMap(f);
  398.             end; {with}
  399.         OpenHeader := true;
  400.     end;
  401.  
  402.  
  403.  
  404.     function SaveHeader (f, slines, sPixelsPerLine, vnum: integer; fname: str255; SavingSelection, SavingTIFF: boolean): OSErr;
  405.         var
  406.             TempHdr: PicHeader;
  407.             DummyHdr: array[1..128] of LongInt;
  408.             i: integer;
  409.             ByteCount: LongInt;
  410.             position: LongInt;
  411.             err: OSErr;
  412.             str: str255;
  413.             UnitsKind: UnitsType;
  414.             UnitsPerCM: extended;
  415.     begin
  416.         with TempHdr, info^ do begin
  417.                 for i := 1 to 128 do
  418.                     DummyHdr[i] := 0;
  419.                 BlockMove(@DummyHdr, @TempHdr, HeaderSize);
  420.                 FileID := FileID8;
  421.                 hnlines := nlines;
  422.                 hPixelsPerLine := PixelsPerLine;
  423.                 hversion := version;
  424.                 hLUTMode := LUTMode;
  425.                 hOldLutMode := LutMode;
  426.                 hnColors := ncolors;
  427.                 hOldnColors := 0;
  428.                 if LutMode = Pseudocolor then begin
  429.                         hOldLutMode := ColorLut;
  430.                         if (ColorTable = CustomTable) and (ncolors <= 32) then
  431.                             for i := 0 to nColors - 1 do begin
  432.                                     hr[i] := RedLUT[i];
  433.                                     hg[i] := GreenLUT[i];
  434.                                     hb[i] := BlueLUT[i];
  435.                                 end;
  436.                     end;
  437.                 hColorStart := ColorStart;
  438.                 hColorEnd := ColorEnd;
  439.                 hFill1 := FillColor1;
  440.                 hFill2 := FillColor2;
  441.                 hTable := ColorTable;
  442.                 hInvertedTable := InvertedColorTable;
  443.                 hOldColorStart := 255 - ColorEnd;
  444.                 if nColors > 0 then
  445.                     hColorWidth := (ColorEnd - ColorStart) div nColors
  446.                 else
  447.                     hColorWidth := 1;
  448.                 hnExtraColors := nExtraColors;
  449.                 hExtraColors := ExtraColors;
  450.                 hForegroundIndex := ForegroundIndex;
  451.                 hBackgroundIndex := BackgroundIndex;
  452.                 {hXScale := xScale;} {68k-bug}
  453.                 RealToDouble(xScale, hXScale);
  454.                 hScaleMagnification := 1.0;
  455.                 hPixelAspectRatio := PixelAspectRatio;
  456.                 hUnitsID := 14; {Pixels. For backward compatibility only since hUnits no longer used.}
  457.                 if SpatiallyCalibrated then begin
  458.                         GetUnitsKind(UnitsKind, UnitsPerCM);
  459.                         hUnitsID := ord(UnitsKind) + 5;
  460.                         if hUnitsID > 14 then
  461.                             hUnitsID := 14;
  462.                     end;
  463.                 FindPoints(hp1x, hp1y, hp2x, hp2y);
  464.                 if fit = uncalibrated then
  465.                     hnCoefficients := 0
  466.                 else
  467.                     hnCoefficients := nCoefficients;
  468.                 hfit := fit;
  469.                 for i:=1 to maxCoeff do
  470.                     {hCoeff[i] := Coefficient[i];} {68k-bug}
  471.                     RealToDouble(Coefficient[i], hCoeff[i]);
  472.                 hZeroClip := ZeroClip;
  473.                 hUM := UnitOfMeasure;
  474.                 hBinaryPic := BinaryPic;
  475.                 hSliceStart := SliceStart;
  476.                 hSliceEnd := SliceEnd;
  477.                 if StackInfo <> nil then
  478.                     with StackInfo^ do begin
  479.                             hNSlices := nSlices;
  480.                             hSliceSpacing := SliceSpacing;
  481.                             hFrameInterval := FrameInterval;
  482.                             hCurrentSlice := CurrentSlice;
  483.                             hStackType := StackType;
  484.                         end
  485.                 else begin
  486.                         hNSlices := 0;
  487.                         hSliceSpacing := 0.0;
  488.                         hFrameInterval := 0.0;
  489.                         hCurrentSlice := 0;
  490.                         hStackType := VolumeStack;
  491.                     end;
  492.                 hXUnit := xUnit;
  493.                 ByteCount := SizeOf(TempHdr);
  494.                 if ByteCount <> HeaderSize then begin
  495.                         NumToString(ByteCount, str);
  496.                         PutError('Internal error check: header size is incorrect.');
  497.                         ExitToShell;
  498.                     end;
  499.                 if SavingSelection then begin
  500.                         hnlines := slines;
  501.                         hPixelsPerLine := sPixelsPerLine;
  502.                     end;
  503.                 err := fswrite(f, ByteCount, @TempHdr);
  504.                 SaveHeader := CheckIO(err);
  505.             end; {with}
  506.     end;
  507.  
  508.  
  509.     procedure PackLines;
  510.   {For odd width images, removes the extra bytes at the end of each line required to make RowBytes even.}
  511.         var
  512.             i: integer;
  513.             SrcPtr, DstPtr: ptr;
  514.     begin
  515.         with info^ do begin
  516.                 SrcPtr := ptr(ord4(PicBaseAddr) + BytesPerRow);
  517.                 DstPtr := ptr(ord4(PicBaseAddr) + PixelsPerLine);
  518.                 for i := 1 to nlines - 1 do begin
  519.                         BlockMove(SrcPtr, DstPtr, PixelsPerLine);
  520.                         SrcPtr := ptr(ord4(SrcPtr) + BytesPerRow);
  521.                         DstPtr := ptr(ord4(DstPtr) + PixelsPerLine);
  522.                     end;
  523.             end;
  524.     end;
  525.  
  526.  
  527.     procedure UnpackLines;
  528.   {For odd width images, adds an extra byte to each line so RowBytes is even.}
  529.         var
  530.             i: integer;
  531.             SrcPtr, DstPtr: ptr;
  532.     begin
  533.         with info^ do begin
  534.                 SrcPtr := ptr(ord4(PicBaseAddr) + (nlines - 1) * PixelsPerLine);
  535.                 DstPtr := ptr(ord4(PicBaseAddr) + (nlines - 1) * BytesPerRow);
  536.                 for i := 1 to nlines - 1 do begin
  537.                         BlockMove(SrcPtr, DstPtr, PixelsPerLine);
  538.                         SrcPtr := ptr(ord4(SrcPtr) - PixelsPerLine);
  539.                         DstPtr := ptr(ord4(DstPtr) - BytesPerRow);
  540.                     end;
  541.             end;
  542.     end;
  543.  
  544.  
  545.     function WriteSlices (f: integer): integer;
  546.         var
  547.             ByteCount, SelectionSize: LongInt;
  548.             i, err, SaveCS: integer;
  549.     begin
  550.         with info^, Info^.StackInfo^ do begin
  551.                 SaveCS := CurrentSlice;
  552.                 for i := 1 to nSlices do begin
  553.                         CurrentSlice := i;
  554.                         SelectSlice(CurrentSlice);
  555.                         UpdateTitleBar;
  556.                         ByteCount := ImageSize;
  557.                         if odd(PixelsPerLine) then
  558.                             PackLines;
  559.                         err := fswrite(f, ByteCount, PicBaseAddr);
  560.                         if odd(PixelsPerLine) then
  561.                             UnpackLines;
  562.                         if err <> 0 then
  563.                             leave;
  564.                     end;
  565.                 CurrentSlice := SaveCS;
  566.                 SelectSlice(CurrentSlice);
  567.                 UpdateTitleBar;
  568.                 WriteSlices := err;
  569.             end;
  570.     end;
  571.  
  572.  
  573.     procedure WriteSelection (f: integer; sLines, sPixelsPerLine: LongInt);
  574.   {Contributed by Edward J. Huff(huff@mcclb0.med.nyu.edu).}
  575.         var
  576.             size, offset, ByteCount, BytesDone: LongInt;
  577.             src, dst: ptr;
  578.             err: OSErr;
  579.     begin
  580.         if sPixelsPerLine > UndoBufSize then
  581.             exit(WriteSelection);
  582.         size := sLines * sPixelsPerLine;
  583.         with info^, info^.RoiRect do begin
  584.                 offset := top * BytesPerRow + left;
  585.                 src := ptr(ord4(PicBaseAddr) + offset);
  586.                 BytesDone := 0;
  587.                 while BytesDone < size do begin
  588.                         ByteCount := 0;
  589.                         dst := UndoBuf;
  590.                         while ((ByteCount + sPixelsPerLine) < UndoBufSize) and (BytesDone < size) do begin
  591.                                 BlockMove(src, dst, sPixelsPerLine);
  592.                                 src := ptr(ord4(src) + BytesPerRow);
  593.                                 dst := ptr(ord4(dst) + sPixelsPerLine);
  594.                                 ByteCount := ByteCount + sPixelsPerLine;
  595.                                 BytesDone := BytesDone + sPixelsPerLine;
  596.                             end;
  597.                         err := fswrite(f, ByteCount, UndoBuf);
  598.                     end;
  599.                 SetupUndo; {Needed for drawing roi outline}
  600.             end
  601.     end;
  602.  
  603.  
  604.     procedure SaveRGBTiff(f: integer; SavingSelection: boolean);
  605.     const
  606.         bufsize = 12000;
  607.     var
  608.         i, row, pixel, count, ignore: LongInt;
  609.         vstart, height, hstart, width: LongInt;
  610.         buffer: packed array [0 .. bufsize] of byte;
  611.         rLine, gLine, bLine: LineType;
  612.         err: OSErr;
  613.     begin
  614.         with info^ do begin
  615.             if SavingSelection then with RoiRect do begin
  616.                 vstart := top;
  617.                 height := bottom - top;
  618.                 hstart := left;
  619.                 width := right - left;
  620.             end else begin
  621.                 vstart := 0;
  622.                 height := nLInes;
  623.                 hstart := 0;
  624.                 width := PixelsPerLine;
  625.             end;
  626.             if width > MaxLine then
  627.                 exit(SaveRGBTiff);
  628.             ShowMeter;
  629.             count := 0;
  630.             for row:=0 to height - 1 do begin
  631.                 if (row mod 10) = 0 then
  632.                     UpdateMeter(((row * 100) div height), 'Saving RGB TIFF');
  633.                 SelectSlice(1);
  634.                 GetLine(hstart, vstart + row, width, rLine);
  635.                 SelectSlice(2);
  636.                 GetLine(hstart, vstart + row, width, gLine);
  637.                 SelectSlice(3);
  638.                 GetLine(hstart, vstart + row, width, bLine);
  639.                 for pixel := 0 to width - 1 do begin
  640.                     buffer[count] := 255 - rLine[pixel];
  641.                     buffer[count + 1] := 255 - gLine[pixel];
  642.                     buffer[count + 2] := 255 - bLine[pixel];
  643.                     count := count + 3;
  644.                     if count > (bufsize - 3) then begin
  645.                         if CheckIO(fswrite(f, count, @buffer)) <> noErr then begin
  646.                             exit(SaveRGBTiff);
  647.                             UpdateMeter(-1, '');
  648.                         end;
  649.                         count := 0;
  650.                     end;
  651.                 end; {for}
  652.             end; {for}
  653.             if count > 0 then
  654.                 err := fswrite(f, count, @buffer);
  655.             UpdateMeter(-1, '');
  656.             with StackInfo^ do begin
  657.                 CurrentSlice := 1;
  658.                 SelectSlice(CurrentSlice);
  659.             end;
  660.             UpdateTitleBar;
  661.         end; {with}
  662.     end;
  663.     
  664.  
  665.     function SaveTiffFile (fname: str255; vnum: integer; slines, sPixelsPerLine: integer; SavingSelection: boolean): boolean;
  666.         var
  667.             f, err, i, width, height: integer;
  668.             HdrSize, ByteCount, ctabSize, StackTiffDirSize, ImageDataSize: LongInt;
  669.             TheInfo: FInfo;
  670.             MCIDHeader: packed array[1..4] of byte;
  671.             SaveColorMap, SaveAs24BitTiff: boolean;
  672.     begin
  673.         SaveTiffFile := false;
  674.         SaveAs24BitTiff := false;
  675.         ShowWatch;
  676.         err := fsopen(fname, vNum, f);
  677.         if CheckIO(err) <> 0 then
  678.             exit(SaveTiffFile);
  679.         with Info^ do begin
  680.                 SaveColorMap := (LutMode <> Grayscale) and (SaveAsWhat <> asRawData);
  681.                 if SaveAsWhat = SaveAsMCID then begin
  682.                         if SavingSelection then begin
  683.                                 width := sPixelsPerLine;
  684.                                 height := slines;
  685.                             end
  686.                         else begin
  687.                                 width := PixelsPerLine;
  688.                                 height := nLines;
  689.                             end;
  690.                         MCIDHeader[1] := (width - 1) mod 256;
  691.                         MCIDHeader[2] := (width - 1) div 256;
  692.                         MCIDHeader[3] := (height - 1) mod 256;
  693.                         MCIDHeader[4] := (height - 1) div 256;
  694.                         ByteCount := 4;
  695.                         err := fswrite(f, ByteCount, @MCIDHeader);
  696.                     end;
  697.                 HeaderOffset := TiffDirSize;
  698.                 ImageDataOffset := TiffDirSize + HeaderSize;
  699.                 if SaveColorMap then
  700.                     ctabSize := SizeOf(TiffColorMapType)
  701.                 else
  702.                     ctabSize := 0;
  703.                 StackTiffDirSize := 0;
  704.                 if SavingSelection then
  705.                     ImageDataSize := ord4(sLines) * sPixelsPerLine
  706.                 else
  707.                     ImageDataSize := ImageSize;
  708.                 if StackInfo <> nil then begin
  709.                         ImageDataSize := ImageSize * StackInfo^.nSlices;
  710.                         if SaveAsWhat <> asRawData then
  711.                             StackTiffDirSize := SizeOf(StackIFDType) * (StackInfo^.nSlices - 1);
  712.                         if (StackInfo^.StackType = rgbStack) and (StackInfo^.nSlices = 3) then begin
  713.                             SaveAs24BitTiff := true;
  714.                             ctabSize := 0;
  715.                             StackTiffDirSize := 0;
  716.                         end;
  717.                     end;
  718.                 if (SaveAsWhat <> asRawData) and (SaveAsWhat <> SaveAsMCID) then begin
  719.                         if SaveTiffDir(f, slines, sPixelsPerLine, SavingSelection, ctabSize, ImageDataSize) <> NoErr then begin
  720.                                 err := fsclose(f);
  721.                                 err := FSDelete(fname, vnum);
  722.                                 exit(SaveTiffFile)
  723.                             end;
  724.                         err := SetFPos(f, FSFromStart, TiffDirSize);
  725.                         if SaveHeader(f, slines, sPixelsPerLine, vnum, fname, SavingSelection, true) <> NoErr then begin
  726.                                 err := fsclose(f);
  727.                                 err := FSDelete(fname, vnum);
  728.                                 exit(SaveTiffFile)
  729.                             end;
  730.                     end;
  731.                 if SaveAsWhat = SaveAsMCID then
  732.                     KillRoi;
  733.                 if SaveAs24bitTiff then
  734.                     SaveRGBTiff(f, SavingSelection)
  735.                 else if SavingSelection then
  736.                     WriteSelection(f, sLines, sPixelsPerLine)
  737.                 else if StackInfo <> nil then
  738.                     err := WriteSlices(f)
  739.                 else begin
  740.                         ByteCount := ImageDataSize;
  741.                         if odd(PixelsPerLine) then
  742.                             PackLines;
  743.                         err := fswrite(f, ByteCount, PicBaseAddr);
  744.                         if odd(PixelsPerLine) then
  745.                             UnpackLines;
  746.                     end;
  747.                 if SaveAsWhat = SaveAsMCID then
  748.                     InvertPic;
  749.                 if CheckIO(err) <> 0 then begin
  750.                         err := fsclose(f);
  751.                         err := FSDelete(fname, vnum);
  752.                         exit(SaveTiffFile)
  753.                     end;
  754.                 if SaveAsWhat = asRawData then
  755.                     HdrSize := 0
  756.                 else if SaveAsWhat = SaveAsMCID then begin
  757.                         HdrSize := 4;
  758.                         SaveAsWhat := asRawData;
  759.                     end
  760.                 else
  761.                     HdrSize := HeaderSize + TiffDirSize;
  762.                 if SaveColorMap then
  763.                     SaveTiffColorMap(f, ImageDataSize);
  764.                 if StackTiffDirSize > 0 then
  765.                     err := WriteExtraTiffIFDs(f, ImageDataSize, cTabSize);
  766.                 err := SetEOF(f, HdrSize + ImageDataSize + ctabSize + StackTiffDirSize);
  767.                 err := fsclose(f);
  768.                 err := GetFInfo(fname, vnum, TheInfo);
  769.                 if TheInfo.fdCreator <> 'Imag' then begin
  770.                         TheInfo.fdCreator := 'Imag';
  771.                         err := SetFInfo(fname, vnum, TheInfo);
  772.                     end;
  773.                 if SaveAsWhat = asRawData then begin
  774.                         TheInfo.fdType := 'RawD';
  775.                         err := SetFInfo(fname, vnum, TheInfo);
  776.                     end
  777.                 else if TheInfo.fdType <> 'TIFF' then begin
  778.                         TheInfo.fdType := 'TIFF';
  779.                         err := SetFInfo(fname, vnum, TheInfo);
  780.                     end;
  781.                 err := FlushVol(nil, vNum);
  782.                 if not SavingSelection then begin
  783.                         if (PictureType <> BlankField) and (PictureType <> FrameGrabberType)  and (SaveAsWhat <> asRawData) then begin
  784.                                 PictureType := TiffFile;
  785.                                 RemovePath(fname);
  786.                                 TruncateString(fname, maxTitle);
  787.                                 title := fname;
  788.                                 vref := vnum;
  789.                                 UpdateTitleBar;
  790.                                 if StackInfo = nil then begin
  791.                                         revertable := true;
  792.                                         InvertedImage := false;
  793.                                     end;
  794.                             end;
  795.                     end;
  796.                 if (SaveAsWhat <> asRawData) and (not RoiShowing) then
  797.                     Changes := false;
  798.             end; {with}
  799.         SaveTiffFile := true;
  800.     end;
  801.  
  802.  
  803.     procedure SaveAsTIFF (fname: str255; RefNum: integer; slines, sPixelsPerLine: integer; SavingSelection: boolean);
  804.         var
  805.             err: integer;
  806.             TheInfo: FInfo;
  807.             replacing, ok: boolean;
  808.             name: str255;
  809.     begin
  810.         if info = NoInfo then
  811.             exit(SaveAsTIFF);
  812.         err := GetFInfo(fname, RefNum, TheInfo);
  813.         case err of
  814.             NoErr: 
  815.                 with TheInfo do begin
  816.                         if (fdType <> 'TIFF') and (fdType <> 'PICT') and (fdType <> 'IPIC') and (fdType <> 'RawD') and (fdType <> 'PICS') then begin
  817.                                 TypeMismatch(fname);
  818.                                 exit(SaveAsTIFF)
  819.                             end;
  820.                         replacing := true;
  821.                     end;
  822.             FNFerr:  begin
  823.                     if SaveAsWhat = asRawData then
  824.                         err := create(fname, RefNum, 'Imag', 'RawD')
  825.                     else
  826.                         err := create(fname, RefNum, 'Imag', 'TIFF');
  827.                     if CheckIO(err) <> 0 then
  828.                         exit(SaveAsTIFF);
  829.                     replacing := false;
  830.                 end;
  831.             otherwise
  832.                 if CheckIO(err) <> 0 then
  833.                     exit(SaveAsTIFF);
  834.         end;
  835.         if replacing then
  836.             if not RoomForFile(fname, RefNum, slines, sPixelsPerLine, SavingSelection) then
  837.                 exit(SaveAsTIFF);
  838.         ok := SaveTiffFile(fname, RefNum, slines, sPixelsPerLine, SavingSelection);
  839.         if ok then
  840.             UpdateWindowsMenuItem;
  841.         with info^ do
  842.             if SavingSelection and Replacing and (PictureType <> BlankField) and (PictureType <> FrameGrabberType)  then
  843.                 PictureType := Leftover;
  844.     end;
  845.  
  846.  
  847.     function SavePICTFile (fname: str255; vnum: integer; SavingSelection, NewFile: boolean): boolean;
  848.         var
  849.             f, err, i, v: integer;
  850.             ByteCount, PICTSize: LongInt;
  851.             PicH: PicHandle;
  852.             fRect, frect2: rect;
  853.             tPort: GrafPtr;
  854.             TheInfo: FInfo;
  855.             SaveInfoRec: PicInfo;
  856.             HeaderSaved: boolean;
  857.             SaveGDevice: GDHandle;
  858.  
  859.         procedure Abort;
  860.         begin
  861.             err := fsclose(f);
  862.             if NewFile then
  863.                 err := FSDelete(fname, vnum);
  864.             DisposeHandle(handle(PicH));
  865.             {exit(SavePICTFile)}   {ppc-bug}
  866.         end;
  867.  
  868.     begin
  869.         with info^ do begin
  870.                 if OpPending then
  871.                     KillRoi;
  872.                 SavePICTFile := false;
  873.                 ShowWatch;
  874.                 GetPort(tPort);
  875.                 if SavingSelection then
  876.                     fRect := RoiRect
  877.                 else
  878.                     SetRect(fRect, 0, 0, PixelsPerLine, nlines);
  879.                 with frect do
  880.                     SetRect(frect2, 0, 0, right - left, bottom - top);
  881.                 with osPort^ do begin
  882.                         SaveGDevice := GetGDevice;
  883.                         SetGDevice(osGDevice);
  884.                         SetPort(GrafPtr(osPort));
  885.                         pmForeColor(BlackIndex);
  886.                         pmBackColor(WhiteIndex);
  887.                         if OldSystem then begin
  888.                                 RGBForeColor(BlackRGB);
  889.                                 RGBBackColor(WhiteRGB);
  890.                             end;
  891.                         ClipRect(PicRect);
  892.                         LoadLUT(cTable);
  893.                         PicH := OpenPicture(fRect2);
  894.                         CopyBits(BitMapHandle(PortPixMap)^^, BitMapHandle(PortPixMap)^^, frect, frect2, SrcCopy, nil);
  895.                         ClosePicture;
  896.                         pmForeColor(ForegroundIndex);
  897.                         pmBackColor(BackgroundIndex);
  898.                     end;
  899.                 SetPort(tPort);
  900.                 SetGDevice(SaveGDevice);
  901.                 PICTSize := GetHandleSize(handle(PicH));
  902.                 if PICTSize <= 10 then begin
  903.                         PutError('Sorry, but there is not enough memory available to save this PICT file. Try closing some windows, or save as TIFF.');
  904.                         if NewFile then
  905.                             err := FSDelete(fname, vnum);
  906.                         DisposeHandle(handle(PicH));
  907.                         exit(SavePICTFile)
  908.                     end;
  909.                 err := fsopen(fname, vnum, f);
  910.                 err := SetFPos(f, FSFromStart, 0);
  911.                 SaveInfoRec := Info^;
  912.                 if (LutMode = GrayScale) or (LutMode = CustomGrayScale) then begin
  913.                         nColors := 256;
  914.                         ColorStart := 0;
  915.                         ColorEnd := 255;
  916.                         LUTMode := Grayscale;
  917.                         IdentityFunction := true;
  918.                     end;
  919.                 HeaderSaved := SaveHeader(f, 0, 0, vnum, fname, SavingSelection, false) = 0;
  920.                 Info^ := SaveInfoRec;
  921.                 if not HeaderSaved then begin
  922.                     abort;
  923.                     exit(SavePICTFile)
  924.                 end;
  925.                 err := fswrite(f, PICTSize, pointer(PicH^));
  926.                 if CheckIO(err) <> 0 then begin
  927.                     abort; 
  928.                     exit(SavePICTFile)
  929.                 end;
  930.                 DisposeHandle(handle(PicH));
  931.                 ByteCount := PICTSize + HeaderSize;
  932.                 err := SetEOF(f, ByteCount);
  933.                 err := fsclose(f);
  934.                 err := GetFInfo(fname, vnum, TheInfo);
  935.                 if TheInfo.fdCreator <> 'Imag' then begin
  936.                         TheInfo.fdCreator := 'Imag';
  937.                         err := SetFInfo(fname, vnum, TheInfo);
  938.                     end;
  939.                 if TheInfo.fdType <> 'PICT' then begin
  940.                         TheInfo.fdType := 'PICT';
  941.                         err := SetFInfo(fname, vnum, TheInfo);
  942.                     end;
  943.                 err := FlushVol(nil, vnum);
  944.                 if not SavingSelection then begin
  945.                         if (PictureType <> BlankField) and (PictureType <> FrameGrabberType)  and (PictureType <> NullPicture) then begin
  946.                                 PictureType := PictFile;
  947.                                 RemovePath(fname);
  948.                                 TruncateString(fname, maxTitle);
  949.                                 title := fname;
  950.                                 UpdateTitleBar;
  951.                                 vref := vnum;
  952.                                 revertable := true;
  953.                                 InvertedImage := false;
  954.                             end;
  955.                         Changes := false;
  956.                     end;
  957.             end; {with}
  958.         SavePICTFile := true;
  959.     end;
  960.  
  961.  
  962.     procedure SaveAsPICT (fname: str255; RefNum: integer; SavingSelection: boolean);
  963.         var
  964.             f, err, i: integer;
  965.             where: Point;
  966.             TheInfo: FInfo;
  967.             replacing, ok: boolean;
  968.             name: str255;
  969.     begin
  970.         err := GetFInfo(fname, RefNum, TheInfo);
  971.         case err of
  972.             NoErr: 
  973.                 with TheInfo do begin
  974.                         if (fdType <> 'TIFF') and (fdType <> 'PICT') and (fdType <> 'IPIC') then begin
  975.                                 TypeMismatch(fname);
  976.                                 exit(SaveAsPICT)
  977.                             end;
  978.                         replacing := true;
  979.                     end;
  980.             FNFerr:  begin
  981.                     err := create(fname, RefNum, 'Imag', 'PICT');
  982.                     if CheckIO(err) <> 0 then
  983.                         exit(SaveAsPICT);
  984.                     replacing := false;
  985.                 end;
  986.             otherwise
  987.                 if CheckIO(err) <> 0 then
  988.                     exit(SaveAsPICT);
  989.         end;
  990.         ok := SavePICTFile(fname, RefNum, SavingSelection, not Replacing);
  991.         if ok then
  992.             UpdateWindowsMenuItem;
  993.         with info^ do
  994.             if SavingSelection and replacing and (PictureType <> BlankField) and (PictureType <> FrameGrabberType)  then
  995.                 PictureType := Leftover;
  996.     end;
  997.  
  998.  
  999.     procedure SaveSelection (fname: str255; RefNum: integer; SaveAsSameType: boolean);
  1000.         var
  1001.             slines, spixelsPerLine: integer;
  1002.     begin
  1003.         if info = NoInfo then
  1004.             exit(SaveSelection);
  1005.         if NoSelection or NotRectangular or NotInBounds then
  1006.             exit(SaveSelection);
  1007.         if OpPending then
  1008.             KillRoi;
  1009.         with info^ do begin
  1010.                 with RoiRect do begin
  1011.                         sPixelsPerLine := right - left;
  1012.                         slines := bottom - top;
  1013.                     end;
  1014.                 if (PictureType = PictFile) and SaveAsSameType and (SaveAsWhat <> asRawData) then
  1015.                     SaveAsPICT(fname, RefNum, true)
  1016.                 else
  1017.                     SaveAsTIFF(fname, RefNum, sLines, sPixelsPerLine, true);
  1018.             end;
  1019.     end;
  1020.  
  1021.  
  1022.     procedure SaveAsText (fname: str255; RefNum: integer);
  1023.         var
  1024.             err, f: integer;
  1025.             TheInfo: FInfo;
  1026.             ByteCount: LongInt;
  1027.     begin
  1028.         err := GetFInfo(fname, RefNum, TheInfo);
  1029.         case err of
  1030.             NoErr: 
  1031.                 if TheInfo.fdType <> 'TEXT' then begin
  1032.                         TypeMismatch(fname);
  1033.                         exit(SaveAsText)
  1034.                     end;
  1035.             FNFerr:  begin
  1036.                     err := create(fname, RefNum, FourCharCode(TextCreator), 'TEXT');
  1037.                     if CheckIO(err) <> 0 then
  1038.                         exit(SaveAsText);
  1039.                 end;
  1040.             otherwise
  1041.                 if CheckIO(err) <> 0 then
  1042.                     exit(SaveAsTExt)
  1043.         end;
  1044.         ShowWatch;
  1045.         err := fsopen(fname, RefNum, f);
  1046.         if CheckIO(err) <> 0 then
  1047.             exit(SaveAsText);
  1048.         ByteCount := TextBufSize;
  1049.         err := fswrite(f, ByteCount, ptr(TextBufP));
  1050.         if CheckIO(err) <> 0 then
  1051.             exit(SaveAsText);
  1052.         err := SetEof(f, ByteCount);
  1053.         err := fsclose(f);
  1054.         err := FlushVol(nil, RefNum);
  1055.         if WhatsOnClip = TextOnClip then
  1056.             WhatsOnClip := NothingOnClip;
  1057.     end;
  1058.  
  1059.  
  1060.     procedure SaveAsPICS (fname: str255; fRefNum: integer);
  1061.         const
  1062.             rErr = 'Error Saving PICS file.';
  1063.         var
  1064.             err: OSErr;
  1065.             TheInfo: FInfo;
  1066.             replacing: boolean;
  1067.             rRefNum, i, SaveCS: integer;
  1068.             frect: rect;
  1069.             PicH: array[1..MaxSlices] of PicHandle;
  1070.             MinFreeRequired: LongInt;
  1071.             SaveGDevice: GDHandle;
  1072.     begin
  1073.         with info^, Info^.StackInfo^ do begin
  1074.                 if StackInfo = nil then begin
  1075.                         PutError('Only Stacks can be saved in PICS format.');
  1076.                         SaveAsWhat := asTiff;
  1077.                         exit(SaveAsPICS);
  1078.                     end;
  1079.                 if ImageSize > MinFree then
  1080.                     MinFreeRequired := ImageSize
  1081.                 else
  1082.                     MinFreeRequired := MinFree;
  1083.                 if MaxBlock < MinFreeRequired then begin
  1084.                         PutError('Not enough memory available to save in PICS format.');
  1085.                         exit(SaveAsPICS);
  1086.                     end;
  1087.                 err := GetFInfo(fname, fRefNum, TheInfo);
  1088.                 if err = NoErr then
  1089.                     with TheInfo do begin
  1090.                             if (fdType <> 'TIFF') and (fdType <> 'PICT') and (fdType <> 'PICS') then begin
  1091.                                     TypeMismatch(fname);
  1092.                                     exit(SaveAsPICS)
  1093.                                 end;
  1094.                             err := FSDelete(fname, fRefNum);
  1095.                         end;
  1096.                 ShowWatch;
  1097.                 err := SetVol(nil, fRefNum);
  1098.                 CreateResFile(fname);
  1099.                 if ResError <> NoErr then
  1100.                     exit(SaveAsPICS);
  1101.                 rRefNum := OpenResFile(fname);
  1102.                 SaveCS := CurrentSlice;
  1103.                 SaveGDevice := GetGDevice;
  1104.                 SetGDevice(osGDevice);
  1105.                 SetPort(GrafPtr(osPort));
  1106.                 with PicRect do
  1107.                     SetRect(frect, 0, 0, right - left, bottom - top);
  1108.                 ClipRect(frect);
  1109.                 LoadLUT(ctable);
  1110.                 pmForeColor(BlackIndex);
  1111.                 pmBackColor(WhiteIndex);
  1112.                 if OldSystem then begin
  1113.                         RGBForeColor(BlackRGB);
  1114.                         RGBBackColor(WhiteRGB);
  1115.                     end;
  1116.                 for i := 1 to nSlices do begin
  1117.                         CurrentSlice := i;
  1118.                         SelectSlice(CurrentSlice);
  1119.                         UpdateTitleBar;
  1120.                         PicH[i] := OpenPicture(frect);
  1121.                         with osPort^ do
  1122.                             CopyBits(BitMapHandle(portPixMap)^^, BitMapHandle(portPixMap)^^, PicRect, frect, SrcCopy, nil);
  1123.                         ClosePicture;
  1124.                         if (PicH[i] = nil) or ((PicH[i] <> nil) and (GetHandleSize(handle(PicH[i])) <= 10)) then begin
  1125.                                 PutError(rErr);
  1126.                                 leave;
  1127.                             end;
  1128.                         AddResource(handle(PicH[i]), 'PICT', i - 1 + 128, '');
  1129.                         if ResError <> NoErr then begin
  1130.                                 PutError(rErr);
  1131.                                 leave;
  1132.                             end;
  1133.                         WriteResource(handle(PicH[i]));
  1134.                         ReleaseResource(handle(PicH[i]));
  1135.                         if ResError <> NoErr then begin
  1136.                                 PutError(rErr);
  1137.                                 leave;
  1138.                             end;
  1139.                     end; {for}
  1140.                 pmForeColor(ForegroundIndex);
  1141.                 pmBackColor(BackgroundIndex);
  1142.                 SetGDevice(SaveGDevice);
  1143.                 CurrentSlice := SaveCS;
  1144.                 SelectSlice(CurrentSlice);
  1145.                 RemovePath(fname);
  1146.                 TruncateString(fname, maxTitle);
  1147.                 title := fname;
  1148.                 PictureType := PicsFile;
  1149.                 UpdateTitleBar;
  1150.                 CloseResFile(rRefNum);
  1151.                 if ResError <> NoErr then
  1152.                     PutError(rErr);
  1153.                 err := GetFInfo(fname, fRefNum, TheInfo);
  1154.                 TheInfo.fdType := 'PICS';
  1155.                 TheInfo.fdCreator := 'Imag';
  1156.                 err := SetFInfo(fname, fRefNum, TheInfo);
  1157.                 err := FlushVol(nil, fRefNum);
  1158.                 UpdateWindowsMenuItem;
  1159.             end; {with}
  1160.     end;
  1161.  
  1162.  
  1163.     function SuggestedName: str255;
  1164.         var
  1165.             name: str255;
  1166.     begin
  1167.         case SaveAsWhat of
  1168.             asTiff, asPict, asMacPaint, asRawData, asPICS:  begin
  1169.                     name := info^.title;
  1170.                     if name = 'Camera' then
  1171.                         name := 'Untitled';
  1172.                     SuggestedName := name;
  1173.                 end;
  1174.             AsPalette: 
  1175.                 SuggestedName := 'Palette';
  1176.             AsOutline: 
  1177.                 SuggestedName := 'Outline';
  1178.         end;
  1179.     end;
  1180.  
  1181.  
  1182.     function SaveAsHook (item: integer; theDialog: DialogPtr): integer;
  1183.         const
  1184.             EditTextID = 7;
  1185.             TiffID = 9;
  1186.             OutlineID = 14;
  1187.         var
  1188.             i: integer;
  1189.             fname: str255;
  1190.             NameEdited: boolean;
  1191.     begin
  1192.         if item = -1 then {Initialize}
  1193.             SetDlogItem(theDialog, TiffID + ord(SaveAsWhat), 1);
  1194.         fname := GetDString(theDialog, EditTextID);
  1195.         NameEdited := fname <> SuggestedName;
  1196.         if (item >= TiffID) and (item <= OutlineID) then begin
  1197.                 SaveAsWhat := SaveAsWhatType(item - TiffID);
  1198.                 if not NameEdited then begin
  1199.                         SetDString(theDialog, EditTextID, SuggestedName);
  1200.                         SelectdialogItemText(theDialog, EditTextID, 0, 32767);
  1201.                     end;
  1202.                 for i := TiffID to OutlineID do
  1203.                     SetDlogItem(theDialog, i, 0);
  1204.                 SetDlogItem(theDialog, item, 1);
  1205.             end;
  1206.         SaveAsHook := item;
  1207.     end;
  1208.  
  1209.  
  1210.     procedure SaveAs (name: str255; RefNum: integer);
  1211.         const
  1212.             CustomDialogID = 60;
  1213.         var
  1214.             where: Point;
  1215.             reply: SFReply;
  1216.             isSelection: boolean;
  1217.             kind: integer;
  1218.     begin
  1219.         if SaveAsDHookProc=nil
  1220.             then SaveAsDHookProc:=NewRoutineDescriptor(@SaveAsHook, uppDlgHookProcInfo, GetCurrentISA);
  1221.         with info^ do begin
  1222.                 if SaveAllState = SaveAllStage2 then begin
  1223.                         name := title;
  1224.                         RefNum := SaveRefNum;
  1225.                         if SaveAsWhat = AsPalette then
  1226.                             SaveAsWhat := AsTiff;
  1227.                     end
  1228.                 else if (name = '') or ((RefNum = 0) and (pos(':', name) = 0)) then begin
  1229.                         where.v := 50;
  1230.                         where.h := 50;
  1231.                         if (StackInfo = nil) and (SaveAsWhat = asPICS) then
  1232.                             SaveAsWhat := asTIFF;
  1233.                         if (StackInfo <> nil) and ((SaveAsWhat = asPICT) or (SaveAsWhat = asMacPaint)) then
  1234.                             SaveAsWhat := asTIFF;
  1235.                         if name = '' then
  1236.                             name := SuggestedName;
  1237.                         SFPPutFile(Where, 'Save as?', name, SaveAsDHookProc, reply, CustomDialogID, nil);
  1238.                         if not reply.good then begin
  1239.                                 SaveAllState := NoSaveAll;
  1240.                                 AbortMacro;
  1241.                                 exit(SaveAs);
  1242.                             end;
  1243.                         with reply do begin
  1244.                                 name := fname;
  1245.                                 RefNum := vRefNum;
  1246.                                 DefaultRefNum := RefNum;
  1247.                             end;
  1248.                     end;
  1249.                 if StackInfo <> nil then begin
  1250.                         if (SaveAsWhat <> asOutline) and not ((StackInfo^.StackType = RGBStack) and (StackInfo^.nSlices = 3)) then
  1251.                             KillRoi;
  1252.                         SaveAllState := NoSaveAll;
  1253.                         if not ((SaveAsWhat = asTIFF) or (SaveAsWhat = asPICS) or (SaveAsWhat = asPalette) or (SaveAsWhat = asOutline)) then begin
  1254.                                 PutError('Stacks can only be saved in TIFF or PICS format.');
  1255.                                 SaveAsWhat := asTIFF;
  1256.                                 exit(SaveAs);
  1257.                             end;
  1258.                     end;
  1259.                 isSelection := RoiShowing and (RoiType = RectRoi);
  1260.                 if SaveAllState = SaveAllStage1 then begin
  1261.                         SaveRefNum := RefNum;
  1262.                         SaveAllState := SaveAllStage2;
  1263.                     end;
  1264.                 case SaveAsWhat of
  1265.                     asTiff, asRawData: 
  1266.                         if isSelection then
  1267.                             SaveSelection(name, RefNum, false)
  1268.                         else
  1269.                             SaveAsTIFF(name, RefNum, 0, 0, false);
  1270.                     asPict: 
  1271.                         if isSelection then
  1272.                             SaveAsPICT(name, RefNum, true)
  1273.                         else
  1274.                             SaveAsPICT(name, RefNum, false);
  1275.                     asMacPaint: 
  1276.                         SaveAsMacPaint(name, RefNum);
  1277.                     asPICS: 
  1278.                         SaveAsPICS(name, RefNum);
  1279.                     AsPalette: 
  1280.                         SaveColorTable(name, RefNum);
  1281.                     AsOutline: 
  1282.                         SaveOutline(name, RefNum);
  1283.                 end; {case}
  1284.                 if (SaveAsWhat = asRawData) and (SaveAllState <> SaveAllStage2) then
  1285.                     SaveAsWhat := asTIFF;
  1286.             end; {with}
  1287.     end;
  1288.  
  1289.  
  1290.     procedure SaveFile;
  1291.         var
  1292.             fname: str255;
  1293.             size: LongInt;
  1294.             ok: boolean;
  1295.     begin
  1296.         if CurrentWindow = ResultsKind then begin
  1297.                 Export('', 0);
  1298.                 exit(SaveFile);
  1299.             end;
  1300.         if CurrentWindow = TextKind then begin
  1301.                 SaveText;
  1302.                 exit(SaveFile);
  1303.             end;
  1304.         if OpPending then
  1305.             KillRoi;
  1306.         with Info^ do begin
  1307.                 fname := title;
  1308.                 size := 0;
  1309.                 if PictureType = TiffFile then
  1310.                     ok := SaveTiffFile(fname, vref, 0, 0, false)
  1311.                 else if PictureType = PictFile then
  1312.                     ok := SavePICTFile(fname, vref, false, false)
  1313.                 else
  1314.                     SaveAs('', 0);
  1315.             end;
  1316.     end;
  1317.  
  1318.  
  1319.     function SaveChanges: integer;
  1320.         const
  1321.             yesID = 1;
  1322.             noID = 2;
  1323.             cancelID = 3;
  1324.         var
  1325.             id: integer;
  1326.             reply: SFReply;
  1327.     begin
  1328.         id := 0;
  1329.         if info^.changes then
  1330.             with info^ do begin
  1331.                     if CommandPeriod or MakingStack or (macro and ((MacroCommand = DisposeC) or (MacroCommand = DisposeAllC))) then begin
  1332.                             SaveChanges := ok;
  1333.                             exit(SaveChanges);
  1334.                         end;
  1335.                     ParamText(title, '', '', '');
  1336.                     InitCursor;
  1337.                     id := alert(600, nil);
  1338.                     if id = yesID then begin
  1339.                             SaveFile;
  1340.                             InitCursor;
  1341.                         end; {if yes}
  1342.                 end; {if changes}
  1343.         if (id = cancelID) or ((id = yesID) and (info^.changes)) then
  1344.             SaveChanges := cancel
  1345.         else
  1346.             SaveChanges := ok;
  1347.     end;
  1348.  
  1349.  
  1350.     function CloseAWindow (WhichWindow: WindowPtr): integer;
  1351.         var
  1352.             i, kind, n: integer;
  1353.             TempInfo: InfoPtr;
  1354.             TempTextInfo: TextInfoPtr;
  1355.             SizeStr, str: str255;
  1356.             wp: ^WindowPtr;
  1357.             pcrect: rect;
  1358.     begin
  1359.         if WhichWindow = nil then
  1360.             exit(CloseAWindow);
  1361.         kind := WindowPeek(WhichWindow)^.WindowKind;
  1362.         CloseAWindow := ok;
  1363.         if WhichWindow = VideoControl then begin
  1364.                 DisposeDialog(VideoControl);
  1365.                 VideoControl := nil;
  1366.                 exit(CloseAWindow);
  1367.             end;
  1368.         case kind of
  1369.             PicKind:  begin
  1370.                     Info := pointer(WindowPeek(WhichWindow)^.RefCon);
  1371.                     with Info^ do begin
  1372.                             if PicNum = 0 then begin
  1373.                                     beep;
  1374.                                     exit(CloseAWindow);
  1375.                                 end;
  1376.                             if SaveChanges = cancel then begin
  1377.                                     CloseAWindow := cancel;
  1378.                                     exit(CloseAWindow)
  1379.                                 end;
  1380.                             DeleteMenuItem(WindowsMenuH, PicNum + WindowsMenuItems + nTextWindows);
  1381.                             for i := PicNum to nPics - 1 do begin
  1382.                                     PicWindow[i] := PicWindow[i + 1];
  1383.                                     TempInfo := pointer(WindowPeek(PicWindow[i])^.RefCon);
  1384.                                     TempInfo^.PicNum := i
  1385.                                 end;
  1386.                             if PictureType = BlankField then
  1387.                                 BlankFieldInfo := nil;
  1388.                             if (PictureType = FrameGrabberType) and (FrameGrabber = QTvdig) then
  1389.                                 CloseVdig;
  1390.                             if StackInfo <> nil then begin
  1391.                                     with StackInfo^ do
  1392.                                         for i := 1 to nSlices do
  1393.                                             DisposeHandle(PicBaseH[i]);
  1394.                                     DisposePtr(pointer(StackInfo));
  1395.                                 end
  1396.                             else begin
  1397.                                     if not MakingStack then
  1398.                                         DisposeHandle(PicBaseHandle);
  1399.                                 end;
  1400.                             DisposeWindow(WhichWindow);
  1401.                             CloseCPort(osPort);
  1402.                             DisposePtr(ptr(osPort));
  1403.                             DisposeRgn(roiRgn);
  1404.                             if DataH <> nil then
  1405.                                     DisposeHandle(DataH);
  1406.                             nPics := nPics - 1;
  1407.                             OpPending := false;
  1408.                             isInsertionPoint := false;
  1409.                             DisposePtr(pointer(Info));
  1410.                             Info := NoInfo;
  1411.                             if (nPics = 0) and (not finished) then
  1412.                                 with info^ do begin
  1413.                                         LoadLUT(info^.cTable);
  1414.                                         if (LutMode = GrayScale) or (LutMode = CustomGrayScale) then
  1415.                                             DrawMap;
  1416.                                     end;
  1417.                             PicLeft := PicLeftBase;
  1418.                             PicTop := PicTopBase;
  1419.                         end;
  1420.                 end; {PicKind}
  1421.             HistoKind:  begin
  1422.                     DisposeWindow(HistoWindow);
  1423.                     HistoWindow := nil;
  1424.                     ContinuousHistogram := false;
  1425.                 end;
  1426.             ProfilePlotKind, CalibrationPlotKind:  begin
  1427.                     DisposeWindow(PlotWindow);
  1428.                     PlotWindow := nil;
  1429.                     KillPicture(PlotPICT);
  1430.                     PlotPICT := nil;
  1431.                 end;
  1432.             ResultsKind:  begin
  1433.                     DisposeWindow(ResultsWindow);
  1434.                     ResultsWindow := nil;
  1435.                     TEDispose(ListTE);
  1436.                 end;
  1437.             TextKind:  begin
  1438.                     TextInfo := TextInfoPtr(WindowPeek(WhichWindow)^.RefCon);
  1439.                     if TextInfo <> nil then
  1440.                         with TextInfo^ do begin
  1441.                                 if SaveTextChanges = cancel then begin
  1442.                                         CloseAWindow := cancel;
  1443.                                         exit(CloseAWindow)
  1444.                                     end;
  1445.                                 DisposeWindow(TextWindowPtr);
  1446.                                 DeleteMenuItem(WindowsMenuH, WindowsMenuItems - 1 + WindowNum);
  1447.                                 TEDispose(TextTE);
  1448.                                 DisposePtr(ptr(TextInfo));
  1449.                                 TextInfo := nil;
  1450.                                 for i := WindowNum to nTextWindows - 1 do begin
  1451.                                         TextWindow[i] := TextWindow[i + 1];
  1452.                                         TempTextInfo := pointer(WindowPeek(TextWindow[i])^.RefCon);
  1453.                                         TempTextInfo^.WindowNum := i
  1454.                                     end;
  1455.                                 nTextWindows := nTextWindows - 1;
  1456.                             end;
  1457.                 end;
  1458.             PasteControlKind:  begin
  1459.                     GetWindowRect(PasteControl, pcrect);
  1460.                     with pcrect do begin
  1461.                             PasteControlLeft := left;
  1462.                             PasteControlTop := top;
  1463.                         end;
  1464.                     DisposeWindow(PasteControl);
  1465.                     PasteControl := nil;
  1466.                     wp := pointer(GhostWindow);
  1467.                     wp^ := nil;
  1468.                 end;
  1469.             otherwise
  1470.                 ;
  1471.         end; {case}
  1472.     end;
  1473.  
  1474.  
  1475.     procedure DoClose;
  1476.         var
  1477.             ignore: integer;
  1478.             fwptr: WindowPtr;
  1479.             kind: integer;
  1480.     begin
  1481.         fwptr := FrontWindow;
  1482.         if fwptr <> nil then begin
  1483.                 if fwptr = VideoControl then begin
  1484.                         DisposeDialog(VideoControl);
  1485.                         VideoControl := nil;
  1486.                         exit(DoClose);
  1487.                     end;
  1488.                 kind := WindowPeek(fwptr)^.WindowKind;
  1489.                 if (kind = PicKind) or (kind = ProfilePlotKind) or (kind = CalibrationPlotKind) or (kind = HistoKind) or (Kind = PasteControlKind) or (Kind = ResultsKind) or (Kind = TextKind) then
  1490.                     ignore := CloseAWindow(fwptr);
  1491.             end;
  1492.     end;
  1493.  
  1494.  
  1495.     procedure Read4BitTIFF (f: integer);
  1496.         var
  1497.             vloc, hloc, i: integer;
  1498.             ByteCount, count: LongInt;
  1499.             err: OSErr;
  1500.             UnpackedLine, PackedLine: LineType;
  1501.     begin
  1502.         with info^ do begin
  1503.                 if PixelsPerLine > MaxLine then
  1504.                     exit(Read4BitTIFF);
  1505.                 ByteCount := (PixelsPerLine + 1) div 2;
  1506.                 for vloc := 0 to nLines - 1 do begin
  1507.                         err := FSRead(f, ByteCount, @PackedLine);
  1508.                         i := 0;
  1509.                         for hloc := 0 to PixelsPerLine - 1 do
  1510.                             if odd(hloc) then begin
  1511.                                     UnpackedLine[hloc] := bsl(band(PackedLine[i], $F), 4);
  1512.                                     i := i + 1;
  1513.                                 end
  1514.                             else
  1515.                                 UnpackedLine[hloc] := band(PackedLine[i], $F0);
  1516.                         PutLine(0, vloc, PixelsPerLine, UnpackedLine);
  1517.                     end;
  1518.             end; {with}
  1519.     end;
  1520.  
  1521.  
  1522. {$POP}
  1523.  
  1524.     procedure CheckFileSize(f:integer; var size: LongInt; offset: LongInt);
  1525.     {Check to make sure we don't read past the end of file.}
  1526.     var
  1527.         FileSize: LongInt;
  1528.         err: OSErr;
  1529.     begin
  1530.         err := GetEof(f, FileSize);
  1531.         if (offset + size) > FileSize then begin
  1532.            size := FileSize - offset;
  1533.            if size < 0 then size := 0;
  1534.         end;
  1535.     end;
  1536.  
  1537.  
  1538.     procedure ReadStackSlices (f, nExtraImages: integer; var table: TiffIFDTable);
  1539.         var
  1540.             i, err, SaveCS: integer;
  1541.             h: handle;
  1542.             DataSize: LongInt;
  1543.             PartialStack: boolean;
  1544.     begin
  1545.         ShowMessage(CmdPeriodToStop);
  1546.         PartialStack := false;
  1547.         with info^ do begin
  1548.                 StackInfo := StackInfoPtr(NewPtr(SizeOf(StackInfoRec)));
  1549.                 if StackInfo = nil then
  1550.                     exit(ReadStackSlices);
  1551.             end;
  1552.         with info^, info^.StackInfo^ do begin
  1553.                 nSlices := nExtraImages + 1;
  1554.                 CurrentSlice := TempStackInfo.CurrentSlice;
  1555.                 if (CurrentSlice < 1) or (CurrentSlice > nSlices) then
  1556.                     CurrentSlice := 1;
  1557.                 SliceSpacing := TempStackInfo.SliceSpacing;
  1558.                 FrameInterval := TempStackInfo.FrameInterval;
  1559.                 StackType := TempStackInfo.StackType;
  1560.                 SaveCS := CurrentSlice;
  1561.                 PicBaseH[1] := PicBaseHandle;
  1562.                 revertable := false;
  1563.                 for i := 2 to nSlices do begin
  1564.                         h := GetBigHandle(PixMapSize);
  1565.                         if h = nil then begin
  1566.                                 nSlices := i - 1;
  1567.                                 PutError(concat('Not enough memory to open all ', long2str(nExtraImages + 1), ' slices in the stack.'));
  1568.                                 PartialStack := true;
  1569.                                 leave;
  1570.                             end;
  1571.                         PicBaseH[i] := h;
  1572.                         CurrentSlice := i;
  1573.                         SelectSlice(i);
  1574.                         UpdateTitleBar;
  1575.                         DataSize := ImageSize;
  1576.                         err := SetFPos(f, fsFromStart, table[i - 1].offset);
  1577.                         CheckFileSize(f, DataSize, table[i - 1].offset);
  1578.                         if DataSize > 0 then
  1579.                             err := fsread(f, DataSize, h^);
  1580.                         if odd(PixelsPerLine) then
  1581.                             UnpackLines;
  1582.                         if InvertedImage then
  1583.                             InvertPic;
  1584.                         UpdatePicWindow;
  1585.                         if CommandPeriod then begin
  1586.                                 beep;
  1587.                                 if i < nSlices then
  1588.                                     PartialStack := true;
  1589.                                 nSlices := i;
  1590.                                 wait(60);
  1591.                                 leave;
  1592.                             end;
  1593.                     end; {for}
  1594.                 CurrentSlice := SaveCS;
  1595.                 if CurrentSlice > nSlices then
  1596.                     CurrentSlice := 1;
  1597.                 SelectSlice(CurrentSlice);
  1598.                 if PartialStack then begin
  1599.                         vref := 0;
  1600.                         PictureType := NewPicture;
  1601.                         title := concat(title, '@');
  1602.                     end;
  1603.                 UpdateTitleBar;
  1604.                 UpdateWindowsMenuItem;
  1605.             end;
  1606.     end;
  1607.  
  1608.  
  1609.     procedure OpenStack (f: integer);
  1610.         var
  1611.             table: TiffIFDTable;
  1612.             i, nExtraImages: integer;
  1613.             where: LongInt;
  1614.     begin
  1615.         nExtraImages := TempStackInfo.nSlices - 1;
  1616.         with info^ do begin
  1617.                 where := ImageDataOffset;
  1618.                 for i := 1 to nExtraImages do
  1619.                     with table[i] do begin
  1620.                             iWidth := PixelsPerLine;
  1621.                             iHeight := nLines;
  1622.                             where := where + ImageSize;
  1623.                             Offset := where;
  1624.                             invert := false;
  1625.                         end;
  1626.                 ReadStackSlices(f, nExtraImages, table);
  1627.             end;
  1628.     end;
  1629.  
  1630.  
  1631.     procedure OpenExtraTiffImages (f: integer; NextTiffIFD: LongInt);
  1632.         var
  1633.             table: TiffIFDTable;
  1634.             TiffInfo: TiffInfoRec;
  1635.             i, nExtraImages: integer;
  1636.             AllSameSize: boolean;
  1637.     begin
  1638.         nExtraImages := 0;
  1639.         repeat
  1640.             if not OpenTiffDirectory(f, NextTiffIFD, TiffInfo, false) then
  1641.                 exit(OpenExtraTiffImages);
  1642.             nExtraImages := nExtraImages + 1;
  1643.             with TiffInfo, table[nExtraImages] do begin
  1644.                     iWidth := width;
  1645.                     iHeight := height;
  1646.                     Offset := OffsetToData;
  1647.                     invert := ZeroIsBlack;
  1648.                     NextTiffIFD := NextIFD;
  1649.                 end;
  1650.         until (NextTiffIFD = 0) or (nExtraImages = MaxSlices);
  1651.         AllSameSize := true;
  1652.         with info^ do begin
  1653.                 for i := 1 to nExtraImages do
  1654.                     AllSameSize := AllSameSize and (PixelsPerLine = table[i].iWidth) and (nLines = table[i].iHeight);
  1655.                 if AllSameSize and not odd(PixelsPerLine) then
  1656.                     ReadStackSlices(f, nExtraImages, table);
  1657.             end;
  1658.     end;
  1659.  
  1660.     procedure OpenRGBTiff(f: integer);
  1661.     const
  1662.         bufsize = 12000;
  1663.     var
  1664.         i, row, pixel, rgbPixel, ignore, SaveRow: integer;
  1665.         NextUpdate, count: LongInt;
  1666.         buffer: packed array [0 .. bufsize] of byte;
  1667.         rLine, gLine, bLine: LineType;
  1668.         err: OSErr;
  1669.         MaskRect: rect;
  1670.     begin
  1671.         with info^ do begin
  1672.             if PixelsPerLine > MaxLine then
  1673.                 exit(OpenRGBTiff);
  1674.             if not MakeStackFromWindow then
  1675.                 exit(OpenRGBTiff);
  1676.             if not AddSlice(false) then begin
  1677.                     info^.changes := false;
  1678.                     ignore := CloseAWindow(info^.wptr);
  1679.                     exit(OpenRGBTiff);
  1680.                 end;
  1681.             if not AddSlice(false) then begin
  1682.                     info^.changes := false;
  1683.                     ignore := CloseAWindow(info^.wptr);
  1684.                     exit(OpenRGBTiff);
  1685.                 end;
  1686.             SaveRow:=0;
  1687.             NextUpdate:=TickCount+6;
  1688.             err := SetFPos(f, fsFromStart, ImageDataOffset);
  1689.             count := 0;
  1690.             for row:=0 to nLines - 1 do begin
  1691.                 for pixel := 0 to PixelsPerLine - 1 do begin
  1692.                     if count <= 0 then begin
  1693.                         count := bufsize;
  1694.                         err := fsread(f, count, @buffer);
  1695.                         if err <> -39 then {eof error}
  1696.                             if CheckIO(err) <> noErr then
  1697.                                 exit(OpenRGBTiff);
  1698.                         rgbPixel := 0;
  1699.                     end;
  1700.                     rLine[pixel] := 255 - buffer[rgbPixel];
  1701.                     gLine[pixel] := 255 - buffer[rgbPixel + 1];
  1702.                     bLine[pixel] := 255 - buffer[rgbPixel + 2];
  1703.                     rgbPixel := rgbPixel + 3;
  1704.                     count := count - 3;
  1705.                 end;
  1706.                 SelectSlice(1);
  1707.                 PutLine(0, row, PixelsPerLine, rLine);
  1708.                 if TickCount>=NextUpdate then begin
  1709.                     SetRect(MaskRect, 0, SaveRow, PixelsPerLine, row+1);
  1710.                     UpdateScreen(MaskRect);
  1711.                     SaveRow:=row + 1;
  1712.                     NextUpdate:=TickCount+6;
  1713.                 end;
  1714.                 SelectSlice(2);
  1715.                 PutLine(0, row, PixelsPerLine, gLine);
  1716.                 SelectSlice(3);
  1717.                 PutLine(0, row, PixelsPerLine, bLine);
  1718.             end; {for}
  1719.             with StackInfo^ do begin
  1720.                 CurrentSlice := 1;
  1721.                 SelectSlice(CurrentSlice);
  1722.                 StackType := rgbStack;
  1723.             end;
  1724.             SetRect(MaskRect, 0, SaveRow, PixelsPerLine, nLines);
  1725.             UpdateScreen(MaskRect);
  1726.             UpdateTitleBar;
  1727.             ResetGrayMap;
  1728.             OpeningRGB := true;
  1729.         end; {with}
  1730.     end;
  1731.     
  1732.  
  1733.     function OpenFile (fname: str255; vnum: integer): boolean;
  1734.         var
  1735.             ticks, ByteCount, i, DataSize, NextTiffIFD: LongInt;
  1736.             err: OSErr;
  1737.             f: integer;
  1738.             line, pixel: integer;
  1739.             iptr, p: ptr;
  1740.             SaveInfo: InfoPtr;
  1741.             TiffInfo: TiffInfoRec;
  1742.             isRGBTiff: boolean;
  1743.     begin
  1744.         OpenFile := false;
  1745.         ShowWatch;
  1746.         err := fsopen(fname, vNum, f);
  1747.         SaveInfo := Info;
  1748.         iptr := NewPtr(SizeOf(PicInfo));
  1749.         if iptr = nil then begin
  1750.                 PutMemoryAlert;
  1751.                 err := fsclose(f);
  1752.                 exit(OpenFile)
  1753.             end;
  1754.         Info := pointer(iptr);
  1755.         CloneInfo(SaveInfo^, Info^);
  1756.         with Info^ do begin
  1757.                 ColorMapOffset := 0;
  1758.                 if not OpenHeader(f, fname, vnum, TiffInfo) then begin
  1759.                         DisposePtr(iptr);
  1760.                         err := fsclose(f);
  1761.                         Info := SaveInfo;
  1762.                         exit(OpenFile)
  1763.                     end;
  1764.                 if WhatToOpen = OpenTIFF then begin
  1765.                     NextTiffIFD := TiffInfo.NextIFD;
  1766.                     isRGBTiff := TiffInfo.SamplesPerPixel = 3;
  1767.                 end else begin
  1768.                     NextTiffIFD := 0;
  1769.                     isRGBTiff := false;
  1770.                 end;
  1771.                 p := GetImageMemory(SaveInfo);
  1772.                 if p = nil then begin
  1773.                         err := fsclose(f);
  1774.                         exit(OpenFile)
  1775.                     end;
  1776.                 PicBaseAddr := p;
  1777.                 MakeNewWindow(fname);
  1778.                 err := SetFPos(f, fsFromStart, ImageDataOffset);
  1779.                 if PictureType = FourBitTIFF then
  1780.                     Read4BitTIFF(f)
  1781.                 else if not isRGBTiff then begin
  1782.                         DataSize := nlines * PixelsPerLine;
  1783.                         CheckFileSize(f, DataSize, ImageDataOffset);
  1784.                         if DataSize > 0 then
  1785.                             err := fsread(f, DataSize, PicBaseAddr);
  1786.                         if CheckIO(err) <> NoErr then begin
  1787.                                 err := fsclose(f);
  1788.                                 exit(OpenFile)
  1789.                             end;
  1790.                     end;
  1791.                 if odd(PixelsPerLine) and (PictureType <> FourBitTiff) then
  1792.                     UnpackLines;
  1793.                 if (PictureType = Imported) and (ImportInvert or (WhatToImport = ImportMCID)) then
  1794.                     InvertedImage := true;
  1795.                 if InvertedImage then
  1796.                     InvertPic;
  1797.                 if PictureType = FourBitTIFF then
  1798.                     PictureType := imported;
  1799.                 if (ColorMapOffset > 0) and (fileVersion = 0) then begin
  1800.                         FixColors; {Fix colors, if necessary, of imported color TIFF files.}
  1801.                         WhatToUndo := NothingToUndo;
  1802.                     end;
  1803.                 vref := vnum;
  1804.                 if PixMapSize > UndoBufSize then
  1805.                     PutWarning;
  1806.                 revertable := true;
  1807.             end; {with}
  1808.             if isRGBTiff then
  1809.                 OpenRGBTiff(f)
  1810.             else if TempStackInfo.nSlices > 0 then
  1811.                 OpenStack(f)
  1812.             else if NextTiffIFD > 0 then
  1813.             OpenExtraTiffImages(f, NextTiffIFD);
  1814.         err := fsclose(f);
  1815.         OpenFile := true;
  1816.     end;
  1817.  
  1818.  
  1819. {$PUSH}
  1820. {$D-}
  1821.  
  1822.     procedure ScaleToEightBits (f: integer);
  1823.         type
  1824.             PixelLUTType = packed array[0..65535] of byte;
  1825.             PixelLUTPtr = ^PixelLUTType;
  1826.             IntLineType = array[0..MaxLine] of integer;
  1827.         var
  1828.             line: LineType;
  1829.             i, j, value, LineSize, offset: LongInt;
  1830.             ScaleFactor: extended;
  1831.             hloc, vloc, wwidth, wheight, IntValue, SaveBytesPerRow: integer;
  1832.             PixelLUT: PixelLUTPtr;
  1833.             str1, str2: str255;
  1834.             err: integer;
  1835.             aLine: IntLineType;
  1836.             LinesPerUpdate: integer;
  1837.  
  1838.         procedure reset;
  1839.             var
  1840.                 DataSize, SliceOffset: LongInt;
  1841.                 p: ptr;
  1842.         begin
  1843.             with info^ do begin
  1844.                     if StackInfo <> nil then
  1845.                         SliceOffset := ImageSize * 2 * (StackInfo^.CurrentSlice - 1)
  1846.                     else
  1847.                         SliceOffset := 0;
  1848.                     err := SetFPos(f, fsFromStart, ImageDataOffset + SliceOffset);
  1849.                     if DataH <> nil then begin
  1850.                             if offset = -1 then begin
  1851.                                     hlock(DataH);
  1852.                                     DataSize := ImageSize * 2;
  1853.                                     CheckFileSize(f, DataSize, ImageDataOffset);
  1854.                                     if DataSize > 0 then
  1855.                                         err := fsread(f, DataSize, DataH^);
  1856.                                 end;
  1857.                             offset := 0
  1858.                         end;
  1859.                 end;
  1860.         end;
  1861.  
  1862.  
  1863.         procedure GetIntLine (var line: IntLineType);
  1864.             type
  1865.                 atype = packed array[1..2] of char;
  1866.             var
  1867.                 p: ptr;
  1868.                 a: atype;
  1869.                 c: char;
  1870.                 i: integer;
  1871.         begin
  1872.             with info^ do begin
  1873.                     if DataH <> nil then begin
  1874.                             p := ptr(ord4(DataH^) + offset);
  1875.                             if (offset + LineSize) <= (PixMapSize * 2) then
  1876.                                 BlockMove(p, @line, LineSize);
  1877.                             offset := offset + LineSize;
  1878.                         end
  1879.                     else
  1880.                         err := fsread(f, LineSize, @line);
  1881.                     if LittleEndian then
  1882.                         for i := 0 to LineSize div 2 - 1 do begin
  1883.                                 a := atype(line[i]);
  1884.                                 c := a[1];
  1885.                                 a[1] := a[2];
  1886.                                 a[2] := c;
  1887.                                 line[i] := integer(a)
  1888.                             end;
  1889.                 end;
  1890.         end;
  1891.         
  1892.         procedure FindMinAndMax;
  1893.         var
  1894.             vloc, hloc: integer;
  1895.             value: LongInt;
  1896.         begin
  1897.             with info^ do begin
  1898.                 AbsoluteMin := 999999;
  1899.                 AbsoluteMax := -999999;
  1900.                 for vloc := 0 to nlines - 1 do begin
  1901.                         if (vloc mod LinesPerUpdate) = 0 then
  1902.                             ShowAnimatedWatch;
  1903.                         GetIntLine(aLine);
  1904.                         for hloc := 0 to PixelsPerLine - 1 do begin
  1905.                                 value := aLine[hloc];
  1906.                                 if (DataType = SixteenBitsUnsigned) and (value < 0) then
  1907.                                     value := value + 65536;
  1908.                                 if value > AbsoluteMax then
  1909.                                     AbsoluteMax := value;
  1910.                                 if value < AbsoluteMin then begin
  1911.                                     if ImportingDicom then begin
  1912.                                         if value <> -32767 then AbsoluteMin := value
  1913.                                     end else
  1914.                                         AbsoluteMin := value;
  1915.                                 end; {value <AbsoluteMin}
  1916.                             end {for hloc:=}
  1917.                     end;{for vloc := }
  1918.                 if (CurrentMin = 0) and (CurrentMax = 0) then begin
  1919.                         CurrentMin := AbsoluteMin;
  1920.                         CurrentMax := AbsoluteMax;
  1921.                     end;
  1922.                 reset;
  1923.             end; {with}
  1924.         end;
  1925.  
  1926.     begin
  1927.         with info^ do begin
  1928.                 PixelLUT := PixelLUTPtr(NewPtr(SizeOf(PixelLUTType)));
  1929.                 if PixelLUT = nil then begin
  1930.                         if DataH <> nil then begin
  1931.                                 DisposeHandle(DataH);
  1932.                                 DataH := nil
  1933.                             end;
  1934.                         PutError('Not enough memory to do 16 to 8-bit scaling.');
  1935.                         AbortMacro;
  1936.                         exit(ScaleToEightBits);
  1937.                     end;
  1938.                 offset := -1;
  1939.                 reset;
  1940.                 LineSize := PixelsPerLine * 2;
  1941.                 LinesPerUpdate := 40000 div LineSize;
  1942.                 if (AbsoluteMin = 0) and (AbsoluteMax = 0) then
  1943.                     FindMinAndMax;
  1944.                 str1 := concat('min=', long2str(CurrentMin), ' (', long2str(AbsoluteMin), ')', crStr, 'max=', long2str(CurrentMax), ' (', long2str(AbsoluteMax), ')');
  1945.                 ScaleFactor := 253.0 / (CurrentMax - CurrentMin);
  1946.                 RealToString(ScaleFactor, 1, 4, str2);
  1947.                 ShowMessage(concat(str1, crStr, 'scale factor= ', str2));
  1948.                 j := 0;
  1949.                 for i := CurrentMin to CurrentMax do begin
  1950.                         PixelLUT^[j] := round((i - CurrentMin) * ScaleFactor + 1);
  1951.                         j := j + 1;
  1952.                     end;
  1953.                 for vloc := 0 to nlines - 1 do begin
  1954.                         if (vloc mod LinesPerUpdate) = 0 then
  1955.                             ShowAnimatedWatch;
  1956.                         GetIntLine(aLine);
  1957.                         for hloc := 0 to PixelsPerLine - 1 do begin
  1958.                                 value := aLine[hloc];
  1959.                                 if (DataType = SixteenBitsUnsigned) and (value < 0) then
  1960.                                     value := value + 65536;
  1961.                                 if value < CurrentMin then
  1962.                                     value := CurrentMin;
  1963.                                 if value > CurrentMax then
  1964.                                     value := CurrentMax;
  1965.                                 line[hloc] := PixelLUT^[value - CurrentMin];
  1966.                                 i := i + 1;
  1967.                             end;
  1968.                         PutLine(0, vloc, PixelsPerLine, line);
  1969.                     end;
  1970.                 if fit = StraightLine then begin
  1971.                         nCoefficients := 2;
  1972.                         coefficient[2] := (CurrentMin - CurrentMax) / 253.0;
  1973.                         coefficient[1] := CurrentMax - coefficient[2];
  1974.                         nKnownValues := 0;
  1975.                         ZeroClip := false;
  1976.                         UpdateTitleBar;
  1977.                     end;
  1978.                 DisposePtr(ptr(PixelLUT));
  1979.                 if DataH <> nil then begin
  1980.                         DisposeHandle(DataH);
  1981.                         DataH := nil
  1982.                     end;
  1983.             end; {with}
  1984.     end;
  1985.  
  1986.  
  1987.     procedure RescaleToEightBits;
  1988.         var
  1989.             range: LongInt;
  1990.             err: OSErr;
  1991.             f: integer;
  1992.     begin
  1993.         with info^ do begin
  1994.                 ShowWatch;
  1995.                 KillRoi;
  1996.                 DisableDensitySlice;
  1997.                 err := fsopen(title, vref, f);
  1998.                 if CheckIO(err) <> 0 then
  1999.                     exit(RescaleToEightBits);
  2000.                 range := CurrentMax - CurrentMin;
  2001.                 if ColorStart > 0 then
  2002.                     CurrentMax := CurrentMax - round((ColorStart / 255.0) * range)
  2003.                 else
  2004.                     CurrentMax := AbsoluteMax;
  2005.                 if ColorEnd < 255 then
  2006.                     CurrentMin := CurrentMin + round(((255 - ColorEnd) / 255.0) * range)
  2007.                 else
  2008.                     CurrentMin := AbsoluteMin;
  2009.                 ScaleToEightBits(f);
  2010.                 err := fsclose(f);
  2011.                 InvertPic;
  2012.                 UpdatePicWindow;
  2013.                 ResetMap;
  2014.                 if fit <> uncalibrated then
  2015.                     GenerateValues;
  2016.             end;
  2017.     end;
  2018.  
  2019.  
  2020.     procedure Import16BitSlices (f: integer);
  2021.         var
  2022.             i, err: integer;
  2023.             h: handle;
  2024.             DataSize, nImages, MaxImages, FileSize: LongInt;
  2025.     begin
  2026.         with info^ do begin
  2027.                 nImages := ImportCustomSlices;
  2028.                 err := GetEof(f, FileSize);
  2029.                 MaxImages := (FileSize - ImportCustomOffset) div (ImageSize * 2);
  2030.                 if nImages > MaxImages then
  2031.                     nImages := MaxImages;
  2032.                 if nImages < 2 then
  2033.                     exit(Import16BitSlices);
  2034.                 ShowMessage(CmdPeriodToStop);
  2035.                 StackInfo := StackInfoPtr(NewPtr(SizeOf(StackInfoRec)));
  2036.                 if StackInfo = nil then
  2037.                     exit(Import16BitSlices);
  2038.             end; {with}
  2039.         with info^, info^.StackInfo^ do begin
  2040.                 nSlices := nImages;
  2041.                 SliceSpacing := 0.0;
  2042.                 FrameInterval := 0.0;
  2043.                 StackType := VolumeStack;
  2044.                 PicBaseH[1] := PicBaseHandle;
  2045.                 revertable := false;
  2046.                 for i := 2 to nSlices do begin
  2047.                         h := NewHandle(PixMapSize);
  2048.                         if h = nil then begin
  2049.                                 nSlices := i - 1;
  2050.                                 leave;
  2051.                             end;
  2052.                         PicBaseH[i] := h;
  2053.                         CurrentSlice := i;
  2054.                         SelectSlice(i);
  2055.                         UpdateTitleBar;
  2056.                         DataSize := ImageSize;
  2057.                         AbsoluteMin := 0;
  2058.                         AbsoluteMax := 0;
  2059.                         CurrentMin := 0;
  2060.                         CurrentMax := 0;
  2061.                         if not ImportAutoScale then begin
  2062.                                 if ((ImportMax - ImportMin) > 65536.0) or (ImportMin > ImportMax) then begin
  2063.                                         ImportMin := 0.0;
  2064.                                         ImportMax := 255;
  2065.                                     end;
  2066.                                 CurrentMin := round(ImportMin);
  2067.                                 CurrentMax := round(ImportMax);
  2068.                             end;
  2069.                         ScaleToEightBits(f);
  2070.                         InvertPic;
  2071.                         UpdatePicWindow;
  2072.                         if CommandPeriod then begin
  2073.                                 beep;
  2074.                                 nSlices := i;
  2075.                                 wait(60);
  2076.                                 leave;
  2077.                             end;
  2078.                     end; {for}
  2079.                 if (MaxBlock < MinFree) and (nSlices > 1) then begin
  2080.                         repeat
  2081.                             DisposeHandle(PicBaseH[nSlices]);
  2082.                             nSlices := nSlices - 1;
  2083.                         until (MaxBlock > MinFree) or (nSlices = 1);
  2084.                         PutError(concat('Not enough memory to open all ', long2str(nImages), ' slices in the stack.'));
  2085.                     end;
  2086.                 CurrentSlice := 1;
  2087.                 SelectSlice(CurrentSlice);
  2088.                 if ImportCalibrate and  ImportAutoScale then begin
  2089.                     RemoveDensityCalibration;
  2090.                     ImportCalibrate := false;
  2091.                 end;
  2092.                 UpdateTitleBar;
  2093.                 UpdateWindowsMenuItem;
  2094.             end;
  2095.     end;
  2096.  
  2097.  
  2098.     function Import16BitFile (fname: str255; vnum: integer): boolean;
  2099.         var
  2100.             ticks, ByteCount, i: LongInt;
  2101.             err: OSErr;
  2102.             f: integer;
  2103.             line, pixel: integer;
  2104.     begin
  2105.         Import16BitFile := false;
  2106.         if ImportCustomWidth > MaxLine then
  2107.             exit(Import16BitFile);
  2108.         if not NewPicWindow(fname, ImportCustomWidth, ImportCustomHeight) then
  2109.             exit(Import16BitFile);
  2110.         ShowWatch;
  2111.         err := fsopen(fname, vNum, f);
  2112.         with info^ do begin
  2113.                 PictureType := imported;
  2114.                 ImageDataOffset := ImportCustomOffset;
  2115.                 DataType := ImportCustomDepth;
  2116.                 vref := vnum;
  2117.                 AbsoluteMin := 0;
  2118.                 AbsoluteMax := 0;
  2119.                 CurrentMin := 0;
  2120.                 CurrentMax := 0;
  2121.                 LittleEndian := ImportSwapBytes;
  2122.                 if ImportCalibrate then begin
  2123.                     fit := StraightLine;
  2124.                     nCoefficients := 2;
  2125.                     coefficient[1] := 0.0; {ScaleToEightBits changes these coefficient}
  2126.                     coefficient[2] := 1.0;
  2127.                 end else
  2128.                     RemoveDensityCalibration;
  2129.                 if not ImportAutoScale then begin
  2130.                         if ((ImportMax - ImportMin) > 65536.0) or (ImportMin > ImportMax) then begin
  2131.                                 ImportMin := 0.0;
  2132.                                 ImportMax := 255;
  2133.                             end;
  2134.                         CurrentMin := round(ImportMin);
  2135.                         CurrentMax := round(ImportMax);
  2136.                     end;
  2137.                 DataH := GetBigHandle(PixMapSize * 2);
  2138.                 ScaleToEightBits(f);
  2139.                 if ImportCustomSlices > 1 then
  2140.                     Import16BitSlices(f);
  2141.                 err := fsclose(f);
  2142.                 InvertPic;
  2143.                 if PixMapSize > UndoBufSize then
  2144.                     PutWarning;
  2145.                 revertable := false;
  2146.             end; {with}
  2147.         Import16BitFile := true;
  2148.     end;
  2149.  
  2150.  
  2151.     procedure InitPictBuffer (howBig: LongInt);
  2152.     begin
  2153.         repeat
  2154.             PictBuffer := NewPtr(howBig);
  2155.             if PictBuffer = nil then
  2156.                 howBig := howBig div 2;
  2157.         until PictBuffer <> nil;
  2158.         DisposePtr(PictBuffer);
  2159.         PictBuffer := NewPtr(howBig div 2);
  2160.     end;
  2161.  
  2162.  
  2163.     procedure FillPictBuffer;
  2164.         var
  2165.             count: LongInt;
  2166.             err: OSErr;
  2167.     begin
  2168.         count := GetPtrSize(PictBuffer);
  2169.         if not fitsInPictBuffer then begin
  2170.                 err := FSRead(PictF, count, PictBuffer);
  2171.                 if err <> NoErr then
  2172.                     PictReadErr := true;
  2173.             end;
  2174.         bytesInPictBuffer := count;
  2175.         curPictBufPtr := PictBuffer;
  2176.     end;
  2177.  
  2178.  
  2179.     procedure GetPICTData (dataPtr: Ptr; byteCount: Integer);
  2180.     {Input picture spooler routine taken from Apple's PICTViewer example program.}
  2181.         var
  2182.             count: LongInt;
  2183.             anErr: OSErr;
  2184.     begin
  2185.         count := byteCount;
  2186.         repeat
  2187.             if bytesInPictBuffer >= count then begin
  2188.                     BlockMove(curPictBufPtr, dataPtr, count);
  2189.                     curPictBufPtr := Ptr(Ord4(curPictBufPtr) + count);
  2190.                     bytesInPictBuffer := bytesInPictBuffer - count;
  2191.                     count := 0;
  2192.                 end
  2193.             else begin        {Not enough in buffer}
  2194.                     if bytesInPictBuffer > 0 then begin
  2195.                             BlockMove(curPictBufPtr, dataPtr, bytesInPictBuffer);
  2196.                             dataPtr := Ptr(Ord4(dataPtr) + bytesInPictBuffer);
  2197.                             count := count - bytesInPictBuffer;
  2198.                         end;
  2199.                     FillPictBuffer;
  2200.                 end;
  2201.         until count = 0;
  2202.     end;
  2203.  
  2204.  
  2205.     procedure BitInfo (var srcBits: PixMap; var srcRect, dstRect: rect; mode: integer; maskRgn: rgnHandle);
  2206.         var
  2207.             i, size: integer;
  2208.     begin
  2209.         if BitInfoCount = 0 then begin
  2210.                 PictSrcRect := srcRect;
  2211.                 if srcBits.rowBytes < 0 then
  2212.                     with srcBits.pmTable^^ do begin {Make sure it is a PixMap.}
  2213.                             size := ctSize;
  2214.                             if size > 255 then
  2215.                                 size := 255;
  2216.                             if size > 0 then begin
  2217.                                     BitInfoCount := BitInfoCount + 1;
  2218.                                     if not UseExistingLUT then
  2219.                                         with info^ do begin
  2220.                                                 for i := 0 to size do
  2221.                                                     cTable[i].rgb := ctTable[i].rgb;
  2222.                                                 LutMode := ColorLut;
  2223.                                                 SetupPseudocolor;
  2224.                                             end;
  2225.                                 end;
  2226.                         end; {with}
  2227.             end;
  2228.     end;
  2229.  
  2230.  
  2231.     procedure GetLUTFromPict (thePict: PicHandle);
  2232.   {Refer to "Screen Dump FKEY for Color Picts", February 1988 MacTutor.}
  2233.         type
  2234.             myPicData = record
  2235.                     p: Picture;
  2236.                     ID: integer
  2237.                 end;
  2238.             myPicPtr = ^myPicData;
  2239.             myPicHdl = ^myPicPtr;
  2240.         var
  2241.             tempProcs: CQDProcs;
  2242.             SavePort: GrafPtr;
  2243.             err: osErr;
  2244.             TempPort: CGrafPort;
  2245.             limbo: rect;
  2246.             xxscale, yyscale: extended;
  2247.     begin
  2248.         GetPort(SavePort);
  2249.         OpenCPort(@TempPort);
  2250.         SetStdCProcs(tempProcs);
  2251.         tempProcs.bitsProc := BitInfoProc;
  2252.         tempProcs.getPicProc := GetPICTDataProc;
  2253.         PictSrcRect := thePict^^.picFrame;
  2254.         BitInfoCount := 0;
  2255.         TempPort.grafProcs := @tempProcs;
  2256.         err := SetFPos(PictF, fsFromStart, 512 + SizeOf(Picture));
  2257.         FillPictBuffer;
  2258.         limbo := thePict^^.picFrame;
  2259.         OffsetRect(limbo, 10000, 10000);
  2260.         if not PictReadErr then
  2261.             DrawPicture(thePict, limbo);
  2262.         CloseCPort(@TempPort);
  2263.         SetPort(SavePort);
  2264.         with info^, PictSrcRect do begin
  2265.                 LoadLUT(cTable);
  2266.                 xxScale := (right - left) / PixelsPerLine;
  2267.                 yyScale := (bottom - top) / nLines;
  2268.                 if (xxScale > 1.0) and ((PixelsPerLine * xxScale) <= MaxLine) and ((xxScale - yyScale) < 0.1) then begin
  2269.                         PixelsPerLine := right - left;
  2270.                         nLines := bottom - top;
  2271.                     end;
  2272.             end; {with}
  2273.     end;
  2274.  
  2275.  
  2276.     function OpenPict;{(fname:str255; vnum:integer; Reverting:boolean):boolean}
  2277.         var
  2278.             err: OSErr;
  2279.             i: integer;
  2280.             iptr, p: ptr;
  2281.             PictSize, HowBig: LongInt;
  2282.             thePict: PicHandle;
  2283.             tPort: GrafPtr;
  2284.             tempProcs: CQDProcs;
  2285.             SaveProcsPtr: QDProcsPtr;
  2286.             SaveInfo: InfoPtr;
  2287.             SaveGDevice: GDHandle;
  2288.             TiffInfo: TiffInfoRec;
  2289.  
  2290.         procedure Abort;
  2291.         begin
  2292.             if not reverting then begin
  2293.                     DisposePtr(pointer(Info));
  2294.                     Info := SaveInfo;
  2295.                     LoadLUT(info^.cTable);
  2296.                 end;
  2297.             if thePict <> nil then
  2298.                 DisposeHandle(handle(thePict));
  2299.             if PictF <> 0 then
  2300.                 err := fsclose(PictF);
  2301.             {exit(OpenPict);} {ppc-bug}
  2302.         end;
  2303.  
  2304.     begin
  2305.         if BitInfoProc=nil
  2306.             then BitInfoProc:=NewRoutineDescriptor(@BitInfo, uppQDBitsProcInfo, GetCurrentISA);
  2307.         if GetPictDataProc=nil
  2308.             then GetPictDataProc:=NewRoutineDescriptor(@GetPictData, uppQDGetPicProcInfo, GetCurrentISA);
  2309.         PictF := 0;
  2310.         thePict := nil;
  2311.         OpenPict := false;
  2312.         PictReadErr := false;
  2313.         ShowWatch;
  2314.         SaveInfo := Info;
  2315.         err := fsopen(fname, vNum, PictF);
  2316.         if CheckIO(err) <> 0 then begin
  2317.             Abort;
  2318.             exit(OpenPict)
  2319.         end;
  2320.         if not Reverting then begin
  2321.                 iptr := NewPtr(SizeOf(PicInfo));
  2322.                 if iptr = nil then begin
  2323.                         PutMemoryAlert;
  2324.                         err := fsclose(PictF);
  2325.                         exit(OpenPict)
  2326.                     end;
  2327.                 Info := pointer(iptr);
  2328.                 CloneInfo(SaveInfo^, Info^);
  2329.             end;
  2330.         with Info^ do begin
  2331.                 err := GetEof(PictF, PictSize);
  2332.                 if CheckIO(err) <> 0 then begin
  2333.                     Abort;
  2334.                     exit(OpenPict)
  2335.                 end;
  2336.                 PictSize := PictSize - 512;
  2337.                 if PictSize <= 0 then begin
  2338.                     Abort;
  2339.                     exit(OpenPict)
  2340.                 end;
  2341.                 WhatToOpen := OpenPICT2;
  2342.                 if not OpenHeader(PictF, fname, vnum, TiffInfo) then begin
  2343.                     Abort;
  2344.                     exit(OpenPict)
  2345.                 end;
  2346.                 thePict := PicHandle(NewHandle(SizeOf(Picture)));
  2347.                 if thePict = nil then begin
  2348.                     Abort;
  2349.                     exit(OpenPict);
  2350.                 end;
  2351.                 err := SetFPos(PictF, fsFromStart, 512);
  2352.                 if CheckIO(err) <> 0 then begin
  2353.                     Abort;
  2354.                     exit(OpenPict)
  2355.                 end;
  2356.                 howBig := SizeOf(Picture);
  2357.                 err := FSRead(PictF, howBig, Pointer(thePict^));
  2358.                 if CheckIO(err) <> 0 then begin
  2359.                     Abort;
  2360.                     exit(OpenPict)
  2361.                 end;
  2362.                 with thePict^^.PicFrame do begin
  2363.                         nlines := bottom - top;
  2364.                         PixelsPerLine := right - left;
  2365.                     end;
  2366.          {....}
  2367.                 err := GetEof(PictF, howBig);
  2368.                 howBig := howBig - (512 + SizeOf(Picture));
  2369.                 InitPictBuffer(HowBig * 2);
  2370.                 if GetPtrSize(PictBuffer) >= howBig then begin
  2371.                         err := FSRead(PictF, howBig, PictBuffer);
  2372.                         if CheckIO(err) <> NoErr then begin
  2373.                                 DisposeHandle(handle(thePict));
  2374.                                 DisposePtr(PictBuffer);
  2375.                                 err := fsclose(PictF);
  2376.                                 exit(OpenPict)
  2377.                             end;
  2378.                         fitsInPictBuffer := true;
  2379.                     end
  2380.                 else
  2381.                     fitsInPictBuffer := false;
  2382.                 if (LutMode = ColorLut) or (LutMode = CustomGrayscale) or (fileVersion = 0) then
  2383.                     GetLUTFromPict(thePict);
  2384.                 if not Reverting then begin
  2385.                         p := GetImageMemory(SaveInfo);
  2386.                         if p = nil then begin
  2387.                                 DisposeHandle(handle(thePict));
  2388.                                 DisposePtr(PictBuffer);
  2389.                                 err := fsclose(PictF);
  2390.                                 exit(OpenPict)
  2391.                             end;
  2392.                         PicBaseAddr := p;
  2393.                         MakeNewWindow(fname);
  2394.                     end;
  2395.                 if (PixMapSize > UndoBufSize) and (not Reverting) then begin
  2396.                         PutWarning;
  2397.                         ShowWatch;
  2398.                     end;
  2399.                 if isGrayScaleLUT then
  2400.                     ResetGrayMap;
  2401.                 SaveGDevice := GetGDevice;
  2402.                 SetGDevice(osGDevice);
  2403.                 GetPort(tPort);
  2404.                 SetPort(GrafPtr(osPort));
  2405.                 pmForeColor(BlackIndex);
  2406.                 pmBackColor(WhiteIndex);
  2407.                 RGBForeColor(BlackRGB);
  2408.                 RGBBackColor(WhiteRGB);
  2409.                 EraseRect(PicRect);
  2410.                 SaveProcsPtr := pointer(osPort^.grafProcs);
  2411.                 SetStdCProcs(tempProcs);
  2412.                 tempProcs.getPicProc := GetPICTDataProc;
  2413.                 osPort^.grafProcs := @TempProcs;
  2414.                 err := SetFPos(PictF, fsFromStart, 512 + SizeOf(Picture));
  2415.                 FillPictBuffer;
  2416.                 if not PictReadErr then
  2417.                     DrawPicture(thePict, PicRect);
  2418.                 osPort^.grafProcs := pointer(SaveProcsPtr);
  2419.                 DisposeHandle(handle(thePict));
  2420.                 DisposePtr(PictBuffer);
  2421.                 pmForeColor(ForegroundIndex);
  2422.                 pmBackColor(BackgroundIndex);
  2423.                 SetPort(tPort);
  2424.                 SetGDevice(SaveGDevice);
  2425.                 vref := vnum;
  2426.                 PictureType := PictFile;
  2427.                 revertable := true;
  2428.             end; {with}
  2429.         err := fsclose(PictF);
  2430.         SetupUndo;
  2431.         if not PictReadErr then
  2432.             OpenPict := true;
  2433.     end;
  2434.  
  2435.  
  2436.     procedure GetCLUT (thePict: PicHandle);
  2437.         type
  2438.             myPicData = record
  2439.                     p: Picture;
  2440.                     ID: integer
  2441.                 end;
  2442.             myPicPtr = ^myPicData;
  2443.             myPicHdl = ^myPicPtr;
  2444.         var
  2445.             tempProcs: CQDProcs;
  2446.             SaveProcsPtr: QDProcsPtr;
  2447.             err: osErr;
  2448.     begin
  2449.         with info^ do begin
  2450.                 SetPort(GrafPtr(osPort));
  2451.                 SaveProcsPtr := pointer(wptr^.grafProcs);
  2452.                 SetStdCProcs(tempProcs);
  2453.                 tempProcs.bitsProc := BitInfoProc;
  2454.                 BitInfoCount := 0;
  2455.                 osPort^.grafProcs := @tempProcs;
  2456.                 DrawPicture(thePict, thePict^^.picFrame);
  2457.                 osPort^.grafProcs := pointer(SaveProcsPtr);
  2458.                 LoadLUT(cTable);
  2459.             end;
  2460.     end;
  2461.  
  2462.  
  2463.     function OpenPICS (name: str255; fRefNum: integer): boolean;
  2464.         var
  2465.             RefNum, picID, hOffset, vOffset, nPICS, i: integer;
  2466.             err: OSErr;
  2467.             PicH: PicHandle;
  2468.             h: handle;
  2469.             MemError, Aborted: boolean;
  2470.             FrameRect: rect;
  2471.             SaveGDevice: GDHandle;
  2472.     begin
  2473.         if BitInfoProc=nil
  2474.             then BitInfoProc:=NewRoutineDescriptor(@BitInfo, uppQDBitsProcInfo, GetCurrentISA);
  2475.         OpenPics := false;
  2476.         if MaxBlock < MinFree then begin
  2477.                 PutError('Insufficient memory to open PICS file.');
  2478.                 exit(OpenPICS);
  2479.             end;
  2480.         ShowWatch;
  2481.         err := SetVol(nil, fRefNum);
  2482.         RefNum := OpenResFile(name);
  2483.         if RefNum = -1 then begin
  2484.                 PutError('Unable to open PICS file.');
  2485.                 exit(OpenPICS);
  2486.             end;
  2487.         nPICS := Count1Resources('PICT');
  2488.         if nPICS < 1 then begin
  2489.                 PutError('No PICTs found.');
  2490.                 CloseResFile(RefNum);
  2491.                 exit(OpenPICS);
  2492.             end;
  2493.         PicH := GetPicture(128);
  2494.         if PicH = nil then begin
  2495.             CloseResFile(RefNum);
  2496.             exit(OpenPICS);
  2497.         end;
  2498.         FrameRect := PicH^^.PicFrame;
  2499.         with FrameRect do begin
  2500.                 hOffset := left;
  2501.                 vOffset := top;
  2502.                 right := right - hOffset;
  2503.                 bottom := bottom - vOffset;
  2504.                 left := 0;
  2505.                 top := 0;
  2506.             end;
  2507.         with FrameRect do
  2508.             if not NewPicWindow(name, right - left, bottom - top) then begin
  2509.                 CloseResFile(RefNum);
  2510.                 exit(OpenPICS);
  2511.             end;
  2512.         with info^ do begin
  2513.                 revertable := false;
  2514.                 StackInfo := StackInfoPtr(NewPtr(SizeOf(StackInfoRec)));
  2515.                 if StackInfo = nil then begin
  2516.                     CloseResFile(RefNum);
  2517.                     exit(OpenPICS);
  2518.                 end;
  2519.                 with StackInfo^ do begin
  2520.                         SliceSpacing := 0.0;
  2521.                         FrameInterval := 0.0;
  2522.                         StackType := VolumeStack;
  2523.                         nSlices := 1;
  2524.                         CurrentSlice := 1;
  2525.                         PicBaseH[1] := PicBaseHandle;
  2526.                     end;
  2527.             end;
  2528.         if not UseExistingLUT then
  2529.             GetCLUT(picH);
  2530.         with info^, Info^.StackInfo^ do begin
  2531.                 SaveGDevice := GetGDevice;
  2532.                 SetGDevice(osGDevice);
  2533.                 SetPort(GrafPtr(osPort));
  2534.                 pmBackColor(WhiteIndex);
  2535.                 EraseRect(PicRect);
  2536.                 DrawPicture(picH, PicRect);
  2537.                 DisposeHandle(handle(picH));
  2538.                 SetGDevice(SaveGDevice);
  2539.                 UpdatePicWindow;
  2540.                 picID := 129;
  2541.                 MemError := false;
  2542.                 for i := 2 to nPICS do begin
  2543.                         PicH := GetPicture(picID);
  2544.                         if (PicH = nil) or (ResError <> NoErr) then
  2545.                             Leave;
  2546.                         h := GetBigHandle(PixMapSize);
  2547.                         if h = nil then begin
  2548.                                 if PicH <> nil then
  2549.                                     DisposeHandle(handle(picH));
  2550.                                 MemError := true;
  2551.                                 Leave;
  2552.                             end;
  2553.                         nSlices := nSlices + 1;
  2554.                         CurrentSlice := CurrentSlice + 1;
  2555.                         PicBaseH[CurrentSlice] := h;
  2556.                         SelectSlice(CurrentSlice);
  2557.                         FrameRect := PicH^^.PicFrame;
  2558.                         with FrameRect do begin
  2559.                                 right := right - hOffset;
  2560.                                 bottom := bottom - vOffset;
  2561.                                 left := left - hOffset;
  2562.                                 top := top - vOffset;
  2563.                             end;
  2564.                         SetGDevice(osGDevice);
  2565.                         EraseRect(PicRect);
  2566.                         if not EqualRect(FrameRect, PicRect) then
  2567.                             BlockMove(PicBaseH[CurrentSlice - 1]^, PicBaseH[CurrentSlice]^, PixMapSize);
  2568.                         DrawPicture(picH, FrameRect);
  2569.                         DisposeHandle(handle(picH));
  2570.                         SetGDevice(SaveGDevice);
  2571.                         UpdatePicWindow;
  2572.                         UpdateTitleBar;
  2573.                         Aborted := CommandPeriod;
  2574.                         if Aborted then begin
  2575.                                 beep;
  2576.                                 wait(60);
  2577.                                 Leave;
  2578.                             end;
  2579.                         picID := picID + 1;
  2580.                     end;
  2581.                 CloseResFile(RefNum);
  2582.                 if MemError then
  2583.                     PutError('Not enough memory to open all images in PICS file.');
  2584.                 CurrentSlice := 1;
  2585.                 SelectSlice(CurrentSlice);
  2586.                 PictureType := PicsFile;
  2587.                 Revertable := false;
  2588.                 UpdateTitleBar;
  2589.                 UpdateWindowsMenuItem;
  2590.                 if not MemError and not Aborted then
  2591.                     OpenPICS := true;
  2592.             end; {with}
  2593.     end;
  2594.  
  2595.  
  2596. {$D-}
  2597.  
  2598.     procedure OpenAll (RefNum: integer);
  2599.       {Opens all appropriate files in a folder.    Original version contributed by Ira Rampil.}
  2600.         var
  2601.             OpenedOK: boolean;
  2602.             index,vRefNum: integer;
  2603.             name: Str255;
  2604.             ftype: OSType;
  2605.             err: OSErr;
  2606.             PB: CInfoPBRec;
  2607.             dirID,ProcID:LongInt;
  2608.     begin
  2609.         vRefNum:=0;
  2610.         err:=GetWDInfo(RefNum,vRefNum,dirID,ProcID);
  2611.         if err<>noErr then
  2612.             exit(OpenAll);
  2613.         index := 0;
  2614.         while true do begin
  2615.                 index := index + 1;
  2616.                 with PB do begin
  2617.                         ioCompletion := nil;
  2618.                         ioNamePtr := @name;
  2619.                         ioVRefNum := RefNum;
  2620.                         ioDirID:=DirID;
  2621.                         ioFDirIndex := index;
  2622.                         err := PBGetCatInfoSync(@PB); {ppc-bug}
  2623.                         if err = fnfErr then
  2624.                             exit(OpenAll);
  2625.                         ftype := ioFlFndrInfo.fdType;
  2626.                     end;
  2627.                 if ftype = 'IPIC' then begin
  2628.                         WhatToOpen := OpenImage;
  2629.                         if not OpenFile(name, RefNum) then
  2630.                             exit(OpenAll);
  2631.                     end
  2632.                 else if ftype = 'PICT' then begin
  2633.                         if not OpenPICT(name, RefNum, false) then
  2634.                             exit(OpenAll)
  2635.                     end
  2636.                 else if ftype = 'TIFF' then begin
  2637.                         WhatToOpen := OpenTiff;
  2638.                         if not OpenFile(name, RefNum) then
  2639.                             exit(OpenAll);
  2640.                     end
  2641.                 else if ftype = 'PNTG' then
  2642.                     if not OpenMacPaint(name, RefNum) then
  2643.                         exit(OpenAll);
  2644.                 if CommandPeriod or (nPics>=MaxPics) then begin
  2645.                         beep;
  2646.                         exit(OpenAll);
  2647.                     end;
  2648.             end; {while}
  2649.     end;
  2650.  
  2651.  
  2652.     function OpenDialogHook (item: integer; theDialog: DialogPtr): integer;
  2653.         const
  2654.             OpenAllID = 11;
  2655.             KeepLutID = 12;
  2656.         var
  2657.             i: integer;
  2658.     begin
  2659.         if (item = -1) and UseExistingLUT then
  2660.             SetDlogItem(theDialog, KeepLutID, 1);
  2661.         if item = OpenAllID then begin
  2662.                 OpenAllFiles := not OpenAllFiles;
  2663.                 SetDlogItem(theDialog, OpenAllID, ord(OpenAllFiles));
  2664.             end;
  2665.         if item = KeepLutID then begin
  2666.                 UseExistingLUT := not UseExistingLUT;
  2667.                 SetDlogItem(theDialog, KeepLutID, ord(UseExistingLut));
  2668.             end;
  2669.         OpenDialogHook := item;
  2670.     end;
  2671.  
  2672.  
  2673.     function isTiffFile (fname: str255; RefNum: integer): boolean;
  2674.   {Returns true if the first 16-bit word of the file contains 'MM' or 'II' and the second contains 42.}
  2675.         var
  2676.             f: integer;
  2677.             ByteCount: LongInt;
  2678.             hdr: array[1..512] of integer;
  2679.             err: OSErr;
  2680.     begin
  2681.         err := fsopen(fname, RefNum, f);
  2682.         err := SetFPos(f, fsFromStart, 0);
  2683.         ByteCount := 4;
  2684.         err := fsread(f, ByteCount, @hdr);
  2685.         isTiffFile := ((hdr[1] = $4949) and (hdr[2] = $2A00) or (hdr[1] = $4D4D) and (hdr[2] = $002A));
  2686.         err := fsclose(f);
  2687.     end;
  2688.  
  2689.  
  2690.     function DoOpen (FileName: str255; RefNum: integer): boolean;
  2691.         const
  2692.             MyDialogID = 70;
  2693.         var
  2694.             where: Point;
  2695.             reply: SFReply;
  2696.             b: boolean;
  2697.             TypeList: array[0..10] of OSType;
  2698.             FileType: OSType;
  2699.             OKToContinue: boolean;
  2700.             FinderInfo: FInfo;
  2701.             err: OSErr;
  2702.     begin
  2703.         if OpenDHookProc=nil
  2704.             then OpenDHookProc:=NewRoutineDescriptor(@OpenDialogHook, uppDlgHookProcInfo, GetCurrentISA);
  2705.         KillOperation;
  2706.         DisableDensitySlice;
  2707.         OpenAllFiles := false;
  2708.         UseExistingLUT := false;
  2709.         OKToContinue := false;
  2710.         if FileName = '' then begin
  2711.                 where.v := 50;
  2712.                 where.h := 50;
  2713.                 typeList[0] := 'IPIC';
  2714.                 typeList[1] := 'PICT';
  2715.                 typeList[2] := 'TIFF';
  2716.                 typeList[3] := 'ICOL';   {Color Tables}
  2717.                 typeList[4] := 'PX05'; {PixelPaint LUT}
  2718.                 typeList[5] := 'CLUT';  {Klutz LUT}
  2719.                 typeList[6] := 'drwC';  {Canvas LUT}
  2720.                 typeList[7] := 'PNTG';  {MacPaint}
  2721.                 typeList[8] := 'PICS';
  2722.                 typeList[9] := 'Iout';    {Outlines}
  2723.                 typeList[10] := 'TEXT';
  2724.                 SFPGetFile(Where, '', nil, 11, @TypeList, OpenDHookProc, reply, MyDialogID, nil);
  2725.                 if reply.good then
  2726.                     with reply do begin
  2727.                             FileName := fname;
  2728.                             FileType := ftype;
  2729.                             RefNum := vRefNum;
  2730.                             DefaultRefNum := RefNum;
  2731.                             DefaultFileName := fname;
  2732.                             OKToContinue := true;
  2733.                         end;
  2734.                 if reply.good and OpenAllFiles then begin
  2735.                         OpenAll(RefNum);
  2736.                         exit(DoOpen);
  2737.                     end;
  2738.             end
  2739.         else begin
  2740.                 err := GetFInfo(FileName, RefNum, FinderInfo);
  2741.                 FileType := FinderInfo.fdType;
  2742.                 OKToContinue := true;
  2743.             end;
  2744.         DoOpen := OKToContinue;
  2745.         if OKToContinue then begin
  2746.                 if FileType = 'IPIC' then begin
  2747.                         WhatToOpen := OpenImage;
  2748.                         b := OpenFile(FileName, RefNum)
  2749.                     end
  2750.                 else if FileType = 'PICT' then begin
  2751.                         b := OpenPICT(FileName, RefNum, false)
  2752.                     end
  2753.                 else if FileType = 'TIFF' then begin
  2754.                         WhatToOpen := OpenTIFF;
  2755.                         b := OpenFile(FileName, RefNum)
  2756.                     end
  2757.                 else if FileType = 'ICOL' then
  2758.                     OpenColorTable(FileName, RefNum)
  2759.                 else if FileType = 'PX05' then
  2760.                     ImportPalette('PX05', FileName, RefNum)
  2761.                 else if FileType = 'CLUT' then
  2762.                     ImportPalette('CLUT', FileName, RefNum)
  2763.                 else if FileType = 'drwC' then
  2764.                     ImportPalette('PX05', FileName, RefNum)
  2765.                 else if FileType = 'PNTG' then
  2766.                     b := OpenMacPaint(FileName, RefNum)etID = 17;
  2767.             EightBitsID = 18;
  2768.             SixteenBitsUnsignedID = 19;
  2769.             SixteenBitsSignedID = 20;
  2770.             SwapBytesID = 21;
  2771.             ImportAllID = 22;
  2772.             EditID = 23;
  2773.             CalibrateID = 24;
  2774.             InvertID = 25;
  2775.  
  2776.         var
  2777.             i: integer;
  2778.  
  2779.         procedure SetRadioButtons1;
  2780.             var
  2781.                 i: integer;
  2782.         begin
  2783.             SetDlogItem(mylog, TiffID, 0);
  2784.             SetDlogItem(mylog, DicomID, 0);    
  2785.             SetDlogItem(mylog, LutID, 0);
  2786.             SetDlogItem(mylog, TextID, 0);
  2787.             SetDlogItem(mylog, CustomID, 0);
  2788.             case WhatToImport of
  2789.                 ImportTiff: 
  2790.                     SetDlogItem(mylog, TiffID, 1);
  2791.                 ImportDicom: 
  2792.                     SetDlogItem(mylog, DicomID, 1);
  2793.                 ImportLUT: 
  2794.                     SetDlogItem(mylog, LutID, 1);
  2795.                 ImportText: 
  2796.                     SetDlogItem(mylog, TextID, 1);
  2797.                 ImportCustom: 
  2798.                     SetDlogItem(mylog, CustomID, 1);
  2799.             end;
  2800.         end;
  2801.  
  2802.         procedure SetRadioButtons2;
  2803.             var
  2804.                 i: integer;
  2805.         begin
  2806.             SetDlogItem(mylog, EightBitsID, 0);
  2807.             SetDlogItem(mylog, SixteenBitsUnsignedID, 0);
  2808.             SetDlogItem(mylog, SixteenBitsSignedID, 0);
  2809.             case ImportCustomDepth of
  2810.                 EightBits: 
  2811.                     SetDlogItem(mylog, EightBitsID, 1);
  2812.                 SixteenBitsUnsigned: 
  2813.                     SetDlogItem(mylog, SixteenBitsUnsignedID, 1);
  2814.                 SixteenBitsSigned: 
  2815.                     SetDlogItem(mylog, SixteenBitsSignedID, 1);
  2816.             end;
  2817.         end;
  2818.  
  2819.         procedure ShowParameters;
  2820.             var
  2821.                 str1, str2, str3: str255;
  2822.         begin
  2823.             NumToString(ImportCustomWidth, str1);
  2824.             NumToString(ImportCustomHeight, str2);
  2825.             NumToString(ImportCustomOffset, str3);
  2826.             ParamText(str1, str2, str3, '');
  2827.         end;
  2828.  
  2829.     begin
  2830.         if item = -1 then begin {Initialize}
  2831.                 SetRadioButtons1;
  2832.                 SetRadioButtons2;
  2833.                 ShowParameters;
  2834.                 SetDlogItem(mylog, SwapBytesID, ord(ImportSwapBytes));
  2835.                 SetDlogItem(mylog, ImportAllID, ord(ImportAll));
  2836.                 SetDlogItem(mylog, InvertID, ord(ImportInvert));
  2837.                 SetDlogItem(mylog, CalibrateID, ord(ImportCalibrate));
  2838.             end;
  2839.         if (item >= TiffID) and (item <= CustomID) then begin
  2840.                 case item of
  2841.                     TiffID: 
  2842.                         WhatToImport := ImportTiff;
  2843.                     DicomID: 
  2844.                         WhatToImport := ImportDicom;    
  2845.                     LutID: 
  2846.                         WhatToImport := ImportLUT;
  2847.                     TextID: 
  2848.                         WhatToImport := ImportText;
  2849.                     CustomID: 
  2850.                         WhatToImport := ImportCustom;
  2851.                 end;
  2852.                 SetRadioButtons1;
  2853.             end;
  2854.         if item = EditID then begin
  2855.                 EditImportParameters;
  2856.                 WhatToImport := ImportCustom;
  2857.                 SetRadioButtons1;
  2858.                 ShowParameters;
  2859.                 SetDlogItem(mylog, CalibrateID, ord(ImportCalibrate));
  2860.             end;
  2861.         if (item >= EightBitsID) and (item <= SixteenBitsSignedID) then begin
  2862.                 case item of
  2863.                     EightBitsID: 
  2864.                         ImportCustomDepth := EightBits;
  2865.                     SixteenBitsUnsignedID: 
  2866.                         ImportCustomDepth := SixteenBitsUnsigned;
  2867.                     SixteenBitsSignedID: 
  2868.                         ImportCustomDepth := SixteenBitsSigned;
  2869.                 end;
  2870.                 SetRadioButtons2;
  2871.                 WhatToImport := ImportCustom;
  2872.                 SetRadioButtons1;
  2873.             end;
  2874.         if item = SwapBytesID then begin
  2875.                 ImportSwapBytes := not ImportSwapBytes;
  2876.                 SetDlogItem(mylog, SwapBytesID, ord(ImportSwapBytes));
  2877.                 WhatToImport := ImportCustom;
  2878.                 SetRadioButtons1;
  2879.             end;
  2880.         if item = ImportAllID then begin
  2881.                 ImportAll := not ImportAll;
  2882.                 SetDlogItem(mylog, ImportAllID, ord(ImportAll));
  2883.             end;
  2884.         if item = InvertID then begin
  2885.                 ImportInvert := not ImportInvert;
  2886.                 SetDlogItem(mylog, InvertID, ord(ImportInvert));
  2887.             end;
  2888.         if item = CalibrateID then begin
  2889.                 ImportCalibrate := not ImportCalibrate;
  2890.                 SetDlogItem(mylog, CalibrateID, ord(ImportCalibrate));
  2891.                 WhatToImport := ImportCustom;
  2892.                 SetRadioButtons1;
  2893.             end;
  2894.         ImportDialogHook := item;
  2895.     end;
  2896.  
  2897.  
  2898.     function ImportFile (FileName: str255; RefNum: integer): boolean;
  2899.         const
  2900.             ImportDialogID = 90;
  2901.         var
  2902.             where: Point;
  2903.             typeList: SFTypeList;
  2904.             reply: SFReply;
  2905.             b, ImportingTIFF, HasColorMap: boolean;
  2906.     begin
  2907.         if ImportDHookProc=nil
  2908.             then ImportDHookProc:=NewRoutineDescriptor(@ImportDialogHook, uppDlgHookProcInfo, GetCurrentISA);
  2909.         ImportFile := true;
  2910.         DisableDensitySlice;
  2911.         if not macro then begin
  2912.             ImportAll := false;
  2913.             if WhatToImport=ImportMCID then
  2914.                 WhatToImport:=ImportTIFF;
  2915.         end;
  2916.         if FileName = '' then begin
  2917.                 where.v := 50;
  2918.                 where.h := 50;
  2919.                 SFPGetFile(Where, '', nil, -1, @typeList, ImportDHookProc, reply, ImportDialogID, nil); 
  2920.                 if not reply.good then begin
  2921.                         ImportFile := false;
  2922.                         exit(ImportFile);
  2923.                     end;
  2924.                 with reply do begin
  2925.                         FileName := fname;
  2926.                         RefNum := vRefNum;
  2927.                         DefaultRefNum := RefNum;
  2928.                         DefaultFileName := fname;
  2929.                     end;
  2930.             end;
  2931.         if isTiffFile(FileName, RefNum) and not macro and not OptionKeyWasDown then
  2932.             WhatToImport := ImportTiff;
  2933.         ImportingTIFF := WhatToImport = ImportTiff;
  2934.         if ImportingTIFF then
  2935.             if not GetTIFFParameters(FileName, RefNum, HasColorMap) then
  2936.                 exit(ImportFile);
  2937.         case WhatToImport of
  2938.             ImportMCID: 
  2939.                 WhatToOpen := OpenImported;
  2940.             ImportCustom:  begin
  2941.                     if (ImportCustomDepth <> EightBits) and (ImportCustomWidth > MaxLine) then begin
  2942.                             PutError(concat('Maximum width of imported 16-bit images is ', long2str(MaxLine), '.'));
  2943.                             exit(ImportFile);
  2944.                         end;
  2945.                     WhatToOpen := OpenCustom;
  2946.                 end;
  2947.             ImportDicom: 
  2948.                begin    
  2949.                     ImportDicomImages(FileName, RefNum, ImportAll, Import16BitFile);
  2950.                     exit(ImportFile);
  2951.                end
  2952.             ImportLUT:  begin
  2953.                     DoImportLut(FileName, RefNum);
  2954.                     exit(ImportFile);
  2955.                 end;
  2956.             ImportText:  begin
  2957.                     ImportFile := ImportTextFile(FileName, RefNum);
  2958.                     exit(ImportFile);
  2959.                 end;
  2960.             otherwise;
  2961.         end;
  2962.         if ImportAll then
  2963.             ImportAllFiles(RefNum)
  2964.         else if (WhatToOpen = OpenCustom) and (ImportCustomDepth <> EightBits) then
  2965.             b := Import16BitFile(FileName, RefNum)
  2966.         else
  2967.             b := OpenFile(FileName, RefNum);
  2968.         if macro then
  2969.             GenerateValues;
  2970.         if ImportingTIFF then
  2971.             WhatToImport := ImportTiff; {GetTIFFParameters may have changed it to ImportCustom.}
  2972.     end;
  2973.  
  2974.  
  2975.     procedure RevertToSaved;
  2976.         var
  2977.             fname: str255;
  2978.             err, f: integer;
  2979.             ok: boolean;
  2980.             size: LongInt;
  2981.     begin
  2982.         if OpPending then
  2983.             KillRoi;
  2984.         DisableDensitySlice;
  2985.         with Info^ do begin
  2986.                 fname := title;
  2987.                 SetPort(wptr);
  2988.                 if PictureType = PICTFile then begin
  2989.                         ok := OpenPICT(fname, vref, true);
  2990.                         UpdatePicWindow;
  2991.                     end
  2992.                 else begin
  2993.                         ShowWatch;
  2994.                         err := fsopen(fname, vref, f);
  2995.                         ok := true;
  2996.                         if HeaderOffset <> -1 then
  2997.                             ok := OpenImageHeader(f, fname, vref);
  2998.                         if ok then begin
  2999.                                 err := SetFPos(f, fsFromStart, ImageDataOffset);
  3000.                                 size := ImageSize;
  3001.                                 CheckFileSize(f, size, ImageDataOffset);
  3002.                                 if size > 0 then
  3003.                                     err := fsread(f, size, PicBaseAddr);
  3004.                                 if odd(PixelsPerLine) then
  3005.                                     UnpackLines;
  3006.                                 if Info^.InvertedImage then
  3007.                                     InvertPic;
  3008.                                 UpdatePicWindow;
  3009.                             end;
  3010.                         err := fsclose(f);
  3011.                         RoiShowing := false;
  3012.                     end;
  3013.                 OpPending := false;
  3014.                 Changes := false;
  3015.                 UpdateTitleBar;
  3016.             end; {with}
  3017.     end;
  3018.  
  3019.  
  3020.     procedure FindWhatToPrint;
  3021.         var
  3022.             kind: integer;
  3023.             WhichWindow: WindowPtr;
  3024.     begin
  3025.         WhatToPrint := NothingToPrint;
  3026.         WhichWindow := FrontWindow;
  3027.         if WhichWindow = nil then
  3028.             exit(FindWhatToPrint);
  3029.         kind := WindowPeek(WhichWindow)^.WindowKind;
  3030.         if (kind = PicKind) and info^.RoiShowing and measuring then
  3031.             kind := InfoKind;
  3032.         case kind of
  3033.             PicKind: 
  3034.                 if info^.RoiShowing then
  3035.                     WhatToPrint := PrintSelection
  3036.                 else
  3037.                     WhatToPRint := PrintImage;
  3038.             HistoKind: 
  3039.                 WhatToPrint := PrintHistogram;
  3040.             ProfilePlotKind, CalibrationPlotKind: 
  3041.                 WhatToPrint := PrintPlot;
  3042.             InfoKind, ResultsKind: 
  3043.                 if mCount > 0 then
  3044.                     WhatToPrint := PrintMeasurements;
  3045.             TextKind: 
  3046.                 WhatToPrint := PrintText;
  3047.             otherwise
  3048.                 ;
  3049.         end;
  3050.         if (WhatToPrint = NothingToPRint) and (info <> NoInfo) then
  3051.             WhatToPrint := PrintImage;
  3052.     end;
  3053.  
  3054.  
  3055.     procedure UpdateFileMenu;
  3056.         var
  3057.             ShowItems, isSelection, notStack: boolean;
  3058.             i: integer;
  3059.             str, str2: str255;
  3060.     begin
  3061.         with info^ do begin
  3062.                 ShowItems := Info <> NoInfo;
  3063.                 isSelection := RoiShowing and (RoiType = RectRoi);
  3064.                 notStack := StackInfo = nil;
  3065.                 if OptionKeyWasDown and (CurrentKind <> TextKind) then begin
  3066.                         SetMenuItemText(FileMenuH, CloseItem, 'Close All…');
  3067.                         SetMenuItemText(FileMenuH, SaveItem, 'Save All');
  3068.                         SetMenuItem(FileMenuH, CloseItem, ShowItems);
  3069.                     end
  3070.                 else begin
  3071.                         SetMenuItemText(FileMenuH, CloseItem, 'Close…');
  3072.                         if isSelection and notStack and (CurrentKind <> TextKind) and (PictureType <> TiffFile) and (PictureType <> PictFile) and (CurrentKind = PicKind) then
  3073.                             SetMenuItemText(FileMenuH, SaveItem, 'Save Selection')
  3074.                         else
  3075.                             SetMenuItemText(FileMenuH, SaveItem, 'Save');
  3076.                         SetMenuItem(FileMenuH, CloseItem, ShowItems or (CurrentKind = TextKind) or (CurrentKind = ResultsKind) or (CurrentKind = ProfilePlotKind) or (CurrentKind = CalibrationPlotKind) or (CurrentKind = HistoKind));
  3077.                     end;
  3078.                 case CurrentKind of
  3079.                     ProfilePlotKind, CalibrationPlotKind: 
  3080.                         ExportAsWhat := asPlotValues;
  3081.                     HistoKind: 
  3082.                         ExportAsWhat := asHistogramValues;
  3083.                     ResultsKind: 
  3084.                         ExportAsWhat := asMeasurements;
  3085.                     PicKind:  begin
  3086.                             if (SaveAsWhat <> asPICT) then
  3087.                                 SaveAsWhat := asTiff;
  3088.                             if (ExportAsWhat > asText) then
  3089.                                 ExportAsWhat := asRaw;
  3090.                         end;
  3091.                     otherwise
  3092.                 end;
  3093.                 if isSelection and notStack and (SaveAsWhat <> AsPalette) and (CurrentKind <> ResultsKind) and (CurrentKind <> TextKind) then
  3094.                     SetMenuItemText(FileMenuH, SaveAsItem, 'Save Selection As…')
  3095.                 else
  3096.                     SetMenuItemText(FileMenuH, SaveAsItem, 'Save As…');
  3097.                 if isSelection and notStack and (ExportAsWhat <= AsText) then
  3098.                     SetMenuItemText(FileMenuH, ExportItem, 'Export Selection As…')
  3099.                 else
  3100.                     SetMenuItemText(FileMenuH, ExportItem, 'Export…');
  3101.                 for i := SaveItem to SaveAsItem do
  3102.                     SetMenuItem(FileMenuH, i, ShowItems or (CurrentKind = TextKind));
  3103.                 SetMenuItem(FileMenuH, ExportItem, (ShowItems or (CurrentKind = ResultsKind)) and (CurrentKind <> TextKind));
  3104.                 if isSelection then
  3105.                     str := 'Duplicate Selection'
  3106.                 else
  3107.                     str := 'Duplicate';
  3108.                 SetMenuItemText(FileMenuH, DuplicateItem, str);
  3109.                 for i := DuplicateItem to GetInfoItem do
  3110.                     SetMenuItem(FileMenuH, i, ShowItems and (CurrentKind <> TextKind));
  3111.                 if DataType <> EightBits then
  3112.                     str := 'Rescale'
  3113.                 else
  3114.                     str := 'Revert to Saved';
  3115.                 SetMenuItemText(FileMenuH, RevertItem, str);
  3116.                 SetMenuItem(FileMenuH, RevertItem, (Revertable or (DataType <> EightBits)) and (CurrentKind <> TextKind));
  3117.                 SetMenuItem(FileMenuH, PlugInExportItem, ShowItems);
  3118.                 FindWhatToPrint;
  3119.                 case WhatToPrint of
  3120.                     NothingToPrint: 
  3121.                         str := '';
  3122.                     PrintImage: 
  3123.                         str := 'Image';
  3124.                     PrintSelection: 
  3125.                         str := 'Selection';
  3126.                     PrintPlot: 
  3127.                         str := 'Plot';
  3128.                     PrintHistogram: 
  3129.                         str := 'Histogram';
  3130.                     PrintMeasurements: 
  3131.                         str := 'Results';
  3132.                     PrintText: 
  3133.                         str := 'Text';
  3134.                 end;
  3135.                 SetMenuItemText(FileMenuH, PrintItem, concat('Print ', str, '…'));
  3136.                 SetMenuItem(FileMenuH, PrintItem, WhatToPrint <> NothingToPrint);
  3137.             end; {with info^}
  3138.     end;
  3139.  
  3140.  
  3141.     procedure SaveAll;
  3142.         var
  3143.             SaveInfo: InfoPtr;
  3144.             i: integer;
  3145.     begin
  3146.         SaveInfo := Info;
  3147.         SaveAsWhat := AsTiff;
  3148.         SaveAllState := SaveAllStage1;
  3149.         for i := 1 to nPics do begin
  3150.                 Info := pointer(WindowPeek(PicWindow[i])^.RefCon);
  3151.                 SaveAs('', 0);
  3152.                 if CommandPeriod or (SaveAllState = NoSaveAll) then
  3153.                     leave;
  3154.             end;
  3155.         Info := SaveInfo;
  3156.         SaveAllState := NoSaveAll;
  3157.     end;
  3158.  
  3159.  
  3160.     function SuggestedExportName: str255;
  3161.         var
  3162.             name: str255;
  3163.     begin
  3164.         name := info^.title;
  3165.         case ExportAsWhat of
  3166.             asRaw, asMCID, asText:  begin
  3167.                     if name = 'Camera' then
  3168.                         name := 'Untitled';
  3169.                     if ExportAsWhat = AsText then
  3170.                         SuggestedExportName := concat(name, ' (Text)')
  3171.                     else
  3172.                         SuggestedExportName := name;
  3173.                 end;
  3174.             AsLUT: 
  3175.                 SuggestedExportName := 'Palette';
  3176.             asMeasurements: 
  3177.                 SuggestedExportName := concat(name, ' (Measurements)');
  3178.             AsPlotValues: 
  3179.                 SuggestedExportName := concat(name, ' (Plot Values)');
  3180.             asHistogramValues: 
  3181.                 SuggestedExportName := concat(name, ' (Histogram)');
  3182.             asCoordinates: 
  3183.                 SuggestedExportName := concat(name, ' (Coordinates)');
  3184.         end;
  3185.     end;
  3186.  
  3187.  
  3188.     function ExportHook (item: integer; theDialog: DialogPtr): integer;
  3189.         const
  3190.             EditTextID = 7;
  3191.             RawID = 9;
  3192.             xyCoordinatesID = 16;
  3193.         var
  3194.             i: integer;
  3195.             fname: str255;
  3196.             NameEdited: boolean;
  3197.     begin
  3198.         if item = -1 then {Initialize}
  3199.             SetDlogItem(theDialog, RawID + ord(ExportAsWhat), 1);
  3200.         fname := GetDString(theDialog, EditTextID);
  3201.         NameEdited := fname <> SuggestedExportName;
  3202.         if (item >= RawID) and (item <= xyCoordinatesID) then begin
  3203.                 ExportAsWhat := ExportAsWhatType(item - RawID);
  3204.                 if not NameEdited then begin
  3205.                         SetDString(theDialog, EditTextID, SuggestedExportName);
  3206.                         SelectdialogItemText(theDialog, EditTextID, 0, 32767);
  3207.                     end;
  3208.                 for i := RawID to xyCoordinatesID do
  3209.                     SetDlogItem(theDialog, i, 0);
  3210.                 SetDlogItem(theDialog, item, 1);
  3211.             end;
  3212.         ExportHook := item;
  3213.     end;
  3214.  
  3215.  
  3216.     procedure Export (name: str255; RefNum: integer);
  3217.         const
  3218.             CustomDialogID = 100;
  3219.         var
  3220.             where: Point;
  3221.             reply: SFReply;
  3222.             isSelection: boolean;
  3223.             kind: integer;
  3224.             SaveAsState: SaveAsWhatType;
  3225.     begin
  3226.         if ExportDHookProc=nil
  3227.             then ExportDHookProc:=NewRoutineDescriptor(@ExportHook, uppDlgHookProcInfo, GetCurrentISA);
  3228.         with info^ do begin
  3229.                 if (name = '') or ((RefNum = 0) and (pos(':', name) = 0)) then begin
  3230.                         where.v := 50;
  3231.                         where.h := 50;
  3232.                         if name = '' then
  3233.                             name := SuggestedExportName;
  3234.                         SFPPutFile(Where, 'Save as?', name, ExportDHookProc, reply, CustomDialogID, nil);
  3235.                         if not reply.good then begin
  3236.                                 AbortMacro;
  3237.                                 exit(Export);
  3238.                             end;
  3239.                         with reply do begin
  3240.                                 name := fname;
  3241.                                 RefNum := vRefNum;
  3242.                                 DefaultRefNum := RefNum;
  3243.                             end;
  3244.                     end;
  3245.                 if (Info = NoInfo) and (ExportAsWhat <= asText) then begin
  3246.                     PutError('No image data available.');
  3247.                     AbortMacro;
  3248.                     exit(Export);
  3249.                 end;
  3250.                 isSelection := RoiShowing and (RoiType = RectRoi);
  3251.                 case ExportAsWhat of
  3252.                     asRaw, asMCID:  begin
  3253.                             if ExportAsWhat = asMCID then
  3254.                                 InvertPic;
  3255.                             SaveAsState := SaveAsWhat;
  3256.                             if ExportAsWhat = AsRaw then
  3257.                                 SaveAsWhat := asRawData
  3258.                             else
  3259.                                 SaveAsWhat := SaveAsMCID;
  3260.                             if isSelection then
  3261.                                 SaveSelection(name, RefNum, false)
  3262.                             else
  3263.                                 SaveAsTIFF(name, RefNum, 0, 0, false);
  3264.                             SaveAsWhat := SaveAsState;
  3265.                         end;
  3266.                     AsText: 
  3267.                         ExportAsText(name, RefNum);
  3268.                     AsLUT: 
  3269.                         SaveLUT(name, RefNum);
  3270.                     asMeasurements: 
  3271.                         if mCount > 0 then
  3272.                             ExportMeasurements(name, RefNum)
  3273.                         else
  3274.                             PutError('Sorry, but no measurements are available to export.');
  3275.                     AsPlotValues: 
  3276.                         if PlotWindow <> nil then begin
  3277.                                 kind := WindowPeek(PlotWindow)^.WindowKind;
  3278.                                 case kind of
  3279.                                     ProfilePlotKind: 
  3280.                                         ConvertPlotToText;
  3281.                                     CalibrationPlotKind: 
  3282.                                         ConvertCalibrationCurveToText;
  3283.                                     otherwise
  3284.                                         TextBufSize := 0;
  3285.                                 end;
  3286.                                 SaveAsText(name, RefNum);
  3287.                             end
  3288.                         else
  3289.                             beep;
  3290.                     asHistogramValues: 
  3291.                         if HistoWindow <> nil then begin
  3292.                                 ConvertHistoToText;
  3293.                                 SaveAsText(name, RefNum);
  3294.                             end
  3295.                         else
  3296.                             beep;
  3297.                     asCoordinates: 
  3298.                         ExportCoordinates(name, RefNum);
  3299.                     otherwise
  3300.                         beep;
  3301.                 end; {case}
  3302.                 if (SaveAsWhat = asRawData) and (SaveAllState <> SaveAllStage2) then
  3303.                     SaveAsWhat := asTIFF;
  3304.             end; {with}
  3305.     end;
  3306.  
  3307.  
  3308.  
  3309. end.