DIRECTORY Basics USING [bitsPerWord, bytesPerWord, LongNumber], BiScrollers USING [ClientDataOfViewer], ImagerPixelMap USING [Clear, Clip, Create, DeviceRectangle, Fill, Intersect, PixelMap, Reshape, Tile, Transfer, TransferTile, Window], IO USING [EndOfStream, Error, GetIndex, SetIndex], PDFileFormat USING [Command, Herald, Run, StartImage, StoreLoad], PDFileReader USING [Close, ColorSamples, ColorTileFromLoad, ColorType, DeviceCommand, Error, Get, Handle, Keep, MaskRectangle, MaskRunGroup, MaskSamples, MaskTrapezoid, Rep, StateChange], PDImageReader USING [Handle, ImageLink, ImageRep, PaintActionProc, Rep], PreView USING [PDData, Rep], ViewerClasses USING [Viewer]; PDImageReaderImpl: CEDAR PROGRAM IMPORTS BiScrollers, PDFileReader, IO, ImagerPixelMap EXPORTS PDImageReader = BEGIN bitsPerWord: NAT = Basics.bitsPerWord; bytesPerWord: NAT = Basics.bytesPerWord; ImageLink: TYPE = PDImageReader.ImageLink; ImageRep: TYPE = PDImageReader.ImageRep; LeftoverRef: TYPE = REF Leftover; Leftover: TYPE = RECORD [ link: LeftoverRef _ NIL, command: REF ANY, colorType: PDFileReader.ColorType, colorTileLoadAddress: INT _ -1, priority: INT ]; InterpretImage: PUBLIC PROC [handle: PDFileReader.Handle, viewer: ViewerClasses.Viewer, paintAction: PDImageReader.PaintActionProc] RETURNS [lastImage: BOOLEAN _ FALSE] = { ENABLE IO.EndOfStream, IO.Error => GOTO Quit; --Viewers closed the stream imageHandle: PDImageReader.Handle_NIL; pdData: PreView.PDData _ NARROW[BiScrollers.ClientDataOfViewer[viewer]]; 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 _ [0,0,0,0,0,NIL]; cachedColorReference: INT _ -1; GetColorTile: PROC = { IF currentColorTileLoadAddress # cachedColorReference THEN { cachedColorTile _ PDFileReader.ColorTileFromLoad[handle: handle, colorTileLoadAddress: (cachedColorReference _ currentColorTileLoadAddress), scratch: cachedColorTile.refRep]; }; }; 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 { SELECT stateChange.whatChanged FROM imageStart => { pdData.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; }; imageEnd => { paintAction[self: viewer, whatChanged: imageHandle]; readHead_writeHead_writeTail_NIL; RETURN [FALSE]; }; priorityChange => NULL; colorChange => NULL; bandChange => { IF pdData.abort THEN {readHead_writeHead_writeTail_NIL; RETURN [TRUE];}; paintAction[self: viewer, 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 [TRUE]; 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: PDImageReader.Handle] = TRUSTED { handle _ NEW[PDImageReader.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 [list: ImageLink, imageCount: INT] = { images, imageTail: ImageLink _ NIL; currentImageNumber: 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 { newImage: ImageLink _ NEW[ImageRep _[link: NIL, type: imageStart, imageNumber: (currentImageNumber_currentImageNumber+1), index: copyHandle.stream.GetIndex[]-(SIZE[PDFileFormat.StartImage]+SIZE[PDFileFormat.Command])*bytesPerWord]]; IF images=NIL THEN images_imageTail_newImage ELSE {imageTail.link_newImage; imageTail_newImage}; }; }; imageEnd => NULL; priorityChange => NULL; colorChange => NULL; bandChange => NULL; loadChange => { newImage: ImageLink_NEW[ImageRep _[link: NIL, type: loadChange, imageNumber: -1, index: copyHandle.stream.GetIndex[]-(SIZE[PDFileFormat.StoreLoad]+SIZE[PDFileFormat.Command]+stateChange.loadChangeLength)*bytesPerWord]]; IF images=NIL THEN images_imageTail_newImage ELSE {imageTail.link_newImage; imageTail_newImage; }; }; documentEnd => { handle.stream.SetIndex[streamInitialIndex]; --restore PD stream RETURN [images, currentImageNumber]; }; ENDCASE => PDFileReader.Error[handle: handle, code: unrecognisedControlCommand, wordIndex: -1, wordCount: -1, description: "Image structure Get error"]; }; ENDCASE => NULL; ENDLOOP; }; ResetToImage: PUBLIC PROC [data: REF ANY] RETURNS [ImageLink] = { rebuildLoad: BOOLEAN _ TRUE; pdData: PreView.PDData _ NARROW[data]; handle: PDFileReader.Handle _ pdData.pdhandle; imageNumber: INT _ pdData.pageNumber; nextImage: ImageLink _ pdData.pageStructure; handle.priority_0; handle.colorType_none; --fake the reader into rebuilding the load IF pdData.atImage#NIL AND pdData.atImage.imageNumber >= imageNumber THEN rebuildLoad_FALSE; UNTIL nextImage=NIL DO SELECT nextImage.type FROM imageStart => IF nextImage.imageNumber=imageNumber THEN { handle.stream.SetIndex[nextImage.index]; --set stream to point to StartImage command pdData.atImage _ nextImage; RETURN[nextImage]; }; loadChange => { IF rebuildLoad THEN { handle.stream.SetIndex[nextImage.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"]; --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"]; nextImage_nextImage.link; ENDLOOP; RETURN[NIL]; --never found the requested imageNumber }; END. ¸PDImageReaderImpl.mesa Last edited by Ken Pier, September 18, 1985 11:53:48 am PDT Leftover list types Interprets one image in a PDFile. Must be called ONLY AFTER the desired image has been selected by a call to ResetToImage. May raise PDFileReader.Warning or PDFileReader.Error or PDReaderOutput.Error or PDReaderOutput.Abort Returns TRUE if the interpreted image is the last image in the document. this routine was changed to recirculate the PixelMapRep in the cachedColorTile now remove this record from readList update pixelMap in handle calculate initial edges: assumes filestream is available from Handle and Gets can be executed safely A routine to reconstruct the load for the image number in pdData.pageNumber. pdData MUST BE a Preview.PDData. It has type REF ANY to avoid circular recompilation dependencies between this module and PreView.mesa. In this case, pdData.pageNumber contains an image number rather than a page number. Requires that a page structure has already been built using GetPageStructure and stored in pdData.pageStructure . Returns an ImageLink (single element) for the image that has been successfully reset to. Returns NIL if pageNumber is not in the images list. Ê Ý˜Jšœ™Jšœ;™;J™šÏk ˜ Jšœœ6œ&œsœœ8œ=œ¸œ>œœ ˜™—unitšÏnœœ˜ Jšœœ˜6Jšœ˜J˜Jšœ œ˜&Jšœœ˜(Jšœ œ˜*Jšœ œ˜(J˜J™Jšœ œœ ˜!šœ œœ˜Jšœœ˜Jšœ œœ˜Jšœ"˜"Jšœœ˜ Jšœ ˜ J˜—J˜š žœœœiœ œœ˜¬J™{Jšœd™dJ™HJ™Jš œœœ œÏc˜IJ˜Jšœ"œ˜&Jšœœ)˜HJšœ.œŸ"˜UJšœ)˜)Jšœœ˜&Jšœœ˜Jšœ œŸ2˜FJšœ œœ˜Jšœ˜Jšœ œ˜Jšœ2œ˜7Jšœœ˜šž œœ˜J™Nšœ4œ˜