63

screenshot

I'm adding a custom overlay to the UIImagePickerController and there is a persistant black bar at the bottom of the view. Here is my code to instantiate the controller.

- (UIImagePickerController *)imagePicker {
    if (_imagePicker) {
        return _imagePicker;
    }

    _imagePicker = [[UIImagePickerController alloc] init];
    _imagePicker.delegate = self;

    if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
        _imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;

        _imagePicker.showsCameraControls = NO;

        _imagePicker.wantsFullScreenLayout = YES;
        _imagePicker.navigationBarHidden = YES;
        _imagePicker.toolbarHidden = YES;

    } else {
        _imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
    }

    return _imagePicker;
}

The returned controller is displayed modally and works just fine (i.e. displays full screen) when I'm not hiding the camera controls.


Thanks to Ole's suggestion I got it working with this code:

// Resize the camera preview
        _imagePicker.cameraViewTransform = CGAffineTransformMakeScale(1.0, 1.03);

A 3% increase in height worked just fine. When I add my custom toolbar at the bottom of the screen there is no longer a visible black bar across the window.

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
kubi
  • 48,104
  • 19
  • 94
  • 118

15 Answers15

55

Scaling by a fixed value isn't a good idea... as I'm sure anyone who used the accepted answer here probably found out when the iPhone 5 came out.

Here's a code snippet to scale dynamically based on the screen resolution to eliminate the letter boxing.

// Device's screen size (ignoring rotation intentionally):
CGSize screenSize = [[UIScreen mainScreen] bounds].size;

// iOS is going to calculate a size which constrains the 4:3 aspect ratio
// to the screen size. We're basically mimicking that here to determine
// what size the system will likely display the image at on screen.
// NOTE: screenSize.width may seem odd in this calculation - but, remember,
// the devices only take 4:3 images when they are oriented *sideways*.
float cameraAspectRatio = 4.0 / 3.0;
float imageWidth = floorf(screenSize.width * cameraAspectRatio);
float scale = ceilf((screenSize.height / imageWidth) * 10.0) / 10.0;

self.ipc.cameraViewTransform = CGAffineTransformMakeScale(scale, scale);
Steve
  • 31,144
  • 19
  • 99
  • 122
  • @Danpe were you able to find a solution for iPhone 5? I am having the same issue - thanks! – daspianist Dec 26 '13 at 16:44
  • It's working fine for iPhone 5 devices. But I am facing another issue. After taking the photo, I am trying to preview the same in a UIImageView. There the image is getting shifted towards right side compared to what the user is capturing in camera. Any fix for that? – Rashmi Ranjan mallick Jul 23 '14 at 07:15
  • After using above, large space reduced to small space. Not fully solved. – arunit21 Sep 04 '14 at 08:42
  • @Steve why *10.0 then /10.0? – M.Y. Sep 23 '14 at 11:49
  • 1
    @steve, could you take a look at this for iPhone 6/iPhone 6Plus please, this doesn't quite fill up the screen yet. A simple project with the imagepicker loading in the parent view controller as a test with this code copied and pasted will yield the same results as mine. Please do get back to us, cheers. – Pavan Dec 25 '14 at 05:34
  • @Pavan, I don't know if your case is the same than mine, but as I was using video instead of photos the aspect ratio is 16 / 9, then I could get the full screen. – Hola Soy Edu Feliz Navidad Mar 13 '15 at 10:03
  • @HolaSoyEduFelizNavidad yeah buddy. I found out the same in the end. I ended up using a video by setting up the camera with AVFoundation framework. Then you have to capture the screen by using a build in process JPEG method which captures an image of the capture device. – Pavan Mar 13 '15 at 12:06
  • @steve @ Rashmi Ranjan mallick, By using CGAffineTransformMakeScale I am able to make my camera to full screen. I have saved the captured image to gallery. But the saved image and the image captured are different. Is there any possible way to fix this? – MouzmiSadiq Jan 08 '16 at 10:47
  • 4
    Scaling doesn't work on iOS 10 beta 7 for me. Any help or ideas? – Rashmi Ranjan mallick Aug 24 '16 at 13:37
  • @RashmiRanjanmallick do you use a CameraOverlayView? For me, that was the problem - in iOS 10, the pinch gesture isn't passed down to the image picker itself. – Glorfindel Sep 16 '16 at 11:06
38

The camera's aspect ratio is 4:3 and the screen's aspect ratio is 3:2. So there is simply no way for the camera picture to fill the screen unless you're willing to crop is to 3:2. To do that, apply an appropriate scale transform.

Ole Begemann
  • 135,006
  • 31
  • 278
  • 256
  • This was exactly it. Thanks! I'm going to update my question with the code that got everything working. – kubi Apr 26 '10 at 23:02
  • 8
    Does anyone have an answer to this that will work on all devices? Scaling with the factors above will distort the picture and scaling with ANY hard-coded number will only work on a device with the same form factor and coordinate system. Is there a way to find the camera view frame and bounds and adjust to the window's bounds? – George Sep 18 '12 at 19:31
22

Hey I saw some people were still getting the black bar at the bottom after calculating the scale for the iPhone 5. I had this problem for a while but then I figured out you have to translate the view so it is in the middle of the screen and then apply the scale. Here is my code for doing those two things and it works for me!

    CGSize screenBounds = [UIScreen mainScreen].bounds.size;

    CGFloat cameraAspectRatio = 4.0f/3.0f;

    CGFloat camViewHeight = screenBounds.width * cameraAspectRatio;
    CGFloat scale = screenBounds.height / camViewHeight;

    m_imagePickerController.cameraViewTransform = CGAffineTransformMakeTranslation(0, (screenBounds.height - camViewHeight) / 2.0);
    m_imagePickerController.cameraViewTransform = CGAffineTransformScale(m_imagePickerController.cameraViewTransform, scale, scale);
strikerdude10
  • 283
  • 3
  • 9
  • This solution works great on the iPhone 5. However, as reported [in this question](http://stackoverflow.com/questions/2042306/scaled-live-iphone-camera-view-in-center-cgaffinetransformtranslate-not-worki), CGAffineTransformTranslate doesn't work in UIImagePickerController with older iOS (not sure when they fixed it). In addition, it seems that you need to do the `ceilf` rounding trick in Steve's answer in order for the CGAffineTransformScale to work in older iOS. – sffc Jan 05 '14 at 11:59
  • 1
    You are right, I should have added "iPhone 5 running iOS 7". I was pulling my hair out for a while with the CGAffineTransformScale not working in older iOSs. – strikerdude10 Jan 06 '14 at 19:49
  • 1
    Working great. Saved a lot of time. – Nazik Dec 24 '14 at 13:42
  • @strikerdude10 Thanks a lot buddy ! – Sam Jul 01 '15 at 13:13
  • @EpicByte can you please confirm it works on iPhone 6 & 6+ ? – Sam Jul 01 '15 at 13:13
11

From my experience on iOS 7, iphone 5S, to see the center of the picture into the full-screen preview you have to concatenate the transformations, not make them sequentially:

pickerController.cameraOverlayView = self.view;

CGSize screenSize = [[UIScreen mainScreen] bounds].size;   // 320 x 568

float scale = screenSize.height / screenSize.width*3/4;  // screen height divided by the pickerController height ... or:  568 / ( 320*4/3 )

CGAffineTransform translate=CGAffineTransformMakeTranslation(0,(screenSize.height - screenSize.width*4/3)*0.5);
CGAffineTransform fullScreen=CGAffineTransformMakeScale(scale, scale);
pickerController.cameraViewTransform =CGAffineTransformConcat(fullScreen, translate);
Enrico Cupellini
  • 447
  • 7
  • 14
10

Transform it with this:

#define CAMERA_TRANSFORM                    1.12412

_picker.wantsFullScreenLayout = YES;
_picker.cameraViewTransform = CGAffineTransformScale(_picker.cameraViewTransform, CAMERA_TRANSFORM, CAMERA_TRANSFORM);
emenegro
  • 6,901
  • 10
  • 45
  • 68
6

And here the answer in Swift.

let screenSize:CGSize = UIScreen.mainScreen().bounds.size

let ratio:CGFloat = 4.0 / 3.0
let cameraHeight:CGFloat = screenSize.width * ratio
let scale:CGFloat = screenSize.height / cameraHeight

let imag:UIImagePickerController = UIImagePickerController()
imag.cameraViewTransform = CGAffineTransformMakeTranslation(0, (screenSize.height - cameraHeight) / 2.0)
imag.cameraViewTransform = CGAffineTransformScale(imag.cameraViewTransform, scale, scale)
M.Othman
  • 5,132
  • 3
  • 35
  • 39
teawithfruit
  • 767
  • 1
  • 11
  • 22
6

This worked for me on iOS 10:

let screenSize = UIScreen.main.bounds.size
let cameraAspectRatio = CGFloat(4.0 / 3.0)
let cameraImageHeight = screenSize.width * cameraAspectRatio
let scale = screenSize.height / cameraImageHeight
imagePickerController.cameraViewTransform = CGAffineTransform(translationX: 0, y: (screenSize.height - cameraImageHeight)/2)
imagePickerController.cameraViewTransform = imagePickerController.cameraViewTransform.scaledBy(x: scale, y: scale)
Furkan Fidan
  • 121
  • 1
  • 4
3

I used this method to calculate the scale.

// get the screen size
CGSize screenSize = [[UIScreen mainScreen] bounds].size;
// establish the height to width ratio of the camera
float heightRatio = 4.0f / 3.0f;
// calculate the height of the camera based on the screen width
float cameraHeight = screenSize.width * heightRatio;
// calculate the ratio that the camera height needs to be scaled by
float scale = screenSize.height / cameraHeight;
imagePicker.cameraViewTransform = CGAffineTransformMakeScale(scale, scale);
Ali Gangji
  • 1,463
  • 13
  • 22
2

my issue solved :)

//Camera is 426 * 320. Screen height is 568.  Multiply by 1.333 in 5 inch (iPhone5) to fill vertical

CGAffineTransform translate = CGAffineTransformMakeTranslation(0.0, 71.0); //This slots the preview exactly in the middle of the screen by moving it down 71 points
self.imagePickerController.cameraViewTransform = translate;

CGAffineTransform scale = CGAffineTransformScale(translate, 1.333333, 1.333333);
self.imagePickerController.cameraViewTransform = scale;
arunit21
  • 670
  • 1
  • 11
  • 25
2

These solutions did not work in total for me. There was still a black bar at the bottom running under iOS 13.x and using an iPhone 6+ and an iPhone 11 Pro. I was able to resolve for both, without using magic numbers, by calculating the offset to center and applying that to the scale calculation. This worked again with both a 6+ and an 11 Pro.

    let screenSize = UIScreen.main.bounds.size
    let cameraAspectRatio = CGFloat(4.0 / 3.0)
    let cameraImageHeight = screenSize.width * cameraAspectRatio
    let offsetToCenter = screenSize.height - cameraImageHeight
    let scale = (screenSize.height + offsetToCenter) / cameraImageHeight

    if UIImagePickerController.isSourceTypeAvailable(.camera) {
        myPickerController.delegate = self
        myPickerController.sourceType = .camera
        myPickerController.showsCameraControls = false
        myPickerController.allowsEditing = false
        myPickerController.cameraViewTransform = CGAffineTransform(scaleX: scale, y: scale)
        myPickerController.cameraOverlayView = CameraOverlay(frame: vc.view.frame, delegate: self)
        currentVC.present(myPickerController, animated: true)
    }
}
C6Silver
  • 3,127
  • 2
  • 21
  • 49
1

Swift 5

100% working Easy Solution If you want show camera in some custom UIView so use that code and camera will be show in full screen

class ViewController: UIViewController, UINavigationControllerDelegate,UIImagePickerControllerDelegate {


}

upper section is for delegate and bottom is function

//Mark:- Call this function and enjoy
var imagePickers:UIImagePickerController?
func addCameraInView(){
    imagePickers = UIImagePickerController()
    if UIImagePickerController.isCameraDeviceAvailable( UIImagePickerController.CameraDevice.rear) {
        imagePickers?.delegate = self
        imagePickers?.sourceType = UIImagePickerController.SourceType.camera
        //imagePickers?.view.frame = customCameraView.bounds
        imagePickers?.view.contentMode = .scaleAspectFit
        imagePickers?.allowsEditing = false
        imagePickers?.showsCameraControls = false
        imagePickers?.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]

       //Mark:- this part is handling camera in full screen in a custom view
       // let screenSize = UIScreen.main.bounds.size
        let screenSize = customCameraView.bounds.size
        let cameraAspectRatio = CGFloat(4.0 / 4.0)
        let cameraImageHeight = screenSize.width * cameraAspectRatio
        let scale = screenSize.height / cameraImageHeight
        imagePickers?.cameraViewTransform = CGAffineTransform(translationX: 0, y: (screenSize.height - cameraImageHeight)/2)
        imagePickers?.cameraViewTransform = (imagePickers?.cameraViewTransform.scaledBy(x: scale, y: scale))!

        // Add the child's View as a subview
        self.customCameraView.addSubview((imagePickers?.view)!)
    }
}

if you want it from main screen then you need to change the ratio (4.0/3.0)

   let screenSize = UIScreen.main.bounds.size
   let cameraAspectRatio = CGFloat(4.0 / 3.0)

enter image description here

Shakeel Ahmed
  • 5,361
  • 1
  • 43
  • 34
0

This is what works for me with Swift 4

let screenSize: CGSize = picker.view.safeAreaLayoutGuide.layoutFrame.size
let ratio: CGFloat = 4.0 / 3.0
let cameraHeight: CGFloat = screenSize.width * ratio
let scale: CGFloat = (screenSize.height + 80) / cameraHeight
picker.cameraViewTransform = picker.cameraViewTransform.scaledBy(x: scale, y: scale)
Schnodderbalken
  • 3,257
  • 4
  • 34
  • 60
0

Following works for me to eliminate Letter boxing and capture full screen images matching exact device height. The code is written in Swift 5.

 // Eliminate letter boxing
 let screenSize = UIScreen.main.bounds
 let cameraAspectRatio: CGFloat = 4.0 / 3.0
 let imageHeight = screenSize.width * cameraAspectRatio
 let scale = ceil((screenSize.height / imageHeight) * 10.0) / 10.0
 var transform = CGAffineTransform(translationX: 0, y: (screenSize.height - imageHeight) / 2)
 transform = transform.scaledBy(x: scale, y: scale)
 picker.cameraViewTransform = transform
Tharindu Madushanka
  • 3,241
  • 7
  • 31
  • 33
-1

Try use this code:

picker.wantsFullScreenLayout = YES;
CGAffineTransform translate = CGAffineTransformMakeTranslation(0.0, 71.0);
CGAffineTransform scale = CGAffineTransformScale(translate, 1.333333, 1.47);
picker.view.transform = scale;
objectively C
  • 960
  • 9
  • 25
vualoaithu
  • 936
  • 10
  • 9
-1
PickerViewController.m    
#define CAMERA_TRANSFORM  1.8

- (void)viewDidAppear:(BOOL)animated
{
 if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
    {
       // type = UIImagePickerControllerSourceTypeCamera;

        UIImagePickerController *picker = [[UIImagePickerController alloc] init];
        picker.allowsEditing = NO;
        picker.delegate   = self;
        picker.sourceType = UIImagePickerControllerSourceTypeCamera;
        picker.showsCameraControls=NO;
        picker.extendedLayoutIncludesOpaqueBars = YES;
        picker.cameraViewTransform = CGAffineTransformScale(picker.cameraViewTransform, CAMERA_TRANSFORM , CAMERA_TRANSFORM);

        [self presentViewController:picker animated:YES completion:nil];
    }else{

        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Message"
                                                        message:@"Device have no camera"
                                                       delegate:self
                                              cancelButtonTitle:@"OK"
                                              otherButtonTitles:nil];
        [alert show];
    }
}
maddie
  • 1,854
  • 4
  • 30
  • 66
SWAMY CHUNCHU
  • 225
  • 5
  • 14