CIAffineClamp 过滤器不夹紧

CIAffineClamp filter does not clamp

我正在尝试做简单的事情。 我有图像视图,里面有图像。我想将图像平移图像大小的一半宽度,并在变换图像的边缘夹住像素,在 CIAffineClamp 的帮助下将它们向外扩展。但这是行不通的。它什么都不做。我附上了示例项目。

我的代码是:

func translateAndClamp(image: UIImage) -> UIImage {
        guard let cgImage = image.cgImage else {
            return image
        }
        let ciImage = CIImage(cgImage: cgImage)

        var transform = CGAffineTransform.identity
        transform = transform.translatedBy(x: image.size.width / 2, y: 0)

        let filter = CIFilter(name: "CIAffineClamp")!
        filter.setValue(ciImage, forKey: kCIInputImageKey)
        filter.setValue(NSValue(cgAffineTransform: transform), forKey: "inputTransform")

        let context = CIContext(options: [CIContextOption.useSoftwareRenderer: true])

        guard let outputImage = filter.outputImage else {
            return image
        }

        let extent = ciImage.extent.applying(transform)

        guard let result = context.createCGImage(outputImage, from: extent) else {
            return image
        }

        return UIImage(cgImage: result, scale: image.scale, orientation: image.imageOrientation)
    }

Sample project

更新


    private func makeResultImageCroppedAndRotated(from image: UIImage) -> UIImage {
        let angle = CGFloat(gestureHandler.rotation(from: imgView.transform))

        guard let cgImage = image.cgImage else {
            return image
        }

        let rotatedCGImage = rotateImage(image: cgImage, angle: angle)
        let rotated = UIImage(cgImage: rotatedCGImage, scale: image.scale, orientation: image.imageOrientation)
        let cropArea = makeCropArea(for: rotated, in: imgView, anchor: layoutContentView)
        let cropped = cropImage(image: rotatedCGImage, to: cropArea)

        return UIImage(cgImage: cropped, scale: image.scale, orientation: image.imageOrientation)
    }


    private func makeCropArea(for image: UIImage, in imageView: UIImageView, anchor: UIView) -> CGRect {
        let boundingRect = LayoutCorrectionUtility.boundingAspectRect(for: image, inside: imageView)
        let factor = LayoutCorrectionUtility.factor(for: image, insideBoundingRect: boundingRect)

        let x = (anchor.bounds.origin.x - boundingRect.origin.x) * factor
        let y = (anchor.bounds.origin.y - boundingRect.origin.y) * factor
        let width = anchor.frame.width * factor
        let height = anchor.frame.height * factor

        return CGRect(x: x, y: y, width: width, height: height)
    }


    func rotateImage(image: CGImage, angle: CGFloat) -> CGImage {
        let ciImage = CIImage(cgImage: image)

        let newAngle = angle * CGFloat(-1)

        var transform = CATransform3DIdentity
        transform = CATransform3DRotate(transform, CGFloat(newAngle), 0, 0, 1)
        let affineTransform = CATransform3DGetAffineTransform(transform)

        let filter = CIFilter(name: "CIAffineClamp")
        filter?.setValue(ciImage, forKey: kCIInputImageKey)
        filter?.setDefaults()
        filter?.setValue(NSValue(cgAffineTransform: affineTransform), forKey: "inputTransform")

        let contex = CIContext(options: [CIContextOption.useSoftwareRenderer: true])

        guard let outputImage = filter?.outputImage else {
            return image
        }

        let extent = ciImage.extent.applying(affineTransform)
        guard let result = contex.createCGImage(outputImage, from: extent) else {
            return image
        }

        return result
    }


    func cropImage(image: CGImage, to rect: CGRect) -> CGImage {
        let ciImage = CIImage(cgImage: image).clampedToExtent()

        var transform = CGAffineTransform(scaleX: 1, y: -1)
        transform = transform.translatedBy(x: 0, y: -CGFloat(image.height))

        let contex = CIContext(options: [CIContextOption.useSoftwareRenderer: true])

        guard let result = contex.createCGImage(ciImage, from: rect.applying(transform)) else {
            return image
        }

        return result
    }

问题是您还将转换应用于输出 extent。这是对我有用的代码,带有一些注释:

func translateAndClamp(image: UIImage) -> UIImage {
    // no need to use use the internal CGImage
    guard let ciImage = CIImage(image: image) else {
        return image
    }

    // Important: use the CIImage's width here since the UIImage's size
    // is in points, not pixels.
    let transform = CGAffineTransform(translationX: ciImage.extent.width / 2, y: 0)

    // This does the same as CIAffineClamp, but is shorter and doesn't return an Optional.
    let outputImage = ciImage.transformed(by: transform).clampedToExtent()

    // I would advise against using the software renderer, but maybe you have your reasons.
    // Also, if you want to call this method more then once, it's better to create the
    // context on object initialization and re-use it every time since it's expensive to create.
    let context = CIContext(options: [CIContextOption.useSoftwareRenderer: true])

    // Important: don't apply the transform to the output extent!
    // Think of this as the "window" on the image you want to draw.
    // Since you moved the image "inside" the window with the transform,
    // the window needs to be the original image's extent.
    let extent = ciImage.extent

    guard let result = context.createCGImage(outputImage, from: extent) else {
        return image
    }

    return UIImage(cgImage: result, scale: image.scale, orientation: image.imageOrientation)
}