Photobooth: DOA.

The physical photobooth is pretty much done; it's constructed and painted, and the button is wired up. Photos automatically upload to the web site. It just needs a few holes cut and some signage and it's ready to go.

Oh, except for the camera issue. Which I've made pretty much no progress on, after having beaten my head against it off and on for a couple of weeks. It's reminding me in no uncertain terms of why I no longer write software for a living. This problem is bullshit and I hate working on it. So basically, I'm ready to admit defeat and throw all that plywood on the scrap heap unless someone else solves this problem for me.

Given the choices of "never have a photo booth" and "continue working on this software problem", I gleefully choose the former.

<lj-cut text=" How you can help -- (12%) ">

Things I believe to be true:

  • The only sensible way to talk to cameras from MacOS is to use ImageCapture.framework.

    • IOkit.framework is too low level.
    • Gphoto2 doesn't work.
    • libptp2 doesn't work.
    • ptpcanon doesn't work.
    • The official binary-only Canon SDK is junk, according to people who have actually used it.
  • The Canon Powershot S30 camera supports a bunch of undocumented commands. I have seen Canon's binary-only software do things, with this very camera, like:

    • Turn the viewfinder on and off;
    • Return a JPEG of the current viewfinder image;
    • Take a picture, with flash, and return a JPEG of it without any CF card in the camera.
  • This camera only advertises two commands, "download file from CF card", and "delete file from CF card". This is according to the Apple CapabilitiesSample demo. Those commands work (e.g., via the SimpleDownload demo.)

  • Just pasting in the hex codes for the undocumented commands in ICAObjectSendMessagePB.message.messageType doesn't work. I don't know if the commands are actually being sent to the camera, or if the framework is filtering them before they get there, or what.

  • Wrapping a kICAMessageCameraPassThrough command around these undocumented commands doesn't work either, after cutting and pasting its definition into my code. Maybe PassThrough is a part of the ImageCapture framework, maybe not. It's documented in the ImageCapture SDK, but is not present in any of the installed ImageCapture.framework header files. Is it from some hypothetical future version of the framework? Or is it only supported by some hypothetical camera driver that is not installed by default? I have no idea.

Here's how you can help:

  • Find me source code that runs on MacOS and that talks to a Canon point-and-shoot camera (I believe they're all the same) and that does something more complicated than "download a file from the CF card; delete it."

  • Find me someone to talk to who understands and has used ImageCapture.framework in some nontrivial way. This person will be an Apple employee, because as far as I can tell, nobody who is not an Apple employee has ever touched it.

  • Modify the following code to do something useful, and show me what you did.

Here's some code that doesn't work:

/* A halfassed attempt at using ImageCapture.framework

   g++ -o test -g -Wall -framework Carbon


#import <Carbon/Carbon.h>

/* As far as I can tell, this shit should be in

   but it's not.  Why? I have no idea.

enum {
kICAMessageCameraPassThrough= 'pass',

enum {
    kPTPPassThruSend    = 0,
    kPTPPassThruReceive     = 1,
    kPTPPassThruNotUsed     = 2,

typedef struct PTPPassThroughPB
} PTPPassThroughPB;

main (int argc, char *argv)
  OSErr err = 0;
  ICAObject list = NULL;

  // Get the list of image-capturable devices
    ICAGetDeviceListPB list_pb;
    memset(&list_pb, 0, sizeof(list_pb));
    err = ICAGetDeviceList(&list_pb, NULL);
    if (err != noErr) {
      fprintf (stderr, "device list error = %d\n", err);
      exit (1);
    list = list_pb.object;

  // Get the first device

  ICAObject device = NULL;

    ICAGetNthChildPB nth_pb;
    UInt32 count;
    ICAGetChildCountPB count_pb;
    memset(&count_pb, 0, sizeof(count_pb));
    count_pb.object = list;
    err = ICAGetChildCount(&count_pb, nil);
    if (err != noErr) {
      fprintf (stderr, "device count error = %d\n", err);
      exit (1);
    count = count_pb.count;

    if (count <= 0) {
      fprintf (stderr, "device count = %d\n", (int) count);
      exit (1);

    memset(&nth_pb, 0, sizeof(nth_pb));
    nth_pb.parentObject = list;
    nth_pb.index = 0;
    err = ICAGetNthChild (&nth_pb, NULL);
    if (err != noErr) {
      fprintf (stderr, "first device error = %d\n", err);
      exit (1);
    device = nth_pb.childObject;

  // Send the device a message.

  ICAObjectSendMessagePB pb;
  memset(&pb, 0, sizeof(pb));
  pb.object = device;

#if 1
//  pb.message.messageType = kICAMessageCameraCaptureNewImage;
  pb.message.messageType = 0x900b; // Turn viewfinder on

  PTPPassThroughPB *ptb = (PTPPassThroughPB *)
    malloc (32 * 1024 + sizeof(*ptb));
  //ptb->commandCode = 0x901d;  //kCanonGetViewfinderImage
  ptb->commandCode = 0x900b;  // turn viewfinder on
  ptb->numOfInputParams = 0;
  ptb->numOfOutputParams = 0;
  ptb->dataUsageMode = kPTPPassThruReceive;
  ptb->dataSize = 1024;
  pb.message.messageType = kICAMessageCameraPassThrough;

  pb.message.startByte= 0;
  pb.message.dataPtr= ptb;
  pb.message.dataSize= 1024;
  pb.message.dataType= kICATypeData;

  err = ICAObjectSendMessage (&pb, NULL);

  fprintf (stderr, "status = %d\n", err);

  return 0;
Tags: , , , , ,

The Tijuana / San Diego Subterranean Expressway