简体   繁体   中英

IOS Swift 3: Flip Front Camera Image Horizontally after taking Camera Picture

There are a couple of questions on StackOverflow that deal with image flipping such as this one here . By default, iOS inverts the front camera horizontal image when a picture is taken. I am trying to prevent the front camera image only from being flipped or to flip it back to its proper orientation. I am interacting with a WKWebview .

The problem is that I don't know what method to call or put in my ViewController to get camera and then set it to the proper orientation, or the correct setting to prevent this behavior. I also don't know how to get the camera information that took the image.

Here is one solution I attempted based on translating some Objective-C code to change the image after the camera was done with the photo. However the picture variable is a constant and can't be changed:

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

Any help would be greatly appreciated. Thank you!

You are flipping your image correctly but why are you assigning back your flipped image to picture variable you can use flippedImage variable and pass it where it is required.

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
}

What I am trying to do is prevent the front camera image only from being flipped

If you are using Default Camera then it is not possible to prevent the camera to prevent flipping the image. To do so either you need to create your own camera using AVFoundation and need to apply your logics there.

If you are ready to use any thirds party library then you can check LEMirroredImagePicker

I've ran into this problem before. I honestly don't understand it completely, but this is what my problem was and it probably has something to do with your problem:

What is happening is the iPhone cameras (likely due to some hardware reason) don't always save the image data in the correct orientation. Depending one the iPhone model and which camera it is, they can be saved upside down, sideways, and/or even flipped on one or both of the axis. Whenever you take a picture on the iPhone, it sometimes to "correct" this by applying EXIF transformation metadata to reverse it.

In the case of transformations, the EXIF metadata tells how to rotate and flip the data after its been opened. My guess why this exists is because it's cheaper to apply EXIF transformation metadata to an image rather than transforming the actual image data in memory.

This is sometimes problematic because not everything that displays an image in iOS respects the transformation metadata. This might be happening with the WKWebview. It could be displaying the image without checking the EXIF data for transformations.

I ran into this problem when building a couple of image-processing apps in the past. While I don't have any easy fixes for you, here's how I solved it: 1) First strip all the EXIF transformation data from your UIImage. This is more computationally expensive, but IMO it's worth it because it makes the images much easier to handle and you don't have to worry about things not handling EXIF data. 2) Then properly transform the image in the correct way if the iPhone camera saved it in an undesirable orientation.

These might be a good place to start

Stripping EXIF:

https://stackoverflow.com/a/34161629/4102858 ,

https://stackoverflow.com/a/25595495/4102858

UIImage transformations:

https://stackoverflow.com/a/29753437/4102858

These might not be perfect fixes for you, but hopefully they will help you understand your problem a little better.

Try This:

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)
  }
}

First get the device Model Extension to check device Model for 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

The logic is to check for the Image resolution . We can get the height and width of the image in pixels by the following code and check for the resolution of the FaceTime(Front) Camera:

Main Code Block

//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)
}

Hope this helps.

I know this question has been answered but I think that people might found the below link useful.

Camera images are always landscape but contain metadata orientation field that indicated the device orientation at capturing time.

Unfortunately, some viewers don't read this field and rotate the image.

A nice approach is to read this variable and rotate the image accordingly.

Code was taken from here - 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
    }
}
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM