<> <> <> <> DIRECTORY AIS, ConvertUnsafe, Directory, Graphics, GraphicsColor, GraphicsOps, MessageWindow, ReadAIS, Real, Rope, SV2d, SVBoundBox, SVFiles, SVImage, SVVector2d; SVImageImpl: PROGRAM IMPORTS AIS, ConvertUnsafe, Directory, Graphics, GraphicsColor, GraphicsOps, MessageWindow, ReadAIS, Real, Rope, SVFiles, SVVector2d EXPORTS SVImage = BEGIN Image: TYPE = REF ImageObj; ImageObj: TYPE = SVImage.ImageObj; BoundBox: TYPE = REF BoundBoxObj; BoundBoxObj: TYPE = SVBoundBox.BoundBoxObj; Color: TYPE = GraphicsColor.Color; ImageRef: TYPE = GraphicsOps.ImageRef; Mark: TYPE = Graphics.Mark; Point2d: TYPE = SV2d.Point2d; WRef: TYPE = AIS.WRef; FRef: TYPE = AIS.FRef; IsEven: PRIVATE PROC [n: NAT] RETURNS [BOOL] = { RETURN [(n/2)*2 = n]; }; RoundDown: PRIVATE PROC [r: REAL] RETURNS [rDown: INTEGER] = { <> IF r = 0 THEN RETURN[0]; IF r > 0 THEN { rDown _ Real.FixI[r]; RETURN} ELSE { r _ -r;-- make it positive rDown _ Real.FixI[r]; rDown _ rDown + 1; rDown _ - rDown; }; }; RoundUp: PRIVATE PROC [r: REAL] RETURNS [rUp: INTEGER] = { <> IF r = 0 THEN RETURN[0]; IF r > 0 THEN { rUp _ Real.FixI[r]; rUp _ rUp + 1; RETURN} ELSE { r _ -r;-- make it positive rUp _ Real.FixI[r]; rUp _ - rUp; }; }; CountSamples: PRIVATE PROC [realMinX, realMinY, realMaxX, realMaxY, resolution: REAL] RETURNS [numberOfSamplesX, numberOfSamplesY: NAT] = { << We are given a minimum bounding box to be filled. Calculate the number of samples in the x direction as follows: Find the number of samples which will just fit in the alloted x extent. Now add one (Since + 1 = number of samples, we actually add two). If the resulting number is odd, add 1 again. Do the same for the y direction. (Because of unimplemented features in some of the printing software, it is useful to round all ais file sizes to even numbers of pixels.) xExtent/72 = x extent in inches. (xExtent/72)*resolution = samples which will fit. Round this down to the nearest integer. >> xExtent, yExtent, realSamplesX, realSamplesY: REAL; xExtent _ realMaxX - realMinX; -- x extent in screen dots yExtent _ realMaxY - realMinY; -- y extent in screen dots realSamplesX _ (xExtent*resolution)/72.0; realSamplesY _ (yExtent*resolution)/72.0; numberOfSamplesX _ Real.FixI[realSamplesX] + 2; numberOfSamplesY _ Real.FixI[realSamplesY] + 2; IF NOT IsEven[numberOfSamplesX] THEN numberOfSamplesX _ numberOfSamplesX + 1; IF NOT IsEven[numberOfSamplesY] THEN numberOfSamplesY _ numberOfSamplesY + 1; }; -- end of CountSamples OpenImage: PUBLIC PROC [aisRope: Rope.ROPE, bAndWOnly: BOOL, realMinX, realMinY, realMaxX, realMaxY, resolution: REAL, raster: AIS.Raster, commentString: LONG STRING] RETURNS [I: Image, numberOfSamplesX, numberOfSamplesY: NAT] = { << Bound box is in camera coordinates>> f: AIS.FRef; I _ NEW[ImageObj]; [numberOfSamplesX, numberOfSamplesY] _ CountSamples[realMinX, realMinY, realMaxX, realMaxY, resolution]; raster^ _ [numberOfSamplesY, numberOfSamplesX, rd, 8, -1, 65535]; IF bAndWOnly THEN { bwString: LONG STRING _ [30]; I.bAndWOnly _ TRUE; ConvertUnsafe.AppendRope[bwString, aisRope]; f _ ReadAIS.CreateFile[bwString, raster, commentString, TRUE, 0, resolution]; I.bwWindow _ AIS.OpenWindow[f]; } ELSE { redRope: Rope.ROPE _ Rope.Concat[SVFiles.FilenameMinusExtension[aisRope], "-red.ais"]; greenRope: Rope.ROPE _ Rope.Concat[SVFiles.FilenameMinusExtension[aisRope], "-green.ais"]; blueRope: Rope.ROPE _ Rope.Concat[SVFiles.FilenameMinusExtension[aisRope], "-blue.ais"]; bwRope: Rope.ROPE _ aisRope; redString: LONG STRING _ [30]; greenString: LONG STRING _ [30]; blueString: LONG STRING _ [30]; bwString: LONG STRING _ [30]; I.bAndWOnly _ FALSE; ConvertUnsafe.AppendRope[bwString, bwRope]; ConvertUnsafe.AppendRope[redString, redRope]; ConvertUnsafe.AppendRope[greenString, greenRope]; ConvertUnsafe.AppendRope[blueString, blueRope]; f _ ReadAIS.CreateFile[redString, raster, commentString, TRUE, 0, resolution]; I.redWindow _ AIS.OpenWindow[f]; f _ ReadAIS.CreateFile[greenString, raster, commentString, TRUE, 0, resolution]; I.greenWindow _ AIS.OpenWindow[f]; f _ ReadAIS.CreateFile[blueString, raster, commentString, TRUE, 0, resolution]; I.blueWindow _ AIS.OpenWindow[f]; f _ ReadAIS.CreateFile[bwString, raster, commentString, TRUE, 0, resolution]; I.bwWindow _ AIS.OpenWindow[f]; }; MessageWindow.Append[" New "]; MessageWindow.Append[aisRope]; MessageWindow.Append["'s created."]; };-- end of OpenImage DeleteFile: PRIVATE PROC [name: Rope.ROPE] = { success: BOOL; nameString: LONG STRING _ [20]; ConvertUnsafe.AppendRope[nameString, name]; success _ AIS.DeleteFile[nameString]; IF NOT success THEN {MessageWindow.Append["No "]; MessageWindow.Append[name]; MessageWindow.Append[". "];} ELSE { MessageWindow.Append[name]; MessageWindow.Append["... "]; }; };-- end of DeleteFile Truncate: PROC [value: REAL] RETURNS [m: CARDINAL] = { <> SELECT value FROM <0 => ERROR; >255.0 => m _ 255; ENDCASE => m _ Real.FixC[value]; }; PutImage2: PROC [I: Image, i, j: INTEGER, color: Color, minX, maxX, minY, maxY: INTEGER] = { <> <> intRed, intGreen, intBlue, intIntensity: CARDINAL; red, green, blue: REAL; [red, green, blue] _ GraphicsColor.ColorToRGB [color]; intRed _ Truncate[red*255.0]; intGreen _ Truncate[green*255.0]; intBlue _ Truncate[blue*255.0]; intIntensity _ Truncate[GraphicsColor.ColorToIntensity[color]*255.0]; AIS.WriteSample[I.redWindow, intRed, maxY - i, j - minX]; AIS.WriteSample[I.greenWindow, intGreen, maxY - i, j - minX]; AIS.WriteSample[I.blueWindow, intBlue, maxY - i, j - minX]; AIS.WriteSample[I.bwWindow, intIntensity, maxY - i, j - minX]; }; PutImage: PUBLIC PROC [I: Image, i, j: INTEGER, color: Color, xSamples, ySamples: NAT] = { <> <> IF I.bAndWOnly THEN { intIntensity: CARDINAL; intIntensity _ Truncate[GraphicsColor.ColorToIntensity[color]*255.0]; AIS.WriteSample[I.bwWindow, intIntensity, ySamples-i, j]; } ELSE { intRed, intGreen, intBlue, intIntensity: CARDINAL; red, green, blue: REAL; [red, green, blue] _ GraphicsColor.ColorToRGB [color]; intRed _ Truncate[red*255.0]; intGreen _ Truncate[green*255.0]; intBlue _ Truncate[blue*255.0]; intIntensity _ Truncate[GraphicsColor.ColorToIntensity[color]*255.0]; AIS.WriteSample[I.redWindow, intRed, ySamples-i, j]; AIS.WriteSample[I.greenWindow, intGreen, ySamples-i, j]; AIS.WriteSample[I.blueWindow, intBlue, ySamples-i, j]; AIS.WriteSample[I.bwWindow, intIntensity, ySamples-i, j]; }; }; CloseImage: PUBLIC PROC [I: Image, aisRope: Rope.ROPE] = { f: AIS.FRef; IF I.bAndWOnly THEN { f _ I.bwWindow.fref; AIS.CloseWindow[I.bwWindow]; AIS.CloseFile[f]; MessageWindow.Append[aisRope]; MessageWindow.Append[" now closed"]; MessageWindow.Blink[]; } ELSE { f _ I.blueWindow.fref; AIS.CloseWindow[I.blueWindow]; AIS.CloseFile[f]; f _ I.bwWindow.fref; AIS.CloseWindow[I.bwWindow]; AIS.CloseFile[f]; f _ I.redWindow.fref; AIS.CloseWindow[I.redWindow]; AIS.CloseFile[f]; f _ I.greenWindow.fref; AIS.CloseWindow[I.greenWindow]; AIS.CloseFile[f]; MessageWindow.Append[" (red green blue BandW) "]; MessageWindow.Append[aisRope]; MessageWindow.Append[" now closed"]; MessageWindow.Blink[]; }; }; -- end of CloseImage BoundBoxOfImage: PRIVATE PROC [image: ImageRef, resolution: REAL _ 72.0] RETURNS [boundBox: BoundBox] = { xmin,ymin,xmax,ymax, xExtent, yExtent: REAL; [xmin,ymin,xmax,ymax] _ GraphicsOps.ImageBox[image]; <> <> xExtent _ xmax - xmin; yExtent _ ymax - ymin; xExtent _ (xExtent/resolution)*72.0; yExtent _ (yExtent/resolution)*72.0; boundBox _ NEW[BoundBoxObj]; boundBox.minVert _ [0,0,0]; boundBox.maxVert _ [xExtent,yExtent, 0]; }; NewBlackAndWhiteImage: PUBLIC PROC [imageName: Rope.ROPE] RETURNS [image: ImageRef, success: BOOL] = { bwName: Rope.ROPE _ Rope.Concat[SVFiles.FilenameMinusExtension[imageName],".ais"]; success _ TRUE; image _ GraphicsOps.NewAisImage[imageName !Directory.Error => {success _ FALSE; CONTINUE}]; IF NOT success THEN { MessageWindow.Append["Open AIS file failed", TRUE]; MessageWindow.Blink[]; RETURN}; }; NewColorImage: PUBLIC PROC [imageName: Rope.ROPE] RETURNS [redimage, greenimage, blueimage: ImageRef, success: BOOL] = { redName: Rope.ROPE _ Rope.Concat[SVFiles.FilenameMinusExtension[imageName],"-red.ais"]; greenName: Rope.ROPE _ Rope.Concat[SVFiles.FilenameMinusExtension[imageName],"-green.ais"]; blueName: Rope.ROPE _ Rope.Concat[SVFiles.FilenameMinusExtension[imageName],"-blue.ais"]; success _ TRUE; redimage _ GraphicsOps.NewAisImage[redName !Directory.Error => {success _ FALSE; CONTINUE}]; greenimage _ GraphicsOps.NewAisImage[greenName !Directory.Error => {success _ FALSE; CONTINUE}]; blueimage _ GraphicsOps.NewAisImage[blueName !Directory.Error => {success _ FALSE; CONTINUE}]; IF NOT success THEN { MessageWindow.Append["Open AIS file failed", TRUE]; MessageWindow.Blink[]; RETURN}; }; DrawAlignedBlackAndWhiteImage: PUBLIC PROC [dc: Graphics.Context, imageName: Rope.ROPE, resolution: REAL, screenWRTCamera: Point2d, boundBox: BoundBox, raw: BOOL] = { << Count how many samples there are in the x and y directions of the image. Look at the resolution (default is 72.0). This gives the actual size of the image. Frame it evenly around the clipBox.>> info: ReadAIS.MyAISInfo; stepSize, xStart, yStart: REAL; lowerLeft, upperRight: Point2d; samplesX, samplesY: NAT; mark: Mark; success: BOOL; extentX, extentY, projectionX, projectionY, trueExtentX, trueExtentY: REAL; [info, success] _ ReadAIS.Read[imageName]; IF NOT success THEN RETURN; <> [samplesX, samplesY] _ ReadAIS.SamplesFromInfo[info]; stepSize _ 72.0/resolution; -- in screen dots per sample lowerLeft _ SVVector2d.Difference[[boundBox.minVert[1], boundBox.minVert[2]], screenWRTCamera]; upperRight _ SVVector2d.Difference[[boundBox.maxVert[1], boundBox.maxVert[2]], screenWRTCamera]; extentX _ boundBox.maxVert[1] - boundBox.minVert[1]; extentY _ boundBox.maxVert[2] - boundBox.minVert[2]; trueExtentX _ Real.Float[samplesX-1]*stepSize; trueExtentY _ Real.Float[samplesY-1]*stepSize; projectionX _ (trueExtentX - extentX)/2.0; projectionY _ (trueExtentY - extentY)/2.0; xStart _ lowerLeft[1] - projectionX; yStart _ lowerLeft[2] - projectionY; xStart _ xStart - stepSize/2.0; yStart _ yStart - stepSize/2.0; mark _ Graphics.Save[dc]; Graphics.Translate[dc, xStart, yStart]; DrawBlackAndWhiteImage[dc, imageName, boundBox, resolution, raw]; Graphics.Restore[dc, mark]; }; DrawBlackAndWhiteImage: PUBLIC PROC [dc: Graphics.Context, imageName: Rope.ROPE, clipBox: BoundBox _ NIL, resolution: REAL _ 72.0, raw: BOOL] = { <> <> <> <> minX, maxX, minY, maxY: REAL; clipPath: Graphics.Path _ Graphics.NewPath[4]; lowerLeft, upperRight: Point2d; image: ImageRef; success: BOOL; scale: REAL; mark: Mark; <> [image, success] _ NewBlackAndWhiteImage[imageName]; IF NOT success THEN RETURN; <> IF clipBox = NIL THEN clipBox _ BoundBoxOfImage[image, resolution]; <> <> lowerLeft _ [0,0];-- screen coords upperRight _ SVVector2d.Sum[[clipBox.maxVert[1], clipBox.maxVert[2]], lowerLeft];-- screen coords <> minX _ lowerLeft[1]; maxX _ upperRight[1] +1; minY _ lowerLeft[2]; maxY _ upperRight[2] +1; <> scale _ 72.0/resolution; mark _ Graphics.Save[dc]; <> <> <> <> <> <> <> <> <> <> Graphics.SetCP[dc, 0, 0];-- put lower left corner of image at this new origin Graphics.SetColor[dc, GraphicsColor.black]; <> Graphics.Scale[dc, scale, scale]; Graphics.DrawImage[dc, image]; Graphics.Restore[dc, mark]; }; DrawAndScaleBlackAndWhiteImage: PUBLIC PROC [dc: Graphics.Context, imageName: Rope.ROPE, screenWRTCamera: Point2d, realMinX, realMinY, realMaxX, realMaxY: REAL] = { minX, maxX, minY, maxY: INTEGER; clipPath: Graphics.Path _ Graphics.NewPath[4]; lowerLeft, upperRight: Point2d; <> <> <> screenOrigin: Point2d; success: BOOL _ TRUE; image: ImageRef; imageXmin, imageYmin, imageXmax, imageYmax, xScale, yScale: REAL; mark: Mark _ Graphics.Save[dc]; [image, success] _ NewBlackAndWhiteImage[imageName]; IF NOT success THEN RETURN; <> lowerLeft _ SVVector2d.Difference[[realMinX, realMinY], screenWRTCamera]; upperRight _ SVVector2d.Difference[[realMaxX, realMaxY], screenWRTCamera]; <> minX _ RoundDown[lowerLeft[1]]; maxX _ RoundUp[upperRight[1]]; minY _ RoundDown[lowerLeft[2]]; maxY _ RoundUp[upperRight[2]]; IF NOT IsEven[maxX - minX + 1] THEN maxX _ maxX + 1; IF NOT IsEven[maxY - minY + 1] THEN maxY _ maxY + 1; screenOrigin _ [minX, minY];-- ais file origin with respect to screen origin <> [imageXmin, imageYmin, imageXmax, imageYmax] _ GraphicsOps.ImageBox[image]; xScale _ (maxX-minX)/(imageXmax-imageXmin); yScale _ (maxY-minY)/(imageYmax-imageYmin); Graphics.MoveTo[clipPath, screenOrigin[1], screenOrigin[2]]; Graphics.LineTo[clipPath, screenOrigin[1], screenOrigin[2]+maxY-minY]; Graphics.LineTo[clipPath, screenOrigin[1] + maxX-minX, screenOrigin[2]+maxY-minY]; Graphics.LineTo[clipPath, screenOrigin[1] + maxX-minX, screenOrigin[2]]; Graphics.ClipArea[dc, clipPath]; Graphics.Translate[dc, screenOrigin[1], screenOrigin[2]]; Graphics.SetCP[dc, 0, 0]; Graphics.Scale[dc, xScale, yScale]; Graphics.SetColor[dc, GraphicsColor.white]; Graphics.DrawImage[dc, image, TRUE]; Graphics.Restore[dc, mark]; }; DrawAlignedColorImage: PUBLIC PROC [dc: Graphics.Context, imageName: Rope.ROPE, resolution: REAL, screenWRTCamera: Point2d, boundBox: BoundBox] = { << Count how many samples there are in the x and y directions of the image. Look at the resolution (default is 72.0). This gives the actual size of the image. Frame it evenly around the clipBox.>> info: ReadAIS.MyAISInfo; stepSize, xStart, yStart: REAL; lowerLeft, upperRight: Point2d; redName: Rope.ROPE _ Rope.Concat[SVFiles.FilenameMinusExtension[imageName],"-red.ais"]; samplesX, samplesY: NAT; mark: Mark; success: BOOL; extentX, extentY, projectionX, projectionY, trueExtentX, trueExtentY: REAL; [info, success] _ ReadAIS.Read[redName]; IF NOT success THEN RETURN; <> [samplesX, samplesY] _ ReadAIS.SamplesFromInfo[info]; stepSize _ 72.0/resolution; -- in screen dots per sample lowerLeft _ SVVector2d.Difference[[boundBox.minVert[1], boundBox.minVert[2]], screenWRTCamera]; upperRight _ SVVector2d.Difference[[boundBox.maxVert[1], boundBox.maxVert[2]], screenWRTCamera]; extentX _ boundBox.maxVert[1] - boundBox.minVert[1]; extentY _ boundBox.maxVert[2] - boundBox.minVert[2]; trueExtentX _ Real.Float[samplesX-1]*stepSize; trueExtentY _ Real.Float[samplesY-1]*stepSize; projectionX _ (trueExtentX - extentX)/2.0; projectionY _ (trueExtentY - extentY)/2.0; xStart _ lowerLeft[1] - projectionX; yStart _ lowerLeft[2] - projectionY; xStart _ xStart - stepSize/2.0; yStart _ yStart - stepSize/2.0; mark _ Graphics.Save[dc]; Graphics.Translate[dc, xStart, yStart]; DrawColorImage[dc, imageName, boundBox, resolution]; Graphics.Restore[dc, mark]; }; DrawColorImage: PUBLIC PROC [dc: Graphics.Context, imageName: Rope.ROPE, clipBox: BoundBox _ NIL, resolution: REAL _ 72.0] = { <> minX, maxX, minY, maxY: REAL; lowerLeft, upperRight: Point2d; success: BOOL; redimage, greenimage, blueimage: ImageRef; scale: REAL; clipPath: Graphics.Path _ Graphics.NewPath[4]; mark: Mark _ Graphics.Save[dc]; [redimage, greenimage, blueimage, success] _ NewColorImage[imageName]; IF NOT success THEN RETURN; IF clipBox = NIL THEN clipBox _ BoundBoxOfImage[redimage, resolution]; lowerLeft _ [0,0];-- screen coords upperRight _ SVVector2d.Sum[[clipBox.maxVert[1], clipBox.maxVert[2]], lowerLeft];-- screen coords <> minX _ lowerLeft[1]; maxX _ upperRight[1] +1; minY _ lowerLeft[2]; maxY _ upperRight[2] +1; <> scale _ 72.0/resolution; Graphics.MoveTo[clipPath, minX, minY]; Graphics.LineTo[clipPath, minX, maxY]; Graphics.LineTo[clipPath, maxX, maxY]; Graphics.LineTo[clipPath, maxX, minY]; Graphics.SetColor[dc, GraphicsColor.black]; Graphics.DrawStroke[dc, clipPath, 2, TRUE]; Graphics.ClipArea[dc, clipPath]; <> <> Graphics.SetCP[dc, 0, 0]; -- put lower left corner of image at this new origin Graphics.Scale[dc, scale, scale]; [] _ Graphics.SetPaintMode[dc, opaque]; Graphics.SetColor[dc, GraphicsColor.red]; Graphics.DrawImage[dc, redimage]; [] _ Graphics.SetPaintMode[dc, transparent]; Graphics.SetColor[dc, GraphicsColor.green]; Graphics.DrawImage[dc, greenimage]; Graphics.SetColor[dc, GraphicsColor.blue]; Graphics.DrawImage[dc, blueimage]; Graphics.Restore[dc, mark]; }; DrawAndScaleColorImage: PUBLIC PROC [dc: Graphics.Context, imageName: Rope.ROPE, screenWRTCamera: Point2d, realMinX, realMinY, realMaxX, realMaxY: REAL] = { minX, maxX, minY, maxY: INTEGER; lowerLeft, upperRight: Point2d; <> screenOrigin: Point2d; redimage, greenimage, blueimage: ImageRef; success: BOOL; imageXmin, imageYmin, imageXmax, imageYmax, xScale, yScale: REAL; clipPath: Graphics.Path _ Graphics.NewPath[4]; mark: Mark _ Graphics.Save[dc]; [redimage, greenimage, blueimage, success] _ NewColorImage[imageName]; IF NOT success THEN RETURN; lowerLeft _ SVVector2d.Difference[[realMinX, realMinY], screenWRTCamera]; upperRight _ SVVector2d.Difference[[realMaxX, realMaxY], screenWRTCamera]; <> minX _ RoundDown[lowerLeft[1]]; maxX _ RoundUp[upperRight[1]]; minY _ RoundDown[lowerLeft[2]]; maxY _ RoundUp[upperRight[2]]; IF NOT IsEven[maxX - minX + 1] THEN maxX _ maxX + 1; IF NOT IsEven[maxY - minY + 1] THEN maxY _ maxY + 1; screenOrigin _ [minX, minY];-- ais file lower left with respect to screen origin <> [imageXmin, imageYmin, imageXmax, imageYmax] _ GraphicsOps.ImageBox[redimage]; xScale _ (maxX-minX)/(imageXmax-imageXmin); yScale _ (maxY-minY)/(imageYmax-imageYmin); Graphics.MoveTo[clipPath, screenOrigin[1], screenOrigin[2]]; Graphics.LineTo[clipPath, screenOrigin[1], screenOrigin[2]+maxY-minY]; Graphics.LineTo[clipPath, screenOrigin[1] + maxX-minX, screenOrigin[2]+maxY-minY]; Graphics.LineTo[clipPath, screenOrigin[1] + maxX-minX, screenOrigin[2]]; Graphics.ClipArea[dc, clipPath]; Graphics.Translate[dc, screenOrigin[1], screenOrigin[2]]; Graphics.SetCP[dc, 0, 0]; Graphics.Scale[dc, xScale, yScale]; [] _ Graphics.SetPaintMode[dc, opaque]; Graphics.SetColor[dc, GraphicsColor.red]; Graphics.DrawImage[dc, redimage]; [] _ Graphics.SetPaintMode[dc, transparent]; Graphics.SetColor[dc, GraphicsColor.green]; Graphics.DrawImage[dc, greenimage]; Graphics.SetColor[dc, GraphicsColor.blue]; Graphics.DrawImage[dc, blueimage]; Graphics.Restore[dc, mark]; }; -- end of DrawAndScaleColorImage END.