我知道很多人问过这个问题,但我没有找到解决此问题的正确答案,我的问题是:如何在预览视图上制作照片(用户点击拍摄按钮后,然后转到预览视图让用户预览)不是镜像,可以在 UIImagePickerController 中解决这个问题吗?我知道如何旋转照片,
UIImageOrientation
中的枚举中的某些内容,例如UIImageOrientationUp
,我知道这意味着什么。我会在用户点击capture按钮后获取照片,然后再进入预览视图,并使用我有镜子的照片覆盖默认照片(使用
cameraOverlayView
),我可以检测到用户点击capture按钮使用 NSNotificationCenter
和 @"_UIImagePickerControllerUserDidCaptureItem",但我找不到办法获取照片。
我使用
cameraViewTransform
,但是当用户拍照(前置摄像头)时,当底部或顶部的Home按钮时,预览视图上的图像不是镜像,但是当左侧或右侧的Home
按钮时,尽管预览视图上的图像不是镜像,但在用户点击capture之前,手机上的图像存在一些问题。使用AVCaptureDeviceDidStartRunningNotification
通知。
- (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;
}
}
最后,我无法在
UIImagePickerController
中解决这个问题,但是我使用AVFoundation
和CoreMotion
解决了这个问题,你可以看到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;
}
下午好。也许我回答晚了,但今天我解决了这个问题。 下面是解决UIImagePickerController预览镜像问题的代码
`
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
}
}
}
`