-- CGAISImageImpl.mesa -- Last changed by Doug Wyatt, October 4, 1982 11:35 am DIRECTORY CGAIS USING [APH, Header, password, RasterPart, UCA, UCACodingType], CGArea USING [Empty, Ref], CGContext USING [GenBox, Rep], CGDevice USING [Ref], CGMatrix USING [Assign, Concat, ConcatTransformation, Make, New, Ref, SetTrans], CGPrivate USING [Context], CGSource USING [Ref, Rep], CGStorage USING [qZone], ConvertUnsafe USING [AppendRope], GraphicsOps USING [], -- exports only GraphicsBasic USING [black], Directory USING [Lookup], File USING [Capability, nullCapability, PageCount, PageNumber], Inline USING [LongDiv, LongMult], Rope USING [ROPE], Space USING [Create, CreateUniformSwapUnits, Delete, GetAttributes, Handle, LongPointer, Map, nullHandle, Unmap, virtualMemory, wordsPerPage]; CGAISImageImpl: CEDAR MONITOR IMPORTS CGArea, CGContext, CGMatrix, CGStorage, ConvertUnsafe, Directory, Inline, Space EXPORTS CGPrivate, GraphicsOps, GraphicsBasic = { OPEN AIS: CGAIS; Context: TYPE = CGPrivate.Context; ContextData: TYPE = REF ContextDataRep; ContextDataRep: PUBLIC TYPE = CGContext.Rep; ImageObject: PUBLIC TYPE = DataRep; -- export to GraphicsBasic -- This is cheating! -- A new representation-independent Image interface is neeeded. -- But for now, this module exports NewAisImage and ImageBox -- directly into GraphicsOps. wordsPerPage: CARDINAL = Space.wordsPerPage; swapUnitSize: CARDINAL _ 10; Data: TYPE = REF DataRep; DataRep: TYPE = RECORD [ file: File.Capability, -- the AIS file rasterBase: File.PageNumber, -- where the raster begins rasterPages: File.PageCount, -- number of pages in the raster scanDirection: CARDINAL, -- scan direction code scanCount: CARDINAL, -- number of scan lines in raster scanLength: CARDINAL, -- pixels per scan line wordsPerLine: CARDINAL, -- words per scan line miv: CGMatrix.Ref, -- image-to-virtual matrix matrix: CGMatrix.Ref, -- image-to-device matrix src: CGSource.Ref -- source info for image ]; dataZone: ZONE = CGStorage.qZone; srcZone: ZONE = CGStorage.qZone; repZone: ZONE = CGStorage.qZone; MalformedFile: ERROR = CODE; NotImplemented: ERROR = CODE; -- Monitored data: cache most recently mapped space cachedFile: File.Capability _ File.nullCapability; cachedSpace: Space.Handle _ Space.nullHandle; -- end monitored data NewAisImage: PUBLIC PROC[name: Rope.ROPE] RETURNS[Data] = { file: File.Capability; TRUSTED { string: STRING _ [200]; ConvertUnsafe.AppendRope[to: string, from: name]; file _ Directory.Lookup[fileName: string] }; -- may raise Directory.Error RETURN[NewAisImageFromCapability[file]]; }; NewAisImageFromCapability: PUBLIC PROC[file: File.Capability] RETURNS[Data] = TRUSTED { lp: LONG POINTER; header: LONG POINTER TO AIS.Header _ NIL; part: LONG POINTER TO AIS.APH _ NIL; rp: LONG POINTER TO AIS.RasterPart _ NIL; up: LONG POINTER TO AIS.UCA _ NIL; lines,pixels,wpl,bps: CARDINAL; rbase, apages, rpages: CARDINAL; rwords: LONG CARDINAL; self: Data _ NIL; space: Space.Handle _ Space.Create[size: 4, parent: Space.virtualMemory]; -- for reading header { ENABLE UNWIND => Space.Delete[space]; Space.Map[space: space, window: [file: file, base: 1]]; header _ lp _ Space.LongPointer[space]; IF header.password=AIS.password THEN part _ LOOPHOLE[header+SIZE[AIS.Header]] ELSE ERROR MalformedFile; -- Wrong password apages _ header.attributeLength/wordsPerPage; rbase _ 1+apages; IF part.type=raster THEN { rp _ LOOPHOLE[part]; part _ part+part.length } ELSE ERROR MalformedFile; -- Raster part missing IF rp.samplesPerPixel=1 THEN NULL ELSE ERROR NotImplemented; -- Can't handle multiple samples per pixel IF rp.codingType=AIS.UCACodingType THEN up _ LOOPHOLE[rp+SIZE[AIS.RasterPart]] ELSE ERROR NotImplemented; -- Coding type not UCA IF up.scanLinesPerBlock=LAST[CARDINAL] THEN NULL ELSE ERROR NotImplemented; -- Can't handle blocked encoding yet lines _ rp.scanCount; pixels _ rp.scanLength; wpl _ up.wordsPerScanLine; bps _ up.bitsPerSample; rwords _ Inline.LongMult[lines, wpl]; -- number of words in raster part rpages _ Inline.LongDiv[rwords+(wordsPerPage-1), wordsPerPage]; -- number of pages needed self _ dataZone.NEW[DataRep _ [file: file, rasterBase: rbase, rasterPages: rpages, scanDirection: rp.scanDirection, scanCount: lines, scanLength: pixels, wordsPerLine: wpl, miv: NIL, matrix: NIL, src: NIL]]; SELECT self.scanDirection FROM 2 => self.miv _ CGMatrix.Make[[1,0,0,1,0,0]]; 3 => self.miv _ CGMatrix.Make[[1,0,0,-1,0,lines]]; 8 => self.miv _ CGMatrix.Make[[0,1,1,0,0,0]]; ENDCASE => ERROR; -- unexpected scanDirection self.matrix _ CGMatrix.New[]; -- placeholder for image-to-device mapping self.src _ srcZone.NEW[CGSource.Rep _ [type: array, mode: opaque, fat: FALSE, bps: bps, color: GraphicsBasic.black, xbase: NIL, xrast: wpl, Get: NIL]]; }; Space.Delete[space]; RETURN[self]; }; DrawImage: PUBLIC PROC[self: Context, image: Data, raw: BOOLEAN] = { ctx: ContextData _ NARROW[self.data]; data: Data _ image; T: CGMatrix.Ref _ ctx.matrix; -- virtual to destination mapping M: CGMatrix.Ref _ data.matrix; -- image to destination mapping src: CGSource.Ref _ data.src; wpl: CARDINAL _ data.wordsPerLine; device: CGDevice.Ref _ ctx.device; DrawImageEntry: ENTRY PROC = TRUSTED { ENABLE UNWIND => cachedFile _ File.nullCapability; -- and release lock file: File.Capability _ data.file; base: File.PageNumber _ data.rasterBase; pages: File.PageCount _ data.rasterPages; space: Space.Handle _ cachedSpace; area: CGArea.Ref; IF cachedFile#file THEN { create: BOOLEAN _ FALSE; -- first ensure a large enough space IF space=Space.nullHandle THEN create _ TRUE ELSE IF Space.GetAttributes[space].size>=pages THEN Space.Unmap[space] ELSE { Space.Delete[space]; cachedSpace _ Space.nullHandle; create _ TRUE }; IF create THEN { space _ Space.Create[size: pages, parent: Space.virtualMemory]; Space.CreateUniformSwapUnits[size: swapUnitSize, parent: space]; }; -- now map the space onto the new file Space.Map[space, [file, base]]; cachedFile _ file; cachedSpace _ space; }; src.xbase _ Space.LongPointer[space]; area _ CGContext.GenBox[ctx, [xmin: 1, ymin: 1, xmax: data.scanLength-1, ymax: data.scanCount-1], M]; IF NOT CGArea.Empty[area] THEN device.Show[device, area, src,M ]; }; CGMatrix.Assign[M,T]; CGMatrix.SetTrans[M,ctx.cp]; -- translate to current position IF NOT ctx.yUp THEN CGMatrix.Concat[M,1,0,0,-1]; CGMatrix.ConcatTransformation[M, data.miv.m]; -- M _ miv * T src.color _ ctx.src.color; src.mode _ ctx.src.mode; src.raw _ raw; DrawImageEntry[]; }; ImageBox: PUBLIC PROC[image: Data] RETURNS[xmin,ymin,xmax,ymax: REAL] = { w: REAL _ image.scanLength; h: REAL _ image.scanCount; SELECT image.scanDirection FROM 2,3 => RETURN[0,0,w,h]; 8 => RETURN[0,0,h,w]; ENDCASE => ERROR; -- Unexpected scanDirection; }; }. Κά– "Mesa" style˜IprocšΞΟcOœΟk œžœžœžœ žœžœžœžœžœOžœžœžœžœžœœžœ œ žœžœ?žœžœžœ žœ™žœžœžœQžœ+žœžœžœ žœ#žœžœ!žœžœ žœžœ Λœžœ%žœžœžœžœžœœœ!œžœœ žœ"œžœœžœœœœœžœžœžœ$žœžœžœžœ4œcœΟn œžœžœ žœžœ&žœ žœsœžœ)Ÿœžœžœžœ žœ žœžœ žœžœžœžœ žœ žœžœžœžœžœžœžœžœžœžœžœžœžœžœžœžœžœžœžœ žœžœžœNœžœžœ€žœžœ žœ žœžœžœ žœžœœFžœžœ žœ$žœžœœžœžœžœžœžœ+œžœžœžœ žœžœžœžœžœœžœžœžœžœžœžœžœ%œ’"œBœžœ§žœ žœžœžœžœ žœžœœ +œžœ5žœ/žœžœ"žœŸ œžœžœ"žœžœ%žœ"œžœ œ'žœ>Ÿœžœžœžœžœžœ&œΓžœžœ žœžœ%œžœžœ žœžœžœ(žœžœAžœ žœžœ₯'œσžœžœžœžœžœžœžœžœ !œžœžœ žœžœ,žœœ_Ÿœžœžœžœžœ žœžœžœžœ žœžœžœžœœ ˜Ά7—…—Έš