Bläddra i källkod

new image processors: blend, compositing

yemodin 8 år sedan
förälder
incheckning
fc51328205

+ 48 - 2
Kingfisher.xcodeproj/project.pbxproj

@@ -190,6 +190,15 @@
 		4BFBEE7F1D7D0C3600699FD3 /* RequestModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BFBEE7C1D7D0C3600699FD3 /* RequestModifier.swift */; };
 		4BFBEE801D7D0C3600699FD3 /* RequestModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BFBEE7C1D7D0C3600699FD3 /* RequestModifier.swift */; };
 		B8BBB7092D89EAC97D6ED888 /* libPods-KingfisherTests-macOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0268A213AE27BC6133BC5E0F /* libPods-KingfisherTests-macOS.a */; };
+		CCA25D271FD4713D00FA5C6E /* kingfisher-blend-4.jpg in Resources */ = {isa = PBXBuildFile; fileRef = CCA25D241FD4713D00FA5C6E /* kingfisher-blend-4.jpg */; };
+		CCA25D281FD4713D00FA5C6E /* kingfisher-blend-4.jpg in Resources */ = {isa = PBXBuildFile; fileRef = CCA25D241FD4713D00FA5C6E /* kingfisher-blend-4.jpg */; };
+		CCA25D2A1FD4713D00FA5C6E /* onevcat-blend-4.jpg in Resources */ = {isa = PBXBuildFile; fileRef = CCA25D251FD4713D00FA5C6E /* onevcat-blend-4.jpg */; };
+		CCA25D2B1FD4713D00FA5C6E /* onevcat-blend-4.jpg in Resources */ = {isa = PBXBuildFile; fileRef = CCA25D251FD4713D00FA5C6E /* onevcat-blend-4.jpg */; };
+		CCA25D2D1FD4713D00FA5C6E /* unicorn-blend-4.png in Resources */ = {isa = PBXBuildFile; fileRef = CCA25D261FD4713D00FA5C6E /* unicorn-blend-4.png */; };
+		CCA25D2E1FD4713D00FA5C6E /* unicorn-blend-4.png in Resources */ = {isa = PBXBuildFile; fileRef = CCA25D261FD4713D00FA5C6E /* unicorn-blend-4.png */; };
+		CCA25D3A1FD49A3100FA5C6E /* kingfisher-compositing-17-mac.jpg in Resources */ = {isa = PBXBuildFile; fileRef = CCA25D371FD49A3100FA5C6E /* kingfisher-compositing-17-mac.jpg */; };
+		CCA25D3B1FD49A3100FA5C6E /* onevcat-compositing-17-mac.jpg in Resources */ = {isa = PBXBuildFile; fileRef = CCA25D381FD49A3100FA5C6E /* onevcat-compositing-17-mac.jpg */; };
+		CCA25D3C1FD49A3100FA5C6E /* unicorn-compositing-17-mac.png in Resources */ = {isa = PBXBuildFile; fileRef = CCA25D391FD49A3100FA5C6E /* unicorn-compositing-17-mac.png */; };
 		D10945F71C526B86001408EB /* Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = D10945EA1C526B6C001408EB /* Image.swift */; };
 		D10945F81C526B86001408EB /* ImageCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D10945EB1C526B6C001408EB /* ImageCache.swift */; };
 		D10945F91C526B86001408EB /* ImageDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = D10945EC1C526B6C001408EB /* ImageDownloader.swift */; };
@@ -583,6 +592,12 @@
 		6CD5C0134AA4B1C0892E7319 /* Pods-KingfisherTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-KingfisherTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-KingfisherTests/Pods-KingfisherTests.release.xcconfig"; sourceTree = "<group>"; };
 		7204D40BEFEA059FA25864C4 /* Pods-KingfisherTests-macOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-KingfisherTests-macOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-KingfisherTests-macOS/Pods-KingfisherTests-macOS.debug.xcconfig"; sourceTree = "<group>"; };
 		9D0E767B01589AA8BE21FFA6 /* libPods-KingfisherTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-KingfisherTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
+		CCA25D241FD4713D00FA5C6E /* kingfisher-blend-4.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "kingfisher-blend-4.jpg"; sourceTree = "<group>"; };
+		CCA25D251FD4713D00FA5C6E /* onevcat-blend-4.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "onevcat-blend-4.jpg"; sourceTree = "<group>"; };
+		CCA25D261FD4713D00FA5C6E /* unicorn-blend-4.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "unicorn-blend-4.png"; sourceTree = "<group>"; };
+		CCA25D371FD49A3100FA5C6E /* kingfisher-compositing-17-mac.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "kingfisher-compositing-17-mac.jpg"; sourceTree = "<group>"; };
+		CCA25D381FD49A3100FA5C6E /* onevcat-compositing-17-mac.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "onevcat-compositing-17-mac.jpg"; sourceTree = "<group>"; };
+		CCA25D391FD49A3100FA5C6E /* unicorn-compositing-17-mac.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "unicorn-compositing-17-mac.png"; sourceTree = "<group>"; };
 		D10945EA1C526B6C001408EB /* Image.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Image.swift; path = Sources/Image.swift; sourceTree = "<group>"; };
 		D10945EB1C526B6C001408EB /* ImageCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ImageCache.swift; path = Sources/ImageCache.swift; sourceTree = "<group>"; };
 		D10945EC1C526B6C001408EB /* ImageDownloader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ImageDownloader.swift; path = Sources/ImageDownloader.swift; sourceTree = "<group>"; };
@@ -785,6 +800,8 @@
 		4BB83E071E32075800B64183 /* Modified */ = {
 			isa = PBXGroup;
 			children = (
+				CCA25D361FD49A3100FA5C6E /* Compositing */,
+				CCA25D231FD4713D00FA5C6E /* Blend */,
 				4BB83E081E32075800B64183 /* B&W */,
 				4BB83E0F1E32075800B64183 /* Blur */,
 				4BB83E161E32075800B64183 /* ColorControl */,
@@ -1052,6 +1069,26 @@
 			name = Pods;
 			sourceTree = "<group>";
 		};
+		CCA25D231FD4713D00FA5C6E /* Blend */ = {
+			isa = PBXGroup;
+			children = (
+				CCA25D241FD4713D00FA5C6E /* kingfisher-blend-4.jpg */,
+				CCA25D251FD4713D00FA5C6E /* onevcat-blend-4.jpg */,
+				CCA25D261FD4713D00FA5C6E /* unicorn-blend-4.png */,
+			);
+			path = Blend;
+			sourceTree = "<group>";
+		};
+		CCA25D361FD49A3100FA5C6E /* Compositing */ = {
+			isa = PBXGroup;
+			children = (
+				CCA25D371FD49A3100FA5C6E /* kingfisher-compositing-17-mac.jpg */,
+				CCA25D381FD49A3100FA5C6E /* onevcat-compositing-17-mac.jpg */,
+				CCA25D391FD49A3100FA5C6E /* unicorn-compositing-17-mac.png */,
+			);
+			path = Compositing;
+			sourceTree = "<group>";
+		};
 		D10EC22A1C3D62D200A4211C /* Sources */ = {
 			isa = PBXGroup;
 			children = (
@@ -1633,6 +1670,7 @@
 				D141464D1E5C7E86001476DF /* onevcat-resize-240-60-aspectFit.jpg in Resources */,
 				4BEC7CC61EE8FAD800759A9E /* onevcat-round-corner-40-iOS11.jpg in Resources */,
 				4BB83EF11E32075800B64183 /* unicorn-round-corner-60-resize-100.png in Resources */,
+				CCA25D281FD4713D00FA5C6E /* kingfisher-blend-4.jpg in Resources */,
 				4BB83E971E32075800B64183 /* unicorn-blur-4-round-corner-60.png in Resources */,
 				4BB83E551E32075800B64183 /* kingfisher-b&w.jpg in Resources */,
 				4BB83EF71E32075800B64183 /* kingfisher-tint-yellow-02.jpg in Resources */,
@@ -1642,6 +1680,7 @@
 				4BB83E7F1E32075800B64183 /* onevcat-color-control-b00-c11-s12-ev07.jpg in Resources */,
 				4BB83E911E32075800B64183 /* onevcat-blur-4-round-corner-60.jpg in Resources */,
 				4BB83E611E32075800B64183 /* unicorn-b&w.png in Resources */,
+				CCA25D2B1FD4713D00FA5C6E /* onevcat-blend-4.jpg in Resources */,
 				4BB83E6D1E32075800B64183 /* onevcat-blur-10.jpg in Resources */,
 				4BB83E671E32075800B64183 /* kingfisher-blur-10.jpg in Resources */,
 				4BA697561EC2F06000AA7935 /* unicorn-round-corner-40-corner-3.png in Resources */,
@@ -1660,6 +1699,7 @@
 				4BB83EE51E32075800B64183 /* onevcat-round-corner-60-resize-100.jpg in Resources */,
 				4BB83EA31E32075800B64183 /* kingfisher-overlay-red.jpg in Resources */,
 				4BA697501EC2F06000AA7935 /* onevcat-round-corner-40-corner-3.jpg in Resources */,
+				CCA25D2E1FD4713D00FA5C6E /* unicorn-blend-4.png in Resources */,
 				4BB83E5B1E32075800B64183 /* onevcat-b&w.jpg in Resources */,
 				4BB83E731E32075800B64183 /* unicorn-blur-10.png in Resources */,
 				4BB83F061E32075800B64183 /* kingfisher.jpg in Resources */,
@@ -1684,6 +1724,7 @@
 			buildActionMask = 2147483647;
 			files = (
 				4BB83EA71E32075800B64183 /* onevcat-overlay-red-07-mac.jpg in Resources */,
+				CCA25D3B1FD49A3100FA5C6E /* onevcat-compositing-17-mac.jpg in Resources */,
 				D1C0B17B1F9B965A00422960 /* unicorn-overlay-red-07-mac-macOS1013.png in Resources */,
 				4BB83EE91E32075800B64183 /* unicorn-round-corner-40-mac.png in Resources */,
 				4BB83E831E32075800B64183 /* unicorn-color-control-b00-c11-s12-ev07-mac.png in Resources */,
@@ -1691,6 +1732,7 @@
 				D1C0B1811F9B997C00422960 /* kingfisher-tint-yellow-02-mac-macOS1013.jpg in Resources */,
 				4BA6976C1EC2F12000AA7935 /* unicorn-round-corner-40-corner-12-mac.png in Resources */,
 				D1D2C32C1C70A3230018F2F9 /* single-frame.gif in Resources */,
+				CCA25D3C1FD49A3100FA5C6E /* unicorn-compositing-17-mac.png in Resources */,
 				4BA697601EC2F12000AA7935 /* kingfisher-round-corner-40-corner-12-mac.jpg in Resources */,
 				4BA697661EC2F12000AA7935 /* onevcat-round-corner-40-corner-12-mac.jpg in Resources */,
 				D14146391E5C7E86001476DF /* kingfisher-resize-240-60-aspectFill-mac.jpg in Resources */,
@@ -1701,6 +1743,7 @@
 				D12E0C8A1C47F7C000AC98AD /* dancing-banana.gif in Resources */,
 				D14146571E5C7E86001476DF /* unicorn-resize-240-60-aspectFit-mac.png in Resources */,
 				4BB83E6B1E32075800B64183 /* onevcat-blur-10-mac.jpg in Resources */,
+				CCA25D3A1FD49A3100FA5C6E /* kingfisher-compositing-17-mac.jpg in Resources */,
 				4BB83E531E32075800B64183 /* kingfisher-b&w-mac.jpg in Resources */,
 				D14146511E5C7E86001476DF /* unicorn-resize-240-60-aspectFill-mac.png in Resources */,
 				4BB83E891E32075800B64183 /* kingfisher-blur-4-round-corner-60-mac.jpg in Resources */,
@@ -1822,6 +1865,7 @@
 				D141464C1E5C7E86001476DF /* onevcat-resize-240-60-aspectFit.jpg in Resources */,
 				4BEC7CBE1EE8FAD700759A9E /* onevcat-round-corner-40-iOS11.jpg in Resources */,
 				4BB83EF01E32075800B64183 /* unicorn-round-corner-60-resize-100.png in Resources */,
+				CCA25D271FD4713D00FA5C6E /* kingfisher-blend-4.jpg in Resources */,
 				4BB83E961E32075800B64183 /* unicorn-blur-4-round-corner-60.png in Resources */,
 				4BB83E541E32075800B64183 /* kingfisher-b&w.jpg in Resources */,
 				4BB83EF61E32075800B64183 /* kingfisher-tint-yellow-02.jpg in Resources */,
@@ -1831,6 +1875,7 @@
 				4BB83E7E1E32075800B64183 /* onevcat-color-control-b00-c11-s12-ev07.jpg in Resources */,
 				4BB83E901E32075800B64183 /* onevcat-blur-4-round-corner-60.jpg in Resources */,
 				4BB83E601E32075800B64183 /* unicorn-b&w.png in Resources */,
+				CCA25D2A1FD4713D00FA5C6E /* onevcat-blend-4.jpg in Resources */,
 				4BB83E6C1E32075800B64183 /* onevcat-blur-10.jpg in Resources */,
 				4BB83E661E32075800B64183 /* kingfisher-blur-10.jpg in Resources */,
 				4BA697551EC2F06000AA7935 /* unicorn-round-corner-40-corner-3.png in Resources */,
@@ -1849,6 +1894,7 @@
 				4BB83EE41E32075800B64183 /* onevcat-round-corner-60-resize-100.jpg in Resources */,
 				4BB83EA21E32075800B64183 /* kingfisher-overlay-red.jpg in Resources */,
 				4BA6974F1EC2F06000AA7935 /* onevcat-round-corner-40-corner-3.jpg in Resources */,
+				CCA25D2D1FD4713D00FA5C6E /* unicorn-blend-4.png in Resources */,
 				4BB83E5A1E32075800B64183 /* onevcat-b&w.jpg in Resources */,
 				4BB83E721E32075800B64183 /* unicorn-blur-10.png in Resources */,
 				4BB83F051E32075800B64183 /* kingfisher.jpg in Resources */,
@@ -2522,7 +2568,7 @@
 				INFOPLIST_FILE = "Demo/Kingfisher-macOS-Demo/Info.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
-				MACOSX_DEPLOYMENT_TARGET = 10.10;
+				MACOSX_DEPLOYMENT_TARGET = 10.11;
 				PRODUCT_BUNDLE_IDENTIFIER = "com.onevcat.Kingfisher-OSX-Demo";
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SDKROOT = macosx;
@@ -2542,7 +2588,7 @@
 				INFOPLIST_FILE = "Demo/Kingfisher-macOS-Demo/Info.plist";
 				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
-				MACOSX_DEPLOYMENT_TARGET = 10.10;
+				MACOSX_DEPLOYMENT_TARGET = 10.11;
 				PRODUCT_BUNDLE_IDENTIFIER = "com.onevcat.Kingfisher-OSX-Demo";
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SDKROOT = macosx;

+ 63 - 0
Sources/Image.swift

@@ -336,6 +336,69 @@ extension Kingfisher where Base: Image {
 
 // MARK: - Image Transforming
 extension Kingfisher where Base: Image {
+    // MARK: - Blend Mode
+    /// Create image based on `self` and apply blend mode.
+    ///
+    /// - parameter blendMode:       The blend mode of creating image.
+    /// - parameter alpha:           The alpha should be used for image.
+    /// - parameter backgroundColor: The background color for the output image.
+    ///
+    /// - returns: An image with blend mode applied.
+    ///
+    /// - Note: This method only works for CG-based image.
+    #if !os(macOS)
+    public func image(withBlendMode blendMode: CGBlendMode,
+                      alpha: CGFloat = 1.0,
+                      backgroundColor: Color? = nil) -> Image
+    {
+        guard let cgImage = cgImage else {
+            assertionFailure("[Kingfisher] Blend mode image only works for CG-based image.")
+            return base
+        }
+
+        let rect = CGRect(origin: .zero, size: size)
+        return draw(cgImage: cgImage, to: rect.size) {
+            if let backgroundColor = backgroundColor {
+                backgroundColor.setFill()
+                UIRectFill(rect)
+            }
+
+            base.draw(in: rect, blendMode: blendMode, alpha: alpha)
+        }
+    }
+    #endif
+
+    // MARK: - Compositing Operation
+    /// Create image based on `self` and apply compositing operation.
+    ///
+    /// - parameter compositingOperation: The compositing operation of creating image.
+    /// - parameter alpha:                The alpha should be used for image.
+    /// - parameter backgroundColor:      The background color for the output image.
+    ///
+    /// - returns: An image with compositing operation applied.
+    ///
+    /// - Note: This method only works for CG-based image.
+    #if os(macOS)
+    public func image(withCompositingOperation compositingOperation: NSCompositingOperation,
+                      alpha: CGFloat = 1.0,
+                      backgroundColor: Color? = nil) -> Image
+    {
+        guard let cgImage = cgImage else {
+            assertionFailure("[Kingfisher] Compositing Operation image only works for CG-based image.")
+            return base
+        }
+
+        let rect = CGRect(origin: .zero, size: size)
+        return draw(cgImage: cgImage, to: rect.size) {
+            if let backgroundColor = backgroundColor {
+                backgroundColor.setFill()
+                rect.fill()
+            }
+
+            base.draw(in: rect, from: NSRect.zero, operation: compositingOperation, fraction: alpha)
+        }
+    }
+    #endif
 
     // MARK: - Round Corner
     /// Create a round corner image based on `self`.

+ 103 - 0
Sources/ImageProcessor.swift

@@ -27,6 +27,10 @@
 import Foundation
 import CoreGraphics
 
+#if os(macOS)
+import AppKit
+#endif
+
 /// The item which could be processed by an `ImageProcessor`
 ///
 /// - image: Input image
@@ -160,6 +164,105 @@ public struct RectCorner: OptionSet {
     }
 }
 
+/// Processor for adding an blend mode to images. Only CG-based images are supported.
+#if !os(macOS)
+public struct BlendImageProcessor: ImageProcessor {
+
+    /// Identifier of the processor.
+    /// - Note: See documentation of `ImageProcessor` protocol for more.
+    public let identifier: String
+
+    public let blendMode: CGBlendMode
+    public let alpha: CGFloat
+
+    /// Background color of the output image. If `nil`, it will stay transparent.
+    public let backgroundColor: Color?
+
+    /// Initialize an `BlendImageProcessor`
+    ///
+    /// - parameter blendMode:       Blend Mode will be used to blend the input image.
+    /// - parameter alpha:           Alpha will be used when blend image.
+    ///                              From 0.0 to 1.0. 1.0 means solid image, 0.0 means transparent image.
+    ///                              Default is 1.0.
+    /// - parameter backgroundColor: Backgroud color to apply for the output image. Default is `nil`.
+    public init(blendMode: CGBlendMode, alpha: CGFloat = 1.0, backgroundColor: Color? = nil) {
+        self.blendMode = blendMode
+        self.alpha = alpha
+        self.backgroundColor = backgroundColor
+        self.identifier = "com.onevcat.Kingfisher.BlendImageProcessor(\(blendMode.rawValue))"
+    }
+
+    /// Process an input `ImageProcessItem` item to an image for this processor.
+    ///
+    /// - parameter item:    Input item which will be processed by `self`
+    /// - parameter options: Options when processing the item.
+    ///
+    /// - returns: The processed image.
+    ///
+    /// - Note: See documentation of `ImageProcessor` protocol for more.
+    public func process(item: ImageProcessItem, options: KingfisherOptionsInfo) -> Image? {
+        switch item {
+        case .image(let image):
+            return image.kf.scaled(to: options.scaleFactor)
+                        .kf.image(withBlendMode: blendMode, alpha: alpha, backgroundColor: backgroundColor)
+        case .data(_):
+            return (DefaultImageProcessor.default >> self).process(item: item, options: options)
+        }
+    }
+}
+#endif
+
+#if os(macOS)
+/// Processor for adding an compositing operation to images. Only CG-based images are supported in macOS.
+public struct CompositingImageProcessor: ImageProcessor {
+
+    /// Identifier of the processor.
+    /// - Note: See documentation of `ImageProcessor` protocol for more.
+    public let identifier: String
+
+    public let compositingOperation: NSCompositingOperation
+    public let alpha: CGFloat
+
+    /// Background color of the output image. If `nil`, it will stay transparent.
+    public let backgroundColor: Color?
+
+    /// Initialize an `CompositingImageProcessor`
+    ///
+    /// - parameter compositingOperation: Compositing operation will be used to the input image.
+    /// - parameter alpha:                Alpha will be used when compositing image.
+    ///                                   From 0.0 to 1.0. 1.0 means solid image, 0.0 means transparent image.
+    ///                                   Default is 1.0.
+    /// - parameter backgroundColor:      Backgroud color to apply for the output image. Default is `nil`.
+    public init(compositingOperation: NSCompositingOperation,
+                alpha: CGFloat = 1.0,
+                backgroundColor: Color? = nil)
+    {
+        self.compositingOperation = compositingOperation
+        self.alpha = alpha
+        self.backgroundColor = backgroundColor
+        self.identifier = "com.onevcat.Kingfisher.CompositingImageProcessor(\(compositingOperation.rawValue))"
+    }
+
+    /// Process an input `ImageProcessItem` item to an image for this processor.
+    ///
+    /// - parameter item:    Input item which will be processed by `self`
+    /// - parameter options: Options when processing the item.
+    ///
+    /// - returns: The processed image.
+    ///
+    /// - Note: See documentation of `ImageProcessor` protocol for more.
+    public func process(item: ImageProcessItem, options: KingfisherOptionsInfo) -> Image? {
+        switch item {
+        case .image(let image):
+            return image.kf.scaled(to: options.scaleFactor)
+                        .kf.image(withCompositingOperation: compositingOperation, alpha: alpha, backgroundColor: backgroundColor)
+        case .data(_):
+            return (DefaultImageProcessor.default >> self).process(item: item, options: options)
+        }
+    }
+}
+#endif
+
 /// Processor for making round corner images. Only CG-based images are supported in macOS, 
 /// if a non-CG image passed in, the processor will do nothing.
 public struct RoundCornerImageProcessor: ImageProcessor {

+ 20 - 0
Tests/KingfisherTests/ImageProcessorTests.swift

@@ -27,6 +27,10 @@
 import XCTest
 import Kingfisher
 
+#if os(macOS)
+import AppKit
+#endif
+
 class ImageProcessorTests: XCTestCase {
     
     let imageNames = ["kingfisher.jpg", "onevcat.jpg", "unicorn.png"]
@@ -54,6 +58,22 @@ class ImageProcessorTests: XCTestCase {
         
         XCTAssertTrue(image1.renderEqual(to: image2))
     }
+
+    #if !os(macOS)
+    func testBlendProcessor() {
+        let p = BlendImageProcessor(blendMode: .darken, alpha: 1.0, backgroundColor: .lightGray)
+        XCTAssertEqual(p.identifier, "com.onevcat.Kingfisher.BlendImageProcessor(\(CGBlendMode.darken.rawValue))")
+        checkProcessor(p, with: "blend-\(CGBlendMode.darken.rawValue)")
+    }
+    #endif
+
+    #if os(macOS)
+    func testCompositingProcessor() {
+        let p = CompositingImageProcessor(compositingOperation: .darken, alpha: 1.0, backgroundColor: .lightGray)
+        XCTAssertEqual(p.identifier, "com.onevcat.Kingfisher.CompositingImageProcessor(\(NSCompositingOperation.darken.rawValue))")
+        checkProcessor(p, with: "compositing-\(NSCompositingOperation.darken.rawValue)")
+    }
+    #endif
     
     func testRoundCornerProcessor() {
         let p = RoundCornerImageProcessor(cornerRadius: 40)