Archive for December, 2007

Accessing Leopard Frameworks

F-Script.app 2.0 is automatically linked with a number of new frameworks found in Leopard. This is convenient for quickly exploring Leopard's capabilities.

Let me illustrate this on a practical example: I'm currently experimenting with the new Image Kit framework introduced in Leopard. I can launch F-Script.app and directly enter the following code:

IKPictureTaker pictureTaker orderFront:nil

It will activate the IKPictureTaker panel, a component of Image Kit that allows, among other things, browsing images in the file system and taking snapshots from digital camera (including the built-in iSight).

Then, once I've got the image I want, I can get the image objet (an NSImage instance) from the panel with:

IKPictureTaker pictureTaker outputImage

I can also explore the image object in the object browser by typing:

sys browse:IKPictureTaker pictureTaker outputImage

Here is the list of frameworks automatically linked with F-Script.app:

      Framework       Description
Address Book Access to the contacts database
Application Kit User interface
Automator Automator plugin system
Calendar Store Access to the calendar database
Colaboration Identity information management
Core Animation Graphical animation
Core Audio Kit Audio Units custom views
Core Data Data model management (object persistence, etc.)
Core Image Image processing
Core Video Video processing
Disc Recording CD and DVD burning
Disc Recording UI User interface components for CD and DVD burning
Disk Arbitration Hard disk events monitoring and management
Exception Handling Exception handling configuration
Foundation Kit Core services (root class, string handling, collections, networking, file management, threading, etc.)
Image Kit User interface components for image browsing and manipulation
Input Method Kit Input methods management
Instant Message Online status of instant messaging users
IOBluetooth Access to Bluetooth devices
IOBluetooth UI User interface components for access to Bluetooth devices
JavaVM Access to the Java environment
OSA Kit Management and execution of OSA-compliant scripts
PDF Kit PDF handling
PubSub RSS and ATOM handling
QT Kit Rendering and manipulation of QuickTime content
Quartz Composer Access to Quartz Composer compositions
Scripting Bridge Control of scriptable applications
Security Foundation Users authorization
Security Interface User interface components for users authorization
Sync Services Data synchronization between multiples computers and devices
WebKit Web content rendering
Xgrid Foundation Cluster management

You can dynamically load other frameworks or bundles (including yours) using standards Cocoa techniques. For example, the following code loads the SenTesting Kit:

(NSBundle bundleWithPath:'/Developer/Library/Frameworks/SenTestingKit.framework') load

You can also have F-Script automatically load additional frameworks or bundles at launch time by putting them in the F-Script repository. This repository is created by the F-Script.app application when you launch it for the first time. By default it will be ~/Library/Application Support/F-Script (where ~ stands for your home directory). You should put your bundles and frameworks in the ~/Library/Application Support/F-Script/classes directory.

Most constants defined in the Objective-C-based frameworks of Leopard are available in F-Script. I used to rely on my own header scanner for this feature on previous Mac OS X versions, but it was essentially a quick and dirty piece of code done ages ago on a full moon night. I was hoping something better would eventually appear that I could reuse. Well, it’s finally here, in the form of BridgeSupport, a technology developed by Laurent Sansonetti at Apple.

BridgeSupport files are XML files that describe the API symbols of frameworks or libraries that cannot be introspected at runtime. These are generally ANSI C symbols that is, non-object-oriented items such as constants, enumerations, structures, and functions but can also include some additional information about Objective-C classes, methods, and informal protocols.

Thanks to the inclusion of this technology in Leopard, my old code is gone and I rely on BridgeSupport in F-Script 2.0.

Accessing the BridgeSupport XML files has been easy, using Cocoa's NSXML classes. Speaking of NSXML, below is a code snippet that illustrates how it can be used to process XML files with F-Script. We’ll access the BridgeSupport XML file for the Application Kit, and look at the names of the constants therein referenced.

"Define the location of the XML document we want to read"
location := NSURL fileURLWithPath:'/System/Library/Frameworks/AppKit.framework/Versions/C/Resources/BridgeSupport/AppKitFull.bridgesupport'.

"Load the XML document"
xml := NSXMLDocument alloc initWithContentsOfURL: location 
                                         options: NSXMLNodePreserveWhitespace 
                                           error: nil.

"Inspect nodes containing constant's names"
((xml rootElement elementsForName:'constant') attributeForName:'name') inspect.

The inspect message in the last instruction opens the array of selected nodes in the graphical array inspector, shown below:

Read Full Post »

The Web is abuzz with a new Google service: a Web API for creating charts.

The Google Chart API returns a PNG-format image in response to a URL. Several types of image can be generated: line, bar, and pie charts for example. For each image type you can specify attributes such as size, colors, and labels.

Accessing it from Cocoa is easy, as we will interactively experiment using F-Script. In the process we will learn how to call the Google Chart API from Cocoa, how to pass data stored in Cocoa arrays, how to apply special effects using Core Image, and a few other cool things…

Charting "Hello World"

First, let's start with a very simple example, the "Hello World" chart, which is described in the Google Chart API documentation:

To see the Chart API in action, open up a browser window and copy the following URL into it:

Press the Enter or Return key and – presto! – you should see the following image:

The URL contains all the data needed to describe the chart. We'll examine that further, but, for now, let's see how we can generate an NSImage for this chart in Cocoa, using F-Script (note: you can download the F-Script 2.0 alpha here: FScriptSources-2_0_alpha.zip).

Cocoa provides us with the NSURL class to manipulate URLs. We'll use it to retrieve our chart from the Google Chart API and generates an NSImage object. We start by defining an NSString that contains our URL:

chartString := 'http://chart.apis.google.com/chart?cht=p3&chd=s:hW&chs=250x100&chl=Hello|World'.

There is a little caveat: for creating our NSURL object, we need to provide the NSURL class with a percent-escaped URL string. Such a string is easy to generate using the stringByAddingPercentEscapesUsingEncoding: method:

escapedChartString := chartString stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding.

All we have to do now is to instantiate an NSURL object and to create our NSImage using the initWithContentsOfURL: method:

url := NSURL URLWithString:escapedChartString.

image := NSImage alloc initWithContentsOfURL:url.

That's it. The initWithContentsOfURL: method takes care of issuing the HTTP request and to initialize our newly allocated NSImage instance with the result. To look at our image, we can send it the inspect message. It opens an inspector that displays the image in a window:

image inspect

Or we can directly use a Cocoa drawing method. For example:

image compositeToPoint:10<>10 operation:NSCompositeSourceOver

Of course, we can directly copy and paste all the code shown here in the F-Script shell, in order to interactively experiment with it. Here is what our F-Script session may look like:

As with any Cocoa object, we can further explore our NSImage object with the object browser:

sys browse:image

Charting our Disk Space

Generating the "Hello World" pie chart is fun (that's how you know you are a geek) but this would be better with actual meaningful values. For instance, let's try to generate a pie chart that shows the proportion of free and used space of our startup disk. The first step is to get at those values. To do that we can use the new Leopard's Scripting Bridge, that allows manipulating other applications as if they were Cocoa objects (see previous entries on that topic: "Fun with Leopard's Scripting Bridge" part 1 and part 2).

Finder:= SBApplication applicationWithBundleIdentifier:'com.apple.finder'.

capacity  := Finder startupDisk capacity.

freeSpace := Finder startupDisk freeSpace.

Now we need to compute the proportions of free space and used space:

percentFree := freeSpace * 100 / capacity.

percentUsed := 100 - percentFree.

We can then call the Google Chart API. As you can see below, we construct the URL using F-Script's string concatenation operator (i.e., ++) to specify values in the URL. As described in the Google Chart API documentation, the data points must be provided with the chd parameter. Also, we are using the chco parameter to specify other colors for the chart, and the chf to specify a background color. We have also modified the chs parameter to make the chart bigger, and added a title using the chtt parameter.

chartString := 'http://chart.apis.google.com/chart?cht=p3&chs=400x150&chco=00AA00&chf=bg,s,F5F5F5&chl=free|used&chd=t:' ++ percentFree printString ++ ',' ++ percentUsed printString.

escapedChartString := chartString stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding.

url := NSURL URLWithString: escapedChartString.

image := NSImage alloc initWithContentsOfURL:url.

image inspect.

In our code, the cht parameter is used to specify the chart type. By changing its value from p3 to p, we can get a 2D pie chart:

Adding Special Effects with Core Image

Our chart is nice but what about making it shiner with some special effect? To do that, we are going to use the Core Image framework provide by Mac OS X. Core Image provides a powerful model for image processing and comes with dozens of built-in effects, in the form of CIFilter objects. To make use of Core Image, we must first create a CIImage object from our chart. CIImage provides various creation methods, including imageWithContentsOfURL: which is well suited in our case (for more on using Core Image filters with F-Script, you can read "Learn F-Script in 20 Minutes and Have Fun Playing with Core Image").

ciimage := CIImage imageWithContentsOfURL:url.

Then we create two Core Image filters. The first one, a CIStarShineGenerator, is used to generate a "star shine" image that we compose over our chart image using the second one, a CISourceOverCompositing.

starShineGenerator := CIFilter filterWithName:'CIStarShineGenerator'.
starShineGenerator setDefaults.
starShineGenerator setValue:4 forKey:'inputRadius'.
starShineGenerator setValue:(CIVector vectorWithX:167 Y:24) forKey:'inputCenter'.

starShineImage := starShineGenerator valueForKey:'outputImage'.

sourceOverCompositing := CIFilter filterWithName:'CISourceOverCompositing'.
sourceOverCompositing setValue:starShineImage forKey:'inputImage'.
sourceOverCompositing setValue:ciimage        forKey:'inputBackgroundImage'.

finalImage := sourceOverCompositing valueForKey:'outputImage'.

We can then look at the result by drawing finalImage (F-Script does not yet provide an inspect method for CIImage objects):

finalImage drawAtPoint:150<>150 fromRect:ciimage extent operation:NSCompositeSourceOver fraction:1.

Charting Cocoa Arrays

In a recent post titled "Is the Smalltalk Community Growing?", I included a bar chart created with iWork. The chart shows the number of attendees to our annual Smalltalk party in Paris over the years. Let's see how we can produce a similar chart using the Google Chart API.

We will first create NSArray objects that contain our attendance data. This will serve to illustrate a common need: charting data stored in arrays.

years := {2002, 2003, 2004, 2005, 2006, 2007}.

attendees := {6, 8, 23, 12, 21, 40}.

As you can see, there were 6 attendee in 2002, 8 in 2003 and so on…

The Google Chart API expects data points to be expressed on a scale that goes from 0 to 100. Therefore, we are going to scale the data from our attendees array (our years array is only used to provide labels on the x axis). To do that, we first find the biggest number in our array (it will also be used to specify the range associated to the y axis), using an operation called reduction that is carried on by the \ operator. You can learn more about reduction and other array programming operations in the F-Script Guide (pdf file).

attendeesMax := attendees \ #max:.

Then we project our data set on a scale from 0 to 100:

attendeesScaled := attendees * 100 / attendeesMax.

We can now prepare the strings that we will put in our Google Chart URL. Data points must be separated by comas, and labels must be separated by pipes:

attendeesString := attendeesScaled componentsJoinedByString:','.

yearsString := years componentsJoinedByString:'|'.

Finally, we can construct our ULR, call the Chart API and inspect the resulting image:

chartString := 'http://chart.apis.google.com/chart?cht=bvs&chs=370x280&chf=bg,s,F0F0F0&chtt=Number+of+attendees&chbh=30,30&chg=0,25,1,0&chco=4E6B9A&chxt=x,y&chxl=0:|' ++ yearsString ++ '&chxr=1,0,'++ attendeesMax printString ++'&chd=t:'++ attendeesString.

escapedChartString := chartString stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding.

image := NSImage alloc initWithContentsOfURL:(NSURL URLWithString:escapedChartString).

image inspect.

Modifying the various parameters in the URL (which are all documented by Google in the developer's guide), we change the appearance of the chart. For example, setting the cht (chart type) parameter to lc produces a line chart:

Finally, saving the image on disk is easy using standard Cocoa methods. For instance the following code saves our image in our Desktop folder using the TIFF format:

image TIFFRepresentation writeToFile:'~/Desktop/attenddes.tiff' stringByExpandingTildeInPath atomically:YES

That's all for today. Happy charting!

Read Full Post »

Last week, I gave a presentation about, guess what :-), F-Script, at our yearly french speaking Smalltalk Party in Paris. This event is organized by Serge Stinckwich for the French Smalltalk User Group and was hosted this year at OCTO Technology, thanks to my colleague Bernard Notarianni. This time, the organizers had to close the registration process early given our room capacity. With 40 attendees, this was by far our biggest gathering for this event, and I think it was filled with innovations and energy. Our little community is happily growing. The graphic below shows the number of attendees over the years (2002 & 2003 numbers are estimations from my memory).

Now, I learn that the registration count for the next Smalltalk gathering, which will take place next week at the university of Buenos Aires, is quickly approaching 300. Wow!

Is this representative of a general trend in the Smalltalk world?

Read Full Post »

New in Leopard is a 64 bit Objective-C runtime and support for 64 bit in the Cocoa frameworks. F-Script 2.0 provides complete 64 bit support. You can still run in 32 bit mode and you can use the F-Script framework in 64 bit and 32 bit applications.

The F-Script API now exposes 64 bit capable interfaces, using Cocoa's NSInteger, NSUInteger and CGFloat macros.

When running in 64 bit mode, F-Script 2.0 directly benefits from the features provided by the 64 bit Objective-C runtime, including the large address space, the optimized dispatch system and the new exception model. Exceptions are now C++ compatible (it is my understanding that the Objective-C and C++ exception system have been somewhat unified) and benefit from the zero-cost setup model now common in modern C++ implementations.

Let's see how we can use this exception system in F-Script. In the following F-Script code, we raise a simple exception using the standard Cocoa NSException class:

(NSException exceptionWithName:'MyError' reason:nil userInfo:nil) raise

And here is the general structure of an exception handler in F-Script:

    ... do some stuff that may raise an exception ... 
[ :e |
    ... handle exception e ... 

As you see, there is no special syntax. It just consists in sending the onException: message to a block, passing another block, the exception handler, as argument. If an exception is raised during the execution of the receiver, the handler is executed with the exception object, an NSException instance, as argument.

The throw method, which was introduced in F-Script 1.3, is deprecated in F-Script 2.0. Since Cocoa now specifies that exceptions must be represented by NSException objects, this method is no longer needed, as NSException already provides a raise method.

Read Full Post »