Заставьте UIImagePickerController сфотографировать в портретной ориентации / размерах iOS

Единственная разрешенная ориентация в моем приложении - альбомная. Я устанавливаю это в свойствах проекта в target > summery и разрешаю только портрет в shouldAutorotateToInterfaceOrientation

Проблема заключается в том, что когда я делаю снимок, держа телефон горизонтально (в альбомной ориентации), снимок будет сделан в горизонтальной ориентации, а пользовательский интерфейс остается в портретном режиме.

Это означает, что в альбомном режиме я получаю широкое изображение 3264 x 2448 вместо высокого изображения (2448 x 3264) в портретном режиме.

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

Есть ли способ заставить UIImagePickerController сделать фотографию в портретном измерении, хотя телефон держится горизонтально (альбомный режим)?

Я инициализирую UIImagePickerController со следующими настройками:

    imagePicker =[[UIImagePickerController alloc] init];
    imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
    imagePicker.cameraCaptureMode = UIImagePickerControllerCameraCaptureModePhoto;
    imagePicker.cameraDevice = UIImagePickerControllerCameraDeviceRear;
    imagePicker.showsCameraControls = NO;
    imagePicker.modalPresentationStyle = UIModalPresentationFullScreen;
    imagePicker.wantsFullScreenLayout = YES;
    imagePicker.cameraViewTransform = CGAffineTransformScale(imagePicker.cameraViewTransform,CAMERA_TRANSFORM, CAMERA_TRANSFORM);
    imagePicker.navigationBarHidden = YES;
    imagePicker.toolbarHidden = YES;
    [self presentModalViewController:imagePicker animated:NO];
    imagePicker.cameraOverlayView = self.cameraOverlay;
    imagePicker.cameraFlashMode = UIImagePickerControllerCameraFlashModeOff;

1 ответ

Решение

Флаг imageOrientation устанавливается на UIImage в зависимости от того, в какую сторону держится камера во время съемки. Этот флаг доступен только для чтения и определяет ориентацию, с которой iOS будет пытаться отобразить изображение, когда вы помещаете его в представление.

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

- (void) imagePickerImage:(UIImage*)image
{
    if (image.imageOrientation == UIImageOrientationUp ) {
        self.imageView.bounds = CGRectMake
           (0, 0, self.view.bounds.size.height, self.view.bounds.size.width);
        self.imageView.transform = CGAffineTransformMakeRotation(M_PI/2);

    } else if (image.imageOrientation == UIImageOrientationDown) {
        self.imageView.bounds = CGRectMake
           (0, 0, self.view.bounds.size.height, self.view.bounds.size.width);
        self.imageView.transform = CGAffineTransformMakeRotation(-M_PI/2);
    }
    else {
        self.imageView.bounds = self.view.bounds;
        self.imageView.transform = CGAffineTransformIdentity;
    }
    self.imageView.image = image;
}

Другим вариантом может быть создание нового изображения из imageRep: это должно удалить информацию об ориентации.

Обновить
Размеры родного пикселя на фотографии iPhone являются альбомными, независимо от того, как телефон удерживается при съемке. Только флаг ориентации EXIF устанавливается по-другому. Вы не можете изменить флаг EXIF, но вы можете удалить его, скопировав данные растрового изображения в новое растровое изображение. Смотрите также мои ответы здесь.

Вот способ удалить данные EXIF и добавить флаг EXIF в портретной форме. Вы создаете новый UIImage и устанавливаете флаг EXIF при его создании. Вы можете использовать это, чтобы пометить ваши ландшафтные изображения как портрет (UIImageOrientationRight).

- (UIImage*)stripExif:(UIImage*)image
{
    CGImageRef cgImage = image.CGImage;
    UIImage* result = [UIImage imageWithCGImage:cgImage scale:1 
                                    orientation:UIImageOrientationRight];
    return result;
}

обновление 2
Неправильно ссылаться на свойство imageOrientation UIImage как флаг EXIF ​​по двум причинам:

(1) метаданные изображения хранятся в структуре словарного стиля, в которой может быть несколько под-словарей, одним из которых является EXIF. Другие включают TIFF, IPTC, PNG, например. Существует также общий набор тегов в словаре верхнего уровня. Ключ ориентации НЕ находится в разделе EXIF, он находится в подкаталогах TIFF и IPTC (если имеется), а также в качестве ключа верхнего уровня. Мы склонны использовать термин EXIF ​​при ссылке на метаданные изображения в целом, но это вводит в заблуждение.

(2) Метаданные для ориентации в файле изображения используют набор соглашений о флагах, отличающийся от тех, которые Apple использует в своем свойстве UIImage.imageOrientation. Поэтому вы должны позаботиться о том, чтобы прочитать это свойство, чтобы правильно отобразить изображение. Apple, очевидно, использует метаданные ориентации файла изображения, чтобы установить свойство UIImage, но происходит небольшой перевод.

 Orientation 

 Apple/UIImage.imageOrientation     Jpeg/File kCGImagePropertyOrientation

    UIImageOrientationUp    = 0  =  Landscape left  = 1
    UIImageOrientationDown  = 1  =  Landscape right = 3
    UIImageOrientationLeft  = 2  =  Portrait  down  = 8
    UIImageOrientationRight = 3  =  Portrait  up    = 6

Вот страница с флагами вращения exif. Сравните с документацией Apple UIImage (раздел констант). Смотрите также Apple CGImageProperties_Reference, особенно kCGImagePropertyOrientation

Я загрузил небольшой проект на GitHub, регистрируя различные проблемы метаданных UIImage

Другие вопросы по тегам