<<--PDReaderPageImpl.mesa>> <<--Last edited by Ken Pier, July 8, 1985 3:51:58 pm PDT>> <<--Last edited by Michael Plass, March 13, 1984 2:07:32 pm PST>> <<>> DIRECTORY Basics, PDFileFormat, PDFileReader, PDReaderPage, ImagerPixelMap, IO, ShowPD, ViewerClasses, ViewerOps ; PDReaderPageImpl: CEDAR PROGRAM IMPORTS PDFileReader, IO, ImagerPixelMap, ViewerOps EXPORTS PDReaderPage = { bitsPerWord: NAT = Basics.bitsPerWord; bytesPerWord: NAT = Basics.bytesPerWord; PageRecRef: TYPE = PDReaderPage.PageRecRef; PageRec: TYPE = PDReaderPage.PageRec; <> LeftoverRef: TYPE = REF Leftover; Leftover: TYPE = RECORD [ link: LeftoverRef _ NIL, command: REF ANY, colorType: PDFileReader.ColorType, colorTileLoadAddress: INT _ -1, priority: INT ]; InterpretPage: PUBLIC PROC [handle: PDFileReader.Handle, viewer: ViewerClasses.Viewer, pages: PageRecRef] RETURNS [ok: BOOLEAN _ FALSE] = { <> <> <<>> ENABLE IO.EndOfStream, IO.Error => GOTO Quit; --Viewers closed the stream imageHandle: PDReaderPage.Handle_NIL; showData: ShowPD.ShowData_NARROW[viewer.data]; readHead, writeHead, writeTail: LeftoverRef _ NIL; --heads and tail of leftover lists currentColorType: PDFileReader.ColorType; currentColorTileLoadAddress: INT _ -1; currentPriority: INT _ -1; leftovers: BOOLEAN; --can't be filled in until StartImage has happened commandRef: REF ANY; band: ImagerPixelMap.PixelMap; bandMaxS: INT; cachedColorTile: ImagerPixelMap.Tile; cachedColorReference: INT _ -1; GetColorTile: PROC = { IF currentColorTileLoadAddress # cachedColorReference THEN { cachedColorTile _ PDFileReader.ColorTileFromLoad[handle, cachedColorReference _ currentColorTileLoadAddress]; }; }; TransferRectangle: PROC [rectangle: ImagerPixelMap.DeviceRectangle] = { SELECT currentColorType FROM none => ERROR; clear => ImagerPixelMap.Fill[band, rectangle, 0]; ink => ImagerPixelMap.Fill[band, rectangle, 1]; opaqueTile => { GetColorTile[]; ImagerPixelMap.TransferTile[band.Clip[rectangle], cachedColorTile]; }; transparentTile => { GetColorTile[]; ImagerPixelMap.TransferTile[band.Clip[rectangle], cachedColorTile, [or, null]]; }; ENDCASE => ERROR; }; DoLine: PROCEDURE [sMin,fMin,fSize: CARDINAL] = { SELECT currentColorType FROM none => ERROR; clear => ImagerPixelMap.Fill[band, [sMin: sMin, fMin: fMin, sSize: 1, fSize: fSize], 0]; opaqueTile, ink => ImagerPixelMap.Fill[band, [sMin: sMin, fMin: fMin, sSize: 1, fSize: fSize], 1]; transparentTile => ImagerPixelMap.TransferTile[band.Clip[[sMin: sMin, fMin: fMin, sSize: 1, fSize: fSize]], cachedColorTile, [or, null]]; ENDCASE => ERROR; }; TempColor: PROC [rectangle: ImagerPixelMap.DeviceRectangle] = { SELECT currentColorType FROM none => ERROR; clear => NULL; ink => NULL; opaqueTile => { GetColorTile[]; ImagerPixelMap.TransferTile[band.Clip[rectangle], cachedColorTile, [xor, complement]]; }; transparentTile => GetColorTile[]; ENDCASE => ERROR; }; AddLeftover: PROC = { []_PDFileReader.Keep[handle: handle, ref: commandRef]; IF writeHead=NIL THEN writeHead_writeTail_NEW[Leftover _[link: NIL, command: commandRef, colorType: currentColorType, colorTileLoadAddress: currentColorTileLoadAddress, priority: currentPriority]] ELSE { writeTail.link_NEW[Leftover _[link: NIL, command: commandRef, colorType: currentColorType, colorTileLoadAddress: currentColorTileLoadAddress, priority: currentPriority]]; writeTail_writeTail.link; }; }; DO ENABLE UNWIND => {readHead_writeHead_writeTail_NIL; handle.Close[];}; IF readHead#NIL AND readHead.priority> readHead_readHead.link; } ELSE { commandRef _ PDFileReader.Get[handle: handle, scanning: FALSE]; currentColorTileLoadAddress_handle.colorTileLoadAddress; currentColorType_handle.colorType; currentPriority_handle.priority; }; IF showData.abortPainting THEN {readHead_writeHead_writeTail_NIL; RETURN [TRUE];}; WITH commandRef SELECT FROM stateChange: PDFileReader.StateChange => { SELECT stateChange.whatChanged FROM imageStart => { showData.image_imageHandle _ StartImage[fileHandle: handle, oldPixelMap: IF imageHandle#NIL THEN imageHandle.pixelMap ELSE [,,,,,,NIL] ]; band _ imageHandle.pixelMap; bandMaxS_band.sOrigin+band.sMin+band.sSize; leftovers _ handle.image.leftOverMode; showData.clearClient_TRUE; ViewerOps.PaintViewer[viewer: viewer, hint: all, clearClient: TRUE, whatChanged: NIL]; }; imageEnd => { ViewerOps.PaintViewer[viewer: viewer, hint: all, clearClient: FALSE, whatChanged: imageHandle]; readHead_writeHead_writeTail_NIL; RETURN [TRUE]; }; priorityChange => NULL; colorChange => NULL; bandChange => { showData.clearClient_FALSE; ViewerOps.PaintViewer[viewer: viewer, hint: all, clearClient: FALSE, whatChanged: imageHandle]; <> imageHandle.pixelMap.sOrigin _ handle.herald.bandSSize*(handle.bandNumber+handle.image.passBands); ImagerPixelMap.Clear[imageHandle.pixelMap]; band _ imageHandle.pixelMap; bandMaxS_band.sOrigin+band.sMin+band.sSize; IF readHead#NIL THEN ERROR; --DEBUGGING CHECK !! readHead_writeHead; writeHead_NIL; }; loadChange => NULL; documentEnd => RETURN [FALSE]; ENDCASE => ERROR; }; maskRectangle: PDFileReader.MaskRectangle => { TransferRectangle[[maskRectangle.sMin, maskRectangle.fMin, maskRectangle.sSize, maskRectangle.fSize]]; IF leftovers AND maskRectangle.sMin+maskRectangle.sSize>bandMaxS THEN AddLeftover[]; }; maskTrapezoid: PDFileReader.MaskTrapezoid => { EdgeBlock: TYPE = RECORD [fPos, fIncr: Basics.LongNumber]; MakeEdge: PROC[fMinLast, fMin, sSize: CARDINAL] RETURNS [edge: EdgeBlock] = { edge.fPos.highbits _ fMin; edge.fPos.lowbits _ 0; edge.fIncr.highbits _ fMinLast - fMin; edge.fIncr.lowbits _ 0; IF sSize > 1 THEN edge.fIncr.li _ edge.fIncr.li/sSize; }; fMinBox: CARDINAL_MIN[maskTrapezoid.fMin, maskTrapezoid.fMinLast]; fMaxBox: CARDINAL_MAX[maskTrapezoid.fMin+maskTrapezoid.fSize, maskTrapezoid.fMinLast+maskTrapezoid.fSizeLast]; fSizeBox: CARDINAL_fMaxBox-fMinBox; trapMaxS: CARDINAL _ maskTrapezoid.sMin+maskTrapezoid.sSize; s: CARDINAL _ maskTrapezoid.sMin; sMinBand: CARDINAL _ MIN[band.sOrigin+band.sMin, maskTrapezoid.sMin+maskTrapezoid.sSize]; sMaxBand: CARDINAL _ MIN[bandMaxS, trapMaxS]; <> minEdge: EdgeBlock _ MakeEdge[fMinLast: maskTrapezoid.fMinLast, fMin: maskTrapezoid.fMin, sSize: maskTrapezoid.sSize]; maxEdge: EdgeBlock _ MakeEdge[fMinLast: maskTrapezoid.fMinLast+maskTrapezoid.fSizeLast, fMin: maskTrapezoid.fMin+maskTrapezoid.fSize, sSize: maskTrapezoid.sSize]; TempColor[[sMin: maskTrapezoid.sMin, fMin: fMinBox, sSize: maskTrapezoid.sSize, fSize: fSizeBox]]; WHILE s < sMinBand DO minEdge.fPos.lc _ minEdge.fPos.lc + minEdge.fIncr.li; maxEdge.fPos.lc _ maxEdge.fPos.lc + maxEdge.fIncr.li; s _ s + 1; ENDLOOP; WHILE s < sMaxBand DO DoLine[sMin: s, fMin: minEdge.fPos.highbits, fSize: maxEdge.fPos.highbits-minEdge.fPos.highbits]; minEdge.fPos.lc _ minEdge.fPos.lc + minEdge.fIncr.li; maxEdge.fPos.lc _ maxEdge.fPos.lc + maxEdge.fIncr.li; s _ s + 1; ENDLOOP; TempColor[[sMin: maskTrapezoid.sMin, fMin: fMinBox, sSize: maskTrapezoid.sSize, fSize: fSizeBox]]; IF leftovers AND trapMaxS>bandMaxS THEN AddLeftover[]; }; maskRunGroup: PDFileReader.MaskRunGroup => TRUSTED { s: CARDINAL _ maskRunGroup.sMin; sMinBand: CARDINAL _ MIN[band.sOrigin+band.sMin, maskRunGroup.sMin+maskRunGroup.sSize]; sMaxBand: CARDINAL _ MIN[band.sOrigin+band.sMin+band.sSize, maskRunGroup.sMin+maskRunGroup.sSize]; run: LONG POINTER TO PDFileFormat.Run _ maskRunGroup.pointer; TempColor[[maskRunGroup.sMin, maskRunGroup.fMin, maskRunGroup.sSize, maskRunGroup.fSize]]; WHILE s < sMinBand DO IF run.lastRun THEN s _ s + 1; run _ run + SIZE[PDFileFormat.Run]; ENDLOOP; WHILE s < sMaxBand DO DoLine[sMin: s, fMin: run.fMin+maskRunGroup.fOffset, fSize: run.fSize]; IF run.lastRun THEN s _ s + 1; run _ run + SIZE[PDFileFormat.Run]; ENDLOOP; TempColor[[maskRunGroup.sMin, maskRunGroup.fMin, maskRunGroup.sSize, maskRunGroup.fSize]]; IF leftovers AND maskRunGroup.loadAddress>=0 AND maskRunGroup.sMin+maskRunGroup.sSize>bandMaxS THEN { maskRunGroup.sSize_maskRunGroup.sSize-(s-maskRunGroup.sMin); maskRunGroup.sMin_s; maskRunGroup.runCount _ -1; --unused, eventually eliminate from DEF maskRunGroup.pointer_run; AddLeftover[]; }; }; maskSamples: PDFileReader.MaskSamples => { rectangle: ImagerPixelMap.DeviceRectangle _ ImagerPixelMap.Window[maskSamples.samples]; TempColor[rectangle]; SELECT currentColorType FROM none => ERROR; clear => ImagerPixelMap.Transfer[band, maskSamples.samples, [and, complement]]; opaqueTile, ink => ImagerPixelMap.Transfer[band, maskSamples.samples, [or, null]]; transparentTile => { bounds: ImagerPixelMap.DeviceRectangle _ ImagerPixelMap.Intersect[rectangle, ImagerPixelMap.Window[band]]; destDesc: ImagerPixelMap.PixelMap_ImagerPixelMap.Create[lgBitsPerPixel: 0, bounds: bounds]; GetColorTile[]; ImagerPixelMap.TransferTile[dest: destDesc, tile: cachedColorTile]; ImagerPixelMap.Transfer[dest: destDesc, source: maskSamples.samples, function: [and, null]]; ImagerPixelMap.Transfer[dest: band, source: destDesc, function: [or, null]]; }; ENDCASE => ERROR; TempColor[rectangle]; IF leftovers AND maskSamples.loadAddress>=0 AND maskSamples.samples.sOrigin+maskSamples.samples.sMin+maskSamples.samples.sSize > bandMaxS THEN AddLeftover[]; }; colorSamples: PDFileReader.ColorSamples => { ImagerPixelMap.Transfer[band, colorSamples.samples]; }; deviceCommand: PDFileReader.DeviceCommand => { }; ENDCASE => NULL; ENDLOOP; EXITS Quit => NULL; }; StartImage: PROC [fileHandle: PDFileReader.Handle, oldPixelMap: ImagerPixelMap.PixelMap_[,,,,,,NIL] ] RETURNS [handle: PDReaderPage.Handle] = TRUSTED { handle_NEW[PDReaderPage.Rep]; IF oldPixelMap.refRep=NIL THEN handle.pixelMap_ImagerPixelMap.Create[lgBitsPerPixel: 0, bounds: [sMin: 0, fMin: 0, sSize: fileHandle.herald.bandSSize, fSize: fileHandle.herald.imageFSize]] ELSE handle.pixelMap_ImagerPixelMap.Reshape[refRep: oldPixelMap.refRep, lgBitsPerPixel: 0, bounds: [sMin: 0, fMin: fileHandle.image.fMinPage, sSize: fileHandle.herald.bandSSize, fSize: fileHandle.image.fSizePage]]; handle.pixelMap.sOrigin _ fileHandle.herald.bandSSize*fileHandle.image.passBands; ImagerPixelMap.Clear[handle.pixelMap]; }; <<>> GetPageStructure: PUBLIC PROC [handle: PDFileReader.Handle] RETURNS [PageRecRef, INT] ~ { <> pages, pageTail: PageRecRef_NIL; currentPageNumber: INT_0; copyHandle: PDFileReader.Handle_NEW[PDFileReader.Rep _ handle^]; streamInitialIndex: INT_handle.stream.GetIndex[]; handle.stream.SetIndex[SIZE[PDFileFormat.Herald]*bytesPerWord];--start of file just past Herald DO WITH copyHandle.Get[scanning: TRUE] SELECT FROM stateChange: PDFileReader.StateChange => { SELECT stateChange.whatChanged FROM imageStart => { IF copyHandle.image.nBands>0 THEN { newPage: PageRecRef_NEW[PageRec _[link: NIL, type: imageStart, pageNumber: (currentPageNumber_currentPageNumber+1), index: copyHandle.stream.GetIndex[]-(SIZE[PDFileFormat.StartImage]+SIZE[PDFileFormat.Command])*bytesPerWord]]; IF pages=NIL THEN pages_pageTail_newPage ELSE {pageTail.link_newPage; pageTail_newPage}; }; }; imageEnd => NULL; priorityChange => NULL; colorChange => NULL; bandChange => NULL; loadChange => { newPage: PageRecRef_NEW[PageRec _[link: NIL, type: loadChange, pageNumber: -1, index: copyHandle.stream.GetIndex[]-(SIZE[PDFileFormat.StoreLoad]+SIZE[PDFileFormat.Command]+stateChange.loadChangeLength)*bytesPerWord]]; IF pages=NIL THEN pages_pageTail_newPage ELSE {pageTail.link_newPage; pageTail_newPage; }; }; documentEnd => { handle.stream.SetIndex[streamInitialIndex]; --restore PD stream RETURN [pages, currentPageNumber]; }; ENDCASE => PDFileReader.Error[handle: handle, code: unrecognisedControlCommand, wordIndex: -1, wordCount: -1, description: "Page structure Get error"]; }; ENDCASE => NULL; ENDLOOP; }; ResetToPage: PUBLIC PROC [data: REF ANY] RETURNS [PageRecRef] ~ { <> <> rebuildLoad: BOOLEAN _ TRUE; showData: ShowPD.ShowData _ NARROW[data]; handle: PDFileReader.Handle _ showData.show; pageNumber: INT _ showData.pageNumber; nextPage: PageRecRef _ showData.pageStructure; handle.priority_0; handle.colorType_none; --fake the reader into rebuilding the load IF showData.atPage#NIL AND showData.atPage.pageNumber >= pageNumber THEN rebuildLoad_FALSE; UNTIL nextPage=NIL DO SELECT nextPage.type FROM imageStart => IF nextPage.pageNumber=pageNumber THEN { handle.stream.SetIndex[nextPage.index]; --set stream to point to StartImage command showData.atPage _ nextPage; RETURN[nextPage]; }; loadChange => { IF rebuildLoad THEN { handle.stream.SetIndex[nextPage.index]; --set stream to point to storeLoad command WITH handle.Get[scanning: FALSE] SELECT FROM --handle.Get[] has the side effect of building the load!! sc: PDFileReader.StateChange => SELECT sc.whatChanged FROM loadChange => NULL; --found the expected loadChange command ENDCASE => PDFileReader.Error[handle: handle, code: unrecognisedControlCommand, wordIndex: -1, wordCount: -1, description: "Page structure index error"]; --found a StateChange which was not a loadChange ENDCASE => PDFileReader.Error[handle: handle, code: unrecognisedControlCommand, wordIndex: -1, wordCount: -1, description: "Page structure index error"]; --pages tried to point to a loadChange but reader didn't find one }; }; ENDCASE => PDFileReader.Error[handle: handle, code: unrecognisedControlCommand, wordIndex: -1, wordCount: -1, description: "Page structure type error"]; nextPage_nextPage.link; ENDLOOP; RETURN[NIL]; --never found the requested pageNumber }; }. --END