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];
~
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];
IO.Backup[stream, 0C];
};
ToPixelArray:
PUBLIC
PROC [fileName:
ROPE]
RETURNS [pa: PixelArray] ~ {
Read the given Macintosh PICT-format file and return a PixelArray with its contents.
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;
};