将裁剪后的 UIImage 保存到 CGPath

Saving a UIImage cropped to a CGPath

我正在尝试屏蔽 UIImage 然后保存屏蔽的图像。到目前为止,当在 UIImageView 预览中显示时,我已经可以正常工作了,如下所示:

let maskLayer = CAShapeLayer()
let maskPath = shape.cgPath
maskLayer.path = maskPath.resized(to: imageView.frame)
maskLayer.fillRule = .evenOdd
imageView.layer.mask = maskLayer

let picture = UIImage(named: "1")!
imageView.contentMode = .scaleAspectFit
imageView.image = picture

其中 shapeUIBezierPath().

resized函数是:

extension CGPath {
    func resized(to rect: CGRect) -> CGPath {
        let boundingBox = self.boundingBox
        let boundingBoxAspectRatio = boundingBox.width / boundingBox.height
        let viewAspectRatio = rect.width / rect.height
        let scaleFactor = boundingBoxAspectRatio > viewAspectRatio ?
            rect.width / boundingBox.width :
            rect.height / boundingBox.height

        let scaledSize = boundingBox.size.applying(CGAffineTransform(scaleX: scaleFactor, y: scaleFactor))
        let centerOffset = CGSize(
            width: (rect.width - scaledSize.width) / (scaleFactor * 2),
            height: (rect.height - scaledSize.height) / (scaleFactor * 2)
        )

        var transform = CGAffineTransform.identity
            .scaledBy(x: scaleFactor, y: scaleFactor)
            .translatedBy(x: -boundingBox.minX + centerOffset.width, y: -boundingBox.minY + centerOffset.height)

        return copy(using: &transform)!
    }
}

所以这在预览我想要的结果方面是有效的。我现在想将这个修改后的 UIImage 以原始大小保存到用户的相册中(因此基本上再次生成它但不要调整图像大小以适合 UIImageView - 保持原样 -是并在上面涂上面具)。

我试过了,但它只保存了原始图像 - 没有应用 path/mask:

func getMaskedImage(path: CGPath) {
    let picture = UIImage(named: "1")!
    UIGraphicsBeginImageContext(picture.size)

    if let context = UIGraphicsGetCurrentContext() {
        let pathNew = path.resized(to: CGRect(x: 0, y: 0, width: picture.size.width, height: picture.size.height))
        context.addPath(pathNew)
        context.clip()

        picture.draw(in: CGRect(x: 0.0, y: 0.0, width: picture.size.width, height: picture.size.height))

        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        UIImageWriteToSavedPhotosAlbum(newImage!, nil, nil, nil)
    }
}

我做错了什么?谢谢。

不要放弃基于图层的方法!在图形上下文中绘图时,您仍然可以使用它。

示例:

func getMaskedImage(path: CGPath) -> UIImage? {
    let picture = UIImage(named: "my_image")!
    let imageLayer = CALayer()
    imageLayer.frame = CGRect(origin: .zero, size: picture.size)
    imageLayer.contents = picture.cgImage
    let maskLayer = CAShapeLayer()
    let maskPath = path.resized(to: CGRect(origin: .zero, size: picture.size))
    maskLayer.path = maskPath
    maskLayer.fillRule = .evenOdd
    imageLayer.mask = maskLayer
    UIGraphicsBeginImageContext(picture.size)
    defer { UIGraphicsEndImageContext() }

    if let context = UIGraphicsGetCurrentContext() {
        imageLayer.render(in: context)
        
        let newImage = UIGraphicsGetImageFromCurrentImageContext()

        return newImage
    }
    return nil
}

请注意,这实际上并没有调整图像的大小。如果你想调整图像的大小,你应该得到调整后的路径的 boundingBox 。然后改为这样做:

// create a context as big as the bounding box
UIGraphicsBeginImageContext(boundingBox.size)
defer { UIGraphicsEndImageContext() }

if let context = UIGraphicsGetCurrentContext() {
    // move the context to the top left of the path
    context.translateBy(x: -boundingBox.origin.x, y: -boundingBox.origin.y)
    imageLayer.render(in: context)
    let newImage = UIGraphicsGetImageFromCurrentImageContext()

    return newImage
}