【问题标题】:Saving a UIImage cropped to a CGPath将裁剪后的 UIImage 保存到 CGPath
【发布时间】:2021-11-29 01:25:44
【问题描述】:

我正在尝试屏蔽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 - 保持原样并应用遮住它)。

我已经尝试过了,但它只是保存了原始图像 - 没有应用路径/掩码:

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

我做错了什么?谢谢。

【问题讨论】:

标签: ios swift uikit uiimage cgcontext


【解决方案1】:

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

例子:

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
}

【讨论】:

  • 大功告成!非常感谢 :) 这两个例子都有效,所以只会看看哪个更适合这种情况。再次感谢!
  • @chumps52 这取决于您是否想要尽可能小的图像。
  • 我想你不知道如何设置它,以便当前被遮罩的区域实际上被移除/变得透明?在UIImageView预览中是这样,但是保存的时候^是白色的。
  • 对我来说不是白色的...你是不是碰巧把它保存为不支持透明度的jpg? @chumps52
  • 啊 - 我正在使用 UIImageWriteToSavedPhotosAlbum(saveImage, nil, nil, nil) 保存到用户的相册,我猜这似乎是 jpeg?这给了白色面具。使用saveImage.pngData() 保存到文件虽然有效。
猜你喜欢
  • 1970-01-01
  • 2011-06-15
  • 1970-01-01
  • 2010-09-14
  • 2011-09-25
  • 1970-01-01
  • 1970-01-01
  • 2012-07-03
  • 1970-01-01
相关资源
最近更新 更多