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
DIRECTORY CtBasic, CtMap, Draw2d, Imager, ImagerBackdoor, ImagerBitmapContext, ImagerDither, ImagerDitherContext, ImagerPixel, ImagerSample, Process, Real, Rope, RuntimeError, SF, ViewerSpecs, ViewerPrivate;
CtBasicImpl: CEDAR PROGRAM
IMPORTS CtMap, Draw2d, Imager, ImagerBackdoor, ImagerBitmapContext, ImagerDitherContext, ImagerPixel, ImagerSample, Process, Real, RuntimeError, SF, ViewerSpecs, ViewerPrivate
EXPORTS CtBasic
~ BEGIN
Errors
Error:       SIGNAL [code: ATOM, reason: Rope.ROPE]; -- able to resume this error
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;
Miscellany
GetBpp: PUBLIC PROC RETURNS [bpp: NAT ¬ 0] ~ {
Inner: PROC [pixelMap: ImagerPixel.PixelMap] ~ {
FOR i: NAT IN [0..pixelMap.samplesPerPixel) DO
bpp ¬ bpp+ImagerSample.GetBitsPerSample[pixelMap[i]];
ENDLOOP;
};
context: Imager.Context ¬ ViewerPrivate.CreateContext[main];
ImagerBackdoor.AccessBufferRectangle[context, Inner, ImagerBackdoor.GetBounds[context]];
};
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)];
};
END.