Tag Archives: imagecapture

Image Capture API

In “episode 21 of Core Intuition”:http://www.coreint.org/2009/07/episode-21-the-tyranny-of-commit-access/, I called the Image Capture API “quirky”. What did I mean by that? A few things.

Refcon. This should be familiar to anyone who has built Mac OS 9 or Carbon apps. I’ve certainly written plenty of code that stuffed a pointer to an object in the refcon field of a structure or passed to a callback method. It’s an essential pattern for being able to integrate C++ or Objective-C objects with a C-based API.

For Image Capture, the code might look like this:

  ICAGetDeviceListPB pb = {};

pb.header.refcon = (unsigned long)self;

OSErr err = ICAGetDeviceList (&pb, YourDeviceListCallbackHere);

Then in the callback you cast the refcon back to your controller object and go about calling methods and accessing member variables.

  void YourDeviceListCallbackHere (ICAHeader* pbHeader)

{

YourController* ic = (YourController *)pbHeader->refcon;

[ic doSomethingUseful:pbHeader];

}

Works fine, but what about 64-bit? The reason I noted this part of the API to blog about was because the first version of my code accidentally cast my pointer to a UInt32. Luckily for us, the refcon is actually declared as an unsigned long instead, so it should share the same pointer size in 64-bit land, where long and void* are both 8 bytes. Other data types in Image Capture, such as ICAObject, are declared to be UInt32.

(What would we do if the refcon was UInt32? The solution is not terribly difficult: use a simple lookup table that maps a random ID or incrementing number stored in the refcon to your 64-bit compatible pointer. But this just doesn’t seem to be necessary very often.)

No delete function. I found this one strange, and had to dig in example code to find the solution. There is no first-class function in Image Capture for deleting objects off of a camera. Apparently this isn’t a feature that is supported by all devices, but nevertheless it seems common enough that it deserves something more than an enum constant hidden in a secondary header file.

Here’s how you go about deleting a video off of the iPhone:

  ICAObjectSendMessagePB pb = {};

pb.header.refcon = 0;

pb.object = (ICAObject)your_movie_id_here;

pb.message.messageType = kICAMessageCameraDeleteOne;

OSErr err = ICAObjectSendMessage (&pb, NULL);

Bad delete on success design. Related to the above, Image Capture has this trick that seems clever at first but which I don’t think could be used for most applications. You can set a flag to tell Image Capture to delete a video after it imports. Maybe this also explains why there’s no standalone delete function, but the design feels dangerous to me; if an import fails halfway through importing 10 videos, the first 5 will still be deleted. I much prefer to examine the imported files to make sure they were saved correctly, and then after everything was successful go back and delete the imported objects.

It’s been a couple months since we recorded Core Intuition 21, but there are some other segments worth noting. Daniel and I talked about the WWDC 2009 session videos, a plug for “rooSwitch”:http://www.roobasoft.com/rooswitch/, beta testing MarsEdit 3, and a listener question about working for non-developer managers. Listen at coreint.org or “subscribe in iTunes”:http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewPodcast?id=281777685.