Вырезать UIImage из маски UIView - PullRequest
0 голосов
/ 04 июля 2019

У меня есть UIView с прозрачным maskLayer определенного радиуса в определенной точке.Кроме того, у меня есть UIImageView с UIPanGesture & UIPinchGesture.

Теперь я могу перетаскивать или увеличивать UIImageView, чтобы он мог вписаться в часть маски UIView.Как только это будет сделано, мне нужно получить UIImage от UIImageView относительно прозрачной части.

Я не знаю, как этого добиться.

masked image

Ниже приведен код, который создает наложение на UIView с указанной маской CGRect & radius.

func createOverlay(frame: CGRect,
                       xOffset: CGFloat,
                       yOffset: CGFloat,
                       radius: CGFloat) -> UIView {
        // Step 1
    let overlayView = UIView(frame: frame)
    overlayView.backgroundColor = UIColor.groupTableViewBackground.withAlphaComponent(0.8)
    // Step 2
    let path = CGMutablePath()
    beizerPath = UIBezierPath(arcCenter: CGPoint(x: xOffset, y: yOffset + radius), radius: radius, startAngle: 0.0, endAngle: 2.0 * .pi, clockwise: false)
    path.addArc(center: CGPoint(x: xOffset, y: yOffset),
                     radius: radius,
                    startAngle: 0.0,
                    endAngle: 2.0 * .pi,
                    clockwise: false)
    path.addRect(CGRect(origin: .zero, size: overlayView.frame.size))
    // Step 3
    let maskLayer = CAShapeLayer()
    maskLayer.backgroundColor = UIColor.black.cgColor
    maskLayer.path = path
    maskLayer.fillRule = .evenOdd
    // Step 4
    overlayView.layer.mask = maskLayer
    overlayView.clipsToBounds = true

    return overlayView
}

Здесь я сохраняю UIBezierPath в случае любогонеобходимость!

Затем я попытался обрезать UIBezierPath на UIImage, но тогда это проблема с прямоугольником.Потому что UIImageView можно перетаскивать и увеличивать, так что CGRect изменяется.Ниже приведен код, который я использовал для создания отсечения.

extension UIImage {

    func imageByApplyingClippingBezierPath(_ path: UIBezierPath) -> UIImage {
        // Mask image using path
        let maskedImage = imageByApplyingMaskingBezierPath(path)

        // Crop image to frame of path
        let croppedImage = UIImage(cgImage: maskedImage.cgImage!.cropping(to: path.bounds)!)
        return croppedImage
    }

    func imageByApplyingMaskingBezierPath(_ path: UIBezierPath) -> UIImage {
        // Define graphic context (canvas) to paint on
        UIGraphicsBeginImageContext(size)
        let context = UIGraphicsGetCurrentContext()!
        context.saveGState()

        // Set the clipping mask
        path.addClip()
        draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))

        let maskedImage = UIGraphicsGetImageFromCurrentImageContext()!

        // Restore previous drawing context
        context.restoreGState()
        UIGraphicsEndImageContext()

        return maskedImage
    }

}

Другое решение, я думаю сделать снимок полного представления, а затем вырезать из него CGRect.Но я не думаю, что это правильный способ!

1 Ответ

1 голос
/ 04 июля 2019

Если возможно, проще всего создать круглый вид и создать снимок этого вида. Проверьте следующее решение:

func cutImageCircle(_ image: UIImage?, inFrame imageFrame: CGRect, contentMode: UIView.ContentMode = .scaleAspectFill, circle: (center: CGPoint, radius: CGFloat)) -> UIImage? {
    guard let image = image else { return nil }

    func generateSnapshotImage(ofView view: UIView, scale: CGFloat = 0.0) -> UIImage? {
        UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, scale)

        defer { UIGraphicsEndImageContext() }

        view.drawHierarchy(in: view.bounds, afterScreenUpdates: true)
        return UIGraphicsGetImageFromCurrentImageContext()
    }

    let imageViewPanel = UIView(frame: CGRect(x: 0.0, y: 0.0, width: circle.radius*2.0, height: circle.radius*2.0))
    imageViewPanel.clipsToBounds = true
    imageViewPanel.layer.cornerRadius = circle.radius

    let imageView = UIImageView(frame: {
        var frame = imageFrame
        frame.origin.x -= circle.center.x-circle.radius
        frame.origin.y -= circle.center.y-circle.radius
        return frame
    }())
    imageView.contentMode = contentMode
    imageView.image = image

    imageViewPanel.addSubview(imageView)

    let cutImage = generateSnapshotImage(ofView: imageViewPanel, scale: 1.0)
    return cutImage
}

Вам нужно только вычислить, где находится центр круга и какой у него размер. Я добавил опцию настройки кадра, чтобы вы могли контролировать размер выходного изображения. Таким образом, вы можете повысить качество получаемого изображения.

...