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 = {
  19. color in
  20. Filter { input in
  21. let colorFilter = CIFilter(name: "CIConstantColorGenerator")!
  22. colorFilter.setValue(CIColor(color: color), forKey: kCIInputColorKey)
  23. let colorImage = colorFilter.outputImage
  24. let filter = CIFilter(name: "CISourceOverCompositing")!
  25. filter.setValue(colorImage, forKey: kCIInputImageKey)
  26. filter.setValue(input, forKey: kCIInputBackgroundImageKey)
  27. return filter.outputImage?.cropping(to: input.extent)
  28. }
  29. }
  30. public typealias ColorElement = (CGFloat, CGFloat, CGFloat, CGFloat)
  31. public static var colorControl: (ColorElement) -> Filter = {
  32. brightness, contrast, saturation, inputEV in
  33. Filter { input in
  34. let paramsColor = [kCIInputBrightnessKey: brightness,
  35. kCIInputContrastKey: contrast,
  36. kCIInputSaturationKey: saturation]
  37. let blackAndWhite = input.applyingFilter("CIColorControls", withInputParameters: paramsColor)
  38. let paramsExposure = [kCIInputEVKey: inputEV]
  39. return blackAndWhite.applyingFilter("CIExposureAdjust", withInputParameters: paramsExposure)
  40. }
  41. }
  42. }
  43. extension CIImageProcessor {
  44. public func process(item: ImageProcessItem, options: KingfisherOptionsInfo) -> Image? {
  45. switch item {
  46. case .image(let image):
  47. return image.kf_apply(filter)
  48. case .data(let data):
  49. return Image.kf_image(data: data, scale: options.scaleFactor, preloadAllGIFData: options.preloadAllGIFData)
  50. }
  51. }
  52. }
  53. extension Image {
  54. func kf_apply(_ filter: Filter) -> Image {
  55. guard let cgImage = cgImage else {
  56. assertionFailure("[Kingfisher] Tint image only works for CG-based image.")
  57. return self
  58. }
  59. let inputImage = CIImage(cgImage: cgImage)
  60. guard let outputImage = filter.transform(inputImage) else {
  61. return self
  62. }
  63. guard let result = ciContext.createCGImage(outputImage, from: outputImage.extent) else {
  64. assertionFailure("[Kingfisher] Can not make an tint image within context.")
  65. return self
  66. }
  67. #if os(macOS)
  68. return Image(cgImage: result, size: .zero)
  69. #else
  70. return Image(cgImage: result)
  71. #endif
  72. }
  73. }