Skip to content

Instantly share code, notes, and snippets.

@rsanders
Created January 22, 2009 17:32
Show Gist options
  • Save rsanders/50627 to your computer and use it in GitHub Desktop.
Save rsanders/50627 to your computer and use it in GitHub Desktop.
A.7. Taking Camera Photos
The Photo Library framework is a proprietary framework providing common methods for the iPhone's Camera application. One useful feature buried inside this framework is the CameraController class, which is capable of snapping 16,001,200 photos in JPEG format.
This is very cool, while also very creepy at the same time. The camera controller itself makes no attempt to notify the user that a photo is being taken, nor is there any indication on the iPhone's display. This creates the possibility for real spyware (that is, voyeurware) to easily be written and installed on a user's iPhone without her knowledge.
A.7.1. Installing CameraController Prototypes
The Photo Library framework is not included in the prototype collection for version 0.30 of the tool chain, so you'll need to dump it directly from the iPhone to begin using the camera controller. The CameraController.h prototype file can be generated using Steve Nygard's class-dump tool, available at http://www.codethecode.com/projects/class-dump. To dump the contents of the Photo Library framework, use the copy of the iPhone's libraries you copied over in Chapter 2:
$ class-dump /usr/local/share/iphone-filesystem\
/System/Library/Frameworks/PhotoLibrary.framework/PhotoLibrary
This will dump all of the classes in the framework, but you'll only need one: the CameraController class. Sort through the output of class-dump to find the interface declaration. Place its contents in the file /usr/local/arm-apple-darwin/include/PhotoLibrary/CameraController.h. The contents you'll be copying into the file will look like this:
Code View:
@interface CameraController : NSObject
{
LKLayer *_cameraLayer;
struct CameraDevice *_camera;
struct CameraImageQueueHelper *_cameraHelper;
id _delegate;
UIView *_previewView;
BOOL _isPreviewing;
}
+ (id)sharedInstance;
- (id)init;
- (void)_setIsReady;
- (BOOL)isReady;
- (void)_tookPicture:(struct _ _CoreSurfaceBuffer *)fp8;
- (void)_tookPicture:(struct CGImage *)fp8
jpegData:(struct _ _CFData *)fp12 imageProperties:(st
ruct _ _CFDictionary *)fp16;
- (struct CameraImageQueueHelper *)_cameraHelper;
- (BOOL)_setupCamera;
- (void)_tearDownCamera;
- (void)setDelegate:(id)fp8;
- (struct CGRect)_cameraFrame;
- (id)previewView;
- (void)startPreview;
- (void)stopPreview;
- (void)capturePhoto;
@end
A.7.2. Taking Pictures
The CameraController class uses a delegate to notify the application of two kinds of events: ready state and picture taken. You must override two methods to accept these notifications.
The cameraControllerReadyStateChanged method is notified whenever the camera's state has changed (for example, when it is placed in preview mode). Your own implementation of this method won't need to perform any special function, but it must exist in your application to avoid generating an exception. This method is useful if you wish to provide some form of notification to the user that the camera is active, such as displaying a red blinking dot.
- (void)cameraControllerReadyStateChanged:
(NSNotification *)aNotification
{
/* Take any action here */
}
The tookPicture method is notified whenever a picture is actually taken. The runtime passes the function the raw JPEG data containing the contents of the 1,600 x1,200 image as well as a UIImage object containing its preview. You'll need to override this method to access the photo itself.
-(void)cameraController:(id)sender
tookPicture:(UIImage*)picture
withPreview:(UIImage*)preview
jpegData:(NSData*)rawData
imageProperties:(struct _ _CFDictionary *)imageProperties
{
/* Save or work with picture here */
}
To take a picture, create an instance of the CameraController class:
CameraController *camera = [ [ CameraController alloc ] init ];
State and picture notifications should then be directed to a specific object:
[ camera setDelegate: self ];
When you're ready to snap a picture, first place the camera in preview mode, then call its capturePhoto method:
[ camera startPreview ];
[ camera capturePhoto ];
After a photo has been snapped, the tookPicture method will be notified, allowing you to save the image or work with it in some other way. When you're finished with the camera, you should turn off the preview mode.
[ camera stopPreview ];
The image data is provided as an NSDATA structure. This is a foundation class present in the Cocoa framework, and is designed to encapsulate raw data into an object. More information about this structure can be found in the Cocoa Reference available on the Apple Developer Connection web site.
A.7.3. Example: Snap App
This example provides a command-line utility for snapping a photo. The program will output "Smile" to stdout and snap a photo one second later. A filename to a JPEG file is provided on the command line.
To compile this example, use the tool chain on the command line as follows:
$ arm-apple-darwin-gcc -o snap snap.m -lobjc \
-framework CoreFoundation -framework Foundation -framework UIKit \
-framework PhotoLibrary
Example A-3 contains the code.
Example A-3. Camera controller example (snap.m)
Code View:
#import <Foundation/Foundation.h>
#import <PhotoLibrary/CameraController.h>
#import <UIKit/UIKit.h>
@interface SnapApp : UIApplication
{
NSString *filename;
}
- (id)_initWithArgc:(int)argc argv:(const char **)argv;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification;
@end
@implementation SnapApp
- (id)_initWithArgc:(int)argc argv:(const char **)argv {
filename = [ [ NSString alloc ] initWithCString: argv[1] ];
return [ super _initWithArgc: argc argv: argv ];
}
- (void)cameraControllerReadyStateChanged:(NSNotification *)aNotification
{
}
-(void)cameraController:(id)sender
tookPicture:(UIImage*)picture
withPreview:(UIImage*)preview
jpegData:(NSData*)rawData
imageProperties:(struct _ _CFDictionary *)imageProperties
{
[ rawData writeToFile: filename atomically: NO ];
[ self terminate ];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
CameraController *camera = [ [ CameraController alloc ] init ];
[ camera setDelegate: self ];
[ camera startPreview ];
printf("Smile...\n");
sleep(1);
[ camera capturePhoto ];
[ camera stopPreview ];
}
int main(int argc, char *argv[])
{
NSAutoreleasePool *autoreleasePool = [
[ NSAutoreleasePool alloc ] init ];
int returnCode;
if (argc == 2) {
returnCode = UIApplicationMain(argc, argv,
[ SnapApp class ]);
} else {
fprintf(stderr, "Syntax: %s [filename]\n", argv[0]);
}
[ autoreleasePool release ];
return returnCode;
}
@end
A.7.4. What's Going On
When the application instantiates, a CameraController object is created and placed into preview mode to ready the camera. Its delegate is set to self, the application instance running.
This triggers a notification to cameraControllerReadyStateChanged. In our example, this performs no action.
One second later, the controller's capturePhoto method is called, instructing it to take a snapshot.
The application's tookPicture method is called, providing the pointer to an NSDATA structure containing the image's raw JPEG data.
The NSDATA structure's writeToFile method is called, storing the file on disk.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment