<> <> <> <> <<>> DIRECTORY AIS USING [Buffer, CloseFile, CreateFile, FRef, OpenWindow, RasterPart, UnsafeWriteLine, WRef, WriteComment], Basics USING [BITAND, BITOR, BITSHIFT, LongNumber], Commander USING [CommandProc, Handle, Register], FS USING [ComponentPositions, Error, ExpandName, StreamOpen], IO USING [Error, GetBlock, GetChar, GetIndex, GetLength, GetTokenRope, IDProc, PutRope, RIS, SetIndex, STREAM, UnsafeGetBlock], RefText USING [ObtainScratch, ReleaseScratch], Rope USING [Cat, Concat, Fetch, Find, FromChar, FromRefText, Length, Replace, ROPE, Substr]; FrameBufferReaderImpl: 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; <> <> <> CreateAISFilesFromSimpleFormat: PROC [cmd: Commander.Handle, upsideDown: BOOLEAN _ FALSE] RETURNS [result: REF _ NIL, msg: ROPE _ NIL] ~ { fileName: ROPE _ IO.GetTokenRope[IO.RIS[cmd.commandLine], IO.IDProc].token; inputStream: IO.STREAM _ FS.StreamOpen[fileName ! FS.Error => {result _ $Failure; msg _ error.explanation; GO TO FileProblem}]; 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"] }; EXITS FileProblem => NULL; }; 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]; }; <> <Entries>84CSLN-0016.tioga>> <> <<>> 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]; 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 => { -- end of disk block index: INT ~ s.GetIndex[]; blockSize: INT ~ h.blockingFactor; blockNumber: INT ~ index/blockSize; blockStart: INT ~ blockNumber*blockSize; IF index#blockStart THEN s.SetIndex[blockStart+blockSize]; LOOP; }; 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]; 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]; }; 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; }; 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; }; <> ReadFrameBufferCmdProc: Commander.CommandProc ~ { [result, msg] _ CreateAISFilesFromSimpleFormat[cmd: cmd, upsideDown: FALSE]; }; ReadFrameBufferBottomUpCmdProc: Commander.CommandProc ~ { [result, msg] _ CreateAISFilesFromSimpleFormat[cmd: cmd, upsideDown: TRUE]; }; ReadLucasfilmCmdProc: 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"]; }; ReadGSLImageCmdProc: 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"]; }; Commander.Register[key: "ReadFrameBuffer", proc: ReadFrameBufferCmdProc, doc: "ReadFrameBuffer framebufferimagefilename.rgb reads a 512x512 image into 3 color AIS files"]; Commander.Register[key: "ReadFrameBufferBottomUp", proc: ReadFrameBufferBottomUpCmdProc, doc: "ReadFrameBufferBottomUp framebufferimagefilename.rgb reads a 512x512 image into 3 color AIS files"]; Commander.Register[key: "ReadLucasfilm", proc: ReadLucasfilmCmdProc, 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: ReadGSLImageCmdProc, doc: "ReadGSLImage imagefilename.wpo reads an image into an AIS file. See Mike Okeefe or Fernando Ponce for details on the file format."]; END.