DIRECTORY Real USING [RoundI, Float], Rope USING [ROPE], Basics USING [bitsPerWord, BITSHIFT], FS USING [StreamOpen], IO USING [STREAM, UnsafeBlock, UnsafeGetBlock, UnsafePutBlock, Close], Imager USING [Context], ImagerBasic USING [DeviceRectangle], ImagerDisplay USING [DisplayData], ImagerPixelMapsExtras USING [LoadScanSeg, StoreScanSeg, ByteSequence], ImagerColorAIS; ImagerColorAISImpl: CEDAR PROGRAM IMPORTS FS, IO, Real, Basics, ImagerPixelMapsExtras EXPORTS ImagerColorAIS ~ BEGIN bytesPerWord: NAT ~ Basics.bitsPerWord / 8; maxBytesPerBlock: NAT ~ 8192; aisPassword: INTEGER ~ -31574; typeDo: INTEGER ~ 17519; -- ASCII for "D0"? PartHeader: TYPE ~ MACHINE DEPENDENT RECORD[ type: [0..64), length: [0..1024) ]; AISHeader: TYPE ~ RECORD[ passWord: INTEGER, length: NAT, partHeader: PartHeader]; AISRasterDef: TYPE ~ RECORD[ scanCount, scanLength, scanDir, samplesPerPixel, codingType, bitsPerSample, wordsPerScanLine, scanLinesPerBlock, paddingPerBlock: NAT ]; ByteSequence: TYPE ~ ImagerPixelMapsExtras.ByteSequence; DisplayData: TYPE ~ ImagerDisplay.DisplayData; ColorAISError: PUBLIC SIGNAL [reason: ATOM] ~ CODE; Ceiling: PROC[number: REAL] RETURNS[result: INTEGER] ~ { result _ Real.RoundI[number]; IF result < number THEN result _ result + 1; }; GetAISFile: PUBLIC PROC[context: Imager.Context, fileName: Rope.ROPE, xOffset, yOffset: INTEGER _ 0] ~ { GetFiles[context, fileName, NIL, NIL, xOffset, yOffset]; }; Get3AISFiles: PUBLIC PROC[context: Imager.Context, redFile, greenFile, blueFile: Rope.ROPE, xOffset, yOffset: INTEGER _ 0] ~ { GetFiles[context, redFile, greenFile, blueFile, xOffset, yOffset]; }; GetFiles: PROC[context: Imager.Context, aisFile, greenFile, blueFile: Rope.ROPE, xOffset, yOffset: INTEGER _ 0] ~ TRUSTED { displayData: DisplayData _ NARROW[ context.data, DisplayData]; -- get context info clipper: ImagerBasic.DeviceRectangle _ displayData.compositeClipper.first; input: IO.STREAM _ FS.StreamOpen[aisFile]; inputRed, inputGrn, inputBlu: IO.STREAM; block: REF ByteSequence _ NEW[ByteSequence[maxBytesPerBlock]]; block2: REF ByteSequence _ NEW[ByteSequence[maxBytesPerBlock]]; blockPtr: LONG POINTER; unsafeBlock: IO.UnsafeBlock; bytesRead: INT; header: REF AISHeader; raster: REF AISRasterDef; scan: INTEGER; index, scanCount, pixelsPerScanline, bitsPerSample, samplesPerPixel, samplesPerByte: NAT; wordsPerScanLine, blockSize, paddingPerBlock, codingType: NAT; blocked: BOOLEAN; scanLinesPerBlock: INTEGER; -- -1 means no blocking clipper.fMin _ clipper.fMin / displayData.displayClass.viewUnitsPerPixel; clipper.sMin _ clipper.sMin / displayData.displayClass.viewUnitsPerPixel; clipper.fSize _ clipper.fSize / displayData.displayClass.viewUnitsPerPixel; clipper.sSize _ clipper.sSize / displayData.displayClass.viewUnitsPerPixel; unsafeBlock.base _ LOOPHOLE[LOOPHOLE[block, LONG POINTER] + 1, LONG POINTER]; unsafeBlock.startIndex _ 0; unsafeBlock.count _ 2048; -- range of bytes to fill bytesRead _ IO.UnsafeGetBlock[ input, unsafeBlock]; header _ LOOPHOLE[unsafeBlock.base, REF AISHeader]; -- look at block in AIS format IF header.passWord # aisPassword -- check password THEN { ColorAISError[$NotAnIASFile]; RETURN[]; }; IF header.length > 1024 THEN { -- read rest of header if long unsafeBlock.startIndex _ 2048; unsafeBlock.count _ header.length * bytesPerWord - 2048; IF unsafeBlock.count + unsafeBlock.startIndex > maxBytesPerBlock THEN { ColorAISError[$ExcessivelyLongAISHeader]; RETURN[]; }; bytesRead _ IO.UnsafeGetBlock[ input, unsafeBlock]; }; index _ 0; WHILE header.partHeader.type # 1 DO -- search for raster description index _ index + header.partHeader.length*bytesPerWord; IF index > (unsafeBlock.startIndex + unsafeBlock.count)/bytesPerWord THEN { ColorAISError[$NoRasterDescription]; RETURN[]; }; header _ LOOPHOLE[unsafeBlock.base + index, REF AISHeader]; ENDLOOP; raster _ LOOPHOLE[unsafeBlock.base + index + 3, REF AISRasterDef]; scanCount _ raster.scanCount; pixelsPerScanline _ raster.scanLength; -- Pixels per scanline IF raster.scanDir # 3 THEN { -- check for right and down scan direction ColorAISError[$NotAVideoRaster]; RETURN[]; }; samplesPerPixel _ raster.samplesPerPixel; codingType _ raster.codingType; bitsPerSample _ Basics.BITSHIFT[1, displayData[0].refRep.lgBitsPerPixel]; IF bitsPerSample = 16 THEN bitsPerSample _ 8; -- 16 means interleaved RG on Dorado IF bitsPerSample # raster.bitsPerSample THEN { ColorAISError[$BitsPerSampleMismatched]; RETURN[]; }; bitsPerSample _ raster.bitsPerSample; samplesPerByte _ 8 / bitsPerSample; wordsPerScanLine _ raster.wordsPerScanLine; IF raster.scanLinesPerBlock < 32768 -- -1 means unblocked THEN { scanLinesPerBlock _ raster.scanLinesPerBlock; -- blocked paddingPerBlock _ raster.paddingPerBlock * bytesPerWord; blocked _ TRUE; } ELSE { scanLinesPerBlock _ maxBytesPerBlock / (wordsPerScanLine * bytesPerWord); paddingPerBlock _ 0; -- unblocked blocked _ FALSE; }; xOffset _ xOffset + (clipper.fSize - LOOPHOLE[pixelsPerScanline, INTEGER])/2; yOffset _ yOffset + (clipper.sSize - LOOPHOLE[scanCount, INTEGER])/2; IF greenFile # NIL AND blueFile # NIL THEN { -- get green and blue files, if there header _ LOOPHOLE[unsafeBlock.base, REF AISHeader]; -- point header record at block start inputRed _ input; inputGrn _ FS.StreamOpen[greenFile]; bytesRead _ IO.UnsafeGetBlock[ inputGrn, unsafeBlock]; IF header.passWord # aisPassword -- check password THEN { ColorAISError[$GreenFileNotAnIASFile]; RETURN[]; }; inputBlu _ FS.StreamOpen[blueFile]; bytesRead _ IO.UnsafeGetBlock[ inputBlu, unsafeBlock]; IF header.passWord # aisPassword -- check password THEN { ColorAISError[$BlueFileNotAnIASFile]; RETURN[]; }; }; scan _ yOffset; scanCount _ MIN[scanCount + scan, clipper.sSize]; unsafeBlock.count _ blockSize _ wordsPerScanLine * bytesPerWord * scanLinesPerBlock + paddingPerBlock; IF greenFile # NIL AND blueFile # NIL AND blockSize*3 > maxBytesPerBlock THEN { block _ NEW[ByteSequence[blockSize*3]]; block2 _ NEW[ByteSequence[blockSize*3]]; unsafeBlock.base _ LOOPHOLE[block, LONG POINTER] + SIZE[ByteSequence[0]]; }; WHILE scan < scanCount DO -- read image bits IF greenFile = NIL OR blueFile = NIL -- read block of scanlines THEN bytesRead _ IO.UnsafeGetBlock[ input, unsafeBlock] ELSE { -- read from 3 files bytesRead _ IO.UnsafeGetBlock[ inputRed, unsafeBlock]; unsafeBlock.count _ blockSize; unsafeBlock.startIndex _ blockSize; bytesRead _ IO.UnsafeGetBlock[ inputGrn, unsafeBlock]; unsafeBlock.count _ blockSize; unsafeBlock.startIndex _ 2 * blockSize; bytesRead _ IO.UnsafeGetBlock[ inputBlu, unsafeBlock]; unsafeBlock.count _ blockSize; unsafeBlock.startIndex _ 0; }; FOR i: NAT IN [0..scanLinesPerBlock) DO IF codingType = typeDo THEN blockPtr _ -- already in Dorado 24-bit format unsafeBlock.base + i * wordsPerScanLine ELSE IF greenFile # NIL AND blueFile # NIL THEN { -- scanline sequential, reformat for Dorado rSrc, gSrc, bSrc, rDst, gDst, bDst: NAT; rSrc _ i * wordsPerScanLine * bytesPerWord; rDst _ 0; gSrc _ rSrc + blockSize; gDst _ rDst + 1; bSrc _ rSrc + 2*blockSize; bDst _ rDst + 2*pixelsPerScanline; FOR j: NAT IN [0..pixelsPerScanline) DO block2[rDst] _ block[rSrc]; rDst _ rDst + 2; rSrc _ rSrc + 1; block2[gDst] _ block[gSrc]; gDst _ gDst + 2; gSrc _ gSrc + 1; block2[bDst] _ block[bSrc]; bSrc _ bSrc + 1; bDst _ bDst + 1; ENDLOOP; blockPtr _ LOOPHOLE[block2, LONG POINTER] + SIZE[ByteSequence[0]]; } ELSE IF samplesPerPixel = 1 THEN blockPtr _ -- straightforward case unsafeBlock.base + i * wordsPerScanLine ELSE IF samplesPerPixel = 3 THEN { -- interleaved RGB, 3 samples per pixel rSrc, gSrc, bSrc, rDst, gDst, bDst: NAT; rSrc _ i * wordsPerScanLine * bytesPerWord; rDst _ 0; gSrc _ rSrc + 1; gDst _ rDst + 1; bSrc _ rSrc + 2; bDst _ rDst + 2*pixelsPerScanline; FOR j: NAT IN [0..pixelsPerScanline) DO block2[rDst] _ block[rSrc]; rDst _ rDst + 2; rSrc _ rSrc + 3; block2[gDst] _ block[gSrc]; gDst _ gDst + 2; gSrc _ gSrc + 3; block2[bDst] _ block[bSrc]; bDst _ bDst + 1; bSrc _ bSrc + 3; ENDLOOP; blockPtr _ LOOPHOLE[block2, LONG POINTER] + SIZE[ByteSequence[0]]; } ELSE IF samplesPerPixel = 4 THEN { ColorAISError[$InterleavedRGBalphaUnimplemented]; RETURN[]; }; IF scan >= 0 AND scan < scanCount THEN FOR j: NAT IN [0..MIN[2, displayData.numberOfSeparations]) DO -- get all 24-bits pxlIndex: CARDINAL _ MAX[0, -xOffset]; wndwIndex: CARDINAL _ MAX[0, xOffset]; ImagerPixelMapsExtras.LoadScanSeg[ displayData[j], clipper.sMin + scan, clipper.fMin + wndwIndex, MIN[clipper.fSize - wndwIndex, pixelsPerScanline - pxlIndex], blockPtr, pxlIndex + (j * 2*pixelsPerScanline) ]; ENDLOOP; scan _ scan + 1; ENDLOOP; ENDLOOP }; PutFastAISFile: PUBLIC PROC[context: Imager.Context, fileName: Rope.ROPE] ~ { PutFile[context, fileName, NIL, NIL, TRUE]; }; PutAISFile: PUBLIC PROC[context: Imager.Context, fileName: Rope.ROPE] ~ { PutFile[context, fileName, NIL, NIL, FALSE]; }; Put3AISFiles: PUBLIC PROC[context: Imager.Context, redFile, greenFile, blueFile: Rope.ROPE] ~ { PutFile[context, redFile, greenFile, blueFile, FALSE];}; PutFile: PROC[context: Imager.Context, fileName, greenFile, blueFile: Rope.ROPE, fast: BOOLEAN] ~ TRUSTED { displayData: DisplayData _ NARROW[ context.data, DisplayData]; -- get context info clipper: ImagerBasic.DeviceRectangle _ displayData.compositeClipper.first; output: ARRAY[0..3) OF IO.STREAM; numFiles: NAT _ 1; block: REF ByteSequence _ NEW[ByteSequence[maxBytesPerBlock]]; block2: REF ByteSequence _ NEW[ByteSequence[maxBytesPerBlock]]; header: REF AISHeader; raster: REF AISRasterDef; unsafeBlock: IO.UnsafeBlock; scan: INTEGER; scanCount, samplesPerByte, samplesPerPixel, wordsPerScanLine, pixelsPerScanline: NAT; scanLinesPerBlock: INTEGER; -- -1 means no blocking clipper.fMin _ clipper.fMin / displayData.displayClass.viewUnitsPerPixel; clipper.sMin _ clipper.sMin / displayData.displayClass.viewUnitsPerPixel; clipper.fSize _ clipper.fSize / displayData.displayClass.viewUnitsPerPixel; clipper.sSize _ clipper.sSize / displayData.displayClass.viewUnitsPerPixel; output[0] _ FS.StreamOpen[fileName, create]; IF (greenFile # NIL) AND (blueFile # NIL) THEN { output[1] _ FS.StreamOpen[greenFile, create]; output[2] _ FS.StreamOpen[blueFile, create]; numFiles _ 3; }; unsafeBlock.base _ LOOPHOLE[block, LONG POINTER] + SIZE[ByteSequence[0]]; unsafeBlock.startIndex _ 0; unsafeBlock.count _ 2048; FOR i: NAT IN [0..1024) DO block[i] _ 0; ENDLOOP; -- zero block for safety header _ LOOPHOLE[unsafeBlock.base, REF AISHeader]; -- look at block in AIS format raster _ LOOPHOLE[unsafeBlock.base + 3, REF AISRasterDef]; header.passWord _ aisPassword; header.length _ 1024; header.partHeader.type _ 1; header.partHeader.length _ 10; raster.scanCount _ displayData[0].sSize; -- scanCount raster.scanLength _ pixelsPerScanline _ displayData[0].fSize; -- scanLength raster.scanDir _ 3; -- scanDir (right-down) raster.samplesPerPixel _ samplesPerPixel _ -- samples/pixel IF (displayData.displayClass.displayType = $Std24bpp) AND (numFiles = 1) THEN 3 ELSE 1; raster.codingType _ IF fast AND (raster.samplesPerPixel = 3) THEN typeDo ELSE 1; -- coding type (UnCompressedArray) raster.bitsPerSample _ Basics.BITSHIFT[1, displayData[0].refRep.lgBitsPerPixel]; -- bits/sample raster.bitsPerSample _ MIN[8, raster.bitsPerSample]; samplesPerByte _ 8 / raster.bitsPerSample; raster.wordsPerScanLine _ wordsPerScanLine _ Ceiling[ -- words/ScanLine Real.Float[displayData[0].fSize * samplesPerPixel] / (bytesPerWord * samplesPerByte)]; LOOPHOLE[raster.scanLinesPerBlock, INTEGER] _ -1; -- ScanLines/block (unblocked) raster.paddingPerBlock _ 0; -- padding/block FOR i: NAT IN [0..numFiles) DO IO.UnsafePutBlock[ output[i], unsafeBlock]; -- write out block ENDLOOP; scan _ displayData[0].sMin; scanLinesPerBlock _ (maxBytesPerBlock * samplesPerByte / samplesPerPixel) / displayData[0].fSize; scanLinesPerBlock _ scanLinesPerBlock / numFiles; scanCount _ displayData[0].sSize + scan; unsafeBlock.startIndex _ 0; unsafeBlock.count _ scanLinesPerBlock * wordsPerScanLine * bytesPerWord; WHILE scan < scanCount DO -- write image bits FOR i: NAT IN [0..scanLinesPerBlock) DO IF scan < scanCount THEN { blockPtr: LONG POINTER _ IF displayData.displayClass.displayType = $Std24bpp AND NOT fast THEN LOOPHOLE[block2, LONG POINTER] + SIZE[ByteSequence[0]] ELSE LOOPHOLE[block, LONG POINTER] + i * wordsPerScanLine + SIZE[ByteSequence[0]]; FOR j: NAT IN [0..MIN[2, displayData.numberOfSeparations]) DO -- get all 24 bits ImagerPixelMapsExtras.StoreScanSeg[ -- store scanline in "blockPtr" displayData[j], scan, clipper.fMin, clipper.fSize, blockPtr, j * 2*pixelsPerScanline ]; ENDLOOP; IF (displayData.displayClass.displayType = $Std24bpp AND NOT fast ) AND (numFiles = 1) THEN { rSrc, gSrc, bSrc, rDst, gDst, bDst: NAT; rDst _ i * wordsPerScanLine * bytesPerWord; rSrc _ 0; gDst _ rDst + 1; gSrc _ rSrc + 1; bDst _ rDst + 2; bSrc _ rSrc + 2*pixelsPerScanline; FOR j: NAT IN [0..pixelsPerScanline) DO block[rDst] _ block2[rSrc]; rDst _ rDst + 3; rSrc _ rSrc + 2; block[gDst] _ block2[gSrc]; gDst _ gDst + 3; gSrc _ gSrc + 2; block[bDst] _ block2[bSrc]; bDst _ bDst + 3; bSrc _ bSrc + 1; ENDLOOP; } ELSE IF displayData.displayClass.displayType = $Std24bpp AND NOT fast THEN { rSrc, gSrc, bSrc, rDst, gDst, bDst: NAT; rDst _ i * wordsPerScanLine * bytesPerWord; rSrc _ 0; gDst _ rDst + unsafeBlock.count; gSrc _ rSrc + 1; bDst _ rDst + 2 * unsafeBlock.count; bSrc _ rSrc + 2*pixelsPerScanline; FOR j: NAT IN [0..pixelsPerScanline) DO block[rDst] _ block2[rSrc]; rSrc _ rSrc + 2; rDst _ rDst + 1; block[gDst] _ block2[gSrc]; gSrc _ gSrc + 2; gDst _ gDst + 1; block[bDst] _ block2[bSrc]; bDst _ bDst + 1; bSrc _ bSrc + 1; ENDLOOP; }; scan _ scan + 1; }; ENDLOOP; FOR j: NAT IN [0..numFiles) DO IO.UnsafePutBlock[ output[j], unsafeBlock]; -- write scanlines, unsafeBlock is really block unsafeBlock.startIndex _ unsafeBlock.startIndex + unsafeBlock.count; ENDLOOP; unsafeBlock.startIndex _ 0; ENDLOOP; FOR i: NAT IN [0..numFiles) DO IO.Close[output[i]]; -- flush all output and close file ENDLOOP; }; END. HImagerColorAISImpl.mesa Copyright c 1984 by Xerox Corporation. All rights reserved. Last Edited by: Crow, August 16, 1984 10:17:34 am PDT Last Edited by: Stone, August 15, 1984 7:09:46 pm PDT Adjust clipper to screen coordinates Read 1024 word file header and set up to read image Now go get the image bits set pointer to new bit location set pointer to new bit location Adjust clipper to screen coordinates Write 1024 word file header Now output the image itself Interleave RGB in one long file (untested) Output three files for color (compatible with longstanding default) ΚΧ˜Iheadšœ™šœ Οmœ1™˜YNšœ=˜=Nšœžœ˜!Nšœžœ&˜8Nšœ žœ˜.J˜Jš œžœžœ žœžœ˜3N˜—š Οnœžœ žœžœ žœ˜8J˜Jšžœžœ˜,J˜—J˜Jš  œžœžœ)žœ˜Fšœžœ ˜,Jšœžœžœ˜8J˜J˜—Jš  œžœžœ˜2Nšœ-žœ˜3šœžœ ˜/JšœB˜BJ˜J˜—Jš œžœ=žœ˜Qšœžœžœ˜2Nšœžœ Ÿ˜TNšœJ˜JNšœžœžœ˜*Nšœžœž˜(Nšœžœžœ!˜>Nšœžœžœ!˜?Nšœ žœžœ˜Nšœ žœ ˜Nšœ žœ˜Nšœžœ ˜Nšœžœ˜Nšœžœ˜Nšœ2žœ"žœ˜YNšœ:žœ˜>Nšœ žœ˜šœžœŸ˜;N™$—NšœI˜INšœI˜INšœK˜KšœK˜KIunitšŸ3™3—Nš œžœžœžœžœžœžœ˜MNšœ8Ÿ˜QNšœ žœ$ž˜3Ošœ žœžœ Ÿ˜RNšžœ!Ÿ˜4Nšžœ&žœ˜8šžœžœ Ÿ˜ENšœ ˜ Nšœ8˜8šžœ?žœ˜GNšœ.žœ˜<—Nšœ žœ$ž˜3N˜—Nšœ ˜ šžœžœŸ&˜KNšœ7˜7šžœCžœ˜NNšœ)žœ˜7—Nšœ žœžœ ˜;Nšž˜—Nšœ žœžœ˜BNšœ˜Nšœ+Ÿ˜AšžœžœŸ*˜KNšœ%žœ˜3—Nšœ)˜)Nšœ˜Nšœžœ*˜INšžœžœŸ$˜Sšžœ&žœ˜.Nšœ-žœ˜9Nšœ˜—Nšœ%˜%Nšœ#˜#Nšœ+˜+Nšžœ,Ÿ˜Cšžœ>Ÿ ˜LNšœ<˜žœžœ˜bNšœžœ˜ Nšœžœ Ÿ˜TNšœJ˜JNš œžœžœžœžœ˜!Nšœ žœ˜Nšœžœžœ!˜>Nšœžœžœ!˜?Nšœžœ ˜Nšœžœ˜Nšœ žœ ˜Nšœžœ˜NšœQžœ˜UšœžœŸ˜3N™$—NšœI˜INšœI˜INšœK˜KšœK˜KN˜—N˜Nšœ žœ˜,š žœžœžœ žœžœ˜0Nšœ žœ˜-Nšœ žœ˜,Nšœ ˜ Nšœ˜OšŸ™—Nš œžœžœžœžœ˜JNšœ˜Nšœ˜Nš žœžœžœ žœžœŸ˜MNšœ žœžœŸ˜SNšœ žœžœ˜:Nšœ˜Nšœ˜Nšœ˜Nšœ˜Nšœ+Ÿ˜Nšœžœ žœŸ%˜@Nšœžœ+Ÿ˜_Nšœžœ˜4Nšœ*˜*šœ;Ÿ˜INšœV˜V—NšžœžœŸ‘ΠciŸ˜QNšœ#Ÿ˜4šžœžœžœž˜Nšžœ-Ÿ˜BNšžœ˜OšŸ™—Nšœ˜NšœI˜INšœ˜Nšœ1˜1Nšœ(˜(Nšœ˜NšœH˜HšžœžœŸ˜5š žœžœžœžœžœžœ˜Dšœ žœžœ˜Nšžœ2žœžœ˜Ašžœ˜Nšžœ žœžœžœ˜6—šžœ˜Nšžœžœžœžœ˜M——š žœžœžœžœ&žœŸ˜Ršœ'Ÿ‘Ÿ˜FNšœ˜Nšœ˜Nšœ ˜ Nšœ˜Jšœ ˜ Jšœ˜Jšœ˜—Jšžœ˜NšŸ*™*—š žœ3žœžœžœžœ˜]Nšœ$žœ˜(Nšœ7˜7Nšœ2˜2Nšœ@˜@šžœžœžœž˜'NšœC˜CNšœA˜ANšœA˜A—Nšžœ˜ N˜NšŸC™C—š žœžœ2žœžœžœ˜LNšœ$žœ˜(Nšœ6˜6Nšœ7˜7NšœK˜Kšžœžœžœž˜'NšœE˜ENšœC˜CNšœC˜C—Nšžœ˜ Nšœ˜—Nšœ˜Nšœ˜Nšžœ˜—šžœžœžœž˜Nšžœ*Ÿ/˜[NšœD˜DNšžœ˜—Nšœ˜Nšž˜—šžœžœžœž˜NšžœŸ"˜;Nšžœ˜—Nšœ˜J˜—Jšžœ˜—…—8θJ