TweetFollow Us on Twitter

Bitmap for SuperPaint
Volume Number:6
Issue Number:2
Column Tag:Programmer's Workshop

Related Info: Color Quickdraw Dialog Manager Menu Manager

BitMapper Utility For SuperPaint

By Michael Ogawa, Oceanside, CA

Note: Source code files accompanying article are located on MacTech CD-ROM or source code disks.

[Michael Ogawa is a Software Designer for Palomar Software where he has been involved in several projects including the Print Preview and PrintQ Monitor features of Palomar’s printer and plotter drivers. He has done design and development on Apple ][ computers since 1978, and has worked on business productivity tools, such as database and word processing applications, for the Macintosh since 1985.]

This article covers two interesting and relatively new topics: SuperPaint plug-ins, and a new data structure/resource format for bit images. The ‘BTMP’ resource type is a handy way of encapsulating a bit image and its dimension specifying bit map data into one package. It is easy to retrieve from disk, and to draw with or manipulate. SuperPaint is a wonderful application for creating bit image graphics. And using a plug-in tool that we’ll create in this article, it’s a snap grabbing an image from a SuperPaint document and creating a ‘BTMP’ resource.

Writing this article should be a snap because I’ll be able to leverage off of two other articles in this issue of MacTutor--meaning that I won’t have to write as much! This article is a how-to on writing a transformation menu command. For an overview of SuperPaint plug-ins, and for specifics on interactive palette tools, see Linda McLennan’s article. Mike Scanlin’s article covers the ‘BTMP’ resource type. It includes routines to retrieve these resources from disk and to draw them. He also shows you how to write a custom ResEdit editor to create and edit these resources directly within ResEdit.

What’s a Butmump?

The familiar ‘ICON’ and ‘SICN’ resources are nothing more than bit image data in pre-defined dimension formats. An ‘ICON’ is a 32-bit by 32-bit bit image which is easily retrieved from disk using the GetICON() Toolbox routine, and drawn using PlotICON(). A ‘SICN’ is a array of 16-bit by 16-bit image. The Macintosh Toolbox doesn’t have any routines specific to this resource type, but most Macintosh developers have their own library routines in their bag of tricks for dealing with them.

So great, we’ve got 32 by 32, and 16 by 16 covered. What if we need to draw a bit image that’s 36-bits wide and 24-bits tall? The common answer is to create a standard ‘PICT’ resource and use GetPicture() and DrawPicture(). One drawback to this is the lack of flexibility in drawing modes. Many developers have implemented their small icon drawing routines with a copy mode parameter allowing them to opaquely (blast-all-them-bits) or transparently (overlay) draw a small icon, or to punch holes using a masking small icon. DrawPicture() has no such flexibility.

Another advantage with bit images has to do with the recent availability of routines to create regions directly from bit map images. Now available from Apple Computer as part of 32-Bit Color QuickDraw, or available separately in MPW object form through Apple Software Licensing, is a routine called BitMapRgn(). Ted Cohn’s article “Covert PICTs to Regions”, MacTutor, June 1989, provides sources to a routine called MakeRgn(). Both of these routines take a bit map and create a region from it. Very handy when you want to drag around a gray region based on some bit image graphic.

What we have to deal with are bit images of non-standard dimensions, and bit map records explaining just what we have in the way of our bit images. The bounds field of the bit map record readily tells us the exact bitwise dimensions of the bit image. The rowBytes field tells us the row width of the bit image, which must be an even number of bytes. (Therefore, the bit image data may have unused bits off to the right of each row of the actual image.)

The bit map record is a fixed size data structure, and contains an even number of bytes. We can conviently tack on the actual bytes of the bit image to the bit map record, creating the variable size ‘BTMP’ data structure and resource type:

/* 1 */

 typedef struct BTMP {
 BitMap map;
 short  image[]; 
 } BTMP, *BTMPPeek, **BTMPPkHndl;
 typedef BitMap  *BTMPPtr, **BTMPHndl;

The only field that is a little “fuzzy” is the baseAddr field of the bit map record. On disk this field has no meaning and is merely a place holder. Once in memory and locked down, this field is set to contain the actual beginning address of the following bit image.

Mike Scanlin’s article contains routines to get and draw these puppies. And because the first field is an actual BitMap record, no type coercion is necessary when passing a ‘BTMP’ to a routine expecting a BitMap.

Writing SuperPaint Externals

Silicon Beach Software has come up with a neat method of making their products extendable. Both SuperPaint 2.0 and Digital Darkroom employ this technology which allows developers to add features to these products by writing some code and wrapping it in a file with a specified file type and a standard version identifying resource. The file is then placed in the same folder as the preferences file and voilá, the application suddenly has a new feature!

SuperPaint supports two types of plug-in modules, the term they use for their “externals”. One type adds custom painting tools to their painting tools palette. This type of tool is referred to as an interactive painting tool. The other type adds a command to the Paint menu and operates on the selected area in the current document. This type of tool is referred to as a menu command or transformation command tool. When the user puts a menu command plug-in in the folder that contains their preferences file, the command appears at the bottom of the Paint menu.

Figure 1. Plug-in menu commands appears at the bottom of the Paint menu in SuperPaint. The resource name of the plug-in menu’s code resource appears as the command name in the menu.

To keep things simple this article only deals with SuperPaint menu command tools. For an overview on plug-in modules and details on other types of tools see Linda McLennan’s article.

The Bare Essentials

You can create a plug-in tool in any development environment that allows you to create a stand-alone code resource (e.g. a definition proc such as a WDEF, CDEF, or LDEF, or a HyperCard or 4th Dimension external). A menu command tool is a file whose file type is ‘BWtc’. That stands for “Black and White transformation command”. It’s creator type is up to you. If you use ‘SPNT’, SuperPaint’s creator type, it will show up on the Finder desktop with a standard plug-in icon provided by SuperPaint. You can give it your own creator type, and provide the other necessary resources (creator, ‘BNDL’, ‘FREF’, and ‘ICN#’) to give it your own unique desktop icon.

The plug-in must contain a plug-in module version information resource, and the code resource. The plug-in module version information resource is used for compatibility checking. It is a resource of type ‘PiMI’. Currently it is two bytes long and must contain the current version value of $0001 (or just plain ol’ decimal one). The code resource must be of type ‘BWtc’, the same as the file type. The resource name of the ‘BWtc’ code resource will show up at the bottom of SuperPaint’s Paint menu, and in SuperPaint’s plug-in info list in the About Box.

The file may contain any other resources the tool requires, and all resources should be marked purgeable. When SuperPaint executes the plug-in code resource the plug-in file is set as the current resource file. The plug-in should do one-deep resource calls (e.g Get1Resource()) unless it is trying to get a resource from the System file.

I’ve Got Your Number

What resource IDs should your resources have? Practically any that you want, as long a you follow the rules. Of course.

You should start numbering resources of each type within your plug-in from 16000, and you should try to have all resources of a type numbered consecutively. The range of 16000 to 32000, a subset of the range reserved for applications, is reserved by Silicon Beach for plug-ins. By starting at a base ID of 16000 you avoid conflicting with resources in SuperPaint and the System. Silicon Beach has eased up their original consecutive numbering limitation, but you should still try very hard to follow it as a guideline, and never have numbering gaps larger than you can survive with to preserve you coding sanity.

The reason for the original insistence on consecutive numbering had to do with potential renumbering of your plug-in’s resources should they be merged into a file with other plug-ins, or moved into the SuperPaint application itself. Just as with desk accessories, a merging utility would have to renumber a plug-in’s resources if their IDs collided with another plug-in’s. (The implications of resource ID renumbering to your coding is discussed in the next section.)

The drawback to developers is this: say your plug-in has a dialog and an alert. You give the ‘DLOG’ and its ‘DITL’ resources IDs of 16000. You can give the ‘ALRT’ resource an ID of 16000, but you can’t give its ‘DITL’ a resource of 16000 because that is already taken. While the Dialog Manager will have no trouble associating ‘DITL’ 16001 with ‘ALRT’ 16000 if you create the resources correctly, this type of odd-ball correspondence definitely flies in the face of creating easily readable source code and product maintenance.

After discussions with Silicon Beach about this annoying restriction, they’ve decided that it can be eased up. Your ‘PiMI’ and ‘BWtc’ resources should still be numbered 16000. And as much as possible all other resource types should be numbered consecutively from a base ID 16000. You don’t have to. But you should try as much as possible, keeping ID gaps as small as possible, so that if renumbering is done on your plug-in’s resource they will take up as small an ID range as possible.

There is an exception that was not considered by Silicon Beach, and that is the Finder’s Get Info version resources that you may want to include in your plug-in. The ‘vers’ resources, as explained in Macintosh Technical Note #189: Version Territory, must be ID number 1 and/or 2. As things are now this works fine for un-merged plug-ins. But what happens when plug-ins are merged?

I recommend that developers that provide ‘vers’ resources do not have ‘vers’ resources numbered with their base ID, or their base ID plus one. I recommend to Silicon Beach or others creating plug-in merge utilities that if they encounter ‘vers’ 1 or 2 resources they be renumbered as if they had been originally numbered at the base ID or base ID plus one. When un-merging a plug-in so that it is in its own file, any ‘vers’ resource at the base ID or base ID plus one be renumbered to ID 1 or 2.

What’s a ‘BWtc’ Code Resource Look Like?

Very simply, a ‘BWtc’ code resource looks to the caller (i.e. SuperPaint) like a function whose prototype definition is:

/* 2 */

 pascal void main(short selector,
 MenuDataPtr toolInfo, long *refCon,
 short *returnCode);

The executable code must begin at the first byte of the ‘BWtc’ resource which SuperPaint will load and lock down before it begins executing it. The resource ID of the ‘BWtc’ resource is considered the plug-in’s base ID. The resource name is the name that SuperPaint will display in the Paint menu.

Selector can be one of three commands: 0 == provide About Box information, 10 == set options, and 11 == command has been selected from menu (do your thing). The file SPMenu.h, supplied by Silicon Beach as part of their plug-in developer’s kit, contains the following symbolic definitions, as well as other equates and data structure definitions:

/* 3 */

 #define menuAbout 0
 #define menuOptions 10
 #define menuSelected11

Before each call of selector == menuAbout or menuSelected, your plug-in will be called with the menuOptions selector. Currently the only use of this call is to allow the menu command to request a scratch buffer from SuperPaint. The toolInfo parameter will point to a menu options record:

/* 4 */

 typedef struct {
 BooleanusesScratch;
 } MenuOptionsRec, *MenuOptionsPtr;

Set the usesScratch field to FALSE if you don’t need SuperPaint to provide a scratch buffer for you tool.

When the user has requested information about your plug-in from SuperPaint’s About Box, it calls your plug-in with selector set to menuAbout. You can provide your own informative About Box using modal dialogs or alerts. If you do, you let SuperPaint know that you’ve handled the request by setting the VAR parameter *returnCode to 0. The toolInfo parameter is a pointer to an abbreviated menu command information record. The only currently used field is the very important toolID field. This field tells you what your current runtime base ID is.

If you have a ‘TEXT’ resource for SuperPaint to display in its plug-in About Box set the VAR parameter *returnCode to textAbout (2). In this case, your informative ‘TEXT’ resource must have the same resource ID as your ‘BWtc’ code resource. If you have nothing to say, set *returnCode to noAbout (1).

Selector menuSelected is where we have our fun. ToolInfo is a pointer to a menu command information record:

!codeexamples

tart/* 5 */

typedef struct {
 short  toolID;  /* tool rsrc ID */
 short  spare1;  /* reserved */
 short  spare2;  /* reserved */
 short  spare3;  /* reserved */
 short  spare4;  /* reserved */
 short  spare5;  /* reserved */
 short  spare6;  /* reserved */
 short  spare7;  /* reserved */
 BooleanshiftIsDown; /*shift key down*/
 BooleancmdIsDown; /*command key down*/
 BooleanoptIsDown; /*option key down*/
 BooleanspareFlag; /* spare */
 BooleanfillPatNone; /* flag to
 indicate if current fill
 pattern is none */
 BooleanlinePatNone; /* flag to
 indicate if current line
 pattern is none */ 
 MenuHandle subMenu; /* handle to
 command’s submenu */
 short  menuItem;/* number of
 submenu item selected */
 BitMap scratchBits; /* scratch buffer
 bitmap */
 BitMap lassoMaskBits;  /* lasso mask
 bitmap */
 BitMap undoBits;/* undo buffer
 bitmap */
 Rect   selectRect;/* selection
 rectangle in document
 coords */
 PatterncurFillPat;/* current fill
 pattern */
 Handle curPatList;/* handle to
 currently selected pattern
 list */
} MenuDatarec, *MenuDataPtr;

Again, there is the all-important toolID field which contains our runtime base ID. The state of the user’s current drawing tools and palettes is given by several fields: fillPatNone, linePatNone, curFillPattern, curPatList.

When a plug-in is called the current grafPort is set up so that the current selection’s top left corner is at local coordinate (0,0). Also, the pnSize, pnMode, pnPat, txFont, txFace, and txSize fields of the grafPort reflect the user’s current tool selections.

And if you need to know just where in the document the selection is, the selectRect field of the menu command information record contains the location of the selection in document coordinates.

Inside BitMapper

BitMapper’s call chain looks like:

 BitMapper (MPW only)
 main
 DoIt
 OpenOutput
 PutPICT
 DoOutput
 PutBTMP
 CopyBits2Buffer
 DoOutput

Main() is a dispatcher routine, and entirely handles the About Box information and set options calls.

The routine AlertErr() (not displayed in the call chain shown above) is very instructional. It contains an example of referencing one of our resources using the runtime base ID. Note how it calls NoteAlert() with a resource ID of: baseID + kALRT_Err, where baseID was passed in as a parameter, and was originally retrieved from the toolID field of the menu command information record. The constant kALRT_Err is defined in a header file as the resource’s offset from the base ID. And the Rez source file defines the ‘ALRT’ resource’s ID as the compile time base ID plus the offset: kOrigBaseID + kALRT_Err.

Another point of interest is the usage of a local variable rather than attempting to use a global variable. Very important rule: NO GLOBALS! This means that you cannot access QuickDraw globals such as thePort, or Black (in ThinkC, in MPW C you can’t use: qd.thePort or qd.Black). It also means you can’t use any variables declared with the storage specifier static or external, nor can you declare any variable outside of a code block. You also cannot use strings embedded within your code, such as: DrawString(“\pHello, world”); because the string data is normally stored as global data. As the code in AlertErr() illustrates, even empty strings such as “” can’t be used!

/* 6 */

 unsigned char str0 = ‘\0’;

 ParamText(s, &str0, &str0, &str0);
 /* The following line would be illegal!!
    ParamText(s, “”, “”, “”); */

As a general development system point of interest that is not specific to creating plug-in tools, AlertErr() calls CenterWindow(), a routine found in the examples in the developer’s kit. This routine has been modified to be ambidextrous--it is compilable from either ThinkC or MPW C 3.0. The changes required had to do with globals and names of include files.

A call to GetMBarHeight() was substituted for the use of the low-memory global MBarHeight, and the usage of the low-memory global CurrentA5 requires conditional compiling because of the difference in how the two compilers treat globals. In ThinkC, usage of a low-memory global implies using the value at the low-memory location. In MPW C you must dereference after coercing the symbol to be a pointer to the appropriate data type. This difference was also the reason for using the function call to get the height of the menu bar. (Note that usage of the menu bar height global is System dependent. Don’t try this at home (or anywhere for that matter) on 128K Macs.)

Also, sizeof(thePort) was changed to sizeof(GrafPtr) so we don’t have to conditionally code it as sizeof(thePort) or sizeof(qd.thePort).

Outside of that, there probably isn’t all that much to elaborate on in the first example that isn’t spelled out in the example’s inline documentation. The stuff that does the grunt-level plug-in environment-specific work is in PutBTMP(), and is summarized by it’s documentation:

/* 7 */

short PutBTMP(TBitMapperPtr pMyInfo)

Makes a ‘BTMP’ resource from the selection area our command is working with, then outputs the resource. PMyInfo is a pointer to a BitMapper record containing information about the currently executing command. This includes a grafPtr to the document port (which is also the current port).

Before calling us, SuperPaint has already set the port’s portRect to be equivalent to the selection bounding rectangle in a coordinate system local to the selection. That is, portRect.topLeft is (0,0), portRect.bottom is equal to the height of the selection area, and portRect.right is equal to the width of the selection area.

The code itself simply does a bit copy from the selection area, which has been set up by SuperPaint as the current grafPort’s portRect, to a private buffer which we send to the clipboard. What is really beautiful is that clipping is handled automatically if the selection is not rectangular! So, for many operations you don’t need to mask to the selection area. If you do need the selection area, the lassoBits field of the menu command record contains a BitMap which specifies the actual selection area. (An oversight is that this field only applies to non-rectangular selections made using the lasso tool. It does not contain a valid BitMap if the selection was made with any other selection tool.)

The transformation command plug-in tools were designed primarily to allow programmers a way to access the bits of the selection area, and to modify them. A really simple example would be to create your own invert command. Simply calling InvertRect(&curGptr->portRect), where curGptr is the current grafPtr, will invert the selected area in the document. It can also be used to import images. And, as this example has shown, it can be used to export images as.

Menu Commands with Sub-Menus

It is also possible for menu commands to contain their own hierarchical sub-menus. A second example, based on the first, illustrates this. Mike Scanlin in his article discusses ‘BTM#’ resources, which, consists of a list of ‘BTMP’ resources. This second example creates a menu command that allows us to create either a ‘BTMP’ or a ‘BTM#’ resource from the SuperPaint selection.

Figure 2. The BitMapper menu command with a hierarchical sub-menu. The name of the ‘BWtc’ resource is still used as the command name in the Paint menu. The sub-menu is as specified in BitMapper’s ‘MENU’ resource, whose resource ID is the same as the ‘BWtc’ resource.

There are only two additional things that you need to know to create a menu command with a sub-menu. The first involves creating the ‘MENU’ resource, the second involves knowing which menu item was chosen by the user at execution time.

The resource ID of the ‘MENU’ resource must be the same as the ‘BWtc’ resource. And, as with other resources in the plug-in, it should be marked purgeable. Purgeable? What about the warning in Inside Macintosh, Volume IV, The Menu Manager: “Menu resources should never be marked purgeable”? Well, because the resource file of a plug-in isn’t open unless it is actually executing, SuperPaint must load and detach a sub-menu’s resource, so at the same time it marks the detached menu resource as non-purgeable.

As for the menu ID of the sub-menu, Apple has specified that sub-menus from applications should use a menu ID in the range of 0-235. SuperPaint restricts sub-menus of plug-in to the range of 200-235, but it also will dynamically change the menu ID as necessary to avoid conflicts with other plug-ins.

At execution time, if your plug-in has a sub-menu, you merely need to check the menuItem field of the menu command data record. In the second example, this is done in the routine DoIt(), which branches accordingly.

A Little Bonus

The BitMapper examples were culled from my SuperPaint plug-in Resourceror, which is available on the MacTutor sources disk in executable (only) form. Resourceror creates ‘ICON’, ‘ICN#’, ‘SICN’, and ‘CURS’ resources from SuperPaint, as well as ‘BTMP’ and ‘BTM#’ resources.

Figure 3. Resourceror’s sub-menu. The user can can select any combination of resources to create from the middle section of the sub-menu. The user can also elect to send the resources to either the Clipboard or directly to a file by toggling the choices in the bottom section of the file. The Create command at the top executes the resource creation.

Resourceror shows an example of remembering user preference settings from the menu command’s sub-menu. The user can toggle any combination of resources to create in the sub-menu. The resources aren’t actually created until the Create command is chosen, but the settings are saved to disk--that is, they are “sticky”.

With Resourceror, the user can also choose to write the resources directly to a resource file rather than to the clipboard by toggling the To File item at the bottom of the sub-menu. Doing this also adds ellipsis to the Create command, indicating, as per Apple Computer’s human interface guidelines, that a dialog will be brought up to complete the command.

Within the Standard GetFile dialog, there are more instructive changes. A prompt (sensitive to whether one or more resource types are being created) has been added to the Standard GetFile dialog, the Open button has been changed to a Save button, a default item hilite border has been added to the Save button, and this hilite is activated or deactivated depending on whether the selection is a file that can be saved to. Files whose resource fork is already open cannot be saved to, and a warning at the bottom of the dialog box indicates this when appropriate. Finally, a New button was added to the dialog that takes the user to a Standard PutFile dialog.

When the resources are saved to the specified file, they are all given the same unique resource ID. This ID is not user selectable, but it is unique, and all resources created with the same command are given the same ID.

Bibliography

Inside Macintosh, Addison-Wesley, 1985.

Macintosh Technical Note #189: Version Territory, Apple Computer, Inc. 1989.

Macintosh Technical Notes #193: So many BitMaps, so little time, Apple Computer, Inc. 1989.

Convert PICTs to Regions, Ted Cohn, MacTutor June 1989.

Plug-in Module Developer’s Toolkit, Silicon Beach Software, 1989.

Figure 4. Setting the Project Type information in ThinkC. The project must be single segment and shouldn’t use QuickDraw globals.

#===========================================#
#file:  Makefile
#date:  11.13.89
#===========================================#
#Makefile for the BitMapper SuperPaint
#plug-in tool.  All objects are built
#into an “ohs” folder within the
#BitMapper source folder.
#===========================================#
#Copyright © 1989, Michael Ogawa and
#MacTutor -- All Rights Reserved.
#===========================================#

# Directories
OHSF    = :ohs:  # objects folders
COptions= -r -mbg ch8

# Plug-in creator signature, filetype,
# and base resource ID.
CREATOR = ‘SPNT’
FILETYPE= ‘BWtc’
ORIG_BASE_ID= 16000

# All object files
OBJS = {OHSF}BitMapper_main.c.o 
 {OHSF}CenterWindow.c.o

# Default dependency rule:
# map source directory to objects folder
{OHSF} ƒ :

# Default dependency rule:
# map C sources to objects
.c.o ƒ .c
 C {Default}.c {COptions} 
 -o {OHSF}{Default}.c.o

# BitMapper file object/source dependencies
BitMapper_main.c.includes = 
 BitMapper.h 
 BitMapper_goodies.h 
 BitMapperRsrc.h 
 CenterWindowIntf.h 
 SPMenu.h
{OHSF}BitMapper_main.c.o ƒ 
 {BitMapper_main.c.includes}
CenterWindow.c.includes = 
 CenterWindowIntf.h 
 qdGlobals.h
{OHSF}CenterWindow.c.o ƒ 
 {CenterWindow.c.includes}

# Plug-in tool executable/objects
# dependencies 
BitMapper ƒƒ {OBJS}
 Link -c {CREATOR} -t {FILETYPE} 
 # code rsrc’s type & ID  
 -rt {FILETYPE}={ORIG_BASE_ID} 
 # name of entry point routine  
 -m “BITMAPPER” 
 # code rsrc name as we want it 
 # to appear in the Paint menu  
 -sn Main=”BitMapper” 
 # progress info, just to be sure  
 -p 
 {OBJS} 
 {CLibraries}CRuntime.o 
 {Libraries}Interface.o 
 -o BitMapper

# Plug-in tool executable/resources
# dependencies 
BitMapper.r.includes = BitMapperRsrc.h
BitMapper ƒƒ BitMapper.r 
 {BitMapper.r.includes}
 Rez BitMapper.r {ROptions} -a 
 -o BitMapper
 # check resources, just to be sure 
 RezDet -l BitMapper
 # Duplicate BitMapper “{SP_POUCH}”

/* ======================================= *
 file:  BitMapper.h
 date:  10.01.89
 * -------------------------------------- *
 Main header file for the BitMapper
 SuperPaint plug-in menu command.
 * -------------------------------------- *
 Copyright © 1989, Michael Ogawa and
 MacTutor -- All Rights Reserved.
 * ======================================= */

#ifndef _H_BitMapper
#define _H_BitMapper

#ifdef applec
#include <Types.h>
#include <Menus.h>
#include <Dialogs.h>
#endif

#include “BitMapper_goodies.h”
#include “BitMapperRsrc.h”
#include “SPMenu.h”
#include “CenterWindowIntf.h”

/* data types ============================ */
typedef struct {
 MenuDataPtrpToolInfo;
 long   *pRefCon;
 GrafPtrdrawGptr;
} TBitMapperRec, *TBitMapperPtr;
/* The BitMapper record is used to pass all
pertinent information for our command in one
data structure.  PToolInfo is a pointer to
the menu data structure that was passed in by
SuperPaint when we were called.  PRefCon is
a pointer to the refCon word passed in, and
that we can modify and use as we desire.
(BitMapper does not use the refCon.)
DrawGptr is the current grafPort set up by
SuperPaint that contains the selection our
command works on. */
/* m_o 09.17.89 */

/* function prototypes =================== */
#ifdef applec
extern pascal void BitMapper(short selector,
 MenuDataPtr toolInfo, long *refCon,
 short *returnCode);
#endif applec

extern pascal void main(short selector,
 MenuDataPtr toolInfo, long *refCon,
 short *returnCode);

#endif _H_BitMapper

/* ======================================= *
 file:  BitMapperRsrc.h
 date:  11.17.89
 * -------------------------------------- *
 Header file for C and Rez for the
 BitMapper SuperPaint plug-in tool.
 Contains symbolic constants, data type
 and resource type definitions that are
 common to both the C and Rez components
 of the project.  Utilizes the Rez
 compiler symbol, “REZ”, to conditionally
 include/exclude definition lines as
 necessary.
 * -------------------------------------- *
 Copyright © 1989, Michael Ogawa and
 MacTutor -- All Rights Reserved.
 * ======================================= */

#ifndef _H_BitMapperRsrc
#define _H_BitMapperRsrc

#ifdef REZ
#ifndef bold
#include “Types.r”
#include “SysTypes.r”
#endif bold
#endif REZ

/* constants ============================= */

#define kOrigBaseID16000
/* All resources of plug-in tools should be
numbered consecutively from a base resource
ID.  This is the ID# we are using as our base
ID. */
/* m_o 09.13.89 */

#define kType_BitMap ‘BTMP’
/* Resource type of our custom bitmap and
image resource that we create with
BitMapper. */
/* m_o 09.13.89 */

#define kALRT_Err0 /* + baseID */
#define kDITL_ErrkALRT_Err/* + baseID */
#define kactb_ErrkALRT_Err/* + baseID */
/* ID offsets for the error alert
resources, based off of the base resource ID.
The resources are Rez compiled with these
resource IDs plus kOrigBaseID.  They are
calculated at runtime based on the value in
the toolID field of the menu command data
record that is passed in to our tool. */
/* m_o 09.17.89 */

/* data types ============================ */
#ifndef REZ
typedef struct {
 BitMap map;
 short  image[]; 
} TBTMP, *TBTMPPeek, **TBTMPPkHndl;
typedef BitMap *TBTMPPtr, **TBTMPHndl;
#else
type kType_BitMap {
 unsigned longint = 0; /* map.baseAddr */
 integer; /* map.rowBytes */
 rect;  /* map.bounds */
 hex string;/* image */
};
#endif REZ
/* Data structure for our custom bitmap and
image resource type. */
/* mps 06.22.89/m_o 06.25.89 */

#endif _H_BitMapperRsrc

/* ======================================= *
 file:  BitMapper_goodies.h
 date:  11.17.89
 * -------------------------------------- *
 Copyright © 1989, Michael Ogawa -- All
 Rights Reserved.
 * ======================================= */

#ifndef _H_BitMapper_goodies
#define _H_BitMapper_goodies

#ifdef applec
#include <Types.h>
#include <Memory.h>
#include <Errors.h>
#endif applec

#ifdef THINK_C
/* #define qDEBUG */
#endif THINK_C

/* constants ============================= */

#ifndef NULL/* also defined in stdio.h */
#define NULL0L
#endif

#define kBitsPerByte 8
#define kBytesPerWord2
#define kBitsPerWord \
 (kBitsPerByte * kBytesPerWord)
#define kWordsPerLWord  2
#define kBytesPerLWord  \
 (kBytesPerWord * kWordsPerLWord)
#define kBitsPerLWord\
 (kBitsPerByte * kBytesLPerWord)
/* Generally useful equates of basic data
element sizes.  One byte consists of eight
bits (kBitsPerByte), one word consists of two
bytes (kBytesPerWord), and one long word
consists of two words (kWordsPerLWord) or
four bytes (kBytesPerLWord).  There are 16
bits in a word (kBitsPerWord), and 32 bits in
a long word (kBitsPerLWord). */
/* m_o 09.17.89 */

/* data types ============================ */
#ifdef THINK_C
#define const  /* not yet implemented */
#endif THINK_C

/* macro-“functions” ===================== */
#define WIDTH(box) \
 (((box).right) - ((box).left))
#define HEIGHT(box)\
 (((box).bottom) - ((box).top))
/* These macros return the width or height
of the specified rectangle. */
/* m_o 07.17.89 */

#define BITS2ROWBYTES(nBits)\
 ((((nBits) - 1) / kBitsPerWord + 1) \
 * kBytesPerWord)
/* Converts the number of bits nBits to its
equivalent number of rowBytes, making sure to
account for the fact that rowBytes must be even. */
/* mps 07.17.89/m_o 09.17.89 */

#endif _H_BitMapper_goodies

/* ======================================= *
 file:  BitMapper_main.c
 date:  11.13.89
 * -------------------------------------- *
 Copyright © 1989, Michael Ogawa and
 MacTutor -- All Rights Reserved.
 * ======================================= */

/* #include <MacHeaders> */
#include “BitMapper.h”

#ifdef applec
#include <Desk.h>
#include <Scrap.h>
#include <Packages.h>
 typedef char  SignedByte;
#endif applec

/* Code resource entry point (MPW) ======= */
#ifdef applec
pascal void BitMapper(short selector,
 MenuDataPtr toolInfo, long *refCon,
 short *returnCode)
/* Code resource entry point for a
SuperPaint transformation command plug-in
tool built in MPW C.  This avoids having to
forward reference all the internal
routines. */
/* m_o 06.23.89 */
{
 main(selector, toolInfo, refCon,
 returnCode);
}
#endif applec

/* private functions ===================== */

static short OpenOutput(TBitMapperPtr pMyInfo)
/* Prepares the appropriate output method.
PMyInfo is a pointer to a BitMapper record
containing information about the currently
executing command.
 This version of OpenOutput() simply
prepares output to the desk scrap.  The
clipboard is cleared, and as a workaround for
MultiFinder’s selective updating of other
partitions’ ScrapCount low-memory variable,
SystemEdit() is called with the copy message.
(See “Macintosh Technical Note #180:
MultiFinder Miscellanea” for details.)
 If no error occured then the result code
noErr is returned as the function return
value; otherwise an appropriate Operating
System result code is returned as the
function return value. */
/* m_o 11.13.89 */
{
#pragma unused(pMyInfo)

 /* MultiFinder work-around: notify
    System of copy operation  */
 (void)SystemEdit(3);
 /* clear the desk scrap  */
 return(ZeroScrap());
}

static short DoOutput(Handle hData,
 ResType rType, TBitMapperPtr pMyInfo)
/* Outputs the data in the relocatable
block specified by the handle hData.  The
data output format is specified by rType.
PMyInfo is a pointer to a BitMapper record
containing information about currently
executing command.
 This version of DoOutput() simply sends
the data to the clipboard using the Toolbox
routine PutScrap(), specifying rType as the
Desk scrap data type.  Note that it does not
call ZeroScrap(), so the output is added to
the current scrap content as an additional
type.  This is not good if the scrap already
contains a resource of the specified type.
Therefore, ZeroScrap() should be called once
before outputting any data to the scrap.
 If no error occured then the result code
noErr is returned as the function return
value; otherwise an appropriate Operating
System result code is returned as the
function return value. */
/* m_o 11.13.89 */
{
#pragma unused(pMyInfo)
 SignedByte savedMPFlags;
 short result;

 /* get master pointer flags and lock down  */
 savedMPFlags = HGetState(hData);
 MoveHHi(hData);
 HLock(hData);

 result = PutScrap(GetHandleSize(hData), rType, *hData);

 /* restore master pointer state  */
 HSetState(hData, savedMPFlags);

 return(result);
}

static void CopyBits2Buffer(
 const BitMap *pSrcBMap,
 const Rect *pSrcRect, Ptr pBuffer,
 short bufferRowBytes, short mode)
/* Transfers a bit image specified by the
bit map *pSrcMap to the image buffer
pBuffer[].  The image buffer must begin on an
even address.  The width, in bytes, of the
destination buffer is specified by
bufferRowBytes, which must also be even.
 The bits enclosed by the source
rectangle *pSrcRect are transferred to a
similar sized rectangle in the destination
image.  The destination rectangle is the same
size as the source rectangle and is aligned
at the top left corner of the destination bit
image.  The destination image buffer must be
big enough to accomodate the entire image
being transferred.  The transfer mode is
specified by the mode parameter. */
/* m_o 06.22.89 */
{
 BitMap dstBMap;

 dstBMap.baseAddr = pBuffer;
 dstBMap.rowBytes = bufferRowBytes;
 dstBMap.bounds = *pSrcRect;
 CopyBits(pSrcBMap, &dstBMap, pSrcRect,
 pSrcRect, mode, NULL);
}

static short PutPICT(TBitMapperPtr pMyInfo)
/* Makes a picture that is a copy of the
selection area our command is working with,
then outputs the picture.  PMyInfo is a
pointer to a BitMapper record containing
information about currently executing
command.  This includes a grafPtr to the
document port (which is also the current
port).
 Before calling us, SuperPaint has
already set the port’s portRect to be
equivalent to the selection bounding
rectangle in a coordinate system local to the
selection.  That is, portRect.topLeft is
(0,0), portRect.bottom is equal to the height
of the selection area, and portRect.right is
equal to the width of the selection area.
 If no error occured then the result code
noErr is returned as the function return
value; otherwise an appropriate Operating
System result code is returned as the
function return value. */
/* m_o 09.13.89 */
{
 short result;
 PicHandle hMyPic;

 if (hMyPic = OpenPicture(
 &pMyInfo->drawGptr->portRect)) {
 /* copy selection  */
 CopyBits(
 &pMyInfo->drawGptr->portBits,
 &pMyInfo->drawGptr->portBits,
 &pMyInfo->drawGptr->portRect,
 &pMyInfo->drawGptr->portRect,
 srcCopy, NULL);
 ClosePicture();
 result = DoOutput((Handle)hMyPic,
 ‘PICT’, pMyInfo);
 KillPicture(hMyPic);
 } else
 result = MemError();
 return(result);
}

static short PutBTMP(TBitMapperPtr pMyInfo)
/* Makes a ‘BTMP’ resource from the
selection area our command is working with,
then outputs the resource.  PMyInfo is a
pointer to a BitMapper record containing
information about the currently executing
command.  This includes a grafPtr to the
document port (which is also the current
port).
 Before calling us, SuperPaint has
already set the port’s portRect to be
equivalent to the selection bounding
rectangle in a coordinate system local to the
selection.  That is, portRect.topLeft is
(0,0), portRect.bottom is equal to the height
of the selection area, and portRect.right is
equal to the width of the selection area.
 If no error occured then the result code
noErr is returned as the function return
value; otherwise an appropriate Operating
System result code is returned as the
function return value. */
/* m_o 09.17.89 */
{
 long sz;
 short result;
 BitMap myMap;
 TBTMPPkHndl hMyBTMP;

 /* set up BitMap: init baseAddr  */
 myMap.baseAddr = NULL;
 /* get bounds rectangle  */
 myMap.bounds = pMyInfo->drawGptr->portRect;
 /* calc rowBytes  */
 myMap.rowBytes =
 BITS2ROWBYTES(WIDTH(myMap.bounds));
 /* calc size of ‘BTMP’ resource  */
 sz = sizeof(TBTMP) +
 myMap.bounds.bottom *
 myMap.rowBytes;

 /* get ‘clean’ memory for new ‘BTMP’ resource  */
 if (!(hMyBTMP =
 (TBTMPPkHndl)NewHandleClear(sz)))
 return(MemError());

 /* copy BitMap  */
 (**hMyBTMP).map = myMap;

 /* copy bit image  */
 MoveHHi((Handle)hMyBTMP);
 HLock((Handle)hMyBTMP);
 CopyBits2Buffer(
 &pMyInfo->drawGptr->portBits,
 &myMap.bounds,
 (Ptr)&(**hMyBTMP).image,
 myMap.rowBytes, srcCopy);
 HUnlock((Handle)hMyBTMP);

 /* ship it! */
 result = DoOutput((Handle)hMyBTMP, ‘BTMP’, pMyInfo);

 /* clean up and leave  */
 DisposHandle((Handle)hMyBTMP);
 return(result);
}

static short DoIt(TBitMapperPtr pMyInfo)
/* Makes a ‘BTMP’ resource and a picture
from the selection area our command is
working with, then outputs the resources.
PMyInfo is a pointer to a BitMapper record
containing information about currently
executing command.  All its fields should be
filled in on entry, except the drawGptr field
which this routine fills in.  (The drawGptr
field is a grafPtr to the document port,
which is also the current port.)
 If no error occured then the result code
noErr is returned as the function return
value; otherwise an appropriate Operating
System result code is returned as the
function return value. */
/* m_o 08.29.89 */
{
 short result;

 GetPort(&pMyInfo->drawGptr);
 if ((result = OpenOutput(pMyInfo)) == noErr) {
 short result2;

 result = PutBTMP(pMyInfo);
 if ((result2 = PutPICT(pMyInfo)) !=
 noErr && result == noErr)
 result = result2;
 }
 return(result);
}

static void AlertErr(short err, short baseID)
/* Puts up an alert telling the user an
error occured.  Err is the result code of
the error.  This is converted to a string
and substituted for param text ^0 in the
alert.
 BaseID is the resource ID of the first
(numerically lowest) resource in our plug-in
tool.  Because resource IDs may be
reassigned, we calculate our alert’s current
resource ID based on this. */
/* m_o 09.30.89 */
{
 Str255 s;
 unsigned char str0 = ‘\0’;

 /* Convert error ID to string format,
    put into param text ^0.  Note usage
    of “str0” because we can’t have any
    globals.  Not even empty strings! */
 NumToString(err, s);
 ParamText(s, &str0, &str0, &str0);
 /* The following line would be illegal!!
    ParamText(s, “”, “”, “”); */

 CenterWindow(‘ALRT’, baseID + kALRT_Err);
 /* make sure cursor is arrow  */
 InitCursor();

 NoteAlert(baseID + kALRT_Err, NULL);
}

/* entry points ========================== */
pascal void main(short selector,
 MenuDataPtr toolInfo, long *refCon,
 short *returnCode)
/* Entry point and command dispatcher for
the BitMapper plug-in command tool.  Selector
is a call type code as defined by Silicon
Beach Software in the Menu Command Interface
section of their plug-in documentation
“Developing Plug-In Modules for SuperPaint”.
*/
/* m_o 08.29.89 */
{
 TBitMapperRec myInfo;

 switch (selector) {
 case menuAbout:
 /* tell SuperPaint we have TEXT
    resource for About Box info  */
 *returnCode = textAbout;
 break;
 case menuOptions:
 /* tell SuperPaint we don’t need
    a scratch buffer  */
 ((MenuOptionsPtr)toolInfo)->usesScratch = false;
 *returnCode = noErr;
 break;
 case menuSelected:
 /* setup private data record and do it!  */
 myInfo.pToolInfo = toolInfo;
 myInfo.pRefCon = refCon;
 *returnCode = DoIt(&myInfo);
 break;
 }

 /* alert user on errors  */
 if (*returnCode != noErr && selector != menuAbout)
 AlertErr(*returnCode, toolInfo->toolID);
 return;
}

/* ======================================= *
 file:  BitMapper.r
 date:  11.17.89
 * -------------------------------------- *
 Resources for the BitMapper SuperPaint
 plug-in menu command.
 * -------------------------------------- *
 Copyright © 1989, Michael Ogawa and
 MacTutor -- All Rights Reserved.
 * ======================================= */

#include “BitMapperRsrc.h”

data ‘PiMI’ (kOrigBaseID, purgeable)
/* Plug-in Module Information specifying
version 1 interface. */
/* m_o 09.13.89 */
{
 $”00 01"
};

resource ‘ALRT’ (kOrigBaseID + kALRT_Err,
 “errAlrt”, purgeable)
/* Alert template for the error alert.  The
window height and width are based on the
actual items in the dialogs.  The top
coordinate is arbitrary.  The left coordinate
is calculated by: (512 - width) / 2.  The
actual desktop position should be calculated
at runtime depending on the actual desktop
size/configuration. */
/* m_o 09.30.89 */
{/*148*/
 {40, 0, 40+92+8, 0+208+8},
 kOrigBaseID + kDITL_Err,
 { /* array: 4 elements */
 OK, visible, sound1,/* [1] */
 OK, visible, sound1,/* [2] */
 OK, visible, sound1,/* [3] */
 OK, visible, sound1 /* [4] */
 }
};

resource ‘DITL’ (kOrigBaseID + kDITL_Err,
 “errAlrt”, purgeable)
/* Dialog item list for the error alert.
The param text ^0 in the prompt text should
be filled in with the error code or some
other message at runtime. */
/* m_o 09.30.89 */
{
 { /* array DITLarray: 2 elements */
 /* [1] */
 {72, 8, 92, 78}, Button
 {enabled, “Darn!” },
 /* [2] */
 {8, 64, 56, 208}, StaticText
 {disabled,
 “Oops!  Something went “
 “wrong.  Sorry about that.  “
 “(^0)”
 }
 }
};

resource ‘actb’ (kOrigBaseID + kactb_Err,
 “errAlrt”, purgeable)
/* This is a default color table for the
error alert */
/* m_o 09.30.89 */
{
 0x0,
 0,
 {}/* array ColorSpec: 0 elements */
};

data ‘TEXT’ (kOrigBaseID, “about”, purgeable)
/* Provides information about BitMapper to
the user from within SuperPaint’s About Box.
 Utilizes the constants kCopyright,
kVersionStr, and kAnnotate. */
/* m_o 09.30.89 */
{
 “  BitMapper takes ‘snapshots’ of your “
 “active SuperPaint document window and “
 “turns them into ‘BTMP’ resources “
 “which it places on the clipboard.  “
 “It also places a ‘PICT’ copy of the “
 “selection on the clipboard so that “
 “you can see what the ‘BTMP’ looks “
 “like.\n”
 “  The ‘BTMP’ resource type consists “
 “of a BitMap data structure followed “
 “by a bit image.  “
 “The baseAddr field of the saved “
 “resource is set to Nil.  “
 “The bounds field is set to a “
 “rectangle the size of the selection “
 “rectangle with its top left corner “
 “set to (0,0).  “
 “RowBytes is the actual width of the “
 “selection (in bytes), rounded up “
 “to an even width if necessary.  “
 “The actual bit image then follows.\n”
 “  For details on using ‘BTMP’ “
 “resources, see Mike Scanlin’s article “
 “in MacTutor magazine.\n”
 “  Please send comments to: Michael “
 “Ogawa, 619-224-3058, 619-721-7000 “
 “(Palomar Software), or AppleLink “
 ““M.O”.\n\n”
 “BitMapper by \n”
 “  Michael Ogawa\n”
 “Special thanks to \n”
 “  Dana Gregory\n”
 “  Linda McClennan\n”
 “  Mike Scanlin\n\n”
 “Copyright © 1989 Michael Ogawa -- All “
 “Rights Reserved.\n”
 “May not be redistributed for “
 “commercial purposes.  May be freely “
 “distributed on electronic bulletin “
 “boards provided no additional charges “
 “above the board’s standard connect “
 “charges are imposed.  May be freely “
 “distributed by non-profit “
 “organizations on disk provided that “
 “any charges for the distribution disk “
 “does not exceed actual disk, “
 “labelling materials, reproduction, “
 “and shipping charges incurred by the “
 “organization.\n”
 “This software is provided “as is”, “
 “with no warranties, either express or “
 “implied, being made regarding its “
 “fitness for any particular purpose.\n”
 “v1.00”
};

resource ‘vers’ (1, purgeable)
/* Finder “get info” resource providing
version information about our plug-in menu
command to the user. */
/* m_o 11.13.89 */
{
 0x01,
 0x00,
 release,
 0x00,
 verUs,
 “1.00”,
 “1.00 (US), © 1989 Michael Ogawa”
};

/* ======================================= *

To create the second example with a hierarchical sub-menu, make the following changes:

Add the following definitions to the end of the constants section in BitMapperRsrc.h:

#define kMENU_BitMapper   200
#ifndef REZ
enum {
 kMITEM_BTMP= 1, /* BTMP */
 kMITEM_BTMN/* BTM# */
};
#endif REZ
/* Menu ID and item numbers for our
sub-menu.  Menu IDs in the range of 0-235
are reserved for applications to use for
sub-menus, SuperPaint reserves the sub-range
of 200-235 for plug-ins. */
/* m_o 11.13.89 */

Add the following definitions to the end of the data types section in BitMapperRsrc.h:

#ifndef REZ
typedef struct {
 short  szEntry;
 TBTMP  theBTMP;
} TBTMNEntry, *TBTMNEntryPtr;
#endif REZ
/* An entry in the ‘BTM#’ resource data
type consists of a field containing the size
of the entry in bytes, followed by the ‘BTMP’
resource data.
 Note that you may want to change the
szEntry field to type Size to deal with very
large bit images. */
/* mps 06.22.89/m_o 11.17.89 */

#ifndef REZ
typedef struct {
 short  count;
 TBTMNEntry theBTMNEntries[];
} *TBMPN, *TBTMNPtr, **TBTMNHndl;
#endif REZ
/* The ‘BTM#’ resource data type consists
of a field indicating the number of entries
in the resource, followed by the entries. */
/* mps 06.22.89/m_o 11.13.89 */

Change the function DoIt() in BitMapper_main.c to:

static short DoIt(TBitMapperPtr pMyInfo)
/* Makes a ‘BTMP’ or ‘BTM#’ resource and a
picture from the selection area our command
is working with, then outputs the resources.
PMyInfo is a pointer to a BitMapper record
containing information about currently
executing command.  All its fields should be
filled in on entry, except the drawGptr field
which this routine fills in.  (The drawGptr
field is a grafPtr to the document port,
which is also the current port.)
 The menuItem field of the menu command
data record specified by the BitMapper record
specifies whether to create a ‘BTMP’ or ‘BTM#’
resource.
 If no error occured then the result code
noErr is returned as the function return
value; otherwise an appropriate Operating
System result code is returned as the
function return value. */
/* m_o 11.17.89 */
{
 short result;

 GetPort(&pMyInfo->drawGptr);
 if ((result = OpenOutput(pMyInfo)) == noErr) {
 short result2;

 result =
 (pMyInfo->pToolInfo->menuItem
 == kMITEM_BTMP) ?
 PutBTMP(pMyInfo) :
 PutBTMN(pMyInfo);
 if ((result2 = PutPICT(pMyInfo)) !=
 noErr && result == noErr)
 result = result2;
 }
 return(result);
}

Add the function PutBTMN() between PutBTMP() and DoIt() in BitMapper_main.c:

static short PutBTMN(TBitMapperPtr pMyInfo)
/* Makes a ‘BTM#’ resource from the
selection area our command is working with,
then outputs the resource.  PMyInfo is a
pointer to a BitMapper record containing
information about the currently executing
command.  This includes a grafPtr to the
document port (which is also the current
port).
 Before calling us, SuperPaint has
already set the port’s portRect to be
equivalent to the selection bounding
rectangle in a coordinate system local to the
selection.  That is, portRect.topLeft is
(0,0), portRect.bottom is equal to the height
of the selection area, and portRect.right is
equal to the width of the selection area.
 If no error occured then the result code
noErr is returned as the function return
value; otherwise an appropriate Operating
System result code is returned as the
function return value. */
/* m_o 11.17.89 */
{
 long sz;
 short result;
 BitMap myMap;
 TBTMNHndl hMyBTMN;
 TBTMNEntryPtr pMyBTMNEntry;

 /* set up BitMap: init baseAddr  */
 myMap.baseAddr = NULL;
 /* get bounds rectangle  */
 myMap.bounds =
 pMyInfo->drawGptr->portRect;
 /* calc rowBytes  */
 myMap.rowBytes =
 BITS2ROWBYTES(WIDTH(myMap.bounds));
 /* calc size of ‘BTMP’ resource  */
 sz = sizeof(TBTMP) +
 myMap.bounds.bottom *
 myMap.rowBytes;

 /* get ‘clean’ memory for new
    ‘BTM#’ resource  */
 if (!(hMyBTMN =
 (TBTMNHndl)NewHandleClear(sz +
 sizeof((**hMyBTMN).count) +
 sizeof((**hMyBTMN).
 theBTMNEntries[0].szEntry))))
 return(MemError());

 /* number of BTMP entries  */
 (**hMyBTMN).count = 1;
 /* lock, get pointer to entry  */
 MoveHHi((Handle)hMyBTMN);
 HLock((Handle)hMyBTMN);
 pMyBTMNEntry =
 (**hMyBTMN).theBTMNEntries;
 /* size of the BTM# entry  */
 pMyBTMNEntry->szEntry =
 sizeof(pMyBTMNEntry->szEntry) + sz;
 /* copy BitMap  */
 pMyBTMNEntry->theBTMP.map = myMap;
 /* copy bit image  */
 CopyBits2Buffer(
 &pMyInfo->drawGptr->portBits,
 &myMap.bounds,
 (Ptr)pMyBTMNEntry->theBTMP.image,
 myMap.rowBytes, srcCopy);
 HUnlock((Handle)hMyBTMN);

 /* ship it! */
 result = DoOutput((Handle)hMyBTMN,
 ‘BTM#’, pMyInfo);

 /* clean up and leave  */
 DisposHandle((Handle)hMyBTMN);
 return(result);
}

Add the following resource to BitMapper.r:

resource ‘MENU’ (16000, purgeable)
/* Hierarchical sub-menu. */
/* m_o 11.17.89 */
{
 kMENU_BitMapper,
 textMenuProc,
 allEnabled,
 enabled,
 “BitMapper”,
 { /* array: 2 elements */
 /* [1] kMITEM_BTMP */
 “BTMP”, noIcon, noKey, noMark,
 plain,
  /* [2] kMITEM_BTMN */
 “BTM#”, noIcon, noKey, noMark,
 plain
 }
};

Change the ‘TEXT’ and ‘vers’ resources in BitMapper.r to:

data ‘TEXT’ (kOrigBaseID, “about”, purgeable)
/* Provides information about BitMapper to
the user from within SuperPaint’s About Box.
 Utilizes the constants kCopyright,
kVersionStr, and kAnnotate. */
/* m_o 09.30.89 */
{
 “  BitMapper takes ‘snapshots’ of your “
 “active SuperPaint document window and “
 “turns them into ‘BTMP’ or ‘BTM#’ “
 “resources which it places on the “
 “clipboard.  It also places a ‘PICT’ “
 “copy of the selection on the “
 “clipboard so that you can see what “
 “the ‘BTMP’ or ‘BTM#’ looks like.\n”
 “  The ‘BTMP’ resource type consists “
 “of a BitMap data structure followed “
 “by a bit image.  “
 “The baseAddr field of the saved “
 “resource is set to Nil.  “
 “The bounds field is set to a “
 “rectangle the size of the selection “
 “rectangle with its top left corner “
 “set to (0,0).  “
 “RowBytes is the actual width of the “
 “selection (in bytes), rounded up “
 “to an even width if necessary.  “
 “The actual bit image then follows.\n”
 “  The ‘BTM#’ resource type consists “
 “of a list of ‘BTMP’ resources.  “
 “It begins with an INTEGER count field “
 “indicating how many ‘BTMP’ entries “
 “are in the resource.  “
 “Then, each entry consists of an “
 “INTEGER szEntry field and a ‘BTMP’.  “
 “The szEntry field gives the size, in “
 “bytes, of the entry.  “ 
 “That is, the size of the ‘BTMP’ “
 “resource for the entry plus two (the “
 “size of the INTEGER szEntry field).  “
 “This makes it easy to quickly walk “
 “through the ‘BTM#’ to get to the “
 “indexed ‘BTMP’ entry that you are “
 “interested in.\n”
 “  For details on using ‘BTMP’ and “
 “‘BTM#’ resources, see Mike Scanlin’s “
 “article in MacTutor magazine.\n”
 “  Please send comments to: Michael “
 “Ogawa, 619-224-3058, 619-721-7000 “
 “(Palomar Software), or AppleLink “
 ““M.O”.\n\n”
 “BitMapper by \n”
 “  Michael Ogawa\n”
 “Special thanks to \n”
 “  Dana Gregory\n”
 “  Linda McClennan\n”
 “  Mike Scanlin\n\n”
 “Copyright © 1989 Michael Ogawa -- All “
 “Rights Reserved.\n”
 “May not be redistributed for “
 “commercial purposes.  May be freely “
 “distributed on electronic bulletin “
 “boards provided no additional charges “
 “above the board’s standard connect “
 “charges are imposed.  May be freely “
 “distributed by non-profit “
 “organizations on disk provided that “
 “any charges for the distribution disk “
 “does not exceed actual disk, “
 “labelling materials, reproduction, “
 “and shipping charges incurred by the “
 “organization.\n”
 “This software is provided “as is”, “
 “with no warranties, either express or “
 “implied, being made regarding its “
 “fitness for any particular purpose.\n”
 “v2.00”
};

resource ‘vers’ (1, purgeable)
/* Finder “get info” resource providing
version information about our plug-in menu
command to the user. */
/* m_o 11.13.89 */
{
 0x02,
 0x00,
 release,
 0x00,
 verUs,
 “2.00”,
 “2.00 (US), © 1989 Michael Ogawa”
};

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Latest Forum Discussions

See All

Amikin Survival opens for pre-orders on...
Join me on the wonderful trip down the inspiration rabbit hole; much as Palworld seemingly “borrowed” many aspects from the hit Pokemon franchise, it is time for the heavily armed animal survival to also spawn some illegitimate children as Helio... | Read more »
PUBG Mobile teams up with global phenome...
Since launching in 2019, SpyxFamily has exploded to damn near catastrophic popularity, so it was only a matter of time before a mobile game snapped up a collaboration. Enter PUBG Mobile. Until May 12th, players will be able to collect a host of... | Read more »
Embark into the frozen tundra of certain...
Chucklefish, developers of hit action-adventure sandbox game Starbound and owner of one of the cutest logos in gaming, has released their roguelike deck-builder Wildfrost. Created alongside developers Gaziter and Deadpan Games, Wildfrost will... | Read more »
MoreFun Studios has announced Season 4,...
Tension has escalated in the ever-volatile world of Arena Breakout, as your old pal Randall Fisher and bosses Fred and Perrero continue to lob insults and explosives at each other, bringing us to a new phase of warfare. Season 4, Into The Fog of... | Read more »
Top Mobile Game Discounts
Every day, we pick out a curated list of the best mobile discounts on the App Store and post them here. This list won't be comprehensive, but it every game on it is recommended. Feel free to check out the coverage we did on them in the links below... | Read more »
Marvel Future Fight celebrates nine year...
Announced alongside an advertising image I can only assume was aimed squarely at myself with the prominent Deadpool and Odin featured on it, Netmarble has revealed their celebrations for the 9th anniversary of Marvel Future Fight. The Countdown... | Read more »
HoYoFair 2024 prepares to showcase over...
To say Genshin Impact took the world by storm when it was released would be an understatement. However, I think the most surprising part of the launch was just how much further it went than gaming. There have been concerts, art shows, massive... | Read more »
Explore some of BBCs' most iconic s...
Despite your personal opinion on the BBC at a managerial level, it is undeniable that it has overseen some fantastic British shows in the past, and now thanks to a partnership with Roblox, players will be able to interact with some of these... | Read more »
Play Together teams up with Sanrio to br...
I was quite surprised to learn that the massive social network game Play Together had never collaborated with the globally popular Sanrio IP, it seems like the perfect team. Well, this glaring omission has now been rectified, as that instantly... | Read more »
Dark and Darker Mobile gets a new teaser...
Bluehole Studio and KRAFTON have released a new teaser trailer for their upcoming loot extravaganza Dark and Darker Mobile. Alongside this look into the underside of treasure hunting, we have received a few pieces of information about gameplay... | Read more »

Price Scanner via MacPrices.net

14-inch M3 MacBook Pro with 16GB of RAM avail...
Apple has the 14″ M3 MacBook Pro with 16GB of RAM and 1TB of storage, Certified Refurbished, available for $300 off MSRP. Each MacBook Pro features a new outer case, shipping is free, and an Apple 1-... Read more
Apple M2 Mac minis on sale for up to $150 off...
Amazon has Apple’s M2-powered Mac minis in stock and on sale for $100-$150 off MSRP, each including free delivery: – Mac mini M2/256GB SSD: $499, save $100 – Mac mini M2/512GB SSD: $699, save $100 –... Read more
Amazon is offering a $200 discount on 14-inch...
Amazon has 14-inch M3 MacBook Pros in stock and on sale for $200 off MSRP. Shipping is free. Note that Amazon’s stock tends to come and go: – 14″ M3 MacBook Pro (8GB RAM/512GB SSD): $1399.99, $200... Read more
Sunday Sale: 13-inch M3 MacBook Air for $999,...
Several Apple retailers have the new 13″ MacBook Air with an M3 CPU in stock and on sale today for only $999 in Midnight. These are the lowest prices currently available for new 13″ M3 MacBook Airs... Read more
Multiple Apple retailers are offering 13-inch...
Several Apple retailers have 13″ MacBook Airs with M2 CPUs in stock and on sale this weekend starting at only $849 in Space Gray, Silver, Starlight, and Midnight colors. These are the lowest prices... Read more
Roundup of Verizon’s April Apple iPhone Promo...
Verizon is offering a number of iPhone deals for the month of April. Switch, and open a new of service, and you can qualify for a free iPhone 15 or heavy monthly discounts on other models: – 128GB... Read more
B&H has 16-inch MacBook Pros on sale for...
Apple 16″ MacBook Pros with M3 Pro and M3 Max CPUs are in stock and on sale today for $200-$300 off MSRP at B&H Photo. Their prices are among the lowest currently available for these models. B... Read more
Updated Mac Desktop Price Trackers
Our Apple award-winning Mac desktop price trackers are the best place to look for the lowest prices and latest sales on all the latest computers. Scan our price trackers for the latest information on... Read more
9th-generation iPads on sale for $80 off MSRP...
Best Buy has Apple’s 9th generation 10.2″ WiFi iPads on sale for $80 off MSRP on their online store for a limited time. Prices start at only $249. Sale prices for online orders only, in-store prices... Read more
15-inch M3 MacBook Airs on sale for $100 off...
Best Buy has Apple 15″ MacBook Airs with M3 CPUs on sale for $100 off MSRP on their online store. Prices valid for online orders only, in-store prices may vary. Order online and choose free shipping... Read more

Jobs Board

Sublease Associate Optometrist- *Apple* Val...
Sublease Associate Optometrist- Apple Valley, CA- Target Optical Date: Mar 22, 2024 Brand: Target Optical Location: Apple Valley, CA, US, 92307 **Requisition Read more
Early Preschool Teacher - Glenda Drive/ *Appl...
Early Preschool Teacher - Glenda Drive/ Apple ValleyTeacher Share by Email Share on LinkedIn Share on Twitter Read more
Retail Assistant Manager- *Apple* Blossom Ma...
Retail Assistant Manager- APPLE BLOSSOM MALL Brand: Bath & Body Works Location: Winchester, VA, US Location Type: On-site Job ID: 04225 Job Area: Store: Management Read more
Housekeeper, *Apple* Valley Village - Cassi...
Apple Valley Village Health Care Center, a senior care campus, is hiring a Part-Time Housekeeper to join our team! We will train you for this position! In this role, Read more
Sonographer - *Apple* Hill Imaging Center -...
Sonographer - Apple Hill Imaging Center - Evenings Location: York Hospital, York, PA Schedule: Full Time Sign-On Bonus Eligible Remote/Hybrid Regular Apply Now See Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.