DIRECTORY AIS USING [CloseFile], Atom USING [GetPName], BasicTime USING [GMT], BiScrollers USING [BiScroller, ClientCoords, ClientDataOfViewer, QuaBiScroller], Convert USING [RopeFromReal], FS USING [Error], FunctionCache USING [Cache, CompareProc, GlobalCache, Insert, Lookup], Geom2D USING [ExtremaOfRect, id, Transform, Rect, Vec], GriffinImageUtils USING [GriffinToImagerCalls], Imager USING [black, ClipRectangle, Color, ConcatT, Context, Error, MaskBox, MaskRectangle, MaskVector, Scale2T, ScaleT, SetColor, SetSampledColor, SetStrokeJoint, SetStrokeWidth, TranslateT, DoSaveAll], ImagerArtwork USING [PasteArtwork, Points], ImagerBackdoor USING [DrawBits, MakeStipple], ImagerInterpress USING [Close, Create, DoPage, Ref], ImagerMemory USING [GetContextSize, NewMemoryContext, Replay], ImagerPixelMap USING [DeviceRectangle, PixelMap, Window], ImagerTransformation USING [PostTranslate, Rectangle, Scale, Transformation, TransformRectangle], InputFocus USING [GetInputFocus, SetInputFocus], Interpress USING [DoPage], IO USING [PutFR], MessageWindow USING [Append, Blink], PDFileReader USING [Close, Handle], PDImageReader USING [Handle, InterpretImage, ResetToImage], PreView USING [AISData, AISState, BBoxOp, bsStyle, Data, GData, IPData, IPLogError, PaintOp, PDData, PressData, PVFeedback, PVListRemove, ResetProcess], PrincOpsUtils USING [], Process USING [GetCurrent], Real USING [LargestNumber], Rope USING [Concat, ROPE], SafeStorage USING [ReclaimCollectibleObjects], ShowPress USING [Close, DrawPressPage, Handle, ShowPressError], ViewerClasses USING [DestroyProc, GetProc, NotifyProc, PaintProc, Viewer], ViewerGroupLocks USING [CallRootUnderWriteLock], ViewerLocks USING [Wedged], ViewerPrivate USING [PaintClient]; PreViewImpl: CEDAR MONITOR IMPORTS AIS, Atom, BiScrollers, Convert, FS, FunctionCache, Geom2D, GriffinImageUtils, Imager, ImagerArtwork, ImagerBackdoor, ImagerInterpress, ImagerMemory, ImagerPixelMap, ImagerTransformation, Interpress, InputFocus, IO, MessageWindow, PDFileReader, PDImageReader, PreView, Process, Rope, SafeStorage, ShowPress, ViewerGroupLocks, ViewerLocks, ViewerPrivate EXPORTS PreView = BEGIN PProc: TYPE = PROC [Imager.Context]; Data: TYPE = PreView.Data; PressData: TYPE = PreView.PressData; PDData: TYPE = PreView.PDData; IPData: TYPE = PreView.IPData; AISData: TYPE = PreView.AISData; GData: TYPE = PreView.GData; CacheKey: TYPE = REF CacheKeyRep; CacheKeyRep: TYPE = RECORD [ fileName: Rope.ROPE, created: BasicTime.GMT, pageNumber: INTEGER ]; globalCache: FunctionCache.Cache _ FunctionCache.GlobalCache[]; screenResolution: REAL = 72.0; -- points per inch pointsPerInch: REAL = 72.0; pointsPerMica: REAL = 72.0/2540.0; micasPerPoint: REAL = 2540.0/72.0; pointsPerMeter: REAL = 72.0/.0254; metersPerPoint: REAL = .0254/72.0; grey: CARDINAL _ 122645B; xorStipple: Imager.Color = ImagerBackdoor.MakeStipple[stipple: grey, xor: TRUE]; borderWidth: REAL _ 2.0; fudge: REAL _ 2.0; messageWindowFeedback: BOOLEAN _ FALSE; Message: PROC [x, y: REAL] = { MessageWindow.Append[Convert.RopeFromReal[x], TRUE]; MessageWindow.Append[", ", FALSE]; MessageWindow.Append[Convert.RopeFromReal[y], FALSE]; }; PVNotify: PUBLIC ViewerClasses.NotifyProc = {-- [self: Viewer, input: LIST OF REF ANY] ENABLE UNWIND => NULL; mouseX, mouseY: REAL _ 0.0; data: Data _ NARROW[BiScrollers.ClientDataOfViewer[self]]; FOR list: LIST OF REF ANY _ input, list.rest UNTIL list = NIL DO WITH list.first SELECT FROM x: ATOM => SELECT x FROM $Abort => { IF data.bBox.active THEN PVFeedback[data: data, v: self, op: remove]; -- remove grey bbox. data.bBox^ _ []; -- initialization default values cancel current clipping rectangle }; $Move => { IF InputFocus.GetInputFocus[].owner#self THEN InputFocus.SetInputFocus[self]; IF data.bBox.mode = waitingForFirstPoint THEN { data.bBox.mode _ waitingForSecondPoint; data.bBox.x0 _ mouseX; data.bBox.y0 _ mouseY; data.bBox.active _ TRUE; }; data.bBox.rect _ [x: MIN[mouseX, data.bBox.x0], y: MIN[mouseY, data.bBox.y0], w: ABS[mouseX-data.bBox.x0], h: ABS[mouseY-data.bBox.y0]]; PVFeedback[data: data, v: self, op: change, x: mouseX, y: mouseY]; -- repaint grey bbox. }; $EndMove => IF data.bBox.active THEN MessageWindow.Append[ message: IO.PutFR["Selection = [x: %g, y: %g, w: %g, h: %g] inches", [real[data.bBox.rect.x/pointsPerInch]], [real[data.bBox.rect.y/pointsPerInch]], [real[data.bBox.rect.w/pointsPerInch]], [real[data.bBox.rect.h/pointsPerInch]]], clearFirst: TRUE] ELSE MessageWindow.Append["No selection", TRUE]; ENDCASE => NULL; z: BiScrollers.ClientCoords => { --TYPE = REF Vec mouseX _ z.x; -- mouseX in BiScroller coords mouseY _ z.y; -- mouseY in BiScroller coords IF messageWindowFeedback THEN Message[mouseX, mouseY]; }; ENDCASE => ERROR; ENDLOOP; }; PVFeedback: PUBLIC PROC [data: Data, v: ViewerClasses.Viewer, x, y: REAL _ 0.0, op: PreView.PaintOp _ paint] = { Action: PROC [context: Imager.Context] = { -- this context in viewer coords Show: PROC [x1, y1, x2, y2: REAL] = { rect: ImagerTransformation.Rectangle; IF x1 > x2 THEN {t: REAL _ x2; x2 _ x1; x1 _ t}; IF y1 > y2 THEN {t: REAL _ y2; y2 _ y1; y1 _ t}; rect _ ImagerTransformation.TransformRectangle[m: ctv, r: [x: x1, y: y1, w: x2-x1, h: y2-y1]]; x1 _ rect.x; y1 _ rect.y; x2 _ rect.x+rect.w; y2 _ rect.y+rect.h; Imager.MaskRectangle[context, [x1-5.0, y1-5.0, 5.0, y2-y1+10.0]]; -- left side Imager.MaskRectangle[context, [x2, y1-5.0, 5.0, y2-y1+10.0]]; -- right side Imager.MaskRectangle[context, [x1, y1-5.0, x2-x1, 5.0]]; -- top side Imager.MaskRectangle[context, [x1, y2, x2-x1, 5.0]]; -- bottom side }; IF data.bBox.lastX=x AND data.bBox.lastY=y AND op#paint THEN RETURN; -- no change Imager.SetColor[context, xorStipple]; SELECT op FROM paint => { Show[data.bBox.rect.x, data.bBox.rect.y, data.bBox.rect.x+data.bBox.rect.w, data.bBox.rect.y+data.bBox.rect.h]; }; remove => { Show[data.bBox.lastX, data.bBox.lastY, data.bBox.x0, data.bBox.y0]; --remove the old box data.bBox.lastX _ data.bBox.lastY _ Real.LargestNumber; }; change => { IF data.bBox.lastX#Real.LargestNumber THEN Show[data.bBox.lastX, data.bBox.lastY, data.bBox.x0, data.bBox.y0]; --remove the old box Show[x, y, data.bBox.x0, data.bBox.y0]; -- to show the new box data.bBox.lastX _ x; data.bBox.lastY _ y; }; ENDCASE => ERROR; }; ctv: ImagerTransformation.Transformation _ PreView.bsStyle.GetTransforms[BiScrollers.QuaBiScroller[v]].clientToViewer; DirectPaint[viewer: v, action: Action]; }; DoFileOps: PUBLIC PROC [op: PreView.BBoxOp, viewer: ViewerClasses.Viewer, data: Data, fileName: Rope.ROPE, clip: BOOL _ TRUE] = { ctv: ImagerTransformation.Transformation _ PreView.bsStyle.GetTransforms[BiScrollers.QuaBiScroller[viewer]].clientToViewer; rectV: ImagerTransformation.Rectangle _ ImagerTransformation.TransformRectangle[m: ctv, r: [x: data.bBox.rect.x, y: data.bBox.rect.y, w: data.bBox.rect.w, h: data.bBox.rect.h]]; SELECT op FROM stuff => { -- stuff requires clip to be TRUE and bBox valid DoStuff: PROC [context: Imager.Context] = { DoIt: PROC = { context.ConcatT[ctv]; DoPainting[context: context, data: data, viewer: viewer]; }; context.TranslateT[t: [-rectV.x, -rectV.y]]; Imager.DoSaveAll[context, DoIt]; IF data.stuffWithBorders THEN { context.SetStrokeWidth[borderWidth]; context.SetColor[Imager.black]; context.MaskVector [ [rectV.x, rectV.y], [rectV.x, rectV.y+rectV.h] ]; -- left side context.MaskVector [ [rectV.x, rectV.y], [rectV.x+rectV.w, rectV.y] ]; -- bottom context.MaskVector [ [rectV.x+rectV.w, rectV.y], [rectV.x+rectV.w, rectV.y+rectV.h] ]; -- right side context.MaskVector [ [rectV.x, rectV.y+rectV.h], [rectV.x+rectV.w, rectV.y+rectV.h] ]; -- top }; }; ImagerArtwork.PasteArtwork[action: DoStuff, bounds: [0, 0, rectV.w, rectV.h], m: ImagerArtwork.Points[], clip: TRUE, fit: data.stuffWithFit]; }; ipMaster => { DoIPMaster: PROC [context: Imager.Context] = { context.ScaleT[metersPerPoint]; IF clip THEN { context.TranslateT[t: [-rectV.x, -rectV.y]]; context.ClipRectangle[rectV]; }; context.ConcatT[ctv]; DoPainting[context: context, data: data, viewer: viewer]; }; r: ImagerInterpress.Ref _ ImagerInterpress.Create[fileName: fileName ! FS.Error => { MessageWindow.Append[message: error.explanation, clearFirst: TRUE]; GOTO Quit; };]; ImagerInterpress.DoPage[self: r, action: DoIPMaster ! Imager.Error => { MessageWindow.Append[message: Rope.Concat[error.explanation, " creating IPMaster"], clearFirst: TRUE]; CONTINUE;};]; ImagerInterpress.Close[r]; EXITS Quit => NULL; }; ENDCASE; }; DirectPaint: PROC [viewer: ViewerClasses.Viewer, action: PProc] = { CallLocked: PROC = { ViewerPrivate.PaintClient[viewer, action ! ABORTED => CONTINUE] }; IF viewer = NIL OR viewer.destroyed OR viewer.paintingWedged THEN RETURN; ViewerGroupLocks.CallRootUnderWriteLock[CallLocked, viewer ! ViewerLocks.Wedged => {viewer.paintingWedged _ TRUE; CONTINUE}]; }; DoPainting: PROC [context: Imager.Context, data: Data, viewer: ViewerClasses.Viewer] = { data.abort _ FALSE; -- need this to clean up any PD abort bits that were set before opening the viewer WITH data SELECT FROM ipData: IPData => PaintIP[context: context, ipData: ipData]; --clobbers context variables, but that is OK pressData: PressData => PaintPress[context: context, pressData: pressData]; pdData: PDData => PaintPD[context: context, pdData: pdData, viewer: viewer]; aisData: AISData => PaintAIS[context: context, aisData: aisData]; gData: GData => PaintGriffin[context: context, gData: gData]; ENDCASE => ERROR; data.abort _ FALSE; --just in case you returned here due to data.abort set while PD painting }; PaintIP: PROC [context: Imager.Context, ipData: IPData] = { SELECT TRUE FROM ipData.switches['M] => { -- M switch means use no ImagerMemory context.SetColor[Imager.black]; context.ScaleT[pointsPerMeter]; -- establish IP coord system Interpress.DoPage[master: ipData.ipMaster, page: ipData.pageNumber, context: context, log: PreView.IPLogError]; }; ipData.pageInMem=ipData.pageNumber => { -- iMemContext is current ImagerMemory.Replay[c: ipData.iMemContext, into: context]; }; ipData.pageInMem#ipData.pageNumber => { -- memory context may be cached PageCompareProc: FunctionCache.CompareProc = { RETURN[NARROW[argument, CacheKey]^=cacheKey^]; }; cacheKey: CacheKey _ NEW[CacheKeyRep _ [ipData.fileInfo.fullFName, ipData.fileInfo.created, ipData.pageNumber]]; IF (ipData.iMemContext _ NARROW[FunctionCache.Lookup[x: globalCache, compare: PageCompareProc, clientID: $PVPage].value, Imager.Context])#NIL THEN { --hit ImagerMemory.Replay[c: ipData.iMemContext, into: context]; ipData.pageInMem _ ipData.pageNumber; } ELSE { -- miss ipData.iMemContext _ ImagerMemory.NewMemoryContext[]; ipData.iMemContext.SetColor[Imager.black]; ipData.iMemContext.ScaleT[pointsPerMeter]; -- establish IP coord system Interpress.DoPage[master: ipData.ipMaster, page: ipData.pageNumber, context: ipData.iMemContext, log: PreView.IPLogError]; FunctionCache.Insert[x: globalCache, argument: cacheKey, value: ipData.iMemContext, size: ImagerMemory.GetContextSize[ipData.iMemContext], clientID: $PVPage]; ipData.pageInMem _ ipData.pageNumber; ImagerMemory.Replay[c: ipData.iMemContext, into: context]; }; }; ENDCASE => NULL; }; PaintPress: PROC [context: Imager.Context, pressData: PressData] = { context.SetColor[Imager.black]; context.ScaleT[pointsPerMica]; -- establish Press coord system ShowPress.DrawPressPage[context: context, show: pressData.presshandle, pageNumber: pressData.pageNumber ! ShowPress.ShowPressError => { SELECT code FROM $NoSuchPage => {IF pressData.pageNumber > 0 THEN {pressData.pageNumber _ pressData.pageNumber-1; RETRY};}; ENDCASE => { MessageWindow.Append[Atom.GetPName[code], TRUE]; MessageWindow.Blink[]; CONTINUE; }; } ]; }; PaintPD: PROC [context: Imager.Context, pdData: PDData, viewer: ViewerClasses.Viewer] = { PaintIt: PROC [self: ViewerClasses.Viewer, whatChanged: REF ANY] = { pdData: PDData _ NARROW[BiScrollers.ClientDataOfViewer[self]]; WITH whatChanged SELECT FROM handle: PDImageReader.Handle => { t: ImagerPixelMap.PixelMap = handle.pixelMap; w: ImagerPixelMap.DeviceRectangle = ImagerPixelMap.Window[t]; IF w.sSize > 0 THEN { context.SetColor[Imager.black]; ImagerBackdoor.DrawBits[context: context, base: handle.pixelMap.refRep.pointer, wordsPerLine: handle.pixelMap.refRep.rast, sMin: t.sMin, fMin: t.fMin, fSize: t.fSize, sSize: t.sSize, tx: w.fMin, ty: pdData.pdhandle.herald.imageSSize-w.sMin+w.sSize]; }; }; ENDCASE => ERROR; }; IF pdData.scalePD THEN context.Scale2T[pdData.scaleFactors]; -- do this only once (outside of paintAction) IF PDImageReader.ResetToImage[pdData: pdData]#NIL THEN IF NOT pdData.abort THEN [] _ PDImageReader.InterpretImage[handle: pdData.pdhandle, viewer: viewer, paintAction: PaintIt]; --this guy eventually calls PaintIt. }; PaintAIS: PROC [context: Imager.Context, aisData: AISData] = { state: PreView.AISState _ aisData.state; IF state.active THEN { Imager.SetSampledColor[context: context, m: ImagerTransformation.Scale[1.0], pa: state.pa, colorOperator: state.op]; Imager.MaskBox[context, [0,0, state.pixels, state.scans]]; }; }; PaintGriffin: PROC [context: Imager.Context, gData: GData] = { SELECT TRUE FROM gData.switches['M] => { -- M switch means use no ImagerMemory context.ScaleT[pointsPerMica]; -- establish Griffin coord. system context.SetStrokeJoint[round]; -- avoid miter problems GriffinImageUtils.GriffinToImagerCalls[context, gData.image]; }; gData.pageInMem=gData.pageNumber => { -- iMemContext is current ImagerMemory.Replay[c: gData.iMemContext, into: context]; }; gData.pageInMem#gData.pageNumber => { -- memory context may be cached PageCompareProc: FunctionCache.CompareProc = { RETURN[NARROW[argument, CacheKey]^=cacheKey^]; }; cacheKey: CacheKey _ NEW[CacheKeyRep _ [gData.fileInfo.fullFName, gData.fileInfo.created, gData.pageNumber]]; IF (gData.iMemContext _ NARROW[FunctionCache.Lookup[x: globalCache, compare: PageCompareProc, clientID: $PVPage].value, Imager.Context])#NIL THEN { --hit ImagerMemory.Replay[c: gData.iMemContext, into: context]; gData.pageInMem _ gData.pageNumber; } ELSE { -- miss gData.iMemContext _ ImagerMemory.NewMemoryContext[]; gData.iMemContext.ScaleT[pointsPerMica]; -- establish Griffin coord. system gData.iMemContext.SetStrokeJoint[round]; -- avoid miter problems GriffinImageUtils.GriffinToImagerCalls[gData.iMemContext, gData.image]; FunctionCache.Insert[x: globalCache, argument: cacheKey, value: gData.iMemContext, size: ImagerMemory.GetContextSize[gData.iMemContext], clientID: $PVPage]; gData.pageInMem _ gData.pageNumber; ImagerMemory.Replay[c: gData.iMemContext, into: context]; }; }; ENDCASE => NULL; }; PVPaint: PUBLIC ENTRY ViewerClasses.PaintProc = TRUSTED { ENABLE UNWIND => NULL; data: Data _ NARROW[BiScrollers.ClientDataOfViewer[self]]; data.process _ Process.GetCurrent[]; DoPainting[context: context, data: data, viewer: self ! UNWIND => PreView.ResetProcess[data]]; IF data.bBox.active THEN PreView.PVFeedback[data: data, v: self, op: paint ! UNWIND => PreView.ResetProcess[data]]; PreView.ResetProcess[data]; -- this call is to a PreViewTool ENTRY PROC so it is synchronized with PreViewTool.StopIfYouCan }; PVDestroy: PUBLIC ENTRY ViewerClasses.DestroyProc = { ENABLE UNWIND => NULL; data: Data _ NARROW[BiScrollers.ClientDataOfViewer[self]]; PreView.PVListRemove[ref: data]; WITH data SELECT FROM ipData: IPData => { ipData.ipMaster _ NIL; -- Interpress.Close doesn't exist }; pressData: PressData => { ShowPress.Close[pressData.presshandle]; pressData.presshandle _ NIL; }; pdData: PDData => { PDFileReader.Close[pdData.pdhandle]; pdData.pdhandle _ NIL; pdData.image _ NIL; }; aisData: AISData => { AIS.CloseFile[aisData.state.openFile]; aisData.state.openFile _ NIL; aisData.state.pa _ NIL; aisData.state.op _ NIL; }; gData: GData => { gData.image _ NIL; }; ENDCASE => ERROR; -- can't happen SafeStorage.ReclaimCollectibleObjects[suspendMe: FALSE]; -- good citizenship }; PVGetName: PUBLIC ViewerClasses.GetProc = { --[self: Viewer, op: ATOM] RETURNS [data: REF ANY] d: Data _ NARROW[BiScrollers.ClientDataOfViewer[self]]; RETURN[d.container.name]; }; PVBasicTransformProc: PUBLIC PROC [bs: BiScrollers.BiScroller] RETURNS [t: Geom2D.Transform] = { iv: ViewerClasses.Viewer _ bs.style.QuaViewer[bs: bs, inner: TRUE]; data: Data _ NARROW[BiScrollers.ClientDataOfViewer[iv]]; t _ Geom2D.id.PostTranslate[[0, iv.ch - data.pageHeight]]; }; PVExtremaProc: PUBLIC PROC [clientData: REF ANY, direction: Geom2D.Vec] RETURNS [min, max: Geom2D.Vec] --BiScrollers.ExtremaProc-- = { data: Data _ NARROW[clientData]; area: Geom2D.Rect _ [x: 0.0, y: 0.0, w: data.pageWidth, h: data.pageHeight]; [min, max] _ Geom2D.ExtremaOfRect[r: area, n: direction]; }; END. hPreViewImpl.mesa Copyright c 1986 by Xerox Corporation. All rights reserved. Last edited by Ken Pier; May 15, 1986 9:55:26 am PDT Doug Wyatt, June 7, 1986 1:51:02 pm PDT Bland, August 28, 1986 4:30:07 pm PDT Mike Spreitzer September 4, 1986 5:56:24 pm PDT data.bBox^ _ []; -- causes initialization of data.bBox values to inactive state PROC [argument: Domain] RETURNS [good: BOOL]; remember that this routine may be called many times and should not do destructive operations on the context state Reset the handle in pdData to the image in pdData.pageNumber, then interpret the image PROC [argument: Domain] RETURNS [good: BOOL]; [self: Viewer, context: Imager.Context, whatChanged: REF ANY, clear: BOOL]; [self: Viewer] This next PROC is for the benefit of TSetter, which will call it when the InputFocus is in the previewer and the TSetter GET button is clicked BiScrollers.TransformGenerator t _ Geom2D.id.PostTranslate[[0, iv.ch - MAX[data.pageHeight, data.pageWidth]]]; Make client <0, max> appear at the upper left corner of viewer. This proc is required by BiScrollers to return the extremes of the displayed data Κ†– "cedar" style˜codešœ™Kšœ Οmœ1™Kšœžœ%˜9KšœžœG˜aKšœ žœ ˜0Kšœ žœ ˜Kšžœžœ ˜Kšœžœ˜$Kšœ žœ˜#Kšœžœ(˜;Kšœžœ‹˜˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ žœ˜Kšœ žœ˜.Kšœ žœ0˜?Kšœžœ7˜JKšœžœ˜0Kšœ žœ ˜Kšœžœ˜"—K˜šΟn œžœž˜Kšžœžœžœ±žœŠ˜θšžœ ž˜K˜——Kšœžœžœ˜$Kšœžœ˜Kšœ žœ˜$Kšœžœ˜Kšœžœ˜Kšœ žœ˜ Kšœžœ˜Kšœ žœžœ ˜!šœ žœžœ˜Kšœžœ˜Kšœžœ˜Kšœ ž˜Kšœ˜—Kšœ?˜?Kšœžœ Οc˜2Kšœžœ˜Kšœžœ˜"Kšœžœ˜"Kšœžœ˜"Kšœžœ˜"Kšœžœ ˜KšœJžœ˜PKšœ žœ˜Kšœžœ˜Kšœžœžœ˜'K˜šŸœžœžœ˜K•StartOfExpansionL[from: REAL, precision: Convert.RealPrecision _ 7, useE: BOOL _ FALSE]šœ.žœ˜4Kšœžœ˜"Kšœ.žœ˜5Kšœ˜K˜—šŸœžœ )˜VKšžœžœžœ˜Kšœžœ˜Kšœ žœ'˜:šžœžœžœžœžœžœžœž˜@šžœ žœž˜šœžœžœž˜šœ ˜ Kšžœžœ. ˜ZKšœ B˜SKšœ˜—šœ ˜ Kšžœ'žœ ˜Mšžœ'žœ˜/Kšœ'˜'Kšœ˜Kšœ˜Kšœžœ˜Kšœ˜—Kš œžœžœžœžœ˜ˆKšœC ˜XKšœ˜—šœ žœ˜–-[message: ROPE, clearFirst: BOOL _ FALSE]šžœ˜Kšœ žœΪ˜εKšœ žœ˜—Kšžœ&žœ˜0—Kšžœžœ˜—šœ! ˜1Kšœ ˜,Kšœ ˜,Kšžœžœ˜6K˜—Kšžœžœ˜—Kšžœ˜—Kšœ˜K˜—šŸ œžœžœ-žœ(˜pšŸœžœ  ˜KšŸœžœžœ˜%Kšœ%˜%Kšžœ žœžœ˜0Kšžœ žœžœ˜0Kšœ^˜^K˜AKšœB  ˜NKšœ>  ˜KKšœ9  ˜DKšœ5 ˜CKšœ˜—Kš žœžœžœ žœžœ  ˜QKšœ%˜%šžœž˜˜ Kšœo˜oKšœ˜—˜ KšœD ˜XKšœ7˜7K˜—šœ ˜ Kšžœ$žœE ˜ƒKšœ) ˜?Kšœ)˜)K˜—Kšžœžœ˜—Kšœ˜—Kšœv˜vKšœ'˜'Kšœ˜K˜—š Ÿ œžœžœOžœžœžœ˜Kšœ{˜{K–O[m: ImagerTransformation.Transformation, r: ImagerTransformation.Rectangle]šœ±˜±šžœž˜šœ  0˜;šŸœžœ˜+šŸœžœ˜Kšœ˜Kšœ9˜9Kšœ˜—Kšœ,˜,KšœŸœ˜ šžœžœ˜K–;[context: Imager.Context, color: ImagerColorDefs.Color]šœ$˜$K–;[context: Imager.Context, color: ImagerColorDefs.Color]˜KšœG  ˜SKšœH  ˜QKšœX  ˜eKšœV ˜]K˜—K˜—Kšœ#ŸœEžœ˜K˜—˜ šΠbn œžœ˜.Kšœ˜šžœžœ˜Kšœ,˜,Kšœ˜K˜—Kšœ˜K˜9K˜—–([fileName: ROPE, header: ROPE _ NIL]šœGžœ ˜TKšœ=žœ˜CKšžœ˜ Kšœ˜—šœG˜GKšœ`žœžœ˜u—Kšœ˜šž˜Kšœžœ˜ —K˜—Kšžœ˜—Kšœ >™OK˜K˜—šŸ œžœ2˜CKš‘ œžœ0žœžœ˜WKš žœ žœžœžœžœžœ˜Išœ:˜:Kšœ1žœžœ˜B—K˜K˜—šŸ œžœH˜XKšœ žœ R˜fšžœžœž˜Kšœ= ,˜iKšœK˜KKšœL˜LKšœA˜AKšœ=˜=Kšžœžœ˜—Kšœ žœ H˜\K˜K˜—šŸœžœ.˜;šžœžœž˜šœ %˜>K˜Kšœ  ˜šœg˜gšœ˜šžœž˜Kšœžœžœ1žœ˜jšžœ˜ Kšœ*žœ˜0Kšœ˜Kšžœ˜ K˜——Kšœ˜—Kšœ˜—K˜K˜—šŸœžœL˜YšŸœžœ+žœžœ˜DK™qKšœžœ'˜>šžœ žœž˜šœ!˜!Kšœ-˜-Kšœ=˜=šžœ žœ˜Kšœ˜šœω˜ωKšœ˜——Kšœ˜—Kšžœžœ˜—K˜—Kšžœžœ' -˜jK™VKš žœ,žœžœžœžœžœc $˜ΦK˜K˜—šŸœžœ0˜>Kšœ(˜(šžœžœ˜Kšœt˜tKšœ:˜:Kšœ˜—Kšœ˜K˜—šŸ œžœ,˜>šžœžœž˜šœ %˜=Kšœ "˜AKšœ ˜6Kšœ=˜=K˜—šœ& ˜?Kšœ9˜9Kšœ˜—šœ& ˜Eš‘œ˜.Kšœ-™-Kšžœžœ!˜.K˜—KšœžœU˜mš žœžœkžœžœ ˜™Kšœ9˜9Kšœ#˜#K˜—šžœ ˜Kšœ4˜4Kšœ) "˜KKšœ) ˜@KšœG˜GKšœœ˜œKšœ#˜#Kšœ9˜9K˜—Kšœ˜—Kšžœžœ˜—K˜K˜—šΠanœžœžœžœ˜9Kš K™KKšžœžœžœ˜Kšœ žœ'˜:K˜$Kšœ8žœ ˜^Kšžœžœ5žœ ˜sKšœ _˜{Kšœ˜K˜—š’ œžœžœ˜5Kšœ™Kšžœžœžœ˜Kšœ žœ'˜:K–)[ref: REF ANY, list: LIST OF REF ANY]šœ ˜ šžœžœž˜˜Kšœžœ !˜8K˜—˜Kšœ'˜'Kšœžœ˜K˜—˜Kšœ$˜$Kšœžœ˜Kšœžœ˜K˜—šœ˜Kšžœ#˜&Kšœžœ˜Kšœžœ˜Kšœžœ˜K˜—šœ˜Kšœžœ˜K˜—Kšžœžœ ˜!—Kšœ1žœ ˜LKšœ˜K˜—K™ŽšŸ œžœ 2˜^Kšœ žœ'˜7Kšžœ˜K˜K˜—šŸœžœžœžœ˜`Kšœ™Kšœ=žœ˜CKšœ žœ%˜8Kšœ'žœ$™OKšœ:˜:K™?K˜K˜—šŸ œžœžœžœžœžœ œ˜†K™QKšœ žœ ˜ KšœL˜LKšœ9˜9K˜K˜—Kšžœ˜—…—@τUβ