裁剪 CIImage

Cropping CIImage

我有一个 class,它接受一个 UIImage,用它初始化一个 CIImage,就像这样:

workingImage = CIImage.init(image: baseImage!)

然后使用该图像以 3x3 的模式从中裁剪出 9 个相邻的正方形 - 在一个循环中:

for x in 0..<3
    {
        for y in 0..<3
        {

            croppingRect = CGRect(x: CGFloat(Double(x) * sideLength + startPointX),
                                  y: CGFloat(Double(y) * sideLength + startPointY),
                                  width: CGFloat(sideLength),
                                  height: CGFloat(sideLength))
            let tmpImg = (workingImage?.cropping(to: croppingRect))!
        }
    }

那些 tmpImgs 被插入到 table 中并稍后使用,但这不是重点。

此代码适用于 IOS 9IOS 10 模拟器,但 不适用于 实际 IOS 10设备。生成的图像要么全是空的,要么其中一个像它应该是的一半,其余的又是空的。

这不是应该在 IOS 10 中完成的吗?

问题的核心是通过CIImage 不是裁剪UIImage 的方式。一方面,从 CIImage 回到 UIImage 是一件复杂的事情。另一方面,整个往返是不必要的。

如何裁剪

要裁剪图像,请制作所需裁剪大小的图像图形上下文,然后在 UIImage 上调用 draw(at:) 以在相对于图形上下文的所需点绘制它,以便所需的部分图像落入上下文。现在提取生成的新图像并关闭上下文。

为了演示,我将裁剪到您要裁剪到的三分之一中的 一个 ,即右下三分之一:

let sz = baseImage.size
UIGraphicsBeginImageContextWithOptions(
    CGSize(width:sz.width/3.0, height:sz.height/3.0), 
    false, 0)
baseImage.draw(at:CGPoint(x: -sz.width/3.0*2.0, y: -sz.height/3.0*2.0))
let tmpImg = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

原图(baseImage):

裁剪图像(tmpImg):

其他部分完全平行

Core Image的坐标系与UIKit不匹配,需要镜像rect。

因此在您的特定情况下,您需要:

var ciRect = croppingRect
ciRect.origin.y = workingImage!.extent.height - ciRect.origin.y - ciRect.height
let tmpImg = workingImage!.cropped(to: ciRect)

这绝对适用于 iOS 10+。

在更一般的情况下,我们将制作一个涵盖两种可能坐标系的 UIImage 扩展,这比 draw(at:):

快得多
extension UIImage {
    /// Return a new image cropped to a rectangle.
    /// - parameter rect:
    /// The rectangle to crop.
    open func cropped(to rect: CGRect) -> UIImage {
        // a UIImage is either initialized using a CGImage, a CIImage, or nothing
        if let cgImage = self.cgImage {
            // CGImage.cropping(to:) is magnitudes faster than UIImage.draw(at:)
            if let cgCroppedImage = cgImage.cropping(to: rect) {
                return UIImage(cgImage: cgCroppedImage)
            } else {
                return UIImage()
            }
        }
        if let ciImage = self.ciImage {
            // Core Image's coordinate system mismatch with UIKit, so rect needs to be mirrored.
            var ciRect = rect
            ciRect.origin.y = ciImage.extent.height - ciRect.origin.y - ciRect.height
            let ciCroppedImage = ciImage.cropped(to: ciRect)
            return UIImage(ciImage: ciCroppedImage)
        }
        return self
    }
}

我已经为它制作了一个pod,所以源代码在https://github.com/Coeur/ImageEffects/blob/master/SwiftImageEffects/ImageEffects%2Bextensions.swift