<> <> <> DIRECTORY Basics USING [bitsPerWord, LongMult], ImagerColor, ImagerDevice USING [Class, ClassRep, Device, DeviceRep, HalftoneParameters, RunProc], ImagerPixelArray, ImagerPixelMap, ImagerPixelRow, ImagerSampler USING [CreateSampler, ObtainInterpolatedSamples, Sampler], ImagerTransformation USING [Cat, PreRotate, Transformation, Translate], PrincOps USING [BBTableSpace, BitBltTable, BitBltTablePtr, zBNDCK, zINC], PrincOpsUtils USING [AlignedBBTable, BITBLT], Real USING [FixC, RoundC], Terminal, Vector2 USING [VEC]; ImagerColor24DeviceImpl: CEDAR PROGRAM IMPORTS Basics, ImagerColor, ImagerPixelArray, ImagerPixelMap, ImagerPixelRow, ImagerSampler, ImagerTransformation, PrincOpsUtils, Real, Terminal ~ BEGIN Device: TYPE ~ ImagerDevice.Device; RunProc: TYPE ~ ImagerDevice.RunProc; HalftoneParameters: TYPE ~ ImagerDevice.HalftoneParameters; DeviceRectangle: TYPE ~ ImagerPixelMap.DeviceRectangle; VEC: TYPE ~ Vector2.VEC; Transformation: TYPE ~ ImagerTransformation.Transformation; Color: TYPE ~ ImagerColor.Color; ConstantColor: TYPE ~ ImagerColor.ConstantColor; SampledColor: TYPE ~ ImagerColor.SampledColor; SpecialColor: TYPE ~ ImagerColor.SpecialColor; ColorOperator: TYPE ~ ImagerColor.ColorOperator; ColorOperatorRep: TYPE ~ ImagerColor.ColorOperatorRep; Case: TYPE ~ {nil, constant, sampled}; Data: TYPE ~ REF DataRep; DataRep: TYPE ~ RECORD[ frameA: ImagerPixelMap.PixelMap _ [0, 0, 0, 0, 0, 0, NIL], -- frame buffer for A channel frameB: ImagerPixelMap.PixelMap _ [0, 0, 0, 0, 0, 0, NIL], -- frame buffer for B channel pixelsPerInch: REAL, -- declared resolution case: Case _ nil, -- what type of color function: ImagerPixelMap.Function _ [null, null], -- bitblt function pixelA, pixelB: CARDINAL _ 0, -- bitblt gray values pa: ImagerPixelArray.PixelArray _ NIL, -- pixel array from sampled color colorOperator: ImagerColor.ColorOperator _ NIL, paToDevice: Transformation _ NIL, -- transformation from pa coords to display sourceR: ImagerPixelMap.PixelMap _ [0, 0, 0, 0, 0, 0, NIL], -- source values for red sourceB: ImagerPixelMap.PixelMap _ [0, 0, 0, 0, 0, 0, NIL], -- source values for green sourceG: ImagerPixelMap.PixelMap _ [0, 0, 0, 0, 0, 0, NIL], -- source values for blue paSampler: ImagerSampler.Sampler _ NIL -- for sampling pixel array ]; class: ImagerDevice.Class ~ NEW[ImagerDevice.ClassRep _ [ type: $Color24Display, SetColor: SetColor, SetPriority: SetPriority, SetHalftone: SetHalftone, MaskRuns: MaskRuns ]]; defaultPixelsPerInch: REAL ~ 42; vt: Terminal.Virtual _ Terminal.Current[]; Create: PUBLIC PROC[pixelsPerInch: REAL _ defaultPixelsPerInch] RETURNS[Device] ~ { data: Data ~ NEW[DataRep _ [pixelsPerInch: pixelsPerInch]]; fSize, sSize: NAT _ 0; surfaceToDevice: Transformation _ NIL; [] _ Terminal.SetColorMode[vt, [TRUE, 0, 0]]; FOR i: NAT IN[0..256) DO Terminal.SetRedMap[vt, i, i]; Terminal.SetGreenMap[vt, i, i]; Terminal.SetBlueMap[vt, i, i]; ENDLOOP; Terminal.TurnOnColorDisplay[vt]; fSize _ vt.colorWidth; sSize _ vt.colorHeight; TRUSTED { lines: NAT ~ vt.colorHeight; rastA: CARDINAL ~ vt.colorWordsPerLineA; rastB: CARDINAL ~ vt.colorWordsPerLineB; data.frameA _ ImagerPixelMap.CreateFrameBuffer[pointer: vt.colorBitmapA, words: INT[rastA]*sSize, lgBitsPerPixel: 4, rast: rastA, lines: lines]; data.frameB _ ImagerPixelMap.CreateFrameBuffer[pointer: vt.colorBitmapB, words: INT[rastB]*sSize, lgBitsPerPixel: 3, rast: rastB, lines: lines]; }; surfaceToDevice _ ImagerTransformation.Translate[[sSize, 0]]; surfaceToDevice.PreRotate[90]; RETURN[NEW[ImagerDevice.DeviceRep _ [class: class, clipBox: [sMin: 0, fMin: 0, sSize: sSize, fSize: fSize], surfaceToDevice: surfaceToDevice, surfaceUnitsPerInch: [pixelsPerInch, pixelsPerInch], surfaceUnitsPerPixel: 1, data: data]]]; }; Val: TYPE ~ ImagerPixelArray.Val; Table: TYPE ~ REF TableRep; TableRep: TYPE ~ RECORD[SEQUENCE size: NAT OF CARDINAL]; BuildTable: PROC[max: Val, scale: REAL, sWhite, sBlack: REAL, map: ImagerColor.SampleMap _ NIL] RETURNS[Table] ~ { table: Table ~ NEW[TableRep[max+1]]; FOR s0: Val IN[0..max] DO s: REAL ~ IF map=NIL THEN s0 ELSE map[s0]; v: REAL ~ MIN[MAX[(s-sBlack)/(sWhite-sBlack), 0], 1]; table[s0] _ Real.FixC[scale*v]; ENDLOOP; RETURN[table]; }; SetColor: PROC[device: Device, color: Color, viewToDevice: Transformation] ~ { data: Data ~ NARROW[device.data]; WITH color SELECT FROM color: ConstantColor => { rgb: ImagerColor.RGB ~ ImagerColor.RGBFromCIE[color.cie]; rPixel: [0..256) ~ Real.RoundC[MIN[MAX[rgb.r, 0], 1]*255]; gPixel: [0..256) ~ Real.RoundC[MIN[MAX[rgb.g, 0], 1]*255]; bPixel: [0..256) ~ Real.RoundC[MIN[MAX[rgb.b, 0], 1]*255]; data.function _ [null, null]; data.pixelA _ rPixel*256+gPixel; data.pixelB _ bPixel*256+bPixel; data.case _ constant; }; color: SampledColor => { pa: ImagerPixelArray.PixelArray ~ color.pa; colorOperator: ImagerColor.ColorOperator ~ color.colorOperator; data.paToDevice _ ImagerTransformation.Cat[pa.m, color.um, viewToDevice]; data.paSampler _ ImagerSampler.CreateSampler[ m: data.paToDevice, x: 0, y: 0, sPixels: pa.sSize, fPixels: pa.fSize]; data.case _ sampled; IF data.pa#pa OR data.colorOperator#colorOperator THEN { samples: ImagerPixelArray.Row ~ NEW[ImagerPixelArray.RowRep[pa.fSize]]; row: ImagerPixelRow.PixelRow ~ ImagerPixelRow.CreatePixelRow[ sMin: 0, fMin: 0, fSize: pa.fSize]; data.sourceR _ ImagerPixelMap.Create[lgBitsPerPixel: 3, bounds: [sMin: 0, fMin: 0, sSize: pa.sSize, fSize: pa.fSize]]; data.sourceG _ ImagerPixelMap.Create[lgBitsPerPixel: 3, bounds: [sMin: 0, fMin: 0, sSize: pa.sSize, fSize: pa.fSize]]; data.sourceB _ ImagerPixelMap.Create[lgBitsPerPixel: 3, bounds: [sMin: 0, fMin: 0, sSize: pa.sSize, fSize: pa.fSize]]; WITH colorOperator SELECT FROM < {>> <> <> <> <> <> <> <> <> <> <> <<};>> op: REF ColorOperatorRep.separations => { sum: ImagerPixelRow.PixelRow ~ ImagerPixelRow.CreatePixelRow[ sMin: 0, fMin: 0, fSize: pa.fSize]; tables: ARRAY[0..4) OF Table _ ALL[NIL]; IF pa.samplesPerPixel#op.samplesPerPixel THEN ERROR; -- samplesPerPixel must match <<-- Red>> FOR i: NAT IN[0..pa.samplesPerPixel) DO sep: ImagerColor.Separation ~ op[i]; rgb: ImagerColor.RGB ~ ImagerColor.RGBFromCIE[sep.cie]; tables[i] _ BuildTable[max: pa.MaxSampleValue[i], scale: 255*rgb.r, sWhite: sep.sMax, sBlack: sep.sMin, map: sep.map]; ENDLOOP; FOR s: NAT IN[0..pa.sSize) DO row.sOrigin _ s; ImagerPixelRow.ClearPixelRow[row]; FOR i: NAT IN[0..pa.samplesPerPixel) DO table: Table ~ tables[i]; ImagerPixelArray.GetRow[pa, samples, s, 0, i]; FOR f: NAT IN[0..pa.fSize) DO row[f] _ row[f]+table[samples[f]] ENDLOOP; ENDLOOP; ImagerPixelRow.StorePixelRow[row, data.sourceR]; ENDLOOP; <<-- Green>> FOR i: NAT IN[0..pa.samplesPerPixel) DO sep: ImagerColor.Separation ~ op[i]; rgb: ImagerColor.RGB ~ ImagerColor.RGBFromCIE[sep.cie]; tables[i] _ BuildTable[max: pa.MaxSampleValue[i], scale: 255*rgb.g, sWhite: sep.sMax, sBlack: sep.sMin, map: sep.map]; ENDLOOP; FOR s: NAT IN[0..pa.sSize) DO row.sOrigin _ s; ImagerPixelRow.ClearPixelRow[row]; FOR i: NAT IN[0..pa.samplesPerPixel) DO table: Table ~ tables[i]; ImagerPixelArray.GetRow[pa, samples, s, 0, i]; FOR f: NAT IN[0..pa.fSize) DO row[f] _ row[f]+table[samples[f]] ENDLOOP; ENDLOOP; ImagerPixelRow.StorePixelRow[row, data.sourceG]; ENDLOOP; <<-- Blue>> FOR i: NAT IN[0..pa.samplesPerPixel) DO sep: ImagerColor.Separation ~ op[i]; rgb: ImagerColor.RGB ~ ImagerColor.RGBFromCIE[sep.cie]; tables[i] _ BuildTable[max: pa.MaxSampleValue[i], scale: 255*rgb.b, sWhite: sep.sMax, sBlack: sep.sMin, map: sep.map]; ENDLOOP; FOR s: NAT IN[0..pa.sSize) DO row.sOrigin _ s; ImagerPixelRow.ClearPixelRow[row]; FOR i: NAT IN[0..pa.samplesPerPixel) DO table: Table ~ tables[i]; ImagerPixelArray.GetRow[pa, samples, s, 0, i]; FOR f: NAT IN[0..pa.fSize) DO row[f] _ row[f]+table[samples[f]] ENDLOOP; ENDLOOP; ImagerPixelRow.StorePixelRow[row, data.sourceB]; ENDLOOP; }; ENDCASE => ERROR; -- unknown ColorOperator data.pa _ pa; data.colorOperator _ colorOperator; }; }; color: SpecialColor => SELECT color.ref FROM $XOR => { data.function _ [xor, null]; data.pixelA _ data.pixelB _ 177777B; data.case _ constant; }; ENDCASE => ERROR; -- unknown special color ENDCASE => ERROR; -- unknown color variant }; SetPriority: PROC[device: Device, priorityImportant: BOOL] ~ { }; SetHalftone: PROC[device: Device, halftone: HalftoneParameters] ~ { }; nullBitBltTable: PrincOps.BitBltTable ~ [ dst: [word: NIL, bit: 0], dstBpl: 0, src: [word: NIL, bit: 0], srcDesc: [srcBpl[0]], width: 0, height: 0, flags: []]; Check: PROC[x: INTEGER, max: NAT] RETURNS[NAT] ~ TRUSTED MACHINE CODE { PrincOps.zINC; PrincOps.zBNDCK }; <> MaskRuns: PROC[device: Device, runs: PROC[RunProc]] ~ { data: Data ~ NARROW[device.data]; frameA: ImagerPixelMap.PixelMap ~ data.frameA; frameB: ImagerPixelMap.PixelMap ~ data.frameB; SELECT data.case FROM nil => ERROR; -- color not initialized constant => TRUSTED { bbspaceA: PrincOps.BBTableSpace; bbA: PrincOps.BitBltTablePtr ~ PrincOpsUtils.AlignedBBTable[@bbspaceA]; bbspaceB: PrincOps.BBTableSpace; bbB: PrincOps.BitBltTablePtr ~ PrincOpsUtils.AlignedBBTable[@bbspaceB]; baseA: LONG POINTER ~ frameA.refRep.pointer; baseB: LONG POINTER ~ frameB.refRep.pointer; rastA: CARDINAL ~ frameA.refRep.rast; rastB: CARDINAL ~ frameB.refRep.rast; grayA: LONG POINTER ~ @data.pixelA; grayB: LONG POINTER ~ @data.pixelB; run: PROC[sMin, fMin: INTEGER, fSize: NAT] ~ TRUSTED { f: NAT ~ Check[fMin, frameA.fSize]; s: NAT ~ Check[sMin, frameA.sSize]; bbA.dst.word _ baseA+Basics.LongMult[s, rastA]+f; bbA.dst.bit _ 0; bbA.width _ 16*Check[fSize, frameA.fSize-f]; bbA.height _ Check[1, frameA.sSize-s]; PrincOpsUtils.BITBLT[bbA]; bbB.dst.word _ baseB+Basics.LongMult[s, rastB]+f/2; bbB.dst.bit _ 8*(f MOD 2); bbB.width _ 8*Check[fSize, frameA.fSize-f]; bbB.height _ Check[1, frameA.sSize-s]; PrincOpsUtils.BITBLT[bbB]; }; bbA^ _ nullBitBltTable; bbB^ _ nullBitBltTable; bbA.dstBpl _ rastA*Basics.bitsPerWord; bbB.dstBpl _ rastB*Basics.bitsPerWord; bbA.src.word _ grayA; bbB.src.word _ grayB; bbA.src.bit _ 0; bbB.src.bit _ 0; bbA.srcDesc.gray _ [yOffset: 0, widthMinusOne: 0, heightMinusOne: 0]; bbB.srcDesc.gray _ [yOffset: 0, widthMinusOne: 0, heightMinusOne: 0]; bbA.flags _ [direction: forward, disjoint: TRUE, gray: TRUE, srcFunc: data.function.srcFunc, dstFunc: data.function.dstFunc]; bbB.flags _ [direction: forward, disjoint: TRUE, gray: TRUE, srcFunc: data.function.srcFunc, dstFunc: data.function.dstFunc]; runs[run]; }; sampled => { rowR: ImagerPixelRow.PixelRow ~ ImagerPixelRow.CreatePixelRow[ sMin: 0, fMin: 0, fSize: frameA.fSize]; rowG: ImagerPixelRow.PixelRow ~ ImagerPixelRow.CreatePixelRow[ sMin: 0, fMin: 0, fSize: frameA.fSize]; run: PROC[sMin, fMin: INTEGER, fSize: NAT] ~ { rowR.sOrigin _ rowG.sOrigin _ Check[sMin, frameA.sSize]; rowR.fOrigin _ rowG.fOrigin _ Check[fMin, frameA.fSize]; rowR.fSize _ rowG.fSize _ Check[fSize, frameA.fSize-fMin]; ImagerSampler.ObtainInterpolatedSamples[sampler: data.paSampler, pixelRow: rowR, source: data.sourceR]; ImagerSampler.ObtainInterpolatedSamples[sampler: data.paSampler, pixelRow: rowG, source: data.sourceG]; FOR f: NAT IN[0..rowR.fSize) DO rowR[f] _ rowR[f]*256+rowG[f]; ENDLOOP; ImagerPixelRow.StorePixelRow[rowR, frameA]; ImagerSampler.ObtainInterpolatedSamples[sampler: data.paSampler, pixelRow: rowR, source: data.sourceB]; ImagerPixelRow.StorePixelRow[rowR, frameB]; }; runs[run]; }; ENDCASE => ERROR; -- illegal case }; <<>> END.