ImageProcessor.swift 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. //
  2. // ImageProcessor.swift
  3. // Kingfisher
  4. //
  5. // Created by WANG WEI on 2016/08/26.
  6. //
  7. // Copyright (c) 2016 Wei Wang <onevcat@gmail.com>
  8. //
  9. // Permission is hereby granted, free of charge, to any person obtaining a copy
  10. // of this software and associated documentation files (the "Software"), to deal
  11. // in the Software without restriction, including without limitation the rights
  12. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. // copies of the Software, and to permit persons to whom the Software is
  14. // furnished to do so, subject to the following conditions:
  15. //
  16. // The above copyright notice and this permission notice shall be included in
  17. // all copies or substantial portions of the Software.
  18. //
  19. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. // THE SOFTWARE.
  26. import Foundation
  27. import CoreGraphics
  28. public enum ImageProcessItem {
  29. case image(Image)
  30. case data(Data)
  31. }
  32. public protocol ImageProcessor {
  33. func process(item: ImageProcessItem, options: KingfisherOptionsInfo) -> Image?
  34. }
  35. typealias ProcessorImp = ((ImageProcessItem, KingfisherOptionsInfo) -> Image?)
  36. public extension ImageProcessor {
  37. func append(another: ImageProcessor) -> ImageProcessor {
  38. return GeneralProcessor { item, options in
  39. if let image = self.process(item: item, options: options) {
  40. return another.process(item: .image(image), options: options)
  41. } else {
  42. return nil
  43. }
  44. }
  45. }
  46. }
  47. fileprivate struct GeneralProcessor: ImageProcessor {
  48. let p: ProcessorImp
  49. func process(item: ImageProcessItem, options: KingfisherOptionsInfo) -> Image? {
  50. return p(item, options)
  51. }
  52. }
  53. public struct DefaultProcessor: ImageProcessor {
  54. public init() {}
  55. public func process(item: ImageProcessItem, options: KingfisherOptionsInfo) -> Image? {
  56. switch item {
  57. case .image(let image):
  58. return image
  59. case .data(let data):
  60. return Image.kf_image(data: data, scale: options.scaleFactor, preloadAllGIFData: options.preloadAllGIFData)
  61. }
  62. }
  63. }
  64. public struct RoundCornerImageProcessor: ImageProcessor {
  65. public let cornerRadius: CGFloat
  66. public let targetSize: CGSize?
  67. public init(cornerRadius: CGFloat, targetSize: CGSize? = nil) {
  68. self.cornerRadius = cornerRadius
  69. self.targetSize = targetSize
  70. }
  71. public func process(item: ImageProcessItem, options: KingfisherOptionsInfo) -> Image? {
  72. switch item {
  73. case .image(let image):
  74. let size = targetSize ?? image.kf_size
  75. return image.kf_image(withRoundRadius: cornerRadius, fit: size, scale: options.scaleFactor)
  76. case .data(_):
  77. return (DefaultProcessor() |> self).process(item: item, options: options)
  78. }
  79. }
  80. }
  81. public struct ResizingImageProcessor: ImageProcessor {
  82. public let targetSize: CGSize
  83. public init(targetSize: CGSize) {
  84. self.targetSize = targetSize
  85. }
  86. public func process(item: ImageProcessItem, options: KingfisherOptionsInfo) -> Image? {
  87. switch item {
  88. case .image(let image):
  89. return image.kf_resize(to: targetSize)
  90. case .data(_):
  91. return (DefaultProcessor() |> self).process(item: item, options: options)
  92. }
  93. }
  94. }
  95. public struct BlurImageProcessor: ImageProcessor {
  96. public let blurRadius: CGFloat
  97. public init(blurRadius: CGFloat) {
  98. self.blurRadius = blurRadius
  99. }
  100. public func process(item: ImageProcessItem, options: KingfisherOptionsInfo) -> Image? {
  101. switch item {
  102. case .image(let image):
  103. let radius = blurRadius * options.scaleFactor
  104. return image.kf_blurred(withRadius: radius)
  105. case .data(_):
  106. return (DefaultProcessor() |> self).process(item: item, options: options)
  107. }
  108. }
  109. }
  110. public struct OverlayImageProcessor: ImageProcessor {
  111. public let overlay: Color
  112. public let fraction: CGFloat
  113. public init(overlay: Color, fraction: CGFloat = 0.5) {
  114. self.overlay = overlay
  115. self.fraction = fraction
  116. }
  117. public func process(item: ImageProcessItem, options: KingfisherOptionsInfo) -> Image? {
  118. switch item {
  119. case .image(let image):
  120. return image.kf_overlaying(with: overlay, fraction: fraction)
  121. case .data(_):
  122. return (DefaultProcessor() |> self).process(item: item, options: options)
  123. }
  124. }
  125. }
  126. public struct TintImageProcessor: ImageProcessor {
  127. public let tint: Color
  128. public init(tint: Color) {
  129. self.tint = tint
  130. }
  131. public func process(item: ImageProcessItem, options: KingfisherOptionsInfo) -> Image? {
  132. switch item {
  133. case .image(let image):
  134. return image.kf_tinted(with: tint)
  135. case .data(_):
  136. return (DefaultProcessor() |> self).process(item: item, options: options)
  137. }
  138. }
  139. }
  140. public struct ColorControlsProcessor: ImageProcessor {
  141. public let brightness: CGFloat
  142. public let contrast: CGFloat
  143. public let saturation: CGFloat
  144. public let inputEV: CGFloat
  145. public init(brightness: CGFloat, contrast: CGFloat, saturation: CGFloat, inputEV: CGFloat) {
  146. self.brightness = brightness
  147. self.contrast = contrast
  148. self.saturation = saturation
  149. self.inputEV = inputEV
  150. }
  151. public func process(item: ImageProcessItem, options: KingfisherOptionsInfo) -> Image? {
  152. switch item {
  153. case .image(let image):
  154. return image.kf_adjusted(brightness: brightness, contrast: contrast, saturation: saturation, inputEV: inputEV)
  155. case .data(_):
  156. return (DefaultProcessor() |> self).process(item: item, options: options)
  157. }
  158. }
  159. }
  160. public struct BlackWhiteProcessor: ImageProcessor {
  161. public init() {}
  162. public func process(item: ImageProcessItem, options: KingfisherOptionsInfo) -> Image? {
  163. return ColorControlsProcessor(brightness: 0.0, contrast: 1.0, saturation: 0.0, inputEV: 0.7)
  164. .process(item: item, options: options)
  165. }
  166. }
  167. infix operator |>: AdditionPrecedence
  168. public func |>(left: ImageProcessor, right: ImageProcessor) -> ImageProcessor {
  169. return left.append(another: right)
  170. }