Skip to content

Commit

Permalink
Update doc
Browse files Browse the repository at this point in the history
  • Loading branch information
onevcat committed Oct 15, 2023
1 parent bb5d936 commit a5be225
Show file tree
Hide file tree
Showing 10 changed files with 635 additions and 603 deletions.
2 changes: 1 addition & 1 deletion Sources/General/KingfisherManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ public class KingfisherManager {
completionHandler: ((Result<RetrieveImageResult, KingfisherError>) -> Void)?) -> DownloadTask?
{
var options = options
if let provider = ImageProgressiveProvider(options, refresh: { image in
if let provider = ImageProgressiveProvider(options: options, refresh: { image in
guard let setter = progressiveImageSetter else {
return
}
Expand Down
79 changes: 48 additions & 31 deletions Sources/Image/Filter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,28 +34,22 @@ import UIKit

import CoreImage

// Reuse the same CI Context for all CI drawing.
// Reuses the same CI Context for all CI drawings.
private let ciContext = CIContext(options: nil)

/// Represents the type of transformer method, which will be used in to provide a `Filter`.
/// Represents the type of transformer method, which will be used to provide a ``Filter``.
public typealias Transformer = (CIImage) -> CIImage?

/// Represents a processor based on a `CIImage` `Filter`.
/// It requires a filter to create an `ImageProcessor`.
/// Represents an ``ImageProcessor`` based on a ``Filter``, for images of `CIImage`.
///
/// You can use any ``Filter``, or in other words, a ``Transformer`` to convert a `CIImage` to another, to create a
/// ``ImageProcessor`` type easily.
public protocol CIImageProcessor: ImageProcessor {
var filter: Filter { get }
}

extension CIImageProcessor {

/// Processes the input `ImageProcessItem` with this processor.
///
/// - Parameters:
/// - item: Input item which will be processed by `self`.
/// - options: Options when processing the item.
/// - Returns: The processed image.
///
/// - Note: See documentation of `ImageProcessor` protocol for more.
public func process(item: ImageProcessItem, options: KingfisherParsedOptionsInfo) -> KFCrossPlatformImage? {
switch item {
case .image(let image):
Expand All @@ -66,17 +60,21 @@ extension CIImageProcessor {
}
}

/// A wrapper struct for a `Transformer` of CIImage filters. A `Filter`
/// value could be used to create a `CIImage` processor.
/// A wrapper struct for a `Transformer` of CIImage filters.
///
/// A ``Filter`` value can be used to create an ``ImageProcessor`` for `CIImage`s.
public struct Filter {

let transform: Transformer


/// Creates a ``Filter`` from a given ``Transformer``.
///
/// - Parameter transform: The value defines how a `CIImage` can be converted to another one.
public init(transform: @escaping Transformer) {
self.transform = transform
}

/// Tint filter which will apply a tint color to images.
/// Tint filter that applies a tint color to images.
public static var tint: (KFCrossPlatformColor) -> Filter = {
color in
Filter {
Expand All @@ -95,34 +93,53 @@ public struct Filter {
}
}

/// Represents color control elements. It is a tuple of
/// `(brightness, contrast, saturation, inputEV)`
public typealias ColorElement = (CGFloat, CGFloat, CGFloat, CGFloat)
/// Represents color control elements.
///
/// It contains necessary variables which can be applied as a filter to `CIImage.applyingFilter` feature as
/// "CIColorControls".
public struct ColorElement {
public let brightness: CGFloat
public let contrast: CGFloat
public let saturation: CGFloat
public let inputEV: CGFloat

/// Creates a ``ColorElement`` value with given parameters.
/// - Parameters:
/// - brightness: The brightness change applied to the image.
/// - contrast: The contrast change applied to the image.
/// - saturation: The saturation change applied to the image.
/// - inputEV: The EV (F-stops brighter or darker) change applied to the image.
public init(brightness: CGFloat, contrast: CGFloat, saturation: CGFloat, inputEV: CGFloat) {
self.brightness = brightness
self.contrast = contrast
self.saturation = saturation
self.inputEV = inputEV
}
}

/// Color control filter which will apply color control change to images.
/// Color control filter that applies color control changes to images.
public static var colorControl: (ColorElement) -> Filter = { arg -> Filter in
let (brightness, contrast, saturation, inputEV) = arg
return Filter { input in
let paramsColor = [kCIInputBrightnessKey: brightness,
kCIInputContrastKey: contrast,
kCIInputSaturationKey: saturation]
let paramsColor = [kCIInputBrightnessKey: arg.brightness,
kCIInputContrastKey: arg.contrast,
kCIInputSaturationKey: arg.saturation]
let blackAndWhite = input.applyingFilter("CIColorControls", parameters: paramsColor)
let paramsExposure = [kCIInputEVKey: inputEV]
let paramsExposure = [kCIInputEVKey: arg.inputEV]
return blackAndWhite.applyingFilter("CIExposureAdjust", parameters: paramsExposure)
}
}
}

extension KingfisherWrapper where Base: KFCrossPlatformImage {

/// Applies a `Filter` containing `CIImage` transformer to `self`.
/// Applies a `Filter` containing a `CIImage` transformer to `self`.
///
/// - Parameter filter: The filter used to transform `self`.
/// - Returns: A transformed image by input `Filter`.
/// - Parameters:
/// - filter: The filter used to transform `self`.
/// - Returns: A transformed image by the input `Filter`.
///
/// - Note:
/// Only CG-based images are supported. If any error happens
/// during transforming, `self` will be returned.
/// > Important: Only CG-based images are supported. If an error occurs during transformation,
/// ``KingfisherWrapper/base`` will be returned.
public func apply(_ filter: Filter) -> KFCrossPlatformImage {

guard let cgImage = cgImage else {
Expand Down
66 changes: 38 additions & 28 deletions Sources/Image/GIFAnimatedImage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,39 +27,40 @@
import Foundation
import ImageIO

/// Represents a set of image creating options used in Kingfisher.
/// Represents a set of image creation options used in Kingfisher.
public struct ImageCreatingOptions {

/// The target scale of image needs to be created.
public let scale: CGFloat
/// The target scale of the image that needs to be created.
public var scale: CGFloat

/// The expected animation duration if an animated image being created.
public let duration: TimeInterval
/// The expected animation duration if an animated image is being created.
public var duration: TimeInterval

/// For an animated image, whether or not all frames should be loaded before displaying.
public let preloadAll: Bool
/// For an animated image, indicates whether or not all frames should be loaded before displaying.
public var preloadAll: Bool

/// For an animated image, whether or not only the first image should be
/// loaded as a static image. It is useful for preview purpose of an animated image.
public let onlyFirstFrame: Bool
/// For an animated image, indicates whether only the first image should be
/// loaded as a static image. It is useful for previewing an animated image.
public var onlyFirstFrame: Bool

/// Creates an `ImageCreatingOptions` object.
///
/// - Parameters:
/// - scale: The target scale of image needs to be created. Default is `1.0`.
/// - duration: The expected animation duration if an animated image being created.
/// A value less or equal to `0.0` means the animated image duration will
/// be determined by the frame data. Default is `0.0`.
/// - preloadAll: For an animated image, whether or not all frames should be loaded before displaying.
/// Default is `false`.
/// - onlyFirstFrame: For an animated image, whether or not only the first image should be
/// loaded as a static image. It is useful for preview purpose of an animated image.
/// Default is `false`.
/// - scale: The target scale of the image that needs to be created. Default is `1.0`.
/// - duration: The expected animation duration if an animated image is being created.
/// A value less than or equal to `0.0` means the animated image duration will
/// be determined by the frame data. Default is `0.0`.
/// - preloadAll: For an animated image, whether or not all frames should be loaded before displaying.
/// Default is `false`.
/// - onlyFirstFrame: For an animated image, whether only the first image should be
/// loaded as a static image. It is useful for previewing an animated image.
/// Default is `false`.
public init(
scale: CGFloat = 1.0,
duration: TimeInterval = 0.0,
preloadAll: Bool = false,
onlyFirstFrame: Bool = false)
onlyFirstFrame: Bool = false
)
{
self.scale = scale
self.duration = duration
Expand All @@ -68,8 +69,8 @@ public struct ImageCreatingOptions {
}
}

/// Represents the decoding for a GIF image. This class extracts frames from an `imageSource`, then
/// hold the images for later use.
/// Represents the decoding for a GIF image. This class extracts frames from an ``ImageFrameSource``, and then
/// holds the images for later use.
public class GIFAnimatedImage {
let images: [KFCrossPlatformImage]
let duration: TimeInterval
Expand Down Expand Up @@ -102,7 +103,7 @@ public class GIFAnimatedImage {
self.init(from: frameSource, options: options)
}

/// Calculates frame duration for a gif frame out of the kCGImagePropertyGIFDictionary dictionary.
/// Calculates the frame duration for a GIF frame out of the `kCGImagePropertyGIFDictionary` dictionary.
public static func getFrameDuration(from gifInfo: [String: Any]?) -> TimeInterval {
let defaultFrameDuration = 0.1
guard let gifInfo = gifInfo else { return defaultFrameDuration }
Expand All @@ -115,7 +116,12 @@ public class GIFAnimatedImage {
return frameDuration.doubleValue > 0.011 ? frameDuration.doubleValue : defaultFrameDuration
}

/// Calculates frame duration at a specific index for a gif from an `imageSource`.
/// Calculates the frame duration at a specific index for a GIF from an `CGImageSource`.
///
/// - Parameters:
/// - imageSource: The image source where the animated image information should be extracted from.
/// - index: The index of the target frame in the image.
/// - Returns: The time duration of the frame at given index in the image.
public static func getFrameDuration(from imageSource: CGImageSource, at index: Int) -> TimeInterval {
guard let properties = CGImageSourceCopyPropertiesAtIndex(imageSource, index, nil)
as? [String: Any] else { return 0.0 }
Expand All @@ -125,23 +131,27 @@ public class GIFAnimatedImage {
}
}

/// Represents a frame source for animated image
/// Represents a frame source for an animated image.
public protocol ImageFrameSource {

/// Source data associated with this frame source.
var data: Data? { get }

/// Count of total frames in this frame source.
/// Count of the total frames in this frame source.
var frameCount: Int { get }

/// Retrieves the frame at a specific index. The result image is expected to be
/// no larger than `maxSize`. If the index is invalid, implementors should return `nil`.
/// Retrieves the frame at a specific index.
///
/// The resulting image is expected to be no larger than `maxSize`. If the index is invalid,
/// implementors should return `nil`.
func frame(at index: Int, maxSize: CGSize?) -> CGImage?

/// Retrieves the duration at a specific index. If the index is invalid, implementors should return `0.0`.
func duration(at index: Int) -> TimeInterval
}

public extension ImageFrameSource {

/// Retrieves the frame at a specific index. If the index is invalid, implementors should return `nil`.
func frame(at index: Int) -> CGImage? {
return frame(at: index, maxSize: nil)
Expand Down
Loading

0 comments on commit a5be225

Please sign in to comment.