【问题标题】:iOS taking photo programmaticallyiOS 以编程方式拍照
【发布时间】:2012-03-30 11:49:49
【问题描述】:

我知道这是可能的,在一些应用程序中看到了这一点(我相信 iGotYa 是最著名的)。 我知道如何设置拍摄照片、保存照片和一切的一切。 但是如何以编程方式完成呢?只需让用户单击某个按钮(在常规视图控制器中),它就会使用前置摄像头自动拍照并保存(或不,将其作为 UIImage 获取)

谢谢!

【问题讨论】:

标签: objective-c ios xcode photo


【解决方案1】:

这很简单,只需使用AVFoundation参考指南:

https://developer.apple.com/library/ios/#documentation/AudioVideo/Conceptual/AVFoundationPG/Articles/04_MediaCapture.html

如果您不希望用户看到预览输入,您可以跳过代码的设置预览层部分。

编辑:更详细。

1)您使用 AVFoundation 设置捕获配置。

  • 将相机输入设置为正面,关闭闪光灯等。

2)你跳过设置视频预览层的部分。

3) 只要您想拍照,就调用 captureStillImageAsynchronouslyFromConnection:completionHandler: 方法。

注意:如果您不想听到闪光灯等,那么您可能会侵犯某些国家/地区(例如日本)的用户权利。我知道的一种解决方法是捕获视频帧(不触发闪光灯)。

【讨论】:

  • 为什么拍摄的图像是黑色的?有什么想法吗?
  • 应用是否有权限使用相机? (我认为现在需要,但不确定)
  • yup.. 应用有权限。
  • @SandeepSingh 你知道为什么图像是黑色的吗? bcz 我也有同样的问题。
  • 这么简单的任务不需要 AVFondation
【解决方案2】:

VLBCameraView 是一个使用 AVFoundation 拍照的库。

预览会显示在视图中,然后您可以通过编程调用方法 VLBCameraView#takePicture 来拍照。

带有 CocoaPods。

【讨论】:

    【解决方案3】:

    你也可以在没有 AVFoundation 的情况下做到这一点,在我看来,只使用 UIImagePickerController 来实现它是一种更简单的方法。 有3个条件:

    1. 显然设备需要有摄像头
    2. 您必须隐藏相机控件
    3. 然后只需使用 UIImagePickerController 中的 takePicture 方法

    下面是一个简单的示例,您通常会在按下按钮后触发

    - (IBAction)takePhoto:(id)sender 
    {
        UIImagePickerController *picker = [[UIImagePickerController alloc] init];
        picker.delegate = self;
        picker.sourceType = UIImagePickerControllerSourceTypeCamera;
        picker.cameraDevice = UIImagePickerControllerCameraDeviceFront;
        picker.showsCameraControls = NO;
        [self presentViewController:picker animated:YES
                         completion:^ {
                             [picker takePicture];
                         }];
    }
    

    【讨论】:

    • 另外self 应该采用UINavigationControllerDelegateUIImagePickerControllerDelegate 协议。
    • 拍照后如何在不点击 UsePhoto 的情况下移动另一个 VC?
    • 这很好用——除了曝光没有正确完成并且照片比平时更暗。我相信它正在发生,因为照片是在打开相机后立即拍摄的。我尝试在“拍照”之前添加一些延迟,但并不总是有效。还有其他修复吗? @GrandSteph
    【解决方案4】:

    Swift 5.2

    供参考 https://gist.github.com/hadanischal/33054429b18287c12ed4f4b8d45a1701

    Info.plist

    <key>NSCameraUsageDescription</key>
    <string>Access camera</string>
    <key>NSPhotoLibraryUsageDescription</key>
    <string>Access PhotoLibrary</string>
    

    AVFoundationHelper

    import AVFoundation
    
    enum CameraStatus {
        case notDetermined
        case restricted
        case denied
        case authorized
    }
    
    protocol AVFoundationHelperProtocol: AnyObject {
        // MARK: - Check and Respond to Camera Authorization Status
    
        var authorizationStatus: CameraStatus { get }
    
        // MARK: - Request Camera Permission
    
        func requestAccess(completionHandler handler: @escaping (Bool) -> Void)
    }
    
    final class AVFoundationHelper: AVFoundationHelperProtocol {
        // MARK: - Check and Respond to Camera Authorization Status
    
        var authorizationStatus: CameraStatus {
            let cameraAuthorizationStatus = AVCaptureDevice.authorizationStatus(for: .video)
            switch cameraAuthorizationStatus {
            case .notDetermined:
                return CameraStatus.notDetermined
            case .authorized:
                return CameraStatus.authorized
            case .restricted:
                return CameraStatus.restricted
            case .denied:
                return CameraStatus.denied
            @unknown default:
                return CameraStatus.notDetermined
            }
        }
    
        // MARK: - Request Camera Permission
    
        func requestAccess(completionHandler handler: @escaping (Bool) -> Void) {
            AVCaptureDevice.requestAccess(for: .video, completionHandler: { accessGranted in
                handler(accessGranted)
            })
        }
    }
    

    视图控制器

    import UIKit
    
    final class ViewController: UIViewController {
        @IBOutlet var cameraAccessButton: UIButton!
        @IBOutlet var photoImageView: UIImageView!
    
        private var model: AVFoundationHelperProtocol = AVFoundationHelper()
    
        override func viewDidLoad() {
            super.viewDidLoad()
        }
    
        @IBAction func cameraButtonPressed(_: Any) {
            let status = model.authorizationStatus
            switch status {
            case .notDetermined:
                model.requestAccess { hasAccess in
                    if hasAccess {
                        DispatchQueue.main.async {
                            self.showCameraReader()
                        }
                    } else {
                        self.alertCameraAccessNeeded()
                    }
                }
            case .restricted, .denied:
                alertCameraAccessNeeded()
    
            case .authorized:
                showCameraReader()
            }
        }
    
        private func alertCameraAccessNeeded() {
            let appName = "This app Name"
    
            let alert = UIAlertController(title: "This feature requires Camera Access",
                                          message: "In iPhone settings, tap \(appName) and turn on Camera access",
                                          preferredStyle: UIAlertController.Style.alert)
    
            let actionSettings = UIAlertAction(title: "Settings", style: .default, handler: { _ -> Void in
                guard let settingsAppURL = URL(string: UIApplication.openSettingsURLString) else { return }
                UIApplication.shared.open(settingsAppURL)
            })
    
            let actionCancel = UIAlertAction(title: "Cancel", style: .destructive, handler: { _ -> Void in
            })
    
            alert.addAction(actionSettings)
            alert.addAction(actionCancel)
    
            present(alert, animated: true, completion: nil)
        }
    }
    
    extension ViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
        private func showCameraReader() {
            if UIImagePickerController.isSourceTypeAvailable(.camera) {
                let imagePicker = UIImagePickerController()
                imagePicker.sourceType = .camera
                imagePicker.allowsEditing = true
                imagePicker.delegate = self
                present(imagePicker, animated: true)
    
            } else if UIImagePickerController.isSourceTypeAvailable(.photoLibrary) {
                let imagePicker = UIImagePickerController()
                imagePicker.sourceType = .photoLibrary
                imagePicker.allowsEditing = true
                imagePicker.delegate = self
                present(imagePicker, animated: true)
    
            } else {
                // TODO: Implement proper alert
                alertCameraAccessNeeded()
            }
        }
    
        func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
            picker.dismiss(animated: true)
    
            guard let image = info[.editedImage] as? UIImage else {
                print("No image found")
                return
            }
            photoImageView.image = image
            // print out the image size as a test
            print(image.size)
        }
    }
    

    目标 C

    在.h文件中

    @interface ABCViewController : UIViewController
    
    @property (strong, nonatomic) IBOutlet UIImageView *imageView;
    
    - (IBAction)takePhoto:  (UIButton *)sender;
    - (IBAction)selectPhoto:(UIButton *)sender;
    
    @end
    

    在 .m 文件中

    @interface ABCViewController : UIViewController <UIImagePickerControllerDelegate, UINavigationControllerDelegate>
    
    - (IBAction)takePhoto:(UIButton *)sender {
    
    
    if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
        
            UIAlertView *myAlertView = [[UIAlertView alloc] initWithTitle:@"Error"
                                                            message:@"Device has no camera"
                                                            delegate:nil
                                                            cancelButtonTitle:@"OK"
                                                            otherButtonTitles: nil];
            
            [myAlertView show];
            
        } else {
        
        UIImagePickerController *picker = [[UIImagePickerController alloc] init];
        picker.delegate = self;
        picker.allowsEditing = YES;
        picker.sourceType = UIImagePickerControllerSourceTypeCamera;
        
        [self presentViewController:picker animated:YES completion:NULL];
    
    }
        
    }
    
    - (IBAction)selectPhoto:(UIButton *)sender {
        
        UIImagePickerController *picker = [[UIImagePickerController alloc] init];
        picker.delegate = self;
        picker.allowsEditing = YES;
        picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
        
        [self presentViewController:picker animated:YES completion:NULL];
    
        
    }
    
    - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
        
        UIImage *chosenImage = info[UIImagePickerControllerEditedImage];
        self.imageView.image = chosenImage;
        
        [picker dismissViewControllerAnimated:YES completion:NULL];
        
    }
    
    
    - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
    
        [picker dismissViewControllerAnimated:YES completion:NULL];
        
    }
    

    【讨论】:

    • 这里添加了一些信息,在 didFinishPickingMediaWithInfo 中我们必须像这样处理 UIImage *image = [info objectForKey:UIImagePickerControllerEditedImage]; if (image == nil) { image = [info objectForKey:UIImagePickerControllerOriginalImage]; }
    【解决方案5】:

    这是Objective -C Custom Camera的代码。您可以添加功能, 根据您的意愿选择按钮。

    #import "CustomCameraVC.h"
    
    @interface CustomCameraVC ()  {
        BOOL frontCamera;
    }
    @property (strong,nonatomic) AVCaptureSession *captureSession;
    @property (strong,nonatomic) AVCaptureStillImageOutput *stillImageOutput;
    @property (strong,nonatomic) AVCaptureVideoPreviewLayer *videoPreviewLayer;
    @property (weak, nonatomic) IBOutlet UIView *viewCamera;
    
    
    @end
    
    @implementation CustomCameraVC
    
    - (void)viewDidLoad {
        [super viewDidLoad];        
    }
    
    -(void)viewWillAppear:(BOOL)animated  {
        [super viewWillAppear:YES];
        frontCamera = NO;
        [self showCameraWithFrontCamera:frontCamera];
    
    }
    
    -(void)showCameraWithFrontCamera:(BOOL)flag {
        self.captureSession = [[AVCaptureSession alloc]init];
        self.captureSession.sessionPreset = AVCaptureSessionPresetPhoto;
        AVCaptureDevice *captureDevice;
        if(flag)  {
          captureDevice= [self frontCamera];
        }
        else {
          captureDevice= [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
        }
        NSError *error = nil;
        AVCaptureDeviceInput *input =   [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:&error];
    
        [self.captureSession addInput:input];
        self.stillImageOutput = [AVCaptureStillImageOutput new];
        self.stillImageOutput.outputSettings = @{AVVideoCodecKey:AVVideoCodecJPEG};
        [self.captureSession addOutput:_stillImageOutput];
        self.videoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.captureSession];
    
        self.videoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
        self.videoPreviewLayer.connection.videoOrientation = AVCaptureVideoOrientationPortrait;
        [self.viewCamera.layer addSublayer:self.videoPreviewLayer];
        [self.captureSession startRunning];
        self.videoPreviewLayer.frame = self.viewCamera.bounds;
    }
    
    
    - (AVCaptureDevice *)frontCamera {
        NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
        for (AVCaptureDevice *device in devices) {
            if ([device position] == AVCaptureDevicePositionFront) {
                return device;
            }
        }
        return nil;
    }
    
    
    - (IBAction)btnCaptureImagePressed:(id)sender {
    
         AVCaptureConnection * videoConnection =  [_stillImageOutput connectionWithMediaType:AVMediaTypeVideo];
    
        [_stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler:^(CMSampleBufferRef  _Nullable sampleBuffer, NSError * _Nullable error) {
           NSData *imageData =  [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:sampleBuffer];
            UIImage *image = [[UIImage alloc]initWithData: imageData];
            UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
        }];
    
    }
    
    @end
    

    【讨论】:

    • 已弃用的 iOS 10
    【解决方案6】:

    这是针对 Xamarin iOS 的相同任务的 C# 实现。

        public void TakePhoto(Action<byte[]> getImageBytesAction)
        {
            var picker = new UIImagePickerController();
            picker.PrefersStatusBarHidden();
            picker.SourceType = UIImagePickerControllerSourceType.Camera;
            picker.CameraDevice = UIImagePickerControllerCameraDevice.Rear;
            
            picker.ShowsCameraControls = false;
            picker.CameraCaptureMode = UIImagePickerControllerCameraCaptureMode.Photo;
            picker.CameraFlashMode = UIImagePickerControllerCameraFlashMode.Off;
    
            picker.FinishedPickingMedia += (object sender, UIImagePickerMediaPickedEventArgs e) =>
            {
                var photo = e.OriginalImage;
                picker.DismissModalViewController(false);
                //var imageSource = ImageSource.FromStream(() => photo.AsJPEG().AsStream());
                //invoke the action when finished taking picture
                var correctedImage = new UIImage(photo.CGImage, 2.0f, UIImageOrientation.Up);   //scaling 2.0 makes image half
                getImageBytesAction.Invoke(correctedImage.AsJPEG().ToArray());
            };
            //open photo picker with TakePicture trigger on load completion (added a delay to let the camera adjust light and focus)
            GetTopViewController().PresentViewController(picker, false, async () => { await Task.Delay(1000); picker.TakePicture(); });
        }
    

    【讨论】:

      猜你喜欢
      • 2010-12-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多