SwiftUI - 使用 UIBezierPath 裁剪的图像未在合适的位置剪切

问题描述 投票:0回答:1

嘿,我正在构建一个裁剪文档应用程序。 我正在从相机获取从 CIImage 转换为 UIImage 的图像。 一旦它到达我的 SwiftUI 视图,我就会在上面绘制一个裁剪视图。 然后我使用 UIBezierPath 裁剪视图。

裁剪中的某些内容有些错误,因为形状是正确的,但图片的内容却不正确。

这是持有我观点的结构:

   struct PathPoint {
    var topLeft: CGPoint
    var topRight: CGPoint
    var bottomLeft: CGPoint
    var bottomRight: CGPoint
    
    init(topLeft: CGPoint = .zero, topRight: CGPoint = .zero, bottomLeft: CGPoint = .zero, bottomRight: CGPoint = .zero) {
        self.topLeft = topLeft
        self.topRight = topRight
        self.bottomLeft = bottomLeft
        self.bottomRight = bottomRight
    }
   
    func createBezierPath() -> UIBezierPath {
        let path = UIBezierPath()
        path.move(to: topLeft)
        path.addLine(to: topRight)
        path.addLine(to: bottomRight)
        path.addLine(to: bottomLeft)
        path.close() // Close the path to form a rectangle
        return path
    }
    
    func createCGPath() -> CGPath {
        createBezierPath().cgPath
    }

}

这里是裁剪代码的地方:


    func imageByApplyingClippingBezierPath(_ path: UIBezierPath) -> UIImage? {
        guard let maskedImage = imageByApplyingMaskingBezierPath(path),
              let cgImage = maskedImage.cgImage else { return nil }
        
        guard let cropped = cgImage.cropping(to: path.bounds) else {
            print(#function, "could not crop for bounds \(path.bounds)")
            return nil
        }
        let croppedImage = UIImage(cgImage: cropped)
        
        return croppedImage
    }
    
    func imageByApplyingMaskingBezierPath(_ path: UIBezierPath) -> UIImage? {
        UIGraphicsBeginImageContext(size)
        let context = UIGraphicsGetCurrentContext()!
        context.saveGState()

        path.addClip()
        draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))

        guard let maskedImage = UIGraphicsGetImageFromCurrentImageContext() else { return nil }

        context.restoreGState()
        UIGraphicsEndImageContext()

        return maskedImage
    }

Cropping done on swiftUI

Result where shape is correct but the image is not

ios image swiftui uikit crop
1个回答
0
投票

正如@DonMag 注意到我缺少缩放部分,其中 UIImage 大小得到适合我们应用裁剪边界/绘制的屏幕的大小。

为了像这样转换我的 CIImage:

    func convertCIImageToUIImage(ciImage: CIImage) -> UIImage? {
        let context = MetalDevice.shared.context
        if let cgImage = context.createCGImage(ciImage, from: ciImage.extent) {
            return UIImage(cgImage: cgImage).scale(newSize: self.view.bounds.size)
        }
                
        return nil
    }

其中 UIImage.scale(newSize:) 扩展名是:


    func scale(newSize: CGSize) -> UIImage {

        let scaleFactorWidth = newSize.width / self.size.width
        let scaleFactorHeight = newSize.height / self.size.height
        
        let scale = min(scaleFactorWidth, scaleFactorHeight)

        
        let newHeight = self.size.height * scale
        let newWidth = self.size.width * scale
        
        UIGraphicsBeginImageContextWithOptions(.init(width: newWidth, height: newHeight), true, 0.0)
        self.draw(in: CGRect(x: 0, y: 0, width: newWidth, height: newHeight))
        
        let newImage: UIImage? = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
        return newImage ?? self
    }

请注意,可以使用 CILanczosScaleTransform 过滤器直接缩放 CIImage。

并且它会被应用在扩展中:

    func lanczosScale(to bounds: CGSize) -> UIImage? {
        let targetWidth = bounds.width
        let targetHeight = bounds.height

        let originalWidth = extent.width
        let originalHeight = extent.height
        let scaleX = targetWidth / originalWidth
        let scaleY = targetHeight / originalHeight

        let scale = min(scaleX, scaleY)

        let scaleFilter = CIFilter(name: "CILanczosScaleTransform")!
        scaleFilter.setValue(self, forKey: kCIInputImageKey)
        scaleFilter.setValue(scale, forKey: kCIInputScaleKey)
        scaleFilter.setValue(1.0, forKey: kCIInputAspectRatioKey) 

        if let outputImage = scaleFilter.outputImage {
            let context = MetalDevice.shared.context
            if let cgImage = context.createCGImage(outputImage, from: outputImage.extent) {
                let resizedImage = UIImage(cgImage: cgImage)
                
                return resizedImage
            }
            return nil
        }
        return nil
    }

现在的问题是,为了保持分辨率,我应该直接对缓冲区应用一些大小调整吗?但这还需要进一步研究。

© www.soinside.com 2019 - 2024. All rights reserved.