Views of UIImagePickerController

The standard image capture in API in the iPhone SDK is the UIImagePickerController. There is much discussion on the web about how this can be customized via subclassing, both from the viewpoint of technical feasibility, and from the viewpoint of being allowed onto the AppStore. It is generally accepted that going direct to private frameworks is unacceptable, even though this arguably can give a better user experience. Phanfare had their app pulled from their AppStore for using the PhotoLibrary private framework, and returned with a new version that instead customizes the UIImagePickerController experience.

I took an in-depth look at the view structure that the standard UIImagePickerController creates. The first is obtained by looking at self.view and is not particularly interesting. It consists of a UITransitionController and a UINavigationController and is clearly the meta-system for switching between the capture and preview screens.

The second view hierarchy is created by PLCameraController, and can be obtained by implementing willShowViewController in the UINavigationControllerDelegate. The first callback to this comes when UIImagePickerController wants to display a PLCameraController. The view hierarchy is much more interesting:

uiimagepickercontroller1

Several of these classes are undocumented, but that doesn’t prevent us from manipulating them with standard APIs. Experimentation showed that the UIImageView highlighted in red is the important one - it’s the camera preview pane. You can remove every other view, and just retain this one, and you will get a full-screen camera view. You can also move the TPPushButton (which represents the cancel button) out of the hierarchy and place it elsewhere on the screen. Doing the same with the TPCameraPushButton causes a crash when you activate the button, because the PLCameraController tries to modify the buttons, and fails because the view structure has changed.

You can also add further views (as Phanfare did) to overlay extra details. Clearly there is yet more scope for customizing other aspects of the hierarchy - this requires more experimentation, and we’ll report on this as we learn more.

74 Responses to “Views of UIImagePickerController”

  1. iDevKit Says:

    Subclassing UIImagePickerController…

    I’m trying to modify the UI that the user is presented with when they’re taking a picture. Specifically, I want to remove the “Take Picture” title bar and replace it with a custom graphic.

    I can cr……

  2. Views of UIImagePickerController » iPhone Tricks Says:

    [...] The Air Source placed an observative post today on Views of UIImagePickerControllerHere’s a quick excerptThe standard image capture in API in the iPhone SDK is the UIImagePickerController…. [...]

  3. » Views of UIImagePickerController Says:

    [...] The standard image capture in API in the iPhone SDK is the UIImagePickerController. There is much discussion on the web about how this can be customized, both from the viewpoint of technical feasibility, and from the viewpoint of being .. More [...]

  4. netsharc Says:

    Is the UIImageView really the cam preview? I onlly get the closed iris view when I grab its image. Or does one have to initialise the camera first?

  5. Ben Says:

    I haven’t yet figured out how to grab the image, but it’s definitely the cam preview - if you remove just that view from the superview, then you get no camera preview at all.

  6. rolando Says:

    Ben,
    thanks for the info. I did my own “investigation” and came up with the same view hierarchy, although, I must say that the ImageView *is* the Iris. So far I have this: PLCameraView has four subviews:
    0: ?;
    1: is the UIImageView (iris);
    2: ?;
    3: all the extra stuff. So to get a full screen preview, with nothing else, you only have to remove that last view (the PLCropOverlay). I tried getting the content of view 0 and 2, but only got black screens so far.

  7. rolando Says:

    sorry, view 0 (first subview) is the cameraPreview, but rendering its content leads me to only a black screen :-(

  8. Ben Says:

    I think we need to trade some code. I’ll get my code up later this week.

  9. rolando Says:

    ok, I got it… I know why I’m only getting a black screen: it’s because renderInContext is limited to only render some parts, not all.

  10. Ben Says:

    That’s where I got to - black screen with renderInContext, yet I could swear I was grabbing view 1, not view 0. I’ll have to check when I’m back on the mac.

  11. Ben Says:

    Rolando - you’re absolutely right. My apologies; I obviously got my ordering wrong when going from my code to a PNG graphic. I’ve corrected the blog post.

  12. rolando Says:

    Ben, I finally was able to grab the screen :-P I’ll put my code online once I clean it up a bit.Btw, the iPhone camera sucks for scanning barcodes in real time :-P

  13. Ben Says:

    Awesome. Look forward to seeing it! The iPhone camera sucks quite a lot, never mind just for barcodes!

  14. Rolando Says:

    Ben, here’s a proof of concept: http://www.youtube.com/watch?v=uc-p221SQ0g, code to follow soon…

  15. gustaf Says:

    Rolando, any code to share yet??

  16. chris comair Says:

    Amazing, thank you so much.

  17. Kendall Says:

    I’m on the same track (just finished playing with the various camera picker subviews and layers before I found this page), if I get any code to work soon that manages to read the preview image I’ll post as well.

    It would be a very nice thing to take to an iPhone Dev Camp I’m attending this weekend…

  18. Tom Says:

    Any thoughts on how to use this to capture the event generated when the shutter button is pressed? I’d like to be able to trigger a function when the view changes to the preview view…

  19. Ben Says:

    Tom - Sure. Add an action to the TPCameraPushButton.

  20. scott Says:

    It would be great to see some demo code…

  21. Tom Says:

    Sweet, that works nicely. Thanks…

  22. Ben Says:

    Tom - great :)

  23. Wonwoo Says:

    Hi.

    is it possible to grab a frame from incoming video and access the raw RGB data of the frame with this approach ?

  24. Ben Says:

    It’s certainly possible, the questionis whether you can do it with a legal API or not. Rolando says it’s possible, and we’re hoping to see some example code from him at some point.

  25. Wonwoo Says:

    Yes, it is possible with hacked toolchain, but it’s not desirable.
    If we can get the raw image data through the official SDK, it will be great.
    I am really looking forward Rolando’s sample code.

  26. Alexandre Gomes Says:

    I’ve been trying to get the pictures from the preview with certain success. Now, in the last 5 days, I’m stuck with the black pictures problem. Rolando says its possible but didn’t provide any more details. Could anyone tell me how to do it? Or can anyone tell me the email of Rolando? Email me at alexmipego @ gmail.com if you have any information please.

  27. Gee Says:

    I am also getting black screens using renderInContext.. any help would be great rolando? For anyone that’s interested, you can use [UIImage imageWithCGImage:UIGetScreenImage()] but that is not an official SDK API call so it probably won’t fly in the app store (who knows)… I’m still looking for a way to do the screen capture with all official APIs.

  28. kuolei Says:

    Hi.
    Now i am writing the program for getting the image data from camera in real time, but have not a good way get it through the official SDK. Rolando, may i see your sample code?
    Please send my mailbox. Thanks.

  29. Alex Says:

    Hi.
    I have the same problem to get a screen image from UIImagePickerController.
    Obviously only Rolando knows how to get the images. Has anyone a response
    from him? It would be great to know what the problem is. Thanks

  30. lajos Says:

    I have a small xcode project and some write up to demonstrate some tweaks to the camera interface here: custom UIImagePickerController camera view.

    It looks like there might be a mistake on your diagram. While the camera view is the first subview of PLCameraView, it is a UIView, not a UIImageView.

  31. kuolei Says:

    Hi, Iajos.
    How can I get a screen image from PLCameraView?
    Thanks.

  32. Alexandre Gomes Says:

    @KUOLEI - search for the renderincontext method

    @ALL - Anyone had an anwser from Rolando?

  33. Alex Says:

    @kuolei & Alexandre
    I have tried the renderInContext method with the PLCameraView but the
    result is a black screen image. Does anyone knows the trick to get the right
    image?

  34. Ben Says:

    I was periodically in contact with Rolando, but I’ve had nothing but radio silence recently (or, indeed, not so recently given this thread has been running for over two months).

  35. Tomas Says:

    Is it possible that this has been blocked since v2.2? Have we seen any confirmation that anyone ( Rolando? ) has had it working since 2.2 came out?

  36. Alexandre Gomes Says:

    The black screen image is the reason most people are here :) Only rolando says he has been able to work around it. Although I suspect he used the UIGetScreenImage method which isn’t approved by Apple.

  37. Ben Says:

    I asked Rolando by email if he used that method, and he indicated clearly that he had not. UIGetScreenImage is a bit slow in any case.

  38. Alexandre Gomes Says:

    Ben, could u give me Rolando’s contact? Or asking him to contact me?

  39. Alexandre Gomes Says:

    @Ben
    The reason I ask is because I’ve something very cool ready except for the black screen image. I’m willing to share code or even release it opensource if I could get it working.

  40. Ben Says:

    @Alexandre I’ve emailed Rolando directly with your email address and asking for an update. Rolando didn’t choose to make his email address public, so I can’t divulge it. Sorry.

  41. Alexandre Gomes Says:

    I understand. Im usually not this anoying on the internet, but Ive spent 2 weeks trying to figure out how to solve the problem. In fact, I know what Rolando means in his last post about the renderincontext not catching everything… I just can’t find a way around it. Lets hope he chooses to help me :)

    Thanks.

  42. Alex Says:

    @Alexandre
    I also stuck on this problem about the renderincontext since few weeks.
    If you heard something from Rolando maybe you can share this feature
    with us.

    Thanks.

  43. links for 2009-01-20 at adam hoyle presents suckmypixel Says:

    [...] The Air Source » Blog Archive » Views of UIImagePickerController The standard image capture in API in the iPhone SDK is the UIImagePickerController. There is much discussion on the web about how this can be customized via subclassing, both from the viewpoint of technical feasibility, and from the viewpoint of being allowed onto the AppStore. (tags: design workaround iphone UIImagePickerController) [...]

  44. Alexandre Gomes Says:

    Well, I’ven’t heard from Rolando. I do however think that sharing what I think the problem might produce some ideas and maybe someone here can solve the problem.

    So, the problem as I guess it is, is that the renderincontext message doesn’t work in all cases. This is poorly documented by Apple, they only say this:

    «The Mac OS X v10.5 implementation of this method does not support the entire Core Animation composition model. QCCompositionLayer, CAOpenGLLayer, and QTMovieLayer layers are not rendered. Additionally, layers that use 3D transforms are not rendered, nor are layers that specify backgroundFilters, filters, compositingFilter, or a mask values. Future versions of Mac OS X may add support for rendering these layers and properties.»

    Now… I’ve tried to figure out if any of those things were beeing used. The only way I know to do this kind of research is to use the debugger and inspect the properties (which, iirc doesn’t provide a 1 on 1 relation with the things specified by Apple). Since I am new to Cocoa/Objective C maybe there’s a better way to inspect the “tree” and properties?

    Also, it occured to me that *maybe* one of those things (ex: composingFilter) could exist not on the preview UIView but on one of the parents. My guess on this is that since I didn’t found one on the UIView and the image is shown resized… then it could be the whole reason for our problems.

    I think thats what I’ve to share. Please comment and provide details if any of you find a solution :)

  45. Rolando Says:

    Just to let everyone know: I have figured it out, but unfortunately, I can’t release any source code until the app for which the library (realtime barcode scanning) gets released, this is due to a nasty NDA with the client for which the app was made. FYI, I did not use UIGetScreenImage neither renderInContext, it was a pretty simple trick after all. Alexandre: you can inspect things using objective-c introspection (I also sent you an email)

  46. kuolei Says:

    Hi, Rolando.
    I get the image data in realtime without renderInContext. But this image data is not a general image, the description of class is CAImageQueue in debugger. How can i get the pixel data for this “image”.My email is kuolei@gmail.com.
    please give me an suggestion.

    Thank you.

  47. John Says:

    Hi kuolei. You’re right that what you get in the contents is a CAImageQueue. I’m not sure what Rolando has done.

    However the only way I’ve found so far to get image data out of the CAImageQueue, which is not a public API, is to dig down into its internals and find a CoreSurface buffer attached to the camera device. Unfortunately, to use this you then need to call CoreSurfaceBufferLock() and friends, which requires linking the CoreSurface framework. It’s not enough to just do the equivalent of CoreSurfaceBufferGetBaseAddress() and copy (neglecting potential tearing), since the buffer is actually owned by the camera device and is not available to you without an IOKit call to map it into your process (which is normally done by CoreSurfaceBufferLock()).

    For this reason I suspect Rolando will have followed a different path.

  48. Ben Says:

    I just saw a post over at StackOverflow

    http://stackoverflow.com/questions/332120/iphone-video-buffer - where a guy says he’s successfully used

    image = [window _createCGImageRefRepresentationInFrame:rectToCapture];

    Obviously a private API, but we’re trying it out now for the purposes of research and will report back.

  49. John Says:

    _createCGImageRefRepresentationInFrame does appear to work, but it appears to be no faster and thus no better for us than UIGetScreenImage().

  50. Rama Says:

    Odd, I posted here yesterday but my browser ate it.

    So far not useful but very interesting (and fun) the UIView -> CALayer -> contents (where contents’ class is a CAImageQueue), so CAImageQueue is a CGImage. This allows you do do fun things like create multiple active live video previews:

    UIImage *image = [UIImage imageWithCGImage:(CGImageRef)view.layer.contents];
    pipImageView.image = image;

    Unfortunately, I cannot extract the bitmap from the CGImageRef (probably because as mentioned it is direct CoreSurface writes).

    Core Animation also takes a snapshot of the video feed when doing something like a UIViewAnimationTransitionFlipFromRight. I have not been able to figure out a way to take advantage of that with a custom animation though.

    Finally, I just found a great write up here:

    http://translate.google.com/translate?prev=_t&hl=en&ie=UTF-8&u=http%3A%2F%2Fcntt.tv%2Fnodes%2Fshow%2F492&sl=vi&tl=en&history_state0=

  51. EXcell Says:

    Is there any way to take a closer look at any piece of code that was published on youtube by Rolando? I’m new in real-time application development but I hold a great interest in mobile augmented reality and any ways how to overlay full screen camera view with any kind of objects as labels/textviews or so.

    For me also it was a great challenge to see something like this http://www.techcrunch50.com/2008/conference/presenter.php?presenter=71#video
    I dont really know if the guys from tonchidot are using any private APIs or undocumented call or whatever. It will be really interested to discover at least some simple code examples and the way how to do it.

    So if somebody can help me out on my investigations, it would be really appreciated.

  52. Tommy Says:

    Does anyone know what subview the activity indicator is when the user takes a photo? I would like that to be hidden as well

  53. Andrew Says:

    Has anyone else figured out Rolando’s solution for? Could we have another hint?
    It seems like getting the CGImage from preview.layer.contents is a step very near to a solution. I’d like to throw my email in the ring if anyone has a suggestion they’d like to pass along: socrates1024@gmail.com

  54. Codz Says:

    Has anyone had any luck trying to mimick the likes of ‘QuadCam’ or ‘25 shot!’ ?

    I’ve seen a few of these apps and they all appear to make the “shutter noise” for every frame which is captured, which is what lead me to believe they were synthesizing touch events, and the OS was triggering the sound.

    Anyone have any ideas?

  55. Ian Says:

    Codz, QuadCam uses UIGetScreenImage() - I’ve been in contact with the developer.

    Has anyone found an alternative to UIGetScreenImage / renderInContext ?

  56. Codz Says:

    Great thanks Ian, I thought as much… I’ve tried for ages trying to find an alternative. :(

  57. Chris Says:

    Has there been any word from Roland? I’m really interested in any suggestions on how to get the preview image as well.

    cmgreening at gmail.com

  58. Tom Says:

    Has anybody had any success getting an app that tweaked PLCameraView approved by Apple? I’ve seen apps that clearly do, but ours got rejected…

  59. Norio Nomura Says:

    I can get pixelbytes from each images of preview as below code.

    http://github.com/norio-nomura/iphonetest/blob/9713242dda6c6bc897da4bd639a1fdadc29b6fd7/CameraTest/Classes/CameraTestAppDelegate.m#L35

    It uses undocumented methods, so Apple will not approve, but work well.

  60. Bob Hearn Says:

    @Tom:

    You tweaked the view structure and your app got rejected? Can you share the details? What did you do, and what did Apple say?

  61. Chris Says:

    Any word from Rolando?

    I’m starting to see a ton of proof of concept augmented reality apps - so people are definitely managing to access the video stream.

    I really want to add this feature to my Sudoku Grab application (http://www.youtube.com/watch?v=oImMJ6p6mKE). I can definitely make my puzzle detection and solver code work in real time so I could superimpose the solved puzzle on top of the image.

    At the moment there’s no point in doing the optimization as it works fast enough (in the latest version <1second) for non real time.

    If anyone can help them drop me an email chris at cmgresearch.com

    There’s a promo code for my app in it (worth a huge $1!)

  62. Andrew Says:

    @Tom, ours did also.

    Does anyone have any experience getting an app accepted that hides the “Take a Picture” overlay or changes its text?

    The feedback from Apple seems to tell us that touching the PLCameraView object at all is against the rules.

  63. Sten Says:

    Yes mine just got rejected too since I called the “undocumented API:s in UIImagePickerController” (I am just hiding the ugly labels).

    There are indications in the 3.0 release notes that the camera view is being changed, so maybe they are getting tougher on this issue.

    Could we hope for a better API in later versions of 3.0? (but that is probably overoptimistic).

    At least everyone show add a request for a better API in the bugreporter.

  64. Ben Says:

    Clearly some apps have been rejected - but there are plenty of apps out there that mess with the views, QuadCamera in particular - and also Microsoft Tag Reader. QuadCamera doesn’t seem to have any issues getting accepted, they are up to something like version 1.8 now, suggesting that they have been through the testing process 9 times.

  65. Vishal Says:

    Hi rolando,

    I just want to confirm are you able to grab the screen after displaying the camera preview on it?

    In my application I want video stream from camera before displaying it on screen. I will process that stream and then display on screen. Is this possible?

    You can mail me at vishalnandanwar@gmail.com

    Vishal N

  66. Randy Says:

    Has anyone made any progress in obtaining raw image data from the camera? I know Rolando has successfully achieved this, but we’ve yet to hear from him.

    @Rolando - Are you able to share your methods now? Also, did your app get rejected from the App Store? Could you share you experience with us?

    Also, for those of you who have published apps (or attempted to) that have manipulated the PLCameraView, could you please share your experiences with Apple? Has anyone figured out a way to do this without getting rejected by Apple?

    As Ben has mentioned, there are obviously people out there getting away with this. I would hate to see all my hard work go to waste b/c of a moody app reviewer. Somehow I feel like the only way to slip these apps through the reviewers is to make friends with one of the evangelists over in Cupertino.

    Has anyone made contact with these guys? Furthermore, has anyone gotten specific feedback regarding policy on manipulating PLCameraView?

    My implementation provides a subclass for UIImagePickerController and does not use any “undocumented” API’s so to speak. It seems ridiculous to me that these apps are getting rejected for hiding UI elements using calls like:

    [[[view subviews] objectAtIndex:0] setHidden:YES]

    Thoughts anyone?

  67. /home/ahhong » Blog Archive » [iPhone] Uncovering the Secrets of UIImagePickerController Part 1 Says:

    [...] did not discover everything on my own. I am using some information from lajos, The Air Source, and Erica [...]

  68. UIImagePickerController in 3.0 at Under The Bridge Says:

    [...] as it was very foreseeable indeed that mucking around with the internals of UIImagePickerController as described here would be likely to break with a system revision. [...]

  69. Kristian Evers Says:

    Hi all

    We have been browsing around for some time looking for info about the problems your discussing.
    Today we came across a newly updated app: RedLaser, a barcode reader.

    In their newest version on AppStore they have realtime scanning of the image from the camera, with custom overlays. Has anyone found new possibilities in latest SDK 3.0? Looks like they found a great approach in RedLaser, which passed the appstore review.

  70. Dileep Y Says:

    Hey is this hierarchy is same for all the iphone os version!!! I had iphone 3.0 os my hierarchy is different from yours!!! what can i do with iphone 3.0??

  71. John Says:

    No. The hierarchy has changed in iPhone OS 3.0. And remember that the behaviour is different on the 3GS, which has auto-focus, than on older devices.

  72. EXcell Says:

    I was playing around with PLCameraController. After updates to 3.0 same source code doesnot work. Not yet figure out the issue. Any ideas?

  73. hypno_toad Says:

    Well the new 3.1 OS certainly makes it a lot nicer to change the UI for the UIImagePickerController

    OverlayViewController *oController = [[OverlayViewController alloc] initWithNibName:@”OverlayView” bundle:nil];
    oController.tabController = self;
    self.overlayController = oController;
    [oController release];
    UIImagePickerController *uip = [[[UIImagePickerController alloc] init] autorelease];
    uip.delegate = self;
    uip.sourceType = UIImagePickerControllerSourceTypeCamera;
    uip.showsCameraControls = NO;
    uip.cameraOverlayView = overlayController.view;

    Currently trying to use the takePicture method in a timer to feed a barcode reader. takePicture seems to be taking a picture though it’s a 2MP (3G iPhone for ref), I resize that to 320×480 and feed it to the barcode reader but then it won’t recognize it. For some reason UIGetScreenImage() works really well though. I would like to stay away from using that, so any suggestions?

  74. Jeff Says:

    Has anyone figured out a solution to this trouble? Rolando, if you have a legal way of doing this or anyone else that is reasonably fast I would be willing to pay for the solution. The new 3.1 routines are too slow. UIGetScreenImage() works fast enough for our usage and uses little memory but it is part of the private api. email: delay at pobox dot com if anyone has any code they want to give away or sell that solves this trouble.

Leave a Reply