我有一个非常简单的应用程序:
- 只需一个屏幕上的按钮即可允许所有方向
- 按钮显示UIImagePickerController
(拍照)
- 使用Xcode 5和SDK 7构建
在 iOS 8 上,无论我是横向还是纵向,UIImagePickerController
的相机都会正确显示,但当我旋转设备时,我将相机视图旋转了90度,这是一个例子:
UIImagePickerController
视图处于横向状态,但相机旋转了90度
其他人是否已经遇到过此问题?
PS:如果我拍照(再次在风景中),照片会被正确拍摄并且现在正确显示:
修改
这个错误似乎在运行iOS 8.1的iPad上得到修复,但似乎没有任何内容与iOS 8.1发行说明中的错误有关:https://developer.apple.com/library/content/releasenotes/General/RN-iOSSDK-8.1/
感谢所有提供针对早期版本的iOS 8的建议修补程序!
答案 0 :(得分:18)
我认为这是iOS 8的错误。例如,如果您打开联系人应用程序并单击编辑/添加照片/拍照,则在标准iOS应用程序上会出现同样的问题!像我一样将问题发布到Apple支持。
答案 1 :(得分:16)
我找到了另一个非常好的解决方案,我目前正在使用这个问题。在使用UIImagePickerController捕获图像后,您只需将图像作为arugument传递给此方法。它适用于所有iOS版本,也适用于Camera的纵向和横向。它使用UIImageOrientaiton检查图像的EXIF属性,并且取决于方向的值,它转换为&缩放图像,以便获得与相机视图方向相同方向的相同返回图像。
在这里,我保持最高分辨率为3000,以便在使用视网膜设备时不会特别破坏图像质量,但您可以根据需要更改其分辨率。
//目标C代码:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info;
{
UIImage *imagePicked = [info valueForKey:UIImagePickerControllerOriginalImage];
imagePicked = [self scaleAndRotateImage:imagePicked];
[[self delegate] sendImage:imagePicked];
[self.imagePicker dismissViewControllerAnimated:YES completion:nil];
}
- (UIImage *) scaleAndRotateImage: (UIImage *)image
{
int kMaxResolution = 3000; // 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 = bounds.size.width / ratio;
}
else {
bounds.size.height = kMaxResolution;
bounds.size.width = 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;
}
// Swift 4.0代码:
func scaleAndRotateImage(image: UIImage, MaxResolution iIntMaxResolution: Int) -> UIImage {
let kMaxResolution = iIntMaxResolution
let imgRef = image.cgImage!
let width: CGFloat = CGFloat(imgRef.width)
let height: CGFloat = CGFloat(imgRef.height)
var transform = CGAffineTransform.identity
var bounds = CGRect.init(x: 0, y: 0, width: width, height: height)
if Int(width) > kMaxResolution || Int(height) > kMaxResolution {
let ratio: CGFloat = width / height
if ratio > 1 {
bounds.size.width = CGFloat(kMaxResolution)
bounds.size.height = bounds.size.width / ratio
}
else {
bounds.size.height = CGFloat(kMaxResolution)
bounds.size.width = bounds.size.height * ratio
}
}
let scaleRatio: CGFloat = bounds.size.width / width
let imageSize = CGSize.init(width: CGFloat(imgRef.width), height: CGFloat(imgRef.height))
var boundHeight: CGFloat
let orient = image.imageOrientation
// The output below is limited by 1 KB.
// Please Sign Up (Free!) to remove this limitation.
switch orient {
case .up:
//EXIF = 1
transform = CGAffineTransform.identity
case .upMirrored:
//EXIF = 2
transform = CGAffineTransform.init(translationX: imageSize.width, y: 0.0)
transform = transform.scaledBy(x: -1.0, y: 1.0)
case .down:
//EXIF = 3
transform = CGAffineTransform.init(translationX: imageSize.width, y: imageSize.height)
transform = transform.rotated(by: CGFloat(Double.pi / 2))
case .downMirrored:
//EXIF = 4
transform = CGAffineTransform.init(translationX: 0.0, y: imageSize.height)
transform = transform.scaledBy(x: 1.0, y: -1.0)
case .leftMirrored:
//EXIF = 5
boundHeight = bounds.size.height
bounds.size.height = bounds.size.width
bounds.size.width = boundHeight
transform = CGAffineTransform.init(translationX: imageSize.height, y: imageSize.width)
transform = transform.scaledBy(x: -1.0, y: 1.0)
transform = transform.rotated(by: CGFloat(Double.pi / 2) / 2.0)
break
default: print("Error in processing image")
}
UIGraphicsBeginImageContext(bounds.size)
let context = UIGraphicsGetCurrentContext()
if orient == .right || orient == .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)
context?.draw(imgRef, in: CGRect.init(x: 0, y: 0, width: width, height: height))
let imageCopy = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return imageCopy!
}
答案 2 :(得分:5)
我找到了一个简单而准确的补丁来解决此问题。在呈现UIImagePickerController之前添加以下代码:
if (iOS8_Device)
{
if([[UIDevice currentDevice]orientation] == UIDeviceOrientationFaceUp)
{
if([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft)
{
[[UIDevice currentDevice]setValue:[NSNumber numberWithInteger:UIDeviceOrientationLandscapeRight] forKey:@"orientation"];
}
else
{
[[UIDevice currentDevice]setValue:[NSNumber numberWithInteger:UIDeviceOrientationLandscapeLeft] forKey:@"orientation"];
}
}
}
此外,你需要子类化UIImagePickerController并覆盖以下方法,以便更好地工作。
- (BOOL)shouldAutorotate
{
[super shouldAutorotate];
return NO;
}
使用上面的代码后,它既适用于横向,也不会更改为UIDeviceOrientationFaceUp模式。
答案 3 :(得分:4)
我认为这是一个iOS 8 Bug,如上所述。我提交了一份关于联系人应用程序示例的Apple Ticket,并在此处制作了一份开放的雷达副本http://openradar.appspot.com/18416803
错误报告详情
摘要:
在“联系人”应用程序中,如果用户将iPad设备旋转至横向,然后将设备平放在桌面上或将其与地面保持水平,则相机取景器将以90度旋转,侧面带有黑条。然后,用户可以拍摄出正确旋转的照片。这是一种糟糕的用户体验,导致用户在捕获图像时遇到很多困难。
重现步骤:
1.打开联系人App
2.将iPad旋转到横向模式
3.将iPad平放在桌子上
4.添加新联系人
5.添加照片>拍照
6.拿起iPad
预期结果:
图像捕获取景器以横向模式显示全屏。
实际结果:
图像捕捉取景器旋转90度,不是全屏。
受影响的版本: iOS 8.0,8.0.2和& 8.1。
答案 4 :(得分:3)
此问题已在iOS 8.1中修复 使用Contacts App进行测试。工作正常。
但是我发现了另一个问题,
使用FaceUp方向测试2次3次,相机视图将再次开始奇怪地旋转,如上图所示的图片所示。
答案 5 :(得分:1)
我遇到了同样的问题,在回到基础并创建一个实际工作的新项目之后......我追踪到了它;
-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
// Had forgot to call the following..
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
}
希望它有所帮助。
答案 6 :(得分:1)
正如@hitme所说,这是iOS 8中的一个错误,但您可以在呈现之前设置-[UIImagePickerController cameraViewTransform]
来解决此问题:
CGFloat angle;
switch (interfaceOrientation)
{
case UIInterfaceOrientationLandscapeLeft:
angle = M_PI_2;
break;
case UIInterfaceOrientationLandscapeRight:
angle = -M_PI_2;
break;
case UIInterfaceOrientationPortraitUpsideDown:
angle = M_PI;
break;
default:
angle = 0;
break;
}
imagePicker.cameraViewTransform = CGAffineTransformMakeRotation([UIApplication sharedApplication].statusBarOrientation);
答案 7 :(得分:0)
我遇到了同样的问题。我在iOS 7.1.2和iOS 8上都进行了测试。到目前为止,它只发生在iOS 8的iPad设备上。所以我通过以下代码暂时修复它:
// In my app, I subclass UIImagePickerController and code my own control buttons
// showsCameraControls = NO;
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[[UIDevice currentDevice] setValue:[NSNumber numberWithInteger:UIInterfaceOrientationPortrait] forKey:@"orientation"];
}
不建议这样做,因为它会破坏presentViewController的方向。
Apple有没有回复?
答案 8 :(得分:0)
不能等待Apple解决问题......
- (void)viewWillAppear:(BOOL)animated
{
...
if (iPad & iOS 8)
{
switch (device_orientation)
{
case UIDeviceOrientationPortraitUpsideDown: self.cameraViewTransform = CGAffineTransformMakeRotation(DEGREES_RADIANS(180)); break;
case UIDeviceOrientationLandscapeLeft: self.cameraViewTransform = CGAffineTransformMakeRotation(DEGREES_RADIANS(90)); break;
case UIDeviceOrientationLandscapeRight: self.cameraViewTransform = CGAffineTransformMakeRotation(DEGREES_RADIANS(-90)); break;
default: break;
}
}
}
答案 9 :(得分:0)
我知道这是一个iOS错误,但我已经实施了一个临时修复:
在显示图像选择器的视图上,如果您没有获得任何方向更改事件(或使用didRotateFromInterfaceOrientation otherwhise),请添加此代码:
- (void)viewDidLoad {
[super viewDidLoad];
// ....
if ([[UIDevice currentDevice].systemVersion floatValue] >=8) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didRotate:) name:UIDeviceOrientationDidChangeNotification object:nil];
}
}
现在轮换,只需解雇并代表你的imagepicker:
- (void)didRotate:(NSNotification *)notification
{
if (self.presentedViewController && self.presentedViewController==self.imagePickerController) {
[self dismissViewControllerAnimated:NO completion:^{
[self presentViewController:self.imagePickerController animated:NO completion:nil];
}];
}
}
工作有点粗糙,但这是我发现的最佳解决方案
答案 10 :(得分:0)
通过将此类别添加到UIImagePickerController
,我找到了一个解决方法:
@implementation UIImagePickerController (Rotation)
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
[self viewWillAppear:NO];
[self viewDidAppear:NO];
}
- (void)viewWillDisappear:(BOOL)animated
{
[[UIApplication sharedApplication] setStatusBarHidden:NO];
}
@end
我意识到直接调用UIViewController
生命周期方法是hacky,但这是我发现的唯一解决方案。希望Apple能尽快解决这个问题!
答案 11 :(得分:0)
这是我用来修复我的应用程序的代码,如果在面朝上位置桌面上的设备启动了相机,则将openCV摄像机旋转到横向。需要将相机强制进入纵向模式才能使应用程序正常运行。
- (BOOL)shouldAutorotate
{
[super shouldAutorotate];
return NO;
}
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear: animated];
if([[UIDevice currentDevice]orientation] == UIDeviceOrientationFaceUp)
{
if([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft)
{
[[UIDevice currentDevice]setValue:[NSNumber numberWithInteger:UIDeviceOrientationPortrait] forKey:@"orientation"];
}
else
{
[[UIDevice currentDevice]setValue:[NSNumber numberWithInteger:UIDeviceOrientationPortrait] forKey:@"orientation"];
}
}
}