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
$100.86
Apple Inc.
-0.77
MSFT
$46.76
Microsoft Corpora
+0.52
GOOG
$579.95
Google Inc.
+6.85

MacTech Search:
Community Search:

Software Updates via MacUpdate

Capture One Pro 8.0.0.433 - RAW workflow...
Capture One Pro 8 is a professional RAW converter offering you ultimate image quality with accurate colors and incredible detail from more than 300 high-end cameras -- straight out of the box. It... Read more
Adobe Acrobat Pro 11.0.09 - Powerful PDF...
Adobe Acrobat allows users to communicate and collaborate more effectively and securely. Unify a wide range of content in a single organized PDF Portfolio. Collaborate through electronic document... Read more
Adobe Reader 11.0.09 - View PDF document...
Adobe Reader allows users to view PDF documents. You may not know what a PDF file is, but you've probably come across one at some point. PDF files are used by companies and even the IRS to... Read more
iFFmpeg 4.6.1 - Convert multimedia files...
iFFmpeg is a graphical front-end for FFmpeg, a command-line tool used to convert multimedia files between formats. The command line instructions can be very hard to master/understand, so iFFmpeg does... Read more
NTFS 11.3.62 - Provides full read and wr...
Paragon NTFS breaks down the barriers between Windows and OS X. Paragon NTFS effectively solves the communication problems between the Mac system and NTFS, providing full read and write access to... Read more
OS X Yosemite 10.10 DP8 - Developer Prev...
Note: This is a Developer Preview. You must be a registered Apple Mac Developer to download this update. You can also sign up for the free OS X Beta Program to download and preview public beta... Read more
FotoMagico 4.5 - Powerful slideshow crea...
FotoMagico lets you create professional slideshows from your photos and music with just a few, simple mouse clicks. It sports a very clean and intuitive yet powerful user interface. High image... Read more
Screenshot Path 1.2.1 - Change the defau...
Screenshot Path lets you change the folder where OS X saves screenshots. Screenshots are saved by default to the user’s desktop. This is handy for the occasional screenshot but those looking to take... Read more
Fantastical 1.3.16 - Create calendar eve...
Fantastical is the Mac calendar you'll actually enjoy using. Creating an event with Fantastical is quick, easy, and fun: Open Fantastical with a single click or keystroke Type in your event details... Read more
GIMP 2.8.14 - Powerful, free image editi...
GIMP is a multi-platform photo manipulation tool. GIMP is an acronym for GNU Image Manipulation Program. The GIMP is suitable for a variety of image manipulation tasks, including photo retouching,... Read more

Latest Forum Discussions

See All

Zynga Unveils First Look at Looney Tunes...
Zynga Unveils First Look at Looney Tunes Dash! Posted by Ellis Spice on September 16th, 2014 [ permalink ] Be vewy, vewy qwiet. I’m hunting wunners featuwing wabbits, and luckily, it’s duck season wunner season. | Read more »
Guardians on the Go – How to Connect to...
At this point I’m relatively certain most of the country is familiar with Destiny. And for those looking to augment their game a bit, Bungie has changed their Bungie Mobile Companion App to Destiny Companion. | Read more »
Kunin Review
Kunin Review By Jordan Minor on September 16th, 2014 Our Rating: :: SHURIKEN DO ITUniversal App - Designed for iPhone and iPad Kunin is a nervous test of ninja reflexes.   Developer: Dodreams Price: FREE Version Reviewed: 1.0.1... | Read more »
4 KEMCO Titles are Just $0.99 for a Limi...
4 KEMCO Titles are Just $0.99 for a Limited Time Posted by Jessica Fisher on September 16th, 2014 [ permalink ] KEMCO RPGs Destiny Fantasia, Infinite Dunamis, Bonds of the Sk | Read more »
Introducing Flash, the Latest Wearable F...
Introducing Flash, the Latest Wearable Fitness Monitor from Misfit Posted by Jessica Fisher on September 16th, 2014 [ permalink ] The Misfit Flash is the newly-released fitness and sleep monitor from | Read more »
Hyper Trip Review
Hyper Trip Review By Jennifer Allen on September 16th, 2014 Our Rating: :: HYPER TWITCHYUniversal App - Designed for iPhone and iPad Tough and unforgiving, Hyper Trip is a bit like Snake – if Snake was really harsh.   | Read more »
Collectible Card Game Earthcore: Shatter...
Collectible Card Game Earthcore: Shattered Elements is Set to Arrive on iOS in 2015 Posted by Ellis Spice on September 16th, 2014 [ permalink ] Polish developers | Read more »
Boogey Boy Review
Boogey Boy Review By Jennifer Allen on September 16th, 2014 Our Rating: :: PRETTY BUT BASICUniversal App - Designed for iPhone and iPad It looks delightful but lack of Game Center support and more variety really affects the fun... | Read more »
Vizzywig 4K (Photography)
Vizzywig 4K 1.0 Device: iOS iPhone Category: Photography Price: $999.99, Version: 1.0 (iTunes) Description: REQUIRES: iOS 7 on iPhone 5S with 32GB or 64GB. (Do not use iOS 8)The world's FIRST mobile 4K video capture, editing and... | Read more »
The Sleeping Prince Review
The Sleeping Prince Review By Jennifer Allen on September 15th, 2014 Our Rating: :: RESTRICTIVE KINGDOM SAVINGUniversal App - Designed for iPhone and iPad The Sleeping Prince looks and feels great to play, but its lack of peril and... | Read more »

Price Scanner via MacPrices.net

Sprint offers 16GB iPad mini for $199.99 with...
Sprint is offering 1st generation 16GB iPad minis for $199.99 with a 2-year service agreement. Standard MSRP for this iPad is $429. Their price is the lowest available for this model. Read more
2.5GHz Mac mini remains on sale for $549, sav...
B&H Photo has the 2.5GHz Mac mini on sale for $549.99 including free shipping. That’s $50 off MSRP, and B&H will also include a free copy of Parallels Desktop software. NY sales tax only. Read more
Apple refurbished iMacs available for up to $...
The Apple Store has Apple Certified Refurbished iMacs available for up to $300 off the cost of new models. Apple’s one-year warranty is standard, and shipping is free. These are the best prices on... Read more
13″ 2.5GHz MacBook Pro offered for $100 off M...
B&H Photo has the 13″ 2.5GHz MacBook Pro on sale for $999.99 including free shipping plus NY sales tax only. Their price is $100 off MSRP. Read more
Free GIMP Professional Grade Graphics App Ver...
The latest 2.8.14 version of the oddly-named GIMP (acronym for: GNU Image Manipulation Program) open source, high-end image editing and creation alternative to Adobe’s Photoshop and refuge from... Read more
Apple Announces Record Pre-orders for iPhone...
Apple has released metrics showing a record number of first day pre-orders of iPhone 6 and iPhone 6 Plus, with over four million sold in the first 24 hours. Demand for the new iPhones exceeds the... Read more
10% off iPhone 6 and 6 Plus Otterbox cases
Get 10% off on popular Otterbox iPhone 6 and iPhone 6 Plus cases at MacMall through September 19th. Use code OTTERBOX10 to see the discount. Read more
15-inch MacBook Pros on sale for up to $125 o...
Amazon has the new 2014 15″ Retina MacBook Pros on sale for up to $125 off MSRP including free shipping: - 15″ 2.2GHz Retina MacBook Pro: $1899.99 save $100 - 15″ 2.5GHz Retina MacBook Pro: $2374... Read more
27-inch 3.2GHz iMac on sale for $1698, $101 o...
Abt has the 27″ 3.2GHz iMac on sale for $1698 including free shipping. Their price is $101 off MSRP. Read more
More To Making A Larger iPad Than Expanded Sc...
CNET’s Ross Rubin has posted a thoughtful analysis of prospects for a larger display iPad Pro, noting that Microsoft and Samsung currently have the large-display touchscreen tablet category to... Read more

Jobs Board

*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* 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* 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* 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* 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
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.