UIImagePickerController相机预览是风景应用中的肖像

时间:2009-02-11 18:08:24

标签: iphone cocoa-touch

在我的仅横向iPhone应用程序中,我启动了一个UIImagePickerController来拍摄照片,但是从相机显示的实时图像是纵向的,周围有空白区域。图像旋转。

按下相机按钮后,预览非常混乱,大部分预览关闭,并且视图未正确对齐。

Apple承认这是缺陷,正在努力。

我的问题是,是否有人通过合法(合法或非法)解决方案让我现在能够正常工作。我不会通过非法修复发布到App Store,但我会有一个更好的用户测试应用程序 - 目前相机在风景中几乎无法使用。

如果可以的话,我会附上一个简单的测试项目和图像。

编辑 - 只是为了澄清,我得到的图像是正确的风景。我想要相机&预览用户界面看起来正确!


Camera

alt text

7 个答案:

答案 0 :(得分:88)

答案比你想象的更荒谬。我遇到了同样的问题,并在某个论坛找到了解决方案。将拍摄的图像传递给这样的方法:

// 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 :(得分:1)

我认为您根本不需要额外的工作来处理imageRotation或EXIF数据。图像drawInRect将自动处理。

所以,你只需要获得这个尺寸或图像并将其重新绘制到一个新图像,这就足够了。

答案 2 :(得分:1)

我不想在捕获后旋转图像;我希望在横向模式下正确显示预览。所以在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;
        });
    }];
}

有点痛苦,但它确实适用于照片和视频。图像选择器的控件以纵向模式显示,但应用程序的其余部分仅为横向显示。

答案 3 :(得分:1)

我通过使UIImagePickerController以全屏模式显示来解决了这个问题,这也是Apple推荐用于iPad的。

来自UIImagePickerController documentation

  

在iPad上,如果指定源类型为UIImagePickerControllerSourceTypeCamera,则可以模态(全屏)或使用弹出窗口显示图像选择器。但是,Apple建议您仅以全屏方式显示相机界面。

答案 4 :(得分:0)

您需要将自定义视图(工具栏和标题)设置为cameraOverlayView,您还需要将allowsEditingshowsCameraControls设置为NO将隐藏标准控件和预览。 这就是我在应用程序中发现的必要(我认为我需要选择器是纵向的,但是如果用户将其设备旋转到横向,我需要它来应用一些ui更改。)
如果需要,可以提供代码。

P.S。我的代码中仍然存在一些错误,但我正在研究它:)

答案 5 :(得分:0)

可以通过如下将modalPresentationStyle设置为overCurrentContext来解决此问题,

 picker.modalPresentationStyle = .overCurrentContext

并在Main Thread上展示您的图片选择器,

DispatchQueue.main.async {

   self.present(picker, animated: true) {

   }
}

为什么会这样?

因为ImagePickerController仅在纵向模式下有效,并且当您尝试从风景视图控制器显示选取器时,尝试将状态栏设置为纵向模式。因此,如果将modalPresentationStyle设置为overCurrentContext,则它将不会尝试设置方向。它将考虑当前方向。

请参见Apple guide line中的ImagePickerController。它说,

  

UIImagePickerController类仅支持纵向模式。该类旨在按原样使用,不支持子类化。此类的视图层次结构是私有的,除了一个例外,不得修改。您可以将自定义视图分配给cameraOverlayView属性,并使用该视图显示其他信息或管理摄像头界面与您的代码之间的交互。

答案 6 :(得分:0)

让我知道是否不鼓励重新发布上面的最佳答案,我为Alex Wayne的答案准备了2019年快速版本。

/**
 Scale and rotate a UIImage so that it is correctly oriented

 :param: image: The image to be rotated

 :returns: UIImage
 */
func scaleAndRotateImage(_ image: UIImage) -> UIImage {
    let kMaxResolution: CGFloat = 640
    let imgRef: CGImage = image.cgImage!
    let width: CGFloat = CGFloat(imgRef.width)
    let height: CGFloat = CGFloat(imgRef.height)
    var transform: CGAffineTransform = CGAffineTransform.identity
    var bounds: CGRect = CGRect(x: 0, y: 0, width: width, height: height)
    if width > kMaxResolution || height > kMaxResolution {
        let ratio: CGFloat = width / height
        if ratio > 1 {
            bounds.size.width = kMaxResolution
            bounds.size.height = (bounds.size.width / ratio)
        }
        else {
            bounds.size.height = kMaxResolution
            bounds.size.width = (bounds.size.height * ratio)
        }
    }
    let scaleRatio: CGFloat = bounds.size.width / width
    let imageSize: CGSize = CGSize(width: CGFloat(imgRef.width), height: CGFloat(imgRef.height))
    var boundHeight: CGFloat
    let orient: UIImage.Orientation = image.imageOrientation
    switch orient {
    case UIImageOrientation.up:
        transform = CGAffineTransform.identity
    case UIImageOrientation.upMirrored:
        transform = CGAffineTransform(translationX: imageSize.width, y: 0.0)
        transform = transform.scaledBy(x: -1.0, y: 1.0)
    case UIImageOrientation.down:
        transform = CGAffineTransform(translationX: imageSize.width, y: imageSize.height)
        transform = transform.rotated(by: CGFloat(Double.pi))
    case UIImageOrientation.downMirrored:
        transform = CGAffineTransform(translationX: 0.0, y: imageSize.height)
        transform = transform.scaledBy(x: 1.0, y: -1.0)
    case UIImageOrientation.leftMirrored:
        boundHeight = bounds.size.height
        bounds.size.height = bounds.size.width
        bounds.size.width = boundHeight
        transform = CGAffineTransform(translationX: imageSize.height, y: imageSize.width)
        transform = transform.scaledBy(x: -1.0, y: 1.0)
        transform = transform.rotated(by: CGFloat(3.0 * .pi / 2.0))
    case UIImageOrientation.left:
        boundHeight = bounds.size.height
        bounds.size.height = bounds.size.width
        bounds.size.width = boundHeight
        transform = CGAffineTransform(translationX: 0.0, y: imageSize.width)
        transform = transform.rotated(by: CGFloat(3.0 * .pi / 2.0))
    case UIImageOrientation.rightMirrored:
        boundHeight = bounds.size.height
        bounds.size.height = bounds.size.width
        bounds.size.width = boundHeight
        transform = CGAffineTransform(scaleX: -1.0, y: 1.0)
        transform = transform.rotated(by: CGFloat(.pi / 2.0))
    case UIImageOrientation.right:
        boundHeight = bounds.size.height
        bounds.size.height = bounds.size.width
        bounds.size.width = boundHeight
        transform = CGAffineTransform(translationX: imageSize.height, y: 0.0)
        transform = transform.rotated(by: CGFloat(.pi / 2.0))
    }
    UIGraphicsBeginImageContext(bounds.size)
    let context: CGContext = UIGraphicsGetCurrentContext()!
    if orient == UIImage.Orientation.right || orient == UIImage.Orientation.left {
        context.scaleBy(x: -scaleRatio, y: scaleRatio)
        context.translateBy(x: -height, y: 0)
    }
    else {
        context.scaleBy(x: scaleRatio, y: -scaleRatio)
        context.translateBy(x: 0, y: -height)
    }
    context.concatenate(transform)
    UIGraphicsGetCurrentContext()?.draw(imgRef, in: CGRect(x: 0, y: 0, width: width, height: height))
    let imageCopy: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
    UIGraphicsEndImageContext()
    return imageCopy
}