iCrany
iCrany

Reputation: 115

UIImagePickerController front camera show mirror image on preview view

I know many people had asked this question, but I am not found some correct answer to fix this issue,My problem is : How can I make the photo on preview view(after user tap the capture button,and then go to the preview view to let the user preview) not mirror, can this prossible fix in UIImagePickerController, I know how to rotate the photo , something in enum in UIImageOrientation like UIImageOrientationUp , I know what this mean.

Try 1:

I attend to get the photo after user tap capture button before go to the preview view and use the photo which I have mirror to cover the default photo (use cameraOverlayView), I can detect the user tap the capture button use NSNotificationCenter with @"_UIImagePickerControllerUserDidCaptureItem", but I find no way to get the photo.

Try 2:

I use cameraViewTransform, but when user take photo (front camera) when the Home button on the bottom or top, the image on preview view is not mirror, but when the Home button on the left or right, the image on phone have some problem before user tap the capture, although the image on the preview view is not mirror.use AVCaptureDeviceDidStartRunningNotification notification.

- (void)cameraChanged:(NSNotification *)notification
{
  if(self.imagePickerController.cameraDevice == UIImagePickerControllerCameraDeviceFront)
  {
     self.imagePickerController.cameraViewTransform = CGAffineTransformIdentity;
     self.imagePickerController.cameraViewTransform = CGAffineTransformScale(self.imagePickerController.cameraViewTransform, -1, 1);
     if (self.imagePickerController.cameraOverlayView) {
        NSLog_DEBUG(@"self.imagePickerController.cameraOverlayView is not nil");
    } else {
        NSLog_DEBUG(@"self.imagePickerController.cameraOverlayView is nil");
    }
    self.imagePickerController.cameraOverlayView.transform = CGAffineTransformScale(self.imagePickerController.cameraViewTransform, -1, 1);
  } else {
    self.imagePickerController.cameraViewTransform = CGAffineTransformIdentity;
  }
}

Upvotes: 1

Views: 1636

Answers (2)

Maks Bogdan
Maks Bogdan

Reputation: 11

Good afternoon. Maybe I'm answering late, but today I solved this problem. Here is the code to solve the UIImagePickerController preview mirroring issue.

`

struct AddImageFromLibrary: UIViewControllerRepresentable {
    
    @Environment(\.presentationMode) private var presentationMode
    
    @Binding var sourceType: UIImagePickerController.SourceType
    @Binding var selectedImage: UIImage?

    
    func makeUIViewController(context: UIViewControllerRepresentableContext<AddImageFromLibrary>) -> UIImagePickerController {
        let imagePicker = CameraCaptureViewController()
        imagePicker.allowsEditing = true
        imagePicker.sourceType = sourceType
        imagePicker.delegate = context.coordinator
        imagePicker.modalPresentationStyle = .fullScreen
        return imagePicker
    }
    
    func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<AddImageFromLibrary>) {}
    
    func makeCoordinator() -> Coordinator {
        return Coordinator(self)
    }
    
    final class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
        var parent: AddImageFromLibrary
        init(_ parent: AddImageFromLibrary) {
            self.parent = parent
        }
        func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
            if let image = info[.editedImage] as? UIImage {
    
                let imageMirroriedNorm = UIImage(cgImage: image.cgImage!, scale: image.scale, orientation: .upMirrored) // mirroed photo
                parent.selectedImage = image
                if picker.sourceType == .camera && picker.cameraDevice == .front{
                    parent.selectedImage = imageMirroriedNorm
                    print("Mirror")
                }else{
                    parent.selectedImage = image
                    print("Original")
                }
            }
            parent.presentationMode.wrappedValue.dismiss()
        }
    }
}

protocol CameraCaptureViewControllerDelegate {
    func cameraPositionDidChanged(newPosition: AVCaptureDevice.Position)
}

class CameraCaptureViewController: UIImagePickerController {

    var lastKnownPosition = AVCaptureDevice.Position.unspecified {
        didSet {
            cameraDelegate?.cameraPositionDidChanged(newPosition: lastKnownPosition)
        }
    }

    var cameraDelegate: CameraCaptureViewControllerDelegate?
    weak private var session: AVCaptureSession?
    private var context = 0

    deinit {
        session?.removeObserver(self, forKeyPath: "inputs")
        NotificationCenter.default.removeObserver(self)
    }
    
    override func viewDidLoad() {
        let notificationCenter = NotificationCenter.default

        notificationCenter.addObserver(forName: NSNotification.Name(rawValue: "_UIImagePickerControllerUserDidCaptureItem"), object: nil, queue: nil) { [weak self] (notification) in
            if self?.lastKnownPosition == .front {
                self?.changePhotoOrientation()
            }
        }

        notificationCenter.addObserver(forName: NSNotification.Name(rawValue: "AVCaptureSessionDidStartRunningNotification"), object: nil, queue: nil) { [weak self] notification in
            self?.handleCaptureSessionDidStartRunning(notification: notification)
        }
        notificationCenter.addObserver(forName: NSNotification.Name(rawValue: "AVCaptureSessionDidStopRunningNotification"), object: nil, queue: nil) { [weak self] notification in
            self?.handleCaptureSessionDidStopRunning(notification: notification)
        }
    }

    func changePhotoOrientation() {
        var subviews: [UIView] = [view]

        while !subviews.isEmpty {
            let subview = subviews.removeFirst()
            subviews += subview.subviews
            if (subview.isKind(of: UIImageView.self)) {
                subview.transform = cameraViewTransform.scaledBy(x: -1, y: 1)
            }
        }
    }

    func handleCaptureSessionDidStartRunning(notification: Notification){
        guard let session = notification.object as? AVCaptureSession else { return }
        self.session = session
        if let input = session.inputs.first as? AVCaptureDeviceInput {
            lastKnownPosition = input.device.position
        }
        session.addObserver(self, forKeyPath: "inputs", options: [ .old, .new ], context: &context)
    }

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

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if let inputs = change?[NSKeyValueChangeKey.newKey] as? [AnyObject], let captureDevice = (inputs.first as? AVCaptureDeviceInput)?.device {
            lastKnownPosition = captureDevice.position
        }
    }
}

`

Upvotes: 1

iCrany
iCrany

Reputation: 115

finally, i can not solve this issue in UIImagePickerController, but i solve this issue using AVFoundation and CoreMotion, you can see AVCam

//init the motionManager
- (void)initializeMotionManager{
  motionManager = [[CMMotionManager alloc] init];
  motionManager.accelerometerUpdateInterval = .1;
  motionManager.gyroUpdateInterval = .1;

  [motionManager startAccelerometerUpdatesToQueue:[NSOperationQueue currentQueue]
                                    withHandler:^(CMAccelerometerData  *accelerometerData, NSError *error) {
                                        if (!error) {
                                            [self outputAccelertionData:accelerometerData.acceleration];
                                        }
                                        else{
                                            NSLog_DEBUG(@"%@", error);
                                        }
                                    }];
  }

//detect the device orientation
- (void)outputAccelertionData:(CMAcceleration)acceleration{

  if (acceleration.x >= 0.75) {
      _orientationNew = UIInterfaceOrientationLandscapeLeft;
  }
  else if (acceleration.x <= -0.75) {
      _orientationNew = UIInterfaceOrientationLandscapeRight;
  }
  else if (acceleration.y <= -0.75) {
      _orientationNew = UIInterfaceOrientationPortrait;
  }
  else if (acceleration.y >= 0.75) {
      _orientationNew = UIInterfaceOrientationPortraitUpsideDown;
  }
  else {
      // Consider same as last time
      return;
  }

  if (_orientationNew == _orientationLast)
      return;

  _orientationLast = _orientationNew;
}

Upvotes: 2

Related Questions