【问题标题】:How to crop UIImage to mask in Swift如何在 Swift 中裁剪 UIImage 以进行遮罩
【发布时间】:2018-11-20 00:46:47
【问题描述】:

我有一个 UIImage,我使用另一个 UIImage 进行了屏蔽。唯一的问题是被屏蔽的 UIImage 之外的区域仍然是用户可交互的。如何将 UIImage 完全裁剪为另一个图像而不是蒙版。

@IBOutlet weak var imageView: UIImageView!

override func viewDidLoad() {
    super.viewDidLoad()
    let imageMask = UIImageView()

    imageMask.image = //image to mask

    imageMask.frame = photoImageView.bounds
    imageView.mask = imageMask
}

【问题讨论】:

标签: swift uiimageview crop


【解决方案1】:

标准

一个简单的测试用例可以为 ViewController 的视图定义背景颜色并加载图像和蒙版。然后将 UITapGestureRecognizer 添加到 ViewController 视图和 UIImageView。

将背景颜色应用到 ViewController 视图时,很容易看出遮罩是否有效。

如果你随后点击了一个不透明的区域,那么 UIImageView 应该会收到点击,否则 ViewController 视图应该会收到点击。

图像和蒙版图像大小

在大多数情况下,图像和遮罩图像的大小或至少图像和遮罩图像的纵横比相同。 对 UIImageView 使用与原始 UIImageView 相同的contentMode 是有意义的,否则最迟在 InterfaceBuilder 中更改内容模式时会出现错位。

测试用例

因此测试用例可能如下所示:

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var imageView: UIImageView!
    private let maskView = UIImageView()

    override func viewDidLoad() {
        super.viewDidLoad()
        self.imageView.image = UIImage(named: "testimage")
        self.maskView.image = UIImage(named: "mask")
        self.imageView.mask = maskView

        let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(backgroundTapped))
        self.view.addGestureRecognizer(tapGestureRecognizer)

        let imageViewGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(iamgeViewTapped))
        self.imageView.addGestureRecognizer(imageViewGestureRecognizer)
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        self.maskView.contentMode = self.imageView.contentMode
        self.maskView.frame = self.imageView.bounds
    }

    @objc private func backgroundTapped() {
        print ("background tapped!")
    }

    @objc private func iamgeViewTapped() {
        print ("image view tapped!")
    }

}

此代码已在运行。然而,正如预期的那样,在 UIImageView 的透明区域上的点击也会到达这里。

自定义图像视图

因此我们需要一个CustomImageView,当点击一个透明像素时返回它不负责。

这可以通过重写这个方法来实现:

func point(inside point: CGPoint, 
      with event: UIEvent?) -> Bool

在此处查看文档:https://developer.apple.com/documentation/uikit/uiview/1622533-point

返回一个布尔值,指示接收器是否包含指定的点。

SO 上已经有这个很酷的答案,只是稍作修改:https://stackoverflow.com/a/27923457

import UIKit

class CustomImageView: UIImageView {

    override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
        return self.alphaFromPoint(point: point) > 32
    }

    private func alphaFromPoint(point: CGPoint) -> UInt8 {
        var pixel: [UInt8] = [0, 0, 0, 0]
        let colorSpace = CGColorSpaceCreateDeviceRGB();
        let alphaInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)
        if let context = CGContext(data: &pixel,
                                   width: 1,
                                   height: 1,
                                   bitsPerComponent: 8,
                                   bytesPerRow: 4,
                                   space: colorSpace,
                                   bitmapInfo: alphaInfo.rawValue) {
            context.translateBy(x: -point.x, y: -point.y)
            self.layer.render(in: context)
        }
        return pixel[3]
    }

}

别忘了在身份检查器的 Xcode 中将 ImageView 的自定义类更改为 CustomImageView。

如果您现在点击透明区域,背景中的 ViewController 的视图就会被点击。如果您点击非透明区域,我们的图像视图就会收到点击。

演示

这是使用问题中的图像和掩码的上述代码的简短演示:

【讨论】:

  • 谢谢,这正好回答了我的问题
猜你喜欢
  • 1970-01-01
  • 2014-05-11
  • 2019-05-26
  • 2014-12-07
  • 1970-01-01
  • 2015-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多