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 Error: SIGNAL [code: ATOM, reason: Rope.ROPE]; -- able to resume this error 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; 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]]; }; 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]]; }; 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; }; 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]; }; 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]; }; }; 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]; FOR x: INT IN [in.x..in.x+in.w) DO copy[x] ฌ in[x]; ENDLOOP; ENDLOOP; }; 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]]]; }; 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]]; Imager.Scale2T[context, [halfSize.f, halfSize.s]]; Imager.SetFont[context, Imager.FindFontScaled["xerox/xc1-2-2/Modern", 10.0/halfSize.f]]; }; 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. \ 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 Errors Types Miscellany Sample Maps Operations 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]; 8 Bit Operations 24 Bit Operations Pixel Array Operations Should use a bitBLT, or use ImagerSample.BasicTransfer of one-line maps: Box/Rectangle Operations Imager Context Operations Premultiply: i.e., scale the canonical [+1, +1] space to the sample map: Font will be scaled by this transform, so unscale a 10 pt font: Coordinate System Transformations ส„–"cedarcode" style•NewlineDelimiter ™™Jšœ ฯeœ6™BJ™/J™-J˜—Jšฯk œฦ˜ฯJ˜šะbl œžœž˜Jšžœจ˜ฏJšžœ˜—J˜Jšœž˜headšฯl™Jš ฯnœžœžœžœฯc˜Q—š ™Jšœžœ˜+Jšœžœ˜)Jšœžœ˜&Jšžœžœ žœ˜Jšœ žœ˜$Jšœžœ˜)Jšœžœ˜.Jšœ žœ˜Jšœ žœ˜'Jšœ žœ˜#Jšœ žœ˜&Jšœ ž œ˜*Jšœž œ˜"Jšœžœ˜1Jšœž œ˜'Jšœ žœ˜,—š  ™ šกœž œžœžœ ˜.šกœžœ%˜0šžœžœžœž˜.J˜5Jšžœ˜—Jšœ˜—J˜Jšœžœ*˜2J˜ šžœžœžœ.ž˜=šœžœžœž˜%J˜ Jšœžœžœžœ ˜J˜ Jšœ žœ ˜J˜J˜J˜J˜J˜J˜—šกœžœžœžœ˜KJ˜*šžœžœžœž˜"J˜J˜J™HJš žœžœžœžœžœ˜