🦋

SwiftUI: 絵文字をモノクロ化してTintカラーで表示する

2023/09/24に公開

絵文字をモノクロ化したり、Tintカラーで表示したいことよくありますよね!


🏖️の絵文字をモノクロ化したりTintカラーで表示したり

それ、NSStringUIGraphicsRendererContextCIFilterでできます。

import SwiftUI
import CoreImage.CIFilterBuiltins

struct PlaygroundView: View {
    var body: some View {
        HStack(spacing: 20) {
            Text("🏖️")
                .font(.system(size: 100))
            Image(systemName: "arrowshape.right.fill")
                .font(.largeTitle)
            convertToMonochrome(emoji: "🏖️")
                .renderingMode(.template)
                .foregroundColor(Color.blue)
        }
    }

    func convertToMonochrome(emoji: String) -> Image {
        let text = NSString(string: emoji)
        let attributes = [
            NSAttributedString.Key.font: UIFont.systemFont(ofSize: 100)
        ]
        let textSize = text.size(withAttributes: attributes)
        UIGraphicsBeginImageContext(textSize)
        text.draw(at: .zero, withAttributes: attributes)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        let dummy = Image(systemName: "questionmark.circle.fill")
        guard let image else { return dummy }
        let monoFilter = CIFilter.photoEffectMono()
        monoFilter.inputImage = CIImage(image: image)
        guard let output = monoFilter.outputImage else { return dummy }
        let invertFilter = CIFilter.colorInvert()
        invertFilter.inputImage = output
        guard let output2 = invertFilter.outputImage else { return dummy }
        let alphaFilter = CIFilter.maskToAlpha()
        alphaFilter.inputImage = output2
        guard let output3 = alphaFilter.outputImage else { return dummy }
        guard let cgImage = CIContext().createCGImage(output3, from: output3.extent) else { return dummy }
        return Image(cgImage, scale: 1.0, label: Text(emoji))
    }
}

ポイント

  • 絵文字を文字列として一度UIImageにする
    • NSString.size(withAttributes:)で画像にした時のサイズを取得
    • UIGraphicsBeginImageContext()UIGraphicsEndImageContext()の間で画像への描画処理を行い、UIGraphicsGetImageFromCurrentImageContext()で画像として出力
  • 絵文字をモノクロAlpha画像化
    • CIFilter.photoEffectMono()で絵文字を白黒に
    • CIFilter.colorInvert()で画像の白黒を反転
    • CIFilter.maskToAlpha()で画像の黒いところをAlphaとして抜く
  • renderingMode(.template)で画像に色をオーバーレイできるようにする

Discussion