<<>> <> <> <> <<>> <> <<>> DIRECTORY FS USING [StreamOpen], ImagerPixel USING [MakePixelMap], ImagerPixelArray USING [Join3, FromPixelMap, PixelArray], ImagerSample USING [Fill, NewSampleMap, Put, RasterSampleMap], IO USING [Close, GetChar, SetIndex, GetIndex, STREAM, EndOfStream], MacPICT, Rope USING [ROPE]; MacPICTImpl: CEDAR PROGRAM IMPORTS FS, ImagerPixel, ImagerPixelArray, ImagerSample, IO EXPORTS MacPICT ~ BEGIN PixelArray: TYPE ~ ImagerPixelArray.PixelArray; RasterSampleMap: TYPE ~ ImagerSample.RasterSampleMap; ROPE: TYPE ~ Rope.ROPE; STREAM: TYPE ~ IO.STREAM; picHigh, picWide: INTEGER; rectTop, rectLeft, rectBottom, rectRight: CARDINAL; dstTop, dstLeft, dstBottom, dstRight: CARDINAL; rowBytes: CARDINAL; small: BOOL ¬ FALSE; smRed, smGreen, smBlue: RasterSampleMap ¬ NIL; clutRed, clutGreen, clutBlue: ARRAY [0..256) OF [0..256); GetByte: PROC [stream: STREAM] RETURNS [BYTE] ~ { RETURN [stream.GetChar[] - 0C] }; GetWord: PROC [stream: STREAM] RETURNS [CARDINAL] ~ { RETURN [(stream.GetChar[] - 0C) * 100H + (stream.GetChar[] - 0C)] }; SkipWord: PROC [stream: STREAM, count: CARDINAL] ~ { FOR i: CARDINAL IN [0..count) DO dummy: CARDINAL ¬ GetWord[stream]; ENDLOOP; }; ReadPixMap: PROC [stream: STREAM] ~ { rowBytes ¬ GetWord[stream]; rowBytes ¬ rowBytes - 8000H; IF rowBytes > 250 THEN small ¬ FALSE ELSE small ¬ TRUE; SkipWord[stream, 22]; -- ignore remaining part }; ReadColorTable: PROC [stream: STREAM] ~ { SkipWord[stream, 3]; -- ignore ctSeed and ctFlags FOR i: CARDINAL IN [0 .. GetWord[stream]] DO SkipWord[stream, 1]; clutRed[i] ¬ GetWord[stream] / 256; clutGreen[i] ¬ GetWord[stream] / 256; clutBlue[i] ¬ GetWord[stream] / 256; ENDLOOP; }; ReadDstRect: PROC [stream: STREAM] ~ { dstTop ¬ GetWord[stream]; dstLeft ¬ GetWord[stream]; dstBottom ¬ GetWord[stream]; dstRight ¬ GetWord[stream]; }; ReadPixData: PROC [stream: STREAM] ~ { colBytes, col: CARDINAL ¬ 0; scolBytes: BYTE ¬ 0; pos: LONG CARDINAL ¬ 0; FOR row: CARDINAL IN [dstTop .. dstBottom) DO IF small THEN scolBytes ¬ GetByte[stream] ELSE colBytes ¬ GetWord[stream]; -- dummy col ¬ dstLeft; WHILE col < rowBytes DO count: BYTE ~ GetByte[stream]; SELECT count FROM 80H => NULL; -- -128 ignored for backward compatibility > 80H => { -- -1..-127 => replicate next byte 2..128 times n: CARDINAL ¬ 101H - count; m: CARDINAL ¬ n; data: BYTE ~ GetByte[stream]; IF col + n > dstRight THEN n ¬ dstRight - col; ImagerSample.Fill[map: smRed, box: [[row, col], [row + 1, col + n]], value: clutRed[data]]; ImagerSample.Fill[map: smGreen, box: [[row, col], [row + 1, col + n]], value: clutGreen[data]]; ImagerSample.Fill[map: smBlue, box: [[row, col], [row + 1, col + n]], value: clutBlue[data]]; col ¬ col + m; }; ENDCASE => { -- 0..127 => copy 1..128 bytes uncompressed FOR i: CARDINAL IN [col .. col + count] DO data: BYTE ~ GetByte[stream]; IF i < dstRight THEN { ImagerSample.Put[map: smRed, index: [row, i], value: clutRed[data]]; ImagerSample.Put[map: smGreen, index: [row, i], value: clutGreen[data]]; ImagerSample.Put[map: smBlue, index: [row, i], value: clutBlue[data]]; }; ENDLOOP; col ¬ col + count + 1; }; ENDLOOP; IF col > rowBytes THEN ERROR; ENDLOOP; pos ¬ IO.GetIndex[stream]; IF pos MOD 2 ~= 0 THEN IO.SetIndex[stream, pos+1]; <> }; ToPixelArray: PUBLIC PROC [fileName: ROPE] RETURNS [pa: PixelArray] ~ { <> invalidVersion: PUBLIC ERROR = CODE; unsupportedOpCode: PUBLIC ERROR = CODE; opCode: CARDINAL; stream: STREAM ~ FS.StreamOpen[fileName]; IO.SetIndex[stream, 512]; -- skip header SkipWord[stream, 1]; -- ignore picSize rectTop ¬ GetWord[stream]; rectLeft ¬ GetWord[stream]; rectBottom ¬ GetWord[stream]; rectRight ¬ GetWord[stream]; picHigh ¬ rectBottom - rectTop; picWide ¬ rectRight - rectLeft; smRed ¬ ImagerSample.NewSampleMap[[max: [picHigh, picWide]], 8]; smGreen ¬ ImagerSample.NewSampleMap[[max: [picHigh, picWide]], 8]; smBlue ¬ ImagerSample.NewSampleMap[[max: [picHigh, picWide]], 8]; opCode ¬ GetWord[stream]; WHILE opCode ~= 00FFH DO SELECT opCode FROM 0000H => NULL; -- Nop 0001H => SkipWord[stream, 5]; -- ignore Clip operation 0011H => -- Version IF GetWord[stream] ~= 02FFH THEN ERROR invalidVersion; 001BH => SkipWord[stream, 3]; -- ignore RGBBkColor 001EH => NULL; -- do nothing for DefHilite 001FH => SkipWord[stream, 3]; -- ignore OpColor 0098H => { ReadPixMap[stream]; ReadColorTable[stream]; SkipWord[stream, 4]; -- ignore srcRect ReadDstRect[stream]; SkipWord[stream, 1]; -- ignore dstRect.Bottom,Right and mode ReadPixData[stream]; }; 0099H => { ReadPixMap[stream]; ReadColorTable[stream]; SkipWord[stream, 4]; -- ignore srcRect ReadDstRect[stream]; SkipWord[stream, 1]; -- ignore dstRect.Bottom,Right and mode SkipWord[stream, 5]; -- (GetWord[stream] - 10 + 4)]; ignore maskRgn ReadPixData[stream]; }; 00A0H => SkipWord[stream, 1]; -- ShortComment 0C00H => SkipWord[stream, 12]; -- ignore HeaderOp ENDCASE => ERROR unsupportedOpCode; opCode ¬ GetWord[stream ! IO.EndOfStream => EXIT;]; ENDLOOP; stream.Close[]; <<>> pa ¬ ImagerPixelArray.Join3[ImagerPixelArray.FromPixelMap[ pixelMap: ImagerPixel.MakePixelMap[smRed], box: [max: [picHigh, picWide]], scanMode: [down, right], immutable: FALSE], ImagerPixelArray.FromPixelMap[ pixelMap: ImagerPixel.MakePixelMap[smGreen], box: [max: [picHigh, picWide]], scanMode: [down, right], immutable: FALSE], ImagerPixelArray.FromPixelMap[ pixelMap: ImagerPixel.MakePixelMap[smBlue], box: [max: [picHigh, picWide]], scanMode: [down, right], immutable: FALSE]]; smRed ¬ NIL; smGreen ¬ NIL; smBlue ¬ NIL; }; <<>> END.