Convert Pict2Rgn
Volume Number: 5
Issue Number: 6
Column Tag: Assembly Lab
Related Info: Quickdraw Window Manager
Convert PICTs to Regions
By Ted Cohn, San Jose, CA
Note: Source code files accompanying article are located on MacTech CD-ROM or
source code disks.
[Ted Cohn has been a long-time Mac enthusiast and used to be an Apple ][ hacker.
He wrote a professional 6502 debugger for the Apple ][ called Bugbyter which Apple
sold with its ProDOS assembly package. He graduated from UC Berkeley with a B.A. in
Computer Science. Since then he has been working at Radius Inc., where he designed
and wrote Tear-off Menus and a real-time magnifier for the Radius Two Page Display.]
Quickdraw Regions What’s This All About?
Have you ever used a region? If so, have you ever tried creating
irregularly-shaped ones? A year ago I wanted to write a desk accessory that would
require several strangely-shaped regions. Unfortunately, I found no simple way to
create them with the routines Quickdraw provides. Creating a region in Quickdraw is
procedural: You must call OpenRgn, draw lines, rectangles, ovals, etc., and then call
CloseRgn to define a region’s boundary. This can be a tedious, almost unbearable
process if you want to create bizarre regions by having to combine simple geometric
shapes. My goal was to find a way to create regions in a non-procedural manner by
drawing them with a standard paint program. Although Quickdraw does provide some
useful functions like UnionRgn, DiffRgn, SectRgn and XorRgn, it does not provide a
routine to convert a bitmap into a region - a routine I believe should be standard
Quickdraw equipment.
The question arose: how do I turn a bitmap into a region? One could develop an
algorithm to trace the edges of the bitmap and use Quickdraw to add each point
individually to the region’s boundary, but that seemed a bit primitive. The only way to
find an efficient algorithm was to first understand the region structure itself. And as
many already know, Apple has never divulged the region’s structure - certainly cause
for some fun detective work. I became sidetracked by this fascinating data structure.
The following explains the region format and my solution to the problem of region
creation. Listed afterwards is MakeRgn, an assembly function to convert a bitmap into
a Quickdraw region, and Pict2Rgn, an MPW tool which utilizes MakeRgn to convert
‘PICT’ resources to ‘RGN ’ resources.
Let There Be Light!
This is what Apple thinks we ought to know about regions:
rgnSize: Integer;
rgnBBox: Rect;
rgnData: Mystery;
Inside Mac, page I-141, states, “A region can be concave or convex, can consist
of one area or many disjoint areas, and can even have ‘holes’ in the middle.” A region
specifies exactly which pixels lie inside and outside of a closed boundary. So, how does
a region represent this boundary? Inside Mac describes only the header of the region
structure, rgnSize and rgnBBox, which are not very interesting. RgnSize specifies the
total number of bytes in the region data structure while rgnBBox contains the region’s
bounding rectangle. This is the smallest rectangle that will completely enclose the
region, that is, each edge of the rectangle will touch at least one point of the region’s
boundary. It seems, however, that rgnData was left as an exercise to the developer - a
complete mystery and a nagging curiosity.
Now let’s get technical. It turns out that the rgnData structure is not as complex
as it might seem. A region is like a bitmap in that it is arranged into scanlines and is
read from left to right, top to bottom. This makes sense since regions are used to
“mask” bitmaps which are also read from left to right, top to bottom. But instead of
containing pixel data, the region need only contain boundary information.
Figure 1a is a doughnut-shaped picture we would like to convert into a region.
Let’s step through the conversion process. If we restrict ourselves to the horizontal
dimension for the moment, we can isolate the boundary pixels of this bitmap by taking
the exclusive-OR of itself with its right-shifted copy. Figure 1b is the result of this
process. Notice that pixels which begin a horizontal line segment remain (pixel [5,0]
for instance). The remaining pixels of each line segment are lost, but we gain an extra
pixel at the end of the line segment. This additional pixel appears because of the XOR
function and signifies the end of the segment. Therefore, in the horizontal dimension,
two pixels are used to define the line segment.