<> <> <> <> DIRECTORY AIS, FS, Graphics, GraphicsColor, GraphicsOps, ReadAIS, Real, Rope, SV2d, SVError, SVFiles, SVImage, SVModelTypes, SVVector2d; SVImageImpl: PROGRAM IMPORTS AIS, FS, Graphics, GraphicsColor, GraphicsOps, ReadAIS, Real, Rope, SVError, SVFiles, SVVector2d EXPORTS SVImage = BEGIN Image: TYPE = REF ImageObj; ImageObj: TYPE = SVImage.ImageObj; BoundBox: TYPE = REF BoundBoxObj; BoundBoxObj: TYPE = SVModelTypes.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, commentString: Rope.ROPE] RETURNS [I: Image, numberOfSamplesX, numberOfSamplesY: NAT] = { << Bound box is in camera coordinates>> <<>> f: AIS.FRef; raster: AIS.Raster; I _ NEW[ImageObj]; [numberOfSamplesX, numberOfSamplesY] _ CountSamples[realMinX, realMinY, realMaxX, realMaxY, resolution]; raster _ NEW[AIS.RasterPart _ [numberOfSamplesY, numberOfSamplesX, rd, 8, -1, 65535]]; IF bAndWOnly THEN { I.bAndWOnly _ TRUE; f _ ReadAIS.CreateFile[aisRope, raster, commentString, TRUE, 0, resolution]; I.bwWindow _ AIS.OpenWindow[f]; SVError.Append[" New "]; SVError.Append[aisRope]; SVError.Append[" created.", FALSE, TRUE]; } ELSE { redRope: Rope.ROPE _ Rope.Concat[SVFiles.FilenameMinusExtension[aisRope], "-red.ais"]; greenRope: Rope.ROPE _ Rope.Concat[SVFiles.FilenameMinusExtension[aisRope], "-grn.ais"]; blueRope: Rope.ROPE _ Rope.Concat[SVFiles.FilenameMinusExtension[aisRope], "-blu.ais"]; bwRope: Rope.ROPE _ aisRope; I.bAndWOnly _ FALSE; f _ ReadAIS.CreateFile[redRope, raster, commentString, TRUE, 0, resolution]; I.redWindow _ AIS.OpenWindow[f]; f _ ReadAIS.CreateFile[greenRope, raster, commentString, TRUE, 0, resolution]; I.greenWindow _ AIS.OpenWindow[f]; f _ ReadAIS.CreateFile[blueRope, raster, commentString, TRUE, 0, resolution]; I.blueWindow _ AIS.OpenWindow[f]; f _ ReadAIS.CreateFile[bwRope, raster, commentString, TRUE, 0, resolution]; I.bwWindow _ AIS.OpenWindow[f]; SVError.Append[" New color "]; SVError.Append[aisRope]; SVError.Append["'s created.", FALSE, TRUE]; }; }; -- end of OpenImage DeleteFile: PRIVATE PROC [name: Rope.ROPE] = { AIS.DeleteFile[name]; SVError.Append[name]; SVError.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]; SVError.Append[aisRope]; SVError.Append[" now closed", FALSE, TRUE]; SVError.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]; SVError.Append[" (red grn blu BandW) "]; SVError.Append[aisRope]; SVError.Append[" now closed", FALSE, TRUE]; SVError.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 !FS.Error => {success _ FALSE; CONTINUE}]; IF NOT success THEN { SVError.Append["Open AIS file failed", TRUE, TRUE]; SVError.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],"-grn.ais"]; blueName: Rope.ROPE _ Rope.Concat[SVFiles.FilenameMinusExtension[imageName],"-blu.ais"]; success _ TRUE; redimage _ GraphicsOps.NewAisImage[redName !FS.Error => {success _ FALSE; CONTINUE}]; greenimage _ GraphicsOps.NewAisImage[greenName !FS.Error => {success _ FALSE; CONTINUE}]; blueimage _ GraphicsOps.NewAisImage[blueName !FS.Error => {success _ FALSE; CONTINUE}]; IF NOT success THEN { SVError.Append["Open AIS file failed", TRUE, TRUE]; SVError.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.>> stepSize, xStart, yStart: REAL; lowerLeft, upperRight: Point2d; samplesX, samplesY: NAT; aisFile: AIS.FRef; raster: AIS.Raster; mark: Mark; extentX, extentY, projectionX, projectionY, trueExtentX, trueExtentY: REAL; aisFile _ AIS.OpenFile[imageName, FALSE]; raster _ AIS.ReadRaster[aisFile]; <> samplesX _ raster.scanLength; samplesY _ raster.scanCount; stepSize _ 72.0/resolution; -- in screen dots per sample lowerLeft _ SVVector2d.Sub[[boundBox.minVert[1], boundBox.minVert[2]], screenWRTCamera]; upperRight _ SVVector2d.Sub[[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.Add[[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.Scale[dc, scale, scale]; Graphics.SetColor[dc, GraphicsColor.black]; 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.Sub[[realMinX, realMinY], screenWRTCamera]; upperRight _ SVVector2d.Sub[[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.>> stepSize, xStart, yStart: REAL; lowerLeft, upperRight: Point2d; redName: Rope.ROPE _ Rope.Concat[SVFiles.FilenameMinusExtension[imageName],"-red.ais"]; samplesX, samplesY: NAT; aisFile: AIS.FRef; raster: AIS.Raster; mark: Mark; extentX, extentY, projectionX, projectionY, trueExtentX, trueExtentY: REAL; aisFile _ AIS.OpenFile[redName, FALSE]; raster _ AIS.ReadRaster[aisFile]; <> samplesX _ raster.scanLength; samplesY _ raster.scanCount; stepSize _ 72.0/resolution; -- in screen dots per sample lowerLeft _ SVVector2d.Sub[[boundBox.minVert[1], boundBox.minVert[2]], screenWRTCamera]; upperRight _ SVVector2d.Sub[[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; <> [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.Add[[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.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.Sub[[realMinX, realMinY], screenWRTCamera]; upperRight _ SVVector2d.Sub[[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.