Skip to content

Commit

Permalink
new image processors: blend, compositing
Browse files Browse the repository at this point in the history
  • Loading branch information
yemodin committed Dec 3, 2017
1 parent 78c36b1 commit c0141de
Show file tree
Hide file tree
Showing 4 changed files with 234 additions and 2 deletions.
50 changes: 48 additions & 2 deletions Kingfisher.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -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 */; };
Expand Down Expand Up @@ -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>"; };
Expand Down Expand Up @@ -785,6 +800,8 @@
4BB83E071E32075800B64183 /* Modified */ = {
isa = PBXGroup;
children = (
CCA25D361FD49A3100FA5C6E /* Compositing */,
CCA25D231FD4713D00FA5C6E /* Blend */,
4BB83E081E32075800B64183 /* B&W */,
4BB83E0F1E32075800B64183 /* Blur */,
4BB83E161E32075800B64183 /* ColorControl */,
Expand Down Expand Up @@ -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 = (
Expand Down Expand Up @@ -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 */,
Expand All @@ -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 */,
Expand All @@ -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 */,
Expand All @@ -1684,13 +1724,15 @@
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 */,
4BB83F011E32075800B64183 /* unicorn-tint-yellow-02-mac.png in Resources */,
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 */,
Expand All @@ -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 */,
Expand Down Expand Up @@ -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 */,
Expand All @@ -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 */,
Expand All @@ -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 */,
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
63 changes: 63 additions & 0 deletions Sources/Image.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down
103 changes: 103 additions & 0 deletions Sources/ImageProcessor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down
Loading

0 comments on commit c0141de

Please sign in to comment.