Tailor made Camera Purposes Development Utilizing Iphone Sdk

Iphone consists of many helpful options. 1 of them is develop-in digicam and Camera software technique for building photos. It seems to be wonderful but what about digicam use with indigenous purposes? Iphone SDK gives the ability of working with digicam via UIImagePickerController class. Which is wonderful but there is a compact disadvantage – you simply cannot develop a entire-monitor persistent “live” digicam view like the Camera software does. As an alternative of that you need to use UIImagePickerController only in modal manner – present the pop-up modal view when you have to have a photo and shut the view immediately after the photo is created. You have to reopen this view once again to consider the subsequent just one.

Also, that modal view consists of more panels and controls that overlay the digicam view. An additional disadvantage is – you simply cannot consider a photo in just one contact you have to have to contact the Shoot button to consider a picture and preview it, and then you have to have to contact the Help save button to get the photo for processing. In all probability it is the very best practice but I really don’t like it and I hope you feel the same way.

What about working with the UIImagePickerController as an ordinal non-modal view controller less than the navigation controller the same way as we use the other view controllers? Test it and you will located that it operates! The digicam view operates and seems to be as it need to. You can assign a delegate and system UIImagePickerControllerDelegate occasions to get and conserve the photo. Alright, contact the Shoot button, contact the Help save button – wonderful, you have obtained the photo! But just appear at this – the Retake and Help save buttons keep above the digicam view, and they really don’t perform now when they are touched… This is for the reason that you simply cannot reset the view to consider a further photo immediately after having just one and touching the Help save button, the view is freezed and the buttons are disabled. It looks you have to have to completely recreate the UIImagePickerController instance to consider a further photo. Which is not so uncomplicated and not so excellent. And you continue to have to have to use the panels and buttons that overlay the digicam view…

Now I have an strategy! When we contact Shoot, the view stops refreshing and displays solitary graphic from the digicam then we have to contact Retake or Help save button. Can we get that graphic and conserve it devoid of working with the UIImagePickerControllerDelegate and then contact the Retake button programmatically to reset the view and get a further photo? Confident we can! If you take a look at the digicam sights hierarchy immediately after touching Shoot you will uncover that there is a concealed view of ImageView sort. This class is not described in the SDK, but we can take a look at its’ techniques working with Aim-C abilities. We can see that the class consists of a strategy called imageRef. Let us test this… Yes, it returns CGImage object! And the graphic size is 1200 x 1600 – it is undoubtedly the digicam picture!

Alright, now we know we can get the photo devoid of UIImagePickerControllerDelegate. But in what minute need to we do this? Can we capture the person touches on the Shoot button to start off processing? It is possible but not so excellent. Do you don’t forget our primary objective – building the persistent entire-monitor digicam view like technique Camera software does? It is time to do it! When we explored the sights hierarchy, we have located that there are quantity of sights above the digicam view. We can test to disguise these sights and develop our individual button beneath the digicam view to consider the photo in just one contact. But how can we drive the digicam view to make the photo? It is incredibly uncomplicated – we can get the corresponding selector from the Shoot button and phone it from our motion handler!

Alright, we have forced receiving the graphic. But it can take us several seconds. How can we detect that the graphic is ready? It transpired when the Cancel and Shoot buttons are replaced by Retake and Help save ones. The simplest way to detect this is beginning a timer with limited interval and checking the buttons. And then we can get and conserve the photo, working with the corresponding selector from the Retake button and contacting it to reset the digicam view and get ready it for building a new just one. In this article is the code:

// Shot button on the toolbar touched. Make the photo.
– (void)shotAction:(id)sender
[self enableInterface:NO]
// Simulate contact on the Image Picker’s Shot button
UIControl *camBtn = [self getCamShutButton]
[camBtn sendActionsForControlEvents:UIControlEventTouchUpInside]

// Set up timer to test the digicam controls to detect when the graphic
// from the digicam will be geared up.
// Image Picker’s Shot button is passed as userInfo to look at with latest button.
[NSTimer scheduledTimerWithTimeInterval:.two goal:self selector:@selector(savePhotoTimerFireMethod:) userInfo:camBtn repeats:NO]

// Return Image Picker’s Shoot button (the button that can make the photo).
– (UIControl*) getCamShutButton

UIView *topView = [self findCamControlsLayerView:self.view]
UIView *buttonsBar = [topView.subviews objectAtIndex:two]
UIControl *btn = [buttonsBar.subviews objectAtIndex:one]

return btn

// Return Image Picker’s Retake button that appears immediately after the person pressed Shoot.
– (UIControl*) getCamRetakeButton

UIView *topView = [self findCamControlsLayerView:self.view]
UIView *buttonsBar = [topView.subviews objectAtIndex:two]
UIControl *btn = [buttonsBar.subviews objectAtIndex:]

return btn

// Locate the view that consists of the digicam controls (buttons)
– (UIView*)findCamControlsLayerView:(UIView*)view

Class cl = [view class]
NSString *desc = [cl description]
if ([desc look at:@”PLCropOverlay”] == NSOrderedSame)
return view

for (NSUInteger i = i < [view.subviews count] i++) UIView *subView = [view.subviews objectAtIndex:i]
subView = [self findCamControlsLayerView:subView]
if (subView)
return subView

return nil

// Referred to as by the timer. Look at the digicam controls to detect that the graphic is ready.
– (void)savePhotoTimerFireMethod:(NSTimer*)theTimer

// Look at latest Image Picker’s Shot button with passed.
UIControl *camBtn = [self getCamShutButton]
if (camBtn != [theTimer userInfo])

// The button replaced by Help save button – the graphic is ready.
[self saveImageFromImageView]

// Simulate contact on Retake button to proceed operating the digicam is ready to consider new photo.
camBtn = [self getCamRetakeButton]
[camBtn sendActionsForControlEvents:UIControlEventTouchUpInside]

[self enableInterface:Yes]


NSTimeInterval interval = [theTimer timeInterval]
[NSTimer scheduledTimerWithTimeInterval:interval goal:self selector:@selector(savePhotoTimerFireMethod:) userInfo:camBtn repeats:NO]

// Help save taken graphic from concealed graphic view.
– (BOOL)saveImageFromImageView

UIView *cameraView = [self.view.subviews objectAtIndex:]
if ([self enumSubviewsToFindImageViewAndSavePhoto:cameraView])
return Yes

return NO

// Recursive enumerate subviews to uncover concealed graphic view and conserve photo
– (BOOL)enumSubviewsToFindImageViewAndSavePhoto:(UIView*)view

Class cl = [view class]
NSString *desc = [cl description]
if ([desc look at:@”ImageView”] == NSOrderedSame)
return [self grabPictureFromImageView:view]

for (int i = i < [view.subviews count] i++) if ([self enumSubviewsToFindImageViewAndSavePhoto:[view.subviews objectAtIndex:i]])
return Yes

return NO

// Get the graphic from concealed graphic view and conserve the photo
– (BOOL)grabPictureFromImageView:(UIView*)view

CGImageRef img = (CGImageRef)[view imageRef]
if (img)

// Taken graphic is in UIImageOrientationRight orientation
UIImage *photo = [self correctImageOrientation:img]
UIImageWriteToSavedPhotosAlbum(photo, nil, nil, nil)

return Yes

return NO

// Correct graphic orientation from UIImageOrientationRight (rotate on ninety levels)
– (UIImage*)correctImageOrientation:(CGImageRef)graphic

CGFloat width = CGImageGetWidth(graphic)
CGFloat top = CGImageGetHeight(graphic)
CGRect bounds = CGRectMake(.0f, .0f, width, top)

CGFloat boundHeight = bounds.size.top
bounds.size.top = bounds.size.width
bounds.size.width = boundHeight

CGAffineTransform change = CGAffineTransformMakeTranslation(top, .0f)
change = CGAffineTransformRotate(change, M_PI / two.0f)


CGContextRef context = UIGraphicsGetCurrentContext()

CGContextScaleCTM(context, – one.0f, one.0f)
CGContextTranslateCTM(context, -top, .0f)
CGContextConcatCTM(context, change)

CGContextDrawImage(context, CGRectMake(.0f, .0f, width, top), graphic)

UIImage *imageCopy = UIGraphicsGetImageFromCurrentImageContext()


return imageCopy

An additional crucial problem is: in what minute can we disguise the overlaying digicam sights and controls and develop our individual button? Hoping the viewDidLoad… Oops… The digicam view is continue to not created. Hoping the viewWillAppear… The same thing… Hoping the viewDidAppear… Yes, the sights have been created and can be concealed now. Alright, we disguise that and develop a toolbar with our Shoot button. It operates, but the monitor flicks – we see how the regular sights and buttons are proven and then concealed. How can we reduce this? I tried out a quantity of approaches and experienced located the very best just one: we need to disguise the sights ahead of they are added to the digicam view (when the addSubview strategy of the digicam view is called). It is possible working with Aim-C ability to replace the strategy dynamically at operate-time. Alright, let’s replace the addSubview by our individual strategy. In our strategy we can test that the passed view is just one of the digicam view subviews and set its’ “hidden” house to Yes. So, we replace the addSubview in the viewWillAppear ahead of the digicam view is created. And we develop our toolbar and Shoot button in the viewDidAppear immediately after the digicam view is created. Just take a appear at the code beneath:

// Change “addSubview:” if called initially time disguise digicam controls or else.
– (void)viewWillAppear:(BOOL)animated {

[super viewWillAppear:animated]

if (toolBar != nil)
// The view was presently appeared we will not have to have to subclass UIView
// but have to have to disguise added digicam controls.
UIView *cameraView = [self findCamControlsLayerView:self.view]
if (cameraView)

cameraView = cameraView.superview
int cnt = [cameraView.subviews count]
if (cnt >= four)

for (int i = two i < cnt - 1 i++) UIView *v = [cameraView.subviews objectAtIndex:i]
v.concealed = Yes


// Subclass UIView and replace addSubview to disguise the digicam view controls on fly.
[RootViewController exchangeAddSubViewFor:self.view]


// Trade addSubview: of UIView class set our individual myAddSubview as an alternative
+ (void)exchangeAddSubViewFor:(UIView*)view

SEL addSubviewSel = @selector(addSubview:)
Technique originalAddSubviewMethod = class_getInstanceMethod([view class], addSubviewSel)

SEL myAddSubviewSel = @selector(myAddSubview:)
Technique replacedAddSubviewMethod = class_getInstanceMethod([self class], myAddSubviewSel)

strategy_exchangeImplementations(originalAddSubviewMethod, replacedAddSubviewMethod)

// Incorporate the subview to view “self” factors to the mum or dad view.
// Set “concealed” to Yes if the subview is the digicam controls view.
– (void) myAddSubview:(UIView*)view

UIView *mum or dad = (UIView*)self

BOOL performed = NO
Class cl = [view class]
NSString *desc = [cl description]

if ([desc look at:@”PLCropOverlay”] == NSOrderedSame)

for (NSUInteger i = i < [view.subviews count] i++) UIView *v = [view.subviews objectAtIndex:i]
v.concealed = Yes

performed = Yes

[RootViewController exchangeAddSubViewFor:mum or dad]

[mum or dad addSubview:view]

if (!performed)
[RootViewController exchangeAddSubViewFor:mum or dad]

The approach described above was utilized in iUniqable software readily available from Apple Application Retailer (Social Networking part). Feel free of charge to use.

Feel free of charge to go to the website of the developer www.enterra-inc.com