DIRECTORY Environment, Font, Imager, ImagerBasic USING [Color, ColorRep, ConstantColor, IntPair, IntRectangle, Pair, PathMapType, PixelArray, PixelArrayRep, PixelBuffer, PixelBufferRep, Rectangle, SampledColor, StrokeEnd, Transformation, TransformType, Visibility], ImagerConic, ImagerFontCache, ImagerHalftone, ImagerMasks, ImagerPD, ImagerPixelMaps, ImagerPrivate, ImagerScanConverter, ImagerStroke, ImagerTransform, PDFileWriter, Real, RefText, Rope, Scaled ; ImagerPDImpl: CEDAR PROGRAM IMPORTS Imager, ImagerConic, ImagerFontCache, ImagerHalftone, ImagerMasks, ImagerPixelMaps, ImagerPrivate, ImagerScanConverter, ImagerStroke, ImagerTransform, PDFileWriter, Real, RefText, Scaled EXPORTS ImagerPD ~ BEGIN OPEN ImagerBasic; PDFileDescription: TYPE ~ ImagerPD.PDFileDescription; PDFileDescriptionRep: TYPE ~ ImagerPD.PDFileDescriptionRep; Raven: PUBLIC PROC [fileName: ROPE] RETURNS [PDFileDescription] ~ { RETURN [NEW[PDFileDescriptionRep _ [ fileName, raven, 300, 300, 2550, 3300, 1, 16, 60000, TRUE, 1 ]]] }; Hornet: PUBLIC PROC [fileName: ROPE] RETURNS [PDFileDescription] ~ { RETURN [NEW[PDFileDescriptionRep _ [ fileName, hornet, 384, 384, 3264, 4224, 1, 16, 60000, TRUE, 1 ]]] }; Gnat: PUBLIC PROC [fileName: ROPE] RETURNS [PDFileDescription] ~ { RETURN [NEW[PDFileDescriptionRep _ [ fileName, gnat, 384, 384, 4224, 5376, 1, 16, 60000, TRUE, 1 ]]] }; PlateMaker: PUBLIC PROC [fileName: ROPE] RETURNS [PDFileDescription] ~ { RETURN [NEW[PDFileDescriptionRep _ [ fileName, mig, 880, 880, 7480, 9680, 1, 16, 60000, TRUE, 1 ]]] }; ReticleMaker: PUBLIC PROC [fileName: ROPE] RETURNS [PDFileDescription] ~ { RETURN [NEW[PDFileDescriptionRep _ [ fileName, reticleMaker, 880, 880, 8800, 8800, 1, 16, 60000, TRUE, 1 ]]] }; Puffin: PUBLIC PROC [fileName: ROPE] RETURNS [PDFileDescription] ~ { RETURN [NEW[PDFileDescriptionRep _ [ fileName, puffin, 384, 384, 4224, 3264, 3, 16, 60000, TRUE, 1 ]]] }; DeviceCode: TYPE ~ PDFileWriter.DeviceCode; FONT: TYPE ~ Font.FONT; Mask: TYPE ~ ImagerMasks.Mask; Name: TYPE ~ ImagerPrivate.Name; PixelMap: TYPE ~ ImagerPixelMaps.PixelMap; DeviceRectangle: TYPE ~ ImagerPixelMaps.DeviceRectangle; ROPE: TYPE ~ Rope.ROPE; SpecialColor: TYPE ~ REF ColorRep[special]; Tile: TYPE ~ ImagerPixelMaps.Tile; Toner: TYPE ~ PDFileWriter.Toner; StatsRecord: TYPE = RECORD[ loadRunGroups, loadRasters, runGroupChars, rasterChars, clippedChars, culledChars: INT _ 0]; stats: StatsRecord _ []; Stats: PROC RETURNS[StatsRecord] = { x: StatsRecord = stats; stats _ []; RETURN[x] }; trc: ARRAY [0..64) OF [0..256] _ InitTRC[]; InitTRC: PROC RETURNS [trc: ARRAY [0..64) OF [0..256]] ~ { FOR i: [0..64) IN [0..64) DO trc[i] _ Real.RoundLI[i/63.0*256.0]; ENDLOOP; }; dummyLoadReference: PDFileWriter.LoadReference ~ LAST[PDFileWriter.LoadReference]; Context: TYPE ~ Imager.Context; Data: TYPE ~ REF DataRep; DataRep: TYPE ~ RECORD [ currentColor: Color, clientClipper: Mask, -- in device coords clientClipperPresent: BOOLEAN, clientClipperExclude: BOOLEAN, compositeClipperValid: BOOLEAN, leftoverMode: BOOLEAN, doSaveCount: [0..1000) _ 0, compositeClipper: Mask, -- in device coords viewClipper: Mask, -- in device coords sOriginView, fOriginView: INTEGER, sOriginBrick, fOriginBrick: INTEGER, currentPosition: Pair, -- in device space transformation: Transformation, viewToDevice: Transformation, surfaceToDevice: Transformation, surfaceBounds: DeviceRectangle, devicePath: ImagerScanConverter.DevicePath, grayTileRef: ARRAY Toner OF ARRAY [0..64) OF PDFileWriter.LoadReference, fontCache: ImagerFontCache.FontCache, lineBuffer: ImagerPixelMaps.PixelMap, pdState: PDFileWriter.PDState, priorityImportant: INT _ 0 ]; deviceBrick: ImagerHalftone.DeviceBrick _ ImagerHalftone.MakeSquareBrick[16, 3, 2, 1, 0.5, 255]; Init: PROC [context: Context, info: REF] ~ { data: Data ~ NEW[DataRep]; desc: PDFileDescription ~ NARROW[info]; sScale: REAL ~ desc.sResolution/72.0; fScale: REAL ~ desc.fResolution/72.0; context.data _ data; data.surfaceBounds _ [sMin: 0, fMin: 0, sSize: desc.imageSSize, fSize: desc.imageFSize]; data.surfaceToDevice _ IF desc.imageFSize >= desc.imageSSize THEN ImagerTransform.Create[sScale, 0, 0, 0, fScale, 0] ELSE ImagerTransform.Create[0, -sScale, desc.imageSSize, fScale, 0, 0]; data.pdState _ PDFileWriter.Create[fileName: desc.fileName, deviceCode: desc.deviceCode, sResolution: desc.sResolution, fResolution: desc.fResolution, imageSSize: desc.imageSSize, imageFSize: desc.imageFSize, nColors: desc.nColors, bandSSize: desc.bandSSize, copies: desc.copies, leftOverMode: desc.leftovers]; data.leftoverMode _ desc.leftovers; data.fontCache _ ImagerFontCache.Create[]; FOR toner: Toner IN Toner DO FOR i: [0..64) IN [0..64) DO data.grayTileRef[toner][i] _ dummyLoadReference ENDLOOP ENDLOOP; data.lineBuffer _ ImagerPixelMaps.Create[0, [0, 0, 1, data.surfaceBounds.fSize]]; Reset[context]; }; Reset: PROC [context: Context] ~ { data: Data _ NARROW[context.data]; data.devicePath _ NIL; data.transformation _ data.viewToDevice _ data.surfaceToDevice; data.clientClipperPresent _ data.clientClipperExclude _ data.compositeClipperValid _ FALSE; data.currentPosition _ [0, 0]; data.viewClipper _ ImagerMasks.Box[data.surfaceBounds]; [[data.sOriginView, data.fOriginView]] _ [[data.sOriginBrick, data.fOriginBrick]] _ ImagerTransform.IntTransform[[0,0], data.surfaceToDevice]; SetColor[data, Imager.black]; }; DoSaveAll: PROC [context: Context, body: PROC] ~ { data: Data _ NARROW[context.data]; cp: Pair _ data.currentPosition; DoSave[context, body]; data.currentPosition _ cp; }; DoSave: PROC [context: Context, body: PROC] ~ { data: Data _ NARROW[context.data]; color: Color _ data.currentColor; clipper: Clipper _ GetClipper[context]; transformation: Transformation _ data.transformation; sOriginView: INTEGER _ data.sOriginView; fOriginView: INTEGER _ data.fOriginView; sOriginBrick: INTEGER _ data.sOriginBrick; fOriginBrick: INTEGER _ data.fOriginBrick; data.doSaveCount _ data.doSaveCount + 1; body[]; data.doSaveCount _ data.doSaveCount - 1; data.sOriginView _ sOriginView; data.fOriginView _ fOriginView; data.sOriginBrick _ sOriginBrick; data.fOriginBrick _ fOriginBrick; data.transformation _ transformation; SetClipper[context, clipper]; IF data.currentColor # color THEN SetColor[data, color]; }; ConcatT: PROC [context: Context, m: Transformation] ~ { data: Data _ NARROW[context.data]; data.transformation _ ImagerTransform.Concat[m, data.transformation]; }; TranslateT: PROC [context: Context, x, y: REAL] ~ { data: Data _ NARROW[context.data]; data.transformation _ ImagerTransform.PreTranslate[x, y, data.transformation]; }; RotateT: PROC [context: Context, a: REAL] ~ { data: Data _ NARROW[context.data]; data.transformation _ ImagerTransform.PreRotate[a, data.transformation]; }; ScaleT: PROC [context: Context, s: REAL] ~ { data: Data _ NARROW[context.data]; data.transformation _ ImagerTransform.PreScale[s, s, data.transformation]; }; Scale2T: PROC [context: Context, sx, sy: REAL] ~ { data: Data _ NARROW[context.data]; data.transformation _ ImagerTransform.PreScale[sx, sy, data.transformation]; }; Move: PROC [context: Context] ~ { data: Data _ NARROW[context.data]; data.transformation.c _ data.currentPosition.x; data.transformation.f _ data.currentPosition.x; }; Trans: PROC [context: Context] ~ { data: Data _ NARROW[context.data]; data.transformation.c _ Real.RoundLI[data.currentPosition.x]; data.transformation.f _ Real.RoundLI[data.currentPosition.x]; }; Clipper: TYPE ~ REF ClipperRep; ClipperRep: TYPE ~ RECORD [ exclude: BOOLEAN, mask: Mask ]; GetClipper: PROC [context: Context] RETURNS [Clipper] ~ { data: Data = NARROW[context.data]; IF data.clientClipperPresent THEN { clipper: Clipper = NEW[ClipperRep]; clipper.exclude _ data.clientClipperExclude; clipper.mask _ data.clientClipper.InlineShift[-data.sOriginView, -data.fOriginView]; ccCount _ ccCount + 1; RETURN [clipper] } ELSE RETURN [NIL] }; SetClipper: PROC [context: Context, clipper: Clipper] ~ { data: Data = NARROW[context.data]; IF clipper = NIL THEN { data.clientClipperPresent _ FALSE; data.clientClipper.refRep _ NIL; ccCount _ ccCount + 1; } ELSE { data.clientClipperPresent _ TRUE; data.clientClipperExclude _ clipper.exclude; data.clientClipper _ clipper.mask.Shift[data.sOriginView, data.fOriginView]; ccCount _ ccCount + 1; }; data.compositeClipperValid _ FALSE; }; IGet: PROC [context: Context, n: Name] RETURNS [REF] = { data: Data = NARROW[context.data]; SELECT n FROM $color => RETURN[data.currentColor]; ENDCASE => ERROR; }; ISet: PROC[context: Context, n: Name, x: REF] = { data: Data = NARROW[context.data]; SELECT n FROM $color => SetColor[data, NARROW[x, Color]]; ENDCASE => ERROR; }; IGetReal: PROC[context: Context, n: Name] RETURNS[REAL] = { data: Data = NARROW[context.data]; SELECT n FROM ENDCASE => ERROR; }; ISetReal: PROC[context: Context, n: Name, x: REAL] = { data: Data = NARROW[context.data]; SELECT n FROM ENDCASE => ERROR; }; IGetInt: PROC[context: Context, n: Name] RETURNS[INT] = { data: Data = NARROW[context.data]; SELECT n FROM priorityImportant => { RETURN [data.priorityImportant] }; ENDCASE => ERROR; }; ISetInt: PROC[context: Context, n: Name, x: INT] = { data: Data = NARROW[context.data]; SELECT n FROM priorityImportant => { data.priorityImportant _ x; [] _ data.pdState.SetPriorityImportant[data.leftoverMode AND x # 0]; }; ENDCASE => ERROR; }; MaskFromPath: PROC [data: Data, pathMap: PathMapType, pathData: REF] RETURNS [mask: Mask] = { GenPath: ImagerScanConverter.PathProc = { m: Transformation _ data.transformation; Xform: PROC [p: Pair] RETURNS [Pair] ~ {RETURN[[ m.a * p.x + m.b * p.y + m.c, m.d * p.x + m.e * p.y + m.f ]]}; Xmove: PROC [p: Pair] ~ { q: Pair = Xform[p]; move[q.x, q.y]; lp _ p }; Xline: PROC [p: Pair] ~ { q: Pair = Xform[p]; line[q.x, q.y]; lp _ p }; Xcurve: PROC [p1, p2, p3: Pair] ~ { q1: Pair = Xform[p1]; q2: Pair = Xform[p2]; q3: Pair = Xform[p3]; curve[q1.x, q1.y, q2.x, q2.y, q3.x, q3.y]; lp _ p3 }; Curve: PROC [p1, p2, p3: Pair] ~ {curve[p1.x, p1.y, p1.x, p1.y, p1.x, p1.y]}; Xconic: PROC [p1, p2: Pair, r: REAL] ~ { q1: Pair = Xform[p1]; q2: Pair = Xform[p2]; ImagerConic.ToCurves[lp, q1, q2, r, Curve]; lp _ p2; }; lp: Pair; pathMap[pathData, Xmove, Xline, Xcurve, Xconic]; }; Runs: PROC[ run: PROC[sMin, fMin: INTEGER, fSize: NAT], repeat: PROC[timesToRepeatScanline: NAT]] = { data.devicePath.ConvertToRuns[runProc: run]; }; data.devicePath _ ImagerScanConverter.CreatePath[pathProc: GenPath, scratch: data.devicePath]; mask _ ImagerMasks.Create[Runs]; }; MaskFromStroke: PROC [data: Data, pathMap: PathMapType, pathData: REF, strokeWidth: REAL, strokeEnd: StrokeEnd, closed: BOOL] RETURNS [mask: Mask] = { Runs: PROC[ run: PROC[sMin, fMin: INTEGER, fSize: NAT], repeat: PROC[timesToRepeatScanline: NAT]] = { data.devicePath.ConvertToRuns[runProc: run]; }; data.devicePath _ ImagerStroke.DevicePathFromStroke[ pathMap: pathMap, pathData: pathData, clientToDevice: data.transformation, width: strokeWidth, strokeEnd: strokeEnd, closed: FALSE, scratch: data.devicePath ]; mask _ ImagerMasks.Create[Runs]; }; MaskFromRectangle: PROC [data: Data, area: Rectangle] RETURNS [mask: Mask] ~ { GenPath: ImagerScanConverter.PathProc = { m: Transformation _ data.transformation; Xform: PROC [p: Pair] RETURNS [Pair] ~ {RETURN[[ m.a * p.x + m.b * p.y + m.c, m.d * p.x + m.e * p.y + m.f ]]}; { q: Pair = Xform[[area.x, area.y]]; move[q.x, q.y] }; { q: Pair = Xform[[area.x + area.w, area.y]]; line[q.x, q.y] }; { q: Pair = Xform[[area.x + area.w, area.y + area.h]]; line[q.x, q.y] }; { q: Pair = Xform[[area.x, area.y + area.h]]; line[q.x, q.y] }; }; Runs: PROC[ run: PROC[sMin, fMin: INTEGER, fSize: NAT], repeat: PROC[timesToRepeatScanline: NAT]] = { data.devicePath.ConvertToRuns[runProc: run]; }; IF data.transformation.type # hard THEN { p1: Pair _ ImagerTransform.Transform[[area.x, area.y], data.transformation]; p2: Pair _ ImagerTransform.Transform[[area.x+area.w, area.y+area.h], data.transformation]; sMin: INTEGER _ Real.RoundLI[MAX[MIN[p1.x, p2.x], -LAST[INTEGER]/2]]; sMax: INTEGER _ Real.RoundLI[MIN[MAX[p1.x, p2.x], LAST[INTEGER]/2]]; fMin: INTEGER _ Real.RoundLI[MAX[MIN[p1.y, p2.y], -LAST[INTEGER]/2]]; fMax: INTEGER _ Real.RoundLI[MIN[MAX[p1.y, p2.y], LAST[INTEGER]/2]]; RETURN [ImagerMasks.InlineBox[ [sMin: sMin, fMin: fMin, sSize: sMax-sMin, fSize: fMax-fMin]]]; }; data.devicePath _ ImagerScanConverter.CreatePath[pathProc: GenPath, scratch: data.devicePath]; mask _ ImagerMasks.Create[Runs]; }; ScaledFromReal: PROC [real: REAL] RETURNS [Scaled.Value] ~ TRUSTED { i: INT _ Real.RoundLI[real * 65536.0]; RETURN[LOOPHOLE[i]] }; MaskFromPixelArray: PROC[data: Data, pixelArray: PixelArray] RETURNS[Mask] = { destArea: Mask _ MaskFromRectangle[data, [0, 0, pixelArray.xPixels, pixelArray.yPixels]]; Runs: PROC[ run: PROC[sMin, fMin: INTEGER, fSize: NAT], repeat: PROC[timesToRepeatScanline: NAT]] = { buffer: PixelBuffer _ NEW[PixelBufferRep[destArea.fSize+1]]; DoRun: PROC[sMin, fMin: INTEGER, fSize: CARDINAL] = { nextPixel: Pair _ ImagerTransform.InverseTransformVec[[0, 1], data.transformation]; start: Pair _ ImagerTransform.InverseTransform[[0.5+sMin, 0.5+fMin], data.transformation]; xStart: Scaled.Value _ ScaledFromReal[start.x]; yStart: Scaled.Value _ ScaledFromReal[start.y]; xDeltaPixel: Scaled.Value _ ScaledFromReal[nextPixel.x]; yDeltaPixel: Scaled.Value _ ScaledFromReal[nextPixel.y]; runStart: NAT _ 0; fRel: NAT _ 0; pixelArray.get[pixelArray, buffer, fSize, 0, xStart, yStart, xDeltaPixel, yDeltaPixel]; WHILE fRel < fSize DO buffer[fSize] _ 0; WHILE buffer[fRel] # 0 DO fRel _ fRel + 1 ENDLOOP; IF fRel > runStart THEN {run[sMin, fMin + fRel, fRel - runStart]}; buffer[fSize] _ 1; WHILE buffer[fRel] = 0 DO fRel _ fRel + 1 ENDLOOP; runStart _ fRel; ENDLOOP; }; destArea.MapRuns[DoRun]; }; RETURN [ImagerMasks.Create[Runs]]; }; CompositeClipper: PROC [data: Data] RETURNS [Mask] ~ { IF NOT data.compositeClipperValid THEN { IF data.clientClipperPresent THEN { IF data.clientClipperExclude THEN data.compositeClipper _ data.viewClipper.Difference[data.clientClipper] ELSE data.compositeClipper _ data.viewClipper.And[data.clientClipper]; } ELSE data.compositeClipper _ data.viewClipper; data.compositeClipperValid _ TRUE; }; RETURN [data.compositeClipper] }; ccCount: INT _ 0; ClipMask: PROC [data: Data, mask: Mask, exclude: BOOLEAN] ~ { data.compositeClipperValid _ FALSE; IF NOT data.clientClipperPresent THEN { data.clientClipperPresent _ TRUE; data.clientClipperExclude _ exclude; data.clientClipper _ mask; ccCount _ ccCount + 1; } ELSE IF exclude THEN { IF data.clientClipperExclude THEN { data.clientClipper _ data.clientClipper.Or[mask]; ccCount _ ccCount + 1; } ELSE { data.clientClipper _ data.clientClipper.Difference[mask]; ccCount _ ccCount + 1; }; } ELSE { IF data.clientClipperExclude THEN { data.clientClipper _ mask.Difference[data.clientClipper]; ccCount _ ccCount + 1; data.clientClipperExclude _ FALSE; } ELSE { data.clientClipper _ data.clientClipper.And[mask]; ccCount _ ccCount + 1; }; }; }; ClipOutline: PROC [context: Context, pathMap: PathMapType, pathData: REF] ~ { data: Data _ NARROW[context.data]; ClipMask[data, MaskFromPath[data, pathMap, pathData], FALSE]; }; ExcludeOutline: PROC [context: Context, pathMap: PathMapType, pathData: REF] ~ { data: Data _ NARROW[context.data]; ClipMask[data, MaskFromPath[data, pathMap, pathData], TRUE]; }; ClipRectangle: PROC [context: Context, x, y, w, h: REAL] ~ { data: Data = NARROW[context.data]; ClipMask[data, MaskFromRectangle[data, [x, y, w, h]], FALSE]; }; ExcludeRectangle: PROC [context: Context, x, y, w, h: REAL] ~ { data: Data = NARROW[context.data]; ClipMask[data, MaskFromRectangle[data, [x, y, w, h]], TRUE]; }; IntegerClipRectangle: PROC[context: Context, x, y, w, h: INTEGER] ~ { ClipRectangle[context, x, y, w, h]; }; IntegerExcludeRectangle: PROC[context: Context, x, y, w, h: INTEGER] ~ { data: Data = NARROW[context.data]; ClipMask[data, MaskFromRectangle[data, [x, y, w, h]], TRUE]; }; InkWell: TYPE ~ ARRAY [0..16) OF PACKED ARRAY [0..16) OF [0..1]; InkWellGray: PROC [gray: [0..256]] RETURNS [inkWell: InkWell] ~ { i, j: NAT _ 0; FOR i: NAT IN [0..16) DO inkWell[i] _ [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]; ENDLOOP; WHILE gray>0 DO inkWell[i][j] _ 0; i _ i+1; IF i>=16 THEN {i_i-16; j _ j+1}; j _ j+3; IF j>=16 THEN j_j-16; gray_gray-1; ENDLOOP; }; InkWellGray45: PROC [gray: [0..256]] RETURNS [inkWell: InkWell] ~ { i, j: INTEGER _ 0; FOR i: NAT IN [0..16) DO inkWell[i] _ [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]; ENDLOOP; WHILE gray>0 DO inkWell[i][j] _ 0; i _ i+1; IF i>=16 THEN {i_i-16; j _ j+1}; j _ j-1; IF j<0 THEN j_j+16; gray_gray-1; ENDLOOP; }; InkWellGrayS: PROC [gray: [0..256]] RETURNS [inkWell: InkWell] ~ { i, j: INTEGER _ 0; FOR i: NAT IN [0..16) DO inkWell[i] _ [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]; ENDLOOP; WHILE gray>0 DO inkWell[i][j] _ 0; i _ i+3; IF i>=16 THEN {i_i-16; j _ j-1}; IF j<0 THEN j_j+16; gray_gray-1; ENDLOOP; }; ConstructGray: PROC [data: Data, toner: Toner, index: [0..64)] ~ { value: [0..256] _ trc[index]; inkWell: InkWell _ SELECT toner FROM yellow => InkWellGrayS[value], magenta => InkWellGray45[value], ENDCASE => InkWellGray[value]; bitsPtr: LONG POINTER; loadReference: PDFileWriter.LoadReference; TRUSTED {bitsPtr _ @inkWell}; loadReference _ data.pdState.LoadContiguousColorTile[phase: 0, sMin: 0, fMin: 0, sSize: 16, fSize: 16, bitsPtr: bitsPtr]; data.grayTileRef[toner][index] _ loadReference; }; SetColor: PROC[data: Data, color: Color] ~ { IF color = data.currentColor THEN RETURN; data.currentColor _ color; IF color = Imager.black THEN { DoToner: PROC [toner: Toner] ~ {data.pdState.SetColorInk[toner]}; data.pdState.DoForEachToner[DoToner]; } ELSE IF color = Imager.white THEN { DoToner: PROC [toner: Toner] ~ {data.pdState.SetColorClear[toner]}; data.pdState.DoForEachToner[DoToner]; } ELSE WITH color SELECT FROM constantColor: ConstantColor => { intensity: INT _ constantColor.Y; index: [0..64) _ MAX[MIN[intensity/(INT[LAST[CARDINAL]]/63), 63], 0]; DoToner: PROC [toner: Toner] = { IF data.grayTileRef[toner][index] = dummyLoadReference THEN ConstructGray[data, toner, index]; data.pdState.SetColorTile[toner, data.grayTileRef[toner][index]] }; data.pdState.DoForEachToner[DoToner]; }; specialColor: SpecialColor => { ERROR; }; sampledColor: SampledColor => NULL; ENDCASE => SetColor[data, Imager.black]; }; MaskStroke: PROC[context: Context, pathMap: PathMapType, pathData: REF, strokeWidth: REAL, strokeEnd: StrokeEnd] ~ { data: Data = NARROW[context.data]; mask: ImagerMasks.Mask _ MaskFromStroke[data, pathMap, pathData, strokeWidth, strokeEnd, FALSE]; ApplyMask[data, mask]; }; MaskStrokeClosed: PROC[context: Context, pathMap: PathMapType, pathData: REF, strokeWidth: REAL] = { data: Data = NARROW[context.data]; mask: ImagerMasks.Mask _ MaskFromStroke[data, pathMap, pathData, strokeWidth, nil, TRUE]; ApplyMask[data, mask]; }; MaskVector: PROC[context: Context, x1, y1, x2, y2: REAL] ~ { ERROR; }; IntegerMaskVector: PROC[context: Context, x1, y1, x2, y2: INTEGER] ~ { MaskVector[context, x1, y1, x2, y2]; }; ApplyMask: PROC [data: Data, mask: Mask] ~ { clipper: Mask _ CompositeClipper[data]; WITH data.currentColor SELECT FROM sampledColor: SampledColor => TRUSTED { transform: Transformation _ sampledColor.m; linePointer: LONG POINTER _ data.lineBuffer.refRep.pointer; Line: PROC [proc: PROC [LONG POINTER]] ~ TRUSTED {proc[linePointer]}; SampledColorRun: PROC [sMin, fMin: INTEGER, fSize: NAT] = TRUSTED { data.lineBuffer.sMin _ sMin; data.lineBuffer.fMin _ fMin; data.lineBuffer.sSize _ 1; data.lineBuffer.fSize _ fSize; ImagerHalftone.Halftone[data.lineBuffer, ImagerMasks.Box[[sMin: sMin, sSize: 1, fMin: fMin, fSize: fSize]], sampledColor.pa, transform, deviceBrick]; PDFileWriter.ColorSamples[data.pdState, black, sMin, fMin, 1, fSize, Line, opaque]; }; mask.MapClippedRuns[clipper, SampledColorRun]; }; ENDCASE => { DeliverRuns: PROC [SendRun: PROC [sMin, fMin, fSize: CARDINAL]] ~ { Run: PROC [sMin, fMin: INTEGER, fSize: NAT] ~ { SendRun[sMin, fMin, fSize]; }; mask.MapClippedRuns[clipper, Run]; }; PDFileWriter.MaskRunGroup[data.pdState, DeliverRuns]; }; }; MaskFill: PROC[context: Context, pathMap: PathMapType, pathData: REF] ~ { data: Data _ NARROW[context.data]; mask: Mask _ MaskFromPath[data, pathMap, pathData]; ApplyMask[data, mask]; }; MaskPixel: PROC [context: Context, pa: PixelArray] ~ { data: Data _ NARROW[context.data]; mask: Mask _ MaskFromPixelArray[data, pa]; ApplyMask[data, mask]; }; scratchPixelArray: PixelArray _ NEW[PixelArrayRep]; scratchBitmapDesc: REF ImagerPixelMaps.PixelMapRep _ NEW[ImagerPixelMaps.PixelMapRep]; MaskBits: PROC [context: Context, base: LONG POINTER, raster: CARDINAL, tile: IntRectangle, area: IntRectangle] ~ { ERROR; }; MaskRectangle: PROC[context: Context, x, y, w, h: REAL] = { data: Data _ NARROW[context.data]; mask: Mask _ MaskFromRectangle[data, [x, y, w, h]]; ApplyMask[data, mask]; }; IntegerMaskRectangle: PROC[context: Context, x, y, w, h: INTEGER] = { data: Data _ NARROW[context.data]; mask: Mask _ MaskFromRectangle[data, [x, y, w, h]]; ApplyMask[data, mask]; }; StartUnderline: PROC[context: Context] = { ERROR; }; MaskUnderline: PROC[context: Context, dy, h: REAL] = { ERROR; }; IntegerMaskUnderline: PROC[context: Context, dy, h: INTEGER] = { MaskUnderline[context, dy, h]; }; SetXY: PROC [context: Context, p: Pair] = { data: Data = NARROW[context.data]; data.currentPosition _ ImagerTransform.Transform[p, data.transformation]; }; IntegerSetXY: PROC [context: Context, x, y: INTEGER] = { SetXY[context, [x, y]]; }; SetXYRel: PROC [context: Context, v: Pair] = { data: Data = NARROW[context.data]; delta: Pair = ImagerTransform.TransformVec[v, data.transformation]; data.currentPosition.x _ data.currentPosition.x + delta.x; data.currentPosition.y _ data.currentPosition.y + delta.y; }; IntegerSetXYRel: PROC [context: Context, x, y: INTEGER] = { SetXYRel[context, [x, y]]; }; GetCP: PROC[context: Context] RETURNS[cp: Pair] ~ { data: Data = NARROW[context.data]; cp _ ImagerTransform.InverseTransform[data.currentPosition, data.transformation]; }; GetCPRounded: PROC[context: Context] RETURNS[cp: Pair] ~ { data: Data = NARROW[context.data]; cpr: Pair = [x: Real.RoundLI[data.currentPosition.x], y: Real.RoundLI[data.currentPosition.y]]; cp _ ImagerTransform.InverseTransform[cpr, data.transformation]; }; rasterToRunGroupStorageRatio: INT _ 1; MaskAndRunCount: TYPE ~ RECORD [mask: Mask, nRuns: INT]; GetCharMask: PROC [font: FONT, transformation: Transformation, char: CHAR] RETURNS [ans: MaskAndRunCount] ~ { nRuns: INT _ 0; Runs: PROC[ run: PROC[sMin, fMin: INTEGER, fSize: NAT], repeat: PROC[timesToRepeatScanline: NAT]] ~ { Run: PROC [sMin, fMin: INTEGER, fSize: NAT] ~ { run[sMin: sMin, fMin: fMin, fSize: fSize]; nRuns _ nRuns + 1; }; font.fontGraphicsClass.maskProc[font, transformation, char, Run]; }; nRuns _ 0; ans.mask _ ImagerMasks.Create[Runs]; ans.nRuns _ nRuns; }; FontCompositeTransform: PROC [data: Data, font: FONT] RETURNS [t: Transformation] ~ { t _ data.transformation; t.c _ t.f _ 0; t _ ImagerTransform.Concat[font.actualTransformation, t]; }; CharRepresentation: TYPE = {null, runGroup, raster}; CharLoadInfo: TYPE = RECORD[ sWidth, fWidth: Scaled.Value, loadRef: PDFileWriter.LoadReference, representation: CharRepresentation, mask: Mask, loadRepSize: INT ]; LoadRunGroup: PROC [pdState: PDFileWriter.PDState, mask: Mask] RETURNS [loadReference: PDFileWriter.LoadReference] ~ { DeliverRuns: PROC [SendRun: PROC [sMin, fMin, fSize: CARDINAL]] = { Run: PROC [sMin, fMin: INTEGER, fSize: NAT] = { SendRun[sMin-mask.SMin, fMin - mask.FMin, fSize]; }; mask.MapRuns[Run]; }; loadReference _ pdState.LoadRunGroup[DeliverRuns]; stats.loadRunGroups _ stats.loadRunGroups + 1; }; LoadBitmap: PROC [pdState: PDFileWriter.PDState, mask: Mask] RETURNS [loadReference: PDFileWriter.LoadReference] ~ { m: Mask _ mask.Bitmap; WITH m.refRep SELECT FROM b: REF ImagerPixelMaps.PixelMapRep => { loadReference _ pdState.LoadContiguousSampleArray[sSize: mask.sSize, fSize: mask.fSize, bitsPtr: b.pointer]; }; ENDCASE => ERROR; stats.loadRasters _ stats.loadRasters + 1; }; LoadCharData: PROC[self: ImagerFontCache.FontObject, charCode: CARDINAL] RETURNS [charData: REF, memoryCost: INT] = { font: FONT = NARROW[self.fontAnyData]; char: CHAR = 0C+charCode; transform: Transformation = ImagerTransform.Create[self.r0, self.r1, self.r2, self.r3, self.r4, self.r5]; -- character (to client) to device clientTransform: Transformation = ImagerTransform.Concat[ ImagerTransform.Invert[font.actualTransformation], transform]; loadInfo: REF CharLoadInfo _ NEW[CharLoadInfo]; maskN: MaskAndRunCount _ GetCharMask[font, transform, char]; runGroupSize: INT _ maskN.nRuns * 2 + 2; rasterSize: INT _ maskN.mask.sSize * INT[(maskN.mask.fSize+15)/16] + 2; width: Pair _ ImagerTransform.TransformVec[font.fontGraphicsClass.widthVectorProc[font, char], clientTransform]; loadInfo.loadRef _ dummyLoadReference; loadInfo.mask _ maskN.mask; SELECT TRUE FROM maskN.mask.sSize = 0 OR maskN.mask.fSize = 0 => { loadInfo.representation _ null; loadInfo.loadRepSize _ 0; }; maskN.mask.fSize > 32*Environment.bitsPerWord OR runGroupSize*rasterToRunGroupStorageRatio < rasterSize => { loadInfo.representation _ runGroup; loadInfo.loadRepSize _ runGroupSize; }; ENDCASE => { loadInfo.representation _ raster; loadInfo.loadRepSize _ rasterSize; }; loadInfo.sWidth _ Scaled.FromReal[width.x]; loadInfo.fWidth _ Scaled.FromReal[width.y]; RETURN[loadInfo, 0]; }; ShowChar: PROC [context: Context, char: CHAR, font: FONT] ~ { text: REF TEXT _ RefText.ObtainScratch[1]; text.length _ 1; text[0] _ char; ShowCharacters[context, text, font, 0, 1]; RefText.ReleaseScratch[text]; }; ShowCharacters: PROC [ context: Context, characters: REF, -- may be a ROPE or a REF TEXT font: FONT, start: INT _ 0, length: INT _ LAST[INT] ] ~ { data: Data = NARROW[context.data]; clipper: Mask _ CompositeClipper[data]; transform: Transformation _ FontCompositeTransform[data, font]; fontCode: ImagerFontCache.FontCode _ ImagerFontCache.GetFontCode[[ CharDataProc: LoadCharData, r0: transform.a, r1: transform.b, r2: transform.c, r3: transform.d, r4: transform.e, r5: transform.f, fontScalarData: 0, -- unused fontAnyData: font]]; sCurrent: Scaled.Value _ ScaledFromReal[data.currentPosition.x]; fCurrent: Scaled.Value _ ScaledFromReal[data.currentPosition.y]; DoChar: PROC[charCode: CARDINAL, charData: REF] = { loadInfo: REF CharLoadInfo _ NARROW[charData]; sCP: INTEGER _ sCurrent.Round; fCP: INTEGER _ fCurrent.Round; mask: Mask _ loadInfo.mask.Shift[sCP, fCP]; visibility: Visibility _ mask.IsVisible[clipper]; IF visibility = visible THEN WITH data.currentColor SELECT FROM sampled: SampledColor => visibility _ partlyVisible; ENDCASE => NULL; IF loadInfo.loadRef = dummyLoadReference AND visibility = visible THEN { IF data.pdState.RemainingLoadSize > loadInfo.loadRepSize + 5 THEN { SELECT loadInfo.representation FROM raster => loadInfo.loadRef _ LoadBitmap[data.pdState, loadInfo.mask]; runGroup => loadInfo.loadRef _ LoadRunGroup[data.pdState, loadInfo.mask]; ENDCASE; } ELSE visibility _ partlyVisible; }; SELECT visibility FROM visible => { SELECT loadInfo.representation FROM raster => { IF loadInfo.loadRef = dummyLoadReference THEN ERROR; data.pdState.MaskSamplesRef[loadInfo.loadRef, mask.SMin, mask.FMin]; stats.rasterChars _ stats.rasterChars + 1; }; runGroup => { IF loadInfo.loadRef = dummyLoadReference THEN ERROR; data.pdState.MaskRunGroupRef[loadInfo.loadRef, mask.SMin, mask.FMin]; stats.runGroupChars _ stats.runGroupChars + 1; }; null => NULL; ENDCASE => ERROR; }; partlyVisible => { ApplyMask[data, mask]; stats.clippedChars _ stats.clippedChars + 1; }; invisible => {stats.culledChars _ stats.culledChars + 1}; ENDCASE => ERROR; sCurrent _ sCurrent.PLUS[loadInfo.sWidth]; fCurrent _ fCurrent.PLUS[loadInfo.fWidth]; }; ImagerFontCache.GetStringData[DoChar, data.fontCache, fontCode, characters, start, length]; data.currentPosition _ [x: sCurrent.Float, y: fCurrent.Float]; }; CorrectMask: PROC[context: Context] = { ERROR; }; CorrectSpace: PROC[context: Context, v: Pair] = { ERROR; }; SetCorrectMeasure: PROC[context: Context, v: Pair] = { ERROR; }; SetCorrectTolerance: PROC[context: Context, v: Pair] = { ERROR; }; Space: PROC[context: Context, x: REAL] = { ERROR; }; IntegerSpace: PROC[context: Context, x: INTEGER] = { ERROR; }; Correct: PROC[context: Context, body: PROC] = { ERROR; }; DrawBitmap: PROC [context: Context, base: LONG POINTER, raster: CARDINAL, area: IntRectangle] ~ { ERROR; }; MaskFromSurfaceRectangle: PROC [data: Data, box: IntRectangle] RETURNS [Mask] ~ { deviceBox: IntRectangle _ ImagerTransform.TransformIntRectangle[box, data.surfaceToDevice]; RETURN [ImagerMasks.InlineBox[[deviceBox.x, deviceBox.y, deviceBox.w, deviceBox.h]]]; }; SetView: PROC [context: Context, box: IntRectangle, halftoneOrigin: IntPair _ [0, 0]] ~ { data: Data _ NARROW[context.data]; mask: Mask _ MaskFromSurfaceRectangle[data, box]; deviceOrigin: IntPair _ ImagerTransform.IntTransform[[box.x, box.y], data.surfaceToDevice]; sOriginView: INTEGER _ deviceOrigin.x; fOriginView: INTEGER _ deviceOrigin.y; sShift: INTEGER _ sOriginView-data.sOriginView; fShift: INTEGER _ fOriginView-data.fOriginView; newHalftoneOrigin: IntPair _ ImagerTransform.IntTransform[halftoneOrigin, data.surfaceToDevice]; IF data.doSaveCount # 0 THEN ERROR; -- Can't change a view with DoSave in progress. IF data.viewClipper = mask AND sShift = 0 AND fShift = 0 AND newHalftoneOrigin = [data.sOriginBrick, data.fOriginBrick] THEN RETURN; data.compositeClipperValid _ FALSE; data.compositeClipper.refRep _ NIL; IF data.clientClipperPresent THEN { data.clientClipper _ data.clientClipper.Shift[sShift, fShift]; ccCount _ ccCount + 1; }; data.viewClipper _ mask; data.currentPosition.x _ data.currentPosition.x + sShift; data.currentPosition.y _ data.currentPosition.y + fShift; data.transformation.c _ data.transformation.c + sShift; data.transformation.f _ data.transformation.f + fShift; data.viewToDevice.c _ data.viewToDevice.c + sShift; data.viewToDevice.f _ data.viewToDevice.f + fShift; data.sOriginView _ sOriginView; data.fOriginView _ fOriginView; [data.sOriginBrick, data.fOriginBrick] _ newHalftoneOrigin; }; ClipView: PROC [context: Context, box: IntRectangle, exclude: BOOLEAN] ~ { data: Data _ NARROW[context.data]; mask: Mask _ MaskFromSurfaceRectangle[data, box]; data.compositeClipperValid _ FALSE; data.compositeClipper.refRep _ NIL; data.viewClipper _ IF exclude THEN data.viewClipper.Difference[mask] ELSE data.viewClipper.And[mask]; }; MoveSurfaceRectangle: PROC [context: Context, source: IntRectangle, dest: IntPair] ~ { ERROR Imager.Error[$NotImplementedForThisDevice]; }; TestRectangle: PROC[context: Context, x, y, w, h: REAL] RETURNS[Visibility] = { data: Data = NARROW[context.data]; mask: Mask = MaskFromRectangle[data, [x, y, w, h]]; RETURN[mask.IsVisible[CompositeClipper[data]]]; }; GetSurfaceBounds: PROC[context: Context] RETURNS[IntRectangle] = { data: Data = NARROW[context.data]; b: DeviceRectangle = data.surfaceBounds; deviceToSurface: Transformation = ImagerTransform.Invert[data.surfaceToDevice]; RETURN [ImagerTransform.TransformIntRectangle[[b.sMin, b.fMin, b.sSize, b.fSize], deviceToSurface]] }; GetViewBounds: PROC[context: Context] RETURNS[IntRectangle] = { data: Data = NARROW[context.data]; deviceToSurface: Transformation = ImagerTransform.Invert[data.surfaceToDevice]; RETURN[ImagerTransform.TransformIntRectangle[[data.viewClipper.sMin, data.viewClipper.fMin, data.viewClipper.sSize, data.viewClipper.fSize], deviceToSurface]] }; NewPage: PROC [context: Context] ~ { data: Data _ NARROW[context.data]; data.pdState.EndPage; }; Close: PROC [context: Context] ~ { data: Data _ NARROW[context.data]; data.pdState.EndPage; data.pdState.Close; }; SpecialOp: PROC[context: Context, op: ATOM, data: REF] RETURNS [REF _ NIL] = { SELECT op FROM $NewPage => NewPage[context]; $Close => Close[context]; ENDCASE => ERROR Imager.Error[$UnimplementedSpecialOp]; }; LFDisplayClass: ImagerPrivate.Class _ NEW [ImagerPrivate.ClassRep _ [ deviceType: $PD, Init: Init, IGet: IGet, ISet: ISet, IGetReal: IGetReal, ISetReal: ISetReal, IGetInt: IGetInt, ISetInt: ISetInt, DoSave: DoSave, DoSaveAll: DoSaveAll, ConcatT: ConcatT, TranslateT: TranslateT, RotateT: RotateT, ScaleT: ScaleT, Scale2T: Scale2T, Move: Move, Trans: Trans, SetXY: SetXY, IntegerSetXY: IntegerSetXY, SetXYRel: SetXYRel, IntegerSetXYRel: IntegerSetXYRel, GetCP: GetCP, GetCPRounded: GetCPRounded, MaskFill: MaskFill, MaskStroke: MaskStroke, MaskStrokeClosed: MaskStrokeClosed, MaskVector: MaskVector, IntegerMaskVector: IntegerMaskVector, MaskRectangle: MaskRectangle, IntegerMaskRectangle: IntegerMaskRectangle, StartUnderline: StartUnderline, MaskUnderline: MaskUnderline, IntegerMaskUnderline: IntegerMaskUnderline, MaskPixel: MaskPixel, ClipOutline: ClipOutline, ExcludeOutline: ExcludeOutline, ClipRectangle: ClipRectangle, ExcludeRectangle: ExcludeRectangle, IntegerClipRectangle: IntegerClipRectangle, IntegerExcludeRectangle: IntegerExcludeRectangle, ShowChar: ShowChar, ShowCharacters: ShowCharacters, CorrectMask: CorrectMask, CorrectSpace: CorrectSpace, SetCorrectMeasure: SetCorrectMeasure, SetCorrectTolerance: SetCorrectTolerance, Space: Space, IntegerSpace: IntegerSpace, Correct: Correct, Reset: Reset, SetView: SetView, ClipView: ClipView, DrawBitmap: DrawBitmap, MaskBits: MaskBits, MoveSurfaceRectangle: MoveSurfaceRectangle, TestRectangle: TestRectangle, GetSurfaceBounds: GetSurfaceBounds, GetViewBounds: GetViewBounds, SpecialOp: SpecialOp ]]; ImagerPrivate.RegisterDevice[LFDisplayClass]; END. PImagerPDImpl.mesa Michael Plass, October 21, 1983 12:11 pm Procedures exported to ImagerPD These are surely wrong. $T => RETURN[ImagerTransform.Concat[data.transformation, ImagerTransform.Invert[data.viewToDevice]]]; $T => data.transformation _ ImagerTransform.Concat[x, data.viewToDevice]; move: PROC [s, f: REAL], line: PROC [s, f: REAL], curve: PROC [s1, f1, s2, f2, s3, f3: REAL] Transforms (x, y) to (s, f)  note s comes first for ScanConvert! move: PROC [s, f: REAL], line: PROC [s, f: REAL], curve: PROC [s1, f1, s2, f2, s3, f3: REAL] Because of an apparent bug in Real.FScale. Ê&u˜Jšœ™™(J˜—šÏk ˜ Jšœ ˜ Jšœ˜Jšœ˜Jšœ œÓ˜äJ˜ Jšœ˜Jšœ˜Jšœ ˜ J˜ Jšœ˜Jšœ˜Jšœ˜Jšœ ˜ Jšœ˜Jšœ ˜ Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜J˜—JšÏn œœ˜Jšœ»˜ÂJšœ ˜šœœœ ˜J˜—Jšœœ˜5šœœ!˜;J˜—™š žœœœ œœ˜Cšœœ˜$Jšœ5œ˜˜>—Jšœ œœ˜/Jšœ<˜˜>Jšœ˜J˜—šž œœ˜'Jšœ˜J˜J˜—šž œœ˜1Jšœ˜J˜J˜—šžœœ˜6Jšœ˜J˜J˜—šžœœ˜8Jšœ˜J˜J˜—šžœœœ˜*Jšœ˜J˜J˜—šž œœœ˜4Jšœ˜J˜J˜—šžœœœ˜/Jšœ˜J˜J˜—š ž œœœœ œ˜aJšœ˜Jšœ˜J˜—šžœœ!œ ˜QJšœ[˜[JšœO˜UJšœ˜J˜—šžœœL˜YJšœ œ˜"Jšœ1˜1Jšœ[˜[Jšœ œ˜&Jšœ œ˜&Jšœœ ˜/Jšœœ ˜/Jšœ`˜`JšœœœŸ/˜SJš œœ œ œ<œœ˜„Jšœœ˜#Jšœœ˜#šœœ˜#Jšœ>˜>J˜J˜—Jšœ˜Jšœ9˜9Jšœ9˜9Jšœ7˜7Jšœ7˜7Jšœ3˜3Jšœ3˜3Jšœ˜Jšœ˜Jšœ;˜;Jšœ˜J˜—šžœœ0œ˜JJšœ œ˜"Jšœ1˜1Jšœœ˜#Jšœœ˜#šœ˜Jšœ œ"˜1Jšœ˜ —Jšœ˜J˜—šžœœ<˜VJšœ,˜1Jšœ˜J˜—šž œœœœ˜OJšœ œ˜"Jšœ3˜3Jšœ)˜/Jšœ˜J˜—šžœœœ˜BJšœ œ˜"Jšœ(˜(JšœO˜OJšœ]˜cJšœ˜J˜—šž œœœ˜?Jšœ œ˜"JšœO˜OJšœ˜˜žJšœ˜J˜—šžœœ˜$Jšœ œ˜"Jšœ˜Jšœ˜J˜—šžœœ˜"Jšœ œ˜"Jšœ˜Jšœ˜Jšœ˜J˜—šž œœœœœœœ˜Nšœ˜J˜J˜Jšœœ'˜7—Jšœ˜J˜—šœ&œ˜EJšœ˜Jšœ ˜ Jšœ ˜ Jšœ ˜ Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ ˜ Jšœ ˜ Jšœ ˜ Jšœ˜Jšœ˜Jšœ!˜!Jšœ ˜ Jšœ˜Jšœ˜Jšœ˜Jšœ#˜#Jšœ˜Jšœ%˜%Jšœ˜Jšœ+˜+Jšœ˜Jšœ˜Jšœ+˜+Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ#˜#Jšœ+˜+Jšœ1˜1Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ%˜%Jšœ)˜)Jšœ ˜ Jšœ˜Jšœ˜Jšœ ˜ Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ+˜+Jšœ˜Jšœ#˜#Jšœ˜Jšœ˜Jšœ˜J˜—šœ-˜-J˜—Jšœ˜—…—ƒx¬=