Как получить пользовательский оверлей для камеры UIImagePicker в полноэкранном режиме в iOS 7?

Мне интересно использовать пользовательский оверлей для UIImagePickerController для элементов управления камерой, которые занимают весь экран, очень похожий на то, что делает приложение камеры по умолчанию при переключении на функцию видео.

Я упомянул несколько вопросов здесь о SO по этой теме, особенно этот один, а также Пример Apple о том, как использовать пользовательский оверлей для UIImagePickerController, но ни один из них не смог создать успешный полноэкранный результат с iOS 7.

Пока что пользовательский интерфейс камеры выглядит с пользовательским наложением (без каких-либо кнопок):

enter image description here

Обратите внимание, что в нижней части экрана есть черная полоса. Я заметил, что я мог удалить черную полосу, если я изменил значение cameraAspectRatio на 1, но это искажает масштабирование камеры, поскольку оно имеет очень увеличенное изображение. Есть ли способ иметь полный экран, не слишком искажая масштаб (я понимаю, что нужно немного), а также удалить черную полосу?

Вот мой код, который настраивает пользовательский оверлей:

{
        self.imagePickerController.showsCameraControls = NO;

        [[NSBundle mainBundle] loadNibNamed:@"overlayView" owner:self options:nil];
        self.overlayView.frame = self.imagePickerController.cameraOverlayView.frame;
        self.imagePickerController.cameraOverlayView = self.overlayView;
        self.overlayView = nil;

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


        float cameraAspectRatio = 4.0 / 3.0; //! Note: 4.0 and 4.0 works
        float imageWidth = floorf(screenSize.width * cameraAspectRatio);
        float scale = ceilf((screenSize.height / imageWidth) * 10.0) / 10.0;

        self.imagePickerController.cameraViewTransform = CGAffineTransformMakeScale(scale, scale);

    }

Update:

Еще одна проблема, которую я заметил, - изображение, которое отображается в предварительном просмотре камеры, всегда меньше и имеет меньше деталей, чем изображение, которое сохраняется при методе [self.imagePickerController takePicture]. Чтобы проиллюстрировать:

Вот как выглядит клавиатура в предварительном просмотре камеры с черной полосой ниже (извините, что она немного шаткая):

enter image description here

Однако обратите внимание, что фактическое снятое изображение в панели предварительного просмотра имеет намного больше деталей, как показано здесь, особенно в верхней части, а также влево и вправо.

enter image description here

Мой вопрос: как можно настроить предварительный просмотр камеры так, чтобы то, что пользователь видит в предварительном просмотре, - это именно тот образ, который он будет захватывать и может быть показан им впоследствии? Спасибо!

Обновление 2

Вот весь код в viewDidLoad, который устанавливает элементы управления камерой.

- (void)viewDidLoad
{
    [super viewDidLoad];

    //Appearance configuration
    self.navigationItem.hidesBackButton = YES;

    //UIImagePickerController initialization and setup
    self.imagePickerController = [[UIImagePickerController alloc] init];
    self.imagePickerController.delegate = self;
    self.imagePickerController.allowsEditing = NO;
    if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]){
        self.imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera; //if there is a camera avaliable
    } else {
        self.imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;//otherwise go to the folder
    }
    self.imagePickerController.mediaTypes = [[NSArray alloc] initWithObjects: (NSString *) kUTTypeImage, nil];
    if (self.imagePickerController.sourceType == UIImagePickerControllerSourceTypeCamera)
    {
        self.imagePickerController.showsCameraControls = NO;

        [[NSBundle mainBundle] loadNibNamed:@"overlayView" owner:self options:nil];
        self.overlayView.frame = self.imagePickerController.cameraOverlayView.frame;
        self.imagePickerController.cameraOverlayView = self.overlayView;
        self.overlayView = nil;

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

        int heightOffset = 0;

        if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0"))
        {
            heightOffset = 120; //whole screen :)
        }

        float cameraAspectRatio = 4.0 / 3.0; //! Note: 4.0 and 4.0 works
        float imageWidth = floorf(screenSize.width * cameraAspectRatio);
        float scale = ceilf(((screenSize.height + heightOffset) / imageWidth) * 10.0) / 10.0;

        self.imagePickerController.cameraViewTransform = CGAffineTransformMakeScale(scale, scale);

    }
}

И в viewWillAppear я вызываю вид подборщика изображений:

BOOL modalPresent = (BOOL)(self.presentedViewController);
    //Present the Camera UIImagePicker if no image is taken
    if (!appDelegate.imageStorageDictionary[@"picture1"]){
        if (modalPresent == NO){ //checks if the UIImagePickerController is modally active
            [self presentViewController:self.imagePickerController animated:NO completion:nil];
        }
    }

Ответ 1

После многих попыток это помогло мне во многом благодаря предложениям других людей. Следующие факты были очень полезны, чтобы знать и иметь в виду:

Разрешение точек камеры 426 * 320. Чтобы высота предварительного просмотра камеры была растянута до высоты экрана телефона 568, при использовании CGAffineTransformScale ее необходимо умножить на коэффициент 1.3333.

Обратите внимание, что ниже жестко закодированы с различными номерами на основе разрешения экрана iPhone 5 в точках. Их можно было бы улучшить, используя такие объекты, как screen.height, screen.width и другие переменные, чтобы сделать его применимым к размерам iPhone 4/4s.

    self.imagePickerController.showsCameraControls = NO;

    [[NSBundle mainBundle] loadNibNamed:@"overlayView" owner:self options:nil];
    self.overlayView.frame = self.imagePickerController.cameraOverlayView.frame;
    self.imagePickerController.cameraOverlayView = self.overlayView;
    self.overlayView = nil;

    //For iphone 5+
    //Camera is 426 * 320. Screen height is 568.  Multiply by 1.333 in 5 inch 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;

Ответ 2

В Swift

var picker: UIImagePickerController = UIImagePickerController();

picker.sourceType = UIImagePickerControllerSourceType.Camera;

picker.showsCameraControls = false;

var screenBounds: CGSize = UIScreen.mainScreen().bounds.size;

var scale = screenBounds.height / screenBounds.width;

picker.cameraViewTransform = CGAffineTransformScale(picker.cameraViewTransform, scale, scale);

Ответ 3

Убедитесь, что вы учитываете изменение строки состояния 20px в iOS7. Если вы столкнулись с черным экраном 20 пикселей в нижней части экрана, это будет вашей проблемой. Вы можете проверить, работает ли приложение в ios7 или нет одним из этих препроцессоров.

#define SYSTEM_VERSION_EQUAL_TO(v)                  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)
#define SYSTEM_VERSION_GREATER_THAN(v)              ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v)                 ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v)     ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)

И вы можете внести следующие изменения в свой код и посмотреть, работает ли он

{
        self.imagePickerController.showsCameraControls = NO;

        [[NSBundle mainBundle] loadNibNamed:@"overlayView" owner:self options:nil];
        self.overlayView.frame = self.imagePickerController.cameraOverlayView.frame;
        self.imagePickerController.cameraOverlayView = self.overlayView;
        self.overlayView = nil;

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

        int heightOffset = 0;

        if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0"))
        {
            heightOffset = 20;
        }

        float cameraAspectRatio = 4.0 / 3.0; //! Note: 4.0 and 4.0 works
        float imageWidth = floorf(screenSize.width * cameraAspectRatio);
        float scale = ceilf(((screenSize.height + heightOffset) / imageWidth) * 10.0) / 10.0;

        self.imagePickerController.cameraViewTransform = CGAffineTransformMakeScale(scale, scale);

    }

Пожалуйста, дайте мне знать, если это сработает. Я не закодировал его для тестирования.

Ответ 4

Поскольку соотношение сторон экрана отличается от соотношения 4/3 самой камеры, вам нужно (как вы упомянули) слегка обрезать края, чтобы изображение было снизу.

Чтобы сделать это, вам нужно, чтобы ширина была достаточно широкой, чтобы высота была полной. Таким образом, ширина и высота изображения должны быть:

float cameraAspectRatio = 4.0 / 3.0; //! Note: 4.0 and 4.0 works
float imageWidth = screenSize.height / cameraAspectRatio;

Вам также, вероятно, потребуется, чтобы представление, представляющее изображение камеры, было такой шириной, которая простирается с обеих сторон экрана.

Ответ 5

Я не знаю, почему вы используете размер экрана. Просто попробуйте этот простой код:

if ([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypeCamera])

{

     UIImagePickerController *controller = [[UIImagePickerController alloc] init];
     controller.sourceType = UIImagePickerControllerSourceTypeCamera;
     controller.allowsEditing = NO;
     controller.mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:
     UIImagePickerControllerSourceTypeCamera];
     controller.delegate = self;
     [self presentViewController:controller animated:NO completion:^{}];
}

Ответ 6

Попробуйте этот код, чтобы сохранить результирующее изображение в произвольном размере. Я получил результат с помощью настраиваемого метода для получения результирующего изображения в качестве настраиваемого размера.

Сначала создайте IBOutlet для UIImageview.

-(void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info
{
    NSString *mediaType = info[UIImagePickerControllerMediaType];
[self dismissViewControllerAnimated:YES completion:nil];


if ([mediaType isEqualToString:(NSString *)kUTTypeImage]) {
    OriginalImage=info[UIImagePickerControllerOriginalImage];
    image = info[UIImagePickerControllerOriginalImage];
//----------------------------------------
     imageview.image = image; //------------- additional method for custom image size
     self resizeImage];


//-----------------------------------------
        if (_newMedia)
            UIImageWriteToSavedPhotosAlbum(image,self,@selector(image:finishedSavingWithError:contextInfo:),nil);

}
else if ([mediaType isEqualToString:(NSString *)kUTTypeMovie])
{
    // Code here to support video if enabled
}

}

//---- Изменение размера исходного изображения с помощью пользовательского метода ----------------------

-(void)resizeImage
{
    UIImage *resizeImage = imageview.image;

    float width = 320;
    float height = 320;

    CGSize newSize = CGSizeMake(320,320);
    UIGraphicsBeginImageContextWithOptions(newSize,NO,0.0);
    CGRect rect = CGRectMake(0, 0, width, height);

    float widthRatio = resizeImage.size.width / width;
    float heightRatio = resizeImage.size.height / height;
    float divisor = widthRatio > heightRatio ? widthRatio : heightRatio;

    width = resizeImage.size.width / divisor;
    height = resizeImage.size.height / divisor;

    rect.size.width  = width;
    rect.size.height = height;

    //indent in case of width or height difference
    float offset = (width - height) / 2;
    if (offset > 0) {
        rect.origin.y = offset;
    }
    else {
        rect.origin.x = -offset;
    }

    [resizeImage drawInRect: rect];

    UIImage *smallImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

imageview.image = smallImage;
imageview.contentMode = UIViewContentModeScaleAspectFit;

}

Ответ 7

Чтобы решить подобную проблему, я создал экземпляр ViewController из раскадровки и использовал представление контроллера в качестве наложения камеры. Я не знаю, если это то, что вы ищете, но я использовал следующий код:

UIImagePickerController *globalPicker = [[UIImagePickerController alloc] init];
globalPicker.delegate = self;
globalPicker.sourceType = UIImagePickerControllerSourceTypeCamera;controller=[self.storyboard instantiateViewControllerWithIdentifier:@"myVC"];
overlayView = controller.view;
UIView *cameraView=[[UIView alloc] initWithFrame:self.view.bounds];
[cameraView addSubview:overlayView];
[globalPicker setCameraOverlayView:cameraView];

Ответ 8

Попробуйте этот код, он отлично работает для меня

UIImagePickerController *cameraUI = [[UIImagePickerController alloc] init];
cameraUI.sourceType = UIImagePickerControllerSourceTypeCamera;
cameraUI.showsCameraControls = NO;

CGSize screenSize = [[UIScreen mainScreen] bounds].size;
float cameraAspectRatio = 4.0 / 3.0;
float imageHeight = floorf(screenSize.width * cameraAspectRatio);
float scale = screenSize.height / imageHeight;
float trans = (screenSize.height - imageHeight)/2;
CGAffineTransform translate = CGAffineTransformMakeTranslation(0.0, trans);
CGAffineTransform final = CGAffineTransformScale(translate, scale, scale);
cameraUI.cameraViewTransform = final
;
cameraUI.delegate = self;
[self presentViewController:cameraUI animated:YES completion:nil];

Этот код предполагает, что аспект исходной области предварительного просмотра камеры равен 4: 3.

Ответ 9

Есть более простой способ получить ваш оверлейный полноэкранный режим, по крайней мере, проверенный в iOS 9.

let view    = ... your overlayView
let bounds  = UIScreen.mainScreen().bounds
view.center = CGPoint(x: bounds.midX, y: bounds.midY)
view.bounds = bounds
self.imagePicker.cameraOverlayView = view