TweetFollow Us on Twitter

Icon Stuffing
Volume Number:7
Issue Number:7
Column Tag:HyperChat

Related Info: Quickdraw Resource Manager

Icon Stuffing XCMD

By Steven Fuchs, Stony Brook, NY

iConjured Up

Last year at a meeting of LIMUG, the Long Island Mac Users Group I was introduced to a very useful utility stack called iConjurer by Tom Wimbish, which as the name would suggest is a tool for creating icons. What iConjuror provides is an environment from which the powerful painting tools contained in HyperCard can be used to create icon sized pictures as well as a convenient method of storing them. iConjuror’s shortcoming was that it provided no direct way to convert the pictures HyperCard created into ICON resources. The workaround for this was to copy the image of the icon onto the clipboard and then launch ResEdit, open the requested stack and paste the picture into ResEdits ICON editor, which would convert the first 32 pixels in each of the first 32 rows into an icon. Although once committed to muscular memory this process could be accomplished quickly, it was decidedly un-Mac like, in other words there had to be a better way. I decided that what was needed was an XCMD which could take the image of an icon and create an ICON resource, either in the current stack or in any desired stack. Hence the impetus behind the creation of the IconStuffer XCMD.

Working Overview

When a picture doesn’t tell a story

The first order of business was to make the data of the selected picture available to the XCMD. While some sleuthing into HyperCards inner workings probably could produce a direct method of obtaining the contents of the selection rectangle this is undesirable for some very good reasons. In general it is by far the more difficult task, and in any programming, Mac programming especially and XCMD programing even more so you should always look to avoid trouble. Secondly a method of this sort would almost certainly not work with a different version of HyperCard and may not even work between different machines. Therefore I chose to take the easier path and obtain this information from the clipboard, after forcing the user to copy the image of the icon. However easier does not mean easy, and accessing the clipboard for the icons image is no exception. The clipboard stores its images in the form of a ‘PICT’ resource, Inside Macintosh tells us that the format for a ‘PICT’ resource consists of the QuickDraw calls necessary to recreate the image. The ‘ICON’ resource is simply a series of 1024 bits, the ones and zeros of which represent the black and white pixels of the icons 32x32 rectangle. While much time could have been spent decoding the ins and outs of ‘PICT’ resources and learning how to convert these to icons, a much easier mechanism exists. All that is involved is pulling a bit of a fast one on the operating system and QuickDraw.

Now You See It

All QuickDraw drawing takes place into a data structure known as a GrafPort. When you create a window unbeknownst to you, you are creating a GrafPort. While the Mac OS allows for the creation of GrafPorts on their own it is rarely used, and I will not do that. What I do need to recreate is an important record of the GrafPort called portBits. The portBits record is a bitmap which is the destination of all drawing by the GrafPort.

This bitmap contains the ones and zeros which make up the black and white pixels of the GrafPort in question. It is this data which can easily be converted into an ‘ICON’ resource. The important record in the bitmap is the BufferAddr record, which is a pointer to the location at which the bits that make up the image begin. The QuickDraw sleight of hand I used was to create my own bitmap and fool the GrafPort into drawing into it. The data is now in a form suitable to my purposes and is ready to be made into an icon.

Step by Step

Take a picture, please

Before proceeding some error checking must be done, I know, boring,boring, boring. What must be, must be however and the first form of this takes place in the function FillIconPointer. Using the toolbox function GetScrap we will determine whether or not there is a ‘PICT’ resource on the clipboard at all. This is done by passing a handle of arbitrary size, and telling it I would like the available ‘PICT’ resource only. The function returns the size of the resource as well as resizing the handle and copying the ‘PICT’ resource into it.

If there was a ‘PICT’ resource in the scrap I need to allocate the memory necessary for the icon. Since I know an ‘ICON’ measures 32x32 I am spared the step of figuring out the size of the necessary bitmap. The space of the bitmap is allocated using the NewPointer function. Since NewPointer accepts its size parameter in bytes and not bits, and there are 8 bits in a byte, the size of the pointer should be 32x32/8 or 128. I allocate this into the pointer BufferAddress and in a fit of safety consciousness, check to be sure the allocation succeeded. Assuming that it did, I then assign the remaining records of the structure OffMap. Record 1 of a bitmap, baseAddr is a pointer to the address at which the bitmap image starts. Record 2 of a bitmap is rowBytes, or the number of bytes wide the image is to be. Since an ICON is a fixed size I know that this value will always be 32/8 or 4. In some other circumstance I would compute rowBytes by dividing the width of the bit image by 8. Also an important note is that the Mac operating system requires that all addresses be even, so to avoid a deadly crash the value for rowBytes must always be even. Finally we set bounds, which is the rectangle which encloses our bitmap or 32 x 4.

Now that we are fully prepared to fool QuickDraw only a few more precautions remain. First and foremost is to remember the bitmap currently stored in portBits so as to return things to their original state upon completion, very important for the XCMD programmer. I obtain the existing portBits by calling GetPort and storing the value of portBits into the variable OldMap. Then I use the toolbox call SetPortBits to reassign any subsequent drawing in that GrafPort to my bitmap. I then call ClipRect to insure that the entire image is drawn and EraseRect in order to clear any existing bits from the BitMap. Then a simple call to DrawPicture will allow QuickDraw to fill in the proper pixels of my bitmap for me. Finally a call to SetPortBits again will restore the GrafPorts portBits, dispose of the handle to the PICT resource, and return as the result of FillIconPointer the address at which the bitmap image of the icon begins.

How a bitmap becomes an ICON

The path to creating an ICON resource now becomes very simple since I now have the data in the form I want it. Most of this remaining work takes place in the function CreateNewIcon . First I create a handle of size 128, the fixed size of an icon. A handle is necessary since the toolbox call AddResource demands a handle aand must be used to attach a resorce to the resource file. I then invoke the toolbox call BlockMove to copy the data from the bitmaps pointer to the handle. With the handle now prepared call AddResource which attaches the handle to the resource fork and WriteResource which makes it final by saving the resource to disk. Finally release the memory used by the icon. Congratulations! You have just made an icon.

Selective Stuffing

IconStuffer can act in one of two modes, simple and difficult. Simple mode is activated when IconStuffer is called with no parameters. It simply jams its new ICON resource into the current resource file, which in my case is the iConjuror stack. This is the default response and requires no additional action to bring about. The complex mode is induced when IconStuffer receives a parameter from HyperCard. IconStuffer expects this parameter to be the full pathname of a file. If a parameter is passed then the function SetResFile is called which accepts a file name and attempts to open a resource file with that name. If there is no file with that name one is created. SetResFile returns the new resource manager reference number. Finally the function CreateNewIcon is called which actually creates the ICON resource and places it in that file, the file is then closed and control returns to HyperCard.

Figure 1: Project File

The Final Steps

Compiling a code resource

For those readers new to the process of compiling a code resource I will provide a short description of this process which is also adequately explained in pages 156-158 of the THINK Users guide. The only items to insure that you use the DRVR runtime lib instead of the default runtime lib, and that the files HyperXCMD and HyperXCMD interface files are included in the project, as shown in Figure 1. The select “Set Project Type” from the project menu, and choose the Code Resource icon. Name the resource IconStuffer, give it any arbitrary number (1120 is used in my example), and set the type to “XCMD”. Now select build Code Resource from the menu and step back. If all goes well you have just created your first, (or yet another) XCMD for HyperCard.

The MenuField concept

My method of calling IconStuffer is through a device known as a MenuField (not my name), the script of which is in Figure 2 . A MenuField is a locked field which responds to mouseups within it depending upon the line clicked in. The first responsibility of a MenuField is to utilize the newfield message. The newfield message is passed to a field upon its being pasted . By trapping this and inserting text into itself the IconStuffer field insures that it will always contain the correct menu choices. Figure 2 contains the script for IconStuffer Field, the newfield handler will add the text “This Stack” into line 1, “Any Stack•” into line 2, and “Choose Stack” into line 3.

The real work is done in the mouseup handler which upon receiving a click determines the line clicked in a takes the proper action. Clicking in line 1 calls the simple mode of IconStuffer, adding the icon to the current stack. Clicking in line 3 pulls a bit of a trick on HyperCard. Sending HyperCard the message go to “the target stack” will cause HyperCard prompt the user for a stack with the prompt “Help find the target stack”.

This flawed logic however will break if the user has a stack named “the target stack”. By choosing a phrase the would not often be used for a stack name this HyperCard trick can be used with success. As a precaution before using this get the long name of the current stack, and afterwards check to be certain that they are not identical. If they are identical you should assume that the user clicked on the cancel button , not selecting a stack. In this case the Mac like thing to do is to abort the operation of the script in as graceful a method as possible.

If the stack names are different then return to the starting point bringing the long name of the target stack with you. This will be in the form of “stack “StartUp:HyperCard:Utilities:IconBox”” for a stack named IconBox. simply remove the word stack, and the opening and closing quotes, this information is ready for passing to IconStuffer. This is what occurs when a user clicks on line 3 of the MenuField or optionclicks on line 2. The different is that an optionclick in line 2 of the MenuField stores the long name of the target stack in line 10 of the field and the short name of the stack in line 2. Subsequent clicks in line 2 of the field will utilize line 10 to paste the icon into that specified file.

--1

on newfield
  Put "This Stack"&return&"Any Stack"&return&"Choose Stack" into me
end newfield

on mouseup
  Put trunc((item 2 of the clickloc-item 2 of the rect of me)¬
  /textheight of me)+1 into LineHit
  if LineHit is 1 then IconStuffer
  else if (the optionkey is down and LineHit is 2) or LineHit is 3 ¬
  or (line 10 of me is empty and LineHit is 2) then
    push card
    Lock Screen
    go to stack "the target stack"
    put the long name of this stack into LName
    delete word 1 of LName
    delete char 1 of LName
    delete last char of LName
    put the short name of this stack into SName
    pop card
    unlock screen
    IconStuffer(LName)
    if LineHit is 2 then
      Put SName into line 2 of me
      Put LName into line 10 of me
    end if
  else  IconStuffer(line 10 of me)
end mouseup

Figure 2: HyperTalk Script

In Closing

My sources close to the Heartbeat of Apple have informed me that HyperCard 2.0 would soon be out , and that it contains an icon editor that not only makes iConjuror obsolete, but makes the writing of IconStuffer a waste of time. As of the writing of this article HyperCard 2.0 had not come out and I have not seen its icon editor. Needless to say that if I had heeded the naysayers and not written IconStuffer I would not be using it today, and much the poorer for it. Let that be a lesson to you. Even with impending obsolescence from the belated HyperCard 2.0 (or 2.01, 2.02, 2.03 etc. ) IconStuffer remains a good guide for creating icons from common QuickDraw calls, and for creating offscreen bitmaps. Good Luck and use in Good Health. Hope you enjoy.

unit IconStufferUnit;
interface
 uses
  HyperXCmd;

 procedure MAIN (ParamPtr: XCmdPtr);
implementation

{FillIconPointer accepts no parameters and returns a }
{pointer to the icons bits. The operation is successful }
{if the clipboard contains a PICT resource and the }
{ memory necessary for the ICON can be obtained}
 function FillIconPointer: Ptr;
  var
   HldHandle: handle;
   IconRect: Rect;
   OldPort: GrafPtr;
   err, TheOffset: longint;
   OffMap, OldBits: BitMap;
   BufferAddress: ptr;
 begin
  BufferAddress := nil;
  HldHandle := NewHandle(2);
  err := GetScrap(HldHandle, 'PICT', TheOffset);
  if err > 0 then
   begin
{**The clipboard contained a PICT  **}
    SetRect(IconRect, 0, 0, 32, 32);
    OffsetRect(IconRect, 40, 40);
    BufferAddress := NewPtr(32 * 4);
    if BufferAddress <> nil then
 {**    Memory for the ICON present**}
     begin
 {**    Create offsreen bitmap**}
      OffMap.baseAddr := BufferAddress;
      OffMap.rowBytes := 4;
      OffMap.bounds := IconRect;
      GetPort(OldPort);
{**Store previous bitmap  **}
      OldBits := OldPort^.portbits;
{**Draw into our bitmap   **}
      SetPortBits(OffMap);
      ClipRect(IconRect);
      EraseRect(IconRect);
      DrawPicture(PicHandle(HldHandle), IconRect);
{**Restore previous bitmap**}
      SetPortBits(OldBits);
      ClipRect(OldPort^.portRect);
     end;
   end;
{**Dispose of our copy of the scrap**}
  DisposHandle(HldHandle);
{**Return data bits**}
  FillIconPointer := BufferAddress;
 end;

{GetNextEmptyID does just that while insuring that the  }
{ID's under 128 which are reserved are not used!**}
 function GetNextEmptyID: integer;
  var
   Answer: integer;
 begin
  Answer := 0;
  repeat
   Answer := UniqueID('ICON');
  until Answer > 128;
  GetNextEmptyID := Answer;
 end;

{**SetResFile accepts a string as a parameter and  }
{returns the resource manager reference number **}
 function SetResFile (TheName: str255): integer;
  var
   TheAns: integer;
 begin
  TheAns := OpenResFile(TheName);
  if TheAns = -1 then
   begin
    CreateResFile(TheName);
    TheAns := OpenResFile(TheName);
   end;
  SetResFile := TheAns;
 end;

{**CreateNewIcon accepts the data and the ID to }
{ be used and creates the ICON resource.Returning true  }
{if the operation was a success**}
 function CreateNewIcon (TheImage: Ptr; TheID: integer): Boolean;
  var
   TheHandle: handle;
 begin
  CreateNewIcon := false;
{**Allocate space for the ICON**}
  TheHandle := NewHandle(128);
  if TheHandle <> nil then
   begin
    HLock(TheHandle);
{**Copy bits from the pointer to the handle  **}
    BlockMove(TheImage, TheHandle^, 128);
    HUnLock(TheHandle);
{**Convert handle to a resource    **}
    AddResource(TheHandle, 'ICON', TheID, '');
    if ResError = noErr then
     begin
{**Test for success! **}
      CreateNewIcon := true;
{**Force a disk update    **}
      WriteResource(TheHandle);
     end;
   end;
 end;

{**MAIN brings the routines together **}
 procedure MAIN (ParamPtr: XCmdPtr);
  var
   TheData: Ptr;
   TheHandle: handle;
   TheID, OldRes, NewRes: integer;
   TheItem: str255;
 begin
  TheData := FillIconPointer;
  if TheData <> nil then
{**Could data for ICON be obtained **}
   begin
    OldRes := CurResFile;
    NewRes := 0;
    if ParamPtr^.paramCount > 0 then
     begin
{**Should a different file be used **}
      ZeroToPas(ParamPtr, ParamPtr^.params[1]^, TheItem);
      NewRes := SetResFile(TheItem);
{**If so use it  **}
      UseResFile(NewRes);
     end;
    if NewRes <> -1 then
     begin
{**If there was no file error **}
      TheID := GetNextEmptyID;
{**Do the work!  **}
      if not CreateNewIcon(TheData, TheID) then
       SendHCMessage(ParamPtr, 'Answer "Icon could not be created"');
{**Restore resource chain **}
      UseResFile(OldRes);
      if NewRes > 0 then
{**If a file was opened then close it**}
       CloseResFile(NewRes);
      DisposPtr(TheData);
     end
    else
     SendHCMessage(ParamPtr, 'Answer "File was not found"');
   end
  else
   SendHCMessage(ParamPtr, 'Answer "PICT could not be obtained"');
 end;
end.

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

GraphicConverter 10.5.1 - $39.95
GraphicConverter is an all-purpose image-editing program that can import 200 different graphic-based formats, edit the image, and export it to any of 80 available file formats. The high-end editing... Read more
Delicious Library 3.7 - Import, browse a...
Delicious Library allows you to import, browse, and share all your books, movies, music, and video games with Delicious Library. Run your very own library from your home or office using our... Read more
Adobe Animate CC 2017 18.0.0.107 - Anima...
Animate CC 2018 is available as part of Adobe Creative Cloud for as little as $19.99/month (or $9.99/month if you're a previous Flash Professional customer). Animate CC 2018 (was Flash CC) lets you... Read more
Adobe After Effects CC 2018 15.0 - Creat...
After Effects CC 2018 is available as part of Adobe Creative Cloud for as little as $19.99/month (or $9.99/month if you're a previous After Effects customer). The new, more connected After Effects CC... Read more
Adobe Premiere Pro CC 2018 12.0.0 - Digi...
Premiere Pro CC 2018 is available as part of Adobe Creative Cloud for as little as $19.99/month (or $9.99/month if you're a previous Premiere Pro customer). Adobe Premiere Pro CC 2018 lets you edit... Read more
Alarm Clock Pro 10.3 - $19.95
Alarm Clock Pro isn't just an ordinary alarm clock. Use it to wake you up in the morning, send and compose e-mails, remind you of appointments, randomize the iTunes selection, control an internet... Read more
Adobe Lightroom 20170919-1412-ccb76bd] -...
Adobe Lightroom is available as part of Adobe Creative Cloud for as little as $9.99/month bundled with Photoshop CC as part of the photography package. Lightroom 6 is also available for purchase as a... Read more
Adobe Illustrator CC 2018 22.0.0 - Profe...
Illustrator CC 2018 is available as part of Adobe Creative Cloud for as little as $19.99/month (or $9.99/month if you're a previous Illustrator customer). Adobe Illustrator CC 2018 is the industry... Read more
Hopper Disassembler 4.3.0- - Binary disa...
Hopper Disassembler is a binary disassembler, decompiler, and debugger for 32- and 64-bit executables. It will let you disassemble any binary you want, and provide you all the information about its... Read more
Adobe InDesign CC 2018 13.0.0.125 - Prof...
InDesign CC 2018 is available as part of Adobe Creative Cloud for as little as $19.99/month (or $9.99/month if you're a previous InDesign customer). Adobe InDesign CC 2018 is part of Creative Cloud.... Read more

ICEY (Games)
ICEY 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: ICEY is a 2D side-scrolling action game. As you follow the narrator's omnipresent voice, you will see through ICEY's eyes and learn the... | Read more »
The best new games we played this week -...
We've made it, folks. Another weekend is upon us. It's time to sit back and relax with the best new releases of the week. Puzzles, strategy RPGs, and arcade games abound this week. There's a lot of quality stuff to unpack this week, so let's hop... | Read more »
Wheels of Aurelia (Games)
Wheels of Aurelia 1.0.1 Device: iOS Universal Category: Games Price: $3.99, Version: 1.0.1 (iTunes) Description: | Read more »
Halcyon 6: Starbase Commander guide - ti...
Halcyon 6 is a well-loved indie RPG with stellar tactical combat and some pretty good writing, too. It's now landed on the App Store, so mobile fans, if you're itching for a good intergalactic adventure, here's your game. Being a strategy RPG, the... | Read more »
Game of Thrones: Conquest guide - how to...
Fans of base building games might be excited to know that yet another entry in the genre has materialized - Game of Thrones: Conquest. Yes, you can now join the many kingdoms of the famed book series, or create your own, as you try to conquer... | Read more »
Halcyon 6: Starbase Commander (Games)
Halcyon 6: Starbase Commander 1.4.2.0 Device: iOS Universal Category: Games Price: $6.99, Version: 1.4.2.0 (iTunes) Description: An epic space strategy RPG with base building, deep tactical combat, crew management, alien diplomacy,... | Read more »
Legacy of Discord celebrates its 1 year...
It’s been a thrilling first year for fans of Legacy of Discord, the stunning PvP dungeon-crawling ARPG from YOOZOO Games, and now it’s time to celebrate the game’s first anniversary. The developers are amping up the festivities with some exciting... | Read more »
3 reasons to play Thunder Armada - the n...
The bygone days of the Battleship board game might have past, but naval combat simulators still find an audience on mobile. Thunder Armada is Chinese developer Chyogames latest entry into the genre, drawing inspiration from the explosive exchanges... | Read more »
Experience a full 3D fantasy MMORPG, as...
Those hoping to sink their teeth into a meaty hack and slash RPG that encourages you to fight with others might want to check out EZFun’s new Eternity Guardians. Available to download for iOS and Android, Eternity Guardians is an MMORPG that lets... | Read more »
Warhammer Quest 2 (Games)
Warhammer Quest 2 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: Dungeon adventures in the Warhammer World are back! | Read more »

Price Scanner via MacPrices.net

Save $100 on 13″ MacBook Airs, prices start a...
Adorama has 2017 13″ MacBook Airs on sale today for $100 off MSRP including free shipping. Adorama charges NY & NJ sales tax only: – 13″ 1.8GHz/128GB MacBook Air (MQD32LL/A): $899, $100 off MSRP... Read more
1.4GHz Mac mini available for $399, $100 off...
TigerDirect has the 1.4GHz Mac mini on sale today for $399 including free shipping. Their price is $100 off MSRP, and it’s the lowest price available for this model. Although currently out of stock,... Read more
21″ 2.3GHz iMac on sale for $999, save $100
MacMall has the 21″ 2.3GHz iMac (MMQA2LL/A) on sale today for $999 including free shipping. Their price is $100 off MSRP, and it’s the lowest price available for this model. Read more
12″ iPad Pros on sale for $50 off MSRP, no ta...
Adorama has 12″ iPad Pros on sale today for $50 off MSRP. Shipping is free, and Adorama charges sales tax in NY & NJ only: – 12″ 64GB iPad Pro: $749, save $50 – 12″ 256GB iPad Pro: $899, save $50... Read more
9″ iPads on sale for $30 off, starting at $29...
MacMall has 9″ iPads on sale for $30 off including free shipping: – 9″ 32GB iPad: $299 – 9″ 128GB iPad: $399 Read more
Apple restocks full line of refurbished 13″ M...
Apple has restocked a full line of Apple Certified Refurbished 2017 13″ MacBook Pros for $200-$300 off MSRP. A standard Apple one-year warranty is included with each MacBook, and shipping is free.... Read more
13″ 3.1GHz/256GB MacBook Pro on sale for $167...
Amazon has the 2017 13″ 3.1GHz/256GB Space Gray MacBook Pro on sale today for $121 off MSRP including free shipping: – 13″ 3.1GHz/256GB Space Gray MacBook Pro (MPXV2LL/A): $1678 $121 off MSRP Keep an... Read more
13″ MacBook Pros on sale for up to $120 off M...
B&H Photo has 2017 13″ MacBook Pros in stock today and on sale for up to $120 off MSRP, each including free shipping plus NY & NJ sales tax only: – 13-inch 2.3GHz/128GB Space Gray MacBook... Read more
15″ MacBook Pros on sale for up to $200 off M...
B&H Photo has 15″ MacBook Pros on sale for up to $200 off MSRP. Shipping is free, and B&H charges sales tax in NY & NJ only: – 15″ 2.8GHz MacBook Pro Space Gray (MPTR2LL/A): $2249, $150... Read more
Roundup of Apple Certified Refurbished iMacs,...
Apple has a full line of Certified Refurbished 2017 21″ and 27″ iMacs available starting at $1019 and ranging up to $350 off original MSRP. Apple’s one-year warranty is standard, and shipping is free... Read more

Jobs Board

Engineering Manager, *Apple* Retail Enginee...
# Engineering Manager, Apple Retail Engineering Job Number: 58139948 Santa Clara Valley, California, United States Posted: 20-Oct-2017 Weekly Hours: 40.00 **Job Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
Commerce Engineer, *Apple* Media Products -...
Commerce Engineer, Apple Media Products (New York City) Job Number: 113028813New York City, New York, United StatesPosted: Sep. 20, 2017Weekly Hours: 40.00 Job Read more
US- *Apple* Store Leader Program - Apple (Un...
US- Apple Store Leader Program Job Number: VariousUnited StatesPosted: Oct. 19, 2017Retail Store Job Summary Learn and grow as you explore the art of leadership at Read more
Product Manager - *Apple* Pay on the *Appl...
Job Summary Apple is looking for a talented product manager to drive the expansion of Apple Pay on the Apple Online Store. This position includes a unique Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.