home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / developm / source / image144.sit / File2.p < prev    next >
Encoding:
Text File  |  1992-03-06  |  65.5 KB  |  2,499 lines

  1. unit File2;
  2.  
  3. {Routines used by Image for printing plus a few additional File Menu routines.}
  4.  
  5. interface
  6.  
  7.  
  8.     uses
  9.         QuickDraw, Palettes, PrintTraps, globals, Utilities, Graphics, Lut;
  10.  
  11.  
  12.     procedure GetInfo;
  13.     procedure DoPageSetup;
  14.     procedure Print (ShowDialog: boolean);
  15.     procedure SetHalftone;
  16.     function OpenMacPaint (fname: str255; vnum: integer): boolean;
  17.     procedure TypeMismatch (fname: str255);
  18.     procedure SaveAsMacPaint (fname: str255; RefNum: integer);
  19.     procedure GetUnits (id: integer);
  20.     function OpenTextFile (var name: str255; var RefNum: integer): boolean;
  21.     procedure InitTextInput (name: str255; RefNum: integer);
  22.     procedure GetLineFromText (var rLine: rLineType; var count: integer);
  23.     function ImportTextFile (name: str255; RefNum: integer): boolean;
  24.     procedure PlotXYZ;
  25.     procedure SaveSettings;
  26.     procedure ExportAsText (fname: str255; RefNum: integer);
  27.     procedure ExportMeasurements (fname: str255; RefNum: integer);
  28.     procedure Swap2Bytes (var i: integer);
  29.     function OpenTiffHeader (f: integer; var DirOffset: LongInt): boolean;
  30.     function OpenTiffDirectory (f: integer; DirOffset: LongInt; var TiffInfo: TiffInfoRec): boolean;
  31.     procedure SaveTiffColorMap (f: integer; ImageDataSize: LongInt);
  32.     procedure GetTiffColorMap (f: integer);
  33.     function SaveTiffDir (f, slines, sPixelsPerLine: integer; SavingSelection: boolean; ctabSize, ImageDataSize: LongInt): OSErr;
  34.     procedure GetLoiLength;
  35.     procedure GetAngle (dx, dy: real; var angle: extended);
  36.     function RoomForFile (fname: str255; RefNum: integer; slines, sPixelsPerLine: integer; SavingSelection: boolean): boolean;
  37.     function WriteExtraTiffIFDs (f: integer; ImageDataSize, cTabSize: LongInt): integer;
  38.     procedure SaveLUT (fname: str255; RefNum: integer);
  39.     procedure SaveColorTable (fname: str255; RefNum: integer);
  40.     procedure ExportCoordinates (fname: str255; RefNum: integer);
  41.     procedure SaveOutline (fname: str255; RefNum: integer);
  42.     procedure OpenOutline (fname: str255; RefNum: integer);
  43.  
  44.  
  45. implementation
  46.  
  47.     var
  48.         gstr: str255;
  49.         LittleEndian: boolean;
  50.  
  51.  
  52.     procedure PrintErrCheck;
  53.         var
  54.             err: integer;
  55.             ticks: LongInt;
  56.     begin
  57.         err := PrError;
  58.         if err < 0 then
  59.             beep;
  60.     end;
  61.  
  62.  
  63.     procedure DoPageSetup;
  64.         var
  65.             result: boolean;
  66.     begin
  67.         if PrintRecord = nil then begin
  68.                 PrintRecord := THPrint(NewHandle(SizeOF(TPrint)));
  69.                 PrintDefault(PrintRecord);
  70.             end;
  71.         PrOpen;
  72.         if PrError = NoErr then begin
  73.                 result := PrValidate(PrintRecord);
  74.                 result := PrStlDialog(PrintRecord);
  75.             end;
  76.         PrClose;
  77.     end;
  78.  
  79.  
  80.     procedure PrintHalftone;
  81.         const
  82.             PostScriptBegin = 190;
  83.             PostScriptEnd = 191;
  84.             PostScriptHandle = 192;
  85.             TextIsPostScript = 194;
  86.         var
  87.             HexBufH: handle;
  88.             hloc, vloc, HexCount, iheight, iwidth, hstart, vstart: integer;
  89.             Height, Width, eof, angle, freq: str255;
  90.             aLine: LineType;
  91.             HexBuf: packed array[0..4200] of char;
  92.             err: OSErr;
  93.             table: LookupTable;
  94.  
  95.         procedure PutHEX (byt: integer);
  96.             var
  97.                 i, LowByte, HighByte, tmp: integer;
  98.                 h: char;
  99.         begin
  100.             if not info^.IdentityFunction then
  101.                 byt := table[byt];
  102.             byt := 255 - byt;
  103.             LowByte := byt mod 16;
  104.             byt := byt div 16;
  105.             HighByte := byt mod 16;
  106.             for i := 1 to 2 do begin
  107.                     if i = 1 then
  108.                         tmp := HighByte
  109.                     else
  110.                         tmp := LowByte;
  111.                     case tmp of
  112.                         0: 
  113.                             h := '0';
  114.                         1: 
  115.                             h := '1';
  116.                         2: 
  117.                             h := '2';
  118.                         3: 
  119.                             h := '3';
  120.                         4: 
  121.                             h := '4';
  122.                         5: 
  123.                             h := '5';
  124.                         6: 
  125.                             h := '6';
  126.                         7: 
  127.                             h := '7';
  128.                         8: 
  129.                             h := '8';
  130.                         9: 
  131.                             h := '9';
  132.                         10: 
  133.                             h := 'a';
  134.                         11: 
  135.                             h := 'b';
  136.                         12: 
  137.                             h := 'c';
  138.                         13: 
  139.                             h := 'd';
  140.                         14: 
  141.                             h := 'e';
  142.                         15: 
  143.                             h := 'f';
  144.                     end;
  145.                     hexbuf[HexCount] := h;
  146.                     HexCount := HexCount + 1;
  147.                     if HexCount mod 80 = 0 then begin
  148.                             HexBuf[HexCount] := cr;
  149.                             HexCount := HexCount + 1
  150.                         end;
  151.                 end;
  152.         end;
  153.  
  154.     begin
  155.         with info^ do begin
  156.                 if not IdentityFunction then
  157.                     GetLookupTable(table);
  158.                 MoveTo(-1, -1);
  159.                 LineTo(-1, -1); {Nothing prints without this dummy dot!}
  160.                 PicComment(PostScriptBegin, 0, nil); {See Tech Note #91}
  161.                 PicComment(TextIsPostScript, 0, nil);
  162.                 NumToString(HalftoneFrequency, freq);
  163.                 NumToString(HalftoneAngle, angle);
  164.                 if HalftoneDotFunction then
  165.                     DrawString(concat(freq, ' ', angle, ' {dup mul exch dup mul add 1 exch sub} setscreen'))
  166.                 else
  167.                     DrawString(concat(freq, ' ', angle, ' {pop} setscreen'));
  168.                 DrawString('0 0 translate');
  169.                 with RoiRect do begin
  170.                         iwidth := right - left;
  171.                         if iwidth > MaxLine then
  172.                             iwidth := MaxLine;
  173.                         iheight := bottom - top;
  174.                         hstart := left;
  175.                         vstart := top;
  176.                     end;
  177.                 NumToString(iwidth, width);
  178.                 NumToString(iheight, height);
  179.                 DrawString(concat(width, ' ', height, ' scale'));
  180.                 DrawString(concat('/PicStr ', width, ' string def'));
  181.                 DrawString(concat(width, ' ', height, ' 8 [', width, ' 0 0 ', height, ' 0 0]'));
  182.                 DrawString('{currentfile PicStr readhexstring pop} image');
  183.                 for vloc := vstart to vstart + iheight - 1 do begin
  184.                         GetLine(hstart, vloc, iwidth, aline);
  185.                         HexCount := 0;
  186.                         for hloc := 0 to iwidth - 1 do
  187.                             PutHex(aline[hloc]);
  188.                         HexBuf[HexCount] := cr;
  189.                         HexCount := HexCount + 1;
  190.                         err := PtrToHand(@HexBuf, HexBufH, HexCount);
  191.                         if err <> noErr then
  192.                             exit(PrintHalftone);
  193.                         PicComment(PostScriptHandle, HexCount, HexBufH);
  194.                         DisposHandle(HexBufH);
  195.                         Show2Values(vloc - vstart, iheight);
  196.                         if CommandPeriod then begin
  197.                                 beep;
  198.                                 eof := chr(4);
  199.                                 DrawString(eof);
  200.                                 exit(PrintHalftone)
  201.                             end;
  202.                     end;
  203.             end;
  204.     end;
  205.  
  206.  
  207.     procedure PrintTheImage (PageWidth, PageHeight: integer);
  208.         var
  209.             PrintRect: rect;
  210.             Width, Height: integer;
  211.     begin
  212.         if isLaserWriter and (not OptionKeyDown) and (not OptionKeyWasDown) and (not DriverHalftoning) then
  213.             PrintHalftone
  214.         else
  215.             with info^ do begin
  216.                     LoadLUT(cTable);
  217.                     hlock(handle(osPort^.portPixMap));
  218.                     with RoiRect do begin
  219.                             width := right - left;
  220.                             height := bottom - top;
  221.                         end;
  222.                     with PrintRect do begin
  223.                             left := 0;
  224.                             top := 0;
  225.                             if width < PageWidth then
  226.                                 left := (PageWidth - width) div 2;
  227.                             if height < PageHeight then
  228.                                 top := (Pageheight - height) div 2;
  229.                             right := left + width;
  230.                             bottom := top + height;
  231.                         end;
  232.                     if BitAnd(thePort^.portBits.rowBytes, $8000) = $8000 then begin
  233.                {Assume driver understands Color QD}
  234.                             hlock(handle(CGrafPort(ThePort^).PortPixMap));
  235.                             CopyBits(BitMapHandle(osPort^.portPixMap)^^, BitMapHandle(CGrafPort(ThePort^).PortPixMap)^^, RoiRect, PrintRect, SrcCopy, nil);
  236.                             hunlock(handle(CGrafPort(ThePort^).PortPixMap))
  237.                         end
  238.                     else
  239.                         CopyBits(BitMapHandle(osPort^.portPixMap)^^, thePort^.PortBits, RoiRect, PrintRect, SrcCopy, nil);
  240.                     hunlock(handle(osPort^.portPixMap));
  241.                 end;
  242.     end;
  243.  
  244.  
  245.     procedure PrintResults (PageHeight: integer; var PrintPort: TPPrPort);
  246.         const
  247.             LineInc = 13;
  248.         var
  249.             hloc, vloc, i, LineCount, CharCount, LinesPerPage: integer;
  250.             aLine: str255;
  251.     begin
  252.         CopyResultsToBuffer(1, mCount, true);
  253.         ClipTextInBuffer := false;
  254.         LinesPerPage := PageHeight div LineInc;
  255.         hloc := 0;
  256.         vloc := LineInc;
  257.         LineCount := 0;
  258.         CharCount := 0;
  259.         TextFont(Monaco);
  260.         TextSize(9);
  261.         i := 1;
  262.         repeat
  263.             while TextBufP^[i] >= ' ' do begin
  264.                     CharCount := CharCount + 1;
  265.                     aLine[CharCount] := TextBufP^[i];
  266.                     i := i + 1;
  267.                 end;
  268.             aLine[0] := chr(CharCount);
  269.             MoveTo(hloc, vloc);
  270.             DrawString(aLine);
  271.             CharCount := 0;
  272.             if TextBufP^[i] = cr then begin
  273.                     vLoc := vLoc + LineInc;
  274.                     hloc := 0;
  275.                     LineCount := LineCount + 1;
  276.                     if LineCount >= LinesPerPage then begin
  277.                             LineCount := 0;
  278.                             if i < TextBufSize then begin
  279.                                     PrClosePage(PrintPort);
  280.                                     PrintErrCheck;
  281.                                     PrOpenPage(PrintPort, nil);
  282.                                     vloc := LineInc
  283.                                 end;
  284.                         end;
  285.                 end;
  286.             i := i + 1;
  287.         until i > TextBufSize;
  288.         UnsavedResults := false;
  289.     end;
  290.  
  291.  
  292.     procedure Print (ShowDialog: boolean);
  293.         var
  294.             err, i, LinesToPrint: Integer;
  295.             tPort: GrafPtr;
  296.             PrintPort: TPPrPort;
  297.             PrintStatusRec: TPrStatus;
  298.             prect: rect;
  299.             result: boolean;
  300.     begin
  301.         if WhatToPrint = PrintImage then
  302.             SelectAll(false);
  303.         if (WhatToPrint = PrintImage) or (WhatToPrint = PrintSelection) then begin
  304.                 if OpPending then
  305.                     KillRoi;
  306.                 with info^.RoiRect do
  307.                     LinesToPrint := bottom - top;
  308.                 if not DriverHalftoning then begin
  309.                         DrawLabels('Line:', 'Total:', '');
  310.                         Show2Values(0, LinesToPrint);
  311.                     end;
  312.             end;
  313.         GetPort(tPort);
  314.         if PrintRecord = nil then begin
  315.                 PrintRecord := THPrint(NewHandle(SizeOF(TPrint)));
  316.                 PrintDefault(PrintRecord);
  317.             end;
  318.         PrOpen;
  319.         if PrError = NoErr then begin
  320.                 InitCursor;
  321.                 result := PrValidate(PrintRecord);
  322.                 isLaserWriter := BSR(PrintRecord^^.prStl.wDev, 8) = 3;
  323.                 prect := PrintRecord^^.prInfo.rPage;
  324.                 if ShowDialog then
  325.                     result := PrJobDialog(PrintRecord)
  326.                 else
  327.                     result := true;
  328.                 if not DriverHalftoning then
  329.                     ShowMessage(CmdPeriodToStop);
  330.                 ShowWatch;
  331.                 if result then
  332.                     for i := 1 to PrintRecord^^.PrJob.icopies do begin
  333.                             PrintPort := PrOpenDoc(PrintRecord, nil, nil);
  334.                             PrintErrCheck;
  335.                             Printing := true;
  336.                             PrOpenPage(PrintPort, nil);
  337.                             if PrError = NoErr then
  338.                                 case WhatToPrint of
  339.                                     PrintImage, PrintSelection: 
  340.                                         PrintTheImage(prect.right, prect.bottom);
  341.                                     PrintMeasurements: 
  342.                                         PrintResults(prect.Bottom, PrintPort);
  343.                                     PrintPlot: 
  344.                                         DrawPlot;
  345.                                     PrintHistogram: 
  346.                                         DrawHistogram;
  347.                                 end;
  348.                             Printing := false;
  349.                             PrClosePage(PrintPort);
  350.                             PrintErrCheck;
  351.                             PrCloseDoc(PrintPort);
  352.                             PrintErrCheck;
  353.                             if PrintRecord^^.prJob.bJDocLoop = bSpoolLoop then
  354.                                 PrPicFile(PrintRecord, nil, nil, nil, PrintStatusRec);
  355.                         end;
  356.             end;
  357.         PrClose;
  358.         SetPort(tPort);
  359.         if WhatToPrint = PrintImage then
  360.             KillRoi;
  361.         ShowMessage(' ');
  362.     end;
  363.  
  364.  
  365.     procedure SetHalftone;
  366.         const
  367.             FrequencyID = 8;
  368.             AngleID = 10;
  369.             DotID = 4;
  370.             LineID = 5;
  371.         var
  372.             mylog: DialogPtr;
  373.             item, i, ignore, SaveFrequency, SaveAngle: integer;
  374.             SaveFunction: boolean;
  375.             str: str255;
  376.     begin
  377.         if DriverHalftoning then begin
  378.                 PutMessage('Custom halftoning is only available when Custom Grayscale Halftoning is checked in the Preferences dialog box.');
  379.                 exit(SetHalftone);
  380.             end;
  381.         SaveFrequency := HalftoneFrequency;
  382.         SaveAngle := HalftoneAngle;
  383.         SaveFunction := HalftoneDotFunction;
  384.         mylog := GetNewDialog(30, nil, pointer(-1));
  385.         SetDNum(MyLog, FrequencyID, HalftoneFrequency);
  386.         SelIText(MyLog, FrequencyID, 0, 32767);
  387.         SetDNum(MyLog, AngleID, HalftoneAngle);
  388.         OutlineButton(MyLog, ok, 16);
  389.         if HalftoneDotFunction then
  390.             SetDialogItem(mylog, DotID, 1)
  391.         else
  392.             SetDialogItem(mylog, LineID, 1);
  393.         repeat
  394.             ModalDialog(nil, item);
  395.             if item = FrequencyID then
  396.                 HalftoneFrequency := GetDNum(MyLog, FrequencyID);
  397.             if item = AngleID then begin
  398.                     HalftoneAngle := GetDNum(MyLog, AngleID);
  399.                     if (HalftoneAngle < 0) or (HalftoneAngle > 180) then begin
  400.                             beep;
  401.                             HalftoneAngle := SaveAngle;
  402.                         end;
  403.                 end;
  404.             if (item >= DotID) and (item <= LineID) then begin
  405.                     for i := DotID to LineID do
  406.                         SetDialogItem(mylog, i, 0);
  407.                     SetDialogItem(mylog, item, 1);
  408.                     HalftoneDotFunction := item = DotID;
  409.                 end;
  410.         until (item = ok) or (item = cancel);
  411.         DisposDialog(mylog);
  412.         if item = cancel then begin
  413.                 HalftoneFrequency := SaveFrequency;
  414.                 HalftoneAngle := SaveAngle;
  415.                 HalftoneDotFunction := SaveFunction;
  416.             end;
  417.     end;
  418.  
  419.     procedure GetFileInfo (name: str255; vnum: integer; var DateCreated, LastModified: str255);
  420.         var
  421.             FileParmBlock: ParmBlkPtr;
  422.             theErr: OSErr;
  423.             DateVar, TimeVar: str255;
  424.             Secs: LongInt;
  425.     begin
  426.         DateCreated := '';
  427.         new(FIleParmBlock);
  428.         if FileParmBlock <> nil then
  429.             with FileParmBlock^ do begin
  430.                     ioCompletion := nil;
  431.                     ioNamePtr := @name;
  432.                     ioVRefNum := vnum;
  433.                     ioFVersNum := 0;
  434.                     ioFDirIndex := 0;
  435.                     theErr := PBGetFInfo(FileParmBlock, false);
  436.                     if theErr = NoErr then begin
  437.                             Secs := ioFlCrDat;
  438.                             IUDateString(Secs, abbrevDate, DateVar);
  439.                             IUTimeString(Secs, true, TimeVar);
  440.                             DateCreated := concat(DateVar, '  ', TimeVar);
  441.                             Secs := ioFlMDDat;
  442.                             IUDateString(Secs, abbrevDate, DateVar);
  443.                             IUTimeString(Secs, true, TimeVar);
  444.                             LastModified := concat(DateVar, '  ', TimeVar);
  445.                         end;
  446.                     Dispose(FileParmBlock);
  447.                 end;
  448.     end;
  449.  
  450.  
  451.     procedure GetVolumnInfo (vnum: integer; var VolumnName: str255; var FreeSpace: LongInt);
  452.         var
  453.             theErr: OSErr;
  454.             SPtr: StringPtr;
  455.             VolParmBlock: ParmBlkPtr;
  456.     begin
  457.         VolumnName := '';
  458.         new(SPtr);
  459.         new(VolParmBlock);
  460.         if (SPtr <> nil) and (VolParmBlock <> nil) then
  461.             with VolParmBlock^ do begin
  462.                     SPtr^ := '';
  463.                     ioVRefNum := vnum;
  464.                     ioNamePtr := SPtr;
  465.                     ioCompletion := nil;
  466.                     ioVolIndex := -1;
  467.                     theErr := PBGetVInfo(VolParmBlock, false);
  468.                     VolumnName := ioNamePtr^;
  469.                     FreeSpace := ioVAlBlkSiz * ioVFrBlk;
  470.                     dispose(SPtr);
  471.                     dispose(VolParmBlock);
  472.                 end;
  473.     end;
  474.  
  475.  
  476.     function RoomForFile (fname: str255; RefNum: integer; slines, sPixelsPerLine: integer; SavingSelection: boolean): boolean;
  477.         var
  478.             err: OSErr;
  479.             f: integer;
  480.             VolumnName: str255;
  481.             FreeSpace, ExistingFileSize, NeededSize: LongInt;
  482.     begin
  483.         with info^ do begin
  484.                 ExistingFileSize := 0;
  485.                 RoomForFile := true;
  486.                 err := fsopen(fname, RefNum, f);
  487.                 if err = 0 then begin
  488.                         err := GetEOF(f, ExistingFileSize);
  489.                         err := fsClose(f);
  490.                     end;
  491.                 if ExistingFileSize <> 0 then begin
  492.                         if SavingSelection then
  493.                             NeededSize := LongInt(slines) * sPixelsPerLine
  494.                         else
  495.                             NeededSize := ImageSize;
  496.                         if StackInfo <> nil then
  497.                             with StackInfo^ do
  498.                                 NeededSize := NeededSize * nSlices + nSlices * SizeOf(StackIFDType);
  499.                         GetVolumnInfo(RefNum, VolumnName, FreeSpace);
  500.                         if (NeededSize - ExistingFileSize + 8192) > FreeSpace then begin
  501.                                 PutMessage('There is not enough free space on this disk to save this image.');
  502.                                 RoomForFile := false;
  503.                             end;
  504.                     end;
  505.             end;
  506.     end;
  507.  
  508.  
  509.     procedure GetLoiLength;
  510.         var
  511.             dx, dy: extended;
  512.     begin
  513.         with info^ do begin
  514.                 dx := LX2 - LX1;
  515.                 dy := LY2 - LY1;
  516.                 uLength := sqrt(sqr(dx) + sqr(dy));
  517.                 if SpatiallyCalibrated then
  518.                     cLength := sqrt(sqr(dx / xSpatialScale) + sqr(dy / ySpatialScale))
  519.                 else
  520.                     cLength := uLength;
  521.             end;
  522.     end;
  523.  
  524.  
  525.     procedure GetAngle (dx, dy: real; var angle: extended);
  526.         var
  527.             quadrant: (q1, q2orq3, q4);
  528.     begin
  529.         if dx <> 0.0 then
  530.             angle := arctan(dy / dx)
  531.         else begin
  532.                 if dy >= 0.0 then
  533.                     angle := pi / 2.0
  534.                 else
  535.                     angle := -pi / 2.0
  536.             end;
  537.         angle := (180.0 / pi) * angle;
  538.         if (dx >= 0.0) and (dy >= 0.0) then
  539.             quadrant := q1
  540.         else if dx < 0.0 then
  541.             quadrant := q2orq3
  542.         else
  543.             quadrant := q4;
  544.         case quadrant of
  545.             q1: 
  546.                 ;
  547.             q2orq3: 
  548.                 angle := angle + 180.0;
  549.             q4: 
  550.                 angle := angle + 360.0;
  551.         end;
  552.     end;
  553.  
  554.  
  555.     procedure GetInfo;
  556.         var
  557.             name, str, DateCreated, LastModified, VolumnName, str2: str255;
  558.             hloc, vloc, InfoWidth, InfoHeight: integer;
  559.             SaveRoiShowing: boolean;
  560.             FreeSpace: LongInt;
  561.             SaveForeIndex, SaveBackIndex: integer;
  562.             ImageInfo, InfoWindowInfo: InfoPtr;
  563.             angle: extended;
  564.             x1, y1, x2, y2: real;
  565.  
  566.         procedure NewLine;
  567.         begin
  568.             vloc := vloc + 13;
  569.             MoveTo(hloc, vloc);
  570.         end;
  571.  
  572.         procedure NewParagraph;
  573.         begin
  574.             vloc := vloc + 18;
  575.             MoveTo(hloc, vloc);
  576.         end;
  577.  
  578.     begin
  579.         InfoWidth := 260;
  580.         InfoHeight := 300;
  581.         with info^ do begin
  582.                 if RoiShowing then
  583.                     InfoHeight := 300;
  584.                 if RoiShowing and (RoiType = LineRoi) then
  585.                     InfoHeight := 340;
  586.                 name := concat('Info About ', title);
  587.                 SaveRoiShowing := RoiShowing;
  588.             end;
  589.         SaveForeIndex := ForegroundIndex;
  590.         SaveBackIndex := BackgroundIndex;
  591.         SetForegroundColor(BlackIndex);
  592.         SetBackgroundColor(WhiteIndex);
  593.         ImageInfo := info;
  594.         if NewPicWindow(name, InfoWidth, InfoHeight) then
  595.             with ImageInfo^ do begin
  596.                     InfoWindowInfo := Info;
  597.                     SetPort(GrafPtr(info^.osPort));
  598.                     TextFont(ApplFont);
  599.                     TextSize(9);
  600.                     hloc := 15;
  601.                     vloc := 10;
  602.                     DrawBString('Name: ');
  603.                     DrawString(title);
  604.                     NewParagraph;
  605.                     DrawBString('Width: ');
  606.                     DrawXDimension(PixelsPerLine, 0);
  607.                     NewLine;
  608.                     DrawBString('Height: ');
  609.                     DrawYDimension(nlines, 0);
  610.                     if StackInfo <> nil then begin
  611.                             NewLine;
  612.                             DrawBString('Depth: ');
  613.                             DrawLong(StackInfo^.nSlices);
  614.                         end;
  615.                     NewLine;
  616.                     DrawBString('Size: ');
  617.                     if StackInfo <> nil then
  618.                         DrawLong((ImageSize * StackInfo^.nSlices) div 1024)
  619.                     else
  620.                         DrawLong(ImageSize div 1024);
  621.                     DrawString('K');
  622.                     NewParagraph;
  623.                     GetFileInfo(title, vref, DateCreated, LastModified); {DateCreated:='';}
  624.                     if DateCreated <> '' then begin
  625.                             DrawBString('Creation Date: ');
  626.                             DrawString(DateCreated);
  627.                             NewLine;
  628.                             DrawBString('Last Modified: ');
  629.                             DrawString(LastModified);
  630.                             NewLine;
  631.                         end;
  632.                     GetVolumnInfo(vref, VolumnName, FreeSpace);
  633.                     if VolumnName <> '' then begin
  634.                             DrawBString('Volume: ');
  635.                             DrawString(VolumnName);
  636.                             DrawString(' (');
  637.                             DrawLong(FreeSpace div 1024);
  638.                             DrawString('K free)');
  639.                             NewParagraph;
  640.                         end;
  641.                     DrawBString('Type: ');
  642.                     if StackInfo <> nil then
  643.                         str := concat('Stack (', long2str(StackInfo^.nSlices), '  slices)')
  644.                     else begin
  645.                             case PictureType of
  646.                                 pdp11: 
  647.                                     str := 'PDP-11';
  648.                                 NewPicture: 
  649.                                     str := 'New';
  650.                                 normal: 
  651.                                     str := 'Normal';
  652.                                 PictFile: 
  653.                                     str := 'PICT';
  654.                                 TiffFile, InvertedTIFF: 
  655.                                     str := 'TIFF';
  656.                                 Leftover: 
  657.                                     str := 'Left Over';
  658.                                 imported: 
  659.                                     str := 'Imported';
  660.                                 QuickCaptureType: 
  661.                                     str := 'Camera(QuickCapture)';
  662.                                 BlankField: 
  663.                                     str := 'Blank Field';
  664.                                 ScionType: 
  665.                                     str := 'Camera(Scion)';
  666.                                 otherwise
  667.                                     ;
  668.                             end;
  669.                             if BinaryPic then
  670.                                 str := concat(str, ' (Binary)');
  671.                         end;
  672.                     DrawString(str);
  673.                     if StackInfo <> nil then
  674.                         with StackInfo^ do
  675.                             if SliceSpacing <> 0.0 then begin
  676.                                     NewLine;
  677.                                     DrawBString('Slice Spacing: ');
  678.                                     RealToString(SliceSpacing, 1, 1, str);
  679.                                     DrawString(str);
  680.                                     DrawString(' pixels');
  681.                                 end;
  682.                     NewLine;
  683.                     DrawBString('Lookup Table: ');
  684.                     case LutMode of
  685.                         PseudoColor: 
  686.                             str := concat('Pseudocolor(', long2str(ncolors), ', ', long2str(ColorStart), '-', long2str(ColorEnd), ')');
  687.                         GrayScale: 
  688.                             str := concat('Grayscale(', long2str(ncolors), ', ', long2str(ColorStart), '-', long2str(ColorEnd), ')');
  689.                         ColorLut: 
  690.                             str := 'Color';
  691.                         CustomGrayscale: 
  692.                             str := 'Custom Grayscale';
  693.                         otherwise
  694.                     end;
  695.                     DrawString(str);
  696.                     NewLine;
  697.                     DrawBString('Magnification: ');
  698.                     if ScaleToFitWindow then begin
  699.                             DrawReal(magnification, 1, 2);
  700.                             DrawString(' (Scale to Window Mode)')
  701.                         end
  702.                     else begin
  703.                             DrawReal(magnification, 1, 0);
  704.                             DrawString(':1')
  705.                         end;
  706.                     NewLine;
  707.                     DrawBString('Scale: ');
  708.                     if SpatiallyCalibrated then begin
  709.                             DrawReal(xSpatialScale, 1, 3);
  710.                             DrawString(' Pixels Per ');
  711.                             DrawString(FullUnits);
  712.                             if ScaleMagnification <> 1.0 then begin
  713.                                     NewLine;
  714.                                     DrawBString('Scale Magnification: ');
  715.                                     DrawReal(ScaleMagnification, 1, 2);
  716.                                 end;
  717.                             if PixelAspectRatio <> 1.0 then begin
  718.                                     NewLine;
  719.                                     DrawBString('Pixel Aspect Ratio: ');
  720.                                     DrawReal(PixelAspectRatio, 1, 4);
  721.                                 end;
  722.                         end
  723.                     else
  724.                         DrawString('None');
  725.                     if DensityCalibrated then begin
  726.                             NewLine;
  727.                             DrawBString('Unit of Measure: ');
  728.                             if UnitOfMEasure = '' then
  729.                                 DrawString('None')
  730.                             else
  731.                                 DrawString(UnitOfMeasure)
  732.                         end;
  733.                     NewParagraph;
  734.                     DrawBString('Free RAM: ');
  735.                     DrawLong(FreeMem div 1024);
  736.                     DrawString('K');
  737.                     NewLine;
  738.                     DrawBString('Largest Free Block: ');
  739.                     DrawLong(MaxBlock div 1024);
  740.                     DrawString('K');
  741.                     NewParagraph;
  742.                     if RoiType <> NoRoi then begin
  743.                             DrawBString('Selection Type: ');
  744.                             case RoiType of
  745.                                 RgnRoi: 
  746.                                     DrawString('Freehand or Polygon');
  747.                                 RectRoi: 
  748.                                     DrawString('Rectangle');
  749.                                 OvalRoi: 
  750.                                     DrawString('Oval');
  751.                                 LineRoi: 
  752.                                     DrawString('Straight Line');
  753.                                 FreeLineRoi: 
  754.                                     DrawString('Freehand Line');
  755.                                 SegLineRoi: 
  756.                                     DrawString('Segmented Line');
  757.                             end;
  758.                             NewLine;
  759.                             case RoiType of
  760.                                 RgnRoi, RectRoi, OvalRoi: 
  761.                                     with RoiRect do begin
  762.                                             DrawBString('    Left: ');
  763.                                             DrawXDimension(left, 0);
  764.                                             NewLine;
  765.                                             DrawBString('    Top: ');
  766.                                             if InvertYCoordinates then
  767.                                                 DrawYDimension(PicRect.bottom - top - 1, 0)
  768.                                             else
  769.                                                 DrawYDimension(top, 0);
  770.                                             NewLine;
  771.                                             DrawBString('    Width: ');
  772.                                             DrawXDimension(right - left, 0);
  773.                                             NewLine;
  774.                                             DrawBString('    Height: ');
  775.                                             DrawYDimension(bottom - top, 0);
  776.                                         end;
  777.                                 LineRoi, FreeLineRoi, SegLineRoi:  begin
  778.                                         info := ImageInfo;
  779.                                         if RoiType = LineRoi then
  780.                                             GetLoiLength;
  781.                                         GetLoi(x1, y1, x2, y2);
  782.                                         Info := InfoWindowInfo;
  783.                                         DrawBString('    Length: ');
  784.                                         if SpatiallyCalibrated then begin
  785.                                                 DrawReal(cLength, 1, 2);
  786.                                                 DrawString(units);
  787.                                             end
  788.                                         else
  789.                                             DrawReal(uLength, 1, 2);
  790.                                         NewLine;
  791.                                         if RoiType = LineRoi then begin
  792.                                                 GetAngle(x2 - x1, y1 - y2, angle);
  793.                                                 DrawBString('    Angle: ');
  794.                                                 DrawReal(Angle, 1, 2);
  795.                                                 DrawString('í');
  796.                                                 NewLine;
  797.                                             end;
  798.                                         DrawBString('    X1: ');
  799.                                         DrawXDimension(x1, 2);
  800.                                         NewLine;
  801.                                         DrawBString('    Y1: ');
  802.                                         if InvertYCoordinates then
  803.                                             DrawYDimension(PicRect.bottom - y1 - 1, 2)
  804.                                         else
  805.                                             DrawYDimension(y1, 2);
  806.                                         NewLine;
  807.                                         DrawBString('    X2: ');
  808.                                         DrawXDimension(x2, 2);
  809.                                         NewLine;
  810.                                         DrawBString('    Y2: ');
  811.                                         if InvertYCoordinates then
  812.                                             DrawYDimension(PicRect.bottom - y2 - 1, 2)
  813.                                         else
  814.                                             DrawYDimension(y2, 2);
  815.                                     end;
  816.                                 otherwise
  817.                             end; {case}
  818.                         end
  819.                     else
  820.                         DrawBString('No Selection');
  821.                 end;
  822.         SetForegroundColor(SaveForeIndex);
  823.         SetBackgroundColor(SaveBackIndex);
  824.     end;
  825.  
  826.  
  827.     function NewPtrClear (blockSize: Size): Ptr;
  828.     {This function will return a pointer of size specified and will}
  829.     {clear the memory to zeros . This is done to create an empty bit}
  830.     {map containing nothing but white bits . }
  831.  
  832.     {MOVE . L  ( SP ) + , D0  ; get Size variable from stack}
  833.     {_NewPtr , clear           ; make pointer }
  834.     {MOVE.L  A0 , ( SP )       ; return pointer }
  835.     {MOVE.W D0, MemErr     ; set up MemErr }
  836.     inline
  837.         $201F, $A31E, $2E88, $31C0, $0220;
  838.  
  839.  
  840.     function IOCheck (err: OSerr): integer;
  841.         var
  842.             ignore: integer;
  843.             errStr: str255;
  844.     begin
  845.         if err <> noErr then begin
  846.                 NumToString(err, errStr);
  847.                 ParamText('', errStr, '', '');
  848.                 InitCursor;
  849.                 ignore := alert(IOErrorID, nil);
  850.             end;
  851.         IOCheck := err;
  852.     end;
  853.  
  854.  
  855.     function OpenMacPaint (fname: str255; vnum: integer): boolean;
  856.         const
  857.             MaxUnPackedSize = 51840;   {Max MacPaint size in bytes=720 lines * 72 bytes/line }
  858.         type
  859.             mpLine = array[1..18] of LongInt;
  860.             mpArrayT = array[1..720] of mpLine;
  861.             mpArrayP = ^mpArrayT;
  862.         var
  863.             i, f, ScanLine, LastLine, LastWord, LastColumn: integer;
  864.             err: osErr;
  865.             srcSize: LongInt;
  866.             srcPtr, dstPtr, src, dst: ptr;
  867.             theBitMap: BitMap;
  868.             mpArray: mpArrayP;
  869.             BlankLine, BlankColumn: boolean;
  870.             frect: rect;
  871.  
  872.         procedure abort;
  873.         begin
  874.             beep;
  875.             if srcPtr <> nil then
  876.                 DisposPtr(srcPtr);
  877.             if dstPtr <> nil then
  878.                 DisposPtr(dstPtr);
  879.             exit(OpenMacPaint);
  880.         end;
  881.  
  882.     begin
  883.         OpenMacPaint := false;
  884.         err := fsOpen(fname, vnum, f);
  885.         if ioCheck(err) <> noErr then
  886.             exit(OpenMacPaint);
  887.         err := GetEOF(f, srcSize);
  888.         srcSize := srcSize - 512;
  889.         srcPtr := NewPtr(srcSize);
  890.         if srcPtr = nil then
  891.             abort;
  892.         err := SetFPos(f, fsFromStart, 512);
  893.         err := fsRead(f, srcSize, srcPtr);
  894.         if ioCheck(err) <> noErr then
  895.             exit(OpenMacPaint);
  896.         err := fsClose(f);
  897.         dstPtr := NewPtrClear(MaxUnPackedSize);
  898.         if dstPtr = nil then
  899.             abort;
  900.         src := srcPtr;
  901.         dst := dstPtr;
  902.         for scanLine := 1 to 720 do
  903.             UnPackBits(src, dst, 72); {bumps both ptrs}
  904.         DisposPtr(srcPtr);
  905.         mpArray := mpArrayP(dstPtr);
  906.         LastLine := 720;
  907.         BlankLine := true;
  908.         repeat
  909.             for i := 1 to 18 do
  910.                 blankLine := BlankLine and (mpArray^[LastLine, i] = 0);
  911.             if BlankLine then
  912.                 LastLine := LastLine - 1;
  913.         until (not BlankLine) or (LastLine = 1);
  914.         LastWord := 18;
  915.         BlankColumn := true;
  916.         repeat
  917.             for i := 1 to LastLine do
  918.                 blankColumn := BlankColumn and (mpArray^[i, LastWord] = 0);
  919.             if BlankColumn then
  920.                 LastWord := LastWord - 1;
  921.         until (not BlankColumn) or (LastWord = 1);
  922.         LastColumn := LastWord * 32;
  923.         LastColumn := LastColumn + 8;
  924.         if LastColumn > 576 then
  925.             LastColumn := 576;
  926.         LastLine := LastLine + 8;
  927.         if LastLine > 720 then
  928.             LastLine := 720;
  929.         SetRect(frect, 0, 0, LastColumn, LastLine);
  930.         with theBitMap do begin
  931.                 baseAddr := dstPtr;
  932.                 rowBytes := 72;
  933.                 bounds := frect;
  934.             end;
  935.         if not NewPicWindow(fname, LastColumn, LastLine) then
  936.             abort;
  937.         SetForegroundColor(BlackIndex);
  938.         SetBackgroundColor(WhiteIndex);
  939.         with info^ do begin
  940.                 hlock(handle(osPort^.portPixMap));
  941.                 CopyBits(theBitMap, BitMapHandle(osPort^.PortPixMap)^^, frect, frect, srcCopy, nil);
  942.                 hunlock(handle(osPort^.PortPixMap));
  943.                 DisposPtr(dstPtr);
  944.                 PictureType := imported;
  945.                 BinaryPic := true;
  946.                 if PixMapSize > UndoBufSize then
  947.                     PutWarning;
  948.             end;
  949.         OpenMacPaint := true;
  950.     end;
  951.  
  952.  
  953.     procedure TypeMismatch (fname: str255);
  954.     begin
  955.         PutMessage(concat('The file "', fname, '" is a different type, and therefore cannot be replaced'));
  956.     end;
  957.  
  958.  
  959.     procedure SaveAsMacPaint (fname: str255; RefNum: integer);
  960.         const
  961.             MaxFileSize = 53072;   { maximum MacPaint file size. }
  962.         var
  963.             TheInfo: FInfo;
  964.             dstPtr, srcPtr, mpBufPtr: Ptr;
  965.             i, f, scanLine, err, width, height: integer;
  966.             dstBuffer: array[1..128] of LongInt;
  967.             size, dstSize: LongInt;
  968.             theBitMap: BitMap;
  969.             mprect, srect, drect: rect;
  970.  
  971.         procedure abort;
  972.         begin
  973.             beep;
  974.             if mpBufPtr <> nil then
  975.                 DisposPtr(mpBufPtr);
  976.             if f <> -1 then
  977.                 err := fsclose(f);
  978.             exit(SaveAsMacPaint);
  979.         end;
  980.  
  981.     begin
  982.         f := -1;
  983.         err := GetFInfo(fname, RefNum, TheInfo);
  984.         case err of
  985.             NoErr: 
  986.                 with TheInfo do begin
  987.                         if fdType <> 'PNTG' then begin
  988.                                 TypeMismatch(fname);
  989.                                 exit(SaveAsMacPaint)
  990.                             end;
  991.                     end;
  992.             FNFerr:  begin
  993.                     err := create(fname, RefNum, 'MPNT', 'PNTG');
  994.                     if IOCheck(err) <> 0 then
  995.                         exit(SaveAsMacPaint);
  996.                 end;
  997.             otherwise
  998.                 if IOCheck(err) <> 0 then
  999.                     exit(SaveAsMacPaint);
  1000.         end;
  1001.         mpBufPtr := NewPtrClear(MaxFileSize);
  1002.         if mpBufPtr = nil then
  1003.             abort;
  1004.         ShowWatch;
  1005.         SetRect(mprect, 0, 0, 576, 720);
  1006.         with theBitMap do begin
  1007.                 baseAddr := mpBufPtr;
  1008.                 rowBytes := 72;
  1009.                 bounds := mprect;
  1010.             end;
  1011.         with info^ do begin
  1012.                 if roiShowing then
  1013.                     srect := RoiRect
  1014.                 else
  1015.                     srect := PicRect;
  1016.                 with srect do begin
  1017.                         width := right - left;
  1018.                         height := bottom - top;
  1019.                         if width > 576 then
  1020.                             width := 576;
  1021.                         if height > 720 then
  1022.                             height := 720;
  1023.                         right := left + width;
  1024.                         bottom := top + height;
  1025.                     end;
  1026.                 SetRect(drect, 0, 0, width, height);
  1027.                 hlock(handle(osPort^.portPixMap));
  1028.                 CopyBits(BitMapHandle(osPort^.PortPixMap)^^, theBitMap, srect, drect, srcCopy, nil);
  1029.                 hunlock(handle(osPort^.PortPixMap));
  1030.             end;
  1031.         err := fsOpen(fname, RefNum, f);
  1032.         if IOCheck(err) <> noErr then
  1033.             abort;
  1034.         for I := 1 to 128 do
  1035.             dstBuffer[I] := 0;
  1036.         Size := 512;
  1037.         err := FSWrite(f, Size, @dstBuffer);
  1038.         if IOCheck(err) <> noErr then
  1039.             abort;
  1040.         srcPtr := theBitMap.baseAddr;
  1041.         for scanLine := 1 to 720 do begin
  1042.                 dstPtr := @dstBuffer; { reset the pointer to bottom }
  1043.                 PackBits(srcPtr, dstPtr, 72); { bumps both ptrs}
  1044.                 dstSize := ord(dstPtr) - ord(@dstBuffer);{calc packed size}
  1045.                 err := fsWrite(f, dstSize, @dstBuffer);
  1046.                 if IOCheck(err) <> noErr then
  1047.                     abort;
  1048.             end;
  1049.         err := fsclose(f);
  1050.         DisposPtr(mpBufPtr);
  1051.         info^.changes := false;
  1052.     end;
  1053.  
  1054.  
  1055.     procedure GetUnits (id: integer);
  1056.     begin
  1057.         with info^ do
  1058.             case id of
  1059.                 5:  begin
  1060.                         UnitsID := Nanometers;
  1061.                         FullUnits := 'Nanometer';
  1062.                         UnitsPerCm := 10000000.0;
  1063.                         units := 'nm';
  1064.                     end;
  1065.                 6:  begin
  1066.                         UnitsID := Micrometers;
  1067.                         FullUnits := 'Micrometer';
  1068.                         UnitsPerCm := 10000.0;
  1069.                         units := 'â•¡m';
  1070.                     end;
  1071.                 7:  begin
  1072.                         UnitsID := Millimeters;
  1073.                         FullUnits := 'Millimeter';
  1074.                         UnitsPerCm := 10.0;
  1075.                         units := 'mm';
  1076.                     end;
  1077.                 8:  begin
  1078.                         UnitsID := Centimeters;
  1079.                         FullUnits := 'Centimeter';
  1080.                         UnitsPerCm := 1.0;
  1081.                         units := 'cm';
  1082.                     end;
  1083.                 9:  begin
  1084.                         UnitsID := Meters;
  1085.                         FullUnits := 'Meter';
  1086.                         UnitsPerCm := 0.01;
  1087.                         units := 'm ';
  1088.                     end;
  1089.                 10:  begin
  1090.                         UnitsID := Kilometers;
  1091.                         FullUnits := 'Kilometer';
  1092.                         UnitsPerCm := 0.00001;
  1093.                         units := 'km';
  1094.                     end;
  1095.                 11:  begin
  1096.                         UnitsID := Inches;
  1097.                         FullUnits := 'Inch';
  1098.                         UnitsPerCm := 0.3937;
  1099.                         units := 'in';
  1100.                     end;
  1101.                 12:  begin
  1102.                         UnitsID := feet;
  1103.                         FullUnits := 'foot';
  1104.                         UnitsPerCm := 0.0328083;
  1105.                         units := 'ft';
  1106.                     end;
  1107.                 13:  begin
  1108.                         UnitsID := Miles;
  1109.                         FullUnits := 'Mile';
  1110.                         UnitsPerCm := 0.000006213;
  1111.                         units := 'mi';
  1112.                     end;
  1113.                 otherwise begin
  1114.                         UnitsID := Pixels;
  1115.                         FullUnits := 'Pixel';
  1116.                         UnitsPerCm := 0.0;
  1117.                         units := '  ';
  1118.                         RawSpatialScale := 0.0;
  1119.                         ScaleMagnification := 1.0;
  1120.                         PixelAspectRatio := 1.0;
  1121.                         xSpatialScale := 0.0;
  1122.                         ySpatialScale := 0.0;
  1123.                         SpatiallyCalibrated := false;
  1124.                     end
  1125.             end; {case}
  1126.     end;
  1127.  
  1128.  
  1129.     function OpenTextFile (var name: str255; var RefNum: integer): boolean;
  1130.         var
  1131.             where: Point;
  1132.             typeList: SFTypeList;
  1133.             reply: SFReply;
  1134.             err: OSErr;
  1135.     begin
  1136.         where.v := 120;
  1137.         where.h := 120;
  1138.         typeList[0] := 'TEXT';
  1139.         SFGetFile(Where, '', nil, 1, typeList, nil, reply);
  1140.         if reply.good then
  1141.             with reply do begin
  1142.                     name := fname;
  1143.                     RefNum := vRefNum;
  1144.                     OpenTextFile := true;
  1145.                 end
  1146.         else
  1147.             OpenTextFile := false;
  1148.     end;
  1149.  
  1150.  
  1151.     procedure GetBuffer;
  1152.         var
  1153.             err: OSErr;
  1154.             count, FilePos: LongInt;
  1155.     begin
  1156.         count := MaxTextBufSize;
  1157.         err := fsread(Textf, count, ptr(TextBufP));
  1158.         TextBufSize := count;
  1159.         err := GetFPos(Textf, FilePos);
  1160.         if FilePos = TextFileSize then begin
  1161.                 TextBufSize := TextBufSize + 1;
  1162.                 if TextBufSize > MaxTextBufSize then
  1163.                     TextBufSize := MaxTextBufSize;
  1164.                 TextBufP^[TextBufSize] := eof;
  1165.                 err := fsclose(Textf);
  1166.             end;
  1167.         TextIndex := 1;
  1168.     end;
  1169.  
  1170.  
  1171.     function GetByte: char;
  1172.     begin
  1173.         GetByte := TextBufP^[TextIndex];
  1174.         TextIndex := TextIndex + 1;
  1175.         if TextIndex > MaxTextBufSize then
  1176.             GetBuffer;
  1177.     end;
  1178.  
  1179.  
  1180.     function GetNumber: real;
  1181.         var
  1182.             c: char;
  1183.             str: str255;
  1184.     begin
  1185.         repeat
  1186.             c := GetByte;
  1187.             if c = tab then begin
  1188.                     GetNumber := 0.0;
  1189.                     exit(GetNumber);
  1190.                 end;
  1191.             if (c = cr) or (c = eof) then begin
  1192.                     TextEol := true;
  1193.                     TextEof := c = eof;
  1194.                     GetNumber := NoValue;
  1195.                     exit(GetNumber);
  1196.                 end;
  1197.         until c in ['0'..'9', '-', '.'];
  1198.         Str := '';
  1199.         while c in ['0'..'9', '+', '-', '.', 'e', 'E'] do begin
  1200.                 Str := concat(str, c);
  1201.                 c := GetByte;
  1202.                 if (c = cr) or (c = eof) then begin
  1203.                         TextEol := true;
  1204.                         TextEof := c = eof;
  1205.                     end;
  1206.             end;
  1207.         GetNumber := StringToReal(str);
  1208.     end;
  1209.  
  1210.  
  1211.     procedure GetLineFromText (var rLine: rLineType; var count: integer);
  1212.         var
  1213.             n: real;
  1214.     begin
  1215.         count := 0;
  1216.         if TextEof then
  1217.             exit(GetLineFromText);
  1218.         repeat
  1219.             n := GetNumber;
  1220.             if n <> NoValue then begin
  1221.                     count := count + 1;
  1222.                     rLine[count] := n;
  1223.                 end;
  1224.         until TextEol or (count = MaxLine);
  1225.         TextEol := false;
  1226.     end;
  1227.  
  1228.  
  1229.     procedure InitTextInput (name: str255; RefNum: integer);
  1230.         var
  1231.             err: OSErr;
  1232.     begin
  1233.         err := FSOpen(name, RefNum, Textf);
  1234.         err := GetEof(Textf, TextFileSize);
  1235.         err := SetFPos(Textf, fsFromStart, 0);
  1236.         ShowWatch;
  1237.         if WhatsOnClip = TextOnClip then
  1238.             WhatsOnClip := Nothing;
  1239.         GetBuffer;
  1240.         TextEol := false;
  1241.         TextEof := false;
  1242.     end;
  1243.  
  1244.  
  1245.     function ImportTextFile (name: str255; RefNum: integer): boolean;
  1246.         var
  1247.             nRows, nColumns, count, i, vloc, BlankPixel, nPixelsPerLine: integer;
  1248.             rLine: rLineType;
  1249.             pvalue: real;
  1250.             min, max, ScaleFactor, DefaultValue, tvalue: extended;
  1251.             err: OSErr;
  1252.             line, BlankLine: LineType;
  1253.             TheInfo: FInfo;
  1254.     begin
  1255.         ImportTextFile := false;
  1256.         err := GetFInfo(name, RefNum, TheInfo);
  1257.         if TheInfo.fdType <> 'TEXT' then begin
  1258.                 PutMessage('File is not of type ''TEXT''.');
  1259.                 exit(ImportTextFile);
  1260.             end;
  1261.         InitTextInput(name, RefNum);
  1262.         nRows := 0;
  1263.         nColumns := 0;
  1264.         max := -10e-10;
  1265.         min := 10e10;
  1266.         ShowMessage(concat('First pass used to find ', cr, 'width, height,min, and max.', cr, cr, CmdPeriodToStop));
  1267.         DrawLabels('Line:', '', '');
  1268.         while not TextEof do begin
  1269.                 GetLineFromText(rLine, count);
  1270.                 if not (TextEof and (count = 0)) then
  1271.                     nRows := nRows + 1;
  1272.                 if count > nColumns then
  1273.                     nColumns := count;
  1274.                 for i := 1 to count do begin
  1275.                         pvalue := rLine[i];
  1276.                         if pvalue > max then
  1277.                             max := pvalue;
  1278.                         if pvalue < min then
  1279.                             min := pvalue;
  1280.                     end;
  1281.                 if nRows mod 10 = 0 then begin
  1282.                         Show1Value(nRows, NoValue);
  1283.                         if CommandPeriod then begin
  1284.                                 beep;
  1285.                                 err := fsclose(Textf);
  1286.                                 Exit(ImportTextFile);
  1287.                             end;
  1288.                     end;
  1289.             end;
  1290.         ShowMessage(concat('rows= ', long2str(nRows), cr, 'columns= ', long2str(ncolumns), cr, 'min= ', long2str(round(min)), cr, 'max= ', long2str(round(max))));
  1291.         if nColumns > MaxLine then begin
  1292.                 PutMessage('More than 2048 pixels per line.');
  1293.                 Exit(ImportTextFile);
  1294.             end;
  1295.         nPixelsPerLine := nColumns;
  1296.         if NewPicWindow(name, nPixelsPerLine, nrows) then
  1297.             with info^ do begin
  1298.                     if (not ImportAutoScale) and (max > min) then begin
  1299.                             min := ImportMin;
  1300.                             max := ImportMax;
  1301.                         end;
  1302.                     ScaleFactor := 253.0 / (max - min);
  1303.                     InitTextInput(name, RefNum);
  1304.                     vloc := 0;
  1305.                     DefaultValue := 0.0;
  1306.                     if DefaultValue < min then
  1307.                         DefaultValue := min;
  1308.                     if DefaultValue > max then
  1309.                         DefaultValue := max;
  1310.                     BlankPixel := round((DefaultValue - min) * ScaleFactor + 1);
  1311.                     for i := 0 to nColumns - 1 do
  1312.                         BlankLine[i] := BlankPixel;
  1313.                     DrawLabels('Line:', 'Total:', '');
  1314.                     while not TextEof do begin
  1315.                             GetLineFromText(rLine, count);
  1316.                             if not (TextEof and (count = 0)) then begin
  1317.                                     line := BlankLine;
  1318.                                     if ImportAutoScale then     {Map values into the range 1-254}
  1319.                                         for i := 1 to count do
  1320.                                             line[i - 1] := round((rLine[i] - min) * ScaleFactor + 1)
  1321.                                     else
  1322.                                         for i := 1 to count do begin
  1323.                                                 tvalue := rLine[i];
  1324.                                                 if tvalue < min then
  1325.                                                     tvalue := min;
  1326.                                                 if tvalue > max then
  1327.                                                     tvalue := max;
  1328.                                                 line[i - 1] := round((tvalue - min) * ScaleFactor + 1);
  1329.                                             end;
  1330.                                     PutLine(0, vloc, PixelsPerLine, line);
  1331.                                     vloc := vloc + 1;
  1332.                                 end;
  1333.                             if vloc mod 10 = 0 then begin
  1334.                                     Show2Values(vloc, nRows);
  1335.                                     if CommandPeriod then begin
  1336.                                             beep;
  1337.                                             err := fsclose(Textf);
  1338.                                             Exit(ImportTextFile);
  1339.                                         end;
  1340.                                 end;
  1341.                         end;
  1342.                     fit := StraightLine;
  1343.                     nCoefficients := 2;
  1344.                     coefficient[2] := (max - min) / 253.0;
  1345.                     coefficient[1] := min - coefficient[2];
  1346.                     DensityCalibrated := true;
  1347.                     UpdateTitleBar;
  1348.                     ZeroClip := false;
  1349.                     changes := true;
  1350.                     PictureType := imported;
  1351.                 end; {with}
  1352.         ImportTextFile := true;
  1353.     end;
  1354.  
  1355.  
  1356.     procedure PlotXYZ;
  1357. {Reads X-Y coordinate pairs and optional intensiy(Z) values from a}
  1358. {two or three column tab-delimited text file and plots them in the current window.}
  1359.         var
  1360.             fname, str: str255;
  1361.             RefNum, i, nColumns, nValues, index, wheight: integer;
  1362.             rLine: rLineType;
  1363.     begin
  1364.         if not OpenTextFile(fname, RefNum) then
  1365.             exit(PlotXYZ);
  1366.         InitTextInput(fname, RefNum);
  1367.         GetLineFromText(rLine, nValues);
  1368.         nColumns := nValues;
  1369.         if not ((nColumns = 2) or (nColumns = 3)) then begin
  1370.                 PutMessage('File must have two or three columns.');
  1371.                 exit(PlotXYZ);
  1372.             end;
  1373.         wheight := info^.nLines;
  1374.         index := ForegroundIndex;
  1375.         repeat
  1376.             if nColumns = 3 then begin
  1377.                     index := round(rLine[3]);
  1378.                     if index > 255 then
  1379.                         index := 255;
  1380.                     if index < 0 then
  1381.                         index := 0;
  1382.                 end;
  1383.             PutPixel(round(rLine[1]), wheight - round(rLine[2] + 1), index);
  1384.             GetLineFromText(rLine, nValues);
  1385.         until nValues = 0;
  1386.         InitCursor;
  1387.     end;
  1388.  
  1389.  
  1390. {$IFC false}
  1391.  
  1392.     function GetWDInfo (wdRefNum: integer; var vRefNum: integer; var DirID, ProcID: LongInt): OSErr;
  1393. {Converts a working directory reference number into a volume reference number and directory ID. See TN 218.}
  1394.         var
  1395.             theWD: WDPBRec;
  1396.             err: OSErr;
  1397.     begin
  1398.         with theWD do begin
  1399.                 ioVRefNum := wdRefNum;
  1400.                 ioCompletion := nil;
  1401.                 ioWDIndex := 0;
  1402.                 ioWDProcID := 0;
  1403.                 ioWDVRefNum := 0;
  1404.                 err := PBGetWDInfo(@theWD, false);
  1405.                 if err = NoErr then begin
  1406.                         vRefNum := ioWDVRefNum;
  1407.                         DirID := ioWDDirID;
  1408.                     end;
  1409.             end; {with}
  1410.         GetWDInfo := err;
  1411.     end;
  1412.  
  1413.  
  1414.     procedure SaveDefaultWorkingDir (var settings: SettingsType);
  1415.         var
  1416.             DefaultVRefNum, err: integer;
  1417.             DefaultDirID: LongInt;
  1418.             ProcID: LongInt;
  1419.     begin
  1420.         with settings do begin
  1421.                 if DefaultRefNum <> 0 then begin
  1422.                         err := GetWDInfo(DefaultRefNum, DefaultVRefNum, DefaultDirID, ProcID);
  1423.                         if err = NoErr then begin
  1424.                                 sDefaultVRefNum := DefaultVRefNum;
  1425.                                 sDefaultDirID := DefaultDirID;
  1426.                             end
  1427.                         else
  1428.                             beep;
  1429.                     end;
  1430.        {ShowMessage(concat('KernelsRefNum=', long2str(KernelsRefNum), cr, 'vRefNum=', long2str(sKernelsVRefNum), cr, 'DirID=', long2str(sKernelsDirID)));}
  1431.             end; {with}
  1432.     end;
  1433.  
  1434.  
  1435.     procedure SaveKernelsWorkingDir (var settings: SettingsType);
  1436.         var
  1437.             KernelsVRefNum, err: integer;
  1438.             KernelsDirID: LongInt;
  1439.             ProcID: LongInt;
  1440.     begin
  1441.         with settings do begin
  1442.                 if KernelsRefNum <> 0 then begin
  1443.                         err := GetWDInfo(KernelsRefNum, KernelsVRefNum, KernelsDirID, ProcID);
  1444.                         if err = NoErr then begin
  1445.                                 sKernelsVRefNum := KernelsVRefNum;
  1446.                                 sKernelsDirID := KernelsDirID;
  1447.                             end
  1448.                         else
  1449.                             beep;
  1450.                     end;
  1451.       {ShowMessage(concat('KernelsRefNum=', long2str(KernelsRefNum), cr, 'vRefNum=', long2str(sKernelsVRefNum), cr, 'DirID=', long2str(sKernelsDirID)));}
  1452.             end; {with}
  1453.     end;
  1454. {$ENDC}
  1455.  
  1456.  
  1457.     procedure SaveSettings;
  1458.         var
  1459.             TheInfo: FInfo;
  1460.             ByteCount: LongInt;
  1461.             f, i: integer;
  1462.             err: OSErr;
  1463.             settings: SettingsType;
  1464.     begin
  1465.         with settings, info^ do begin
  1466.                 sID := 'IMAG';
  1467.                 sVersion := version;
  1468.                 sForegroundIndex := ForegroundIndex;
  1469.                 sBackgroundIndex := BackgroundIndex;
  1470.                 sBrushHeight := BrushHeight;
  1471.                 sBrushWidth := BrushWidth;
  1472.                 sAirbrushDiameter := AirbrushDiameter;
  1473.                 sLUTMode := LUTMode;
  1474.                 sOldColorStart := 30;
  1475.                 sOldColorWidth := 10;
  1476.                 sCurrentFontID := CurrentFontID;
  1477.                 sCurrentStyle := CurrentStyle;
  1478.                 sCurrentSize := CurrentSize;
  1479.                 sTextJust := TextJust;
  1480.                 sTextBack := TextBack;
  1481.                 sNExtraColors := nExtraColors;
  1482.                 sExtraColors := ExtraColors;
  1483.                 sInvertVideo := InvertVideo;
  1484.                 sMeasurements := Measurements;
  1485.                 sInvertPlots := InvertPlots;
  1486.                 sAutoScalePlots := AutoScalePlots;
  1487.                 sLinePlot := LinePlot;
  1488.                 sDrawPlotLabels := DrawPlotLabels;
  1489.                 for i := 1 to 12 do
  1490.                     sUnused1[i] := 0;
  1491.                 sFixedSizePlot := FixedSizePlot;
  1492.                 sProfilePlotWidth := ProfilePlotWidth;
  1493.                 sProfilePlotHeight := ProfilePlotHeight;
  1494.                 sFramesToAverage := FramesToAverage;
  1495.                 sNewPicWidth := NewPicWidth;
  1496.                 sNewPicHeight := NewPicHeight;
  1497.                 sBufferSize := BufferSize;
  1498.                 sMaxScionWidth := MaxScionWidth;
  1499.                 sThresholdToForeground := ThresholdToForeground;
  1500.                 sNonThresholdToBackground := NonThresholdToBackground;
  1501.                 sVideoChannel := VideoChannel;
  1502.                 sWhatToImport := WhatToImport;
  1503.                 sImportCustomWidth := ImportCustomWidth;
  1504.                 sImportCustomHeight := ImportCustomHeight;
  1505.                 sImportCustomOffset := ImportCustomOffset;
  1506.                 sWandAutoMeasure := WandAutoMeasure;
  1507.                 sWandAdjustAreas := WandAdjustAreas;
  1508.                 sBinaryIterations := BinaryIterations;
  1509.                 sScaleArithmetic := ScaleArithmetic;
  1510.                 sInvertPixelValues := InvertPixelValues;
  1511.                 sInvertYCoordinates := InvertYCoordinates;
  1512.                 sFieldWidth := FieldWidth;
  1513.                 sPrecision := precision;
  1514.                 sMinParticleSize := MinParticleSize;
  1515.                 sMaxParticleSize := MaxParticleSize;
  1516.                 sIgnoreParticlesTouchingEdge := IgnoreParticlesTouchingEdge;
  1517.                 sLabelParticles := LabelParticles;
  1518.                 sOutlineParticles := OutlineParticles;
  1519.                 sIncludeHoles := IncludeHoles;
  1520.                 sOscillatingMovies := OscillatingMovies;
  1521.                 sDriverHalftoning := DriverHalftoning;
  1522.                 sMaxRegions := MaxRegions;
  1523.                 sImportCustomDepth := ImportCustomDepth;
  1524.                 sImportSwapBytes := ImportSwapBytes;
  1525.                 sImportCalibrate := ImportCalibrate;
  1526.                 sImportAutoscale := ImportAutoscale;
  1527.                 for i := 1 to 12 do
  1528.                     sUnused2[i] := 0;
  1529.                 sShowHeadings := ShowHeadings;
  1530.                 sDefaultVRefNum := 0;
  1531.                 sDefaultDirID := 0;
  1532.                 sKernelsVRefNum := 0;
  1533.                 sKernelsDirID := 0;
  1534.         {***}
  1535.                 sProfilePlotMin := ProfilePlotMin;
  1536.                 sProfilePlotMax := ProfilePlotMax;
  1537.                 sImportMin := ImportMin;
  1538.                 sImportMax := ImportMax;
  1539.                 sHighlightPixels := HighlightSaturatedPixels;
  1540.         {***}
  1541.                 sBallRadius := BallRadius;
  1542.                 sFasterBackgroundSubtraction := FasterBackgroundSubtraction;
  1543.                 sScaleConvolutions := ScaleConvolutions;
  1544.         {V1.42}
  1545.                 sBinaryCount := BinaryCount;
  1546.                 sColorTable := ColorTable;
  1547.                 sColorStart := ColorStart;
  1548.                 sColorEnd := ColorEnd;
  1549.                 sInvertedTable := InvertedColorTable;
  1550.         {V1.44}
  1551.                 sHalftoneFrequency := HalftoneFrequency;
  1552.                 sHalftoneAngle := HalftoneAngle;
  1553.                 sHalftoneDotFunction := HalftoneDotFunction;
  1554.             end; {with}
  1555. {PBGetWDInfo seems to crash a lot, particularly under System 7. Does anyone know why?}
  1556. {SaveDefaultWorkingDir(settings);}
  1557. {SaveKernelsWorkingDir(settings);}
  1558.         err := GetFInfo(PrefsName, SystemRefNum, TheInfo);
  1559.         if err = FNFerr then begin
  1560.                 err := create(PrefsName, SystemRefNum, 'Imag', 'PREF');
  1561.                 if IOCheck(err) <> 0 then
  1562.                     exit(SaveSettings);
  1563.             end;
  1564.         err := fsopen(PrefsName, SystemRefNum, f);
  1565.         if IOCheck(err) <> 0 then
  1566.             exit(SaveSettings);
  1567.         err := SetFPos(f, FSFromStart, 0);
  1568.         ByteCount := SizeOf(settings);
  1569.         err := fswrite(f, ByteCount, @settings);
  1570.         if IOCheck(err) <> 0 then begin
  1571.                 err := fsclose(f);
  1572.                 exit(SaveSettings)
  1573.             end;
  1574.         err := SetEof(f, ByteCount);
  1575.         err := fsclose(f);
  1576.         err := FlushVol(nil, SystemRefNum);
  1577.     end;
  1578.  
  1579.  
  1580.     procedure ExportAsText (fname: str255; RefNum: integer);
  1581.         var
  1582.             err, f, width, hloc, vloc: integer;
  1583.             TheInfo: FInfo;
  1584.             ByteCount, FileSize: LongInt;
  1585.             AutoSelectAll: boolean;
  1586.             tLine: LineType;
  1587.     begin
  1588.         err := GetFInfo(fname, RefNum, TheInfo);
  1589.         case err of
  1590.             NoErr: 
  1591.                 if TheInfo.fdType <> 'TEXT' then begin
  1592.                         TypeMismatch(fname);
  1593.                         exit(ExportAsText)
  1594.                     end;
  1595.             FNFerr:  begin
  1596.                     err := create(fname, RefNum, 'XCEL', 'TEXT');
  1597.                     if IOCheck(err) <> 0 then
  1598.                         exit(ExportAsText);
  1599.                 end;
  1600.             otherwise
  1601.                 if IOCheck(err) <> 0 then
  1602.                     exit(ExportAsText)
  1603.         end;
  1604.         ShowWatch;
  1605.         err := fsopen(fname, RefNum, f);
  1606.         if IOCheck(err) <> 0 then
  1607.             exit(ExportAsText);
  1608.         AutoSelectAll := not info^.RoiShowing;
  1609.         if AutoSelectAll then
  1610.             SelectAll(true);
  1611.         if TooWide then
  1612.             exit(ExportAsText);
  1613.         FileSize := 0;
  1614.         with info^.RoiRect do begin
  1615.                 width := right - left;
  1616.                 for vloc := top to bottom - 1 do begin
  1617.                         GetLine(left, vloc, width, tLine);
  1618.                         TextBufSize := 0;
  1619.                         for hloc := 0 to width - 1 do begin
  1620.                                 PutLong(tLine[hloc], 0);
  1621.                                 if hloc <> (width - 1) then
  1622.                                     PutTab;
  1623.                             end;
  1624.                         PutChar(cr);
  1625.                         ByteCount := TextBufSize;
  1626.                         err := fswrite(f, ByteCount, ptr(TextBufP));
  1627.                         FIleSize := FileSize + ByteCount;
  1628.                         if (IOCheck(err) <> 0) or CommandPeriod then
  1629.                             leave;
  1630.                     end;
  1631.                 err := SetEof(f, FileSize);
  1632.                 err := fsclose(f);
  1633.                 err := FlushVol(nil, RefNum);
  1634.             end;
  1635.         if AutoSelectAll then
  1636.             KillRoi;
  1637.     end;
  1638.  
  1639.  
  1640.     procedure ExportCoordinates (fname: str255; RefNum: integer);
  1641.         var
  1642.             err, f, i, y: integer;
  1643.             TheInfo: FInfo;
  1644.             ByteCount, FileSize: LongInt;
  1645.             InvertY: boolean;
  1646.     begin
  1647.         if nCoordinates <= 0 then begin
  1648.                 PutMessage('No coordinates available. First use the polygon, freehand, line or wand tool to create an outline.');
  1649.                 exit(ExportCoordinates)
  1650.             end;
  1651.         err := GetFInfo(fname, RefNum, TheInfo);
  1652.         case err of
  1653.             NoErr: 
  1654.                 if TheInfo.fdType <> 'TEXT' then begin
  1655.                         TypeMismatch(fname);
  1656.                         exit(ExportCoordinates)
  1657.                     end;
  1658.             FNFerr:  begin
  1659.                     err := create(fname, RefNum, 'MSWD', 'TEXT');
  1660.                     if IOCheck(err) <> 0 then
  1661.                         exit(ExportCoordinates);
  1662.                 end;
  1663.             otherwise
  1664.                 if IOCheck(err) <> 0 then
  1665.                     exit(ExportCoordinates)
  1666.         end;
  1667.         ShowWatch;
  1668.         err := fsopen(fname, RefNum, f);
  1669.         if IOCheck(err) <> 0 then
  1670.             exit(ExportCoordinates);
  1671.         FileSize := 0;
  1672.         InvertY := InvertYCoordinates and (Info <> NoInfo);
  1673.         with info^ do
  1674.             for i := 1 to nCoordinates do begin
  1675.                     TextBufSize := 0;
  1676.                     PutLong(xCoordinates^[i], 0);
  1677.                     PutTab;
  1678.                     y := yCoordinates^[i];
  1679.                     if InvertY then
  1680.                         y := PicRect.bottom - y - 1;
  1681.                     PutLong(y, 0);
  1682.                     PutChar(cr);
  1683.                     ByteCount := TextBufSize;
  1684.                     err := fswrite(f, ByteCount, ptr(TextBufP));
  1685.                     FIleSize := FileSize + ByteCount;
  1686.                     if (IOCheck(err) <> 0) or CommandPeriod then
  1687.                         leave;
  1688.                 end;
  1689.         err := SetEof(f, FileSize);
  1690.         err := fsclose(f);
  1691.         err := FlushVol(nil, RefNum);
  1692.     end;
  1693.  
  1694.  
  1695.     procedure ExportMeasurements (fname: str255; RefNum: integer);
  1696.         const
  1697.             LinesPerPass = 25;
  1698.         var
  1699.             err, f, i, first, last: integer;
  1700.             TheInfo: FInfo;
  1701.             ByteCount, FileSize: LongInt;
  1702.     begin
  1703.         err := GetFInfo(fname, RefNum, TheInfo);
  1704.         case err of
  1705.             NoErr: 
  1706.                 if TheInfo.fdType <> 'TEXT' then begin
  1707.                         TypeMismatch(fname);
  1708.                         exit(ExportMeasurements)
  1709.                     end;
  1710.             FNFerr:  begin
  1711.                     err := create(fname, RefNum, 'XCEL', 'TEXT');
  1712.                     if IOCheck(err) <> 0 then
  1713.                         exit(ExportMeasurements);
  1714.                 end;
  1715.             otherwise
  1716.                 if IOCheck(err) <> 0 then
  1717.                     exit(ExportMeasurements)
  1718.         end;
  1719.         ShowWatch;
  1720.         err := fsopen(fname, RefNum, f);
  1721.         if IOCheck(err) <> 0 then
  1722.             exit(ExportMeasurements);
  1723.         FileSize := 0;
  1724.         first := 1;
  1725.         last := LinesPerPass;
  1726.         repeat
  1727.             if last > mCount then
  1728.                 last := mCount;
  1729.             CopyResultsToBuffer(first, last, ShowHeadings or OptionKeyWasDown);
  1730.             ByteCount := TextBufSize;
  1731.             err := fswrite(f, ByteCount, ptr(TextBufP));
  1732.             FIleSize := FileSize + ByteCount;
  1733.             if (IOCheck(err) <> 0) or CommandPeriod or (last = mCount) then
  1734.                 leave;
  1735.             first := first + LinesPerPass;
  1736.             last := last + LinesPerPass;
  1737.         until false;
  1738.         err := SetEof(f, FileSize);
  1739.         err := fsclose(f);
  1740.         err := FlushVol(nil, RefNum);
  1741.         UnsavedResults := false;
  1742.     end;
  1743.  
  1744.  
  1745.     procedure Swap2Bytes (var i: integer);
  1746.         type
  1747.             atype = packed array[1..2] of char;
  1748.         var
  1749.             a: atype;
  1750.             c: char;
  1751.     begin
  1752.         a := atype(i);
  1753.         c := a[1];
  1754.         a[1] := a[2];
  1755.         a[2] := c;
  1756.         i := integer(a)
  1757.     end;
  1758.  
  1759.  
  1760.     procedure Swap4Bytes (var i: LongInt);
  1761.         var
  1762.             a: ostype;
  1763.             c: char;
  1764.     begin
  1765.         a := ostype(i);
  1766.         c := a[1];
  1767.         a[1] := a[4];
  1768.         a[4] := c;
  1769.         c := a[2];
  1770.         a[2] := a[3];
  1771.         a[3] := c;
  1772.         i := LongInt(a)
  1773.     end;
  1774.  
  1775.  
  1776.     function OpenTiffHeader (f: integer; var DirOffset: LongInt): boolean;
  1777.         var
  1778.             TiffHeader: TiffHdr;
  1779.             ByteCount: LongInt;
  1780.             err: OSErr;
  1781.     begin
  1782.         ByteCount := 8;
  1783.         err := SetFPos(f, fsFromStart, 0);
  1784.         err := fsread(f, ByteCount, @TiffHeader);
  1785.         if IOCheck(err) <> NoErr then begin
  1786.                 OpenTiffHeader := false;
  1787.                 exit(OpenTiffHeader);
  1788.             end;
  1789.         with TiffHeader do begin
  1790.                 IntelByteOrder := ByteOrder = 'II';
  1791.                 if (ByteOrder <> 'MM') and (ByteOrder <> 'II') then begin
  1792.                         PutMessage('Invalid TIFF header.');
  1793.                         OpenTiffHeader := false;
  1794.                         exit(OpenTiffHeader)
  1795.                     end;
  1796.                 DirOffset := FirstIFDOffset;
  1797.                 if IntelByteOrder then
  1798.                     Swap4Bytes(DirOffset);
  1799.                 OpenTiffHeader := true;
  1800.             end;
  1801.     end;
  1802.  
  1803.  
  1804.     procedure GetTiffEntry (f: integer; var tag: integer; var N, value: LongInt);
  1805.         var
  1806.             IFDEntry: TiffEntry;
  1807.             ByteCount: LongInt;
  1808.             IntValue: integer;
  1809.             err: OSErr;
  1810.             str: str255;
  1811.     begin
  1812.         ByteCount := 12;
  1813.         err := FSRead(f, ByteCount, @IFDEntry);
  1814.         with IFDEntry do begin
  1815.                 tag := TagField;
  1816.                 N := length;
  1817.                 if IntelByteOrder then begin
  1818.                         Swap2Bytes(tag);
  1819.                         Swap4Bytes(N);
  1820.                     end;
  1821.                 value := offset;
  1822.                 if (ftype = short) and (N = 1) then begin
  1823.                         value := bsr(value, 16);
  1824.                         if IntelByteOrder then begin
  1825.                                 IntValue := value;
  1826.                                 Swap2Bytes(IntValue);
  1827.                                 value := IntValue
  1828.                             end
  1829.                     end
  1830.                 else if IntelByteOrder then
  1831.                     Swap4Bytes(value);
  1832.                 if OptionKeyWasDown then begin
  1833.                         gstr := concat(gstr, long2str(tag), '  ', long2str(ftype), '  ', long2str(N), '  ', long2str(value), cr);
  1834.                         ShowMessage(gstr);
  1835.                     end;
  1836.             end;
  1837.     end;
  1838.  
  1839.  
  1840.     function OpenTiffDirectory (f: integer; DirOffset: LongInt; var TiffInfo: TiffInfoRec): boolean;
  1841.         const
  1842.             NoUnit = 1;
  1843.             inch = 2;
  1844.             centimeter = 3;
  1845.         var
  1846.             ByteCount, length, ftype, N, value, PixelsPerStrip, SaveFPos: LongInt;
  1847.             err: OSErr;
  1848.             nEntries, i, tag, entry: integer;
  1849.             StripOffsetsArray: array[1..2] of LongInt;
  1850.             xRes, yRes: extended;
  1851.  
  1852.         function GetResolution: extended;
  1853.             var
  1854.                 resolution: array[1..2] of LongInt;
  1855.         begin
  1856.             err := GetFPos(f, SaveFPos);
  1857.             err := SetFPos(f, fsFromStart, value);
  1858.             ByteCount := 8;
  1859.             err := fsread(f, ByteCount, @Resolution);
  1860.             if IntelByteOrder then begin
  1861.                     Swap4Bytes(Resolution[1]);
  1862.                     Swap4Bytes(Resolution[2]);
  1863.                 end;
  1864.             err := SetFPos(f, fsFromStart, SaveFPos);
  1865.             if resolution[2] <> 0 then
  1866.                 GetResolution := resolution[1] / resolution[2]
  1867.             else
  1868.                 GetResolution := 0.0;
  1869.         end;
  1870.  
  1871.     begin
  1872.         if OptionKeyWasDown then
  1873.             gstr := '';
  1874.         xRes := 0.0;
  1875.         err := SetFPos(f, fsFromStart, DirOffset);
  1876.         ByteCount := 2;
  1877.         err := FSRead(f, ByteCount, @nEntries);
  1878.         if IOCheck(err) <> NoErr then begin
  1879.                 OpenTiffDirectory := false;
  1880.                 exit(OpenTiffDirectory);
  1881.             end;
  1882.         if IntelByteOrder then
  1883.             Swap2Bytes(nEntries);
  1884.         with TiffInfo do begin
  1885.                 width := 0;
  1886.                 height := 0;
  1887.                 OffsetToData := 0;
  1888.                 Resolution := 0.0;
  1889.                 ResUnits := tNoUnits;
  1890.                 OffsetToColorMap := 0;
  1891.                 OffsetToImageHeader := -1;
  1892.                 for entry := 1 to nEntries do begin
  1893.                         GetTiffEntry(f, tag, N, value);
  1894.                         if tag = 0 then begin
  1895.                                 PutMessage('Invalid TIFF format.');
  1896.                                 OpenTiffDirectory := false;
  1897.                                 exit(OpenTiffDirectory)
  1898.                             end;
  1899.                         case tag of
  1900.                             ImageWidth: 
  1901.                                 width := value;
  1902.                             ImageLength: 
  1903.                                 height := value;
  1904.                             BitsPerSample:  begin
  1905.                                     BitsPerPixel := value;
  1906.                                     if value = 1 then begin
  1907.                                             PutMessage('Image cannot open 1-bit TIFF files.');
  1908.                                             OpenTiffDirectory := false;
  1909.                                             exit(OpenTiffDirectory)
  1910.                                         end;
  1911.                                 end;
  1912.                             SamplesPerPixel: 
  1913.                                 if value > 1 then begin
  1914.                                         PutMessage('Image cannot open 24-bit files.');
  1915.                                         OpenTiffDirectory := false;
  1916.                                         exit(OpenTiffDirectory)
  1917.                                     end;
  1918.                             Compression: 
  1919.                                 if value <> 1 then begin
  1920.                                         PutMessage('Image cannot open compressed TIFF files.');
  1921.                                         OpenTiffDirectory := false;
  1922.                                         exit(OpenTiffDirectory)
  1923.                                     end;
  1924.                             PhotoInterp: 
  1925.                                 ZeroIsBlack := value = 1;
  1926.                             StripOffsets: 
  1927.                                 if N = 1 then
  1928.                                     OffsetToData := value
  1929.                                 else begin
  1930.                                         err := GetFPos(f, SaveFPos);
  1931.                                         err := SetFPos(f, fsFromStart, value);
  1932.                                         ByteCount := 8;
  1933.                                         err := fsread(f, ByteCount, @StripOffsetsArray);
  1934.                                         if IntelByteOrder then begin
  1935.                                                 Swap4Bytes(StripOffsetsArray[1]);
  1936.                                                 Swap4Bytes(StripOffsetsArray[2]);
  1937.                                             end;
  1938.                                         err := SetFPos(f, fsFromStart, SaveFPos);
  1939.                                     end;
  1940.                             RowsPerStrip: 
  1941.                                 if value < height then begin
  1942.                                         PixelsPerStrip := value * width;
  1943.                                         if StripOffsetsArray[2] <> (StripOffsetsArray[1] + PixelsPerStrip) then begin
  1944.                                                 PutMessage('Image cannot open TIFF files with discontiguous strips.');
  1945.                                                 OpenTiffDirectory := false;
  1946.                                                 exit(OpenTiffDirectory)
  1947.                                             end;
  1948.                                         OffsetToData := StripOffsetsArray[1];
  1949.                                     end;
  1950.                             XResolution: 
  1951.                                 XRes := GetResolution;
  1952.                             YResolution:  begin
  1953.                                     yRes := GetResolution;
  1954.                                     if (xRes = yRes) and (xRes > 0.0) then begin
  1955.                                             resolution := xRes;
  1956.                                             ResUnits := tInches;
  1957.                                         end;
  1958.                                 end;
  1959.                             ResolutionUnit: 
  1960.                                 case value of
  1961.                                     NoUnit: 
  1962.                                         ResUnits := tNoUnits;
  1963.                                     Centimeter: 
  1964.                                         ResUnits := tCentimeters;
  1965.                                     otherwise
  1966.                                 end;
  1967.                             ColorMapTag: 
  1968.                                 if N = 768 then
  1969.                                     OffsetToColorMap := value;
  1970.                             ImageHdrTag: 
  1971.                                 OffsetToImageHeader := value;
  1972.                             otherwise
  1973.                         end;
  1974.                     end; {for}
  1975.                 ByteCount := 4;
  1976.                 err := FSRead(f, ByteCount, @NextIFD);
  1977.                 if IntelByteOrder then
  1978.                     Swap4Bytes(NextIFD);
  1979.                 if OptionKeyWasDown then begin
  1980.                         gstr := concat(gstr, 'Next IFD=', long2str(NextIFD));
  1981.                         ShowMessage(gstr);
  1982.                     end;
  1983.                 if width = 0 then begin
  1984.                         PutMessage('Error opening TIFF directory');
  1985.                         OpenTiffDirectory := false;
  1986.                         exit(OpenTiffDirectory)
  1987.                     end;
  1988.             end; {with}
  1989.         OpenTiffDirectory := true;
  1990.     end;
  1991.  
  1992.  
  1993.     procedure SaveTiffColorMap (f: integer; ImageDataSize: LongInt);
  1994.         var
  1995.             i: integer;
  1996.             err: OSErr;
  1997.             ColorMap: TiffColorMapType;
  1998.             ColorMapSize: LongInt;
  1999.     begin
  2000.         LoadLUT(info^.cTable);
  2001.         for i := 0 to 255 do
  2002.             with cScreenPort^.portPixMap^^.pmTable^^.ctTable[i].rgb do begin
  2003.                     ColorMap[1, i] := red;
  2004.                     ColorMap[2, i] := green;
  2005.                     ColorMap[3, i] := blue;
  2006.                 end;
  2007.         err := SetFPos(f, FSFromStart, HeaderSize + TiffDirSize + ImageDataSize);
  2008.         ColorMapSize := SizeOf(ColorMap);
  2009.         err := fswrite(f, ColorMapSize, @ColorMap);
  2010.         if IOCheck(err) <> 0 then
  2011.             beep;
  2012.     end;
  2013.  
  2014.  
  2015.     procedure GetTiffColorMap (f: integer);
  2016.         var
  2017.             i: integer;
  2018.             ByteCount: LongInt;
  2019.             err: OSErr;
  2020.             ColorMap: TiffColorMapType;
  2021.     begin
  2022.         with info^ do begin
  2023.                 ByteCount := SizeOf(ColorMap);
  2024.                 err := SetFPos(f, fsFromStart, ColorMapOffset);
  2025.                 err := fsRead(f, ByteCount, @ColorMap);
  2026.                 if err = NoErr then begin
  2027.                         if IntelByteOrder then
  2028.                             for i := 0 to 255 do begin
  2029.                                     Swap2Bytes(ColorMap[1, i]);
  2030.                                     Swap2Bytes(ColorMap[2, i]);
  2031.                                     Swap2Bytes(ColorMap[3, i]);
  2032.                                 end;
  2033.                         for i := 0 to 255 do
  2034.                             with cTable[i].rgb do begin
  2035.                                     red := ColorMap[1, i];
  2036.                                     green := ColorMap[2, i];
  2037.                                     blue := ColorMap[3, i];
  2038.                                 end;
  2039.                         LoadLUT(cTable);
  2040.                         LUTMode := ColorLut;
  2041.                         SetupPseudocolor;
  2042.                         IdentityFunction := false;
  2043.                         if isGrayScaleLUT then begin
  2044.                                 info^.LutMode := CustomGrayScale;
  2045.                                 DrawMap;
  2046.                             end;
  2047.                     end
  2048.                 else
  2049.                     beep;
  2050.             end;{with}
  2051.     end;
  2052.  
  2053.  
  2054.     function SaveTiffDir (f, slines, sPixelsPerLine: integer; SavingSelection: boolean; ctabSize, ImageDataSize: LongInt): OSErr;
  2055.         var
  2056.             i: integer;
  2057.             err: OSErr;
  2058.             ByteCount, width, height: LongInt;
  2059.             TiffInfo1: record
  2060.                     Header: TiffHdr;   {8}
  2061.                     nEntries: integer; {2}
  2062.                     TiffDir: array[1..8] of TiffEntry; {96}
  2063.                 end;
  2064.             ColorMapEntry: TiffEntry;  {12(Optional)}
  2065.             TiffInfo2: record
  2066.                     ImageHdrEntry: TiffEntry;  {12}
  2067.                     NextIFD: LongInt;  {4}
  2068.                     filler: array[1..TiffFillerSize] of integer; {134}
  2069.                 end;
  2070.     begin
  2071.         with info^ do begin
  2072.                 if SavingSelection then begin
  2073.                         width := sPixelsPerLine;
  2074.                         height := sLines
  2075.                     end
  2076.                 else begin
  2077.                         width := PixelsPerLine;
  2078.                         height := nLines
  2079.                     end;
  2080.                 with TiffInfo1 do begin
  2081.                         with header do begin
  2082.                                 ByteOrder := 'MM';
  2083.                                 Version := 42;
  2084.                                 FirstIFDOffset := 8;
  2085.                             end;
  2086.                         if ctabSize > 0 then
  2087.                             nEntries := 10
  2088.                         else
  2089.                             nEntries := 9;
  2090.                         for i := 1 to 8 do
  2091.                             with TiffDir[i] do begin
  2092.                                     ftype := 3;
  2093.                                     length := 1
  2094.                                 end;
  2095.                         with TiffDir[1] do begin
  2096.                                 TagField := NewSubfileType;
  2097.                                 ftype := 4;
  2098.                                 offset := 0;
  2099.                             end;
  2100.                         with TiffDir[2] do begin
  2101.                                 TagField := ImageWidth;
  2102.                                 offset := bsl(width, 16);
  2103.                             end;
  2104.                         with TiffDir[3] do begin
  2105.                                 TagField := ImageLength;
  2106.                                 offset := bsl(height, 16);
  2107.                             end;
  2108.                         with TiffDir[4] do begin
  2109.                                 TagField := BitsPerSample;
  2110.                                 offset := bsl(8, 16);
  2111.                             end;
  2112.                         with TiffDir[5] do begin
  2113.                                 TagField := PhotoInterp;
  2114.                                 if ctabSize > 0 then
  2115.                                     offset := bsl(3, 16)
  2116.                                 else
  2117.                                     offset := 0;
  2118.                             end;
  2119.                         with TiffDir[6] do begin
  2120.                                 TagField := StripOffsets;
  2121.                                 ftype := 4;
  2122.                                 offset := TiffDirSize + HeaderSize;
  2123.                             end;
  2124.                         with TiffDir[7] do begin
  2125.                                 TagField := RowsPerStrip;
  2126.                                 offset := bsl(height, 16);
  2127.                             end;
  2128.                         with TiffDir[8] do begin
  2129.                                 TagField := StripByteCount;
  2130.                                 ftype := 4;
  2131.                                 offset := width * height;
  2132.                             end;
  2133.                     end;
  2134.                 ByteCount := SizeOf(TiffInfo1);
  2135.                 err := SetFPos(f, FSFromStart, 0);
  2136.                 err := FSWrite(f, ByteCount, @TiffInfo1);
  2137.                 if IOCheck(err) <> NoErr then begin
  2138.                         SaveTiffDir := err;
  2139.                         exit(SaveTiffDir);
  2140.                     end;
  2141.                 if ctabSize > 0 then
  2142.                     with ColorMapEntry do begin
  2143.                             TagField := ColorMapTag;
  2144.                             ftype := 3;
  2145.                             length := 768;
  2146.                             offset := HeaderSize + TiffDirSize + ImageDataSize;
  2147.                             ByteCount := SizeOf(ColorMapEntry);
  2148.                             err := FSWrite(f, ByteCount, @ColorMapEntry);
  2149.                             if IOCheck(err) <> NoErr then begin
  2150.                                     SaveTiffDir := err;
  2151.                                     exit(SaveTiffDir);
  2152.                                 end;
  2153.                         end;
  2154.                 with TiffInfo2 do begin
  2155.                         with ImageHdrEntry do begin
  2156.                                 TagField := ImageHdrTag;
  2157.                                 ftype := 3;
  2158.                                 length := 256;
  2159.                                 offset := TiffDirSize;
  2160.                             end;
  2161.                         NextIFD := 0;
  2162.                         if StackInfo <> nil then
  2163.                             if StackInfo^.nSlices > 1 then
  2164.                                 NextIFD := HeaderSize + TiffDirSize + ImageDataSize + ctabSize;
  2165.                         for i := 1 to TiffFillerSize do
  2166.                             filler[i] := 0;
  2167.                     end;
  2168.             end;
  2169.         ByteCount := SizeOf(TiffInfo2);
  2170.         err := FSWrite(f, ByteCount, @TiffInfo2);
  2171.         SaveTiffDir := IOCheck(err);
  2172.     end;
  2173.  
  2174.  
  2175.     function WriteExtraTiffIFDs (f: integer; ImageDataSize, cTabSize: LongInt): integer;
  2176.         var
  2177.             IFD, entry: integer;
  2178.             StackIFD: StackIFDType;
  2179.             err: OSErr;
  2180.             IFDoffset, SliceOffset, ByteCount: LongInt;
  2181.     begin
  2182.         with info^, StackInfo^, StackIFD do begin
  2183.                 IFDoffset := HeaderSize + TiffDirSize + ImageDataSize + ctabSize;
  2184.                 err := SetFPos(f, FSFromStart, IFDoffset);
  2185.                 SliceOffset := HeaderSize + TiffDirSize + ImageSize;
  2186.                 for IFD := 2 to nSlices do  {IFD=Image File Directory}
  2187.                     begin
  2188.                         nEntries := 6;
  2189.                         for entry := 1 to nEntries do
  2190.                             with TiffDir[entry] do begin
  2191.                                     ftype := 3;
  2192.                                     length := 1
  2193.                                 end;
  2194.                         with TiffDir[1] do begin
  2195.                                 TagField := NewSubfileType;
  2196.                                 ftype := 4;
  2197.                                 offset := 0;
  2198.                             end;
  2199.                         with TiffDir[2] do begin
  2200.                                 TagField := ImageWidth;
  2201.                                 offset := bsl(PixelsPerLine, 16);
  2202.                             end;
  2203.                         with TiffDir[3] do begin
  2204.                                 TagField := ImageLength;
  2205.                                 offset := bsl(nLines, 16);
  2206.                             end;
  2207.                         with TiffDir[4] do begin
  2208.                                 TagField := BitsPerSample;
  2209.                                 offset := bsl(8, 16);
  2210.                             end;
  2211.                         with TiffDir[5] do begin
  2212.                                 TagField := PhotoInterp;
  2213.                                 offset := 0;
  2214.                             end;
  2215.                         with TiffDir[6] do begin
  2216.                                 TagField := StripOffsets;
  2217.                                 ftype := 4;
  2218.                                 offset := SliceOffset;
  2219.                             end;
  2220.                         SliceOffset := SliceOffset + ImageSize;
  2221.                         IFDoffset := IFDoffset + SizeOf(StackIFD);
  2222.                         if IFD <> nSlices then
  2223.                             NextIFD := IFDoffset
  2224.                         else
  2225.                             NextIFD := 0;
  2226.                         ByteCount := SizeOf(StackIFD);
  2227.                         err := fswrite(f, ByteCount, @StackIFD);
  2228.                         if err <> NoErr then begin
  2229.                                 WriteExtraTiffIFDs := err;
  2230.                                 exit(WriteExtraTiffIFDs);
  2231.                             end;
  2232.                     end; {for}
  2233.             end; {with}
  2234.         WriteExtraTiffIFDs := NoErr;
  2235.     end;
  2236.  
  2237.  
  2238.     procedure SaveLUT (fname: str255; RefNum: integer);
  2239.         var
  2240.             err: integer;
  2241.             TheInfo: FInfo;
  2242.             LUT: array[1..3] of packed array[0..255] of byte;
  2243.             i, f: integer;
  2244.             ByteCount: LongInt;
  2245.     begin
  2246.         err := GetFInfo(fname, RefNum, TheInfo);
  2247.         case err of
  2248.             NoErr: 
  2249.                 if TheInfo.fdType <> 'ICOL' then begin
  2250.                         TypeMismatch(fname);
  2251.                         exit(SaveLUT)
  2252.                     end;
  2253.             FNFerr:  begin
  2254.                     err := create(fname, RefNum, 'Imag', 'ICOL');
  2255.                     if IOCheck(err) <> 0 then
  2256.                         exit(SaveLUT);
  2257.                 end;
  2258.             otherwise
  2259.                 if IOCheck(err) <> 0 then
  2260.                     exit(SaveLUT);
  2261.         end;
  2262.         DisableDensitySlice;
  2263.         LoadLUT(Info^.cTable);
  2264.         for i := 0 to 255 do
  2265.             with cScreenPort^.portPixMap^^.pmTable^^.ctTable[i].rgb do begin
  2266.                     LUT[1, i] := band(bsr(red, 8), 255);
  2267.                     LUT[2, i] := band(bsr(green, 8), 255);
  2268.                     LUT[3, i] := band(bsr(blue, 8), 255);
  2269.                 end;
  2270.         err := fsopen(fname, RefNum, f);
  2271.         if IOCheck(err) <> 0 then
  2272.             exit(SaveLUT);
  2273.         err := SetFPos(f, FSFromStart, 0);
  2274.         ByteCount := SizeOf(LUT);
  2275.         err := fswrite(f, ByteCount, @LUT);
  2276.         if IOCheck(err) <> 0 then begin
  2277.                 err := fsclose(f);
  2278.                 err := FSDelete(fname, RefNum);
  2279.                 exit(SaveLUT)
  2280.             end;
  2281.         err := SetEof(f, ByteCount);
  2282.         err := fsclose(f);
  2283.         err := GetFInfo(fname, RefNum, TheInfo);
  2284.         if TheInfo.fdCreator <> 'Imag' then begin
  2285.                 TheInfo.fdCreator := 'Imag';
  2286.                 err := SetFInfo(fname, RefNum, TheInfo);
  2287.             end;
  2288.         err := FlushVol(nil, RefNum);
  2289.     end;
  2290.  
  2291.  
  2292.     procedure SaveColorTable (fname: str255; RefNum: integer);
  2293.         var
  2294.             err: integer;
  2295.             TheInfo: FInfo;
  2296.             i, f: integer;
  2297.             ByteCount: LongInt;
  2298.             hdr: PaletteHeader;
  2299.     begin
  2300.         with info^ do
  2301.             err := GetFInfo(fname, RefNum, TheInfo);
  2302.         case err of
  2303.             NoErr: 
  2304.                 if TheInfo.fdType <> 'ICOL' then begin
  2305.                         TypeMismatch(fname);
  2306.                         exit(SaveColorTable)
  2307.                     end;
  2308.             FNFerr:  begin
  2309.                     err := create(fname, RefNum, 'Imag', 'ICOL');
  2310.                     if IOCheck(err) <> 0 then
  2311.                         exit(SaveColorTable);
  2312.                 end;
  2313.             otherwise
  2314.                 if IOCheck(err) <> 0 then
  2315.                     exit(SaveColorTable);
  2316.         end;
  2317.         with info^ do begin
  2318.                 InitPaletteHeader(hdr);
  2319.                 err := fsopen(fname, RefNum, f);
  2320.                 if IOCheck(err) <> 0 then
  2321.                     exit(SaveColorTable);
  2322.                 err := SetFPos(f, FSFromStart, 0);
  2323.                 ByteCount := SizeOf(PaletteHeader);
  2324.                 if ByteCount <> 32 then
  2325.                     PutMessage('Palette header size <> 32.');
  2326.                 err := fswrite(f, ByteCount, @hdr);
  2327.                 ByteCount := nColors;
  2328.                 err := fswrite(f, ByteCount, @redLUT);
  2329.                 ByteCount := nColors;
  2330.                 err := fswrite(f, ByteCount, @greenLUT);
  2331.                 ByteCount := nColors;
  2332.                 err := fswrite(f, ByteCount, @blueLUT);
  2333.                 if IOCheck(err) <> 0 then begin
  2334.                         err := fsclose(f);
  2335.                         err := FSDelete(fname, RefNum);
  2336.                         exit(SaveColorTable)
  2337.                     end;
  2338.                 err := SetEOF(f, SizeOf(PaletteHeader) + 3 * nColors);
  2339.                 err := fsclose(f);
  2340.                 err := GetFInfo(fname, RefNum, TheInfo);
  2341.                 if TheInfo.fdCreator <> 'Imag' then begin
  2342.                         TheInfo.fdCreator := 'Imag';
  2343.                         err := SetFInfo(fname, RefNum, TheInfo);
  2344.                     end;
  2345.                 err := FlushVol(nil, RefNum);
  2346.             end; {with info^}
  2347.     end;
  2348.  
  2349.  
  2350.     procedure SaveOutline (fname: str255; RefNum: integer);
  2351.         var
  2352.             err: integer;
  2353.             TheInfo: FInfo;
  2354.             i, f: integer;
  2355.             ByteCount, DataSize: LongInt;
  2356.             hdr: RoiHeader;
  2357.             SaveCoordinates: boolean;
  2358.     begin
  2359.         with info^ do begin
  2360.                 if not RoiShowing then begin
  2361.                         PutMessage('No outline available to save.');
  2362.                         exit(SaveOutline);
  2363.                     end;
  2364.                 SaveCoordinates := (RoiType = RgnRoi) or (RoiType = FreeLineRoi) or (RoiType = SegLineRoi);
  2365.                 if SaveCoordinates and (nCoordinates = 0) then begin
  2366.                         PutMessage('Coordinates for this outline not available.');
  2367.                         exit(SaveOutline);
  2368.                     end;
  2369.                 err := GetFInfo(fname, RefNum, TheInfo);
  2370.                 case err of
  2371.                     NoErr: 
  2372.                         if TheInfo.fdType <> 'Iout' then begin
  2373.                                 TypeMismatch(fname);
  2374.                                 exit(SaveOutline)
  2375.                             end;
  2376.                     FNFerr:  begin
  2377.                             err := create(fname, RefNum, 'Imag', 'Iout');
  2378.                             if IOCheck(err) <> 0 then
  2379.                                 exit(SaveOutline);
  2380.                         end;
  2381.                     otherwise
  2382.                         if IOCheck(err) <> 0 then
  2383.                             exit(SaveOutline);
  2384.                 end;
  2385.                 with hdr do begin
  2386.                         rID := 'Iout';
  2387.                         rVersion := version;
  2388.                         rRoiType := RoiType;
  2389.                         rRoiRect := RoiRect;
  2390.                         rNCoordinates := nCoordinates;
  2391.                         GetLoi(rX1, rY1, rX2, rY2);
  2392.                         rLineWidth := LineWidth;
  2393.                         for i := 1 to 14 do
  2394.                             rUnused[i] := 0;
  2395.                     end;
  2396.                 err := fsopen(fname, RefNum, f);
  2397.                 if IOCheck(err) <> 0 then
  2398.                     exit(SaveOutline);
  2399.                 err := SetFPos(f, FSFromStart, 0);
  2400.                 ByteCount := SizeOf(RoiHeader);
  2401.                 if ByteCount <> 64 then
  2402.                     PutMessage('Roi header size <> 32.');
  2403.                 err := fswrite(f, ByteCount, @hdr);
  2404.                 if SaveCoordinates then begin
  2405.                         ByteCount := nCoordinates * 2;
  2406.                         err := fswrite(f, ByteCount, ptr(xCoordinates));
  2407.                         ByteCount := nCoordinates * 2;
  2408.                         err := fswrite(f, ByteCount, ptr(yCoordinates));
  2409.                         DataSize := nCoordinates * 4;
  2410.                     end
  2411.                 else
  2412.                     DataSize := 0;
  2413.                 if IOCheck(err) <> 0 then begin
  2414.                         err := fsclose(f);
  2415.                         err := FSDelete(fname, RefNum);
  2416.                         exit(SaveOutline)
  2417.                     end;
  2418.                 err := SetEOF(f, SizeOf(RoiHeader) + DataSize);
  2419.                 err := fsclose(f);
  2420.                 err := GetFInfo(fname, RefNum, TheInfo);
  2421.                 if TheInfo.fdCreator <> 'Imag' then begin
  2422.                         TheInfo.fdCreator := 'Imag';
  2423.                         err := SetFInfo(fname, RefNum, TheInfo);
  2424.                     end;
  2425.                 err := FlushVol(nil, RefNum);
  2426.             end; {with info^}
  2427.     end;
  2428.  
  2429.  
  2430.     procedure OpenOutline (fname: str255; RefNum: integer);
  2431.         var
  2432.             err, f: integer;
  2433.             count: LongInt;
  2434.             hdr: RoiHeader;
  2435.             okay: boolean;
  2436.     begin
  2437.         if Info = NoInfo then begin
  2438.                 if (LongInt(NewPicWidth) * NewPicHeight) <= UndoBufSize then begin
  2439.                         if not NewPicWindow('Untitled', NewPicWidth, NewPicHeight) then
  2440.                             exit(OpenOutline)
  2441.                     end
  2442.                 else begin
  2443.                         beep;
  2444.                         exit(OpenOutline)
  2445.                     end;
  2446.             end;
  2447.         KillRoi;
  2448.         err := fsopen(fname, RefNum, f);
  2449.         with info^, hdr do begin
  2450.                 count := SizeOf(RoiHeader);
  2451.                 err := fsread(f, count, @hdr);
  2452.                 if rID <> 'Iout' then begin
  2453.                         err := fsclose(f);
  2454.                         PutMessage('File is corrupted.');
  2455.                         exit(OpenOutline)
  2456.                     end;
  2457.                 if (rRoiRect.right > PicRect.right) or (rRoiRect.bottom > PicRect.bottom) then begin
  2458.                         err := fsclose(f);
  2459.                         PutMessage('Image is too small for the outline.');
  2460.                         exit(OpenOutline)
  2461.                     end;
  2462.                 case rRoiType of
  2463.                     LineRoi:  begin
  2464.                             LX1 := rX1;
  2465.                             LY1 := rY1;
  2466.                             LX2 := rX2;
  2467.                             LY2 := rY2;
  2468.                             RoiType := LineRoi;
  2469.                             MakeRegion;
  2470.                             SetupUndo;
  2471.                             RoiShowing := true;
  2472.                         end;
  2473.                     RectRoi, OvalRoi:  begin
  2474.                             RoiType := rRoiType;
  2475.                             RoiRect := rRoiRect;
  2476.                             MakeRegion;
  2477.                             SetupUndo;
  2478.                             RoiShowing := true;
  2479.                         end;
  2480.                     RgnRoi: 
  2481.                         if (rNCoordinates > 2) and (rNCoordinates <= MaxCoordinates) then begin
  2482.                                 count := rNCoordinates * 2;
  2483.                                 err := fsread(f, count, ptr(xCoordinates));
  2484.                                 count := rNCoordinates * 2;
  2485.                                 err := fsread(f, count, ptr(yCoordinates));
  2486.                                 if IOCheck(err) = 0 then begin
  2487.                                         nCoordinates := rNCoordinates;
  2488.                                         SelectionMode := NewSelection;
  2489.                                         MakeOutline;
  2490.                                         SetupUndo;
  2491.                                     end;
  2492.                             end;
  2493.                 end;
  2494.             end;
  2495.         err := fsclose(f);
  2496.     end;
  2497.  
  2498.  
  2499. end.