<<>> <> <> <> <> <<>> DIRECTORY ColorizeViewPoint, ColorizeViewPointBackdoor, ColorizeViewPointGraphicsCommon, ColorizeViewPointSweep, Convert, Ieee, IO, IPMaster, IPScan, PBasics, Profiles, Rope, SymTab, Vector2; ColorizeViewPointGraphicsCommonImpl: CEDAR PROGRAM IMPORTS ColorizeViewPoint, ColorizeViewPointBackdoor, ColorizeViewPointSweep, Convert, IO, IPMaster, IPScan, PBasics, Profiles, Rope, SymTab EXPORTS ColorizeViewPointGraphicsCommon ~ BEGIN OPEN ColorizeViewPointGraphicsCommon; Colorization: TYPE ~ ColorizeViewPointBackdoor.Colorization; Profile: TYPE ~ Profiles.Profile; ROPE: TYPE ~ Rope.ROPE; SampledColorIPFragments: TYPE ~ ColorizeViewPointBackdoor.SampledColorIPFragments; SampledColorTransformSet: TYPE ~ ColorizeViewPointSweep.SampledColorTransformSet; ASSERTION: TYPE ~ BOOL [TRUE..TRUE]; <> ColorizeGraphics: PUBLIC PROC [ip: ROPE, subs: SubsInfo, opList: LIST OF Op, getColor: GetColorProc, seqList: LIST OF Seq _ NIL, customOnly: BOOL _ FALSE] RETURNS [colorizedIP: ROPE _ NIL] ~ { PerColorSpecified: IPScan.ScanProc = { <<[min: INT, max: INT, op: IPMaster.Op _ nil, seq: IPScan.Seq _ nil, num: INTEGER _ 0, punt: BOOL _ FALSE]>> color, addendum: ROPE _ NIL; -- addendum follows replacementColor to store it correctly replacementColor: REF; [newMin: min, newMax: max, color: color, addendum: addendum] _ getColor[ip, min, max]; --client defines the piece of the ip to be replaced and what addendum to add after the replacement IF color=NIL THEN RETURN; --client returns NIL if ip segment unrecognized; leave alone replacementColor _ GetReplacementColor[color: color, subs: subs, customOnly: customOnly]; IF ~customOnly AND replacementColor=NIL AND color.Find["\017\317\224\240\347"]#-1 --YES color-- THEN {ColorizeViewPointBackdoor.SetProfileBoolean[profile: subs.palette, key: "AmbushAllYESColors", val: FALSE]; ColorizeViewPointBackdoor.SetProfileBoolean [profile: subs.palette, key: "IP2", val: FALSE]}; --replacementColor=NIL means a YES color isn't getting changed, so don't remove YES operators and don't use 2.0 header IF ~punt AND replacementColor#NIL THEN WITH replacementColor SELECT FROM replacementColor: ROPE => { --Constant color colorizedIP _ colorizedIP.Cat[ip.Substr[start: flushFrom, len: min-flushFrom], replacementColor, addendum]; --replace MakeSampledBlack section w/ replacementColor flushFrom _ max; --reset marker to after original color & ISET section }; replacementColor: REF SampledColorIPFragments => { --Sampled color (sweep) replacement: ROPE _ NARROW[sampledColors.Fetch[key: color].val]; ts: SampledColorTransformSet; pos: INT; SELECT TRUE FROM replacement#NIL => { --Have already spatially resolved this color in ENDCASE below colorizedIP _ colorizedIP.Cat[ip.Substr[start: flushFrom, len: min-flushFrom], replacement, addendum]; --replace MakeSampledBlack section w/ replacement flushFrom _ max; --reset marker to after original color & ISET section }; (([transformSet: ts, finalPos: pos] _ BuildTransformSet[ip: ip, pos: max, remove: replacementColor.removeDefiningObject]).transformSet = nullTransformSet) => SIGNAL ColorizeViewPoint.Warning[$MalformedDefiningObject, "Malformed Sweep defining object"]; --Failure (but on non-failures this branch causes the transformation vector set to be built before going to ENDCASE) ENDCASE => { --build the transform for the pixel array replacement _ Rope.Cat[replacementColor.beforeTransform, ColorizeViewPointSweep.ConstructSweepTransform[ts: ts, sc: replacementColor], replacementColor.afterTransform]; [] _ SymTab.Store[x: sampledColors, key: color, val: replacement]; colorizedIP _ colorizedIP.Cat[ip.Substr[start: flushFrom, len: min-flushFrom], replacement, addendum]; --replace original color and MaskRectangle section with a MakeSampledColor section. MaskRectangle is removed (if "removeDefiningObject" is TRUE) because it is not part of the image; it is only used to define sweep size and angle parms flushFrom _ pos; --throws out the defining rectangle or triangle if "removeDefiningObject" is TRUE, otherwise (default) keeps it. }; }; ENDCASE => ERROR; }; sampledColors: SymTab.Ref ~ SymTab.Create[]; flushFrom: INT _ 0; IPScan.ScanRope[ip: ip, ops: opList, seqs: seqList, action: PerColorSpecified]; colorizedIP _ colorizedIP.Concat[ip.Substr[start: flushFrom, len: ip.Size]]; }; GetReplacementColor: PROC [color: ROPE, subs: SubsInfo, customOnly: BOOL _ FALSE] RETURNS [ipFrag: REF _ NIL] ~ {--customOnly => only look in Custom palette for color lookupColor: REF _ SymTab.Fetch[x: subs.subs, key: color].val; --first time, should be a Color like [25%AC, $CVPPattern]. After that, an already resolved REF IF lookupColor#NIL THEN WITH lookupColor SELECT FROM getVal: Color => { --not previously resolved value: LIST OF ROPE; levelsExceeded: BOOL; [value, levelsExceeded] _ ColorizeViewPointBackdoor.GetRecursiveValue[key: getVal.value, palette: subs.palette, subpaletteList: subs.subpaletteList, mapData: subs.mapData, customOnly: customOnly]; SELECT TRUE FROM value=NIL => { [] _ SymTab.Store[x: subs.subs, key: color, val: NIL];--saves time next time RETURN; }; levelsExceeded => { [] _ SymTab.Store[x: subs.subs, key: color, val: NIL];--saves time next time SIGNAL ColorizeViewPoint.Warning[class: $MalformedPaletteEntry, explanation: IO.PutFR[format: "%g is part of a recursive color definition beyond allowable levels; ignoring it.", v1: [rope[color]]]]; RETURN; }; ENDCASE => { ipFrag _ ColorizeViewPointBackdoor.IPFragmentForColorDefinition[value, subs.palette]; [] _ SymTab.Store[x: subs.subs, key: color, val: ipFrag];--so already done next time }; }; ENDCASE --already resolved before-- => RETURN [lookupColor]; }; nullTransformSet: SampledColorTransformSet ~ ColorizeViewPointSweep.nullTransformSet; BuildTransformSet: PROC [ip: ROPE, pos: INT, remove: BOOL] RETURNS [transformSet: SampledColorTransformSet, finalPos: INT] ~ { <> <> <> <> <> <> <> Token: PROC RETURNS [IPMaster.Token] ~ { [token: token, next: pos] _ IPMaster.GetToken[encoding: ip, start: pos]; <> IF token.seq=sequenceInteger THEN { token.type _ num; token.num _ IPMaster.IntFromSequenceData[text: Rope.ToRefText[ip.Substr[pos, token.len]]]; --not bothering to reset token.seq and token.len pos _ pos + token.len; --move pointer beyond sequence; for seqs, pos is not moved by IPMaster.GetToken }; RETURN [token]; }; token: IPMaster.Token; t: SampledColorTransformSet; transformSet _ nullTransformSet; finalPos _ pos; --Return values for error <> IF Token[].type=num THEN t.offset.x _ token.num ELSE RETURN; --n1 IF Token[].type=num THEN t.offset.y _ token.num ELSE RETURN; --n2 IF Token[].type=op AND token.op=setxy THEN {--occasionally an n1 n2 SETXY is stuck in the way (eg, in Bitmapper graphics frames) IF Token[].type=num THEN t.offset.x _ token.num ELSE RETURN; --n1 again IF Token[].type=num THEN t.offset.y _ token.num ELSE RETURN; --n2 again [] _ Token[]; --advance token to look at next }; SELECT TRUE FROM token.type=num => { --Case I : n3 found t.width.x _ token.num; t.width.y _ 0; IF Token[].type#num THEN RETURN; --looking for n4 else error t.height.x _ 0; t.height.y _ token.num; IF t.width.x<0 AND t.height.y<0 --typical BasicGraphics pattern starts the rectangle farthest from origin and subtracts the length and width; relocate the startpoint closest to origin and add length and width to match ProIllustrator-- THEN { t.offset.x _ t.offset.x+t.width.x; t.offset.y _ t.offset.y+t.height.y; t.width.x _ ABS[t.width.x]; -- height and width positive t.height.y _ ABS[t.height.y]; }; IF Token[].op#maskrectangle THEN RETURN; --end Case1 }; token.type=op AND token.op=moveto => { --Cases II and III - triangles temp: IPMaster.Token; IF Token[].type=num THEN t.width.x _ token.num - t.offset.x ELSE RETURN; --width will be the first leg of the triangle drawn IF Token[].type=num THEN t.width.y _ token.num - t.offset.y ELSE RETURN; IF Token[]--.type#op OR token--.op#lineto THEN RETURN; IF Token[].type=num THEN t.height.x _ token.num - (t.offset.x+t.width.x) ELSE RETURN; --height will be the second leg of the triangle drawn IF Token[].type=num THEN t.height.y _ token.num - (t.offset.y+t.width.y) ELSE RETURN; IF Token[]--.type#op OR token--.op#lineto THEN RETURN; IF (temp _ Token[]).type#num THEN RETURN; --Could be 1 or n1 SELECT Token[].type FROM op => { --Case II IF temp.num#1 OR token.op#makeoutline THEN RETURN; }; num => { --Case III IF t.offset#[x: temp.num, y: token.num] OR Token[]--.type#op OR token--.op#lineto OR Token[]--.type#num OR token--.num#1 OR Token[]--.type#op OR token--.op#makeoutline THEN RETURN; }; ENDCASE => RETURN; IF Token[]--.type#op OR token--.op#maskfill THEN RETURN; --end Cases II and III }; ENDCASE => RETURN; <> transformSet _ t; IF remove THEN finalPos _ pos; --ELSE finalpos doesn't change }; InvalidGfxKey: PUBLIC ERROR ~ CODE; --Never seen outside GfxPaletteFromProfile: PUBLIC PROC [profile: Profiles.Profile, seqAction: SeqAction, gfxTexture: GfxTextureProc, gfxGray: GfxGrayProc, transparent, opaque: BOOL _ TRUE] ~ {--looks up each pattern in profile, uses callbacks to construct its ip frag PerKey: Profiles.EnumProc = { <<[key: ROPE] RETURNS [quit: BOOL _ FALSE]>> ENABLE ColorizeViewPoint.Error => { --Map the error to a warning and proceed SIGNAL ColorizeViewPoint.Warning[class: class, explanation: explanation]; GOTO AbandonKey; }; Action: SeqAction ~ { seqAction[key: key, makeSampledBlack: makeSampledBlack, real: real, textured: textured, transparent: transparent] }; IF Rope.Match[pattern: "ForceTo*", object: key, case: FALSE] THEN RETURN; --ignores entries like "ForceTo25%ABD: c1, c15" for color mapping GfxSeqFromKey[ key: key, gfxTexture: gfxTexture, gfxGray: gfxGray, seqAction: Action, transparent: transparent, opaque: opaque ! InvalidGfxKey => GOTO AbandonKey ]; EXITS AbandonKey => NULL; }; Profiles.EnumerateKeys[profile: profile, pattern: "*%*", proc: PerKey]; --patterns have "%" (eg, "0%AE") }; GfxSeqFromKey: PROC [key: ROPE, gfxTexture: GfxTextureProc, gfxGray: GfxGrayProc, seqAction: SeqAction, transparent, opaque: BOOL _ TRUE] ~ { < permit the transparent form of the MAKESAMPLEDBLACK>> < permit the opaque form of the MAKESAMPLEDBLACK>> pattern: Pattern _ ALL[0]; setGrayRope: ROPE _ NIL; f: REAL _ 0; textured: BOOL _ FALSE; --TRUE => a texture has been included text: Rope.Text ~ Rope.NewText[size: 64]; msbFirstPart, msbPixelPattern, msbThirdPart: ROPE; --msb=makesampledblack { --Set up the pattern for msbPixelPattern s: IO.STREAM ~ IO.RIS[rope: key]; char: CHAR; DO IncludePattern: PROC [new: Pattern] ~ TRUSTED { FOR k: NAT IN [0..16) DO pattern[k] _ PBasics.BITOR[pattern[k], new[k]]; ENDLOOP; }; KeyBreak: IO.BreakProc = { <<[char: CHAR] RETURNS [IO.CharClass]>> RETURN [SELECT char FROM IN ['A..'A+GfxTexture.LAST], 'O, 'T => break, IN ['0..'9], '. => other, ENDCASE => sepr --includes '%--]; }; token: ROPE _ IO.GetTokenRope[stream: s, breakProc: KeyBreak ! IO.EndOfStream => EXIT].token; IF token.Size=1 AND (char _ token.Fetch) IN ['A..'Z] THEN { SELECT char FROM IN ['A..'A+GfxTexture.LAST] => { IncludePattern[gfxTexture[char-'A]]; textured _ TRUE; }; 'O => transparent _ FALSE; 'T => opaque _ FALSE; ENDCASE => SIGNAL ColorizeViewPoint.Warning[$MalformedPaletteEntry, IO.PutFR[format: "Character \"%g\" illegal in profile entry", v1: [character[char]]]]; } ELSE { ENABLE Convert.Error => { ERROR ColorizeViewPoint.Error[$MalformedPaletteEntry, IO.PutFR[format: "Illegal key: \"%g\"", v1: [rope[key]]]]; }; f _ (MIN[100.0, MAX[0.0, Convert.RealFromRope[r: token]]])/100.0; --0.0 to 1.0; for tokens betwn 0.0 & 100.0 <> IncludePattern[gfxGray[f]]; }; ENDLOOP; }; { tI: NAT _ 0; --Index into the REF TEXT FOR i: NAT IN [0..16) DO CharPair: TYPE = MACHINE DEPENDENT RECORD [high, low: CHAR]; [high: text[tI], low: text[tI+1]] _ LOOPHOLE[pattern[i], CharPair]; text[tI+2] _ text[tI+3] _ '\000; tI _ tI+4; ENDLOOP; }; msbFirstPart _ "\017\260\017\260\017\241\017\241\017\241\304\004\000\001\000\020\240\244\017F\240\243\240\245\017\240\017\241\240\242\240\245"; -- 16 16 1 1 1 n SCALE -90 ROTATE CONCAT 0 1 TRANSLATE CONCAT msbPixelPattern _ Rope.Concat["\311D\000\001\000\020" --sequencePackedPixelVector, 68 bytes long, 1 bit/sample, 16 samples/scan line--, text]; msbThirdPart _ "\241\302\304\004\360 \000\036\304\004\017\340\000\036\240\246\017\244\222\240\245"; --MAKEPIXELARRAY n n SCALE2 4 IGET CONCAT IF transparent THEN seqAction[key: key, makeSampledBlack: Rope.Cat[msbFirstPart, msbPixelPattern, msbThirdPart, "\017\241\241\252" --1 MAKESAMPLEDBLACK--], real: f, textured: textured, transparent: TRUE]; IF opaque THEN seqAction[key: key, makeSampledBlack: Rope.Cat[msbFirstPart, msbPixelPattern, msbThirdPart, "\017\240\241\252" --0 MAKESAMPLEDBLACK--], real: f, textured: textured, transparent: FALSE]; }; END.