-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathRenderer.swift
137 lines (113 loc) · 4.56 KB
/
Renderer.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
//
// Renderer.swift
// Example
//
// Created by Nacho Soto on 12/1/18.
// Copyright © 2018 Nacho Soto. All rights reserved.
//
import Result
import ReactiveCocoa
import ReactiveSwift
import AsyncImageView
public struct Photos {
typealias RendererType = AnyRenderer<Renderer.RasterizedRenderData, ImageResult, NoError>
typealias ImageView = AsyncImageView<Renderer.RasterizedRenderData, Data, RendererType, RendererType>
static func createAspectFillView(initialFrame frame: CGRect) -> ImageView {
return ImageView(
initialFrame: frame,
renderer: Renderer.singleton.aspectFillRenderer
)
}
static func createAspectFitView(initialFrame frame: CGRect) -> ImageView {
return ImageView(
initialFrame: frame,
renderer: Renderer.singleton.aspectFitRenderer
)
}
struct Data: ImageViewDataType {
let imageData: FlickrImageData
init(imageData: FlickrImageData) {
self.imageData = imageData
}
func renderDataWithSize(_ size: CGSize) -> Renderer.RasterizedRenderData {
return RenderData(imageData: self.imageData, size: size)
}
}
public final class Renderer {
private let remoteRenderer: RendererType
let aspectFillRenderer: RendererType
let aspectFitRenderer: RendererType
static let singleton: Renderer = {
return Renderer(screenScale: UIScreen.main.scale)
}()
init(screenScale: CGFloat) {
self.remoteRenderer = AnyRenderer(
RemoteImageRenderer<RemoteRenderData>(session: URLSession(configuration: URLSessionConfiguration.default))
.logAndIgnoreErrors { print("Error downloading image: \($0)") }
.mapData { RemoteRenderData(imageData: $0.imageData, size: $0.size) }
.multicasted()
)
self.aspectFillRenderer = AnyRenderer(
remoteRenderer
.inflatedWithScale(screenScale, opaque: true, contentMode: .aspectFill)
// Cache rasterized images. Not that important for this, but it can be useful
// if there is extra processing done to remote images (using RendererType.processedWithScale)
.withCache(DiskCache.onCacheSubdirectory("aspect_fill"))
.multicasted()
)
self.aspectFitRenderer = AnyRenderer(
remoteRenderer
.inflatedWithScale(screenScale, opaque: true, contentMode: .aspectFit)
.withCache(DiskCache.onCacheSubdirectory("aspect_fit"))
.multicasted()
)
}
// MARK: - RenderDataTypes
public struct RasterizedRenderData: RenderDataType, DataFileType {
public let imageData: FlickrImageData
public let size: CGSize
public var uniqueFilename: String {
return self.imageData.uniqueFilename
}
}
public struct RemoteRenderData: RemoteRenderDataType, DataFileType {
public let imageData: FlickrImageData
public let size: CGSize
public var imageURL: URL {
return self.imageData.url
}
public var subdirectory: String? {
// We don't want to separate by size because the source image is the same.
return nil
}
public var uniqueFilename: String {
return self.imageData.uniqueFilename
}
}
}
}
private extension FlickrImageData {
var url: URL {
return URL(string: "https://farm\(self.farm).static.flickr.com/\(self.server)/\(self.id)_\(self.secret).jpg")!
}
var uniqueFilename: String {
return (url as NSURL)
.resourceSpecifier!
.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)!
}
}
extension Photos.Renderer.RemoteRenderData: Hashable {
public static func ==(lhs: Photos.Renderer.RemoteRenderData, rhs: Photos.Renderer.RemoteRenderData) -> Bool {
return (lhs.imageURL == rhs.imageURL)
}
public func hash(into hasher: inout Hasher) {
hasher.combine(self.imageURL)
}
}
extension Photos.Renderer.RasterizedRenderData: Hashable {
public func hash(into hasher: inout Hasher) {
hasher.combine(self.imageData)
hasher.combine(self.size.width)
hasher.combine(self.size.height)
}
}