--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;
Leftover list types
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: BOOLEANFALSE] = {
Interprets one page (may be multiple passes ??), and paints it in viewer.
May raise PDFileReader.Warning or PDFileReader.Error. Returns FALSE upon document end.
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<handle.priority THEN {
commandRef ← readHead.command;
currentColorTileLoadAddress←readHead.colorTileLoadAddress;
currentColorType←readHead.colorType;
currentPriority←readHead.priority;
now remove this record from readList
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�nd.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];
update pixelMap in handle
imageHandle.pixelMap.sOrigin ← handle.herald.bandSSize*(handle.bandNumber+handle.image.passBands);
ImagerPixelMap.Clear[imageHandle.pixelMap];
band ← imageHandle.pixelMap;
bandMaxS�nd.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: CARDINALMIN[maskTrapezoid.fMin, maskTrapezoid.fMinLast];
fMaxBox: CARDINALMAX[maskTrapezoid.fMin+maskTrapezoid.fSize, maskTrapezoid.fMinLast+maskTrapezoid.fSizeLast];
fSizeBox: CARDINAL𡤏MaxBox-fMinBox;
trapMaxS: CARDINAL ← maskTrapezoid.sMin+maskTrapezoid.sSize;
s: CARDINAL ← maskTrapezoid.sMin;
sMinBand: CARDINALMIN[band.sOrigin+band.sMin, maskTrapezoid.sMin+maskTrapezoid.sSize];
sMaxBand: CARDINALMIN[bandMaxS, trapMaxS];
calculate initial edges:
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: CARDINALMIN[band.sOrigin+band.sMin, maskRunGroup.sMin+maskRunGroup.sSize];
sMaxBand: CARDINALMIN[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] ~ {
assumes filestream is available from Handle and Gets can be executed safely
pages, pageTail: PageRecRef←NIL;
currentPageNumber: INT𡤀
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𡤌urrentPageNumber+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] ~ {
a DUMB routine to reconstruct the load for the given page
requires that a page structure has already been built using GetPageStructure
rebuildLoad: BOOLEANTRUE;
showData: ShowPD.ShowData ← NARROW[data];
handle: PDFileReader.Handle ← showData.show;
pageNumber: INT ← showData.pageNumber;
nextPage: PageRecRef ← showData.pageStructure;
handle.priority𡤀 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