DIRECTORY AIS, Basics, Commander, FS, IO, RefText, Rope; FrameBufferReader: CEDAR PROGRAM IMPORTS AIS, Basics, Commander, FS, IO, RefText, Rope = BEGIN ROPE: TYPE ~ Rope.ROPE; Pixel: TYPE = [0..256); BufferRep: TYPE ~ PACKED ARRAY [0..1024) OF Pixel; LucasfilmMagicNumber: INT ~ 0164200B; LucasfilmHeader: TYPE = REF LucasfilmHeaderRec; LucasfilmHeaderRec: TYPE = RECORD [ magicNumber: INT, version: INTEGER, label: ROPE, pictureHeight: INTEGER, pictureWidth: INTEGER, tileHeight: INTEGER, tileWidth: INTEGER, pictureFormat: {A, B, BA, G, GA, GB, GBA, R, RA, RB, RBA, RG, RGA, RGB, RGBA}, pictureStorage: {encoded8bit, encoded12bit, dumped8bit, dumped12bit, encoded11bit, dumped11bit}, blockingFactor: INTEGER, alphaMode: {mattedToBlack, unassociated}, xOffset: INTEGER, yOffset: INTEGER, colorMapPointer: INT, colorMapFileName: ROPE]; CreateAISFilesFromFrameBufferImage: Commander.CommandProc ~ { CreateAISFiles[cmd: cmd, upsideDown: FALSE]; }; CreateAISFilesFromUofTFrameBufferImage: Commander.CommandProc ~ { CreateAISFiles[cmd: cmd, upsideDown: TRUE]; }; CreateAISFiles: PROC [cmd: Commander.Handle, upsideDown: BOOLEAN _ FALSE] ~ { fileName: ROPE _ IO.GetTokenRope[IO.RIS[cmd.commandLine], IO.IDProc].token; inputStream: IO.STREAM _ FS.StreamOpen[fileName]; comment: ROPE _ GetComment[inputStream]; cmd.out.PutRope[comment]; IF comment.Length > 256 THEN comment _ Rope.Cat[comment.Substr[0, 251], "...\n"]; { fullFileName: ROPE; cp: FS.ComponentPositions; fileNameStem: ROPE; [fullFileName, cp] _ FS.ExpandName[fileName]; fileNameStem _ fullFileName.Substr[cp.base.start, cp.base.length]; cmd.out.PutRope["\nStarting red"]; DoAISSeparation[inputStream, fileNameStem.Concat["-red.AIS"], comment, upsideDown]; cmd.out.PutRope["\nStarting green"]; DoAISSeparation[inputStream, fileNameStem.Concat["-green.AIS"], comment, upsideDown]; cmd.out.PutRope["\nStarting blue"]; DoAISSeparation[inputStream, fileNameStem.Concat["-blue.AIS"], comment, upsideDown]; cmd.out.PutRope[". . . Done\n"] }; }; GetComment: PROC [stream: IO.STREAM] RETURNS [line: ROPE] ~ { streamLength: INT _ stream.GetLength[]; rgbFrameBufferSize: INT ~ LONG[512]*LONG[512]*LONG[3]; commentLength: INT _ IF streamLength > rgbFrameBufferSize THEN streamLength-rgbFrameBufferSize ELSE streamLength MOD 512; buffer: REF TEXT = RefText.ObtainScratch[commentLength]; { ENABLE UNWIND => RefText.ReleaseScratch[buffer]; [] _ IO.GetBlock[stream, buffer, 0, commentLength]; line _ Rope.FromRefText[buffer]; }; RefText.ReleaseScratch[buffer]; FOR i: INT _ line.Find["\l"], line.Find["\l"] UNTIL i < 0 DO line _ line.Replace[i, 1, "\n"]; ENDLOOP; RETURN [line]; }; DoAISSeparation: PROC [s: IO.STREAM, aisFileName: ROPE, comment: ROPE, upsideDown: BOOLEAN _ FALSE] ~ TRUSTED { ais: AIS.FRef _ AIS.CreateFile[ name: aisFileName, raster: NEW[AIS.RasterPart _ [ scanCount: 512, scanLength: 512, scanMode: rd, bitsPerPixel: 8, linesPerBlock: -1, paddingPerBlock: 0]], attributeLength: 1]; window: AIS.WRef _ AIS.OpenWindow[ais]; BufferRep: TYPE ~ PACKED ARRAY [0..512) OF [0..256); buffer: REF BufferRep _ NEW[BufferRep]; bufferDesc: AIS.Buffer _ [length: 512, addr: BASE[buffer^]]; AIS.WriteComment[ais, comment]; FOR i: NAT IN [0..512) DO [] _ s.UnsafeGetBlock[block: [base: LOOPHOLE[bufferDesc.addr], startIndex: 0, count: 512]]; AIS.UnsafeWriteLine[window, bufferDesc, IF upsideDown THEN 512-i-1 ELSE i]; ENDLOOP; AIS.CloseFile[ais]; }; CreateAISFilesFromLucasfilmImage: Commander.CommandProc ~ { fileName: ROPE _ IO.GetTokenRope[IO.RIS[cmd.commandLine], IO.IDProc ! IO.Error => GOTO NoFileName].token; inputStream: IO.STREAM _ FS.StreamOpen[fileName]; header: LucasfilmHeader _ GetLucasfilmHeader[inputStream]; cmd.out.PutRope[header.label]; IF header.label.Length > 256 THEN header.label _ Rope.Cat[header.label.Substr[0, 251], "...\n"]; { fullFileName: ROPE; cp: FS.ComponentPositions; fileNameStem: ROPE; [fullFileName, cp] _ FS.ExpandName[fileName]; fileNameStem _ fullFileName.Substr[cp.base.start, cp.base.length]; DoLucasfilmFormatSeparations[inputStream, fileNameStem, header]; }; EXITS NoFileName => RETURN [$failure, "No filename given for frame buffer image"]; }; DoLucasfilmFormatSeparations: PROC [s: IO.STREAM, aisFileNameRoot: ROPE, h: LucasfilmHeader] ~ TRUSTED { aisRed: AIS.FRef _ AIS.CreateFile[ name: aisFileNameRoot.Concat["-red.AIS"], raster: NEW[AIS.RasterPart _ [ scanCount: h.pictureHeight, scanLength: h.pictureWidth, scanMode: rd, bitsPerPixel: 8, linesPerBlock: -1, paddingPerBlock: 0]], attributeLength: 1]; aisGreen: AIS.FRef _ AIS.CreateFile[ name: aisFileNameRoot.Concat["-green.AIS"], raster: NEW[AIS.RasterPart _ [ scanCount: h.pictureHeight, scanLength: h.pictureWidth, scanMode: rd, bitsPerPixel: 8, linesPerBlock: -1, paddingPerBlock: 0]], attributeLength: 1]; aisBlue: AIS.FRef _ AIS.CreateFile[ name: aisFileNameRoot.Concat["-blue.AIS"], raster: NEW[AIS.RasterPart _ [ scanCount: h.pictureHeight, scanLength: h.pictureWidth, scanMode: rd, bitsPerPixel: 8, linesPerBlock: -1, paddingPerBlock: 0]], attributeLength: 1]; windowRed: AIS.WRef _ AIS.OpenWindow[aisRed]; windowGreen: AIS.WRef _ AIS.OpenWindow[aisGreen]; windowBlue: AIS.WRef _ AIS.OpenWindow[aisBlue]; bufferRed: REF BufferRep _ NEW[BufferRep]; bufferGreen: REF BufferRep _ NEW[BufferRep]; bufferBlue: REF BufferRep _ NEW[BufferRep]; bufferDescRed: AIS.Buffer _ [length: h.pictureWidth, addr: BASE[bufferRed^]]; bufferDescGreen: AIS.Buffer _ [length: h.pictureWidth, addr: BASE[bufferGreen^]]; bufferDescBlue: AIS.Buffer _ [length: h.pictureWidth, addr: BASE[bufferBlue^]]; AIS.WriteComment[aisRed, h.label]; AIS.WriteComment[aisGreen, h.label]; AIS.WriteComment[aisBlue, h.label]; FOR scanLine: NAT IN [0..h.pictureHeight) DO ExtractLucasfilmScanLine[s, h, bufferRed, bufferGreen, bufferBlue]; AIS.UnsafeWriteLine[windowRed, bufferDescRed, scanLine]; AIS.UnsafeWriteLine[windowGreen, bufferDescGreen, scanLine]; AIS.UnsafeWriteLine[windowBlue, bufferDescBlue, scanLine]; ENDLOOP; AIS.CloseFile[aisRed]; AIS.CloseFile[aisGreen]; AIS.CloseFile[aisBlue]; }; ExtractLucasfilmScanLine: PROC [s: IO.STREAM, h: LucasfilmHeader, bufferRed, bufferGreen, bufferBlue: REF BufferRep] ~ { SELECT h.pictureStorage FROM dumped8bit => { SELECT h.pictureFormat FROM RGB => { FOR pixel: NAT IN [0..h.pictureWidth) DO bufferRed[pixel] _ LOOPHOLE[s.GetChar[]]; bufferGreen[pixel] _ LOOPHOLE[s.GetChar[]]; bufferBlue[pixel] _ LOOPHOLE[s.GetChar[]]; ENDLOOP; }; ENDCASE => ERROR; }; encoded8bit => { SELECT h.pictureFormat FROM RGB => { i: NAT _ 0; WHILE i < h.pictureWidth DO inCaseOfErrorRememberIndex: INT _ s.GetIndex[]; byte1: CARDINAL _ LOOPHOLE[s.GetChar[]]; byte2: CARDINAL _ LOOPHOLE[s.GetChar[]]; flag: INT _ Basics.BITSHIFT[byte1, -4]; -- flag <0:4> pixelCount: INT _ Basics.BITOR[Basics.BITSHIFT[Basics.BITAND[byte1, 17B], 8], byte2]; -- count <8:11> count <0:7> SELECT flag FROM 0 => LOOP; -- end of disk block 1 => ERROR; -- full channel dump 2 => { THROUGH [0..pixelCount] DO length: CARDINAL _ LOOPHOLE[s.GetChar[]]; redPixel: Pixel _ LOOPHOLE[s.GetChar[]]; greenPixel: Pixel _ LOOPHOLE[s.GetChar[]]; bluePixel: Pixel _ LOOPHOLE[s.GetChar[]]; THROUGH [0..length] DO bufferRed[i] _ redPixel; bufferGreen[i] _ greenPixel; bufferBlue[i] _ bluePixel; i _ i + 1; ENDLOOP; ENDLOOP; }; ENDCASE => ERROR; ENDLOOP; IF i # h.pictureWidth THEN ERROR; }; ENDCASE => ERROR; }; ENDCASE => ERROR; }; GetLucasfilmHeader: PROC [s: IO.STREAM] RETURNS [h: LucasfilmHeader _ NEW[LucasfilmHeaderRec]] ~ { i: NAT; FourBytes: PROC [s: IO.STREAM] RETURNS [INT] ~ TRUSTED { n: Basics.LongNumber; n.ll _ LOOPHOLE[s.GetChar[]]; n.lh _ LOOPHOLE[s.GetChar[]]; n.hl _ LOOPHOLE[s.GetChar[]]; n.hh _ LOOPHOLE[s.GetChar[]]; RETURN [n.li] }; TwoBytes: PROC [s: IO.STREAM] RETURNS [INTEGER] ~ TRUSTED { n: Basics.LongNumber; n.ll _ LOOPHOLE[s.GetChar[]]; n.lh _ LOOPHOLE[s.GetChar[]]; RETURN [n.lowbits] }; h.magicNumber _ FourBytes[s]; IF h.magicNumber # LucasfilmMagicNumber THEN ERROR; h.version _ TwoBytes[s]; h.label _ NIL; THROUGH [0..246) DO h.label _ Rope.Concat[h.label, Rope.FromChar[s.GetChar[]]]; ENDLOOP; FOR i DECREASING IN [0..246) WHILE h.label.Fetch[i] = '\000 DO ENDLOOP; h.label _ Rope.Substr[h.label, 0, i]; s.SetIndex[416]; h.pictureHeight _ TwoBytes[s]; h.pictureWidth _ TwoBytes[s]; h.tileHeight _ TwoBytes[s]; h.tileWidth _ TwoBytes[s]; IF h.pictureHeight # h.tileHeight OR h.pictureWidth # h.tileWidth THEN ERROR; h.pictureFormat _ SELECT TwoBytes[s] FROM 1B => A, 2B => B, 3B => BA, 4B => G, 5B => GA, 6B => GB, 7B => GBA, 10B => R, 11B => RA, 12B => RB, 13B => RBA, 14B => RG, 15B => RGA, 16B => RGB, 17B => RGBA, ENDCASE => RGBA; IF h.pictureFormat # RGB THEN ERROR; h.pictureStorage _ SELECT TwoBytes[s] FROM 0 => encoded8bit, 1 => encoded12bit, 2 => dumped8bit, 3 => dumped12bit, 4 => encoded11bit, 5 => dumped11bit, ENDCASE => encoded8bit; IF h.pictureStorage # dumped8bit AND h.pictureStorage # encoded8bit THEN ERROR; h.blockingFactor _ TwoBytes[s]; h.alphaMode _ IF TwoBytes[s] = 0 THEN mattedToBlack ELSE unassociated; h.xOffset _ TwoBytes[s]; h.yOffset _ TwoBytes[s]; IF h.xOffset # 0 OR h.yOffset # 0 THEN ERROR; s.SetIndex[h.blockingFactor]; }; GSLHeader: TYPE ~ REF GSLHeaderRec; GSLHeaderRec: TYPE ~ RECORD[ label: ROPE, rows: INTEGER, columns: INTEGER, pictureHeight: INTEGER, pictureWidth: INTEGER]; CreateAISFilesFromGSLImage: Commander.CommandProc ~ { fileName: ROPE _ IO.GetTokenRope[IO.RIS[cmd.commandLine], IO.IDProc ! IO.Error => GOTO NoFileName].token; inputStream: IO.STREAM _ FS.StreamOpen[fileName]; header: GSLHeader _ GetGSLHeader[inputStream]; cmd.out.PutRope[header.label]; IF header.label.Length > 256 THEN header.label _ Rope.Cat[header.label.Substr[0, 251], "...\n"]; { fullFileName: ROPE; cp: FS.ComponentPositions; fileNameStem: ROPE; [fullFileName, cp] _ FS.ExpandName[fileName]; fileNameStem _ fullFileName.Substr[cp.base.start, cp.base.length]; DoGSLFormatConversion[inputStream, fileNameStem, header]; }; EXITS NoFileName => RETURN [$failure, "No filename given for frame buffer image"]; }; GetGSLHeader: PROC [s: IO.STREAM] RETURNS [h: GSLHeader _ NEW[GSLHeaderRec]] ~ { FourBytes: PROC [s: IO.STREAM] RETURNS [INT] ~ TRUSTED { n: Basics.LongNumber; n.ll _ LOOPHOLE[s.GetChar[]]; n.lh _ LOOPHOLE[s.GetChar[]]; n.hl _ LOOPHOLE[s.GetChar[]]; n.hh _ LOOPHOLE[s.GetChar[]]; RETURN [n.li] }; TwoBytes: PROC [s: IO.STREAM] RETURNS [INTEGER] ~ TRUSTED { n: Basics.LongNumber; n.ll _ LOOPHOLE[s.GetChar[]]; n.lh _ LOOPHOLE[s.GetChar[]]; RETURN [n.lowbits] }; [] _ TwoBytes[s]; -- record separator h.label _ NIL; h.rows _ FourBytes[s]; h.columns _ FourBytes[s]; h.pictureHeight _ FourBytes[s]; h.pictureWidth _ FourBytes[s]; IF h.pictureWidth MOD 2 = 1 THEN h.pictureWidth _ h.pictureWidth - 1; }; DoGSLFormatConversion: PROC [s: IO.STREAM, aisFileNameRoot: ROPE, h: GSLHeader] ~ TRUSTED { ais: AIS.FRef _ AIS.CreateFile[ name: aisFileNameRoot.Concat[".ais"], raster: NEW[AIS.RasterPart _ [ scanCount: h.pictureHeight, scanLength: h.pictureWidth, scanMode: rd, bitsPerPixel: 8, linesPerBlock: -1, paddingPerBlock: 0]], attributeLength: 1]; window: AIS.WRef _ AIS.OpenWindow[ais]; buffer: REF BufferRep _ NEW[BufferRep]; bufferDesc: AIS.Buffer _ [length: h.pictureWidth, addr: BASE[buffer^]]; AIS.WriteComment[ais, h.label]; FOR scanLine: NAT IN [0..h.pictureHeight) DO ExtractGSLScanLine[s, h, buffer]; AIS.UnsafeWriteLine[window, bufferDesc, scanLine]; ENDLOOP; AIS.CloseFile[ais]; }; ExtractGSLScanLine: PROC [s: IO.STREAM, h: GSLHeader, buffer: REF BufferRep] ~ { TwoBytes: PROC [s: IO.STREAM] RETURNS [INTEGER] ~ TRUSTED { n: Basics.LongNumber; n.ll _ LOOPHOLE[s.GetChar[]]; n.lh _ LOOPHOLE[s.GetChar[]]; RETURN [n.lowbits] }; ByteValue: PROC [s: IO.STREAM] RETURNS [INTEGER] ~ TRUSTED { n: Basics.LongNumber; n.ll _ LOOPHOLE[s.GetChar[]]; n.lh _ 0; n.lowbits _ IF n.lowbits >= 128 THEN n.lowbits - 128 ELSE n.lowbits + 128; RETURN [n.lowbits] }; [] _ TwoBytes[s]; FOR i:NAT IN [0..h.columns) DO buffer[i] _ ByteValue[s]; ENDLOOP; FOR i: NAT IN [h.columns .. h.pictureWidth) DO buffer[i] _ buffer[i MOD h.columns]; ENDLOOP; }; Commander.Register[key: "ReadFrameBuffer", proc: CreateAISFilesFromFrameBufferImage, doc: "ReadFrameBuffer framebufferimagefilename.rgb reads a 512x512 image into 3 color AIS files"]; Commander.Register[key: "ReadUofTFrameBuffer", proc: CreateAISFilesFromUofTFrameBufferImage, doc: "ReadUofTFrameBuffer framebufferimagefilename.rgb reads a 512x512 image into 3 color AIS files"]; Commander.Register[key: "ReadLucasfilm", proc: CreateAISFilesFromLucasfilmImage, doc: "ReadLucasfilm framebufferimagefilename.rgb reads a frame buffer image into 3 (or 4 if alpha) color AIS files. See [Indigo]Entries>84CSLN-0016.Tioga for details on the frame buffer image format."]; Commander.Register[key: "ReadGSLImage", proc: CreateAISFilesFromGSLImage, doc: "ReadGSLImage imagefilename.wpo reads an image into an AIS file. See Mike Okeefe or Fernando Ponce for details on the file format."]; END. nFrameBufferReader.Mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Created by Rick Beach, March 2, 1985 1:30:58 pm PST If the comment is longer than 256 characters (an AIS file format limitation) then truncate it with an ellipsis. Similar to IO.GetLineRope, but uses knowledge about the framebuffer image file to determine how long the comment is in the frame buffer image. If the comment is longer than 256 characters (an AIS file format limitation) then truncate it with an ellipsis. If the comment is longer than 256 characters (an AIS file format limitation) then truncate it with an ellipsis. ÊE˜™J™