Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIImagePickerController Camera view size issue

I'm building an app using the UIImagePickerController and a custom Overlay. What is does is comparing two images (before image and after image). I am using a custom overlay with the before image when taking the after photo(please see the image attached).

iPhone 5 - ios7 enter image description here

iPhone 4 - iOS7 (When taking the image) enter image description here

iPhone 4 - iOS 7 (After taking the photo) enter image description here

See the size difference between iPhone 4 and iPhone 5 camera view.

Application works fine with iPhone 5 screen size(Both ios 6 and ios7). But iPhone 4/4s screen size, it works fine ONLY with iOS6. The issue is with iphone 4/4s(ios7 ONLY), Camera view takes full screen. That means, you can notice iPhone 5 camera view size ~ 320*427 (iOS 6 and iOS 7) iPhone 4 camera view size ~ 320*427 (iOS 6) BUT iPhone 4 camera view size ~ 320*480 (iOS 7).

After the image is taken, it fitted to the actual size of 320*427. Because of this issue, I cannot align before image with camera view on iPhone 4 iOS7 (because its screeches to 320*480).

Does anyone faces this strange issue. I tried almost everything, but NO luck. Any ideas please???

This is my piece code for loading the camera view with custom before photo overlay.

- (void)loadCameraWithImage
{
    if (!isLoadedOnce)
    {
    isLoadedOnce = YES;
            UIImagePickerController *cameraView = [[UIImagePickerController alloc] init];
           cameraView.sourceType = UIImagePickerControllerSourceTypeCamera;
           cameraView.wantsFullScreenLayout = NO;

        if ([self respondsToSelector:@selector(setEdgesForExtendedLayout:)]) {
         [self setEdgesForExtendedLayout:UIRectEdgeNone];
        }


    // crop before image

    UIImage *imgTmpCropped = [self imageByCropping:imgBefore toRect:CGRectMake(0, 0, imgBefore.size.width/2, imgBefore.size.height)];
    UIImage *overleyImage = [[UIImage alloc] initWithCGImage: imgTmpCropped.CGImage
                                                   scale: [UIScreen mainScreen].scale
                                             orientation: UIImageOrientationDownMirrored];

    UIImageView *crosshairView;
    UIImageView *beforeView;

    CGFloat screenHieght = [UIScreen mainScreen].bounds.size.height;

    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad){
        //overleyImage = [UIImage imageNamed:@"overlay_ipad.png"];
        crosshairView = [[UIImageView alloc] initWithImage:overleyImage];
        crosshairView.frame = CGRectMake(0, 0, 768, 1024);
        [crosshairView setUserInteractionEnabled:YES];
        crosshairView.backgroundColor = [UIColor clearColor];

        beforeView = [[UIImageView alloc] initWithImage:overleyImage];
        beforeView.frame = CGRectMake(0, 0, 384, 1024);
        beforeView.alpha = 0.5;
        beforeView.contentMode = UIViewContentModeScaleAspectFill;
    }

    else {
        //overleyImage = [UIImage imageNamed:@"overleyImageAfter.png"];
        crosshairView = [[UIImageView alloc] init];
        beforeView = [[UIImageView alloc] initWithImage:overleyImage];

        if(screenHieght>500){
            crosshairView.frame = CGRectMake(0, 60, 320, 480);
            beforeView.frame = CGRectMake(0, 70, 160, 427);
        }
        else{

            if([[[UIDevice currentDevice] systemVersion] floatValue] <7.0){
                crosshairView.frame = CGRectMake(0, 0, 320, 480);
                beforeView.frame = CGRectMake(0, 0, 160, 427);
            }
            else{
                crosshairView.frame = CGRectMake(0, 0, 320, 480);
                beforeView.frame = CGRectMake(0, 0, 160, 480);
            }

        }

        [crosshairView setUserInteractionEnabled:YES];
        crosshairView.backgroundColor = [UIColor clearColor];
        beforeView.alpha = 0.5;
        beforeView.contentMode = UIViewContentModeScaleToFill;
    }


    //[crosshairView addSubview:beforeView];

    //set our custom overlay view
    cameraView.cameraOverlayView = beforeView;
    cameraView.delegate = (id)self;
    cameraView.showsCameraControls = YES;
    cameraView.navigationBarHidden = YES;
    cameraView.toolbarHidden = YES;
    [cameraView setHidesBottomBarWhenPushed:YES];


    [self.view.window.rootViewController presentViewController:cameraView animated:YES completion:nil];

    isLoadedOnce = NO;
}

}

like image 246
smartsanja Avatar asked Feb 11 '14 11:02

smartsanja


1 Answers

TL;DR

Camera's preview has the same aspect ratio in every device (4:3), screens don't. Asume the preview will have that specific aspect ratio and that it will be placed in a specific position on the screen. Draw your overlay inside that area.

Longer:

We faced the same issue. (Our use case is taking pictures of credit cards with an overlay with the same size as a card). The main problem is that the camera preview's proportions are always the same (4:3) in every device but different phones have different screen proportions (iPhone 4s vs iPhone 5, for example) so the preview's need to be fitted differently and that makes putting an overlay and cropping that very difficult.

Our solution was (the code is somewhat messy and hacky, sorry):

    // Adjust camera preview to be a little bit more centered instead of adjusted to the top
    CGSize screenSize = [[UIScreen mainScreen] bounds].size;
    float cameraAspectRatio = 4.0 / 3.0;
    float imageHeight = screenSize.width * cameraAspectRatio;
    float verticalAdjustment;
    if (screenSize.height - imageHeight <= 54.0f) {
        verticalAdjustment = 0;
    } else {
        verticalAdjustment = (screenSize.height - imageHeight) / 2.0f;
        verticalAdjustment /= 2.0f; // A little bit upper than centered
    }
    CGAffineTransform transform = self.cameraController.cameraViewTransform;
    transform.ty += verticalAdjustment;
    self.cameraController.cameraViewTransform = transform;

    CGRect previewFrame = CGRectMake(0, verticalAdjustment, screenSize.width, imageHeight);
    CardPhotoView *overlayView = [[CardPhotoView alloc] initWithFrame:CGRectMake(0, 0, screenSize.width, screenSize.height) widthPercentageOfCamera:self.widthPercentageOfCamera previewFrame:previewFrame];
    self.overlayView = overlayView;

    self.overlayView.delegate = self;
    self.overlayView.useViewport = YES;
    [self.overlayView setCameraReady:NO];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(cameraIsReady:) name:AVCaptureSessionDidStartRunningNotification object:nil];

    self.cameraController.showsCameraControls = NO;
    self.cameraController.navigationBarHidden = YES;
    self.cameraController.toolbarHidden = YES;
    self.cameraController.cameraOverlayView = self.overlayView;

    [self presentViewController:self.cameraController animated:NO completion:nil];

Explanation:

self.cameraController is a UIImagePickerController. CardPhotoView is a view subclass that draws the overlay, it takes the preview frame to know exactly where the preview will be positioned (some devices will have black bars on top and bottom, some won't). It also takes a width percentage to add a little padding to the cropping window. Also, we have hidden all default camera controls and we have implemented some buttons that will do the work for us. Those buttons are added in the CardPhotoView class and they are drawn taking into account where the preview frame is.

like image 118
txulu Avatar answered Oct 22 '22 12:10

txulu