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”
};

 
AAPL
$117.60
Apple Inc.
-1.03
MSFT
$47.47
Microsoft Corpora
-0.12
GOOG
$541.08
Google Inc.
+1.81

MacTech Search:
Community Search:

Software Updates via MacUpdate

MacUpdate Desktop 6.0.3 - Discover and i...
MacUpdate Desktop 6 brings seamless 1-click installs and version updates to your Mac. With a free MacUpdate account and MacUpdate Desktop 6, Mac users can now install almost any Mac app on macupdate.... Read more
SteerMouse 4.2.2 - Powerful third-party...
SteerMouse is an advanced driver for USB and Bluetooth mice. It also supports Apple Mighty Mouse very well. SteerMouse can assign various functions to buttons that Apple's software does not allow,... Read more
iMazing 1.1 - Complete iOS device manage...
iMazing (was DiskAid) is the ultimate iOS device manager with capabilities far beyond what iTunes offers. With iMazing and your iOS device (iPhone, iPad, or iPod), you can: Copy music to and from... Read more
PopChar X 7.0 - Floating window shows av...
PopChar X helps you get the most out of your font collection. With its crystal-clear interface, PopChar X provides a frustration-free way to access any font's special characters. Expanded... Read more
Carbon Copy Cloner 4.0.3 - Easy-to-use b...
Carbon Copy Cloner backups are better than ordinary backups. Suppose the unthinkable happens while you're under deadline to finish a project: your Mac is unresponsive and all you hear is an ominous,... Read more
ForeverSave 2.1.3 - Universal auto-save...
ForeverSave auto-saves all documents you're working on while simultaneously doing backup versioning in the background. Lost data can be quickly restored at any time. Losing data, caused by... Read more
Voila 3.8.1 - Capture, annotate, organiz...
Voila is a screen-capture, recording, and annotation tool that is a full-featured replacement for Mac's screen-capture and screen-recording capabilities. It has a large and robust set of editing,... Read more
SyncTwoFolders 2.0.6 - Syncs two user-sp...
SyncTwoFolders simply synchronizes two folders. It supports synchronization across mounted network drives and it is a possibility to run a simulation showing in a log what will be done. Please visit... Read more
Duplicate Annihilator 5.1.1 - Find and d...
Duplicate Annihilator takes on the time-consuming task of comparing the images in your iPhoto library using effective algorithms to make sure that no duplicate escapes. Duplicate Annihilator detects... Read more
HandBrake 0.10.0 - Versatile video encod...
HandBrake is a tool for converting video from nearly any format to a selection of modern, widely supported codecs. Supported Sources: VIDEO_TS folder, DVD image or real DVD (unencrypted -- CSS is... Read more

Latest Forum Discussions

See All

Screeny (Utilities)
Screeny 1.0 Device: iOS iPhone Category: Utilities Price: $.99, Version: 1.0 (iTunes) Description: Screeny is an utility app that helps you save space consumed by screenshots. It screens your camera roll and helps you to filter and... | Read more »
Tilt to Live Bundle Set to Arrive This T...
Tilt to Live Bundle Set to Arrive This Thanksgiving Posted by Ellis Spice on November 25th, 2014 [ permalink ] One Man Left has unveiled an upcoming Tilt to Live bundle, allowing players to get the series for a di | Read more »
BattleLore: Command (Entertainment)
BattleLore: Command 1.0 Device: iOS Universal Category: Entertainment Price: $9.99, Version: 1.0 (iTunes) Description: ***NOTE: Compatible with iPad 2/iPad mini, iPod touch 5 and up and iPhone 4S and up – WILL NOT RUN ON EARLIER... | Read more »
Weather Or Not Review
Weather Or Not Review By Jennifer Allen on November 25th, 2014 Our Rating: :: STYLISH WEATHER REPORTINGiPhone App - Designed for the iPhone, compatible with the iPad Check the weather quickly and conveniently with Weather or Not... | Read more »
The All-New Football Manager Handheld 20...
The All-New Football Manager Handheld 2015 is Available Now Posted by Jessica Fisher on November 25th, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Six iOS Games to Get You Ready for Thank...
Image Source: Friends Wiki At this point in the month, you or at least a few people you know are probably getting ready to scramble around (or are already scrambling around) for Thanksgiving Dinner. It’s a hectic day of precise oven utilization, but... | Read more »
Call of Duty: Heroes: Tips, Tricks, and...
Hello Heroes: What’d we think of Call of Duty‘s take on Clash of Clans? Check out our Call of Duty: Heroes review to find out! Just downloaded Call of Duty: Heroes and need some handy tips and tricks on how to get ahead of the rest? As we often do,... | Read more »
Call of Duty: Heroes Review
Call of Duty: Heroes Review By Jennifer Allen on November 25th, 2014 Our Rating: :: CLASH OF FRANCHISESUniversal App - Designed for iPhone and iPad Mix Clash of Clans with Call of Duty, and this is what you get.   | Read more »
Slider Review
Slider Review By Jordan Minor on November 25th, 2014 Our Rating: :: SLIDE TO PLAYUniversal App - Designed for iPhone and iPad Slider has all the excitement of unlocking your phone screen.   | Read more »
oh my giraffe (Games)
oh my giraffe 1.0.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0.0 (iTunes) Description: Eat fruits while being chased by lions. Cut the vines to send fruit plummeting onto the lions. Don't worry, your flexible... | Read more »

Price Scanner via MacPrices.net

Early Black Friday MacBook Pro sale: 15-inch...
 Best Buy has posted early Black Friday prices on 15″ Retina MacBook Pros, with models on sale for $300 off MSRP on their online store for a limited time. Choose free local store pickup (if available... Read more
A9 Chips Already?
It’s barely more than a couple of months since Apple got the first A8 systems-on-chip into consumer hands, but rumor and news focus is already turning to the next-generation A9 SoC. Apple Daily... Read more
NewerTech Announces NuGuard KXs Impact X-Orbi...
NewerTech has announced updates to its family of Impact X-Orbing Screen Armor bringing military grade, triple layer protection to Apple’s new iPhone 6 and 6 Plus. Like all models in the NuGuard KXs... Read more
13-inch 1.4GHz MacBook Air on sale for $889,...
 B&H Photo has the 13″ 1.4GHz/128GB MacBook Air on sale for $889 including free shipping plus NY tax only. Their price is $110 off MSRP. B&H will also include free copies of Parallels Desktop... Read more
Save up to $300 on Macs and iPads with your A...
Purchase a new Mac or iPad at The Apple Store for Education and take up to $300 off MSRP. All teachers, students, and staff of any educational institution qualify for the discount. Shipping is free,... Read more
Apple refurbished Mac Pros available for up t...
The Apple Store is offering Apple Certified Refurbished Mac Pros for up to $600 off the cost of new models. An Apple one-year warranty is included with each Mac Pro, and shipping is free. The... Read more
Jumptuit Launches One-Tap Windows 8.1 iTunes...
Jumptuit has launched Windows 8.1 support for One-Tap iTunes Sync. with which Windows 8.1 users can now easily sync their iTunes libraries with Microsoft OneDrive. Jumptuit provides easy access from... Read more
Apple restocks refurbished 13-inch 2014 Retin...
The Apple Store has restocked Apple Certified Refurbished 2014 13″ 2.6GHz Retina MacBook Pros for up to $230 off the cost of new models. An Apple one-year warranty is included with each model, and... Read more
CEA Study Finds More People Recycling Electro...
A new study by the Consumer Electronics Association (CEA) finds that electronics recycling receives the continued and growing support of consumers. According to the CEA,s Recycling and Reuse Study,... Read more
15″ 2.2GHz Retina MacBook Pro on sale for $17...
 B&H Photo has the 2014 15″ 2.2GHz Retina MacBook Pro on sale today for $1749. Shipping is free, and B&H charges NY sales tax only. B&H will also include free copies of Parallels Desktop... Read more

Jobs Board

*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
Senior Event Manager, *Apple* Retail Market...
…This senior level position is responsible for leading and imagining the Apple Retail Team's global event strategy. Delivering an overarching brand story; in-store, Read more
*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.