ios UIImagePickerController 中的前置摄像头

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9255633/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 16:49:07  来源:igfitidea点击:

Front facing camera in UIImagePickerController

iosobjective-ciphoneswiftuiimagepickercontroller

提问by dineshprasanna

I am developing the front facing camera app in iPad2 by using the UIImagePickerController.

我正在 iPad2 中使用UIImagePickerController.

When I capture the image it's shows as flipped from left to right.

当我捕获图像时,它显示为从左到右翻转。

How do I correct this?

我该如何纠正?

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];
    }

回答by Inder Kumar Rathore

You can flip the image from the source image use this

您可以使用此从源图像翻转图像

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


Edit:Added swift code

编辑:添加了快速代码

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

回答by Yonatan Betzer

I had the same problem - and the solution above only got me half the answer, because the user had to approve the mirrored image before getting to the next page of my app - where I use the captured image after flipping it.

我遇到了同样的问题 - 上面的解决方案只给了我一半的答案,因为用户必须在进入我的应用程序的下一页之前批准镜像图像 - 我在翻转后使用捕获的图像。

To solve this I had to flip the camera view whenever I switch to the front facing camera:

为了解决这个问题,每当我切换到前置摄像头时,我都必须翻转摄像头视图:

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


Just to expand on this great answer, some typical complete code, Dec2013, iOS7 / Xcode5. Does everything. You just need an icon (cameraToggle.PNG in the example).

只是为了扩展这个很好的答案,一些典型的完整代码,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];
    }

回答by Lucas Eduardo

As the other answers, I had the same problem. As Yonatan Betzer mentioned, just flip the final image is only half the answer, because the preview image, displayed by the UIPickerController when you take a picture with the front camera, it's still inverted (mirrored).

作为其他答案,我遇到了同样的问题。正如 Yonatan Betzer 提到的,只需翻转最终图像只是答案的一半,因为当您使用前置摄像头拍照时 UIPickerController 显示的预览图像仍然是倒置的(镜像)。

Yonatan Betzer's anwser works great, but he did not mentioned how or where to put the action to change the camera device.

Yonatan Betzer 的 anwser 工作得很好,但他没有提到如何或在哪里放置动作来改变相机设备。

Based in some codes from internet, I created a Pod to get this wanted behavior:

基于来自互联网的一些代码,我创建了一个 Pod 来获得这种想要的行为:

https://github.com/lucasecf/LEMirroredImagePicker

https://github.com/lucasecf/LEMirroredImagePicker

After installed, you just have to call this two lines of code together with your UIImagePickerController:

安装后,您只需将这两行代码与您的UIImagePickerController

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

And thats it, simply as that. You can check for more informations in the README of the github link.

就是这样,就这么简单。您可以在 github 链接的 README 中查看更多信息。

回答by Darren

Just to add how I have just achieved this without subclassing UIImagePickerController and without adding extra buttons to the camera view.

只是补充一下我是如何在不继承 UIImagePickerController 并且不向相机视图添加额外按钮的情况下实现的。

Simply listen for this notification which is fired several times whenever the camera is changed:

只需侦听此通知,每当更改相机时都会多次触发该通知:

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

Then use this method to flip the camera view:

然后使用这个方法来翻转相机视图:

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

回答by barndog

I know this question is really old but it seems like this is a still a common problem. Just set a CGAffineTransformon the cameraViewTransformproperty on a UIImagePickerControllerobject.

我知道这个问题真的很老,但似乎这仍然是一个常见问题。只需在对象CGAffineTransformcameraViewTransform属性上设置 a 即可UIImagePickerController

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

回答by user3054579

Updated "bandog" answer for swift 4

为 swift 4 更新了“bandog”答案

let picker = UIImagePickerController()
picker.cameraViewTransform = picker.cameraViewTransform.scaledBy(x: -1, y: 1)

回答by Niels

It looks like AVCaptureDeviceDidStartRunningNotificationis no longer available as a means of detecting camera device changes. Also, the cameraDeviceproperty on UIImagePickerControllerdoesn't work with KVO. However, it's still possible to detect camera device changes, as shown below (though long-term support for this solution isn't guaranteed as we're using KVO on a property that isn't explicitly marked as KVO-compliant).

它看起来AVCaptureDeviceDidStartRunningNotification不再可用作检测相机设备变化的手段。此外,cameraDevice属性 onUIImagePickerController不适用于 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)
    }
}

回答by Shalugin

It took me few hours, but I think I got there. Here is a working solution for Swift 5.2of how to get correct image (both in ImagePicker preview and in output).

我花了几个小时,但我想我到了那里。这是Swift 5.2如何获得正确图像(在 ImagePicker 预览和输出中)的工作解决方案。


     //Registering to get notification when users takes a picture

    override func viewDidLoad() {
        NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "_UIImagePickerControllerUserDidCaptureItem"), object: nil, queue: nil) { (notification) in
            self.changePhotoOrientation()
    }

    //Changing image orientation for ImagePicker preview

    func changePhotoOrientation() {
        var subviews: [UIView] = [imagePicker.view]
        while (!subviews.isEmpty) {
            let subview = subviews.removeFirst()
            subviews += subview.subviews
            if (subview.isKind(of: UIImageView.self)) {
                subview.transform = self.imagePicker.cameraViewTransform.scaledBy(x: -1, y: 1)
            }
        }
    }

    //Changing image orientation for the output image

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        if let userPickedImage = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
            image = UIImage(cgImage: userPickedImage.cgImage!, scale: userPickedImage.scale, orientation: .leftMirrored)
        }
    }

}

回答by King-Wizard

Full Working Example in Swift, which answers to the initial question of this post (tested on an iPhone 5c using iOS 8.2):

Swift 中的完整工作示例,它回答了这篇文章的最初问题(在使用 iOS 8.2 的 iPhone 5c 上测试):

        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