원문

 

개요

이 글에서 이야기하는 Swift의 이미지에 그레이스케일 적용하는 세 가지 방법은 다음과 같습니다.

  • 그레이스케일로 변환 가능하지만 화질을 유지하려면 시간이 걸리는 CIFilter
  • 시간이 덜 걸리고 한 번에 여러 이미지에 적용할 수 있지만 투명한 요소(transparent elements)를 색상으로 바꾸는 CoreGraphics 필터
  • Swift UI에서 View에 그레이스케일 옵션 추가하기

 

첫 번째 방법 – CIFilter

이미지에 그레이스케일을 적용한다고 하면 이미지용 필터가 바로 떠오릅니다. 시중에 이미지에 필터를 적용할 수 있는 앱이 많이 있습니다. 그리고 이것이 Swift에서 그레이스케일을 사용하는 가장 일반적인 방법이기도 합니다.

이 경우 이미지에 효과와 필터를 추가하기 위해 만든 CIFilter를 사용합니다. CIFilter에는 iOS 사진 앱의 효과에 사용되는 CIPhotoEffectNoir라는 구성 요소가 있습니다.

이미지에 적용할 수 있는 2가지 유사한 효과도 있습니다.

  • CIPhotoEffectMono
  • CIPhotoEffectTonal

 

따라서 이미지 품질을 손상시키지 않고 그레이스케일을 추가하려면 이 기능을 적용하면 됩니다.

func grayscale(image: UIImage, filterName: String = "CIPhotoEffectNoir") -> UIImage? {
    
    let context = CIContext(options: nil)
    if let filter = CIFilter(name: filterName) {
        filter.setValue(CIImage(image: image), forKey: kCIInputImageKey)
        if let output = filter.outputImage {
            if let cgImage = context.createCGImage(output, from: output.extent) {
                return UIImage(cgImage: cgImage)
            }
        }
    }
    return nil
}

이 효과는 잘 작동하지만 모든 CIFilter와 마찬가지로 문제는 소요 시간에 있습니다. CIPhotoEffectNoir(또는 기타)로 이미지를 변경하는 데 몇 초가 걸립니다. CIFilter가 이미지 품질을 유지하기 때문입니다. 따라서 한 번에 둘 이상의 이미지를 변환하려면 시간이 걸립니다.

 

 

두 번째 방법 – CGColorSpaceCreateDeviceGray

시간이 덜 걸리고 한 번에 둘 이상의 이미지에 대해 구현할 수 있는 또 다른 옵션은 CoreGraphics입니다.

함수를 살펴보겠습니다.

func convertToGrayScale(image: UIImage) -> UIImage? {
    
    let imageRect: CGRect = CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height)
    let colorSpace = CGColorSpaceCreateDeviceGray()
    let width = image.size.width
    let height = image.size.height
    let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue)
    let context = CGContext(data: nil, width: Int(width), height: Int(height), bitsPerComponent: 8, bytesPerRow: 0, space: colorSpace, bitmapInfo: bitmapInfo.rawValue)
    
    if let cgImg = image.cgImage {
        context?.draw(cgImg, in: imageRect)
        if let makeImg = context?.makeImage() {
            let imageRef = makeImg
            let newImage = UIImage(cgImage: imageRef)
            return newImage
        }
    }
    
    return UIImage()
}

훨씬 빠르게 작동하지만 한계도 있습니다. 투명 요소가 포함된 이미지에는 CGImageAlphaInfo.none을 사용할 수 없습니다. 이는 모든 PNG가 투명도 없이 이미지로 변환된다는 것을 의미합니다. 이미지의 배경색을 지우면 검은색으로 바뀝니다.

이것은 색상을 교체하여 처리할 수도 있지만 이 글에서는 그레이스케일에만 초점을 맞추고 싶습니다.

 

 

세 번째 방법 – SwiftUI 전용

마지막으로 이미지를 그레이스케일로 변환하는 가장 간단한 방법을 보여 드리겠습니다. 이것은 SwiftUI에서만 작동하므로 스토리보드에서는 사용할 수 없습니다. Viewgrayscale이라는 옵션을 추가하기만 하면 됩니다.

func grayscale(_ amount: Double) -> some View

여기서 “amount“는 보기에 적용하려는 그레이스케일의 강도입니다. 이 옵션은 구현하기가 매우 쉽지만 이미지를 CGColorSpace 객체로 변환하는 것만큼 빠르게 작동하지 않는다는 점을 기억해야 합니다.

 

struct Saturation: View {
    var body: some View {
        HStack {
            ForEach(0..<6) {
                Color.red.frame(width: 60, height: 60, alignment: .center)
                    .grayscale(Double($0) * 0.1999)
                    .overlay(Text("\(Double($0) * 0.1999 * 100, specifier: "%.4f")%"),
                             alignment: .bottom)
                    .border(Color.gray)
            }
        }
    }
}

 

문의 | 코멘트 또는 yoonbumtae@gmail.com


카테고리: Swift


0개의 댓글

답글 남기기

Avatar placeholder

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다