J'ai une application très simple: - Toutes les orientations sont autorisées avec seulement un bouton sur un écran - Le bouton affiche un UIImagePickerController
(pour prendre une photo) - Construire avec Xcode 5 et SDK 7
Sur iOS 8 , la caméra du UIImagePickerController
apparaît correctement que je sois en paysage ou en portrait, mais lorsque je fais pivoter l'appareil , J'ai fait pivoter la vue de la caméra de 90 degrés, voici un exemple:
UIImagePickerController
La vue est en paysage mais la caméra pivote de 90 degrés
Quelqu'un d'autre a-t-il déjà eu ce problème?
PS: Et si je prends une photo (encore en paysage), la photo est correctement prise et maintenant correctement affichée:
[~ # ~] modifier [~ # ~]
Le bogue semble être corrigé sur mon iPad exécutant iOS 8.1, mais rien ne semble lié à ce bogue dans les notes de version iOS 8.1: https://developer.Apple.com/library/content/releasenotes/General/RN-iOSSDK -8,1 /
Merci à tous pour les correctifs proposés pour les versions antérieures d'iOS 8!
Je pense que c'est un bug iOS 8. Par exemple, si vous ouvrez votre application de contacts et cliquez sur éditer/ajouter une photo/prendre une photo, le même problème se produit sur une application iOS standard! Publiez le problème sur Apple support comme moi.
J'ai trouvé une autre très bonne solution pour ce problème que j'utilise actuellement. Vous avez juste besoin de passer l'image comme argument à cette méthode après avoir capturé l'image à l'aide de UIImagePickerController. Il fonctionne bien pour toutes les versions d'iOS et également pour les orientations portrait et paysage de l'appareil photo. Il vérifie la propriété EXIF de l'image en utilisant UIImageOrientaiton et selon la valeur de l'orientation, il transforme et met à l'échelle l'image afin que vous obteniez la même image de retour avec la même orientation que l'orientation de la vue de votre caméra.
Ici, j'ai gardé des résolutions maximales de 3000 afin que la qualité d'image ne soit pas gâchée spécialement lorsque vous utilisez des appareils de rétine, mais vous pouvez changer sa résolution selon vos besoins.
// Code objectif 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:
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!
}
J'ai trouvé un correctif facile et précis pour résoudre ce problème. Ajoutez le code suivant avant de présenter 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"];
}
}
}
Vous devez également sous-classer UIImagePickerController et remplacer la méthode suivante comme ci-dessous pour mieux fonctionner.
- (BOOL)shouldAutorotate
{
[super shouldAutorotate];
return NO;
}
Après avoir utilisé le code ci-dessus, cela fonctionnera bien pour l'orientation paysage et l'orientation ne sera pas modifiée en mode UIDeviceOrientationFaceUp.
Je crois que c'est un bug iOS 8 comme hitme l'a mentionné. J'ai déposé un Apple ticket en ce qui concerne l'exemple de l'application de contacts et en ai fait une copie radar ouverte ici http://openradar.appspot.com/184168
Détails du rapport de bogue
Résumé: Dans l'application Contacts, si l'utilisateur fait pivoter l'appareil iPad de manière à ce qu'il soit en orientation paysage, puis pose l'appareil à plat sur un bureau ou le maintient au niveau du sol, le viseur de l'appareil photo sera lancé pivoté de 90 degrés avec du noir barres sur les côtés. L'utilisateur peut alors prendre la photo qui apparaît correctement pivotée. Il s'agit d'une expérience utilisateur terrible et les utilisateurs ont beaucoup de difficulté à capturer une image.
Étapes à reproduire:
1. Ouvrir l'application Contacts
2. Faire pivoter l'iPad en mode paysage
3. Posez l'iPad à plat sur un bureau
4. Ajouter un nouveau contact
5. Ajouter une photo> Prendre une photo 6. Prenez l'iPad
Résultats attendus:
Viseur de capture d'image S'affiche en plein écran orienté en mode Paysage.
Résultats actuels:
Le viseur de capture d'image pivote de 90 degrés et n'est pas en plein écran.
Versions concernées: iOS 8.0, 8.0.2 et 8.1.
Le problème a été résolu dans iOS 8.1 Testé avec l'application Contacts. fonctionne bien.
Mais un autre problème que j'ai trouvé,
Testez-le 2 3 fois avec l'orientation FaceUp, la vue de la caméra recommencera à tourner étrangement comme vous pouvez le voir dans les images téléchargées ci-dessus.
J'ai eu le même problème et après être revenu à l'essentiel et avoir créé un nouveau projet qui a réellement fonctionné .. je l'ai retrouvé;
-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
// Had forgot to call the following..
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
}
J'espère que ça aide.
Comme l'a dit @hitme, il s'agit d'un bogue dans iOS 8, mais vous pouvez contourner le problème en définissant -[UIImagePickerController cameraViewTransform]
avant de le présenter:
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);
Voici un correctif que j'ai trouvé en ajoutant cette catégorie à 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
Je me rends compte qu'il est difficile d'appeler directement les méthodes de cycle de vie UIViewController
, mais c'est la seule solution que j'ai trouvée. Espérons Apple corrigera cela bientôt!
J'ai le même problème. J'ai testé à la fois sur iOS 7.1.2 et iOS 8. Jusqu'à présent, cela ne s'est produit que sur un appareil iPad avec iOS 8. Je le corrige donc temporairement en utilisant le code suivant:
// 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"];
}
Il n'est pas recommandé car il perturbera l'orientation de PresentViewController.
Y a-t-il des réponses de Apple encore?
Impossible d'attendre Apple pour résoudre le problème ...
- (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;
}
}
}
C'est le code que j'ai utilisé pour réparer mon application qui faisait tourner la caméra openCV en paysage si la caméra était démarrée avec l'appareil sur le bureau en position face vers le haut. L'appareil photo devait être forcé en mode portrait pour que l'application fonctionne correctement.
- (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"];
}
}
}
Je sais que c'est un bug iOS, mais j'ai implémenté un correctif temporaire:
dans la vue qui présente le sélecteur d'images, ajoutez ce code si vous n'obtenez aucun événement de changement d'orientation (ou utilisez didRotateFromInterfaceOrientation otherwhise):
- (void)viewDidLoad {
[super viewDidLoad];
// ....
if ([[UIDevice currentDevice].systemVersion floatValue] >=8) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didRotate:) name:UIDeviceOrientationDidChangeNotification object:nil];
}
}
maintenant en rotation, il suffit de rejeter et de représenter votre imagepicker:
- (void)didRotate:(NSNotification *)notification
{
if (self.presentedViewController && self.presentedViewController==self.imagePickerController) {
[self dismissViewControllerAnimated:NO completion:^{
[self presentViewController:self.imagePickerController animated:NO completion:nil];
}];
}
}
fonctionne un peu rugueux, mais c'est la meilleure solution que j'ai trouvée