UIImagePickerController 相机视图在 iOS 8 上奇怪地旋转(图片)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25932642/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
UIImagePickerController camera view rotating strangely on iOS 8 (pictures)
提问by Kevin Hirsch
I have a very simple application:
- All orientations are permitted with only a button on a screen
- The button show a UIImagePickerController
(to take a photo)
- Build with Xcode 5 and SDK 7
我有一个非常简单的应用程序: - 只有屏幕上的一个按钮才允许所有方向 - 按钮显示一个UIImagePickerController
(拍照) - 使用 Xcode 5 和 SDK 7 构建
On iOS 8, the camera of the UIImagePickerController
is appearing correctly whether I am in landscape or in portrait, but when I rotate the device, I got the camera view rotated by 90 degrees, here's a an example:
在iOS 8 上,UIImagePickerController
无论我是横向还是纵向,相机都正确显示,但是当我旋转设备时,我的相机视图旋转了 90 度,这是一个示例:
- I have my app in portrait
- I push the button that shows me the
UIImagePickerController
- I am in the camera view and I go to landscape mode, here is what I get:
- 我的应用程序是纵向的
- 我按下显示我的按钮
UIImagePickerController
- 我在相机视图中,进入横向模式,这是我得到的:
The view is in landscape but the camera is rotated by 90 degrees
视图为横向,但相机旋转了 90 度
Did someone else already got this issue?
其他人已经遇到这个问题了吗?
PS: And if I take a photo (again in landscape), the photo is correctly taken and now correctly displayed :
PS:如果我拍照(再次横向),照片会正确拍摄并正确显示:
EDIT
编辑
The bug seems to be fixed on my iPad running iOS 8.1 but nothing appears related to that bug in iOS 8.1 Release Notes: https://developer.apple.com/library/content/releasenotes/General/RN-iOSSDK-8.1/
该错误似乎已在我运行 iOS 8.1 的 iPad 上修复,但在 iOS 8.1 发行说明中似乎没有与该错误相关的内容:https: //developer.apple.com/library/content/releasenotes/General/RN-iOSSDK-8.1/
Thanks allfor the proposed fixes for earlier versions of iOS 8!
感谢大家为早期版本的 iOS 8 提出的修复建议!
采纳答案by hitme
I believe it is an iOS 8 bug. For example if you open your contacts app and click edit/add photo/take photo, the same issue occurs on a standard iOS app! Post the issue to Apple support just as I have.
我相信这是一个 iOS 8 错误。例如,如果您打开通讯录应用程序并单击编辑/添加照片/拍照,则标准 iOS 应用程序也会出现同样的问题!像我一样将问题发布到 Apple 支持。
回答by sajgan2015
I have found an another very good solution for this issue which i am using currently. You just need to pass the image as an arugument to this method after capturing image using UIImagePickerController. It works well for all version of iOS and also for both portrait and landscape orientations of Camera. It checks for EXIF property of image using UIImageOrientaiton and accordind to the value of orientation, it transforms & scales the image so you will get the same return image with same orientation as your camera view orientation.
对于我目前正在使用的这个问题,我找到了另一个非常好的解决方案。在使用 UIImagePickerController 捕获图像后,您只需要将图像作为参数传递给此方法。它适用于所有版本的 iOS 以及相机的纵向和横向方向。它使用 UIImageOrientaiton 检查图像的 EXIF 属性,并根据方向的值,转换和缩放图像,以便您获得与相机视图方向相同的方向的返回图像。
Here i have kept maximum resolutions of 3000 so that the image quality doesn't get spoiled specially while you are using retina devices but you can change its resolution as per your requirement.
在这里,我将最大分辨率保持为 3000,这样在您使用视网膜设备时图像质量就不会受到特别破坏,但您可以根据需要更改其分辨率。
// Objective C code:
// 目标 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 Code:
// 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!
}
回答by sajgan2015
I found an easy and accurate patch to resolve this issue. Add following code before presenting UIImagePickerController:
我找到了一个简单而准确的补丁来解决这个问题。在呈现 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"];
}
}
}
Also you need to subclass UIImagePickerController and override following method as below to work it better.
您还需要继承 UIImagePickerController 并覆盖以下方法以更好地工作。
- (BOOL)shouldAutorotate
{
[super shouldAutorotate];
return NO;
}
After using above code it will work for both landscape orientation well and the orientation will not be changed to UIDeviceOrientationFaceUp mode.
使用上面的代码后,它可以很好地用于横向,并且方向不会更改为 UIDeviceOrientationFaceUp 模式。
回答by Polar Bear
I believe that this is an iOS 8 Bug as hitme mentioned. I filed an Apple Ticket in regards to the example of the contacts app and made an open radar copy of it here http://openradar.appspot.com/18416803
我相信这是hitme提到的iOS 8错误。我提交了一份关于联系人应用程序示例的 Apple 票证,并在此处制作了一个开放的雷达副本http://openradar.appspot.com/18416803
Details of Bug Report
Summary:
In the Contacts app if the user rotates the iPad device so its in landscape orientation and then lays the device flat on a desk or holds it level with the ground the Camera Viewfinder will be launched rotated 90 degrees with black bars on the sides. The user can then take the photo which appears correctly rotated. This is a terrible user experience and results in the user having lots of difficulty in capturing an image.
错误报告
摘要的详细信息:在“联系人”应用程序中,如果用户旋转 iPad 设备使其处于横向状态,然后将设备平放在桌子上或将其与地面保持水平,则相机取景器将启动 90 度并带有黑条在两侧。然后用户可以拍摄正确旋转的照片。这是一种糟糕的用户体验,并导致用户在捕获图像时遇到很多困难。
Steps to Reproduce:
1. Open Contacts App
2. Rotate iPad to Landscape Mode
3. Lay the iPad to flat on a desk
4. Add New Contact
5. Add Photo > Take Photo
6. Pick up the iPad
重现步骤:
1. 打开通讯录 App
2. 将 iPad 旋转到横向模式
3. 将 iPad 平放在桌子上
4. 添加新联系人
5. 添加照片 > 拍照 6. 拿起 iPad
Expected Results:
Image Capture Viewfinder Displays in full screen oriented in Landscape mode.
预期结果:
图像捕捉取景器在横向模式下以全屏显示。
Actual Results:
Image Capture Viewfinder is rotated 90 degrees and is not full screen.
实际结果:
图像捕捉取景器旋转了 90 度并且不是全屏。
Versions Affected: iOS 8.0, 8.0.2, & 8.1.
受影响的版本:iOS 8.0、8.0.2 和 8.1。
回答by MaNn
The issue has been fixed in iOS 8.1 Tested with Contacts App. works fine.
此问题已在 iOS 8.1 Tested with Contacts App 中修复。工作正常。
But another issue I found ,
但是我发现了另一个问题,
- Go to Contacts App
- Keep your device like ipad camera is facing the ground.
- Add contact -> Take Photo
- 转到通讯录应用
- 让您的设备像 ipad 相机一样面向地面。
- 添加联系人 -> 拍照
Test it 2 3 times with FaceUp orientation, the camera view will start rotating strangely again as you can see in the Pictures uploaded above.
使用 FaceUp 方向测试 2 3 次,相机视图将再次开始奇怪地旋转,如您在上面上传的图片中所见。
回答by PaulB
I had the same issue and after getting back to basics and creating a new project which actually worked.. I tracked it down to;
我遇到了同样的问题,在回归基础并创建了一个实际有效的新项目之后……我将其追溯到;
-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
// Had forgot to call the following..
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
}
Hope it helps.
希望能帮助到你。
回答by Austin
As @hitme said, it is a bug in iOS 8, but you can work around the issue by setting -[UIImagePickerController cameraViewTransform]
before presenting it:
正如@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);
回答by Cosworth66
This is the code I used to fix my app that was rotating the openCV camera into landscape if the camera was started with the device on the desk in Face Up position. The camera needed to be forced into portrait mode for the app to function correctly.
这是我用来修复我的应用程序的代码,如果相机是在桌面上的设备以面朝上位置启动的情况下,我的应用程序会将 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"];
}
}
}
回答by Ray
I got the same issue. I tested on both iOS 7.1.2 and iOS 8. So far, it only happened on iPad device with iOS 8. So I temporarily fix it by following code:
我遇到了同样的问题。我在 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"];
}
It is not recommended because it will mess up the presentingViewController's orientation.
不推荐这样做,因为它会弄乱presentingViewController 的方向。
Are there any replies from Apple yet?
苹果还有回复吗?
回答by Ray
Cannot wait for Apple to fix the issue...
等不及苹果解决这个问题了……
- (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;
}
}
}