[net.micro.apple] MacPaint Document Format

e-smith@utah-cs.UUCP (Eric Smith) (07/17/84)

The following material spontaneously evolved from a mudpuddle
(amazing, isn't it?)
---------------------------------------------------------------------
The MacPaint Document Format
By Bill Atkinson

MacPaint documents are easy to read and write, and have become a
standard interchange format for full-page bitmap images on Macintosh.
Their internal format is described here to aid program developers in
generating and reading MacPaint documents.

MacPaint documents use only the data fork of the file system; the resource
fork is not used and may be ignored.  The data fork contains a 512 byte
header and then the compressed data representing a single bitmap of 576
pixels wide by 720 pixels tall.  At 72 pixels per inch, this bitmap occupies
the full 8 by 10 inch printable area of the Imagewriter printeg page.

HEADER:

The first 512 bytes of the document form a header with a 4 byte version
number (default = 2), then 38*8 = 304 bytes of patterns, then 204 unused
bytes reserved for future expansion.  If the version number is zero, the
rest of the header block is ignored and default patterns are used, so
programs generating MacPaint documents can simply write out 512 bytes
of zero as the document header.  Most programs which read MacPaint
documents can simply skip over the header when reading.

BITMAP:

Following the header are 720 compressed scanlines of data which form the
576 wide by 720 tall bitmap.  Without compression, this bitmap would
occupy 51840 bytes and chew up disk space pretty fast; typical MacPaint
documents compress to about 10 Kbytes using the PackBits procedure in
the Macintosh ROM to compress runs of equal bytes within each scanline.
The bitmap part of a MacPaint document is simply 720 times the output of
PackBits with 72 bytes input.

READING SAMPLE:

CONST srcBlocks = 2; { at least 2, bigger makes it faster }
      srcSize = 1024; { 512 * srcBlocks }
TYPE diskBlock = PACKED ARRAY[1..512] of QDByte;
VAR srcBuf: ARRAY[1..srcBlocks] of diskBlock;
    srcPtr,dstPtr: QDPtr;

{ skip the header }
ReadData(srcFile,@srcBuf,512);

{ prime srcBuf}
ReadData(srcFile,@srcBuf,srcSize);

{ unpack each scanline into dstBits, reading more source as needed }
srcPtr := @srcBuf;
dstPtr := dstBits.baseAddr;
FOR scanLine := 1 to 720 DO
  BEGIN
    UnPackBits(srcPtr,dstPtr,72);  { bumps both ptrs }
    { time to read next chunck of packed source? }
    IF ORD(srcPtr) > ORD(@srcBuf) + srcSize - 512 THEN
      BEGIN
        srcBuf[1] := srcBuf[srcBlocks];  { move up last block }
        ReadData(srcFile,@srcBuf[2],srcSize-512);
        srcPtr := Pointer(ORD(srcPtr) - srcSize + 512);
      END;
  END;

WRITING SAMPLE:

To write out a 576 by 720 bitmap which is contained in memory, the
following fragment of code could be used:

TYPE diskBlock = PACKED ARRAY[1..512] OF QDByte;
VAR srcPtr,dstPtr: QDPtr;
    dstBuf: diskBlock;
    dstBytes: INTEGER;

{ write the header, all zeros }
FOR i := 1 TO 512 DO dstBuf[i] := 0;
WriteData(dstFile,@dstBuf,512);

{ Compress each scanline and write it }
srcPtr := srcBits.baseAddr;
FOR scanLine := 1 TO 720 DO
  BEGIN
    dstPtr := @ dstBuf;
    PackBits(srcPtr,dstPtr,72);  { bumps both ptrs }
    dstBytes := ORD(dstPtr) - ORD(@dstBuf);  { calc packed size }
    WriteData(dstFile,@dstBuf,dstBytes);  { write packed data }
  END;

----------------------------------------------------------------------

This will probably only help you if you have Inside Macintosh; even
then, the PackBits and UnpackBits calls to QuickDraw are currently
not documented (the above code shows how to call them from Lisa
Pascal, by referring to the IM chapter "Assembly Language" you could
figure out how to call them from assembly code).

To read MacPaint documents from BASIC, you would probably either need
to figure out what PackBits and UnpackBits do, or write an interface
routine in assembly and poke it into memory.

Inside Macintosh is a two volume set (in two LARGE three ring binders)
which describes all but 37 of the traps to the Macintosh ROM, which
includes the OS, the user interface toolkit, and QuickDraw.

Also available (and necessary for program development) is the
"Macintosh Software Supplement to the Lisa Pascal Workshop 2.0" which includes
2 disks of Macintosh example programs and utilities (including the
resource mover, alert/dialog editor, font editor, icon editor, etc.),
1 MacWorks disk to allow you to run most Macintosh software on the Lisa,
1 MacWorks disk with the LisaBug debugger, and 4 disks full of the actual
Lisa software you need to develop Macintosh applications (you still need to
get the Lisa Pascal Workshop 2.0; this is just a supplement) and source code
of several example programs and a desk accessory.  When you purchase the
supplement you also get (someday?) the updates to Inside Macintosh and a
final copy (probably about when the Mac is obsolete).  Beats me why the IM
update comes with the supplement rather than the IM itself.  Oh well, you
need both anyhow.

Inside Macintosh and the Macintosh Software Supplement may be obtained (at
least they could when I got 'em) for $150 and $100, respectively, by sending
a company check (no P.O.s) to Apple's San Jose order processing facility:

Apple Computer, Inc.
467 Saratoga Avenue, Suite 621
San Jose, CA  95129.

They told me to expect to get it four to six weeks ARO; I got mine six
weeks to the day after I got the return receipt from the post office
(I was beginning to pull my hair out!)

The Lisa Pascal Workshop 2.0 (Apple part no. A6D0201) should be available
from your local Apple Lisa dealer.

				Eric L. Smith

				B324 Van Cott Hall
				University of Utah
				Salt Lake City, Utah  84112

				(801) 584-4276

( I don't know my net address yet, I'm new to this and will have to find
out tomorrow. )