ColorizeIconsImpl.mesa
Copyright Ó 1991 by Xerox Corporation. All rights reserved.
Michael Plass, October 22, 1991 10:58 am PDT
Willie-s, November 1, 1991 12:35 pm PST
DIRECTORY SF, ViewerOps, Ascii, Commander, CommanderOps, ViewerClasses, Vector2, IO, Basics, Atom, Icons, Imager, Rope, RopeHash, ImagerColor, ImagerSample, RefTab;
ColorizeIconsImpl: CEDAR PROGRAM
IMPORTS IO, ViewerOps, Commander, CommanderOps, Rope, Ascii, Atom, Imager, RopeHash, ImagerColor, ImagerSample, RefTab
~ BEGIN
ROPE: TYPE ~ Rope.ROPE;
RasterSampleMap: TYPE ~ ImagerSample.RasterSampleMap;
SampleBuffer: TYPE ~ ImagerSample.SampleBuffer;
ColorizeIconProc: TYPE = PROC [context: Imager.Context, label: Rope.ROPE, iconInfo: Icons.IconRef, x, y: INTEGER] RETURNS [Icons.IconRef];
HSVColor: PROC [H, S, V: REAL] RETURNS [Imager.Color] ~ {
RETURN [ImagerColor.ColorFromHSV[H, S, V]]
};
bg1: ARRAY [0..8) OF Imager.Color ¬ [
HSVColor[0.09, 0.5, 1],
HSVColor[0.17, 0.4, 1],
HSVColor[0.30, 0.5, 1],
HSVColor[0.50, 0.4, 1],
HSVColor[0.60, 0.4, 1],
HSVColor[0.66, 0.4, 1],
HSVColor[0.80, 0.4, 1],
HSVColor[0.94, 0.4, 1]
];
bg2: ARRAY [0..6) OF Imager.Color ¬ [
HSVColor[0/6.0, 0.4, 1],
HSVColor[1/6.0, 0.4, 1],
HSVColor[2/6.0, 0.4, 1],
HSVColor[3/6.0, 0.4, 1],
HSVColor[4/6.0, 0.4, 1],
HSVColor[5/6.0, 0.4, 1]
];
debugStream: IO.STREAM ¬ NIL;
LabelHash: PROC [label: ROPE] RETURNS [CARD] ~ {
start: INT ¬ MAX[Rope.FindBackward[s1: label, s2: "/"], 0];
end: INT ¬ Rope.SkipTo[s: label, pos: start, skip: " .!:"];
IF end-start < 3 THEN { start ¬ 0; end ¬ INT.LAST };
WITH debugStream SELECT FROM
stream: IO.STREAM => { IO.PutRope[stream, label, start, end-start]; IO.PutChar[stream, '\n] };
ENDCASE;
RETURN [RopeHash.FromRope[rope: label, case: FALSE, start: start, len: end-start]]
};
ColorizeIcon: ColorizeIconProc ~ {
BEGIN ENABLE UNCAUGHT => CONTINUE;
sep: Separations ~ GetSeparations[iconInfo];
IF sep # NIL THEN {
IF use1 THEN
Imager.SetColor[context, bg1[LabelHash[label] MOD LENGTH[bg1]]]
ELSE
Imager.SetColor[context, bg2[LabelHash[label] MOD LENGTH[bg2]]];
Imager.MaskRectangleI[context, x+iconInfo.lx, y+iconInfo.ly, iconInfo.lw, iconInfo.lh];
Imager.MaskBitmap[context, sep.background, [Icons.iconH,0], Imager.defaultScanMode, [x,y]];
Imager.SetColor[context, ImagerColor.ColorFromRGB[[0,0,.5]]];
};
END;
RETURN [iconInfo]
};
cache: RefTab.Ref ¬ RefTab.Create[];
GetSeparations: PROC [iconInfo: Icons.IconRef] RETURNS [sep: Separations ¬ NIL] ~ {
Updater: RefTab.UpdateAction ~ {
IF found
THEN sep ¬ NARROW[val]
ELSE {
sep ¬ ComputeSeparations[iconInfo];
RETURN [op: store, new: sep]
};
};
RefTab.Update[cache, iconInfo, Updater];
};
Separations: TYPE ~ REF SeparationsRep;
SeparationsRep: TYPE ~ RECORD [
background: RasterSampleMap
];
ComputeSeparations: PROC [iconInfo: Icons.IconRef] RETURNS [Separations] ~ {
Link: TYPE = [0..Icons.iconH*Icons.iconW];
LinkArray: TYPE = PACKED ARRAY [0..Icons.iconH*Icons.iconW] OF Link;
null: Link ~ Icons.iconH*Icons.iconW;
link: REF LinkArray = NEW[LinkArray ¬ ALL[null]];
ndx: PROC [i: [0..Icons.iconH), j: [0..Icons.iconW)] RETURNS [Link] ~ INLINE {
RETURN [i*Icons.iconW+j]
};
Rep: PROC [a: Link] RETURNS [Link] ~ {
r: Link ¬ a;
UNTIL link[r] = null DO r ¬ link[r] ENDLOOP;
UNTIL a = r DO
next: Link ¬ r;
link[a] ¬ r;
a ¬ next;
ENDLOOP;
RETURN [r]
};
MakeEquiv: PROC [a, b: Link] ~ {
aRep: Link ¬ Rep[a];
bRep: Link ¬ Rep[b];
IF aRep # bRep THEN link[aRep] ¬ bRep;
};
ScanRegion: PROC [a: Link] RETURNS [ImagerSample.RasterSampleMap] ~ {
r: Link ~ Rep[a];
map: ImagerSample.RasterSampleMap ¬ ImagerSample.NewSampleMap[[max:[Icons.iconH,Icons.iconW]]];
ImagerSample.Clear[map];
FOR i: [0..Icons.iconH) IN [0..Icons.iconH) DO
FOR j: [0..Icons.iconW) IN [0..Icons.iconW) DO
IF Rep[ndx[i,j]] = r THEN {
ImagerSample.Put[map, [i,j], 1];
};
ENDLOOP;
ENDLOOP;
RETURN [map]
};
bits: PACKED ARRAY [0..Icons.iconH*Icons.iconW) OF [0..1] ~ LOOPHOLE[iconInfo.bits];
FOR i: [0..Icons.iconH) IN [0..Icons.iconH) DO
FOR j: [0..Icons.iconW) IN [0..Icons.iconW) DO
IF bits[ndx[i,j]] = 0 THEN {
IF i # 0 AND bits[ndx[i-1,j]] = 0 THEN MakeEquiv[ndx[i-1,j],ndx[i,j]];
IF j # 0 AND bits[ndx[i,j-1]] = 0 THEN MakeEquiv[ndx[i,j],ndx[i,j-1]];
};
ENDLOOP;
ENDLOOP;
RETURN [NEW[SeparationsRep ¬ [background: ScanRegion[ndx[Icons.iconH-1-(iconInfo.ly+iconInfo.lh/2), iconInfo.lx+iconInfo.lw/2]]]]];
};
FindRegion: PROC [bitmap: ImagerSample.SampleMap, s, f: INTEGER] RETURNS [result: RasterSampleMap] ~ {
box: SF.Box ~ bitmap.GetBox;
fSize: NAT ~ box.max.f-box.min.f;
link: RasterSampleMap ~ ImagerSample.ObtainScratchMap[box, 32];
Link: TYPE ~ MACHINE DEPENDENT RECORD [s, f: INT16];
null: Link ~ [INT16.FIRST, 0];
p: SampleBuffer ¬ ImagerSample.ObtainScratchSamples[fSize];
q: SampleBuffer ¬ ImagerSample.ObtainScratchSamples[fSize];
GetLink: PROC [a: Link] RETURNS [Link] ~ {
RETURN [LOOPHOLE[ImagerSample.Get[link, [a.s, a.f]]]]
};
PutLink: PROC [a, r: Link] ~ {
ImagerSample.Put[link, [a.s, a.f], LOOPHOLE[r]];
};
Rep: PROC [a: Link] RETURNS [Link] ~ {
Finds the representative for the link (union-find with path compression)
r: Link ¬ a;
next: Link;
UNTIL (next ¬ GetLink[r]) = null DO r ¬ next ENDLOOP;
UNTIL a = r DO
next ¬ r;
PutLink[a, r];
a ¬ next;
ENDLOOP;
RETURN [r]
};
MakeEquiv: PROC [a, b: Link] ~ {
aRep: Link ¬ Rep[a];
bRep: Link ¬ Rep[b];
IF aRep # bRep THEN PutLink[aRep, bRep];
};
ScanRegion: PROC [a: Link] RETURNS [ImagerSample.RasterSampleMap] ~ {
r: Link ~ Rep[a];
map: ImagerSample.RasterSampleMap ¬ ImagerSample.NewSampleMap[box];
ImagerSample.Clear[map];
FOR s: INT IN [box.min.s..box.max.s) DO
FOR f: INT IN [box.min.f..box.max.f) DO
IF Rep[[s,f]] = r THEN ImagerSample.Put[map, [s, f], 1];
ENDLOOP;
ENDLOOP;
RETURN [map]
};
ImagerSample.Fill[map: link, value: LOOPHOLE[null]];
FOR s: INT IN [box.min.s..box.max.s) DO
ImagerSample.GetSamples[map: bitmap, initIndex: [s, box.min.f], buffer: q];
FOR j: INT IN [0..fSize) DO
f: INT16 ~ box.min.f+j;
IF s#box.min.s AND q[j]#p[j] THEN MakeEquiv[[s-1,f],[s,f]];
IF j#0 AND q[j]#q[j-1] THEN MakeEquiv[[s,f],[s,f-1]];
ENDLOOP;
{t: SampleBuffer ¬ p; p ¬ q; q ¬ t}
ENDLOOP;
result ¬ ScanRegion[[s,f]];
ImagerSample.ReleaseScratchMap[link];
ImagerSample.ReleaseScratchSamples[p];
ImagerSample.ReleaseScratchSamples[q];
};
PaintIfIconic: PROC [v: ViewerClasses.Viewer] RETURNS [BOOL ¬ TRUE] ~ {
IF v.iconic THEN ViewerOps.PaintViewer[v, all];
};
Register: PROC [ref: REF ColorizeIconProc] ~ {
Atom.PutProp[$Icons, $ColorizeIcon, ref];
};
use1: BOOL ¬ TRUE;
iconColorOn: BOOL ¬ FALSE;
docIconColor: Rope.ROPE ~ "Control icon colorization. Args: on | off";
Lower: Rope.TranslatorType ~ {RETURN [Ascii.Lower[old]]};
IconColorCommand: Commander.CommandProc ~ {
arg: ROPE ~ CommanderOps.NextArgument[cmd];
atom: ATOM ~ IF arg = NIL THEN NIL ELSE Atom.MakeAtom[arg.Translate[translator: Lower]];
SELECT atom FROM
$on, $one => { Register[NEW[ColorizeIconProc ¬ ColorizeIcon]]; use1 ¬ TRUE; };
$two => { Register[NEW[ColorizeIconProc ¬ ColorizeIcon]]; use1 ¬ FALSE; };
$off => { Register[NIL]; RefTab.Erase[cache] };
ENDCASE => ERROR CommanderOps.Failed[cmd.procData.doc];
ViewerOps.EnumerateViewers[PaintIfIconic];
};
Commander.Register["IconColor", IconColorCommand, docIconColor];
END.
----------------------------------------------------------------------------------------
Test: PROC [n: INT] ~ {
IconFileFormat: TYPE = Icons.IconFileFormat;
format: REF IconFileFormat ~ NEW[IconFileFormat]; -- 1024 bytes!
bytesPerIcon: INT ~ BYTES[IconFileFormat];
iconInfo: Icons.IconRef;
stream: IO.STREAM ¬ ImagerSys.OpenInputFile["/r/Standard.icons"];
IO.SetIndex[stream, bytesPerIcon*n];
TRUSTED {
base: LONG POINTER TO Basics.RawBytes ~ LOOPHOLE[format];
bytesRead: INT ~ IO.UnsafeGetBlock[stream, [base: base, count: bytesPerIcon]];
};
iconInfo ¬ NEW[Icons.IconRep ¬ [bits: format.bits,
label: format.label, invertLabel: format.invertLabel,
lx: format.lx, ly: format.ly, lw: format.lw, lh: format.lh]];
IO.Close[stream];
BitmapViewer.SetBitmap[BitmapViewer.Create[], ComputeSeparations[iconInfo].background];
};
TestC: Commander.CommandProc ~ {FOR i: INT IN [0..10) DO Test[i] ENDLOOP};
Commander.Register["Test",TestC];