Передняя лицевая камера в UIImagePickerController

Я разрабатываю приложение для передней камеры в iPad2 с помощью UIImagePickerController.

Когда я фиксирую изображение, оно отображается как перевернутое слева направо.

Как это исправить?

if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) 
    {
        UIImagePickerController *imgPkr = [[UIImagePickerController alloc] init];
        imgPkr.delegate = self;
        imgPkr.sourceType = UIImagePickerControllerSourceTypeCamera;
        imgPkr.cameraDevice=UIImagePickerControllerCameraDeviceFront;


        UIImageView *anImageView=[[UIImageView alloc] initWithImage:[UIImage imageNamed:[NSString stringWithFormat:@"select%d.png",val]]];
        anImageView.frame = CGRectMake(0, 0, anImageView.image.size.width, anImageView.image.size.height);
        imgPkr.cameraOverlayView = anImageView;
        [theApp.TabViewControllerObject presentModalViewController:imgPkr animated:YES];
        [imgPkr release];
    }

Ответ 1

Вы можете перевернуть изображение из исходного изображения, используя это

UIImage *flippedImage = [UIImage imageWithCGImage:picture.CGImage scale:picture.scale orientation:UIImageOrientationLeftMirrored];

Изменить: Добавлен быстрый код

let flippedImage = UIImage(CGImage: picture.CGImage, scale: picture.scale, orientation:.LeftMirrored)

Ответ 2

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

Чтобы решить эту проблему, мне пришлось перевернуть просмотр камеры, когда я переключаюсь на фронтальную камеру:

- (IBAction)flipCamera:(id)sender {
if(cameraUI.cameraDevice == UIImagePickerControllerCameraDeviceFront)
{
    cameraUI.cameraDevice = UIImagePickerControllerCameraDeviceRear;
}
else {
    cameraUI.cameraDevice = UIImagePickerControllerCameraDeviceFront;
}
cameraUI.cameraViewTransform = CGAffineTransformScale(cameraUI.cameraViewTransform, -1,     1);     
}

Просто, чтобы расширить этот отличный ответ, некоторый типичный полный код, Dec2013, iOS7/Xcode5. Делает все. Вам просто нужен значок (cameraToggle.PNG в примере).

-(void)showTheDeviceCamera
    {
    if ( ! [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera] )
        return;

    // self.cameraController is a UIImagePickerController
    self.cameraController = [[UIImagePickerController alloc] init];
    self.cameraController.delegate = (id)self;
    self.cameraController.mediaTypes = @[(NSString *)kUTTypeImage];
    self.cameraController.allowsEditing = YES;
    self.cameraController.sourceType = UIImagePickerControllerSourceTypeCamera;
    [self presentViewController:self.cameraController animated:YES completion:NULL];


        // Add front-rear toggle button MANUALLY, IF NECESSARY
        // (You seem to usually get it for free, on iPhone, but
        // need to add manually on an iPad.)

        UIView *buttonView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"cameraToggle"]];
        [buttonView sizeToFit];

        buttonView.userInteractionEnabled = YES;
        [self.cameraController.view addSubview:buttonView];

        UITapGestureRecognizer *tap =
            [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(_frontRearButtonClicked) ];
        tap.numberOfTapsRequired = 1;
        [buttonView addGestureRecognizer:tap];

        // we'll add it at the top right .. could be anywhere you want
        buttonView.center = CGPointMake(
                self.cameraController.view.frame.size.width-buttonView.frame.size.width,
                3.0 * buttonView.frame.size.height
                );

    }

-(void)_frontRearButtonClicked
    {
    [UIView transitionWithView:self.cameraController.view
        duration:1.0
        options:UIViewAnimationOptionAllowAnimatedContent | UIViewAnimationOptionTransitionFlipFromLeft
        animations:^{
            if ( self.cameraController.cameraDevice == UIImagePickerControllerCameraDeviceRear )
                self.cameraController.cameraDevice = UIImagePickerControllerCameraDeviceFront;
            else
                self.cameraController.cameraDevice = UIImagePickerControllerCameraDeviceRear;
        } completion:NULL];
    }

Ответ 3

Как и другие ответы, у меня была та же проблема. Как упоминал Йонатан Бетцер, просто перевернуть финальное изображение - это всего лишь половина ответа, потому что изображение предварительного просмотра, отображаемое UIPickerController, когда вы делаете снимок с передней камеры, оно все еще инвертировано (зеркально).

Yonatan Betzer anwser отлично работает, но он не упомянул, как и где можно было поместить действие для изменения устройства камеры.

На основе некоторых кодов из Интернета я создал Pod, чтобы получить это желаемое поведение:

https://github.com/lucasecf/LEMirroredImagePicker

После установки вам просто нужно вызвать эти две строки кода вместе с вашим UIImagePickerController:

self.mirrorFrontPicker = [[LEMirroredImagePicker alloc] initWithImagePicker:pickerController];
[self.mirrorFrontPicker mirrorFrontCamera];

И это все, просто так. Вы можете проверить дополнительную информацию в README ссылки github.

Ответ 4

Просто добавлю, как я только что достиг этого, без подкласса UIImagePickerController и без добавления дополнительных кнопок в представление камеры.

Просто прослушайте это уведомление, которое запускается несколько раз при каждом изменении камеры:

[[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(cameraChanged:)
                                                 name:@"AVCaptureDeviceDidStartRunningNotification"
                                               object:nil];

Затем используйте этот метод, чтобы перевернуть вид камеры:

- (void)cameraChanged:(NSNotification *)notification
{
    if(imagePicker.cameraDevice == UIImagePickerControllerCameraDeviceFront)
    {
        imagePicker.cameraViewTransform = CGAffineTransformIdentity;
        imagePicker.cameraViewTransform = CGAffineTransformScale(imagePicker.cameraViewTransform, -1,     1);
    } else {
        imagePicker.cameraViewTransform = CGAffineTransformIdentity;
    }
}

Ответ 5

Я знаю, что этот вопрос действительно старый, но похоже, что это еще одна проблема. Просто установите CGAffineTransform в свойстве cameraViewTransform на объект UIImagePickerController.

let picker = UIImagePickerController()
picker.cameraViewTransform = CGAffineTransformScale(picker.cameraViewTransform, -1, 1)

Ответ 6

Полный рабочий пример в Swift, который отвечает на начальный вопрос этого сообщения (тестируется на iPhone 5c с помощью iOS 8.2):

        import UIKit

        class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate, UIActionSheetDelegate {

         @IBOutlet var myUIImageView: UIImageView!

         var myUIImagePickerController: UIImagePickerController!

         override func viewDidLoad() {
             super.viewDidLoad()
         }

         override func viewWillAppear(animated: Bool) {
             println("viewWillAppear(animated: Bool) method called.")
             super.viewWillAppear(animated)
             NSNotificationCenter.defaultCenter().removeObserver(self)
         }

         override func viewWillDisappear(animated: Bool) {
             println("viewWillDisappear(animated: Bool) method called.")
             super.viewWillDisappear(animated)
             NSNotificationCenter.defaultCenter().addObserver(self, selector: "cameraChanged:", name: "AVCaptureDeviceDidStartRunningNotification", object: nil)
         }

         /* UIImagePickerControllerDelegate Section */
         func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) {
              if(self.myUIImagePickerController.sourceType == UIImagePickerControllerSourceType.Camera) {
                 self.myUIImageView.image = info[UIImagePickerControllerEditedImage] as? UIImage
              } else {
                 self.myUIImageView.image = info[UIImagePickerControllerOriginalImage] as? UIImage
              }
              self.dismissViewControllerAnimated(true, completion: nil)
         }

        func imagePickerControllerDidCancel(picker: UIImagePickerController) {
            self.dismissViewControllerAnimated(true, completion: nil)
        }

        /*
        You can choose to use one of the UIResponder methods:
        touchesBegan, touchesMoved, touchesEnded etc, in order to detect the touch
        on the UIImageView.
        */
        override func touchesEnded(touches: NSSet, withEvent event: UIEvent) {
            let touch: UITouch? = touches.anyObject() as? UITouch
            if (touch?.view == myUIImageView) {
                println("myUIImageView has been tapped by the user.")
                self.takingAPictureUsingTheCamera()
            }
        }

        func takingAPictureUsingTheCamera() {
            self.myUIImagePickerController = UIImagePickerController()
            self.myUIImagePickerController.delegate = self // Set the delegate
            self.myUIImagePickerController.sourceType = UIImagePickerControllerSourceType.Camera
            self.myUIImagePickerController.cameraDevice = UIImagePickerControllerCameraDevice.Front
    //        self.myUIImagePickerController.editing = true
            self.myUIImagePickerController.allowsEditing = true
            self.presentViewController(self.myUIImagePickerController, animated: true, completion: nil)
        }

        func cameraChanged(notification: NSNotification) {
             println("cameraChanged(notification: NSNotification) method called.")
             self.myUIImagePickerController.cameraViewTransform = CGAffineTransformIdentity
             if(self.myUIImagePickerController.cameraDevice == UIImagePickerControllerCameraDevice.Front){
                 self.myUIImagePickerController.cameraViewTransform = CGAffineTransformScale(self.myUIImagePickerController.cameraViewTransform, -1, 1)
             }
        }
       }// End class

Ответ 7

Я пробовал все ответы, описанные здесь, но ни один из них не предложил результат, который я искал. Eiter весь UIImagePickerViewController был преобразован, поэтому камера была неинтуитивной, а не как смотреть в зеркало, или только изображение было преобразовано впоследствии, что было прекрасно, но у вас неправильный просмотр изображения между ними. Таким образом, я закончил с этим взломом, это определенно не лучше всего, но работает на iOS8 и 9 и дает мне результат, который мне нужен.

Убедитесь, что вы добавили наблюдателя для получения уведомления при нажатии кнопки захвата изображения:

NSNotificationCenter.defaultCenter().addObserver(self, selector: "photoTaken", name: "_UIImagePickerControllerUserDidCaptureItem", object: nil)

В методе potoTaken вы можете сделать что-то подобное, чтобы найти изображение предварительного просмотра и преобразовать его так, как вы ожидаете:

func photoTaken() {
        for subview in self.imagePicker.view.subviews {
            for subsubview in subview.subviews {
                for subsubsubview in subsubview.subviews {
                    for subsubsubsubview in subsubsubview.subviews {
                        for subsubsubsubsubview in subsubsubsubview.subviews {
                            for subsubsubsubsubsubview in subsubsubsubsubview.subviews {
                                for subsubsubsubsubsubsubview in subsubsubsubsubsubview.subviews {
                                    if subsubsubsubsubsubsubview.isKindOfClass(UIImageView) {
                                        subsubsubsubsubsubsubview.transform = CGAffineTransformScale(self.imagePicker.cameraViewTransform, -1, 1)
                                    }
                                }

                            }
                        }
                    }
                }
            }
        }
    }

И в своем делегате didFinishPickingMediaWithInfo снова переверните изображение перед сохранением или отображением.

func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
        if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {

            let flippedImage = UIImage(CGImage: pickedImage.CGImage!, scale: pickedImage.scale, orientation: .LeftMirrored)

            myCustomPhotoAlbum.sharedInstance.saveImage(flippedImage)
            self.imageView.image = flippedImage
        }

        self.dismissViewControllerAnimated(true, completion: nil)
    }

Ответ 8

Похоже, что AVCaptureDeviceDidStartRunningNotification больше не используется в качестве средства обнаружения изменений в устройстве камеры. Кроме того, свойство cameraDevice на UIImagePickerController не работает с KVO. Тем не менее, все еще возможно обнаружить изменения устройства камеры, как показано ниже (хотя долгосрочная поддержка этого решения не гарантируется, поскольку мы используем KVO для свойства, которое явно не обозначено как KVO-совместимое).

import AVFoundation

var context = 0

override func viewDidLoad() {
    super.viewDidLoad()
    // Register for notifications
    let notificationCenter = NSNotificationCenter.defaultCenter()
    notificationCenter.addObserver(self, selector: #selector(handleCaptureSessionDidStartRunning(_:)), name: AVCaptureSessionDidStartRunningNotification, object: nil)
    notificationCenter.addObserver(self, selector: #selector(handleCaptureSessionDidStopRunning(_:)), name: AVCaptureSessionDidStopRunningNotification, object: nil)
}

deinit {
    NSNotificationCenter.defaultCenter().removeObserver(self)
}

func handleCaptureSessionDidStartRunning(notification: NSNotification) {
    guard let session = notification.object as? AVCaptureSession else { return }
    session.addObserver(self, forKeyPath: "inputs", options: [ .Old, .New ], context: &context)
}

func handleCaptureSessionDidStopRunning(notification: NSNotification) {
    guard let session = notification.object as? AVCaptureSession else { return }
    session.removeObserver(self, forKeyPath: "inputs")
}

override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
    if context == &self.context {
        if let inputs = change?[NSKeyValueChangeNewKey] as? [AnyObject], captureDevice = (inputs.first as? AVCaptureDeviceInput)?.device {
            switch captureDevice.position {
            case .Back: print("Switched to back camera")
            case .Front: print("Switched to front camera")
            case .Unspecified: break
            }
        }
    } else {
        super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
    }
}