在将UIImage转换为CIImage,然后转换为CGImage并返回UIImage

时间:2018-08-08 09:52:31

标签: ios swift uiimage cgimage ciimage

我知道有很多这样的问题,但是他们的解决方案对我不起作用。

注意:该图片是从Internet下载的。它不是从iPhone的相机中拍摄的。

我有一个UIImage。为了进行一些图像处理操作,我使用Metal并将图像显示在MTKView中。因此,我将图像转换为CIImage。  对图像进行所有修改后,我将其转换回CGImage,然后转换为UIImage并保存。

结果保存的图像方向错误。

我不确定在哪一步会放宽方向(从UIImage转换为CIImage以添加到MTKView时,或从CIImage转换为{ {1}},然后放入CGImage中保存)。因为我不确定,因此下面提供了我为每个步骤尝试过的所有内容:

用于从UIImage转换为UIImage

最初,我只是以这种方式转换图像:

CIImage

然后我尝试使用以下方式:

let let ciImage = CIImage(image: image)

这是方法 let ciImage = CIImage(image: image)?.oriented(forExifOrientation: imageOrientationToTiffOrientation(value: image.imageOrientation)) 的实现(我发现它是here):

imageOrientationToTiffOrientation

要从func imageOrientationToTiffOrientation(value: UIImageOrientation) -> Int32 { switch (value) { case .up: return 1 case .down: return 3 case .left: return 8 case .right: return 6 case .upMirrored: return 2 case .downMirrored: return 4 case .leftMirrored: return 5 case .rightMirrored: return 7 } } 转换为CIImage,然后转换为CGImage

我照常将UIImage转换为CIImage

CGImage

然后我将let cgImage = context?.createCGImage(ciImage, from: ciImage.extent) 转换为cgImageUIImage):

imageToSave

let imageToSave = UIImage(cgImage: cgImage, scale: image.scale, orientation: imageOrientation) imageOrientation是原始图像的方向和比例。

结果,保存的图像仍然具有错误的方向。

有趣的是,当我打印这些图像方向原始值时,它们与image.scale相同的0,但是正如我所说,保存后方向是错误的。

我很困惑为什么会这样。如果您对如何解决此问题有任何建议,我们将不胜感激。

3 个答案:

答案 0 :(得分:2)

TLDR:

let uiImage: UIImage = ...
let ciImage = CIImage(image: uiImage, options:
    [.applyOrientationProperty: true,
     .properties: [kCGImagePropertyOrientation: CGImagePropertyOrientation(uiImage.imageOrientation).rawValue]])

要将UIImageOrientation转换为CGImagePropertyOrientation,此代码使用https://developer.apple.com/documentation/imageio/cgimagepropertyorientation的扩展名

extension CGImagePropertyOrientation {
    init(_ uiOrientation: UIImageOrientation) {
        switch uiOrientation {
            case .up: self = .up
            case .upMirrored: self = .upMirrored
            case .down: self = .down
            case .downMirrored: self = .downMirrored
            case .left: self = .left
            case .leftMirrored: self = .leftMirrored
            case .right: self = .right
            case .rightMirrored: self = .rightMirrored
        }
    }
}

长版:

我刚遇到类似的问题。将UIImage转换为CIImage时,图像可能以错误的方向出现:

let uiImage: UIImage = ...
let ciImage CIImage(image: uiImage) /* does not use uiImage orientation */

最简单的解决方案是使用oriented(_:)方法来更改方向:

let ciImage = CIImage(image: uiImage)?.oriented(CGImagePropertyOrientation(uiImage.imageOrientation))
/* uses CGImagePropertyOrientation extension (see above) */

这可以,但是oriented(_:)方法会创建一个新图像。我认为必须有一种方法可以创建没有中间对象的正确定向的CIImage。还有!尽管我在Internet上的任何地方都找不到它,并且Apple对它的记录不够清楚,所以我将其发布在这里。 @matt向正确的方向迈出了一步,但这还不够。

该解决方案在applyOrientationProperty描述中被“加密”。

图像可以包含在捕获时显示方向的元数据。 您可以加载 使用imageWithContentsOfURL:或init(data :)将此元数据导入CIImage 当捕获的图像包含方向元数据时。使用任何 initWith:options:如果属性(元数据的NSDictionary) 属性)选项

重要的部分被强调。那是关键。 在这里不要混淆optionsproperties也很重要。 )

答案 1 :(得分:1)

创建CIImage时从原始UIImage拾取方向的方法是说:

let ciImage = CIImage(image: image, options: [.applyOrientationProperty:true])!

使用完CIImage后,请使用CIContext().writeJPEGRepresentation将数据保存到磁盘,然后将保留方向元数据。

答案 2 :(得分:0)

您可以尝试此方法

 func image(with image: UIImage?, scaledToSizeKeepingAspect newSize: CGSize) -> UIImage? {
    var newSize = newSize
    var imgHeight = Float(image?.size.height ?? 0.0)
    var imgWeight = Float(image?.size.width ?? 0.0)
    var fact: Float = 0.0
    if imgHeight > imgWeight {
        fact = Float(CGFloat(imgHeight) / newSize.width)
    } else {
        fact = Float(CGFloat(imgWeight) / newSize.height)
    }
    imgHeight = imgHeight / fact
    imgWeight = imgWeight / fact
    newSize = CGSize(width: CGFloat(imgWeight), height: CGFloat(imgHeight))
    UIGraphicsBeginImageContext(newSize)
    // Tell the old image to draw in this new context, with the desired
    // new size
    image?.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height))
        // Get the new image from the context
    let newImage: UIImage? = UIGraphicsGetImageFromCurrentImageContext()
    // End the context
    UIGraphicsEndImageContext()
    // Return the new image.
    return newImage
}

像这样的调用方法:

image(withImage:image,scaledToSizeKeepingAspect:image.size)

这里image是UIImage对象,您要更改的图像通过此方法传递。