CtBasicImpl.mesa
Copyright Ó 1985, 1992 by Xerox Corporation. All rights reserved.
Plass and Bloomenthal, July 3, 1992 1:23 pm PDT
Andrew Glassner November 14, 1990 3:40 pm PST
CtBasicImpl:
CEDAR
PROGRAM
IMPORTS CtMap, Draw2d, Imager, ImagerBackdoor, ImagerBitmapContext, ImagerDitherContext, ImagerPixel, ImagerSample, Process, Real, RuntimeError, SF, ViewerSpecs, ViewerPrivate
EXPORTS CtBasic
Types
IntegerPair: TYPE ~ CtBasic.IntegerPair;
PixelArray: TYPE ~ CtBasic.PixelArray;
RealPair: TYPE ~ CtBasic.RealPair;
RGB: TYPE ~ CtBasic.RGB;
RGBProc: TYPE ~ CtBasic.RGBProc;
SampleMaps: TYPE ~ CtBasic.SampleMaps;
SampleMapsRep: TYPE ~ CtBasic.SampleMapsRep;
Vec: TYPE ~ CtBasic.Vec;
ValueProc: TYPE ~ CtBasic.ValueProc;
Context: TYPE ~ Imager.Context;
Rectangle: TYPE ~ Imager.Rectangle;
PixelMap: TYPE ~ ImagerPixel.PixelMap;
Box: TYPE ~ ImagerSample.Box;
SampleBuffer: TYPE ~ ImagerSample.SampleBuffer;
Sample: TYPE ~ ImagerSample.Sample;
SampleMap: TYPE ~ ImagerSample.SampleMap;
Sample Maps Operations
SampleMapsFromPixelMap:
PUBLIC
PROC
[pixelMap:
PixelMap]
RETURNS
[sm:
SampleMaps]
~
{
IF pixelMap = NIL OR pixelMap.samplesPerPixel = 0 THEN RETURN;
sm ¬ NEW[SampleMapsRep[pixelMap.samplesPerPixel]];
sm.bpp ¬ 0;
FOR n:
NAT
IN [0..sm.nChannels ¬ pixelMap.samplesPerPixel)
DO
type:
ATOM ¬
SELECT sm.nChannels
FROM
1 => $BW,
3 => SELECT n FROM 0 => $Red, 1 => $Green, ENDCASE => $Blue,
ENDCASE => $Unknown;
sm[n] ¬ [type, ImagerSample.ZeroOrigin[pixelMap[n]]];
sm.bpp ¬ sm.bpp+ImagerSample.GetBitsPerSample[pixelMap[n]];
ENDLOOP;
sm.box ¬ ImagerSample.GetBox[sm[0].map];
sm.size ¬ SF.Size[sm.box];
sm.x ¬ sm.box.min.f;
sm.y ¬ sm.box.min.s;
sm.w ¬ sm.size.f;
sm.h ¬ sm.size.s;
};
SampleMapsFromMaps:
PUBLIC PROC [map1, map2, map3: SampleMap]
RETURNS [SampleMaps]
~ {
RETURN[SampleMapsFromPixelMap[ImagerPixel.MakePixelMap[map1, map2, map3]]];
};
CreateMaps:
PUBLIC PROC [bpp, x, y, w, h:
NAT, allocateMaps:
BOOL ¬
TRUE]
RETURNS [maps: SampleMaps]
~ {
Allocate:
PROC [type:
ATOM]
RETURNS [ch: CtBasic.Channel] ~ {
ch.type ¬ type;
IF allocateMaps THEN ch.map ¬ ImagerSample.ObtainScratchMap[maps.box, 8];
};
nChannels: NAT ¬ IF bpp = 24 THEN 3 ELSE 1;
maps ¬ NEW[SampleMapsRep[nChannels]];
maps.nChannels ¬ nChannels;
maps.bpp ¬ bpp;
maps.box ¬ BoxFromXYWH[maps.x ¬ x, maps.y ¬ y, maps.w ¬ w, maps.h ¬ h];
maps.size ¬ [maps.h, maps.w];
IF bpp = 24
THEN {
maps[0] ¬ Allocate[$Red];
maps[1] ¬ Allocate[$Green];
maps[2] ¬ Allocate[$Blue];
}
ELSE
maps[0] ¬ Allocate[$BW];
};
CopyOfMaps:
PUBLIC
PROC
[maps:
SampleMaps,
x,
y,
w,
h:
NAT]
RETURNS
[s:
SampleMaps]
~
{
box: Box ¬ SF.Intersect[BoxFromXYWH[x, y, w, h], maps.box];
s ¬ CreateMaps[maps.bpp, box.min.f, box.min.s, box.max.f-box.min.f, box.max.s-box.min.s];
FOR n:
NAT
IN [0..s.nChannels)
DO
ImagerSample.BasicTransfer[s[n].map, maps[n].map, box.min, box.min, SF.Size[box]];
s[n].type ¬ maps[n].type;
ENDLOOP;
};
ClipMaps:
PUBLIC PROC [maps: SampleMaps, x, y, w, h:
NAT] ~ {
ReIndexMaps[maps,, BoxFromXYWH[x, y, w, h]];
box: Box ← BoxFromXYWH[x, y, w, h];
FOR n: NAT IN [0..maps.nChannels) DO
maps[n].map ← ImagerSample.Clip[maps[n].map, box];
maps.box ← ImagerSample.GetBox[maps[n].map];
ENDLOOP;
[maps.x, maps.y, maps.w, maps.h] ← XYWHFromBox[maps.box];
maps.size ← [maps.h, maps.w];
};
MoveMaps:
PUBLIC PROC [maps: SampleMaps, srcMin, dstMin, size: Vec] ~ {
Inner: PROC [map: SampleMap] ~ {ImagerSample.Move[map, dstMin, srcMin, size]};
FOR n: NAT IN [0..maps.nChannels) DO Inner[maps[n].map]; ENDLOOP;
};
ShiftMaps:
PUBLIC
PROC [maps: SampleMaps, delta: Vec]
RETURNS [SampleMaps] ~ {
maps.box ¬ SF.Displace[maps.box, delta];
FOR n:
NAT
IN [0..maps.nChannels)
DO
maps[n].map ¬ ImagerSample.Shift[maps[n].map, delta];
ENDLOOP;
RETURN[maps];
};
FillMaps:
PUBLIC PROC [maps: SampleMaps, bw, r, g, b:
CARDINAL ¬ 0] ~ {
IF maps.bpp = 24
THEN FillRGBMap[maps, [r, g, b]]
ELSE FillBWMap[maps[0].map, bw];
};
CopyMaps:
PUBLIC PROC [src, dst: SampleMaps] ~ {
dst.bpp ¬ src.bpp;
dst.nChannels ¬ src.nChannels;
FOR n:
NAT
IN [0..dst.nChannels)
DO
ImagerSample.Transfer[dst[n].map, src[n].map];
dst[n].type ¬ src[n].type;
ENDLOOP;
};
CopyClippedMaps:
PUBLIC
PROC [src, dst: SampleMaps, srcBox, dstBox: Box] ~ {
Inner:
PROC [src, dst: SampleMap] ~ {
SameMaps:
PROC [map1, map2: SampleMap]
RETURNS [same:
BOOL ¬
FALSE] ~ {
WITH map1
SELECT
FROM
r1: ImagerSample.RasterSampleMap =>
WITH map2
SELECT
FROM
r2: ImagerSample.RasterSampleMap =>
same ¬ ImagerSample.GetBase[r1] = ImagerSample.GetBase[r2];
ENDCASE;
ENDCASE;
};
s: Vec ¬ [MIN[SF.SizeS[srcBox], SF.SizeS[dstBox]], MIN[SF.SizeF[srcBox], SF.SizeF[dstBox]]];
IF SameMaps[src, dst]
THEN ImagerSample.Move[dst, dstBox.min, srcBox.min, s]
ELSE ImagerSample.BasicTransfer[dst, src, dstBox.min, srcBox.min, s];
};
srcBox ¬ SF.Intersect[srcBox, src.box];
dstBox ¬ SF.Intersect[dstBox, dst.box];
FOR n: NAT IN [0..src.nChannels) DO Inner[src[n].map, dst[n].map]; ENDLOOP;
};
ReIndexMaps:
PUBLIC
PROC [maps: SampleMaps, delta: Vec ¬ [0, 0], box: Box ¬
SF.maxBox] ~ {
IF maps = NIL THEN RETURN;
FOR n:
NAT
IN [0..maps.nChannels)
DO
maps[n].map ¬ ImagerSample.ReIndex[maps[n].map, delta, box];
maps.box ¬ ImagerSample.GetBox[maps[0].map];
ENDLOOP;
[maps.x, maps.y, maps.w, maps.h] ¬ XYWHFromBox[maps.box];
maps.size ¬ [maps.h, maps.w];
};
ReleaseDescriptors:
PUBLIC
PROC [maps: SampleMaps] ~ {
IF maps #
NIL
THEN
FOR n:
NAT
IN [0..maps.nChannels)
DO
ImagerSample.ReleaseScratchMap[maps[n].map];
ENDLOOP;
};
8 Bit Operations
FillBWMap:
PUBLIC
PROC
[map:
SampleMap,
color:
CARDINAL]
~
{
ImagerSample.Fill[map,, color];
};
PutBWPixel:
PUBLIC PROC [map: SampleMap, x, y:
INTEGER, value:
CARDINAL] ~ {
ImagerSample.Put[map, [y, x], value ! RuntimeError.BoundsFault => CONTINUE];
};
GetBWPixel:
PUBLIC PROC [map: SampleMap, x, y:
INTEGER]
RETURNS [value:
CARDINAL] ~ {
value ¬ ImagerSample.Get[map, [y, x] ! RuntimeError.BoundsFault => CONTINUE];
};
PutBWBox:
PUBLIC PROC [map: SampleMap, x0, y0, x1, y1:
INTEGER, value:
CARDINAL] ~ {
[x0, y0, x1, y1] ¬ OrderBox[x0, y0, x1, y1];
ImagerSample.Fill[map, [[y0, x0], [y1, x1]], value];
};
PutBWLine:
PUBLIC PROC [map: SampleMap, x0, y0, x1, y1:
INTEGER, value:
CARDINAL] ~ {
Proc: Draw2d.PixelProc ~ {
ImagerSample.Put[map, [y, x], value ! RuntimeError.BoundsFault => CONTINUE];
};
Draw2d.DoWithLine[[x0, y0], [x1, y1], Proc];
};
PutBWScanLine:
PUBLIC
PROC [
map: SampleMap, y: INTEGER, proc: ValueProc, clientData: REF ¬ NIL]
~ {
w: NAT ¬ ImagerSample.GetSize[map].f;
line: SampleBuffer ~ ImagerSample.ObtainScratchSamples[w];
FOR x:
NAT
IN [0..w)
DO
line.samples[x] ¬ proc[x, y, clientData];
ENDLOOP;
ImagerSample.PutSamples[map, [y, 0],, line, 0, w];
ImagerSample.ReleaseScratchSamples[line];
};
PutBWFrame:
PUBLIC
PROC [map: SampleMap, proc: ValueProc, clientData:
REF ¬
NIL] ~ {
box: Box ¬ ImagerSample.GetBox[map];
w: NAT ¬ ImagerSample.GetSize[map].f;
line: SampleBuffer ~ ImagerSample.ObtainScratchSamples[box.max.f];
FOR y:
NAT
IN [box.min.s..box.max.s)
DO
Process.CheckForAbort[];
FOR x:
NAT
IN [box.min.f..box.max.f)
DO
line.samples[x] ¬ proc[x, y, clientData];
ENDLOOP;
ImagerSample.PutSamples[map, [y, box.min.f],, line, 0, w];
ENDLOOP;
ImagerSample.ReleaseScratchSamples[line];
};
24 Bit Operations
FillRGBMap:
PUBLIC
PROC [maps: SampleMaps, rgb:
RGB] ~ {
IF maps.bpp # 24 THEN RETURN;
FillBWMap[maps[0].map, rgb.r];
FillBWMap[maps[1].map, rgb.g];
FillBWMap[maps[2].map, rgb.b];
};
PutRGBPixel:
PUBLIC
PROC [maps: SampleMaps, x, y:
INTEGER, rgb:
RGB] ~ {
ENABLE RuntimeError.BoundsFault => GOTO Bad;
IF maps.bpp # 24 THEN RETURN;
ImagerSample.Put[maps[0].map, [y, x], rgb.r];
ImagerSample.Put[maps[1].map, [y, x], rgb.g];
ImagerSample.Put[maps[2].map, [y, x], rgb.b];
EXITS Bad => NULL;
};
GetRGBPixel:
PUBLIC
PROC [maps: SampleMaps, x, y:
INTEGER]
RETURNS [rgb:
RGB] ~ {
ENABLE RuntimeError.BoundsFault => GOTO Bad;
IF maps.bpp = 24
THEN rgb ¬ [
ImagerSample.Get[maps[0].map, [y, x]],
ImagerSample.Get[maps[1].map, [y, x]],
ImagerSample.Get[maps[2].map, [y, x]]];
EXITS Bad => NULL;
};
PutRGBBox:
PUBLIC PROC [maps: SampleMaps, x0, y0, x1, y1:
INTEGER, rgb:
RGB] ~ {
IF maps.bpp # 24 THEN RETURN;
[x0, y0, x1, y1] ¬ OrderBox[x0, y0, x1, y1];
ImagerSample.Fill[maps[0].map, [[y0, x0], [y1, x1]], rgb.r];
ImagerSample.Fill[maps[1].map, [[y0, x0], [y1, x1]], rgb.g];
ImagerSample.Fill[maps[2].map, [[y0, x0], [y1, x1]], rgb.b];
PutRGBLine:
PUBLIC PROC [maps: SampleMaps, x0, y0, x1, y1:
INTEGER, rgb:
RGB] ~ {
ENABLE RuntimeError.BoundsFault => GOTO Bad;
Inner: Draw2d.PixelProc ~ {
ImagerSample.Put[r, [y, x], rgb.r];
ImagerSample.Put[g, [y, x], rgb.g];
ImagerSample.Put[b, [y, x], rgb.b];
};
r: SampleMap ¬ maps[0].map;
g: SampleMap ¬ maps[1].map;
b: SampleMap ¬ maps[2].map;
IF maps.bpp = 24 THEN Draw2d.DoWithLine[[x0, y0], [x1, y1], Inner];
EXITS Bad => NULL;
PutRGBScanLine:
PUBLIC
PROC [
maps: SampleMaps,
y: INTEGER,
proc: RGBProc,
clientData: REF ¬ NIL]
~ {
IF maps.bpp = 24
THEN {
rLine: SampleBuffer ~ ImagerSample.ObtainScratchSamples[maps.w];
gLine: SampleBuffer ~ ImagerSample.ObtainScratchSamples[maps.w];
bLine: SampleBuffer ~ ImagerSample.ObtainScratchSamples[maps.w];
FOR x:
NAT
IN [0..maps.w)
DO
rgb: RGB ¬ proc[x, y, clientData];
rLine.samples[x] ¬ rgb.r;
gLine.samples[x] ¬ rgb.g;
bLine.samples[x] ¬ rgb.b;
ENDLOOP;
ImagerSample.PutSamples[maps[0].map, [y, 0],, rLine, 0, maps.w];
ImagerSample.PutSamples[maps[1].map, [y, 0],, gLine, 0, maps.w];
ImagerSample.PutSamples[maps[2].map, [y, 0],, bLine, 0, maps.w];
ImagerSample.ReleaseScratchSamples[rLine];
ImagerSample.ReleaseScratchSamples[gLine];
ImagerSample.ReleaseScratchSamples[bLine];
};
};
PutRGBFrame:
PUBLIC
PROC [maps: SampleMaps, proc: RGBProc, clientData:
REF ¬
NIL] ~ {
IF maps.bpp = 24
THEN {
box: Box ¬ maps.box;
rLine: SampleBuffer ~ ImagerSample.ObtainScratchSamples[box.max.f];
gLine: SampleBuffer ~ ImagerSample.ObtainScratchSamples[box.max.f];
bLine: SampleBuffer ~ ImagerSample.ObtainScratchSamples[box.max.f];
FOR y:
NAT
IN [box.min.s..box.max.s)
DO
Process.CheckForAbort[];
FOR x:
NAT
IN [box.min.f..box.max.f)
DO
rgb: RGB ¬ proc[x, y, clientData];
bLine.samples[x] ¬ rgb.r;
bLine.samples[x] ¬ rgb.g;
bLine.samples[x] ¬ rgb.b;
ENDLOOP;
ImagerSample.PutSamples[maps[0].map, [y, box.min.f],, rLine, box.min.f, maps.w];
ImagerSample.PutSamples[maps[1].map, [y, box.min.f],, gLine, box.min.f, maps.w];
ImagerSample.PutSamples[maps[2].map, [y, box.min.f],, bLine, box.min.f, maps.w];
ENDLOOP;
ImagerSample.ReleaseScratchSamples[rLine];
ImagerSample.ReleaseScratchSamples[gLine];
ImagerSample.ReleaseScratchSamples[bLine];
};
};
Pixel Array Operations
InitializePixelArray:
PUBLIC
PROC [box: Box, bpp:
NAT ¬ 8]
RETURNS [pa: PixelArray] ~ {
pa ¬ NEW[CtBasic.PixelArrayRep[box.max.s]];
pa.bpp ¬ bpp;
SetPixelArrayRange[pa, box];
};
AllocatePixelArray:
PUBLIC
PROC [box: Box, bpp:
NAT ¬ 8]
RETURNS [PixelArray] ~ {
pa: PixelArray ¬ InitializePixelArray[box, bpp];
xMax: NAT ¬ pa.x+pa.w;
FOR y:
INT
IN [pa.y..pa.y+pa.h)
DO
pa[y] ¬ ImagerSample.NewSamples[xMax];
ENDLOOP;
RETURN[pa];
};
PixelArrayFromSampleMap:
PUBLIC
PROC [map: SampleMap]
RETURNS [pa: PixelArray] ~ {
pa ¬ AllocatePixelArray[ImagerSample.GetBox[map], ImagerSample.GetBitsPerSample[map]];
FOR y:
INT
IN [pa.y..pa.y+pa.h)
DO
ImagerSample.GetSamples[map, [y, pa.x],, pa[y], pa.x, pa.w];
ENDLOOP;
};
SampleMapFromPixelArray:
PUBLIC
PROC [pa: PixelArray]
RETURNS [map: SampleMap] ~ {
IF pa = NIL THEN RETURN;
map ¬ ImagerSample.NewSampleMap[[[pa.y, pa.x], [pa.y+pa.h, pa.x+pa.w]], pa.bpp];
TransferPixelArrayToMap[pa, map];
};
TransferPixelArrayToMap:
PUBLIC PROC [pa: PixelArray, map: SampleMap] ~ {
FOR y:
NAT
IN [pa.y..pa.y+pa.h)
DO
ImagerSample.PutSamples[map, [y, pa.x],, pa[y], pa.x, pa.w];
ENDLOOP;
};
PixelArrayBoxToMap:
PUBLIC PROC [
pa: PixelArray,
map: SampleMap,
x1, y1, x2, y2: INTEGER]
~ {
w: NAT ¬ ABS[x2-x1];
IF x1 < pa.x THEN x1 ¬ pa.x;
IF x2 > INTEGER[pa.x+pa.w] THEN x2 ¬ pa.x+pa.w;
IF y1 < pa.y THEN y1 ¬ pa.y;
IF y2 > INTEGER[pa.y+pa.h] THEN y2 ¬ pa.y+pa.h;
IF x1 < x2
AND y1 < y2
THEN
FOR y:
NAT
IN [y1..y2)
DO
ImagerSample.PutSamples[map, [y, x1],, pa[y], x1, w];
ENDLOOP;
};
BoxFromPixelArray:
PUBLIC PROC [pa: PixelArray]
RETURNS [box: Box] ~ {
box ¬ [[pa.y, pa.x], [pa.y+pa.h, pa.x+pa.w]];
};
DoToPixelArray:
PUBLIC
PROC [
pa: PixelArray, proc: ValueProc, map: SampleMap ¬ NIL, clientData: REF ¬ NIL]
~ {
box: Box ¬ [[pa.y, pa.x], [pa.y+pa.h, pa.x+pa.w]];
IF map # NIL THEN box ¬ SF.Intersect[box, ImagerSample.GetBox[map]];
FOR y:
NAT
IN [box.min.s..box.max.s)
DO
Process.CheckForAbort[];
FOR x:
NAT
IN [box.min.f..box.max.f)
DO
pa[y][x] ¬ proc[x, y, clientData];
ENDLOOP;
IF map # NIL THEN ImagerSample.PutSamples[map, [y, pa.x],, pa[y], pa.x, pa.w];
ENDLOOP;
};
IntersectionOfPixelArrays:
PUBLIC PROC [pa1, pa2, pa3, pa4: PixelArray ¬
NIL]
RETURNS [Box]
~ {
box: Box ¬ [[0, 0], [INTEGER.LAST, INTEGER.LAST]];
IF pa1 # NIL THEN box ¬ SF.Intersect[box, BoxFromPixelArray[pa1]];
IF pa2 # NIL THEN box ¬ SF.Intersect[box, BoxFromPixelArray[pa2]];
IF pa3 # NIL THEN box ¬ SF.Intersect[box, BoxFromPixelArray[pa3]];
IF pa4 # NIL THEN box ¬ SF.Intersect[box, BoxFromPixelArray[pa4]];
RETURN[box];
};
SetPixelArrayRange:
PUBLIC PROC [pa: PixelArray, box: Box] ~ {
pa.box ¬ box;
pa.size ¬ SF.Size[box];
pa.x ¬ box.min.f;
pa.y ¬ box.min.s;
pa.w ¬ box.max.f-box.min.f;
pa.h ¬ box.max.s-box.min.s;
};
CopyPixelArray:
PUBLIC
PROC [in: PixelArray]
RETURNS [copy: PixelArray] ~ {
copy ¬ AllocatePixelArray[in.box, in.bpp];
FOR y:
INT
IN [in.y..in.y+in.h)
DO
inbuf: SampleBuffer ¬ in[y];
outbuf: SampleBuffer ¬ copy[y];
Should use a bitBLT, or use ImagerSample.BasicTransfer of one-line maps:
FOR x: INT IN [in.x..in.x+in.w) DO copy[x] ¬ in[x]; ENDLOOP;
ENDLOOP;
};
Box/Rectangle Operations
OrderBox:
PROC [x0, y0, x1, y1:
INTEGER]
RETURNS [
INTEGER,
INTEGER,
INTEGER,
INTEGER] ~ {
IF x0 > x1 THEN {t: INTEGER ¬ x0; x0 ¬ x1; x1 ¬ t};
IF y0 > y1 THEN {t: INTEGER ¬ y0; y0 ¬ y1; y1 ¬ t};
RETURN[x0, y0, x1, y1];
};
BoxFromXYWH:
PUBLIC
PROC [x, y, w, h:
INTEGER]
RETURNS [box: Box] ~ {
box ¬ [[y, x], [y+h, x+w]];
};
XYWHFromBox:
PUBLIC
PROC [box: Box]
RETURNS [x, y, w, h:
INTEGER] ~ {
x ¬ box.min.f;
y ¬ box.min.s;
w ¬ box.max.f-x;
h ¬ box.max.s-y;
};
RectangleFromXYs:
PUBLIC PROC [x0, y0, x1, y1:
INTEGER]
RETURNS [r: Rectangle] ~ {
r.x ¬ MIN[x0, x1];
r.y ¬ MIN[y0, y1];
r.w ¬ MAX[x0, x1]-r.x;
r.h ¬ MAX[y0, y1]-r.y;
};
BoxFromRectangle:
PUBLIC
PROC [rectangle: Rectangle]
RETURNS [Box] ~ {
x: INTEGER ¬ Real.Round[rectangle.x];
y: INTEGER ¬ Real.Round[rectangle.y];
w: INTEGER ¬ Real.Round[rectangle.w];
h: INTEGER ¬ Real.Round[rectangle.h];
RETURN[[[y, x], [y+h, x+w]]];
};
Imager Context Operations
DoWithSampleMapsFromContext:
PUBLIC
PROC [
context: Context,
action: PROC [maps: SampleMaps]]
~ {
IF context #
NIL
AND action #
NIL
THEN {
Inner: PROC [pixelMap: PixelMap] ~ {action[SampleMapsFromPixelMap[pixelMap]]};
ImagerBackdoor.AccessBufferRectangle[context, Inner, ImagerBackdoor.GetBounds[context]];
};
};
registry:
LIST
OF ImagerDither.MapEntries ¬
NIL;
-- cached color maps
ContextFromSampleMaps:
PUBLIC
PROC [maps: SampleMaps, ignoreColormap:
BOOL ¬
FALSE]
RETURNS [context: Context]
~ {
SELECT maps.bpp
FROM
0, 1 => {
context ¬ ImagerBitmapContext.Create[maps.size, [down, right], [72.0, 72.0], 1, TRUE];
ImagerBitmapContext.SetBitmap[context, maps[0].map];
};
8, 24 => {
context ¬ ImagerDitherContext.Create[maps.size, [down, right], [72.0, 72.0], TRUE];
ImagerDitherContext.SetSampleMap[context, maps[0].map];
IF
NOT ignoreColormap
THEN {
cmap: CtMap.Cmap ¬ CtMap.Read[];
list: ImagerDither.MapEntries ¬ NIL;
FOR l:
LIST
OF ImagerDither.MapEntries ¬ registry, l.rest
WHILE l #
NIL
DO
FOR m: ImagerDither.MapEntries ¬ l.first, m.rest
WHILE m #
NIL
DO
IF cmap[0][m.first.mapIndex] # m.first.red
OR
cmap[1][m.first.mapIndex] # m.first.green OR
cmap[2][m.first.mapIndex] # m.first.blue THEN EXIT;
REPEAT FINISHED => list ¬ l.first;
ENDLOOP;
IF list # NIL THEN EXIT;
ENDLOOP;
IF list =
NIL
THEN {
FOR i:
NAT
IN [0..256)
DO
list ¬ CONS[[i, cmap[0][i], cmap[1][i], cmap[2][i]], list];
ENDLOOP;
registry ¬ CONS[list, registry];
};
ImagerDitherContext.SetDitherMap[context, list]; -- fast if previously cached
};
};
ENDCASE;
};
TransformContextToMap:
PUBLIC PROC [context: Context, map: SampleMap] ~ {
box: Box ~ ImagerSample.GetBox[map];
colorScreenHeight: NAT ¬ ViewerSpecs.colorScreenHeight;
halfSize: Vec ~ [(box.max.s-box.min.s)/2, (box.max.f-box.min.f)/2];
Imager.TranslateT[context, [box.min.f+halfSize.f, colorScreenHeight-halfSize.s-box.min.s]];
Premultiply: i.e., scale the canonical [±1, ±1] space to the sample map:
Imager.Scale2T[context, [halfSize.f, halfSize.s]];
Font will be scaled by this transform, so unscale a 10 pt font:
Imager.SetFont[context, Imager.FindFontScaled["xerox/xc1-2-2/Modern", 10.0/halfSize.f]];
};
Coordinate System Transformations
PairFromMapCoords:
PUBLIC
PROC [x, y:
INTEGER, map: SampleMap, fit:
BOOL ¬
TRUE]
RETURNS [RealPair]
~ {
box: Box ~ ImagerSample.GetBox[map];
size: Vec ~ ImagerSample.GetSize[map];
pairScale: RealPair;
IF fit
THEN pairScale ¬ [2.0/size.f, 2.0/size.s]
ELSE {
min: REAL ¬ 2.0*MIN[size.f, size.s];
pairScale ¬ [min, min];
};
RETURN[[(x-box.min.f)*pairScale.x-1.0, (size.s+box.min.s-y)*pairScale.y-1.0]];
};
MapCoordsFromPair:
PUBLIC
PROC [pair: RealPair, map: SampleMap, fit:
BOOL ¬
TRUE]
RETURNS [p: IntegerPair]
~ {
box: Box ~ ImagerSample.GetBox[map];
size: Vec ~ ImagerSample.GetSize[map];
mapScale: RealPair;
IF fit
THEN mapScale ¬ [0.5*size.f, 0.5*size.s]
ELSE {
min: REAL ¬ 0.5*MIN[size.f, size.s];
mapScale ¬ [min, min];
};
p.x ¬ Real.Round[(pair.x+1.0)*mapScale.x+box.min.f];
p.y ¬ ViewerSpecs.colorScreenHeight-Real.Round[(size.s+box.min.s-(pair.y+1.0)*mapScale.y)];
};