Реплицировать результат `маскировки функции (_ mask: CGImage) -> CGImage?` с помощью Core Image framework

#ios #swift #uiimage #cgimage #ciimage

#iOS #swift #uiimage #cgimage #ciimage

Вопрос:

Есть ли возможность реплицировать func masking(_ mask: CGImage) -> CGImage? из Core Graphics с помощью CoreImage и одного из CIFilter ? Я пытался CIBlendWithMask и CIBlendWithAlphaMask безуспешно. Самое главное, что мне нужно сохранить альфа-канал, поэтому я хочу, чтобы изображение было замаскировано таким образом, что если маска черная -> показать изображение, если маска белая -> прозрачная. Мой код маскировки:

 extension UIImage {
    
    func masked(by mask: UIImage) -> UIImage {
        guard let maskRef = mask.cgImage,
            let selfRef = cgImage,
            let dataProvider = maskRef.dataProvider,
            let mask = CGImage(
                maskWidth: maskRef.width,
                height: maskRef.height,
                bitsPerComponent: maskRef.bitsPerComponent,
                bitsPerPixel: maskRef.bitsPerPixel,
                bytesPerRow: maskRef.bytesPerRow,
                provider: dataProvider,
                decode: nil,
                shouldInterpolate: false),
            let masked = selfRef.masking(mask) else {
                    fatalError("couldnt create mask!")
        }
        let maskedImage = UIImage(cgImage: masked)
        return maskedImage
    }
}
  

Ответ №1:

Я нашел решение. Ключ в том, чтобы использовать изображение в формате оттенков серого, rgb и другие не будут работать. Шаг изменения размера можно удалить, если изображение и maks имеют одинаковый размер. Выполнимо как расширение, может быть выполнено и как подкласс CIImage. Наслаждайтесь 🙂

Конечно, его можно изменить как расширение на UIImage , CIImage , CIFilter , как вам нравится.

 extension CGImage {
    
    func masked(by cgMask: CGImage) -> CIImage {
        let selfCI = CIImage(cgImage: self)
        let maskCI = CIImage(cgImage: cgMask)
        
        let maskFilter = CIFilter(name: "CIMaskToAlpha")
        maskFilter?.setValue(maskCI, forKey: "inputImage")
        let scaleFilter = CIFilter(name: "CILanczosScaleTransform")
        scaleFilter?.setValue(maskFilter?.outputImage, forKey: "inputImage")
        scaleFilter?.setValue(selfCI.extent.height / maskCI.extent.height, forKey: "inputScale")
        let filter: CIFilter! = CIFilter(name: "CIBlendWithAlphaMask")
        filter.setValue(selfCI, forKey: "inputBackgroundImage")
        let maskOutput = scaleFilter?.outputImage
        filter.setValue(maskOutput, forKey: "inputMaskImage")
        let outputImage = filter.outputImage!
        return outputImage
    }
}
  

Ответ №2:

Вам нужно создать свой собственный пользовательский фильтр. Учебные пособия:

Документы Apple

Документы Apple 2

Raywenderlich.com Учебное пособие

Это не тривиально, но это окупается, когда вы узнаете, как это сделать 🙂

Комментарии:

1. О черт. Действительно. Я пытался использовать clear ciimage в качестве входного изображения и использовать изображение для фильтрации в качестве фона, нулевых результатов. Возможно, моя маска неверна. Может быть, маска должна составлять один байт на пиксель, изображение в оттенках серого для маски?

2. Я упростил CIImage 🙂