In the previous 2 posts, I talked about the secrets of view hierarchy and how to retrieve image from the UIImagePickerController. By understanding the internals of a UIImagePickerController, we are able to change some of the undocumented features. Steve Nygard has published an excellent class dumping utility. Eric Sadun‘s script make use of Steve’s class-dump to create a folder and fill it with header files from the iPhone’s private and public framework. I am going to share some of the information I have inferred from these header files.
The UIImagePickerController (PLCameraViewController) is a delegate of CameraView (/0/0/0). In the viewfinder mode, CameraView sends cameraViewCancelled: to its delegate when the Cancel button is pushed. If the Camera button is pushed, the following messages is sent in sequence: cameraViewShouldShowIris:, cameraViewShouldShowProgressWhileCapturing:, cameraViewShouldShowPreviewAfterSelection:. After “Use Photo” is pushed, cameraView:photoSaved: will be sent to its delegate. By using CameraView’s setDelegate:, you can assign a new delegate. I have successfully change the CameraView’s to my UIImagePickerController’s subclass. If you change the CameraView’s delegate, I will advice you to implement all 4 methods, and remember to forward these messages to the parent in these implementations.
In similar manner, cropOverlayWasCancelled:, cropOverlayWasOKed:, and cropOverlay:didFinishSaving: are sent to CameraView from PLCropLayer (/0/0/0/3). I guess you can customize the UI by playing with the (void)setShowsCropOverlay:(BOOL)fp8 and (void)setChangesStatusBar:(BOOL)fp8 methods in CameraView.
(void)setCropTitle:(id)fp8 subtitle:(id)fp12 buttonTitle:(id)fp16 looks interesting, but I can’t use it due to the limitation of NSObject’s performSelector. The titles (in view and buttons) can still be changed using the follow code:
There are more to be discovered, I leave the rest of the exploration to you.
Part 1 | Part 2
WARNING: Readers are adviced not to use the techniques presented in this 3 parts series. It is against the terms stated in the iPhone Developer Program. When undocumented features are used, the application may not work when a newer iPhone OS is released. DO IT AT YOUR OWN RISK.
Posted in
Tao Of Programming at June 15th, 2009.
No Comments.
With that view hierarchy information, I make change to the views. To remove the “Take Picture” words from the viewfinder, and the following code to the viewDidAppear: method:
Instead of removing them by using removeFromSuperView, I hide. It is not advisable to remove or replace them because the these views contain components that may be used by other objects (e.g. PLCropOverlay, PLCameraView, etc). By the way, you can also use this technique to remove hide the buttons (hint: /0/0/0/3). I followed lajos‘s example and start a timer when Camera button is clicked. The timer will invoke a function, which checks the /0/0/0/2 UIView. When the image is ready, /0/0/0/2 will contain subviews. To skip the confirmation screen, I just have to retrieve the image and dismiss the UIImagePickerController. How do I retrieve the image?
On Air Source blog, Gee mentioned the use of UIGetScreenImage(), which is an undocumented function in the SDK. UIGetScreenImage() does a printscreen and returns a CGImageRef. Well, it works, but it is not really a good solution. The screen size is 360×480, but the image that the camera produces is 1200×1600. Is it possible to get the original image produced by the camera?
Every view has a Core Animation layer. I am unable to retrieve the original UIImage/CGImageRef, but I can get the CALayer to draw out the 1200×1600 image. When the image is ready, use the following code to create an image:
This is a better solution, compared to the usage of UIGetScreenImage(). The former does not use any undocumented SDK feature (except for retrieving the view /0/0/0/2/0/0/0).
Part 1 | Part 3
WARNING: Readers are adviced not to use the techniques presented in this 3 parts series. It is against the terms stated in the iPhone Developer Program. When undocumented features are used, the application may not work when a newer iPhone OS is released.DO IT AT YOUR OWN RISK.
Posted in
Tao Of Programming at June 12th, 2009.
2 Comments.
Acknowledgement: I did not discover everything on my own. I am using some information from lajos, The Air Source, and Erica Sadun.
The UIImagePickerController allows an application to use camera to take picture. Customization is very limited. Taking picture through a camera is a 2 steps process:
- When UIImagePickerController (sourceType=UIImagePickerControllerSourceTypeCamera) is launched, user will be presented with a view finder. There is a “Take Picture” title on the top, Cancel button at bottom-left, and a Camera button at the bottom-right of the screen.
- When Camera button is pressed, user will be taken to another (confirmation) screen. It has “Retake” and “Use Photo” buttons.
There are only 3 configurable properties, but developers want more customizations. Initially my intention was to skip the confirmation screen, grab the picture after the Camera button is pressed. I start off by exploring the view hierarchy of UIImagePickerContorller.
This little piece of function will traverse the view hierarchy in a preorder manner:
Create a subclass of UIImagePickerController and add this function to its implementation. Invoke this function in viewDidAppear::
I will encourage you to inspect the view in the viewDidLoad and viewWillAppear: methods to compare the differences.
View hierarchy in iPhone simulator:
- UILayoutContiainerView (root)
- UITransitionView (/0)
- UIView (/0/0)
- PLCameraView (/0/0/0)
- UIImageView (/0/0/0/0)
- UIView (/0/0/0/1)
- PLCropOverlay (/0/0/0/2)
- UIImageView (/0/0/0/2/0)
- PLCropLCDLayer (/0/0/0/2/1)
- TPBottomDualButtonBar (/0/0/0/2/2)
- TPPushButton (/0/0/0/2/2/0)
- TPCameraPushButton (/0/0/0/2/2/1)
- UIImageView (/0/0/0/2/2/1/0)
- UINavigationBar(/0)
- UINavigationItemView (/1/0)
View hierarchy in iPhone (viewfinder mode):
- UILayoutContiainerView (root)
- UITransitionView (/0)
- UIView (/0/0)
- PLCameraView (/0/0/0)
- UIView (/0/0/0/0) The shutter image layer.
- UIImageView (/0/0/0/1)
- UIView (/0/0/0/2)
- PLCropOverlay (/0/0/0/3)
- UIImageView (/0/0/0/3/0)
- PLCropLCDLayer (/0/0/0/3/1)
- TPBottomDualButtonBar (/0/0/0/3/2)
- TPPushButton (/0/0/0/3/2/0)
- TPCameraPushButton (/0/0/0/3/2/1)
- UIImageView (/0/0/0/3/2/1/0)
- UINavigationBar(/0)
- UINavigationItemView (/1/0)
View hierarchy in iPhone (after picture is taken):
- UILayoutContiainerView (root)
- UITransitionView (/0)
- UIView (/0/0)
- PLCameraView (/0/0/0)
- UIView (/0/0/0/0)
- UIImageView (/0/0/0/1)
- PLImageTile (/0/0/0/2)
- PLRotationView (/0/0/0/2/0)
- PLImageScroller (/0/0/0/2/0/0)
- PLImageView (/0/0/0/2/0/0/0)
- PLCropOverlay (/0/0/0/3)
- UIImageView (/0/0/0/3/0)
- PLCropLCDLayer (/0/0/0/3/1)
- TPBottomDualButtonBar (/0/0/0/3/2)
- TPPushButton (/0/0/0/3/2/0)
- TPCameraPushButton (/0/0/0/3/2/1)
- UIImageView (/0/0/0/3/2/1/0)
- UINavigationBar(/0)
- UINavigationItemView (/1/0)
Part 2 | Part 3
WARNING: Readers are adviced not to use the techniques presented in this 3 parts series. It is against the terms stated in the iPhone Developer Program. When undocumented features are used, the application may not work when a newer iPhone OS is released.DO IT AT YOUR OWN RISK.
Posted in
Tao Of Programming at June 10th, 2009.
2 Comments.