Created
September 28, 2023 09:53
-
-
Save FezVrasta/d03e709e30c21d470889853b1157b48c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
import CoreImage | |
import UIKit | |
func convertCIImageToUIImage(ciImage: CIImage) -> UIImage { | |
let context = CIContext(options: nil) | |
let cgImage = context.createCGImage(ciImage, from: ciImage.extent) | |
let uiImage = UIImage(cgImage: cgImage!) | |
return uiImage | |
} | |
func convertUIImageToCIImage(uiImage: UIImage) -> CIImage { | |
guard let ciImage = uiImage.ciImage ?? CIImage(image: uiImage) else { | |
fatalError("Failed to convert UIImage to CIImage.") | |
} | |
return ciImage | |
} | |
func applyCustomCIFilter(uiImage: UIImage)-> UIImage? { | |
let origImage = convertUIImageToCIImage(uiImage: uiImage) | |
// custom filter to convert light gray to white and dark gray to black | |
let invertWithThresholdKernel = CIColorKernel(source: """ | |
kernel vec4 invertWithThreshold(__sample pixel, float threshold) { | |
// Determine the saturation by comparing the range of colors. | |
// If the most intense channel is very close to the least intense channel, | |
// then this color is close to gray. | |
float minColor = min(pixel.r, min(pixel.g, pixel.b)); | |
float maxColor = max(pixel.r, max(pixel.g, pixel.b)); | |
float saturation = maxColor == 0.0 ? 0.0 : (maxColor - minColor) / maxColor; | |
if (saturation < threshold) { | |
// Invert the color, setting alpha to 1 | |
// Handling transparency requires first unmultiplying the colors. Rather than mess with that, | |
// this code assumes that everything is opaque. | |
return vec4(1.0 - pow(pixel.r, 2.2), 1.0 - pow(pixel.g, 2.2), 1.0 - pow(pixel.b, 2.2), 1.0); | |
} else { | |
return pixel; | |
} | |
} | |
""") | |
guard let outImage = invertWithThresholdKernel?.apply(extent: (origImage.extent), arguments: [origImage as Any, 0.1 as Float])! else { return nil } | |
return convertCIImageToUIImage(ciImage: outImage); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I would be curious to know what's the correct way to use this in a widget since the CIColorKernel is deprecated but Metal shaders don't seem to be supported in widgets?