Proyectos de Subversion Iphone Microlearning

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
//
2
//  ImageFilter.swift
3
//
4
//  Copyright (c) 2015 Alamofire Software Foundation (http://alamofire.org/)
5
//
6
//  Permission is hereby granted, free of charge, to any person obtaining a copy
7
//  of this software and associated documentation files (the "Software"), to deal
8
//  in the Software without restriction, including without limitation the rights
9
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
//  copies of the Software, and to permit persons to whom the Software is
11
//  furnished to do so, subject to the following conditions:
12
//
13
//  The above copyright notice and this permission notice shall be included in
14
//  all copies or substantial portions of the Software.
15
//
16
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
//  THE SOFTWARE.
23
//
24
 
25
import Foundation
26
 
27
#if os(iOS) || os(tvOS) || os(watchOS)
28
import UIKit
29
#elseif os(macOS)
30
import Cocoa
31
#endif
32
 
33
// MARK: ImageFilter
34
 
35
/// The `ImageFilter` protocol defines properties for filtering an image as well as identification of the filter.
36
public protocol ImageFilter {
37
    /// A closure used to create an alternative representation of the given image.
38
    var filter: (Image) -> Image { get }
39
 
40
    /// The string used to uniquely identify the filter operation.
41
    var identifier: String { get }
42
}
43
 
44
extension ImageFilter {
45
    /// The unique identifier for any `ImageFilter` type.
46
    public var identifier: String { "\(type(of: self))" }
47
}
48
 
49
// MARK: - Sizable
50
 
51
/// The `Sizable` protocol defines a size property intended for use with `ImageFilter` types.
52
public protocol Sizable {
53
    /// The size of the type.
54
    var size: CGSize { get }
55
}
56
 
57
extension ImageFilter where Self: Sizable {
58
    /// The unique idenitifier for an `ImageFilter` conforming to the `Sizable` protocol.
59
    public var identifier: String {
60
        let width = Int64(size.width.rounded())
61
        let height = Int64(size.height.rounded())
62
 
63
        return "\(type(of: self))-size:(\(width)x\(height))"
64
    }
65
}
66
 
67
// MARK: - Roundable
68
 
69
/// The `Roundable` protocol defines a radius property intended for use with `ImageFilter` types.
70
public protocol Roundable {
71
    /// The radius of the type.
72
    var radius: CGFloat { get }
73
}
74
 
75
extension ImageFilter where Self: Roundable {
76
    /// The unique idenitifier for an `ImageFilter` conforming to the `Roundable` protocol.
77
    public var identifier: String {
78
        let radius = Int64(self.radius.rounded())
79
        return "\(type(of: self))-radius:(\(radius))"
80
    }
81
}
82
 
83
// MARK: - DynamicImageFilter
84
 
85
/// The `DynamicImageFilter` class simplifies custom image filter creation by using a trailing closure initializer.
86
public struct DynamicImageFilter: ImageFilter {
87
    /// The string used to uniquely identify the image filter operation.
88
    public let identifier: String
89
 
90
    /// A closure used to create an alternative representation of the given image.
91
    public let filter: (Image) -> Image
92
 
93
    /// Initializes the `DynamicImageFilter` instance with the specified identifier and filter closure.
94
    ///
95
    /// - parameter identifier: The unique identifier of the filter.
96
    /// - parameter filter:     A closure used to create an alternative representation of the given image.
97
    ///
98
    /// - returns: The new `DynamicImageFilter` instance.
99
    public init(_ identifier: String, filter: @escaping (Image) -> Image) {
100
        self.identifier = identifier
101
        self.filter = filter
102
    }
103
}
104
 
105
// MARK: - CompositeImageFilter
106
 
107
/// The `CompositeImageFilter` protocol defines an additional `filters` property to support multiple composite filters.
108
public protocol CompositeImageFilter: ImageFilter {
109
    /// The image filters to apply to the image in sequential order.
110
    var filters: [ImageFilter] { get }
111
}
112
 
113
extension CompositeImageFilter {
114
    /// The unique idenitifier for any `CompositeImageFilter` type.
115
    public var identifier: String {
116
        filters.map { $0.identifier }.joined(separator: "_")
117
    }
118
 
119
    /// The filter closure for any `CompositeImageFilter` type.
120
    public var filter: (Image) -> Image {
121
        { image in
122
            self.filters.reduce(image) { $1.filter($0) }
123
        }
124
    }
125
}
126
 
127
// MARK: - DynamicCompositeImageFilter
128
 
129
/// The `DynamicCompositeImageFilter` class is a composite image filter based on a specified array of filters.
130
public struct DynamicCompositeImageFilter: CompositeImageFilter {
131
    /// The image filters to apply to the image in sequential order.
132
    public let filters: [ImageFilter]
133
 
134
    /// Initializes the `DynamicCompositeImageFilter` instance with the given filters.
135
    ///
136
    /// - parameter filters: The filters taking part in the composite image filter.
137
    ///
138
    /// - returns: The new `DynamicCompositeImageFilter` instance.
139
    public init(_ filters: [ImageFilter]) {
140
        self.filters = filters
141
    }
142
 
143
    /// Initializes the `DynamicCompositeImageFilter` instance with the given filters.
144
    ///
145
    /// - parameter filters: The filters taking part in the composite image filter.
146
    ///
147
    /// - returns: The new `DynamicCompositeImageFilter` instance.
148
    public init(_ filters: ImageFilter...) {
149
        self.init(filters)
150
    }
151
}
152
 
153
#if os(iOS) || os(tvOS) || os(watchOS)
154
 
155
// MARK: - Single Pass Image Filters (iOS, tvOS and watchOS only) -
156
 
157
/// Scales an image to a specified size.
158
public struct ScaledToSizeFilter: ImageFilter, Sizable {
159
    /// The size of the filter.
160
    public let size: CGSize
161
 
162
    /// Initializes the `ScaledToSizeFilter` instance with the given size.
163
    ///
164
    /// - parameter size: The size.
165
    ///
166
    /// - returns: The new `ScaledToSizeFilter` instance.
167
    public init(size: CGSize) {
168
        self.size = size
169
    }
170
 
171
    /// The filter closure used to create the modified representation of the given image.
172
    public var filter: (Image) -> Image {
173
        { image in
174
            image.af.imageScaled(to: self.size)
175
        }
176
    }
177
}
178
 
179
// MARK: -
180
 
181
/// Scales an image from the center while maintaining the aspect ratio to fit within a specified size.
182
public struct AspectScaledToFitSizeFilter: ImageFilter, Sizable {
183
    /// The size of the filter.
184
    public let size: CGSize
185
 
186
    /// Initializes the `AspectScaledToFitSizeFilter` instance with the given size.
187
    ///
188
    /// - parameter size: The size.
189
    ///
190
    /// - returns: The new `AspectScaledToFitSizeFilter` instance.
191
    public init(size: CGSize) {
192
        self.size = size
193
    }
194
 
195
    /// The filter closure used to create the modified representation of the given image.
196
    public var filter: (Image) -> Image {
197
        { image in
198
            image.af.imageAspectScaled(toFit: self.size)
199
        }
200
    }
201
}
202
 
203
// MARK: -
204
 
205
/// Scales an image from the center while maintaining the aspect ratio to fill a specified size. Any pixels that fall
206
/// outside the specified size are clipped.
207
public struct AspectScaledToFillSizeFilter: ImageFilter, Sizable {
208
    /// The size of the filter.
209
    public let size: CGSize
210
 
211
    /// Initializes the `AspectScaledToFillSizeFilter` instance with the given size.
212
    ///
213
    /// - parameter size: The size.
214
    ///
215
    /// - returns: The new `AspectScaledToFillSizeFilter` instance.
216
    public init(size: CGSize) {
217
        self.size = size
218
    }
219
 
220
    /// The filter closure used to create the modified representation of the given image.
221
    public var filter: (Image) -> Image {
222
        { image in
223
            image.af.imageAspectScaled(toFill: self.size)
224
        }
225
    }
226
}
227
 
228
// MARK: -
229
 
230
/// Rounds the corners of an image to the specified radius.
231
public struct RoundedCornersFilter: ImageFilter, Roundable {
232
    /// The radius of the filter.
233
    public let radius: CGFloat
234
 
235
    /// Whether to divide the radius by the image scale.
236
    public let divideRadiusByImageScale: Bool
237
 
238
    /// Initializes the `RoundedCornersFilter` instance with the given radius.
239
    ///
240
    /// - parameter radius:                   The radius.
241
    /// - parameter divideRadiusByImageScale: Whether to divide the radius by the image scale. Set to `true` when the
242
    ///                                       image has the same resolution for all screen scales such as @1x, @2x and
243
    ///                                       @3x (i.e. single image from web server). Set to `false` for images loaded
244
    ///                                       from an asset catalog with varying resolutions for each screen scale.
245
    ///                                       `false` by default.
246
    ///
247
    /// - returns: The new `RoundedCornersFilter` instance.
248
    public init(radius: CGFloat, divideRadiusByImageScale: Bool = false) {
249
        self.radius = radius
250
        self.divideRadiusByImageScale = divideRadiusByImageScale
251
    }
252
 
253
    /// The filter closure used to create the modified representation of the given image.
254
    public var filter: (Image) -> Image {
255
        { image in
256
            image.af.imageRounded(withCornerRadius: self.radius,
257
                                  divideRadiusByImageScale: self.divideRadiusByImageScale)
258
        }
259
    }
260
 
261
    /// The unique idenitifier for an `ImageFilter` conforming to the `Roundable` protocol.
262
    public var identifier: String {
263
        let radius = Int64(self.radius.rounded())
264
        return "\(type(of: self))-radius:(\(radius))-divided:(\(divideRadiusByImageScale))"
265
    }
266
}
267
 
268
// MARK: -
269
 
270
/// Rounds the corners of an image into a circle.
271
public struct CircleFilter: ImageFilter {
272
    /// Initializes the `CircleFilter` instance.
273
    ///
274
    /// - returns: The new `CircleFilter` instance.
275
    public init() {}
276
 
277
    /// The filter closure used to create the modified representation of the given image.
278
    public var filter: (Image) -> Image {
279
        { image in
280
            image.af.imageRoundedIntoCircle()
281
        }
282
    }
283
}
284
 
285
// MARK: -
286
 
287
#if os(iOS) || os(tvOS)
288
 
289
/// The `CoreImageFilter` protocol defines `parameters`, `filterName` properties used by CoreImage.
290
public protocol CoreImageFilter: ImageFilter {
291
    /// The filter name of the CoreImage filter.
292
    var filterName: String { get }
293
 
294
    /// The image filter parameters passed to CoreImage.
295
    var parameters: [String: Any] { get }
296
}
297
 
298
extension ImageFilter where Self: CoreImageFilter {
299
    /// The filter closure used to create the modified representation of the given image.
300
    public var filter: (Image) -> Image {
301
        { image in
302
            image.af.imageFiltered(withCoreImageFilter: self.filterName, parameters: self.parameters) ?? image
303
        }
304
    }
305
 
306
    /// The unique idenitifier for an `ImageFilter` conforming to the `CoreImageFilter` protocol.
307
    public var identifier: String { "\(type(of: self))-parameters:(\(parameters))" }
308
}
309
 
310
/// Blurs an image using a `CIGaussianBlur` filter with the specified blur radius.
311
public struct BlurFilter: ImageFilter, CoreImageFilter {
312
    /// The filter name.
313
    public let filterName = "CIGaussianBlur"
314
 
315
    /// The image filter parameters passed to CoreImage.
316
    public let parameters: [String: Any]
317
 
318
    /// Initializes the `BlurFilter` instance with the given blur radius.
319
    ///
320
    /// - parameter blurRadius: The blur radius.
321
    ///
322
    /// - returns: The new `BlurFilter` instance.
323
    public init(blurRadius: UInt = 10) {
324
        parameters = ["inputRadius": blurRadius]
325
    }
326
}
327
 
328
#endif
329
 
330
// MARK: - Composite Image Filters (iOS, tvOS and watchOS only) -
331
 
332
/// Scales an image to a specified size, then rounds the corners to the specified radius.
333
public struct ScaledToSizeWithRoundedCornersFilter: CompositeImageFilter {
334
    /// Initializes the `ScaledToSizeWithRoundedCornersFilter` instance with the given size and radius.
335
    ///
336
    /// - parameter size:                     The size.
337
    /// - parameter radius:                   The radius.
338
    /// - parameter divideRadiusByImageScale: Whether to divide the radius by the image scale. Set to `true` when the
339
    ///                                       image has the same resolution for all screen scales such as @1x, @2x and
340
    ///                                       @3x (i.e. single image from web server). Set to `false` for images loaded
341
    ///                                       from an asset catalog with varying resolutions for each screen scale.
342
    ///                                       `false` by default.
343
    ///
344
    /// - returns: The new `ScaledToSizeWithRoundedCornersFilter` instance.
345
    public init(size: CGSize, radius: CGFloat, divideRadiusByImageScale: Bool = false) {
346
        filters = [ScaledToSizeFilter(size: size),
347
                   RoundedCornersFilter(radius: radius, divideRadiusByImageScale: divideRadiusByImageScale)]
348
    }
349
 
350
    /// The image filters to apply to the image in sequential order.
351
    public let filters: [ImageFilter]
352
}
353
 
354
// MARK: -
355
 
356
/// Scales an image from the center while maintaining the aspect ratio to fit within a specified size, then rounds the
357
/// corners to the specified radius.
358
public struct AspectScaledToFillSizeWithRoundedCornersFilter: CompositeImageFilter {
359
    /// Initializes the `AspectScaledToFillSizeWithRoundedCornersFilter` instance with the given size and radius.
360
    ///
361
    /// - parameter size:                     The size.
362
    /// - parameter radius:                   The radius.
363
    /// - parameter divideRadiusByImageScale: Whether to divide the radius by the image scale. Set to `true` when the
364
    ///                                       image has the same resolution for all screen scales such as @1x, @2x and
365
    ///                                       @3x (i.e. single image from web server). Set to `false` for images loaded
366
    ///                                       from an asset catalog with varying resolutions for each screen scale.
367
    ///                                       `false` by default.
368
    ///
369
    /// - returns: The new `AspectScaledToFillSizeWithRoundedCornersFilter` instance.
370
    public init(size: CGSize, radius: CGFloat, divideRadiusByImageScale: Bool = false) {
371
        filters = [AspectScaledToFillSizeFilter(size: size),
372
                   RoundedCornersFilter(radius: radius, divideRadiusByImageScale: divideRadiusByImageScale)]
373
    }
374
 
375
    /// The image filters to apply to the image in sequential order.
376
    public let filters: [ImageFilter]
377
}
378
 
379
// MARK: -
380
 
381
/// Scales an image to a specified size, then rounds the corners into a circle.
382
public struct ScaledToSizeCircleFilter: CompositeImageFilter {
383
    /// Initializes the `ScaledToSizeCircleFilter` instance with the given size.
384
    ///
385
    /// - parameter size: The size.
386
    ///
387
    /// - returns: The new `ScaledToSizeCircleFilter` instance.
388
    public init(size: CGSize) {
389
        filters = [ScaledToSizeFilter(size: size), CircleFilter()]
390
    }
391
 
392
    /// The image filters to apply to the image in sequential order.
393
    public let filters: [ImageFilter]
394
}
395
 
396
// MARK: -
397
 
398
/// Scales an image from the center while maintaining the aspect ratio to fit within a specified size, then rounds the
399
/// corners into a circle.
400
public struct AspectScaledToFillSizeCircleFilter: CompositeImageFilter {
401
    /// Initializes the `AspectScaledToFillSizeCircleFilter` instance with the given size.
402
    ///
403
    /// - parameter size: The size.
404
    ///
405
    /// - returns: The new `AspectScaledToFillSizeCircleFilter` instance.
406
    public init(size: CGSize) {
407
        filters = [AspectScaledToFillSizeFilter(size: size), CircleFilter()]
408
    }
409
 
410
    /// The image filters to apply to the image in sequential order.
411
    public let filters: [ImageFilter]
412
}
413
 
414
#endif