andymatuschak.org: Square Signals

This article was published on Sunday, April 09th, 2006 at 2:20 pm.

Young Dro ringtonesMC Hammer ringtones

Making the HUD, Item 2: Culling Colors and Isolating Images

Setting up F-Script Anywhere

An Important Note: F-Script Anywhere—essential to this tutorial—no longer works on Leopard at the time of this writing.

FSA is pretty much the most important tool of this trade, and it’s important that you’re well aware how to use it. Sadly, installing FSA is a pretty big hassle (maybe I should make a .pkg), so I’ll walk you through the steps.

  1. Download the F-Script Framework.
  2. Extract the archive and copy the framework to ~/Library/Frameworks.
  3. Download F-Script Anywhere (by Ken Ferry, Nicholas Riley’s doesn’t work anymore).
  4. Mount the FSA image.
  5. If you don’t already have SIMBL installed, copy the SIMBL folder from the FSA image to ~/Library/InputManagers (creating that folder if necessary).
  6. Copy FScriptAnywhereSIMBL.bundle from the FSA image to ~/Library/Application Support/SIMBL/Plugins. You’ll probably have to create the intervening folders.
  7. Now you have to activate FSA for the program you’re trying to hack. In this tutorial, we’ll use iPhoto (since you’re more likely to have it), but this works just as well for Aperture.
    • Right-click the installed FScriptAnywhereSIMBL.bundle and Show Package Contents.
    • Open Info.plist in the Contents directory.
    • At the bottom of this property list is the SIMBLApplicationIdentifier array, which contains the identifiers of all the apps that will load FSA.
    • Add a string to the array for com.apple.iPhoto (or whatever).

Alright, that was annoying, but the pain is over; the fun’s about to begin. That’s right: there’s cake at the FSA party.

Open Your Eyes

Launch iPhoto, and check out the menu bar. There’s a new FSA menu. Let’s use it! Go to FSA > New F-Script Workspace. This is a little console that lets you manipulate the application using F-Script, but it’s not very helpful at the moment. Let’s examine some HUD.

Double-click one of your images and click the Adjust button on the fake iLife toolbar. At the bottom of this window is our target:

Reset Sliders Button

Go to the F-Script workspace you made earlier and click New Object Browser. Click the Select View in the object browser’s toolbar and click the Reset Sliders button. Voila! You can view properties of this control and call its methods.

The F-Script Object Browser

A Font-Finding Mission

Here’s an easy first task. We want to replicate the appearance of the text in this button, but what’s the font? Is it different from that of a normal button? We could do some trial-and-error spike work to see, but FSA lets us immediately find the correct answer. Just type “font” into the search field in the toolbar, and you’ll be presented with the answer: Lucida Grande 11pt.

Hijacking Images

Having the font is nice and all, but we really need the button body itself before we can have a good, convincing replica. You could take a screenshot, but since the HUD window is transparent, you wouldn’t get good values. Now, in the case of iPhoto, you could just go into the app bundle’s resources directory, and you’d find all the source images for the HUD button. But that’s not true of Pro apps, so we’re going to extract sources images from Aperture.

Go back to the FSA Info.plist and add an entry for Aperture. Open it up, open an image, and go to Window > Show Keywords HUD. See the Import button? That’s our target.

Aperture's Import HUD Button

To do this, we’re going to need more than the Object Browser: we’re going to need the full power of F-Script at our fingertips. But to be able to refer to this button in the F-Script environment, we have to associate the interface with a global F-Script variable.

  1. Open an F-Script workspace, then go to FSA > Associate with Interface.
  2. Click the Start Capture button.
  3. Click the Import button, and choose NSProButton.
  4. Click the Stop Capture button.
  5. Type button into the Variable Name field.
  6. Click the Associate button.

The Associate with Interface Window

Before I show you the code for how this is done, I’ll outline our basic strategy. We’re going to make an NSImage, lock it, draw the view, then write the image to file. Pretty easy, really.

Now, if we’re going to make an NSImage for this thing, we need to know how big it is. Go to your Object Browser and find the button’s frame using the technique I discussed earlier. Note that the rects are written with corner coordinates (not sizes) in F-Script, so be careful. It says (112<>5 corner:180<>24), but for an NSRect, that’s { {112, 5}, {68, 19} }. Right, so we’ve got the size: 68×19.

Now go to your F-Script workspace and type these commands in sequence. I’ll discuss the code afterwards:

image := NSImage alloc initWithSize:(NSValue sizeWithWidth:68 height:19)
image lockFocus
button drawRect:(button bounds)
image unlockFocus
image TIFFRepresentation writeToFile:('~/Desktop/Button.tif' stringByExpandingTildeInPath) atomically:NO

A Few Things to Note:

  • The language syntax is pretty much like Smalltalk, if you’re familiar with that.
  • We use a new method on NSValue (sizeWithWidth:height) because we don’t have NSMakeSize: F-Script doesn’t support C functions.
  • Strings use single quotes, as you see in the path.
  • Just like in Cocoa, you’ve got to expand your user-path tildes when writing to file.

So yes, go check out ~/Desktop/Button.tif! If everything went well, you’ll see the fruits of your labor. Just open it up in your favorite image editor (I like Pixen, myself) and slice it up into left, right, and middle chunks for use in your NSButtonCell subclass. Nice.

You’d probably like the other states of the button, too: disabled, and highlighted. They’re simple to get. For the former, type button setEnabled:NO into the F-Script workspace, then repeat the recipe above. For the latter, type button highlight:YES and then extract (remember to re-enable the button first, if you’re doing these states back-to-back).

You can use this technique to extract good images of just about any user interface element from just about any Cocoa program. Pretty useful.

Culling Colors

Sadly, FSA can only go so far. It’s nice to get images of user interface elements, but a lot of the time, you want to draw things yourself: Apple’s moving towards resolution-independent sizes, so it’s definitely good karma to draw with vector, not raster. A lot of the time, it’s easy to find the necessary colors using the two methods I’ve described before. Sometimes, it’s trickier. And that’s when we go hex-diving.

ProKit uses an obfuscated archive called ProThemeBits.car to store all its information in a nice, pretty tree. Included in it are PSDs of user interface elements and color constants. I’ve made only modest progress in extracting the former, but the colors are much simpler. So I have for you an andymatuschak.org exclusive: a method for culling colors from the ProThemeBits.car archive.

First, you’ll need a hex editor. HexFiend is excellent. Pop open /System/Library/PrivateFrameworks/ProKit.framework/Resources/ProThemeBits.car and look around.

Let’s grab our first color: the background color of a HUD window. This is something that could be extracted from FSA, so it seems pointless to grab it this way, but by choosing a known value, we can verify that our method is correct.

Search for the ASCII string (make sure to select ASCII if your hex editor searches hex strings by default): “windowBackgroundHUDColor”. You’ll see that string, followed by a bunch of zeroes. Scan down a few lines, and you’ll find the next color’s name. But eight bytes before that, there’s some meaningful data.

Hex Gold!

Check out the four bytes that read “BF 20 20 20”. These represent the color value for the name preceding them. I’m actually not sure if it’s ABGR or ARGB, but since Pro and HUD colors are pretty much exclusively gray, it doesn’t really matter.

So this tells you that the alpha is BF (191); the red is 20 (32); the green is 20 (32); and the blue is 20 (32).

To summarize! The procedure for reading a color from ProThemeBits.car:

  1. Find the name of the color.
  2. Look down a couple lines to find the next name, then look eight bytes before that.
  3. Here are the four color values stored in ARGB (or maybe ABGR).

The Conversation {2 comments}

  1. Morten Carlsen 21 October, 07 @ 10:26 am

    Hi There,

    first I find what you do really useful and great:-)

    Problem, I cannot find the Associate With Interface menu item ANYWHERE….. I have followed your instruc. and triple checked ‘em. I wanted to analyze the ProKit stuff. Everything else is working but the descrip. to analze Aperture’S import button does not work at all

    Thanks for any feed back

  2. Nicolas Weber 26 November, 07 @ 3:55 am

    Morten: This is now available in F-Script. Select FSA->Browser for target and click the control you want. Then select the topleft-most line in the object browser and click Name. Enter a variable name. After that, you can use this name in FSA->New FScript Workspace.

Leave a Comment

Currently you have JavaScript disabled. In order to post comments, please make sure JavaScript and Cookies are enabled, and reload the page.

You can follow any responses to this entry via its RSS comments feed.

If you're looking for something specific then give the search form below a try:

RSS Wordpress Grady (theme) Return to the Top ↑