Filter.swift 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. //
  2. // Filter.swift
  3. // Kingfisher
  4. //
  5. // Created by WANG WEI on 2016/08/31.
  6. // Copyright © 2016年 Wei Wang. All rights reserved.
  7. //
  8. import CoreImage
  9. import Accelerate
  10. // Reuse the same CI Context for all CI drawing.
  11. private let ciContext = CIContext(options: nil)
  12. public typealias Transformer = (CIImage) -> CIImage?
  13. public protocol CIImageProcessor: ImageProcessor {
  14. var filter: Filter { get }
  15. }
  16. public struct Filter {
  17. let transform: Transformer
  18. public static var tint: (Color) -> Filter = { color in
  19. Filter { input in
  20. let colorFilter = CIFilter(name: "CIConstantColorGenerator")!
  21. colorFilter.setValue(CIColor(color: color), forKey: kCIInputColorKey)
  22. let colorImage = colorFilter.outputImage
  23. let filter = CIFilter(name: "CISourceOverCompositing")!
  24. filter.setValue(colorImage, forKey: kCIInputImageKey)
  25. filter.setValue(input, forKey: kCIInputBackgroundImageKey)
  26. return filter.outputImage?.cropping(to: input.extent)
  27. }
  28. }
  29. public typealias ColorElement = (CGFloat, CGFloat, CGFloat, CGFloat)
  30. public static var colorControl: (ColorElement) -> Filter = {
  31. brightness, contrast, saturation, inputEV in
  32. Filter { input in
  33. let paramsColor = [kCIInputBrightnessKey: brightness,
  34. kCIInputContrastKey: contrast,
  35. kCIInputSaturationKey: saturation]
  36. let blackAndWhite = input.applyingFilter("CIColorControls", withInputParameters: paramsColor)
  37. let paramsExposure = [kCIInputEVKey: inputEV]
  38. return blackAndWhite.applyingFilter("CIExposureAdjust", withInputParameters: paramsExposure)
  39. }
  40. }
  41. }
  42. extension CIImageProcessor {
  43. public func process(item: ImageProcessItem, options: KingfisherOptionsInfo) -> Image? {
  44. switch item {
  45. case .image(let image):
  46. return image.kf_apply(filter)
  47. case .data(let data):
  48. return Image.kf_image(data: data, scale: options.scaleFactor, preloadAllGIFData: options.preloadAllGIFData)
  49. }
  50. }
  51. }
  52. extension Image {
  53. func kf_apply(_ filter: Filter) -> Image {
  54. guard let cgImage = cgImage else {
  55. assertionFailure("[Kingfisher] Tint image only works for CG-based image.")
  56. return self
  57. }
  58. let inputImage = CIImage(cgImage: cgImage)
  59. guard let outputImage = filter.transform(inputImage) else {
  60. return self
  61. }
  62. guard let result = ciContext.createCGImage(outputImage, from: outputImage.extent) else {
  63. assertionFailure("[Kingfisher] Can not make an tint image within context.")
  64. return self
  65. }
  66. #if os(macOS)
  67. return Image(cgImage: result, size: .zero)
  68. #else
  69. return Image(cgImage: result)
  70. #endif
  71. }
  72. }