unit File2; {Routines used by NIH Image for printing plus a few additional File Menu routines.} interface uses Types, Memory, QuickDraw, QuickDrawText, Packages, Menus, Events, Fonts, Scrap, ToolUtils, Resources, Errors, Palettes, Printing, StandardFile, Folders, TextUtils, Dialogs, Files, Finder, Script, globals, Utilities, Graphics, Lut, PictUtils, QDOffscreen, Components, ImageCompression, Movies, QuickTimeComponents, Sound, FixMath, GestaltEqu; procedure GetInfo; procedure DoPageSetup; procedure Print (ShowDialog: boolean); procedure SetHalftone; function OpenMacPaint (fname: str255; vnum: integer): boolean; procedure TypeMismatch (fname: str255); function GetTextFile (var name: str255; var RefNum: integer): boolean; procedure InitTextInput (name: str255; RefNum: integer); procedure GetLineFromText (var rLine: RealLine; var count: integer); function ImportTextFile (name: str255; RefNum: integer): boolean; procedure PlotXYZ; procedure SaveSettings; procedure ExportAsText (fname: str255; RefNum: integer); procedure ExportMeasurements (fname: str255; RefNum: integer); function OpenTiffHeader (f: integer; var DirOffset: LongInt): boolean; function OpenTiffDirectory (f: integer; DirOffset: LongInt; var TiffInfo: TiffInfoRec; Importing: boolean): boolean; procedure SaveTiffColorMap (f: integer; ImageDataSize: LongInt); procedure GetTiffColorMap (f: integer); function SaveTiffDir (f, slines, sPixelsPerLine: integer; SavingSelection: boolean; ctabSize, ImageDataSize: LongInt): OSErr; function RoomForFile (fname: str255; RefNum: integer; slines, sPixelsPerLine: integer; SavingSelection: boolean): boolean; function WriteExtraTiffIFDs (f: integer; ImageDataSize, cTabSize: LongInt): integer; procedure SaveLUT (fname: str255; RefNum: integer); procedure SaveColorTable (fname: str255; RefNum: integer); procedure ExportCoordinates (fname: str255; RefNum: integer); procedure SaveOutline (fname: str255; RefNum: integer); procedure OpenOutline (fname: str255; RefNum: integer); function CheckIO (err: OSerr): integer; function GetTIFFParameters (name: str255; RefNum: integer; var HasColorMap: boolean): boolean; procedure GetXUnits (UnitsKind: UnitsType); procedure GetUnitsKInd (var UnitsKind: UnitsType; var UnitsPerCM: extended); procedure Swap2Bytes (var i: integer); procedure Swap4Bytes (var i: LongInt); function OpenQuickTime (name: str255; fRefNum: integer; UseExistingLUT: boolean): boolean; procedure SaveAsQuickTime (fname: str255; fRefNum: integer); function OpenMovieToolbox:boolean; implementation var gstr: str255; {$PUSH} {$D-} procedure PrintErrCheck; var err: integer; ticks: LongInt; begin err := PrError; if err < 0 then beep; end; procedure DoPageSetup; var result: boolean; begin PrOpen; if PrintRecord = nil then begin PrintRecord := THPrint(NewHandle(SizeOF(TPrint))); PrintDefault(PrintRecord); end; if PrError = NoErr then begin result := PrValidate(PrintRecord); result := PrStlDialog(PrintRecord); end; PrClose; end; procedure PrintHalftone; const PostScriptBegin = 190; PostScriptEnd = 191; PostScriptHandle = 192; TextIsPostScript = 194; var HexBufH: handle; hloc, vloc, HexCount, iheight, iwidth, hstart, vstart: integer; Height, Width, eofStr, angle, freq: str255; aLine: LineType; HexBuf: packed array[0..4200] of char; err: OSErr; table: LookupTable; procedure PutHEX (byt: integer); var i, LowByte, HighByte, tmp: integer; h: char; begin if not info^.IdentityFunction then byt := table[byt]; byt := 255 - byt; LowByte := byt mod 16; byt := byt div 16; HighByte := byt mod 16; for i := 1 to 2 do begin if i = 1 then tmp := HighByte else tmp := LowByte; case tmp of 0: h := '0'; 1: h := '1'; 2: h := '2'; 3: h := '3'; 4: h := '4'; 5: h := '5'; 6: h := '6'; 7: h := '7'; 8: h := '8'; 9: h := '9'; 10: h := 'a'; 11: h := 'b'; 12: h := 'c'; 13: h := 'd'; 14: h := 'e'; 15: h := 'f'; end; hexbuf[HexCount] := h; HexCount := HexCount + 1; if HexCount mod 80 = 0 then begin HexBuf[HexCount] := cr; HexCount := HexCount + 1 end; end; end; begin with info^ do begin if not IdentityFunction then GetLookupTable(table); MoveTo(-1, -1); LineTo(-1, -1); {Nothing prints without this dummy dot!} PicComment(PostScriptBegin, 0, nil); {See Tech Note #91} PicComment(TextIsPostScript, 0, nil); NumToString(HalftoneFrequency, freq); NumToString(HalftoneAngle, angle); if HalftoneDotFunction then DrawString(concat(freq, ' ', angle, ' {dup mul exch dup mul add 1 exch sub} setscreen')) else DrawString(concat(freq, ' ', angle, ' {pop} setscreen')); DrawString('0 0 translate'); with RoiRect do begin iwidth := right - left; if iwidth > MaxLine then iwidth := MaxLine; iheight := bottom - top; hstart := left; vstart := top; end; NumToString(iwidth, width); NumToString(iheight, height); DrawString(concat(width, ' ', height, ' scale')); DrawString(concat('/PicStr ', width, ' string def')); DrawString(concat(width, ' ', height, ' 8 [', width, ' 0 0 ', height, ' 0 0]')); DrawString('{currentfile PicStr readhexstring pop} image'); for vloc := vstart to vstart + iheight - 1 do begin GetLine(hstart, vloc, iwidth, aline); HexCount := 0; for hloc := 0 to iwidth - 1 do PutHex(aline[hloc]); HexBuf[HexCount] := cr; HexCount := HexCount + 1; err := PtrToHand(@HexBuf, HexBufH, HexCount); if err <> noErr then exit(PrintHalftone); PicComment(PostScriptHandle, HexCount, HexBufH); DisposeHandle(HexBufH); Show2Values(vloc - vstart, iheight); if CommandPeriod then begin beep; eofStr := chr(4); DrawString(eofStr); exit(PrintHalftone) end; end; end; end; procedure PrintTheImage (PageWidth, PageHeight: integer); var PrintRect: rect; Width, Height: integer; procedure ScaleToFitPage; var hscale, vscale, scale: extended; begin hscale := PageWidth / width; vscale := PageHeight / height; if hscale <= vscale then scale := hscale else scale := vscale; width := trunc(scale * width); height := trunc(scale * height); end; procedure CenterOnPage; begin with PrintRect do begin left := 0; top := 0; if width < PageWidth then left := (PageWidth - width) div 2; if height < PageHeight then top := (Pageheight - height) div 2; right := left + width; bottom := top + height; end; end; begin if isLaserWriter and (not DriverHalftoning) then PrintHalftone else with info^ do begin LoadLUT(cTable); hlock(handle(osPort^.portPixMap)); with RoiRect do begin width := right - left; height := bottom - top; end; if (width > PageWidth) or (height > PageHeight) then ScaleToFitPage; CenterOnPage; if BitAnd(qd.thePort^.portBits.rowBytes, $8000) = $8000 then begin {Assume driver understands Color QD} CopyBits(BitMapHandle(osPort^.portPixMap)^^, BitMapHandle(CGrafPtr(qd.thePort)^.PortPixMap)^^, RoiRect, PrintRect, SrcCopy, nil); end else CopyBits(BitMapHandle(osPort^.portPixMap)^^, qd.thePort^.PortBits, RoiRect, PrintRect, SrcCopy, nil); end; end; procedure PrintTextBuffer (PageHeight: integer; var PrintPort: TPPrPortRef); const LineInc = 13; var vloc, i, LineCount, CharCount, LinesPerPage, MaxCount: integer; aLine: str255; begin ClipTextInBuffer := false; LinesPerPage := PageHeight div LineInc; vloc := LineInc; LineCount := 0; CharCount := 0; TextFont(Monaco); TextSize(9); if WhatToPrint = PrintText then MaxCount := 85 else MaxCount := 255; i := 1; repeat CharCount := 0; while (TextBufP^[i] <> cr) and (CharCount < MaxCount) and (i <= TextBufSize) do begin CharCount := CharCount + 1; aLine[CharCount] := TextBufP^[i]; i := i + 1; end; if TextBufP^[i] = cr then i := i + 1 else if CharCount = MaxCount then begin while (aLine[CharCount] <> ' ') and (CharCount > (MaxCount - 15)) do begin CharCount := CharCount - 1; i := i - 1; end; if TextBufP^[i] = ' ' then i := i + 1; end; aLine[0] := chr(CharCount); MoveTo(0, vloc); DrawString(aLine); vLoc := vLoc + LineInc; LineCount := LineCount + 1; if LineCount >= LinesPerPage then begin LineCount := 0; if i < TextBufSize then begin PrClosePage(PrintPort); PrintErrCheck; PrOpenPage(PrintPort, nil); vloc := LineInc end; end; until i > TextBufSize; end; procedure DoPrintText (PageHeight: integer; var PrintPort: TPPrPortRef); var ByteCount: LongInt; begin if TextInfo <> nil then with TextInfo^.TextTE^^ do begin ByteCount := TELength; BlockMove(hText^, ptr(TextBufP), ByteCount); TextBufSize := ByteCount; PrintTextBuffer(PageHeight, PrintPort); end; end; procedure Print (ShowDialog: boolean); var err, i, LinesToPrint: Integer; tPort: GrafPtr; PrintPort: TPPrPortRef; PrintStatusRec: TPPrStatusRef; {was TPrStatus} prect: rect; result: boolean; begin if WhatToPrint = PrintImage then SelectAll(false); if (WhatToPrint = PrintImage) or (WhatToPrint = PrintSelection) then begin if OpPending then KillRoi; with info^.RoiRect do LinesToPrint := bottom - top; if not DriverHalftoning then begin DrawLabels('Line:', 'Total:', ''); Show2Values(0, LinesToPrint); end; end; GetPort(tPort); PrOpen; if PrintRecord = nil then begin PrintRecord := THPrint(NewHandle(SizeOF(TPrint))); PrintDefault(PrintRecord); end; if PrError = NoErr then begin InitCursor; result := PrValidate(PrintRecord); isLaserWriter := BSR(PrintRecord^^.prStl.wDev, 8) = 3; prect := PrintRecord^^.prInfo.rPage; if ShowDialog then result := PrJobDialog(PrintRecord) else result := true; if not DriverHalftoning then ShowMessage(CmdPeriodToStop); ShowWatch; if result then for i := 1 to PrintRecord^^.PrJob.icopies do begin PrintPort := PrOpenDoc(PrintRecord, nil, nil); PrintErrCheck; Printing := true; PrOpenPage(PrintPort, nil); if PrError = NoErr then case WhatToPrint of PrintImage, PrintSelection: PrintTheImage(prect.right, prect.bottom); PrintMeasurements: begin CopyResultsToBuffer(1, mCount, true); PrintTextBuffer(prect.Bottom, PrintPort); UnsavedResults := false; end; PrintPlot: DrawPlot; PrintHistogram: DrawHistogram; PrintText: DoPrintText(prect.Bottom, PrintPort); end; Printing := false; PrClosePage(PrintPort); PrintErrCheck; PrCloseDoc(PrintPort); PrintErrCheck; if PrintRecord^^.prJob.bJDocLoop = bSpoolLoop then PrPicFile(PrintRecord, nil, nil, nil, nil{PrintStatusRec}); end; end; PrClose; SetPort(tPort); if WhatToPrint = PrintImage then KillRoi; ShowMessage(' '); end; procedure SetHalftone; const FrequencyID = 8; AngleID = 10; DotID = 4; LineID = 5; CustomID = 13; var mylog: DialogPtr; item, i, ignore, SaveFrequency, SaveAngle: integer; SaveFunction, SaveCustom: boolean; str: str255; begin SaveFrequency := HalftoneFrequency; SaveAngle := HalftoneAngle; SaveFunction := HalftoneDotFunction; SaveCustom := DriverHalftoning; mylog := GetNewDialog(30, nil, pointer(-1)); SetDNum(MyLog, FrequencyID, HalftoneFrequency); SelectdialogItemText(MyLog, FrequencyID, 0, 32767); SetDNum(MyLog, AngleID, HalftoneAngle); SetDlogItem(mylog, CustomID, ord(not DriverHalftoning)); OutlineButton(MyLog, ok, 16); if HalftoneDotFunction then SetDlogItem(mylog, DotID, 1) else SetDlogItem(mylog, LineID, 1); repeat ModalDialog(nil, item); if item = FrequencyID then begin HalftoneFrequency := GetDNum(MyLog, FrequencyID); DriverHalftoning := false; SetDlogItem(mylog, CustomID, ord(not DriverHalftoning)); end; if item = AngleID then begin HalftoneAngle := GetDNum(MyLog, AngleID); if (HalftoneAngle < 0) or (HalftoneAngle > 180) then begin beep; HalftoneAngle := SaveAngle; end; DriverHalftoning := false; SetDlogItem(mylog, CustomID, ord(not DriverHalftoning)); end; if (item >= DotID) and (item <= LineID) then begin for i := DotID to LineID do SetDlogItem(mylog, i, 0); SetDlogItem(mylog, item, 1); HalftoneDotFunction := item = DotID; DriverHalftoning := false; SetDlogItem(mylog, CustomID, ord(not DriverHalftoning)); end; if item = CustomID then begin DriverHalftoning := not DriverHalftoning; SetDlogItem(mylog, CustomID, ord(not DriverHalftoning)); end; until (item = ok) or (item = cancel); DisposeDialog(mylog); if item = cancel then begin HalftoneFrequency := SaveFrequency; HalftoneAngle := SaveAngle; HalftoneDotFunction := SaveFunction; DriverHalftoning := SaveCustom; end; end; {$POP} procedure GetFileInfo (name: str255; vnum: integer; var DateCreated, LastModified: str255); var FileParmBlock: CInfoPBRec; theErr: OSErr; DateVar, TimeVar: str255; Secs: LongInt; begin DateCreated := ''; with FileParmBlock do begin ioCompletion := nil; ioNamePtr := @name; ioVRefNum := vnum; ioFVersNum := 0; ioFDirIndex := 0; theErr := PBGetCatInfoSync(@FileParmBlock); {ppc-bug} if theErr = NoErr then begin Secs := ioFlCrDat; IUDateString(Secs, abbrevDate, DateVar); IUTimeString(Secs, true, TimeVar); DateCreated := concat(DateVar, ' ', TimeVar); Secs := ioFlMDDat; IUDateString(Secs, abbrevDate, DateVar); IUTimeString(Secs, true, TimeVar); LastModified := concat(DateVar, ' ', TimeVar); end; end; end; procedure GetVolumnInfo (vnum: integer; var VolumnName: str255; var FreeSpace: LongInt); var theErr: OSErr; str: str255; VolParmBlock: ParamBlockRec; begin VolumnName := ''; with VolParmBlock do begin str := ''; ioVRefNum := vnum; ioNamePtr := @str; ioCompletion := nil; ioVolIndex := -1; theErr := PBGetVInfoSync(@VolParmBlock); {ppc-bug} VolumnName := ioNamePtr^; FreeSpace := ioVAlBlkSiz * ioVFrBlk; end; end; function RoomForFile (fname: str255; RefNum: integer; slines, sPixelsPerLine: integer; SavingSelection: boolean): boolean; var err: OSErr; f: integer; VolumnName: str255; FreeSpace, ExistingFileSize, NeededSize: LongInt; begin with info^ do begin ExistingFileSize := 0; RoomForFile := true; err := fsopen(fname, RefNum, f); if err = 0 then begin err := GetEOF(f, ExistingFileSize); err := fsClose(f); end; if ExistingFileSize <> 0 then begin if SavingSelection then begin NeededSize := sLines; NeededSize := NeededSize * sPixelsPerLine end else NeededSize := ImageSize; if StackInfo <> nil then with StackInfo^ do NeededSize := NeededSize * nSlices + nSlices * SizeOf(StackIFDType); GetVolumnInfo(RefNum, VolumnName, FreeSpace); if (NeededSize - ExistingFileSize + 8192) > FreeSpace then begin PutError('There is not enough free space on this disk to save this image.'); RoomForFile := false; end; end; end; end; procedure GetInfo; var name, str, DateCreated, LastModified, VolumnName, str2: str255; hloc, vloc, InfoWidth, InfoHeight: integer; SaveRoiShowing: boolean; FreeSpace, DataSize: LongInt; SaveForeIndex, SaveBackIndex: integer; ImageInfo, InfoWindowInfo: InfoPtr; x1, y1, x2, y2, ulength, clength: extended; SaveGDevice: GDHandle; procedure NewLine; begin vloc := vloc + 13; MoveTo(hloc, vloc); end; procedure NewParagraph; begin vloc := vloc + 18; MoveTo(hloc, vloc); end; begin InfoWidth := 260; InfoHeight := 260; with info^ do begin if RoiShowing then InfoHeight := InfoHeight + 50; if RoiShowing and (RoiType = LineRoi) then InfoHeight := InfoHeight + 20; if vref <> 0 then InfoHeight := InfoHeight + 60; name := concat('Info About ', title); SaveRoiShowing := RoiShowing; end; SaveForeIndex := ForegroundIndex; SaveBackIndex := BackgroundIndex; SetForegroundColor(BlackIndex); SetBackgroundColor(WhiteIndex); ImageInfo := info; if NewPicWindow(name, InfoWidth, InfoHeight) then with ImageInfo^ do begin InfoWindowInfo := Info; SaveGDevice := GetGDevice; SetGDevice(osGDevice); SetPort(GrafPtr(info^.osPort)); TextFont(Geneva); TextSize(9); hloc := 15; vloc := 10; NewLine; DrawBString('Name: '); DrawString(title); NewParagraph; DrawBString('Width: '); DrawXDimension(PixelsPerLine, 0); NewLine; DrawBString('Height: '); DrawYDimension(nlines, 0); if StackInfo <> nil then begin NewLine; DrawBString('Depth: '); DrawLong(StackInfo^.nSlices); end; NewLine; DrawBString('Size: '); if StackInfo <> nil then DataSize := PixMapSize * StackInfo^.nSlices else if DataH <> nil then DataSize := PixMapSize + PixMapSize * SizeOf(real) else DataSize := PixMapSize; DrawLong((DataSize + 511) div 1024); DrawString('K'); NewParagraph; GetFileInfo(title, vref, DateCreated, LastModified); {DateCreated:='';} if DateCreated <> '' then begin DrawBString('Creation Date: '); DrawString(DateCreated); NewLine; DrawBString('Last Modified: '); DrawString(LastModified); NewLine; end; if fileVersion > 0 then begin DrawBString('Version: '); DrawString('Created by NIH Image '); DrawReal(fileVersion / 100.0, 1, 2); NewParagraph; end; DrawBString('Type: '); if StackInfo <> nil then case StackInfo^.StackType of VolumeStack, MovieStack: str := concat('Stack (', long2str(StackInfo^.nSlices), ' slices)'); rgbStack: str := 'RGB color stack'; else ; end else begin case PictureType of NewPicture: str := 'New'; Normal: str := 'Normal'; PictFile: str := 'PICT'; TiffFile: str := 'TIFF'; Leftover: str := 'Left Over'; Imported: begin if DataType = EightBits then str := 'Imported 8-bit image' else str := 'Imported 16-bit image'; end; FrameGrabberType: str := 'Camera'; BlankField: str := 'Blank Field'; otherwise ; end; if BinaryPic then str := concat(str, ' (Binary)'); end; DrawString(str); if StackInfo <> nil then with StackInfo^ do if SliceSpacing <> 0.0 then begin NewLine; DrawBString('Slice Spacing: '); if SpatiallyCalibrated then DrawString(StringOf(SliceSpacing / xScale:1:2, ' ', xunit, ' (', SliceSpacing:1:2, ' pixels)')) else DrawString(StringOf(SliceSpacing:1:2, ' pixels')); end; NewLine; DrawBString('Lookup Table: '); case LutMode of PseudoColor: str := concat('Pseudocolor (', long2str(ncolors), ', ', long2str(ColorStart), '-', long2str(ColorEnd), ')'); GrayScale: str := concat('Grayscale (', long2str(ncolors), ', ', long2str(ColorStart), '-', long2str(ColorEnd), ')'); ColorLut: str := 'Color'; CustomGrayscale: str := 'Custom Grayscale'; otherwise end; DrawString(str); NewLine; DrawBString('Magnification: '); if ScaleToFitWindow then begin DrawReal(magnification, 1, 2); DrawString(' (Scale to Window Mode)') end else begin DrawReal(magnification, 1, 0); DrawString(':1') end; NewLine; DrawBString('Scale: '); if SpatiallyCalibrated then begin DrawReal(xScale, 1, 3); DrawString(' pixels per '); DrawString(xUnit); if PixelAspectRatio <> 1.0 then begin NewLine; DrawBString('Pixel Aspect Ratio: '); DrawReal(PixelAspectRatio, 1, 4); end; end else DrawString('None'); if fit <> uncalibrated then begin NewLine; DrawBString('Unit of Measure: '); if UnitOfMEasure = '' then DrawString('None') else DrawString(UnitOfMeasure) end; NewParagraph; DrawBString('Free RAM: '); DrawLong(FreeMem div 1024); DrawString('K'); NewLine; DrawBString('Largest Free Block: '); DrawLong(MaxBlock div 1024); DrawString('K'); if FrameGrabber <> NoFrameGrabber then begin NewLine; DrawBString('Frame Grabber: '); case FrameGrabber of QuickCapture: begin if fgWidth = 768 then DrawString('50Hz') else DrawString('60Hz'); DrawString(' Data Translation QuickCapture'); end; ScionLG3: begin if fgWidth = 768 then DrawString('50Hz') else DrawString('60Hz'); DrawString(' Scion LG-3 ('); DrawLong(MaxLG3Frames div 2); DrawString(' MB)'); end; ScionAG5: begin if fgWidth = 768 then DrawString('50Hz') else DrawString('60Hz'); DrawString(' Scion AG-5'); end; ScionVG5f: begin if fgWidth = 768 then DrawString('50Hz') else DrawString('60Hz'); DrawString(' Scion VG-5'); end QTvdig: DrawString('QuickTime Video Digitizer'); end; end; NewParagraph; if RoiType <> NoRoi then begin DrawBString('Selection Type: '); case RoiType of PolygonRoi: DrawString('Polygon'); FreehandRoi: DrawString('Freehand'); RectRoi: DrawString('Rectangle'); OvalRoi: DrawString('Oval'); LineRoi: DrawString('Straight Line'); FreeLineRoi: DrawString('Freehand Line'); SegLineRoi: DrawString('Segmented Line'); TracedRoi: DrawString('Traced'); end; NewLine; case RoiType of PolygonRoi, FreehandRoi, RectRoi, OvalRoi, TracedRoi: with RoiRect do begin DrawBString(' Left: '); DrawXDimension(left, 0); NewLine; DrawBString(' Top: '); if InvertYCoordinates then DrawYDimension(PicRect.bottom - top - 1, 0) else DrawYDimension(top, 0); NewLine; DrawBString(' Width: '); DrawXDimension(right - left, 0); NewLine; DrawBString(' Height: '); DrawYDimension(bottom - top, 0); end; LineRoi: begin info := ImageInfo; GetLengthOrPerimeter(ulength, clength); GetLoi(x1, y1, x2, y2); Info := InfoWindowInfo; DrawBString(' Length: '); if SpatiallyCalibrated then begin DrawReal(cLength, 1, 2); DrawString(xUnit); end else DrawReal(uLength, 1, 2); NewLine; DrawBString(' Angle: '); DrawReal(LAngle, 1, 2); DrawString('¡'); NewLine; DrawBString(' X1: '); DrawXDimension(x1, 2); NewLine; DrawBString(' Y1: '); if InvertYCoordinates then DrawYDimension(PicRect.bottom - y1 - 1, 2) else DrawYDimension(y1, 2); NewLine; DrawBString(' X2: '); DrawXDimension(x2, 2); NewLine; DrawBString(' Y2: '); if InvertYCoordinates then DrawYDimension(PicRect.bottom - y2 - 1, 2) else DrawYDimension(y2, 2); end; FreeLineRoi, SegLineRoi: begin info := ImageInfo; GetLengthOrPerimeter(ulength, clength); Info := InfoWindowInfo; DrawBString(' Length: '); if SpatiallyCalibrated then begin DrawReal(cLength, 1, 2); DrawString(xUnit); end else DrawReal(uLength, 1, 2); NewLine; end; otherwise end; {case} end else DrawBString('No Selection'); SetGDevice(SaveGDevice); end; {with ImageInfo^} SetForegroundColor(SaveForeIndex); SetBackgroundColor(SaveBackIndex); end; function CheckIO (err: OSerr): integer; var ErrStr, Message: str255; ignore: integer; SaveGDevice: GDHandle; begin if err <> 0 then begin case err of -34: Message := 'Disk Full'; -35: Message := 'No such volume'; -36: Message := 'I/O Error'; -39: Message := 'End of file error'; -49: Message := 'File in Use'; -61: Message := 'Write Permission Error'; -120: Message := 'Folder not found' otherwise Message := ''; end; SaveGDevice := GetGDevice; SetGDevice(GetMainDevice); NumToString(err, ErrStr); ParamText(Message, ErrStr, '', ''); InitCursor; ignore := alert(IOErrorID, nil); SetGDevice(SaveGDevice); AbortMacro; end; CheckIO := err; end; function OpenMacPaint (fname: str255; vnum: integer): boolean; const MaxUnPackedSize = 51840; {Max MacPaint size in bytes=720 lines * 72 bytes/line } type mpLine = array[1..18] of LongInt; mpArrayT = array[1..720] of mpLine; mpArrayP = ^mpArrayT; var i, f, ScanLine, LastLine, LastWord, LastColumn: integer; err: osErr; srcSize: LongInt; srcPtr, dstPtr, src, dst: ptr; theBitMap: BitMap; mpArray: mpArrayP; BlankLine, BlankColumn: boolean; frect: rect; SaveGDevice: GDHandle; procedure abort; begin beep; if srcPtr <> nil then DisposePtr(srcPtr); if dstPtr <> nil then DisposePtr(dstPtr); {exit(OpenMacPaint);} {ppc-bug} end; begin OpenMacPaint := false; err := fsOpen(fname, vnum, f); if CheckIO(err) <> noErr then exit(OpenMacPaint); err := GetEOF(f, srcSize); srcSize := srcSize - 512; srcPtr := NewPtr(srcSize); if srcPtr = nil then begin abort; exit(OpenMacPaint); end; err := SetFPos(f, fsFromStart, 512); err := fsRead(f, srcSize, srcPtr); if CheckIO(err) <> noErr then exit(OpenMacPaint); err := fsClose(f); dstPtr := NewPtrClear(MaxUnPackedSize); if dstPtr = nil then begin abort; exit(OpenMacPaint); end; src := srcPtr; dst := dstPtr; for scanLine := 1 to 720 do UnPackBits(src, dst, 72); {bumps both ptrs} DisposePtr(srcPtr); mpArray := mpArrayP(dstPtr); LastLine := 720; BlankLine := true; repeat for i := 1 to 18 do blankLine := BlankLine and (mpArray^[LastLine, i] = 0); if BlankLine then LastLine := LastLine - 1; until (not BlankLine) or (LastLine = 1); LastWord := 18; BlankColumn := true; repeat for i := 1 to LastLine do blankColumn := BlankColumn and (mpArray^[i, LastWord] = 0); if BlankColumn then LastWord := LastWord - 1; until (not BlankColumn) or (LastWord = 1); LastColumn := LastWord * 32; LastColumn := LastColumn + 8; if LastColumn > 576 then LastColumn := 576; LastLine := LastLine + 8; if LastLine > 720 then LastLine := 720; SetRect(frect, 0, 0, LastColumn, LastLine); with theBitMap do begin baseAddr := dstPtr; rowBytes := 72; bounds := frect; end; if not NewPicWindow(fname, LastColumn, LastLine) then begin abort; exit(OpenMacPaint); end; SaveGDevice := GetGDevice; SetGDevice(osGDevice); SetForegroundColor(BlackIndex); SetBackgroundColor(WhiteIndex); with info^ do begin CopyBits(theBitMap, BitMapHandle(osPort^.PortPixMap)^^, frect, frect, SrcCopy, nil); DisposePtr(dstPtr); PictureType := imported; BinaryPic := true; SetGDevice(SaveGDevice); if PixMapSize > UndoBufSize then PutWarning; end; OpenMacPaint := true; end; procedure TypeMismatch (fname: str255); begin PutError(concat('The file "', fname, '" is a different type, and therefore cannot be replaced')); end; function GetTextFile (var name: str255; var RefNum: integer): boolean; var where: Point; typeList: SFTypeList; reply: SFReply; err: OSErr; pBlock: WDPBRec; begin where.v := 120; where.h := 120; typeList[0] := 'TEXT'; SFGetFile(Where, '', nil, 1, @typeList, nil, reply); if reply.good then with reply do begin name := fname; RefNum := vRefNum; GetTextFile := true; end else GetTextFile := false; end; procedure GetBuffer; var err: OSErr; count, FilePos: LongInt; begin count := MaxTextBufSize; err := fsread(Textf, count, ptr(TextBufP)); TextBufSize := count; err := GetFPos(Textf, FilePos); if FilePos = TextFileSize then begin TextBufSize := TextBufSize + 1; if TextBufSize > MaxTextBufSize then TextBufSize := MaxTextBufSize; TextBufP^[TextBufSize] := eofChr; err := fsclose(Textf); end; TextIndex := 1; end; function GetByte: char; begin GetByte := TextBufP^[TextIndex]; TextIndex := TextIndex + 1; if TextIndex > MaxTextBufSize then GetBuffer; end; function GetNumber: extended; var c: char; str: str255; begin repeat c := GetByte; if c = tab then begin GetNumber := 0.0; {Assume 0 zero for missing value.} exit(GetNumber); end; if (c = cr) or (c = eofChr) then begin TextEol := true; TextEof := c = eofChr; GetNumber := NoValue; exit(GetNumber); end; until c in ['0'..'9', '-', '.']; Str := ''; while c in ['0'..'9', '+', '-', '.', 'e', 'E'] do begin Str := concat(str, c); c := GetByte; if (c = cr) or (c = eofChr) then begin TextEol := true; TextEof := c = eofChr; end; end; GetNumber := StringToReal(str); end; procedure GetLineFromText (var rLine: RealLine; var count: integer); var n: extended; begin count := 0; if TextEof then exit(GetLineFromText); repeat n := GetNumber; if n <> NoValue then begin count := count + 1; rLine[count] := n; end; until TextEol or (count = MaxLine); TextEol := false; end; procedure InitTextInput (name: str255; RefNum: integer); var err: OSErr; begin err := FSOpen(name, RefNum, Textf); err := GetEof(Textf, TextFileSize); err := SetFPos(Textf, fsFromStart, 0); ShowWatch; if WhatsOnClip = TextOnClip then WhatsOnClip := NothingOnClip; GetBuffer; TextEol := false; TextEof := false; end; function ImportTextFile (name: str255; RefNum: integer): boolean; var nRows, nColumns, count, i, vloc, BlankPixel, nPixelsPerLine: integer; rLine: RealLine; pvalue: extended; min, max, ScaleFactor, DefaultValue, tvalue: extended; err: OSErr; line, BlankLine: LineType; TheInfo: FInfo; noScaling:boolean; begin ImportTextFile := false; err := GetFInfo(name, RefNum, TheInfo); if TheInfo.fdType <> 'TEXT' then begin PutError('File is not of type ''TEXT''.'); exit(ImportTextFile); end; InitTextInput(name, RefNum); nRows := 0; nColumns := 0; max := -10e-10; min := 10e10; ShowMessage(concat('First pass used to find ', crStr, 'width, height,min, and max.', crStr, crStr, CmdPeriodToStop)); DrawLabels('Line:', '', ''); while not TextEof do begin GetLineFromText(rLine, count); if not (TextEof and (count = 0)) then nRows := nRows + 1; if count > nColumns then nColumns := count; for i := 1 to count do begin pvalue := rLine[i]; if pvalue > max then max := pvalue; if pvalue < min then min := pvalue; end; if nRows mod 10 = 0 then begin Show1Value(nRows, NoValue); ShowAnimatedWatch; if CommandPeriod then begin beep; err := fsclose(Textf); Exit(ImportTextFile); end; end; end; ShowMessage(concat('rows= ', long2str(nRows), crStr, 'columns= ', long2str(ncolumns), crStr, 'min= ', long2str(round(min)), crStr, 'max= ', long2str(round(max)))); if nColumns > MaxLine then begin PutError(concat('More than ',long2str(MaxLine),' pixels per line.')); Exit(ImportTextFile); end; nPixelsPerLine := nColumns; if NewPicWindow(name, nPixelsPerLine, nrows) then with info^ do begin if (not ImportAutoScale) and (max > min) then begin min := ImportMin; max := ImportMax; end; ScaleFactor := 253.0 / (max - min); InitTextInput(name, RefNum); vloc := 0; DefaultValue := 0.0; if DefaultValue < min then DefaultValue := min; if DefaultValue > max then DefaultValue := max; BlankPixel := round((DefaultValue - min) * ScaleFactor + 1); for i := 0 to nColumns - 1 do BlankLine[i] := BlankPixel; NoScaling:=not ImportAutoScale and ((min=0) and (max=255)); DrawLabels('Line:', 'Total:', ''); while not TextEof do begin GetLineFromText(rLine, count); if not (TextEof and (count = 0)) then begin line := BlankLine; if ImportAutoScale then {Map values into the range 1-254} for i := 1 to count do line[i - 1] := round((rLine[i] - min) * ScaleFactor + 1) else for i := 1 to count do begin tvalue := rLine[i]; if tvalue < min then tvalue := min; if tvalue > max then tvalue := max; if noScaling then line[i - 1]:=round(tvalue) else line[i - 1] := round((tvalue - min) * ScaleFactor + 1); end; PutLine(0, vloc, PixelsPerLine, line); vloc := vloc + 1; end; if vloc mod 10 = 0 then begin Show2Values(vloc, nRows); ShowAnimatedWatch; if CommandPeriod then begin beep; err := fsclose(Textf); Exit(ImportTextFile); end; end; end; if noScaling then ImportCalibrate:=false else begin fit := StraightLine; nCoefficients := 2; coefficient[2] := (max - min) / 253.0; coefficient[1] := min - coefficient[2]; nKnownValues := 0; UpdateTitleBar; if macro then GenerateValues; ZeroClip := false; end; changes := true; PictureType := imported; end; {with} ImportTextFile := true; end; procedure PlotXYZ; {Reads X-Y coordinate pairs and optional intensiy(Z) values from a} {two or three column tab-delimited text file and plots them in the current window.} var fname, str: str255; RefNum, i, nColumns, nValues, index, wheight: integer; rLine: RealLine; begin RefNum := 0; if not GetTextFile(fname, RefNum) then exit(PlotXYZ); InitTextInput(fname, RefNum); GetLineFromText(rLine, nValues); nColumns := nValues; if not ((nColumns = 2) or (nColumns = 3)) then begin PutError('File must have two or three columns.'); exit(PlotXYZ); end; wheight := info^.nLines; index := ForegroundIndex; repeat if nColumns = 3 then begin index := round(rLine[3]); if index > 255 then index := 255; if index < 0 then index := 0; end; PutPixel(round(rLine[1]), wheight - round(rLine[2] + 1), index); GetLineFromText(rLine, nValues); until nValues = 0; InitCursor; end; procedure SaveSettings; var TheInfo: FInfo; ByteCount: LongInt; f, i: integer; err: OSErr; settings: SettingsType; PrefsVRef: integer; PrefsDirID: LongInt; PrefsSpec: FSSpec; PrefsError:boolean; begin with settings, info^ do begin sID := 'IMAG'; sVersion := version; sForegroundIndex := ForegroundIndex; sBackgroundIndex := BackgroundIndex; sBrushHeight := BrushHeight; sBrushWidth := BrushWidth; sSprayCanDiameter := SprayCanDiameter; sLUTMode := LUTMode; sOldColorStart := 30; sOldColorWidth := 10; sCurrentFontID := CurrentFontID; sCurrentStyle := CurrentStyle; sCurrentSize := CurrentSize; sTextJust := TextJust; sTextBack := TextBack; sNExtraColors := nExtraColors; sExtraColors := ExtraColors; sInvertVideo := InvertVideo; sMeasurements := Measurements; sInvertPlots := InvertPlots; sAutoScalePlots := AutoScalePlots; sLinePlot := LinePlot; sDrawPlotLabels := DrawPlotLabels; for i := 1 to 12 do sUnused1[i] := 0; sFixedSizePlot := FixedSizePlot; sProfilePlotWidth := ProfilePlotWidth; sProfilePlotHeight := ProfilePlotHeight; sFramesToAverage := FramesToAverage; sNewPicWidth := NewPicWidth; sNewPicHeight := NewPicHeight; sBufferSize := BufferSize; sThresholdToForeground := ThresholdToForeground; sNonThresholdToBackground := NonThresholdToBackground; sVideoChannel := VideoChannel; sWhatToImport := WhatToImport; sImportCustomWidth := ImportCustomWidth; sImportCustomHeight := ImportCustomHeight; sImportCustomOffset := ImportCustomOffset; sWandAutoMeasure := WandAutoMeasure; sWandAdjustAreas := WandAdjustAreas; sBinaryIterations := BinaryIterations; sScaleArithmetic := ScaleArithmetic; sInvertPixelValues := InvertPixelValues; sInvertYCoordinates := InvertYCoordinates; sFieldWidth := FieldWidth; sPrecision := precision; sMinParticleSize := MinParticleSize; sMaxParticleSize := MaxParticleSize; sIgnoreParticlesTouchingEdge := IgnoreParticlesTouchingEdge; sLabelParticles := LabelParticles; sOutlineParticles := OutlineParticles; sIncludeHoles := IncludeHoles; sOscillatingMovies := OscillatingMovies; sDriverHalftoning := DriverHalftoning; sMaxMeasurements := MaxMeasurements; sImportCustomDepth := ImportCustomDepth; sImportSwapBytes := ImportSwapBytes; sImportCalibrate := ImportCalibrate; sImportAutoscale := ImportAutoscale; for i := 1 to 12 do sUnused2[i] := 0; sShowHeadings := ShowHeadings; sDefaultVRefNum := 0; sDefaultDirID := 0; sKernelsVRefNum := 0; sKernelsDirID := 0; {***} sProfilePlotMin := ProfilePlotMin; sProfilePlotMax := ProfilePlotMax; sImportMin := ImportMin; sImportMax := ImportMax; sHighlightPixels := HighlightSaturatedPixels; {***} sBallRadius := BallRadius; sFasterBackgroundSubtraction := FasterBackgroundSubtraction; sScaleConvolutions := ScaleConvolutions; {V1.42} sBinaryCount := BinaryCount; sColorTable := ColorTable; sColorStart := ColorStart; sColorEnd := ColorEnd; sInvertedTable := InvertedColorTable; {V1.44} sHalftoneFrequency := HalftoneFrequency; sHalftoneAngle := HalftoneAngle; sHalftoneDotFunction := HalftoneDotFunction; sDacLow := DacLow; sDacHigh := DacHigh; sSyncMode := SyncMode; sSwitchLUTOnSuspend := SwitchLUTOnSuspend; sVideoRateAveraging := VideoRateAveraging; sImportInvert := ImportInvert; sTextCreator := TextCreator; sMathSubGain:=MathSubGain; sMathSubOffset:=round(MathSubOffset); {V1.60} sfgScale := fgScale; sUseBuiltinDigitizer := UseBuiltinDigitizer; sDigitizerMode := DigitizerMode; sDigitizerStandard := DigitizerStandard; sLutFriendlyMode := LutFriendlyMode; for i := 1 to 10 do sUnused[i] := 0; end; {with} if System7 then begin {Save in Preferences folder} PrefsError:=true; err:=FindFolder(kOnSystemDisk, kPreferencesFolderType, false, PrefsVRef, PrefsDirID); if err=noErr then err:=FSMakeFSSpec(PrefsVRef, PrefsDirID, PrefsName, PrefsSpec); if err=noErr then err:=FSpDelete(PrefsSpec); if (err=noErr) or (err=fnfErr) then begin err:=FSpCreate(PrefsSpec, 'Imag', 'pref', smSystemScript); if err=noErr then err:=FSpOpenDF(PrefsSpec, fsCurPerm, f); if err=noErr then PrefsError:=false; end; if PrefsError then begin PutError('Error saving settings file'); exit(SaveSettings); end; end else begin {Save in System folder} err := GetFInfo(PrefsName, SystemRefNum, TheInfo); if err = FNFerr then begin err := create(PrefsName, SystemRefNum, 'Imag', 'pref'); if CheckIO(err) <> 0 then exit(SaveSettings); end; err := fsopen(PrefsName, SystemRefNum, f); end; if CheckIO(err) <> 0 then exit(SaveSettings); err := SetFPos(f, FSFromStart, 0); ByteCount := SizeOf(settings); err := fswrite(f, ByteCount, @settings); if CheckIO(err) <> 0 then begin err := fsclose(f); exit(SaveSettings) end; err := SetEof(f, ByteCount); err := fsclose(f); err := FlushVol(nil, SystemRefNum); end; procedure ExportAsText (fname: str255; RefNum: integer); var err, f, width, hloc, vloc: integer; TheInfo: FInfo; ByteCount, FileSize: LongInt; AutoSelectAll, InvertValues: boolean; tLine: LineType; begin if info = NoInfo then exit(ExportAsText); err := GetFInfo(fname, RefNum, TheInfo); case err of NoErr: if TheInfo.fdType <> 'TEXT' then begin TypeMismatch(fname); exit(ExportAsText) end; FNFerr: begin err := create(fname, RefNum, FourCharCode(TextCreator), 'TEXT'); if CheckIO(err) <> 0 then exit(ExportAsText); end; otherwise if CheckIO(err) <> 0 then exit(ExportAsText) end; ShowWatch; err := fsopen(fname, RefNum, f); if CheckIO(err) <> 0 then exit(ExportAsText); AutoSelectAll := not info^.RoiShowing; if AutoSelectAll then SelectAll(true); if TooWide then exit(ExportAsText); FileSize := 0; with info^, info^.RoiRect do begin InvertValues := isInvertingFunction; width := right - left; for vloc := top to bottom - 1 do begin GetLine(left, vloc, width, tLine); TextBufSize := 0; for hloc := 0 to width - 1 do begin if fit = uncalibrated then PutLong(tLine[hloc], 0) else if InvertValues then PutLong(255 - tLine[hloc], 0) else PutString(StringOf(cValue[tLine[hloc]]:1:precision)); if hloc <> (width - 1) then PutTab; end; PutChar(cr); ByteCount := TextBufSize; err := fswrite(f, ByteCount, ptr(TextBufP)); FIleSize := FileSize + ByteCount; if (CheckIO(err) <> 0) or CommandPeriod then leave; if (vloc mod 10) = 0 then ShowAnimatedWatch; end; err := SetEof(f, FileSize); err := fsclose(f); err := FlushVol(nil, RefNum); end; if AutoSelectAll then KillRoi; end; procedure ExportCoordinates (fname: str255; RefNum: integer); var err, f, i, y: integer; TheInfo: FInfo; ByteCount, FileSize: LongInt; InvertY: boolean; begin if not CoordinatesAvailableMsg then begin exit(ExportCoordinates) end; err := GetFInfo(fname, RefNum, TheInfo); case err of NoErr: if TheInfo.fdType <> 'TEXT' then begin TypeMismatch(fname); exit(ExportCoordinates) end; FNFerr: begin err := create(fname, RefNum, FourCharCode(TextCreator), 'TEXT'); if CheckIO(err) <> 0 then exit(ExportCoordinates); end; otherwise if CheckIO(err) <> 0 then exit(ExportCoordinates) end; ShowWatch; err := fsopen(fname, RefNum, f); if CheckIO(err) <> 0 then exit(ExportCoordinates); FileSize := 0; InvertY := InvertYCoordinates and (Info <> NoInfo); with info^ do for i := 1 to nCoordinates do begin TextBufSize := 0; PutLong(xCoordinates^[i] + RoiRect.left, 0); PutTab; y := yCoordinates^[i] + RoiRect.top; if InvertY then y := PicRect.bottom - y - 1; PutLong(y, 0); PutChar(cr); ByteCount := TextBufSize; err := fswrite(f, ByteCount, ptr(TextBufP)); FIleSize := FileSize + ByteCount; if (CheckIO(err) <> 0) or CommandPeriod then leave; end; err := SetEof(f, FileSize); err := fsclose(f); err := FlushVol(nil, RefNum); end; procedure ExportMeasurements (fname: str255; RefNum: integer); const LinesPerPass = 25; var err, f, i, first, last: integer; TheInfo: FInfo; ByteCount, FileSize: LongInt; begin err := GetFInfo(fname, RefNum, TheInfo); case err of NoErr: if TheInfo.fdType <> 'TEXT' then begin TypeMismatch(fname); exit(ExportMeasurements) end; FNFerr: begin err := create(fname, RefNum, FourCharCode(TextCreator), 'TEXT'); if CheckIO(err) <> 0 then exit(ExportMeasurements); end; otherwise if CheckIO(err) <> 0 then exit(ExportMeasurements) end; ShowWatch; err := fsopen(fname, RefNum, f); if CheckIO(err) <> 0 then exit(ExportMeasurements); FileSize := 0; first := 1; last := LinesPerPass; repeat if last > mCount then last := mCount; CopyResultsToBuffer(first, last, ShowHeadings or OptionKeyWasDown); ByteCount := TextBufSize; err := fswrite(f, ByteCount, ptr(TextBufP)); FIleSize := FileSize + ByteCount; if (CheckIO(err) <> 0) or CommandPeriod or (last = mCount) then leave; first := first + LinesPerPass; last := last + LinesPerPass; until false; err := SetEof(f, FileSize); err := fsclose(f); err := FlushVol(nil, RefNum); UnsavedResults := false; end; procedure Swap2Bytes (var i: integer); type atype = packed array[1..2] of char; var a: atype; c: char; begin a := atype(i); c := a[1]; a[1] := a[2]; a[2] := c; i := integer(a) end; procedure Swap4Bytes (var i: LongInt); var a: ostype; c: char; begin a := ostype(i); c := a[1]; a[1] := a[4]; a[4] := c; c := a[2]; a[2] := a[3]; a[3] := c; i := LongInt(a) end; function OpenTiffHeader (f: integer; var DirOffset: LongInt): boolean; var TiffHeader: TiffHdr; ByteCount: LongInt; err: OSErr; begin ByteCount := 8; err := SetFPos(f, fsFromStart, 0); err := fsread(f, ByteCount, @TiffHeader); if CheckIO(err) <> NoErr then begin OpenTiffHeader := false; exit(OpenTiffHeader); end; with TiffHeader do begin IntelByteOrder := ByteOrder = 'II'; if (ByteOrder <> 'MM') and (ByteOrder <> 'II') then begin PutError('Invalid TIFF header.'); OpenTiffHeader := false; exit(OpenTiffHeader) end; DirOffset := FirstIFDOffset; if IntelByteOrder then Swap4Bytes(DirOffset); OpenTiffHeader := true; end; end; procedure GetTiffEntry (f: integer; var tag: integer; var N, value: LongInt); var IFDEntry: TiffEntry; ByteCount: LongInt; IntValue: integer; err: OSErr; str: str255; begin ByteCount := 12; err := FSRead(f, ByteCount, @IFDEntry); with IFDEntry do begin tag := TagField; N := length; if IntelByteOrder then begin Swap2Bytes(tag); Swap2Bytes(ftype); Swap4Bytes(N); end; value := offset; if (ftype = short) and (N = 1) then begin value := bsr(value, 16); if IntelByteOrder then begin IntValue := value; Swap2Bytes(IntValue); value := IntValue end end else if IntelByteOrder then Swap4Bytes(value); if OptionKeyWasDown then begin gstr := concat(gstr, long2str(tag), ' ', long2str(ftype), ' ', long2str(N), ' ', long2str(value), crStr); ShowMessage(gstr); end; end; end; function OpenTiffDirectory (f: integer; DirOffset: LongInt; var TiffInfo: TiffInfoRec; Importing: boolean): boolean; const NoUnit = 1; inch = 2; centimeter = 3; var ByteCount, length, ftype, N, value, BytesPerStrip, SaveFPos: LongInt; err: OSErr; nEntries, i, tag, entry: integer; StripOffsetsArray: array[1..2] of LongInt; xRes, yRes: extended; function GetResolution: extended; var resolution: array[1..2] of LongInt; begin err := GetFPos(f, SaveFPos); err := SetFPos(f, fsFromStart, value); ByteCount := 8; err := fsread(f, ByteCount, @Resolution); if IntelByteOrder then begin Swap4Bytes(Resolution[1]); Swap4Bytes(Resolution[2]); end; err := SetFPos(f, fsFromStart, SaveFPos); if resolution[2] <> 0 then GetResolution := resolution[1] / resolution[2] else GetResolution := 0.0; end; begin if OptionKeyWasDown then gstr := ''; xRes := 0.0; err := SetFPos(f, fsFromStart, DirOffset); ByteCount := 2; err := FSRead(f, ByteCount, @nEntries); if CheckIO(err) <> NoErr then begin OpenTiffDirectory := false; exit(OpenTiffDirectory); end; if IntelByteOrder then Swap2Bytes(nEntries); with TiffInfo do begin width := 0; height := 0; BitsPerPixel := 8; SamplesPerPixel:=1; PlanarConfig := 1; OffsetToData := 0; Resolution := 0.0; ResUnits := tNoUnits; OffsetToColorMap := 0; OffsetToImageHeader := -1; StripOffsetsArray[1] := 0; for entry := 1 to nEntries do begin GetTiffEntry(f, tag, N, value); if tag = 0 then begin PutError('Invalid TIFF format.'); OpenTiffDirectory := false; exit(OpenTiffDirectory) end; case tag of ImageWidth: width := value; ImageLength: height := value; BitsPerSample: begin if N = 1 then BitsPerPixel := value; if value = 1 then begin PutError('NIH Image cannot open 1-bit TIFF files.'); OpenTiffDirectory := false; exit(OpenTiffDirectory) end; if (value = 16) and not importing then begin PutError('Use Import to open 16-bit TIFF files.'); OpenTiffDirectory := false; exit(OpenTiffDirectory) end; end; SamplesPerPixelTag: if (value = 1) or (value = 3) then SamplesPerPixel:=value else begin PutError('NIH Image can only open TIFF files with 1 or 3 samples per pixel.'); OpenTiffDirectory := false; exit(OpenTiffDirectory) end; PlanarConfigTag: PlanarConfig := value; Compression: if value <> 1 then begin PutError('NIH Image cannot open compressed TIFF files.'); OpenTiffDirectory := false; exit(OpenTiffDirectory) end; PhotoInterp: ZeroIsBlack := value = 1; StripOffsets: if N = 1 then OffsetToData := value else begin err := GetFPos(f, SaveFPos); err := SetFPos(f, fsFromStart, value); ByteCount := 8; err := fsread(f, ByteCount, @StripOffsetsArray); if IntelByteOrder then begin Swap4Bytes(StripOffsetsArray[1]); Swap4Bytes(StripOffsetsArray[2]); end; err := SetFPos(f, fsFromStart, SaveFPos); end; RowsPerStrip: if (OffsetToData=0) and (value < height) then begin BytesPerStrip := value * width; if BitsPerPixel = 16 then BytesPerStrip := BytesPerStrip * 2 else if SamplesPerPixel = 3 then BytesPerStrip := BytesPerStrip * 3; if StripOffsetsArray[1] = 0 then begin PutError('Invalid TIFF directory.'); OpenTiffDirectory := false; exit(OpenTiffDirectory) end; if StripOffsetsArray[2] <> (StripOffsetsArray[1] + BytesPerStrip) then begin PutError('NIH Image cannot open TIFF files with discontiguous strips.'); OpenTiffDirectory := false; exit(OpenTiffDirectory) end; OffsetToData := StripOffsetsArray[1]; end; XResolution: XRes := GetResolution; YResolution: begin yRes := GetResolution; if (xRes = yRes) and (xRes > 0.0) then begin resolution := xRes; ResUnits := tInches; end; end; ResolutionUnit: case value of NoUnit: ResUnits := tNoUnits; Centimeter: ResUnits := tCentimeters; otherwise end; ColorMapTag: if N = 768 then OffsetToColorMap := value; ImageHdrTag: OffsetToImageHeader := value; otherwise end; end; {for} if OffsetToData = 0 then OffsetToData := StripOffsetsArray[1]; ByteCount := 4; err := FSRead(f, ByteCount, @NextIFD); if IntelByteOrder then Swap4Bytes(NextIFD); if OptionKeyWasDown then begin gstr := concat(gstr, 'Next IFD=', long2str(NextIFD)); ShowMessage(gstr); end; if width = 0 then begin PutError('Error opening TIFF directory'); OpenTiffDirectory := false; exit(OpenTiffDirectory) end; end; {with} OpenTiffDirectory := true; end; procedure SaveTiffColorMap (f: integer; ImageDataSize: LongInt); var i: integer; err: OSErr; ColorMap: TiffColorMapType; ColorMapSize: LongInt; begin LoadLUT(info^.cTable); if ScreenDepth=8 then begin for i := 0 to 255 do with cScreenPort^.portPixMap^^.pmTable^^.ctTable[i].rgb do begin ColorMap[1, i] := red; ColorMap[2, i] := green; ColorMap[3, i] := blue; end; end else begin for i := 0 to 255 do with info^.cTable[i].rgb do begin ColorMap[1, i] := red; ColorMap[2, i] := green; ColorMap[3, i] := blue; end; end; err := SetFPos(f, FSFromStart, HeaderSize + TiffDirSize + ImageDataSize); ColorMapSize := SizeOf(ColorMap); err := fswrite(f, ColorMapSize, @ColorMap); if CheckIO(err) <> 0 then beep; end; procedure GetTiffColorMap (f: integer); var i: integer; ByteCount: LongInt; err: OSErr; ColorMap: TiffColorMapType; begin with info^ do begin ByteCount := SizeOf(ColorMap); err := SetFPos(f, fsFromStart, ColorMapOffset); err := fsRead(f, ByteCount, @ColorMap); if err = NoErr then begin if IntelByteOrder then for i := 0 to 255 do begin Swap2Bytes(ColorMap[1, i]); Swap2Bytes(ColorMap[2, i]); Swap2Bytes(ColorMap[3, i]); end; for i := 0 to 255 do with cTable[i].rgb do begin red := ColorMap[1, i]; green := ColorMap[2, i]; blue := ColorMap[3, i]; end; LoadLUT(cTable); LUTMode := ColorLut; SetupPseudocolor; IdentityFunction := false; if isGrayScaleLUT then begin info^.LutMode := CustomGrayScale; DrawMap; end; end else beep; end;{with} end; function SaveTiffDir (f, slines, sPixelsPerLine: integer; SavingSelection: boolean; ctabSize, ImageDataSize: LongInt): OSErr; var i: integer; err: OSErr; SavingStack, SavingRGBStack: boolean; ByteCount, width, height: LongInt; TiffInfo1: record Header: TiffHdr; {8} nEntries: integer; {2} TiffDir: array[1..9] of TiffEntry; {108} end; ColorMapEntry: TiffEntry; {12 (Optional)} TiffInfo2: record ImageHdrEntry: TiffEntry; {12} NextIFD: LongInt; {4} BitsPerPixelData: array[1..3] of integer; {6} {only used for RGB files} filler: array[1..TiffFillerSize] of integer; {116} end; BitsPerSampleData: record rBitsPerSample, gBitsPerSample, bBitsPerSample:integer; end; begin with info^ do begin SavingStack := false; SavingRGBStack := false; if StackInfo <> nil then SavingStack := StackInfo^.nSlices > 1; if SavingStack then if (StackInfo^.StackType = rgbStack) and (StackInfo^.nSlices = 3) then begin SavingRGBStack := true; ctabSize := 0; end; if SavingSelection then begin width := sPixelsPerLine; height := sLines end else begin width := PixelsPerLine; height := nLines end; with TiffInfo1 do begin with header do begin ByteOrder := 'MM'; Version := 42; FirstIFDOffset := 8; end; if ctabSize > 0 then nEntries := 11 else nEntries := 10; for i := 1 to 9 do with TiffDir[i] do begin ftype := 3; length := 1 end; with TiffDir[1] do begin TagField := NewSubfileType; ftype := 4; offset := 0; end; with TiffDir[2] do begin TagField := ImageWidth; offset := bsl(width, 16); end; with TiffDir[3] do begin TagField := ImageLength; offset := bsl(height, 16); end; with TiffDir[4] do begin TagField := BitsPerSample; if SavingRGBStack then begin ftype := 3; length := 3; offset := SizeOf(TiffInfo1) + SizeOf(TiffEntry) + SizeOf(LongInt); with TiffInfo2 do for i := 1 to 3 do BitsPerPixelData[i] := 8; end else begin offset := bsl(8, 16); with TiffInfo2 do for i := 1 to 3 do BitsPerPixelData[i] := 0; end; end; with TiffDir[5] do begin TagField := PhotoInterp; if SavingRGBStack then offset := bsl(2, 16) else if ctabSize > 0 then offset := bsl(3, 16) else offset := 0; end; with TiffDir[6] do begin TagField := StripOffsets; ftype := 4; offset := TiffDirSize + HeaderSize; end; with TiffDir[7] do begin TagField := SamplesPerPixelTag; if SavingRGBStack then offset := bsl(3, 16) else offset := bsl(1, 16); end; with TiffDir[8] do begin TagField := RowsPerStrip; offset := bsl(height, 16); end; with TiffDir[9] do begin TagField := StripByteCount; ftype := 4; if SavingRGBStack then offset := width * height * 3 else offset := width * height; end; end; ByteCount := SizeOf(TiffInfo1); err := SetFPos(f, FSFromStart, 0); err := FSWrite(f, ByteCount, @TiffInfo1); if CheckIO(err) <> NoErr then begin SaveTiffDir := err; exit(SaveTiffDir); end; if ctabSize > 0 then with ColorMapEntry do begin TagField := ColorMapTag; ftype := 3; length := 768; offset := HeaderSize + TiffDirSize + ImageDataSize; ByteCount := SizeOf(ColorMapEntry); err := FSWrite(f, ByteCount, @ColorMapEntry); if CheckIO(err) <> NoErr then begin SaveTiffDir := err; exit(SaveTiffDir); end; end; with TiffInfo2 do begin with ImageHdrEntry do begin TagField := ImageHdrTag; ftype := 3; length := 256; offset := TiffDirSize; end; NextIFD := 0; if SavingStack then NextIFD := HeaderSize + TiffDirSize + ImageDataSize + ctabSize; for i := 1 to TiffFillerSize do filler[i] := 0; end; end; {with info^} ByteCount := SizeOf(TiffInfo2); err := FSWrite(f, ByteCount, @TiffInfo2); SaveTiffDir := CheckIO(err); end; function WriteExtraTiffIFDs (f: integer; ImageDataSize, cTabSize: LongInt): integer; var IFD, entry: integer; StackIFD: StackIFDType; err: OSErr; IFDoffset, SliceOffset, ByteCount: LongInt; begin with info^, StackInfo^, StackIFD do begin IFDoffset := HeaderSize + TiffDirSize + ImageDataSize + ctabSize; err := SetFPos(f, FSFromStart, IFDoffset); SliceOffset := HeaderSize + TiffDirSize + ImageSize; for IFD := 2 to nSlices do {IFD=Image File Directory} begin nEntries := 6; for entry := 1 to nEntries do with TiffDir[entry] do begin ftype := 3; length := 1 end; with TiffDir[1] do begin TagField := NewSubfileType; ftype := 4; offset := 0; end; with TiffDir[2] do begin TagField := ImageWidth; offset := bsl(PixelsPerLine, 16); end; with TiffDir[3] do begin TagField := ImageLength; offset := bsl(nLines, 16); end; with TiffDir[4] do begin TagField := BitsPerSample; offset := bsl(8, 16); end; with TiffDir[5] do begin TagField := PhotoInterp; offset := 0; end; with TiffDir[6] do begin TagField := StripOffsets; ftype := 4; offset := SliceOffset; end; SliceOffset := SliceOffset + ImageSize; IFDoffset := IFDoffset + SizeOf(StackIFD); if IFD <> nSlices then NextIFD := IFDoffset else NextIFD := 0; ByteCount := SizeOf(StackIFD); err := fswrite(f, ByteCount, @StackIFD); if err <> NoErr then begin WriteExtraTiffIFDs := err; exit(WriteExtraTiffIFDs); end; end; {for} end; {with} WriteExtraTiffIFDs := NoErr; end; procedure SaveLUT (fname: str255; RefNum: integer); var err: integer; TheInfo: FInfo; LUT: array[1..3] of packed array[0..255] of byte; i, f: integer; ByteCount: LongInt; tempRGB:rgbColor; begin err := GetFInfo(fname, RefNum, TheInfo); case err of NoErr: if TheInfo.fdType <> 'ICOL' then begin TypeMismatch(fname); exit(SaveLUT) end; FNFerr: begin err := create(fname, RefNum, 'Imag', 'ICOL'); if CheckIO(err) <> 0 then exit(SaveLUT); end; otherwise if CheckIO(err) <> 0 then exit(SaveLUT); end; DisableDensitySlice; LoadLUT(Info^.cTable); if ScreenDepth = 8 then begin for i := 0 to 255 do with cScreenPort^.portPixMap^^.pmTable^^.ctTable[i].rgb do begin LUT[1, i] := band(bsr(red, 8), 255); LUT[2, i] := band(bsr(green, 8), 255); LUT[3, i] := band(bsr(blue, 8), 255); end; end else begin for i := 0 to 255 do with info^.cTable[i].rgb do begin LUT[1, i] := band(bsr(red, 8), 255); LUT[2, i] := band(bsr(green, 8), 255); LUT[3, i] := band(bsr(blue, 8), 255); end; end; err := fsopen(fname, RefNum, f); if CheckIO(err) <> 0 then exit(SaveLUT); err := SetFPos(f, FSFromStart, 0); ByteCount := SizeOf(LUT); err := fswrite(f, ByteCount, @LUT); if CheckIO(err) <> 0 then begin err := fsclose(f); err := FSDelete(fname, RefNum); exit(SaveLUT) end; err := SetEof(f, ByteCount); err := fsclose(f); err := GetFInfo(fname, RefNum, TheInfo); if TheInfo.fdCreator <> 'Imag' then begin TheInfo.fdCreator := 'Imag'; err := SetFInfo(fname, RefNum, TheInfo); end; err := FlushVol(nil, RefNum); end; procedure SaveColorTable (fname: str255; RefNum: integer); var err: integer; TheInfo: FInfo; i, f: integer; ByteCount: LongInt; hdr: PaletteHeader; begin with info^ do err := GetFInfo(fname, RefNum, TheInfo); case err of NoErr: if TheInfo.fdType <> 'ICOL' then begin TypeMismatch(fname); exit(SaveColorTable) end; FNFerr: begin err := create(fname, RefNum, 'Imag', 'ICOL'); if CheckIO(err) <> 0 then exit(SaveColorTable); end; otherwise if CheckIO(err) <> 0 then exit(SaveColorTable); end; with info^ do begin InitPaletteHeader(hdr); err := fsopen(fname, RefNum, f); if CheckIO(err) <> 0 then exit(SaveColorTable); err := SetFPos(f, FSFromStart, 0); ByteCount := SizeOf(PaletteHeader); if ByteCount <> 32 then PutError('Palette header size <> 32.'); err := fswrite(f, ByteCount, @hdr); ByteCount := nColors; err := fswrite(f, ByteCount, @redLUT); ByteCount := nColors; err := fswrite(f, ByteCount, @greenLUT); ByteCount := nColors; err := fswrite(f, ByteCount, @blueLUT); if CheckIO(err) <> 0 then begin err := fsclose(f); err := FSDelete(fname, RefNum); exit(SaveColorTable) end; err := SetEOF(f, SizeOf(PaletteHeader) + 3 * nColors); err := fsclose(f); err := GetFInfo(fname, RefNum, TheInfo); if TheInfo.fdCreator <> 'Imag' then begin TheInfo.fdCreator := 'Imag'; err := SetFInfo(fname, RefNum, TheInfo); end; err := FlushVol(nil, RefNum); end; {with info^} end; procedure SaveOutline (fname: str255; RefNum: integer); var err: integer; TheInfo: FInfo; i, f: integer; ByteCount, DataSize: LongInt; hdr: RoiHeader; SaveCoordinates: boolean; dX1, dY1, dX2, dY2: extended; begin with info^ do begin if not RoiShowing then begin PutError('No outline available to save.'); exit(SaveOutline); end; if (RoiType = FreeLineRoi) or (RoiType = SegLineRoi) then begin PutError('Freehand and segmented line selections cannot be saved.'); exit(SaveOutline); end; SaveCoordinates := (RoiType = PolygonRoi) or (RoiType = FreehandRoi) or (RoiType = TracedRoi); if SaveCoordinates then if not CoordinatesAvailableMsg then begin exit(SaveOutline); end; err := GetFInfo(fname, RefNum, TheInfo); case err of NoErr: if TheInfo.fdType <> 'Iout' then begin TypeMismatch(fname); exit(SaveOutline) end; FNFerr: begin err := create(fname, RefNum, 'Imag', 'Iout'); if CheckIO(err) <> 0 then exit(SaveOutline); end; otherwise if CheckIO(err) <> 0 then exit(SaveOutline); end; with hdr do begin rID := 'Iout'; rVersion := version; rRoiType := RoiType; rRoiRect := RoiRect; rNCoordinates := nCoordinates; GetLoi(dX1, dY1, dX2, dY2); rX1:=dX1; rY1:=dY1; rX2:=dX2; rY2:=dY2; rLineWidth := LineWidth; for i := 1 to 14 do rUnused[i] := 0; end; err := fsopen(fname, RefNum, f); if CheckIO(err) <> 0 then exit(SaveOutline); err := SetFPos(f, FSFromStart, 0); ByteCount := SizeOf(RoiHeader); if ByteCount <> 64 then PutError('Roi header size <> 32.'); err := fswrite(f, ByteCount, @hdr); if SaveCoordinates then begin ByteCount := nCoordinates * 2; err := fswrite(f, ByteCount, ptr(xCoordinates)); ByteCount := nCoordinates * 2; err := fswrite(f, ByteCount, ptr(yCoordinates)); DataSize := nCoordinates * 4; end else DataSize := 0; if CheckIO(err) <> 0 then begin err := fsclose(f); err := FSDelete(fname, RefNum); exit(SaveOutline) end; err := SetEOF(f, SizeOf(RoiHeader) + DataSize); err := fsclose(f); err := GetFInfo(fname, RefNum, TheInfo); if TheInfo.fdCreator <> 'Imag' then begin TheInfo.fdCreator := 'Imag'; err := SetFInfo(fname, RefNum, TheInfo); end; err := FlushVol(nil, RefNum); end; {with info^} end; procedure OpenOutline (fname: str255; RefNum: integer); var err, f, i: integer; count: LongInt; hdr: RoiHeader; okay: boolean; begin if Info = NoInfo then begin if (NewPicWidth * NewPicHeight) <= UndoBufSize then begin if not NewPicWindow('Untitled', NewPicWidth, NewPicHeight) then exit(OpenOutline) end else begin beep; exit(OpenOutline) end; end; KillRoi; err := fsopen(fname, RefNum, f); with info^, hdr do begin count := SizeOf(RoiHeader); err := fsread(f, count, @hdr); if rID <> 'Iout' then begin err := fsclose(f); PutError('File is corrupted.'); exit(OpenOutline) end; if (rRoiRect.right > PicRect.right) or (rRoiRect.bottom > PicRect.bottom) then begin err := fsclose(f); PutError('Image is too small for the outline.'); exit(OpenOutline) end; case rRoiType of LineRoi: begin LX1 := rX1; LY1 := rY1; LX2 := rX2; LY2 := rY2; RoiType := LineRoi; MakeRegion; SetupUndo; RoiShowing := true; end; RectRoi, OvalRoi: begin RoiType := rRoiType; RoiRect := rRoiRect; MakeRegion; SetupUndo; RoiShowing := true; end; PolygonRoi, FreehandRoi, TracedRoi: if (rNCoordinates > 2) and (rNCoordinates <= MaxCoordinates) then begin count := rNCoordinates * 2; err := fsread(f, count, ptr(xCoordinates)); count := rNCoordinates * 2; err := fsread(f, count, ptr(yCoordinates)); if CheckIO(err) = 0 then begin nCoordinates := rNCoordinates; SelectionMode := NewSelection; if rVersion >= 148 then for i := 1 to nCoordinates do with rRoiRect do begin xCoordinates^[i] := xCoordinates^[i] + left; yCoordinates^[i] := yCoordinates^[i] + top; end; MakeOutline(rRoiType); SetupUndo; end; end; end; end; err := fsclose(f); end; function GetTIFFParameters (name: str255; RefNum: integer; var HasColorMap: boolean): boolean; var err: OSErr; f: integer; DirOffset: LongInt; TiffInfo: TiffInfoRec; begin GetTIFFParameters := false; HasColorMap := false; err := fsopen(name, RefNum, f); if err <> NoErr then exit(GetTIFFParameters); if not OpenTiffHeader(f, DirOffset) then begin err := fsclose(f); exit(GetTIFFParameters) end; if not OpenTiffDirectory(f, DirOffset, TiffInfo, true) then begin err := fsclose(f); exit(GetTIFFParameters) end; with TiffInfo do begin ImportCustomWidth := width; ImportCustomHeight := height; ImportCustomOffset := OffsetToData; ImportAutoScale:=true; if BitsPerPixel = 16 then begin ImportCustomDepth := SixteenBitsUnsigned; ImportSwapBytes := IntelByteOrder; end else begin ImportCustomDepth := EightBits; ImportInvert := ZeroIsBlack; end; HasColorMap := OffsetToColorMap > 0; end; if ImportCustomDepth = EightBits then begin WhatToImport := ImportTiff; WhatToOpen := OpenTiff end else begin WhatToImport := ImportCustom; WhatToOpen := OpenCustom end; err := fsclose(f); GetTIFFParameters := true; end; procedure GetXUnits (UnitsKind: UnitsType); begin with info^ do case UnitsKind of Nanometers: xUnit := 'nm'; Micrometers: xUnit := 'µm'; Millimeters: xUnit := 'mm'; Centimeters: xUnit := 'cm'; Meters: xUnit := 'meter'; Kilometers: xUnit := 'km'; Inches: xUnit := 'inch'; feet: xUnit := 'ft'; Miles: xUnit := 'mile'; Pixels: xUnit := 'pixel'; otherwise ; end; end; procedure GetUnitsKInd (var UnitsKind: UnitsType; var UnitsPerCM: extended); begin with info^ do begin if xunit = 'nm' then begin UnitsKind := Nanometers; UnitsPerCm := 10000000.0; end else if xUnit = 'µm' then begin UnitsKind := Micrometers; UnitsPerCm := 10000.0; end else if xUnit = 'mm' then begin UnitsKind := Millimeters; UnitsPerCm := 10.0; end else if xUnit = 'cm' then begin UnitsKind := Centimeters; UnitsPerCm := 1.0; end else if xUnit = 'meter' then begin UnitsKind := Meters; UnitsPerCm := 0.01; end else if xUnit = 'km' then begin UnitsKind := Kilometers; UnitsPerCm := 0.00001; end else if xUnit = 'inch' then begin UnitsKind := Inches; UnitsPerCm := 0.3937; end else if xUnit = 'ft' then begin UnitsKind := feet; UnitsPerCm := 0.0328083; end else if xUnit = 'mile' then begin UnitsKind := Miles; UnitsPerCm := 0.000006213; end else if xUnit = 'pixel' then begin UnitsKind := pixels; UnitsPerCm := 0.0; SpatiallyCalibrated := false; end else begin UnitsKind := OtherUnits; UnitsPerCm := 0.0; end; end; end; function OpenMovieToolbox:boolean; var result: LongInt; err: OSErr; begin if MovieToolboxInitialized then begin OpenMovieToolbox := true; exit(OpenMovieToolbox); end; if Gestalt(gestaltQuickTime, result) <> noErr then begin ShowMessage('QuickTime Required'); OpenMovieToolbox := false; exit(OpenMovieToolbox); end; err := EnterMovies; if (err <> noErr) then begin PutMessage('QuickTime Required'); OpenMovieToolbox := false; exit(OpenMovieToolbox); end; MovieToolboxInitialized := true; OpenMovieToolbox := true; end; function OpenQuickTime (name: str255; fRefNum: integer; UseExistingLUT: boolean): boolean; {Written 3/25/94 by Eric Shelden (shelden@umich.edu)} const forwardNormalSpeed = $00010000; var RefNum, picID, hOffset, vOffset, nPICS, i: LongInt; err: OSErr; PicH: PicHandle; h: handle; MemError, Aborted: boolean; FrameRect: rect; movieResRefNum, actualResId, verb: integer; theMovie: Movie; theTrack, videoTrack: Track; theMedia: Media; inTime, trackOffset, trackEnd, sampleTime: TimeValue; mySpec: FSSpec; TheInfo: FInfo; fName: Str255; check: Boolean; trackCount, count: LongInt; mediaType, manuf: OSType; imageCTable: CTabHandle; imageDescH: ImageDescriptionHandle; pInfo: PictInfo; creatorName: str255; SavePort: GrafPtr; SaveGDevice: GDHandle; procedure Abort; begin err := CloseMovieFile(movieResRefNum); exit(OpenQuickTime); end; begin OpenQuickTime := false; check := FALSE; sampleTime := 0; if MaxBlock < MinFree then begin PutError('Insufficient memory to open QuickTime movie.'); exit(OpenQuickTime); end; ShowWatch; if not OpenMovieToolbox then exit(OpenQuickTime); err := GetFInfo(name, fRefNum, TheInfo); err := FSMakeFSSpec(fRefNum, 0, name, mySpec); err := OpenMovieFile(mySpec, movieResRefNum, fsRdPerm); if (err <> noErr) then begin PutError('QuickTime Error'); exit(OpenQuickTime); end; actualResId := DoTheRightThing; err := NewMovieFromFile(theMovie, movieResRefNum, actualResId, nil, newMovieActive, check); trackCount := GetMovieTrackCount(theMovie); videoTrack := nil; for i := 1 to trackCount do begin videoTrack := GetMovieIndTrack(theMovie, i); creatorName := ''; GetMediaHandlerDescription(GetTrackMedia(videoTrack), mediaType, creatorName, manuf); if (mediaType = 'vide') then i := trackCount + 1 else videoTrack := nil; end; if (videoTrack = nil) then begin PutError('No Movie Pictures found.'); abort; end; GetMovieBox(theMovie, FrameRect); with FrameRect do begin hOffset := left; vOffset := top; right := right - hOffset; bottom := bottom - vOffset; left := 0; top := 0; end; with FrameRect do if not NewPicWindow(name, right - left, bottom - top) then Abort; with info^ do begin revertable := false; StackInfo := StackInfoPtr(NewPtr(SizeOf(StackInfoRec))); if StackInfo = nil then Abort; with StackInfo^ do begin SliceSpacing := 0.0; nSlices := 1; CurrentSlice := 1; PicBaseH[1] := PicBaseHandle; end; end; trackEnd := GetTrackDuration(videoTrack); trackOffset := GetTrackOffset(videoTrack); inTime := trackOffset; PicH := GetTrackPict(videoTrack, inTime); { verb := returnColorTable; err := GetPictInfo(PicH, pInfo, verb, 256, systemMethod, 0); if not UseExistingLUT then begin LoadColorTable(pInfo.theColorTable); DrawLUT; end; } with info^, Info^.StackInfo^ do begin SaveGDevice := GetGDevice; SetGDevice(osGDevice); GetPort(SavePort); SetPort(GrafPtr(osPort)); IndexToRgbBackColor(WhiteIndex); EraseRect(PicRect); DrawPicture(PicH, PicRect); DisposeHandle(handle(PicH)); UpdatePicWindow; MemError := false; picID := 0; while (inTime <> -1) do begin GetTrackNextInterestingTime(videoTrack, nextTimeMediaSample, inTime, forwardNormalSpeed, inTime, sampleTime); if (inTime = -1) then Leave; picH := GetTrackPict(videoTrack, inTime); if (PicH = nil) or (ResError <> NoErr) then Leave; h := GetBigHandle(PixMapSize); if h = nil then begin if PicH <> nil then DisposeHandle(handle(picH)); MemError := true; Leave; end; nSlices := nSlices + 1; CurrentSlice := CurrentSlice + 1; PicBaseH[CurrentSlice] := h; SelectSlice(CurrentSlice); FrameRect := PicH^^.PicFrame; with FrameRect do begin right := right - hOffset; bottom := bottom - vOffset; left := left - hOffset; top := top - vOffset; end; EraseRect(PicRect); if not EqualRect(FrameRect, PicRect) then BlockMove(PicBaseH[CurrentSlice - 1]^, PicBaseH[CurrentSlice]^, PixMapSize); DrawPicture(picH, FrameRect); DisposeHandle(handle(picH)); UpdatePicWindow; SetGDevice(SaveGDevice); UpdateTitleBar; SetGDevice(osGDevice); Aborted := CommandPeriod; if Aborted then begin beep; wait(60); Leave; end; picID := picID + 1; end; {for} err := CloseMovieFile(movieResRefNum); if MemError then PutError('Not enough memory to open all images in MooV file.'); CurrentSlice := 1; SelectSlice(CurrentSlice); PictureType := PicsFile; Revertable := false; SetPort(SavePort); SetGDevice(SaveGDevice); UpdateTitleBar; UpdateWindowsMenuItem; if not MemError and not Aborted then OpenQuickTime := true; end; {with} end; procedure SaveAsQuickTime (fname: str255; fRefNum: integer); {Written by Eric A. Shelden (shelden@umich.edu) 3/23/94} const rErr = 'Error Saving QuickTime file.'; var err: OSErr; TheInfo: FInfo; replacing: boolean; rRefNum, i, SaveCS: integer; frect: rect; MinFreeRequired: LongInt; theTimeSettings: SCTemporalSettings; theRateSettings: SCDataRateSettings; theSpaceSettings: SCSpatialSettings; myComponentPtr: ptr; framesPerSecond, maxCompressedSize, curSample: longint; myResult: ComponentResult; myComponentInstance: ComponentInstance; mySpec: FSSpec; theSFR: StandardFileReply; resRefNum, resID: integer; theMovie: Movie; movieData: MovieRecord; theTrack: Track; theMedia: Media; trackFrame: Rect; theGWorld: GWorldPtr; compressedData: Handle; compressedDataptr: Ptr; imageDesc: ImageDescriptionHandle; thePixMap: PixMapHandle; check: Boolean; oldPort: CGrafPtr; oldGDeviceH: GDHandle; myTimeScale, actualTime: TimeScale; testflags: integer; begin with info^, Info^.StackInfo^ do begin if ImageSize > MinFree then MinFreeRequired := ImageSize else MinFreeRequired := MinFree; if MaxBlock < MinFreeRequired then begin PutError('Not enough memory available to save in QuickTime format.'); exit(SaveAsQuickTime); end; if not OpenMovieToolbox then exit(SaveAsQuickTime); err := GetFInfo(fname, fRefNum, TheInfo); if err = NoErr then with TheInfo do begin if (fdType <> 'TIFF') and (fdType <> 'PICT') and (fdType <> 'PICS') and (fdType <> 'MooV') then begin TypeMismatch(fname); exit(SaveAsQuickTime) end; err := FSDelete(fname, fRefNum); end; SaveCS := CurrentSlice; SetPort(GrafPtr(osPort)); with PicRect do SetRect(frect, 0, 0, right - left, bottom - top); ClipRect(frect); LoadLUT(ctable); IndexToRgbForeColor(BlackIndex); IndexToRgbBackColor(WhiteIndex); if OldSystem then begin RGBForeColor(BlackRGB); RGBBackColor(WhiteRGB); end; testflags := 0; theGWorld := osPort; thePixMap := GetGWorldPixMap(theGWorld); check := LockPixels(thePixMap); myComponentInstance := OpenDefaultComponent('scdi', 'imag'); {myResult := SCSetTestImagePixMap(myComponentInstance, thePixMap, @frect, testflags);} myResult := SCRequestSequenceSettings(myComponentInstance); if (myResult = 1) then begin myResult := CloseComponent(myComponentInstance); exit(SaveAsQuickTime); end; if (myResult = -50) then begin myResult := CloseComponent(myComponentInstance); PutError('Invalid Parameter detected.'); exit(SaveAsQuickTime); end; myResult := SCGetInfo(myComponentInstance, 'sptl', ptr(@theSpaceSettings)); myResult := SCGetInfo(myComponentInstance, scTemporalSettingsType, ptr(@theTimeSettings)); myResult := SCGetInfo(myComponentInstance, scDataRateSettingsType, ptr(@theRateSettings)); myResult := CloseComponent(myComponentInstance); UnlockPixels(thePixMap); framesPerSecond := longint(theTimeSettings.frameRate); framesPerSecond := framesPerSecond div 65536; resRefNum := 0; theMovie := nil; ShowWatch; err := FSMakeFSSpec(fRefNum, 0, fname, mySpec); err := CreateMovieFile(mySpec, 'TVOD', $FE, createMovieFileDeleteCurFile, resRefNum, theMovie); if (err <> 0) then begin PutError(rErr); exit(SaveAsQuickTime); end; trackFrame := fRect; theTrack := NewMovieTrack(theMovie, FixRatio(trackFrame.right, 1), FixRatio(trackFrame.bottom, 1), kNoVolume); theMedia := NewTrackMedia(theTrack, 'vide', TimeScale(60), nil, ' '); err := BeginMediaEdits(theMedia); check := LockPixels(thePixMap); err := GetMaxCompressionSize(thePixMap, trackFrame, theSpaceSettings.depth, theSpaceSettings.spatialQuality, theSpaceSettings.codecType, CompressorComponent(theSpaceSettings.codec), maxCompressedSize); compressedData := NewHandle(maxCompressedSize); if (compressedData = nil) or (MemError <> 0) then begin err := EndMediaEdits(theMedia); if (theMovie <> Movie(0)) then begin err := CloseMovieFile(resRefNum); DisposeMovie(theMovie); PutError(rErr); exit(SaveAsQuickTime); end; end; MoveHHi(compressedData); HLock(compressedData); compressedDataPtr := StripAddress(compressedData^); imageDesc := ImageDescriptionHandle(NewHandle(4)); myTimeScale := 60 div framesPerSecond; GetGWorld(oldPort, oldGDeviceH); SetGWorld(theGWorld, nil); for i := 1 to nSlices do begin CurrentSlice := i; SelectSlice(CurrentSlice); err := CompressImage(thePixMap, trackFrame, theSpaceSettings.spatialQuality, theSpaceSettings.codecType, imageDesc, compressedDataPtr); err := AddMediaSample(theMedia, compressedData, 0, imageDesc^^.dataSize, myTimeScale, SampleDescriptionHandle(imageDesc), 1, 0, actualTime); end; UnlockPixels(thePixMap); SetGWorld(oldPort, oldGDeviceH); if (imageDesc <> nil) then DisposeHandle(Handle(imageDesc)); if (compressedData <> nil) then DisposeHandle(Handle(compressedData)); err := EndMediaEdits(theMedia); err := InsertMediaIntoTrack(theTrack, 0, 0, GetMediaDuration(theMedia), fixed1); err := AddMovieResource(theMovie, resRefNum, resID, fname); if (resRefNum <> 0) then err := CloseMovieFile(resRefNum); DisposeMovie(theMovie); CurrentSlice := SaveCS; SelectSlice(CurrentSlice); title := fname; PictureType := PicsFile; UpdateTitleBar; UpdateWindowsMenuItem; IndexToRgbForeColor(ForegroundIndex); IndexToRgbBackColor(BackgroundIndex); end; {with} end; end.