IOS Swift 3:在拍摄相机照片后水平翻转前置摄像头图像

15

在StackOverflow上有几个关于图像翻转的问题,例如这里。默认情况下,iOS在拍照时会翻转前置摄像头水平图像。我正在尝试防止仅翻转前置摄像头图像或将其翻转回正确的方向。我正在使用一个WKWebview交互。

问题在于我不知道要调用哪个方法或在我的ViewController中放置什么来获取相机并将其设置为正确方向,或者正确的设置以防止此行为。我也不知道如何获取拍摄照片的相机信息。

这是我尝试的一种解决方案,基于将一些Objective-C代码转换为在摄像头完成照片后更改图像的代码。但是,图片变量是一个常量,无法更改:

func didTakePicture(_ picture: UIImage) {
    var flippedImage = UIImage(cgImage: picture.cgImage!, scale: picture.scale, orientation: .leftMirrored)
    picture = flippedImage
}

任何帮助都将不胜感激。谢谢!

5个回答

19
你已经正确地翻转了图像,但为什么要将翻转后的图像再次赋值给picture变量?你可以使用flippedImage变量,并在需要时传递它。
func didTakePicture(_ picture: UIImage) {
    var flippedImage = UIImage(CGImage: picture.CGImage!, scale: picture.scale, orientation: .leftMirrored)
    // Here you have got flipped image you can pass it wherever you are using image
}

我想做的是只防止前置摄像头图像翻转。
如果您使用默认相机,则无法防止相机翻转图像。要这样做,您需要使用AVFoundation创建自己的相机并在那里应用逻辑。
如果您准备使用任何第三方库,则可以检查LEMirroredImagePicker

那就是问题所在。我正在使用HTML文件输入标签通过相机拍摄照片。我不知道如何在拍摄相机照片后立即将翻转的图像发送回进行文件上传。 - applecrusher
@applecrusher 你设置好了将图片放入输入标签吗?我认为没有必要将图片放入输入标签中。在WKWebView中提示图片正在上传到服务器就足够了,例如缩略图。 - jhd
我想我明白了。那么告诉wkwebview前置摄像头拍照,甚至可以通过元数据来实现。这可能有效,但我不确定如何通过该方法获取哪个相机拍摄的照片。 - applecrusher
@ applecrusher 你可以通过检查所拍照片的分辨率来知道照片是由哪个相机拍摄的,所有前置摄像头都拍摄1.2、5或7 mp的照片。iPad mini 2、3、iPad第四代和iPad air都有5 mpx的后置摄像头,这在我的解决方案中已处理。检查一下,我认为它应该可以工作。 - Md. Ibrahim Hassan
我使用了.upMirrored方向来获得结果。 - Aaban Tariq Murtaza

3
我以前也遇到过这个问题。我并不完全理解它,但这就是我的问题所在,它可能与你的问题有关:
由于某些硬件原因,iPhone相机通常不会将图像数据保存在正确的方向上。根据iPhone型号和摄像头类型,它们可能会倒置、侧倒或甚至在一个或两个轴上翻转。每当你在iPhone上拍照时,它有时会通过应用EXIF变换元数据来“纠正”它。
在变换的情况下,EXIF元数据告诉如何在打开后旋转和翻转数据。我猜这个存在的原因是因为将EXIF变换元数据应用于图像比在内存中转换实际图像数据更便宜。
这有时会出现问题,因为在iOS上显示图像的所有内容都不一定尊重变换元数据。这可能正在发生在WKWebview上。它可能在不检查变换的EXIF数据的情况下显示图像。
我曾在过去构建几个图像处理应用程序时遇到了这个问题。虽然我没有为您提供任何简单的解决方法,但以下是我解决问题的方法:1)首先从UIImage中删除所有EXIF转换数据。这更加消耗计算资源,但我认为它很值得,因为它使图像更容易处理,而且您不必担心无法处理EXIF数据的问题。2)如果iPhone相机以不理想的方向保存了图像,则正确地进行变换。

这些可能是一个好的起点

去除EXIF:

https://dev59.com/5Wct5IYBdhLWcg3wNq2v#34161629,

https://dev59.com/AoLba4cB1Zd3GeqPl_iB#25595495

UIImage转换:

https://dev59.com/dV4d5IYBdhLWcg3wLf4g#29753437

这些可能不是完美的解决方案,但希望它们能帮助您更好地理解问题。

2
试试这个:

if captureDevice.position == AVCaptureDevicePosition.back {
  if let image = context.createCGImage(ciImage, from: imageRect) {
    return UIImage(cgImage: image, scale: UIScreen.main.scale, orientation: .right)
  }
}

if captureDevice.position == AVCaptureDevicePosition.front {
  if let image = context.createCGImage(ciImage, from: imageRect) {
    return UIImage(cgImage: image, scale: UIScreen.main.scale, orientation: .leftMirrored)
  }
}

1

首先获取设备型号 检查UIDevice的设备型号扩展 link

import UIKit

public extension UIDevice {

    var modelName: String {
        var systemInfo = utsname()
        uname(&systemInfo)
        let machineMirror = Mirror(reflecting: systemInfo.machine)
        let identifier = machineMirror.children.reduce("") { identifier, element in
            guard let value = element.value as? Int8 where value != 0 else { return identifier }
            return identifier + String(UnicodeScalar(UInt8(value)))
        }

        switch identifier {
        case "iPod5,1":                                 return "iPod Touch 5"
        case "iPod7,1":                                 return "iPod Touch 6"
        case "iPhone3,1", "iPhone3,2", "iPhone3,3":     return "iPhone 4"
        case "iPhone4,1":                               return "iPhone 4s"
        case "iPhone5,1", "iPhone5,2":                  return "iPhone 5"
        case "iPhone5,3", "iPhone5,4":                  return "iPhone 5c"
        case "iPhone6,1", "iPhone6,2":                  return "iPhone 5s"
        case "iPhone7,2":                               return "iPhone 6"
        case "iPhone7,1":                               return "iPhone 6 Plus"
        case "iPhone8,1":                               return "iPhone 6s"
        case "iPhone8,2":                               return "iPhone 6s Plus"
        case "iPhone9,1", "iPhone9,3":                  return "iPhone 7"
        case "iPhone9,2", "iPhone9,4":                  return "iPhone 7 Plus"
        case "iPhone8,4":                               return "iPhone SE"
        case "iPad2,1", "iPad2,2", "iPad2,3", "iPad2,4":return "iPad 2"
        case "iPad3,1", "iPad3,2", "iPad3,3":           return "iPad 3"
        case "iPad3,4", "iPad3,5", "iPad3,6":           return "iPad 4"
        case "iPad4,1", "iPad4,2", "iPad4,3":           return "iPad Air"
        case "iPad5,3", "iPad5,4":                      return "iPad Air 2"
        case "iPad2,5", "iPad2,6", "iPad2,7":           return "iPad Mini"
        case "iPad4,4", "iPad4,5", "iPad4,6":           return "iPad Mini 2"
        case "iPad4,7", "iPad4,8", "iPad4,9":           return "iPad Mini 3"
        case "iPad5,1", "iPad5,2":                      return "iPad Mini 4"
        case "iPad6,3", "iPad6,4", "iPad6,7", "iPad6,8":return "iPad Pro"
        case "AppleTV5,3":                              return "Apple TV"
        case "i386", "x86_64":                          return "Simulator"
        default:                                        return identifier
        }
    }

}

You call it like this:

let modelName = UIDevice.currentDevice().modelName

逻辑是检查图像分辨率。我们可以通过以下代码获取图像的像素高度宽度,并检查FaceTime(前置)摄像头的分辨率:

主要代码块

//Getting model Name
let modelName = UIDevice.currentDevice().modelName
//Getting the height and the width of the image captured. The apple devices either have a 7 MP,5 MP front camera or a 1.2 MP front camera. 
let heightInPoints = image.size.height
let heightInPixels = heightInPoint * image.scale

let widthInPoints = image.size.width
let widthInPixels = widthInPoints * image.scale

//Checking for 7 megapixel
//3,072 x 2304 or 3180x2375 (Sorry I am not sure about the exact resolution)
if (heightInPixels == 2304 && widthInPixels== 3,072)
{
 var flippedImage = UIImage(cgImage: picture.cgImage!, scale: picture.scale, orientation: .leftMirrored)
}
//Checking for 5 megapixel 
//2592 x 1936 resolution 
if (heightInPixels == 1944 && widthInPixels== 2592)
{
 if (modelName == "iPad Mini 2" || modelName == "iPad Mini 3" || modelName == "iPad Air" || modelName == "iPad 4")
{
print ("iPad models with 5mp back camera")
}
else
{
 var flippedImage = UIImage(cgImage: picture.cgImage!, scale: picture.scale, orientation: .leftMirrored)
}
     }
//Checking for 1.2 MP camera
//1200 x 780 pixels 2MP resolution for iPhone 6/6+/someipad Models they have a 1.2MP camera 

//No apple iDevice has a main camera below this resolution
else if (heightInPixels == 780 && widthInPixel == 1200)
{
 var flippedImage = UIImage(cgImage: picture.cgImage!, scale: picture.scale, orientation: .leftMirrored)
}

希望这有所帮助。

1
我需要更仔细地查看你的代码,但是你是说只有某些模型会翻转图像吗?当使用前置摄像头时,我注意到 iPhone 7+ 上存在 y 轴反射。 - Moondra

0

我知道这个问题已经有答案了,但我认为人们可能会发现下面的链接很有用。

相机图像始终是横向的,但包含元数据方向字段,指示捕获时的设备方向。

不幸的是,一些查看器不读取此字段并旋转图像。

一个好的方法是读取此变量并相应地旋转图像。

代码来自这里 - https://github.com/nativ18/Swift-Extensions/blob/master/UIImage%2BExtensions

extension UIImage {

func alignOrientationMetadataAndSize() -> UIImage? {
    let landscapeMetadata = imageOrientation == .left || imageOrientation == .leftMirrored || imageOrientation == .right || imageOrientation == .rightMirrored
    let landscapeSize = size.width > size.height
    switch (landscapeSize, landscapeMetadata) {
    case (false, true), (true, false):
        var newSize = CGSize(width: size.height, height: size.width)
        // Trim off the extremely small float value to prevent core graphics from rounding it up
        newSize.width = floor(newSize.width)
        newSize.height = floor(newSize.height)
        UIGraphicsBeginImageContextWithOptions(newSize, false, self.scale)
        let context = UIGraphicsGetCurrentContext()!
        context.translateBy(x: newSize.width/2, y: newSize.height/2)
        self.draw(in: CGRect(x: -self.size.width/2, y: -self.size.height/2, width: self.size.width, height: self.size.height))
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage
    default:
        return self
    }
}
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接