简体   繁体   中英

CGImage from portrait UIImage

Trying to figure how image is being rotated or flipped when one gets cgImage from UIImage which is in portrait mode.

Ie if I have a case, where image.size.width < image.size.height and then call let cg = image.cgImage! , I get cg.width > cg.height (in fact, cg.width == image.size.height && cg.height == image.size.width ). I know about the difference in coordinates for CGImage and UIImage , but what I don't understand - which corner of UIImage is taken as the origin for CGImage and whether image is flipped somehow?

This messes up with my cropping code, where I simply calculate cropping rectangle for UIImage but then trying to crop image by calling image.cgImage!.cropping(to: rect) gives me unexpected results (wrong area is cropped). Does rect need to be in CGImage 's coordinate system? I tried flipping it like this, but it doesn't help either:

swap(&croppingRect.origin.x, &croppingRect.origin.y)
swap(&croppingRect.size.width, &croppingRect.size.height)

For those, who might run into similar problems as I did, I post this Swift playground code, which helped me understand what's going on and how to tackle it:

import UIKit

let image : UIImage = UIImage(named: "down.JPG")!
image.size
image.imageOrientation.rawValue

let center = CGPoint(x: 0.3, y: 0.3)
let kx = (center.x > 0.5 ? (1-center.x) : center.x)
let ky = (center.y > 0.5 ? (1-center.y) : center.y)
let size = CGSize(width: image.size.width*kx, height: image.size.height*ky)
// cropRect is defined in UIImage coordinate system
// it is defined as a rectangle with center in "center", with proportions
// to the original image. size of rectangle is defined by the distance from 
// the center to the nearest edge divided by 2
// this was chosen due to my specific needs and can be adjusted at will 
// (just don't exceed limits of the original image)
var cropRect = CGRect(x: center.x*image.size.width-size.width/2,
                      y: center.y*image.size.height-size.height/2,
                      width: size.width,
                      height: size.height)

cropRect

if self.imageOrientation == .right || self.imageOrientation == .down || self.imageOrientation == .left
{
    let k : CGFloat = (self.imageOrientation == .right ? -1 :(self.imageOrientation == .left ? 1 : 2))
    let dy = (self.imageOrientation == .right ? self.size.width : (self.imageOrientation == .left ? 0 :self.size.height))
    let dx = (self.imageOrientation == .down ? self.size.width : (self.imageOrientation == .left ? self.size.height : 0))
    let rotate = CGAffineTransform(rotationAngle: k*90/180*CGFloat.pi)
    let translate = CGAffineTransform(translationX: dx, y: dy)
    cropRect = cropRect.applying(rotate).applying(translate)
}

let cgImage = image.cgImage!
cgImage.width
cgImage.height

cropRect

let cropped = cgImage.cropping(to: cropRect)

if cropped != nil
{
    cropped!.width
    cropped!.height

    let croppedImage = UIImage(cgImage: cropped!, scale: image.scale, orientation: image.imageOrientation)

}

Take 4 pictures: "up.JPG", "down.JPG", "left.JPG" and "right.JPG" for all possible camera configurations and upload them to the Resources subfolder of your playground. Load them one by one and check what's happening to the arguments. This code helped me to come up with the working solution: when image has .right or .down orientation, apply affine transforms to the cropping rectangle in order to get desired cropping .

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