LoginSignup
3
3

UIImageにモザイクを入れる方法

Last updated at Posted at 2023-08-20

UIImageにモザイクを適用する場面があったため、備忘録として残しておきます。

実装

public extension UIImage {
    func mosaic(_ scale: Float) -> UIImage {
        guard let filter = CIFilter(name: "CIPixellate"),
              let ciImage = CIImage(image: self)
        else {
            return self
        }

        filter.setValue(ciImage, forKey: kCIInputImageKey)
        filter.setValue(scale, forKey: kCIInputScaleKey)

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

        return UIImage(ciImage: outputImage)
    }
}

また、このような実装だと、画素数が異なるとモザイクの精度まで異なってしまいます。
そこで、画素数が変化してもモザイクの精度が変わらないように細工します。

public extension UIImage {
    func mosaic(_ scale: Float) -> UIImage {
        guard let filter = CIFilter(name: "CIPixellate"),
              let ciImage = CIImage(image: self)
        else {
            return self
        }

        filter.setValue(ciImage, forKey: kCIInputImageKey)
        filter.setValue(Float(size.width) * scale / 1000, forKey: kCIInputScaleKey)

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

        return UIImage(ciImage: outputImage)
    }
}

1000で割っていますが、ここは自分で調整してください。

使用方法

let image = UIImage(named: "hoge")?.mosaic(50)

このようにモザイクを適用できていることがわかります。
IMG_E62B62F772B9-1.jpeg

注意

CIImageはSwiftUIでは使用できません!!
SwiftUIで使用したい場合はこのようにUIImageViewをSwiftUIでWrapして使用しましょう.

public struct UIImageViewWrap: UIViewRepresentable {
    // BindingにしないとupdateUIViewが呼ばれない
    @Binding var image: UIImage

    public init(image: Binding<UIImage>) {
        self._image = image
    }

    public func makeUIView(context: Context) -> UIView {
        let view = UIView(frame: .zero)
        let imageView = UIImageView(image: image)
        imageView.contentMode = .scaleAspectFit

        imageView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(imageView)

        NSLayoutConstraint.activate([
            imageView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            imageView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            imageView.topAnchor.constraint(equalTo: view.topAnchor),
            imageView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
        ])

        return view
    }

    public func updateUIView(_ uiView: UIView, context: Context) {
        if let imageView = uiView.subviews.compactMap({ $0 as? UIImageView }).first {
            imageView.image = image
        }
    }
}
3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3