Ver código fonte

Refactor CI related filters

onevcat 9 anos atrás
pai
commit
dd58eacb07
3 arquivos alterados com 103 adições e 58 exclusões
  1. 8 0
      Kingfisher.xcodeproj/project.pbxproj
  2. 91 0
      Sources/Filter.swift
  3. 4 58
      Sources/Image.swift

+ 8 - 0
Kingfisher.xcodeproj/project.pbxproj

@@ -19,6 +19,9 @@
 		4B3766841C478F940001443F /* Kingfisher.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D13F49D61BEDA67C00CE335D /* Kingfisher.framework */; };
 		4B3766841C478F940001443F /* Kingfisher.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D13F49D61BEDA67C00CE335D /* Kingfisher.framework */; };
 		4B3766A01C4794460001443F /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B37669F1C4794460001443F /* CFNetwork.framework */; };
 		4B3766A01C4794460001443F /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B37669F1C4794460001443F /* CFNetwork.framework */; };
 		4B3766A21C47944D0001443F /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B3766A11C47944D0001443F /* CFNetwork.framework */; };
 		4B3766A21C47944D0001443F /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B3766A11C47944D0001443F /* CFNetwork.framework */; };
+		4B6313F41D766BEF0078E017 /* Filter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B6313F31D766BEF0078E017 /* Filter.swift */; };
+		4B6313F51D766BEF0078E017 /* Filter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B6313F31D766BEF0078E017 /* Filter.swift */; };
+		4B6313F61D766BEF0078E017 /* Filter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B6313F31D766BEF0078E017 /* Filter.swift */; };
 		4B98674F1CD1CF42003ADAC7 /* AnimatedImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B98674E1CD1CF42003ADAC7 /* AnimatedImageView.swift */; };
 		4B98674F1CD1CF42003ADAC7 /* AnimatedImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B98674E1CD1CF42003ADAC7 /* AnimatedImageView.swift */; };
 		4B9867501CD1CF42003ADAC7 /* AnimatedImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B98674E1CD1CF42003ADAC7 /* AnimatedImageView.swift */; };
 		4B9867501CD1CF42003ADAC7 /* AnimatedImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B98674E1CD1CF42003ADAC7 /* AnimatedImageView.swift */; };
 		4BCCF33D1D5B02F8003387C2 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BCCF3361D5B02F8003387C2 /* AppDelegate.swift */; };
 		4BCCF33D1D5B02F8003387C2 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BCCF3361D5B02F8003387C2 /* AppDelegate.swift */; };
@@ -463,6 +466,7 @@
 		4B37669F1C4794460001443F /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS9.1.sdk/System/Library/Frameworks/CFNetwork.framework; sourceTree = DEVELOPER_DIR; };
 		4B37669F1C4794460001443F /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS9.1.sdk/System/Library/Frameworks/CFNetwork.framework; sourceTree = DEVELOPER_DIR; };
 		4B3766A11C47944D0001443F /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/System/Library/Frameworks/CFNetwork.framework; sourceTree = DEVELOPER_DIR; };
 		4B3766A11C47944D0001443F /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/System/Library/Frameworks/CFNetwork.framework; sourceTree = DEVELOPER_DIR; };
 		4B3E714D1B01FEB200F5AAED /* WatchKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WatchKit.framework; path = System/Library/Frameworks/WatchKit.framework; sourceTree = SDKROOT; };
 		4B3E714D1B01FEB200F5AAED /* WatchKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WatchKit.framework; path = System/Library/Frameworks/WatchKit.framework; sourceTree = SDKROOT; };
+		4B6313F31D766BEF0078E017 /* Filter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Filter.swift; path = Sources/Filter.swift; sourceTree = "<group>"; };
 		4B98674E1CD1CF42003ADAC7 /* AnimatedImageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AnimatedImageView.swift; path = Sources/AnimatedImageView.swift; sourceTree = "<group>"; };
 		4B98674E1CD1CF42003ADAC7 /* AnimatedImageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AnimatedImageView.swift; path = Sources/AnimatedImageView.swift; sourceTree = "<group>"; };
 		4BCCF3361D5B02F8003387C2 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
 		4BCCF3361D5B02F8003387C2 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
 		4BCCF3371D5B02F8003387C2 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
 		4BCCF3371D5B02F8003387C2 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
@@ -889,6 +893,7 @@
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
 				4B2B8E491D70128200FC4749 /* ImageProcessor.swift */,
 				4B2B8E491D70128200FC4749 /* ImageProcessor.swift */,
+				4B6313F31D766BEF0078E017 /* Filter.swift */,
 				4B98674E1CD1CF42003ADAC7 /* AnimatedImageView.swift */,
 				4B98674E1CD1CF42003ADAC7 /* AnimatedImageView.swift */,
 				D10945EA1C526B6C001408EB /* Image.swift */,
 				D10945EA1C526B6C001408EB /* Image.swift */,
 				D10945EB1C526B6C001408EB /* ImageCache.swift */,
 				D10945EB1C526B6C001408EB /* ImageCache.swift */,
@@ -1994,6 +1999,7 @@
 				4B2B8E4C1D70141000FC4749 /* ImageProcessor.swift in Sources */,
 				4B2B8E4C1D70141000FC4749 /* ImageProcessor.swift in Sources */,
 				D109461E1C526C61001408EB /* ImageView+Kingfisher.swift in Sources */,
 				D109461E1C526C61001408EB /* ImageView+Kingfisher.swift in Sources */,
 				D109461F1C526C61001408EB /* KingfisherManager.swift in Sources */,
 				D109461F1C526C61001408EB /* KingfisherManager.swift in Sources */,
+				4B6313F61D766BEF0078E017 /* Filter.swift in Sources */,
 				182FFF781CC9ACBA004B728D /* NSButton+Kingfisher.swift in Sources */,
 				182FFF781CC9ACBA004B728D /* NSButton+Kingfisher.swift in Sources */,
 				D10946201C526C61001408EB /* KingfisherOptionsInfo.swift in Sources */,
 				D10946201C526C61001408EB /* KingfisherOptionsInfo.swift in Sources */,
 				D10946211C526C61001408EB /* Resource.swift in Sources */,
 				D10946211C526C61001408EB /* Resource.swift in Sources */,
@@ -2063,6 +2069,7 @@
 			buildActionMask = 2147483647;
 			buildActionMask = 2147483647;
 			files = (
 			files = (
 				D109460E1C526C0D001408EB /* Image.swift in Sources */,
 				D109460E1C526C0D001408EB /* Image.swift in Sources */,
+				4B6313F51D766BEF0078E017 /* Filter.swift in Sources */,
 				4B9867501CD1CF42003ADAC7 /* AnimatedImageView.swift in Sources */,
 				4B9867501CD1CF42003ADAC7 /* AnimatedImageView.swift in Sources */,
 				D109460F1C526C0D001408EB /* ImageCache.swift in Sources */,
 				D109460F1C526C0D001408EB /* ImageCache.swift in Sources */,
 				D10946101C526C0D001408EB /* ImageDownloader.swift in Sources */,
 				D10946101C526C0D001408EB /* ImageDownloader.swift in Sources */,
@@ -2121,6 +2128,7 @@
 			buildActionMask = 2147483647;
 			buildActionMask = 2147483647;
 			files = (
 			files = (
 				D10945F71C526B86001408EB /* Image.swift in Sources */,
 				D10945F71C526B86001408EB /* Image.swift in Sources */,
+				4B6313F41D766BEF0078E017 /* Filter.swift in Sources */,
 				4B98674F1CD1CF42003ADAC7 /* AnimatedImageView.swift in Sources */,
 				4B98674F1CD1CF42003ADAC7 /* AnimatedImageView.swift in Sources */,
 				D10945F81C526B86001408EB /* ImageCache.swift in Sources */,
 				D10945F81C526B86001408EB /* ImageCache.swift in Sources */,
 				D10945F91C526B86001408EB /* ImageDownloader.swift in Sources */,
 				D10945F91C526B86001408EB /* ImageDownloader.swift in Sources */,

+ 91 - 0
Sources/Filter.swift

@@ -0,0 +1,91 @@
+//
+//  Filter.swift
+//  Kingfisher
+//
+//  Created by WANG WEI on 2016/08/31.
+//  Copyright © 2016年 Wei Wang. All rights reserved.
+//
+
+import CoreImage
+import Accelerate
+
+// Reuse the same CI Context for all CI drawing.
+private let ciContext = CIContext(options: nil)
+
+public typealias Transformer = (CIImage) -> CIImage?
+public protocol CIImageProcessor: ImageProcessor {
+    var filter: Filter { get }
+}
+
+public struct Filter {
+    
+    let transform: Transformer
+    
+    public static var tint: (Color) -> Filter = { color in
+        
+        Filter { input in
+            let colorFilter = CIFilter(name: "CIConstantColorGenerator")!
+            colorFilter.setValue(CIColor(color: color), forKey: kCIInputColorKey)
+            
+            let colorImage = colorFilter.outputImage
+            let filter = CIFilter(name: "CISourceOverCompositing")!
+            filter.setValue(colorImage, forKey: kCIInputImageKey)
+            filter.setValue(input, forKey: kCIInputBackgroundImageKey)
+            return filter.outputImage?.cropping(to: input.extent)
+        }
+    }
+    
+    public typealias ColorElement = (CGFloat, CGFloat, CGFloat, CGFloat)
+    public static var colorControl: (ColorElement) -> Filter = {
+        brightness, contrast, saturation, inputEV in
+        Filter { input in
+            let paramsColor = [kCIInputBrightnessKey: brightness,
+                               kCIInputContrastKey: contrast,
+                               kCIInputSaturationKey: saturation]
+            
+            let blackAndWhite = input.applyingFilter("CIColorControls", withInputParameters: paramsColor)
+            let paramsExposure = [kCIInputEVKey: inputEV]
+            return blackAndWhite.applyingFilter("CIExposureAdjust", withInputParameters: paramsExposure)
+        }
+        
+    }
+}
+
+
+
+extension CIImageProcessor {
+    public func process(item: ImageProcessItem, options: KingfisherOptionsInfo) -> Image? {
+        switch item {
+        case .image(let image):
+            return image.kf_apply(filter)
+        case .data(let data):
+            return Image.kf_image(data: data, scale: options.scaleFactor, preloadAllGIFData: options.preloadAllGIFData)
+        }
+    }
+}
+
+extension Image {
+    func kf_apply(_ filter: Filter) -> Image {
+        
+        guard let cgImage = cgImage else {
+            assertionFailure("[Kingfisher] Tint image only works for CG-based image.")
+            return self
+        }
+        
+        let inputImage = CIImage(cgImage: cgImage)
+        guard let outputImage = filter.transform(inputImage) else {
+            return self
+        }
+        
+        guard let result = ciContext.createCGImage(outputImage, from: outputImage.extent) else {
+            assertionFailure("[Kingfisher] Can not make an tint image within context.")
+            return self
+        }
+        
+        #if os(macOS)
+            return Image(cgImage: result, size: .zero)
+        #else
+            return Image(cgImage: result)
+        #endif
+    }
+}

+ 4 - 58
Sources/Image.swift

@@ -45,11 +45,9 @@ private var animatedImageDataKey: Void?
 import ImageIO
 import ImageIO
 import CoreGraphics
 import CoreGraphics
 
 
-#if os(iOS) || os(macOS) || os(tvOS)
+#if !os(watchOS)
 import Accelerate
 import Accelerate
 import CoreImage
 import CoreImage
-    
-private let ciContext = CIContext(options: nil)
 #endif
 #endif
 
 
 // MARK: - Image Properties
 // MARK: - Image Properties
@@ -563,38 +561,9 @@ extension Image {
     // MARK: - Tint
     // MARK: - Tint
     func kf_tinted(with color: Color) -> Image {
     func kf_tinted(with color: Color) -> Image {
         #if os(watchOS)
         #if os(watchOS)
-            return self
-        #else
-        guard let cgImage = cgImage else {
-            assertionFailure("[Kingfisher] Tint image only works for CG-based image.")
-            return self
-        }
-    
-        let colorFilter = CIFilter(name: "CIConstantColorGenerator")!
-        colorFilter.setValue(CIColor(color: color), forKey: kCIInputColorKey)
-        
-        let colorImage = colorFilter.outputImage
-            
-        let input = CIImage(cgImage: cgImage)
-        let filter = CIFilter(name: "CISourceOverCompositing")!
-        filter.setValue(colorImage, forKey: kCIInputImageKey)
-        filter.setValue(input, forKey: kCIInputBackgroundImageKey)
-        
-        guard let output = filter.outputImage?.cropping(to: input.extent) else {
-            assertionFailure("[Kingfisher] Tint filter failed to create output image.")
-            return self
-        }
-            
-        guard let result = ciContext.createCGImage(output, from: output.extent) else {
-            assertionFailure("[Kingfisher] Can not make an tint image within context.")
-            return self
-        }
-            
-        #if os(macOS)
-            return Image(cgImage: result, size: .zero)
+        return self
         #else
         #else
-            return Image(cgImage: result)
-        #endif
+        return kf_apply(.tint(color))
         #endif
         #endif
     }
     }
     
     
@@ -603,30 +572,7 @@ extension Image {
         #if os(watchOS)
         #if os(watchOS)
         return self
         return self
         #else
         #else
-        guard let cgImage = cgImage else {
-            assertionFailure("[Kingfisher] B&W only works for CG-based image.")
-            return self
-        }
-        let input = CIImage(cgImage: cgImage)
-        
-        let paramsColor = [kCIInputBrightnessKey: brightness,
-                             kCIInputContrastKey: contrast,
-                           kCIInputSaturationKey: saturation]
-            
-        let blackAndWhite = input.applyingFilter("CIColorControls", withInputParameters: paramsColor)
-        let paramsExposure = [kCIInputEVKey: inputEV]
-        let output = blackAndWhite.applyingFilter("CIExposureAdjust", withInputParameters: paramsExposure)
-        
-        guard let result = ciContext.createCGImage(output, from: output.extent) else {
-            assertionFailure("Can not make an B&W image within context.")
-            return self
-        }
-            
-        #if os(macOS)
-        return Image(cgImage: result, size: .zero)
-        #else
-        return Image(cgImage: result)
-        #endif
+        return kf_apply(.colorControl(brightness, contrast, saturation, inputEV))
         #endif
         #endif
     }
     }
 }
 }