Предварительный просмотр камеры UIImagePickerController - портрет в ландшафтном приложении - PullRequest
45 голосов
/ 11 февраля 2009

В своем приложении для iPhone только в альбомной ориентации я запускаю UIImagePickerController для съемки фотографии, но изображение, отображаемое с камеры в реальном времени, имеет портретную ориентацию с пустым пространством вокруг него. Изображение поворачивается.

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

Apple признала, что это дефект, и работает над этим.

Мой вопрос: есть ли у кого-нибудь обходной путь (легальный или нелегальный), который позволил бы мне получить эту работу сейчас. Я бы не выпустил в App Store нелегальное исправление, но у меня было бы гораздо лучшее приложение для пользовательского тестирования - в настоящее время камера практически непригодна для использования в ландшафте.

Я приложу простой тестовый проект и изображения, если смогу.

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


Camera

alt text

Ответы [ 6 ]

88 голосов
/ 11 февраля 2009

Ответ более нелеп, чем вы думаете. У меня была такая же проблема, и я нашел решение где-то на форуме. Передайте ваше снятое изображение в метод, подобный этому:

// Code from: http://discussions.apple.com/thread.jspa?messageID=7949889
- (UIImage *)scaleAndRotateImage:(UIImage *)image {
  int kMaxResolution = 640; // Or whatever

    CGImageRef imgRef = image.CGImage;

    CGFloat width = CGImageGetWidth(imgRef);
    CGFloat height = CGImageGetHeight(imgRef);


    CGAffineTransform transform = CGAffineTransformIdentity;
    CGRect bounds = CGRectMake(0, 0, width, height);
    if (width > kMaxResolution || height > kMaxResolution) {
        CGFloat ratio = width/height;
        if (ratio > 1) {
            bounds.size.width = kMaxResolution;
            bounds.size.height = roundf(bounds.size.width / ratio);
        }
        else {
            bounds.size.height = kMaxResolution;
            bounds.size.width = roundf(bounds.size.height * ratio);
        }
    }

    CGFloat scaleRatio = bounds.size.width / width;
    CGSize imageSize = CGSizeMake(CGImageGetWidth(imgRef), CGImageGetHeight(imgRef));
    CGFloat boundHeight;
    UIImageOrientation orient = image.imageOrientation;
    switch(orient) {

        case UIImageOrientationUp: //EXIF = 1
            transform = CGAffineTransformIdentity;
            break;

        case UIImageOrientationUpMirrored: //EXIF = 2
            transform = CGAffineTransformMakeTranslation(imageSize.width, 0.0);
            transform = CGAffineTransformScale(transform, -1.0, 1.0);
            break;

        case UIImageOrientationDown: //EXIF = 3
            transform = CGAffineTransformMakeTranslation(imageSize.width, imageSize.height);
            transform = CGAffineTransformRotate(transform, M_PI);
            break;

        case UIImageOrientationDownMirrored: //EXIF = 4
            transform = CGAffineTransformMakeTranslation(0.0, imageSize.height);
            transform = CGAffineTransformScale(transform, 1.0, -1.0);
            break;

        case UIImageOrientationLeftMirrored: //EXIF = 5
            boundHeight = bounds.size.height;
            bounds.size.height = bounds.size.width;
            bounds.size.width = boundHeight;
            transform = CGAffineTransformMakeTranslation(imageSize.height, imageSize.width);
            transform = CGAffineTransformScale(transform, -1.0, 1.0);
            transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);
            break;

        case UIImageOrientationLeft: //EXIF = 6
            boundHeight = bounds.size.height;
            bounds.size.height = bounds.size.width;
            bounds.size.width = boundHeight;
            transform = CGAffineTransformMakeTranslation(0.0, imageSize.width);
            transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);
            break;

        case UIImageOrientationRightMirrored: //EXIF = 7
            boundHeight = bounds.size.height;
            bounds.size.height = bounds.size.width;
            bounds.size.width = boundHeight;
            transform = CGAffineTransformMakeScale(-1.0, 1.0);
            transform = CGAffineTransformRotate(transform, M_PI / 2.0);
            break;

        case UIImageOrientationRight: //EXIF = 8
            boundHeight = bounds.size.height;
            bounds.size.height = bounds.size.width;
            bounds.size.width = boundHeight;
            transform = CGAffineTransformMakeTranslation(imageSize.height, 0.0);
            transform = CGAffineTransformRotate(transform, M_PI / 2.0);
            break;

        default:
            [NSException raise:NSInternalInconsistencyException format:@"Invalid image orientation"];

    }

    UIGraphicsBeginImageContext(bounds.size);

    CGContextRef context = UIGraphicsGetCurrentContext();

    if (orient == UIImageOrientationRight || orient == UIImageOrientationLeft) {
        CGContextScaleCTM(context, -scaleRatio, scaleRatio);
        CGContextTranslateCTM(context, -height, 0);
    }
    else {
        CGContextScaleCTM(context, scaleRatio, -scaleRatio);
        CGContextTranslateCTM(context, 0, -height);
    }

    CGContextConcatCTM(context, transform);

    CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, width, height), imgRef);
    UIImage *imageCopy = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return imageCopy;
}

(

1 голос
/ 12 марта 2015

Я решил эту проблему, заставив UIImagePickerController отображаться в полноэкранном режиме, что Apple также рекомендует для iPad.

Из UIImagePickerController документации :

На iPad, если указать тип источника UIImagePickerControllerSourceTypeCamera, вы можете представить средство выбора изображений модально (во весь экран) или с помощью всплывающего окна. Однако Apple рекомендует представлять интерфейс камеры только в полноэкранном режиме.

1 голос
/ 31 января 2013

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

@implementation MyNonrotatingNavigationController

-(NSUInteger) supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskLandscape;
}

@end

Так что все, что когда-либо показывалось внутри этого контроллера навигации, будет в горизонтальной ориентации (вы можете сделать это с любым контроллером вида). Теперь, когда мне нужно показать средство выбора изображений, я заменяю корневой контроллер окна приложения на стандартный, который поддерживает портретный режим. Чтобы предотвратить освобождение старого корневого контроллера представления и его представлений, я поддерживаю указатели на них до тех пор, пока не буду готов вернуть их обратно в окно приложения.

#define APP_DELEGATE ((MyAppDelegate*)[[UIApplication sharedApplication] delegate])
static UIViewController *pickerContainer = nil;
static UIViewController *oldRoot = nil;
static UIView *holdView = nil;

-(void) showPicker
{
    ...create UIImagePickerController...

    oldRoot = APP_DELEGATE.window.rootViewController;
    holdView = [[UIView alloc] initWithFrame:APP_DELEGATE.window.bounds];
    [holdView addSubview:oldRoot.view];

    pickerContainer = [UIViewController new];
    pickerContainer.view = [[UIView alloc] initWithFrame:APP_DELEGATE.window.bounds];
    APP_DELEGATE.window.rootViewController = pickerContainer;
    [pickerContainer presentViewController:picker animated:YES completion:NULL];
}

-(void) imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info
{
    [pickerContainer dismissViewControllerAnimated:YES completion:^{
        dispatch_async( dispatch_get_main_queue(), ^{
            APP_DELEGATE.window.rootViewController = oldRoot;
            [APP_DELEGATE.window addSubview:oldRoot.view];
            pickerContainer = nil;
            oldRoot = nil;
            holdView = nil;
        });
    }];
}

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

1 голос
/ 23 мая 2012

Я не думаю, что вам нужна дополнительная работа, чтобы иметь дело с imageRotation или данными EXIF ​​вообще. Image drawInRect позаботится об этом автоматически.

Итак, вам нужно только получить этот размер или изображение и перерисовать его в новое изображение, этого будет достаточно.

0 голосов
/ 19 февраля 2019

Эту проблему можно решить, установив modalPresentationStyle в overCurrentContext, как показано ниже,

 picker.modalPresentationStyle = .overCurrentContext

и представление средства выбора изображений на Main Thread, как,

DispatchQueue.main.async {

   self.present(picker, animated: true) {

   }
}

Почему это происходит?

Поскольку ImagePickerController работает только в портретном режиме, и когда вы пытаетесь представить инструмент выбора из ландшафтного контроллера, он пытается установить вашу строку состояния в портретном режиме. Итак, если вы установите modalPresentationStyle на overCurrentContext, он не будет пытаться установить ориентацию. Он будет учитывать текущую ориентацию.

см. направляющую линию Apple для ImagePickerController. В нем говорится,

Класс UIImagePickerController поддерживает только портретный режим. Этот класс предназначен для использования как есть и не поддерживает создание подклассов. Иерархия представления для этого класса является частной и не должна изменяться, за одним исключением. Вы можете назначить собственное представление свойству cameraOverlayView и использовать это представление для представления дополнительной информации или управления взаимодействиями между интерфейсом камеры и вашим кодом.

0 голосов
/ 15 июля 2011

Вам необходимо установить пользовательский вид (с панелью инструментов и заголовком) как cameraOverlayView, также вам нужно будет установить allowsEditing и showsCameraControls на NO, так как это скроет стандартные элементы управления и предварительный просмотр. Это то, что я нашел по мере необходимости в приложении, которое я создаю (хотя мне нужно, чтобы средство выбора было в портретном режиме, но мне нужно, чтобы оно применило некоторые изменения пользовательского интерфейса, если пользователь поворачивает свое устройство в альбомную ориентацию).
Код может быть предоставлен, если в этом есть необходимость.

P.S. В моем коде все еще есть ошибки, но я над этим работаю:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...