<> <> <> <> DIRECTORY AIS, AtomButtonsTypes, Feedback, FS, Imager, ImagerColor, ImagerColorPrivate, ImagerPixelArray, ImagerTransformation, Real, Rope, SVShading, SV2d, SVBasicTypes, SVFiles, SVImage, SVModelTypes, SVVector2d, ViewerClasses; SVImageImpl: CEDAR PROGRAM IMPORTS AIS, Feedback, FS, Imager, ImagerColor, ImagerColorPrivate, ImagerPixelArray, ImagerTransformation, Real, Rope, SVShading, SVFiles, SVVector2d EXPORTS SVImage = BEGIN BoundBox: TYPE = REF BoundBoxObj; BoundBoxObj: TYPE = SVBasicTypes.BoundBoxObj; Color: TYPE = Imager.Color; FeedbackData: TYPE = AtomButtonsTypes.FeedbackData; FRef: TYPE = AIS.FRef; Image: TYPE = REF ImageObj; ImageObj: TYPE = SVImage.ImageObj; Point2d: TYPE = SV2d.Point2d; Viewer: TYPE = ViewerClasses.Viewer; WRef: TYPE = AIS.WRef; 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.Fix[r]; RETURN} ELSE { r _ -r;-- make it positive rDown _ Real.Fix[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.Fix[r]; rUp _ rUp + 1; RETURN} ELSE { r _ -r;-- make it positive rUp _ Real.Fix[r]; rUp _ - rUp; }; }; CountSamples: PUBLIC 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.Fix[realSamplesX] + 2; numberOfSamplesY _ Real.Fix[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, feedback: FeedbackData] 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 _ AIS.CreateFile[aisRope, raster]; I.bwWindow _ AIS.OpenWindow[f]; Feedback.PutF[feedback, oneLiner, " New %g created.", [rope[aisRope]]]; } 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 _ AIS.CreateFile[redRope, raster]; I.redWindow _ AIS.OpenWindow[f]; f _ AIS.CreateFile[greenRope, raster]; I.greenWindow _ AIS.OpenWindow[f]; f _ AIS.CreateFile[blueRope, raster]; I.blueWindow _ AIS.OpenWindow[f]; f _ AIS.CreateFile[bwRope, raster]; I.bwWindow _ AIS.OpenWindow[f]; Feedback.PutF[feedback, end, " New color %g's created.", [rope[aisRope]]]; }; }; -- end of OpenImage <> <> <> <<}; -- end of DeleteFile>> Truncate: PROC [value: REAL] RETURNS [m: CARDINAL] = { <> SELECT value FROM <0 => ERROR; >255.0 => m _ 255; ENDCASE => m _ Real.Fix[value]; }; PutImage2: PROC [I: Image, i, j: INTEGER, color: Color, minX, maxX, minY, maxY: INTEGER] = { <> <> intRed, intGreen, intBlue, intIntensity: CARDINAL; red, green, blue, intensity: REAL; [red, green, blue] _ SVShading.ExtractRGB[color]; intensity _ ImagerColorPrivate.IntensityFromColor[NARROW[color]]; intRed _ Truncate[red*255.0]; intGreen _ Truncate[green*255.0]; intBlue _ Truncate[blue*255.0]; intIntensity _ Truncate[intensity*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]; }; RGBTo8Bits: PUBLIC PROC [r,g,b: REAL] RETURNS [red, green, blue, black: NAT] = { k: REAL; red _ Real.Fix[r*255.0]; green _ Real.Fix[g*255.0]; blue _ Real.Fix[b*255.0]; k _ IntensityFromRGB[r,g,b]; black _ Real.Fix[k*255.0]; }; IntensityFromRGB: PROC [r,g,b: REAL] RETURNS [REAL] ~ { <> Y: REAL ~ 0.30*r+0.59*g+0.11*b; IF Y<=0 THEN RETURN[0]; <=1 THEN RETURN[1];>> RETURN[Y]; }; PutImage: PUBLIC PROC [I: Image, i, j: INTEGER, color: Color, xSamples, ySamples: NAT] = { <> <> IF I.bAndWOnly THEN { intIntensity: CARDINAL; intensity: REAL; intensity _ ImagerColorPrivate.IntensityFromColor[NARROW[color]]; intIntensity _ Truncate[intensity*255.0]; AIS.WriteSample[I.bwWindow, intIntensity, ySamples-i, j]; } ELSE { intRed, intGreen, intBlue, intIntensity: CARDINAL; red, green, blue, intensity: REAL; [red, green, blue] _ SVShading.ExtractRGB[color]; intensity _ ImagerColorPrivate.IntensityFromColor[NARROW[color]]; intRed _ Truncate[red*255.0]; intGreen _ Truncate[green*255.0]; intBlue _ Truncate[blue*255.0]; intIntensity _ Truncate[intensity*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, comment: Rope.ROPE, feedback: FeedbackData] = { f: AIS.FRef; IF I.bAndWOnly THEN { f _ I.bwWindow.fref; AIS.CloseWindow[I.bwWindow]; AIS.WriteComment[f, comment]; AIS.CloseFile[f]; Feedback.PutF[feedback, end, "%g now closed", [rope[aisRope]]]; Feedback.Blink[feedback]; } ELSE { f _ I.blueWindow.fref; AIS.CloseWindow[I.blueWindow]; AIS.WriteComment[f, comment]; AIS.CloseFile[f]; f _ I.bwWindow.fref; AIS.CloseWindow[I.bwWindow]; AIS.WriteComment[f, comment]; AIS.CloseFile[f]; f _ I.redWindow.fref; AIS.CloseWindow[I.redWindow]; AIS.WriteComment[f, comment]; AIS.CloseFile[f]; f _ I.greenWindow.fref; AIS.CloseWindow[I.greenWindow]; AIS.WriteComment[f, comment]; AIS.CloseFile[f]; Feedback.PutF[feedback, end, " (red grn blu BandW) %g now closed.", [rope[aisRope]]]; Feedback.Blink[feedback]; }; }; -- end of CloseImage BoundBoxOfImage: PRIVATE PROC [image: ImagerPixelArray.PixelArray, resolution: REAL _ 72.0] RETURNS [boundBox: BoundBox] = { xExtent, yExtent: REAL; <> <> xExtent _ (image.fSize/resolution)*72.0; yExtent _ (image.sSize/resolution)*72.0; boundBox _ NEW[BoundBoxObj]; boundBox.loX _ boundBox.loY _ 0; boundBox.hiX _ xExtent; boundBox.hiY _ yExtent; }; NewBlackAndWhiteImage: PROC [imageName: Rope.ROPE, feedback: FeedbackData] RETURNS [image: ImagerPixelArray.PixelArray, success: BOOL] = { bwName: Rope.ROPE _ Rope.Concat[SVFiles.FilenameMinusExtension[imageName],".ais"]; success _ TRUE; image _ ImagerPixelArray.FromAIS[imageName !FS.Error => {success _ FALSE; CONTINUE}]; IF NOT success THEN { Feedback.Append[feedback, "Open AIS file failed", oneLiner]; Feedback.Blink[feedback]; RETURN}; }; NewColorImage: PUBLIC PROC [imageName: Rope.ROPE, feedback: FeedbackData] RETURNS [image: ImagerPixelArray.PixelArray, 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; image _ ImagerPixelArray.Join3AIS[redName, greenName, blueName !FS.Error => {success _ FALSE; CONTINUE}]; IF NOT success THEN { Feedback.Append[feedback, "Open AIS file failed", oneLiner]; Feedback.Blink[feedback]; RETURN}; }; <<>> DrawAlignedBlackAndWhiteImage: PUBLIC PROC [dc: Imager.Context, imageName: Rope.ROPE, resolution: REAL, screenWRTCamera: Point2d, boundBox: BoundBox, feedback: FeedbackData] = { << Count how many samples there are in the x and y directions of the image. Look at the resolution (samples per inch. default is 72.0). This gives the actual size of the image, in inches. Frame it evenly around the clipBox. The clipBox is in Camera coordinates. Strategy: Find the center of the clipBox in camera coordinates. Convert to screen coordinates. Find the width of the ais image (in screen coordinates -- just use 72.0 as a magic number). Find the origin (xStart, yStart) in screen coordinates.>> stepSize, xStart, yStart: REAL; samplesX, samplesY: NAT; aisFile: AIS.FRef; raster: AIS.Raster; originScreen, screenExtent: Point2d; originCameraX, originCameraY: REAL; DrawAlignedBlackAndWhiteImageAux: SAFE PROC = { Imager.TranslateT[dc, [xStart, yStart]]; DrawBlackAndWhiteImage[dc, imageName, screenExtent, resolution, feedback]; }; aisFile _ AIS.OpenFile[imageName, FALSE]; raster _ AIS.ReadRaster[aisFile]; AIS.CloseFile[aisFile]; <> <> samplesX _ raster.scanLength; samplesY _ raster.scanCount; stepSize _ 72.0/resolution; -- in screen dots per sample IF boundBox = NIL THEN { originCameraX _ 0.0; originCameraY _ 0.0; } ELSE { originCameraX _ (boundBox.hiX + boundBox.loX)/2.0; originCameraY _ (boundBox.hiY + boundBox.loY)/2.0; }; originScreen _ SVVector2d.Sub[[originCameraX, originCameraY], screenWRTCamera]; screenExtent[1] _ Real.Float[samplesX-1]*stepSize; -- screen dots screenExtent[2] _ Real.Float[samplesY-1]*stepSize; -- screen dots xStart _ originScreen[1] - screenExtent[1]/2.0; yStart _ originScreen[2] - screenExtent[2]/2.0; <> <> Imager.DoSaveAll[dc, DrawAlignedBlackAndWhiteImageAux]; }; DrawAlignedColorImage: PUBLIC PROC [dc: Imager.Context, imageName: Rope.ROPE, resolution: REAL, screenWRTCamera: Point2d, boundBox: BoundBox, feedback: FeedbackData] = { << 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; samplesX, samplesY: NAT; aisFile: AIS.FRef; raster: AIS.Raster; originScreen, screenExtent: Point2d; originCameraX, originCameraY: REAL; redName: Rope.ROPE _ Rope.Concat[SVFiles.FilenameMinusExtension[imageName],"-red.ais"]; DrawAlignedColorImageAux: SAFE PROC = { Imager.TranslateT[dc, [xStart, yStart]]; DrawColorImage[dc, imageName, screenExtent, resolution, feedback]; }; aisFile _ AIS.OpenFile[redName, FALSE]; raster _ AIS.ReadRaster[aisFile]; AIS.CloseFile[aisFile]; <> <<>> <> samplesX _ raster.scanLength; samplesY _ raster.scanCount; stepSize _ 72.0/resolution; -- in screen dots per sample IF boundBox = NIL THEN { originCameraX _ 0.0; originCameraY _ 0.0; } ELSE { originCameraX _ (boundBox.hiX + boundBox.loX)/2.0; originCameraY _ (boundBox.hiY + boundBox.loY)/2.0; }; originScreen _ SVVector2d.Sub[[originCameraX, originCameraY], screenWRTCamera]; screenExtent[1] _ Real.Float[samplesX-1]*stepSize; -- screen dots screenExtent[2] _ Real.Float[samplesY-1]*stepSize; -- screen dots xStart _ originScreen[1] - screenExtent[1]/2.0; yStart _ originScreen[2] - screenExtent[2]/2.0; Imager.DoSaveAll[dc, DrawAlignedColorImageAux]; }; <<>> DrawBlackAndWhiteAtOrigin: PUBLIC PROC [dc: Imager.Context, imageName: Rope.ROPE, resolution: REAL _ 72.0, feedback: FeedbackData] = { stepSize: REAL; samplesX, samplesY: NAT; aisFile: AIS.FRef; raster: AIS.Raster; screenExtent: Point2d; aisFile _ AIS.OpenFile[imageName, FALSE]; raster _ AIS.ReadRaster[aisFile]; AIS.CloseFile[aisFile]; samplesX _ raster.scanLength; samplesY _ raster.scanCount; stepSize _ 72.0/resolution; -- in screen dots per sample screenExtent[1] _ Real.Float[samplesX-1]*stepSize; -- screen dots screenExtent[2] _ Real.Float[samplesY-1]*stepSize; -- screen dots DrawBlackAndWhiteImage[dc, imageName, screenExtent, resolution, feedback]; }; DrawColorImageAtOrigin: PUBLIC PROC [dc: Imager.Context, imageName: Rope.ROPE, resolution: REAL _ 72.0, feedback: FeedbackData] = { stepSize: REAL; samplesX, samplesY: NAT; aisFile: AIS.FRef; redName: Rope.ROPE _ Rope.Concat[SVFiles.FilenameMinusExtension[imageName],"-red.ais"]; raster: AIS.Raster; screenExtent: Point2d; aisFile _ AIS.OpenFile[redName, FALSE]; raster _ AIS.ReadRaster[aisFile]; AIS.CloseFile[aisFile]; samplesX _ raster.scanLength; samplesY _ raster.scanCount; stepSize _ 72.0/resolution; -- in screen dots per sample screenExtent[1] _ Real.Float[samplesX-1]*stepSize; -- screen dots screenExtent[2] _ Real.Float[samplesY-1]*stepSize; -- screen dots DrawColorImage[dc, imageName, screenExtent, resolution, feedback]; }; DrawBlackAndWhiteImage: PROC [dc: Imager.Context, imageName: Rope.ROPE, screenExtent: Point2d, resolution: REAL _ 72.0, feedback: FeedbackData] = { <> <> <> <> minX, maxX, minY, maxY: REAL; image: ImagerPixelArray.PixelArray; success: BOOL; scale: REAL; colors: Imager.ColorOperator _ ImagerColor.NewColorOperatorGrayLinear[255, 0]; DrawBlackAndWhiteImageAux: SAFE PROC = { Imager.SetSampledColor[dc, image, ImagerTransformation.Scale[scale], colors]; Imager.MaskBox[dc, [minX, minY, maxX, maxY]]; }; <> [image, success] _ NewBlackAndWhiteImage[imageName, feedback]; IF NOT success THEN RETURN; <> scale _ 72.0/resolution; <> minX _ 0.0; minY _ 0.0; maxX _ screenExtent[1]; maxY _ screenExtent[2]; Imager.DoSaveAll[dc, DrawBlackAndWhiteImageAux]; }; DrawColorImage: PROC [dc: Imager.Context, imageName: Rope.ROPE, screenExtent: Point2d, resolution: REAL _ 72.0, feedback: FeedbackData] = { <> minX, maxX, minY, maxY: REAL; image: ImagerPixelArray.PixelArray; success: BOOL; scale: REAL; <> colors: Imager.ColorOperator _ ImagerColor.NewColorOperatorRGB[255]; DrawColorImageAux: SAFE PROC = { Imager.SetSampledColor[dc, image, ImagerTransformation.Scale[scale], colors]; Imager.MaskBox[dc, [minX, minY, maxX, maxY]]; }; <> [image, success] _ NewColorImage[imageName, feedback]; IF NOT success THEN RETURN; <> scale _ 72.0/resolution; <> minX _ 0.0; minY _ 0.0; maxX _ screenExtent[1]; maxY _ screenExtent[2]; Imager.DoSaveAll[dc, DrawColorImageAux]; }; END.