Skip to content

iPhone Camera Overlay App With Custom Button Example

There seems to be a lot of interest recently in making apps that use a camera view with an overlay for augmented reality or what some might call pseudo-augmented reality applications (because often these apps just layer an image or data on a camera view). I wasn’t satisfied with the few examples I found on the topic so I decided to try one myself. I will endeavour to make it as clear as I can and show you how to make a custom button while I am at it, but I do assume a basic knowledge of Objective-C and iPhone app development in Xcode.

OverlayViewTester screenshot

OverlayViewTester screenshot

So first I will describe the OverlayViewTester app. Basically it just overlays some cool looking red selection braces on a camera view and has a button that when pressed performs a ’scan’ for two seconds and lets you know by adding a “Scanning…” label at the top of the screen during that time. So really it does nothing, but it looks good and is a good first step to making a more fun and interesting interactive camera overlay app.

To get started download the source code from GitHub. Next I will go through the files in the project and present the juicy bits. Consult the source code you downloaded for the full meal deal.

OverlayViewTesterApDelegate

Taking a look at the project we start with a typical app delegate, OverlayViewTesterAppDelegate which loads the OverlayViewController. Nothing monumental there so I won’t bother reproducing it here.

OverlayViewController

Now on to the OverlayViewController where we create the camera view.

In the interface, OverlayViewController.h: we define some constants:

// Transform values for full screen support:
#define CAMERA_TRANSFORM_X 1
#define CAMERA_TRANSFORM_Y 1.12412

// iPhone screen dimensions:
#define SCREEN_WIDTH  320
#define SCREEN_HEIGTH 480

In the implementation, OverlayViewController.m there is a bit of a GOTCHA. The line

[self presentModalViewController:picker animated:YES];

must be called in viewDidAppear: not in a viewDidLoad: method. Here it is:

- (void) viewDidAppear:(BOOL)animated {
    OverlayView *overlay = [[OverlayView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGTH)];

    // Create a new image picker instance:
    UIImagePickerController *picker = [[UIImagePickerController alloc] init];

    // Set the image picker source:
    picker.sourceType = UIImagePickerControllerSourceTypeCamera;

    // Hide the controls:
    picker.showsCameraControls = NO;
    picker.navigationBarHidden = YES;

    // Make camera view full screen:
    picker.wantsFullScreenLayout = YES;
    picker.cameraViewTransform = CGAffineTransformScale(picker.cameraViewTransform, CAMERA_TRANSFORM_X, CAMERA_TRANSFORM_Y);

    // Insert the overlay:
    picker.cameraOverlayView = overlay;

    // Show the picker:
    [self presentModalViewController:picker animated:YES];
    [picker release];

    [super viewDidAppear:YES];
}

I think the comments make it clear what is going on there.

OverlayView

Next lets look at the custom subclass of UIView called OverlayView. This is where we actually create our overlay.

In the interface, OverlayView.h we declare two new methods:

- (void)scanButtonTouchUpInside;
- (void)clearLabel:(UILabel *)label;

Here are the important parts of the implementation, OverlayView.m:

- (id)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        // Clear the background of the overlay:
	self.opaque = NO;
	self.backgroundColor = [UIColor clearColor];

	// Load the image to show in the overlay:
	UIImage *overlayGraphic = [UIImage imageNamed:@"overlaygraphic.png"];
	UIImageView *overlayGraphicView = [[UIImageView alloc] initWithImage:overlayGraphic];
	overlayGraphicView.frame = CGRectMake(30, 100, 260, 200);
	[self addSubview:overlayGraphicView];
	[overlayGraphicView release];

	ScanButton *scanButton = [[ScanButton alloc] initWithFrame:CGRectMake(130, 320, 60, 30)];

	// Add a target action for the button:
	[scanButton addTarget:self action:@selector(scanButtonTouchUpInside) forControlEvents:UIControlEventTouchUpInside];
	[self addSubview:scanButton];
    }
    return self;
}

- (void) scanButtonTouchUpInside {
    UILabel *scanningLabel = [[UILabel alloc] initWithFrame:CGRectMake(100, 50, 120, 30)];
    scanningLabel.backgroundColor = [UIColor clearColor];
    scanningLabel.font = [UIFont fontWithName:@"Courier" size: 18.0];
    scanningLabel.textColor = [UIColor redColor];
    scanningLabel.text = @"Scanning...";

    [self addSubview:scanningLabel];

    [self performSelector:@selector(clearLabel:) withObject:scanningLabel afterDelay:2];

    [scanningLabel release];
}

- (void)clearLabel:(UILabel *)label {
    label.text = @"";
}

Notice that we have used an instance of ScanButton which we will get to next. When the ScanButton detects a UIControlEventTouchUpInside it calls the scanButtonTouchUpInside method which places a label on the screen for 2 seconds.

ScanButton

So finally we are left with our ScanButton. You might think that for a custom button we would subclass UIButton, but unless you really want to use the UIBUtton method setTitle:ForState it is recommended that you subclass UIControl. It will save you a world of hurt.

Here is the interface, ScanButton.h:

#import <Foundation/Foundation.h>

@interface ScanButton : UIControl {
}

- (void)buttonPressed;

@end

I put the buttonPressed method in here for future use. It is meant to be used to change things related to the button itself and not the actions associated with the button in the OverlayViewController. You could for example use it to have the button’s image or state or both toggle.

Last but not least we have the implementation, ScanButton.m:

#import "ScanButton.h"

@implementation ScanButton

- (id)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
	// Set button image:
	UIImageView *buttonImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 60, 30)];
	buttonImage.image = [UIImage imageNamed:@"scanbutton.png"];

	[self addTarget:self action:@selector(buttonPressed) forControlEvents:UIControlEventTouchUpInside]; // for future use

        [self addSubview:buttonImage];
    }
    return self;
}

- (void)buttonPressed {
    // TODO: Could toggle a button state and/or image
}

@end

So there you have it. A custom camera overlay and a custom button. I hope that with this code you will be well on your way to writing much more useful, interesting and creative apps than this example. Happy coding!

  • Digg
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • Technorati
  • LinkedIn
  • RSS
  • Slashdot
  • Twitter

{ 11 } Comments

  1. Rennen Chacham | 2010 01 08 at 9:21 am | Permalink

    The code in GitHub fails to run on a machine, as it’s missing the OverLayController.xib nib file.
    The OverLayController.xib is referenced in MainWindow.xib.

    Did I get anything wrong or the file is really missing?

  2. Jason Job | 2010 01 09 at 12:20 am | Permalink

    Hi Rennen,

    There is no OverlayController.xib. The only nib file is the MainWindow one. I just double checked the Xcode project and GitHub and everything is there as it should be.

    Could you give me more details on what isn’t working for you. I’d be happy to help you get it to work.

    Jason

  3. Claris Li | 2010 02 04 at 7:29 am | Permalink

    Jason,

    You can fix it by creating a new “View XIB” file called OverlayViewController.xib and setting the File’s Owner class to OverlayViewController. Remember to set the view outlet too.

    It should work after you done these steps.

    Best,
    Claris

  4. Jason Job | 2010 02 23 at 1:53 pm | Permalink

    Thank you Claris! I’m still unclear why this was working on my phone without the OverlayViewController.xib but hopefully your fix will get this working for everyone that was having problems. I have updated the project at github. Thanks again!

  5. Antoine | 2010 02 24 at 3:23 am | Permalink

    Hi thanks for the great tutorial, it was extremly helpful!
    Is their a way to create the overlay view directly from the nib or does it all have to be in code?

    Thanks again
    Antoine

  6. Antoine | 2010 02 24 at 5:00 am | Permalink

    I was also wondering if I could change the size of the camera view

  7. Marian | 2010 02 24 at 7:14 am | Permalink

    How can I access the pixels in the red square d area?
    And is there any way I can resize that area on screen ?

    Sorry if it sounds stupid to you but I am new with iPhone dev.

    Regards,
    Marian

  8. Jason Job | 2010 02 24 at 12:57 pm | Permalink

    Hi Antoine,

    I don’t think you can create the overlay view in the nib. If someone knows better please let us know.

    Jason

  9. Jason Job | 2010 02 24 at 1:05 pm | Permalink

    Antoine,

    Absolutely you can change the size.

    Look for this line (17) in OverlayViewController.m:

    OverlayView *overlay = [[OverlayView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGTH)];

    You can change SCREEN_WIDTH and SCREEN_HEIGHT to be whatever you want.

    Let me know how that works for you. I’m interested if and how this might affect the picker.cameraViewTransform.

    Good luck!

  10. Antoine | 2010 02 25 at 6:17 am | Permalink

    Jason to change the size all you have to do is go into the ViewController.h and change these values:

    #define CAMERA_TRANSFORM_X 1
    #define CAMERA_TRANSFORM_Y 1.12412

    Funny I scaled them to half and I got a quater sized camera view!

  11. Antoine | 2010 02 25 at 6:19 am | Permalink

    Oh ya almost forgot you have to set the following propert y to no and not yes:

    picker.wantsFullScreenLayout = NO;

Post a Comment

Your email is never published nor shared. Required fields are marked *