@amazon-devices/expo-image 2.0.1758683737

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (289) hide show
  1. package/.eslintrc.js +2 -0
  2. package/CHANGELOG.md +285 -0
  3. package/CMakeLists.txt +91 -0
  4. package/LICENSE +7 -0
  5. package/README.kepler.md +123 -0
  6. package/README.md +54 -0
  7. package/THIRD_PARTY_NOTICES.txt +24 -0
  8. package/android/build.gradle +124 -0
  9. package/android/proguard-rules.pro +28 -0
  10. package/android/src/main/AndroidManifest.xml +15 -0
  11. package/android/src/main/java/expo/modules/image/Exceptions.kt +9 -0
  12. package/android/src/main/java/expo/modules/image/ExpoImageAppGlideModule.kt +19 -0
  13. package/android/src/main/java/expo/modules/image/ExpoImageModule.kt +192 -0
  14. package/android/src/main/java/expo/modules/image/ExpoImageView.kt +220 -0
  15. package/android/src/main/java/expo/modules/image/ExpoImageViewWrapper.kt +652 -0
  16. package/android/src/main/java/expo/modules/image/GlideModel.kt +73 -0
  17. package/android/src/main/java/expo/modules/image/ImageUtils.kt +50 -0
  18. package/android/src/main/java/expo/modules/image/ImageViewWrapperTarget.kt +313 -0
  19. package/android/src/main/java/expo/modules/image/ResourceIdHelper.kt +47 -0
  20. package/android/src/main/java/expo/modules/image/ThumbnailRequestCoordinatorExtension.kt +21 -0
  21. package/android/src/main/java/expo/modules/image/YogaUtils.kt +20 -0
  22. package/android/src/main/java/expo/modules/image/blurhash/BlurHashFetcher.kt +32 -0
  23. package/android/src/main/java/expo/modules/image/blurhash/BlurhashDecoder.kt +189 -0
  24. package/android/src/main/java/expo/modules/image/blurhash/BlurhashModelLoader.kt +30 -0
  25. package/android/src/main/java/expo/modules/image/blurhash/BlurhashModelLoaderFactory.kt +14 -0
  26. package/android/src/main/java/expo/modules/image/blurhash/BlurhashModule.kt +17 -0
  27. package/android/src/main/java/expo/modules/image/dataurls/Base64DataFetcher.kt +27 -0
  28. package/android/src/main/java/expo/modules/image/dataurls/Base64ModelLoader.kt +24 -0
  29. package/android/src/main/java/expo/modules/image/dataurls/Base64ModelLoaderFactory.kt +12 -0
  30. package/android/src/main/java/expo/modules/image/dataurls/Base64Module.kt +16 -0
  31. package/android/src/main/java/expo/modules/image/drawing/OutlineProvider.kt +201 -0
  32. package/android/src/main/java/expo/modules/image/enums/ContentFit.kt +89 -0
  33. package/android/src/main/java/expo/modules/image/enums/ImageCacheType.kt +14 -0
  34. package/android/src/main/java/expo/modules/image/enums/Priority.kt +15 -0
  35. package/android/src/main/java/expo/modules/image/events/GlideRequestListener.kt +64 -0
  36. package/android/src/main/java/expo/modules/image/events/OkHttpProgressListener.kt +26 -0
  37. package/android/src/main/java/expo/modules/image/okhttp/ExpoImageOkHttpClientGlideModule.kt +80 -0
  38. package/android/src/main/java/expo/modules/image/okhttp/GlideUrlWrapperLoader.kt +55 -0
  39. package/android/src/main/java/expo/modules/image/records/CachePolicy.kt +10 -0
  40. package/android/src/main/java/expo/modules/image/records/ContentPosition.kt +89 -0
  41. package/android/src/main/java/expo/modules/image/records/ImageTransition.kt +8 -0
  42. package/android/src/main/java/expo/modules/image/records/SourceMap.kt +160 -0
  43. package/android/src/main/java/expo/modules/image/records/events.kt +25 -0
  44. package/android/src/main/java/expo/modules/image/svg/SVGDecoder.kt +33 -0
  45. package/android/src/main/java/expo/modules/image/svg/SVGDrawableTranscoder.kt +37 -0
  46. package/android/src/main/java/expo/modules/image/svg/SVGModule.kt +26 -0
  47. package/android/src/main/java/expo/modules/image/thumbhash/ThumbhashDecoder.kt +365 -0
  48. package/android/src/main/java/expo/modules/image/thumbhash/ThumbhashFetcher.kt +31 -0
  49. package/android/src/main/java/expo/modules/image/thumbhash/ThumbhashModelLoader.kt +26 -0
  50. package/android/src/main/java/expo/modules/image/thumbhash/ThumbhashModelLoaderFactory.kt +14 -0
  51. package/android/src/main/java/expo/modules/image/thumbhash/ThumbhashModule.kt +17 -0
  52. package/build/ExpoImage.d.ts +15 -0
  53. package/build/ExpoImage.d.ts.map +1 -0
  54. package/build/ExpoImage.js +75 -0
  55. package/build/ExpoImage.js.map +1 -0
  56. package/build/ExpoImage.kepler.d.ts +23 -0
  57. package/build/ExpoImage.kepler.d.ts.map +1 -0
  58. package/build/ExpoImage.kepler.js +71 -0
  59. package/build/ExpoImage.kepler.js.map +1 -0
  60. package/build/ExpoImage.web.d.ts +9 -0
  61. package/build/ExpoImage.web.d.ts.map +1 -0
  62. package/build/ExpoImage.web.js +90 -0
  63. package/build/ExpoImage.web.js.map +1 -0
  64. package/build/ExpoImageModules.d.ts +3 -0
  65. package/build/ExpoImageModules.d.ts.map +1 -0
  66. package/build/ExpoImageModules.js +4 -0
  67. package/build/ExpoImageModules.js.map +1 -0
  68. package/build/ExpoImageModules.kepler.d.ts +6 -0
  69. package/build/ExpoImageModules.kepler.d.ts.map +1 -0
  70. package/build/ExpoImageModules.kepler.js +5 -0
  71. package/build/ExpoImageModules.kepler.js.map +1 -0
  72. package/build/Image.d.ts +30 -0
  73. package/build/Image.d.ts.map +1 -0
  74. package/build/Image.js +49 -0
  75. package/build/Image.js.map +1 -0
  76. package/build/Image.types.d.ts +374 -0
  77. package/build/Image.types.d.ts.map +1 -0
  78. package/build/Image.types.js +2 -0
  79. package/build/Image.types.js.map +1 -0
  80. package/build/ImageBackground.d.ts +6 -0
  81. package/build/ImageBackground.d.ts.map +1 -0
  82. package/build/ImageBackground.js +13 -0
  83. package/build/ImageBackground.js.map +1 -0
  84. package/build/ImageViewNativeComponent.d.ts +20 -0
  85. package/build/ImageViewNativeComponent.d.ts.map +1 -0
  86. package/build/ImageViewNativeComponent.js +42 -0
  87. package/build/ImageViewNativeComponent.js.map +1 -0
  88. package/build/NativeImageLoaderKepler.d.ts +18 -0
  89. package/build/NativeImageLoaderKepler.d.ts.map +1 -0
  90. package/build/NativeImageLoaderKepler.js +3 -0
  91. package/build/NativeImageLoaderKepler.js.map +1 -0
  92. package/build/fabric/registerNativeComponent.d.ts +15 -0
  93. package/build/fabric/registerNativeComponent.d.ts.map +1 -0
  94. package/build/fabric/registerNativeComponent.js +47 -0
  95. package/build/fabric/registerNativeComponent.js.map +1 -0
  96. package/build/index.d.ts +4 -0
  97. package/build/index.d.ts.map +1 -0
  98. package/build/index.js +4 -0
  99. package/build/index.js.map +1 -0
  100. package/build/utils/AssetSourceResolver.web.d.ts +24 -0
  101. package/build/utils/AssetSourceResolver.web.d.ts.map +1 -0
  102. package/build/utils/AssetSourceResolver.web.js +67 -0
  103. package/build/utils/AssetSourceResolver.web.js.map +1 -0
  104. package/build/utils/blurhash/base83.d.ts +3 -0
  105. package/build/utils/blurhash/base83.d.ts.map +1 -0
  106. package/build/utils/blurhash/base83.js +103 -0
  107. package/build/utils/blurhash/base83.js.map +1 -0
  108. package/build/utils/blurhash/decode.d.ts +7 -0
  109. package/build/utils/blurhash/decode.d.ts.map +1 -0
  110. package/build/utils/blurhash/decode.js +92 -0
  111. package/build/utils/blurhash/decode.js.map +1 -0
  112. package/build/utils/blurhash/error.d.ts +4 -0
  113. package/build/utils/blurhash/error.d.ts.map +1 -0
  114. package/build/utils/blurhash/error.js +8 -0
  115. package/build/utils/blurhash/error.js.map +1 -0
  116. package/build/utils/blurhash/useBlurhash.d.ts +8 -0
  117. package/build/utils/blurhash/useBlurhash.d.ts.map +1 -0
  118. package/build/utils/blurhash/useBlurhash.js +64 -0
  119. package/build/utils/blurhash/useBlurhash.js.map +1 -0
  120. package/build/utils/blurhash/utils.d.ts +5 -0
  121. package/build/utils/blurhash/utils.d.ts.map +1 -0
  122. package/build/utils/blurhash/utils.js +21 -0
  123. package/build/utils/blurhash/utils.js.map +1 -0
  124. package/build/utils/resolveAssetSource.d.ts +3 -0
  125. package/build/utils/resolveAssetSource.d.ts.map +1 -0
  126. package/build/utils/resolveAssetSource.js +3 -0
  127. package/build/utils/resolveAssetSource.js.map +1 -0
  128. package/build/utils/resolveAssetSource.web.d.ts +9 -0
  129. package/build/utils/resolveAssetSource.web.d.ts.map +1 -0
  130. package/build/utils/resolveAssetSource.web.js +31 -0
  131. package/build/utils/resolveAssetSource.web.js.map +1 -0
  132. package/build/utils/resolveHashString.d.ts +14 -0
  133. package/build/utils/resolveHashString.d.ts.map +1 -0
  134. package/build/utils/resolveHashString.js +31 -0
  135. package/build/utils/resolveHashString.js.map +1 -0
  136. package/build/utils/resolveHashString.web.d.ts +20 -0
  137. package/build/utils/resolveHashString.web.d.ts.map +1 -0
  138. package/build/utils/resolveHashString.web.js +31 -0
  139. package/build/utils/resolveHashString.web.js.map +1 -0
  140. package/build/utils/resolveSources.d.ts +8 -0
  141. package/build/utils/resolveSources.d.ts.map +1 -0
  142. package/build/utils/resolveSources.js +45 -0
  143. package/build/utils/resolveSources.js.map +1 -0
  144. package/build/utils/thumbhash/thumbhash.d.ts +66 -0
  145. package/build/utils/thumbhash/thumbhash.d.ts.map +1 -0
  146. package/build/utils/thumbhash/thumbhash.js +338 -0
  147. package/build/utils/thumbhash/thumbhash.js.map +1 -0
  148. package/build/utils.d.ts +17 -0
  149. package/build/utils.d.ts.map +1 -0
  150. package/build/utils.js +85 -0
  151. package/build/utils.js.map +1 -0
  152. package/build/web/AnimationManager.d.ts +37 -0
  153. package/build/web/AnimationManager.d.ts.map +1 -0
  154. package/build/web/AnimationManager.js +155 -0
  155. package/build/web/AnimationManager.js.map +1 -0
  156. package/build/web/ColorTintFilter.d.ts +12 -0
  157. package/build/web/ColorTintFilter.d.ts.map +1 -0
  158. package/build/web/ColorTintFilter.js +30 -0
  159. package/build/web/ColorTintFilter.js.map +1 -0
  160. package/build/web/ImageWrapper.d.ts +5 -0
  161. package/build/web/ImageWrapper.d.ts.map +1 -0
  162. package/build/web/ImageWrapper.js +44 -0
  163. package/build/web/ImageWrapper.js.map +1 -0
  164. package/build/web/ImageWrapper.types.d.ts +29 -0
  165. package/build/web/ImageWrapper.types.d.ts.map +1 -0
  166. package/build/web/ImageWrapper.types.js +2 -0
  167. package/build/web/ImageWrapper.types.js.map +1 -0
  168. package/build/web/getImageWrapperEventHandler.d.ts +8 -0
  169. package/build/web/getImageWrapperEventHandler.d.ts.map +1 -0
  170. package/build/web/getImageWrapperEventHandler.js +25 -0
  171. package/build/web/getImageWrapperEventHandler.js.map +1 -0
  172. package/build/web/hooks.d.ts +13 -0
  173. package/build/web/hooks.d.ts.map +1 -0
  174. package/build/web/hooks.js +58 -0
  175. package/build/web/hooks.js.map +1 -0
  176. package/build/web/imageStyles.d.ts +2 -0
  177. package/build/web/imageStyles.d.ts.map +1 -0
  178. package/build/web/imageStyles.js +137 -0
  179. package/build/web/imageStyles.js.map +1 -0
  180. package/build/web/positioning.d.ts +11 -0
  181. package/build/web/positioning.d.ts.map +1 -0
  182. package/build/web/positioning.js +35 -0
  183. package/build/web/positioning.js.map +1 -0
  184. package/build/web/useSourceSelection.d.ts +14 -0
  185. package/build/web/useSourceSelection.d.ts.map +1 -0
  186. package/build/web/useSourceSelection.js +98 -0
  187. package/build/web/useSourceSelection.js.map +1 -0
  188. package/expo-module.config.json +9 -0
  189. package/ios/Blurhash.swift +326 -0
  190. package/ios/BlurhashLoader.swift +52 -0
  191. package/ios/ContentFit.swift +55 -0
  192. package/ios/ContentPosition.swift +108 -0
  193. package/ios/ExpoImage.podspec +30 -0
  194. package/ios/ImageCachePolicy.swift +24 -0
  195. package/ios/ImageCacheType.swift +21 -0
  196. package/ios/ImageModule.swift +127 -0
  197. package/ios/ImagePriority.swift +22 -0
  198. package/ios/ImageSource.swift +44 -0
  199. package/ios/ImageTransition.swift +67 -0
  200. package/ios/ImageUtils.swift +227 -0
  201. package/ios/ImageView.swift +469 -0
  202. package/ios/Loaders/PhotoLibraryAssetLoader.swift +146 -0
  203. package/ios/Thumbhash.swift +550 -0
  204. package/ios/ThumbhashLoader.swift +53 -0
  205. package/jest.config.js +3 -0
  206. package/kepler/ExpoImage.cpp +63 -0
  207. package/kepler/ExpoImage.h +29 -0
  208. package/kepler/ExpoImageCacheHandler.cpp +15 -0
  209. package/kepler/ExpoImageCacheHandler.h +28 -0
  210. package/kepler/ExpoImageComponent.cpp +579 -0
  211. package/kepler/ExpoImageComponent.h +199 -0
  212. package/kepler/ImageWrapper/BlurhashImageWrapper.cpp +37 -0
  213. package/kepler/ImageWrapper/BlurhashImageWrapper.h +23 -0
  214. package/kepler/ImageWrapper/CacheImageWrapper.cpp +80 -0
  215. package/kepler/ImageWrapper/CacheImageWrapper.h +41 -0
  216. package/kepler/ImageWrapper/HashImageWrapper.cpp +21 -0
  217. package/kepler/ImageWrapper/HashImageWrapper.h +22 -0
  218. package/kepler/ImageWrapper/ImageWrapper.cpp +24 -0
  219. package/kepler/ImageWrapper/ImageWrapper.h +33 -0
  220. package/kepler/ImageWrapper/LocalImageWrapper.cpp +61 -0
  221. package/kepler/ImageWrapper/LocalImageWrapper.h +30 -0
  222. package/kepler/ImageWrapper/ThumbhashImageWrapper.cpp +33 -0
  223. package/kepler/ImageWrapper/ThumbhashImageWrapper.h +20 -0
  224. package/kepler/KeplerImageViewComponent.h +64 -0
  225. package/kepler/KeplerInit.cpp +35 -0
  226. package/kepler/blurhash/common.h +32 -0
  227. package/kepler/blurhash/decode.cpp +187 -0
  228. package/kepler/blurhash/decode.h +58 -0
  229. package/kepler/contentposition/ImageContentPosition.cpp +86 -0
  230. package/kepler/contentposition/ImageContentPosition.h +48 -0
  231. package/kepler/enums/ImageContentFit.h +17 -0
  232. package/kepler/enums/ImagePriority.h +17 -0
  233. package/kepler/managers/ExpoImageManager.cpp +38 -0
  234. package/kepler/managers/ExpoImageManager.h +23 -0
  235. package/kepler/test/ExpoImage.cpp +73 -0
  236. package/kepler/test/ExpoImageComponent.cpp +290 -0
  237. package/kepler/test/blurhash/decode.cpp +39 -0
  238. package/kepler/test/contentposition/ImageContentPosition.cpp +100 -0
  239. package/kepler/test/managers/ExpoImageManager.cpp +39 -0
  240. package/kepler/test/thumbhash/decode.cpp +18 -0
  241. package/kepler/test/utils/LoaderDelegate.cpp +130 -0
  242. package/kepler/thumbhash/decode.cpp +166 -0
  243. package/kepler/thumbhash/decode.h +22 -0
  244. package/kepler/utils/PlaceholderImageLoaderDelegate.cpp +26 -0
  245. package/kepler/utils/PlaceholderImageLoaderDelegate.h +26 -0
  246. package/kepler/utils/PrefetchImageLoaderDelegate.cpp +55 -0
  247. package/kepler/utils/PrefetchImageLoaderDelegate.h +35 -0
  248. package/kepler/utils/SourceImageLoaderDelegate.cpp +47 -0
  249. package/kepler/utils/SourceImageLoaderDelegate.h +42 -0
  250. package/kepler/utils/SourceImageLoaderDelegateEmitter.cpp +15 -0
  251. package/kepler/utils/SourceImageLoaderDelegateEmitter.h +28 -0
  252. package/kepler-compatibility.json +8 -0
  253. package/package.json +1 -0
  254. package/react-native.config.js +22 -0
  255. package/src/ExpoImage.kepler.tsx +119 -0
  256. package/src/ExpoImage.tsx +119 -0
  257. package/src/ExpoImage.web.tsx +155 -0
  258. package/src/ExpoImageModules.kepler.ts +7 -0
  259. package/src/ExpoImageModules.ts +4 -0
  260. package/src/Image.tsx +82 -0
  261. package/src/Image.types.ts +450 -0
  262. package/src/ImageBackground.tsx +18 -0
  263. package/src/ImageViewNativeComponent.ts +59 -0
  264. package/src/NativeImageLoaderKepler.ts +22 -0
  265. package/src/fabric/registerNativeComponent.ts +70 -0
  266. package/src/index.ts +3 -0
  267. package/src/utils/AssetSourceResolver.web.ts +88 -0
  268. package/src/utils/blurhash/base83.ts +104 -0
  269. package/src/utils/blurhash/decode.ts +114 -0
  270. package/src/utils/blurhash/error.ts +7 -0
  271. package/src/utils/blurhash/useBlurhash.tsx +81 -0
  272. package/src/utils/blurhash/utils.ts +21 -0
  273. package/src/utils/resolveAssetSource.tsx +3 -0
  274. package/src/utils/resolveAssetSource.web.ts +40 -0
  275. package/src/utils/resolveHashString.tsx +36 -0
  276. package/src/utils/resolveHashString.web.tsx +33 -0
  277. package/src/utils/resolveSources.tsx +48 -0
  278. package/src/utils/thumbhash/thumbhash.ts +387 -0
  279. package/src/utils.ts +109 -0
  280. package/src/web/AnimationManager.tsx +224 -0
  281. package/src/web/ColorTintFilter.tsx +36 -0
  282. package/src/web/ImageWrapper.tsx +85 -0
  283. package/src/web/ImageWrapper.types.ts +36 -0
  284. package/src/web/getImageWrapperEventHandler.ts +29 -0
  285. package/src/web/hooks.ts +72 -0
  286. package/src/web/imageStyles.tsx +136 -0
  287. package/src/web/positioning.ts +48 -0
  288. package/src/web/useSourceSelection.ts +151 -0
  289. package/tsconfig.json +9 -0
@@ -0,0 +1,127 @@
1
+ // Copyright 2022-present 650 Industries. All rights reserved.
2
+
3
+ import ExpoModulesCore
4
+ import SDWebImage
5
+ import SDWebImageWebPCoder
6
+ import SDWebImageAVIFCoder
7
+ import SDWebImageSVGCoder
8
+
9
+ public final class ImageModule: Module {
10
+ lazy var prefetcher = SDWebImagePrefetcher.shared
11
+
12
+ public func definition() -> ModuleDefinition {
13
+ Name("ExpoImage")
14
+
15
+ OnCreate {
16
+ ImageModule.registerCoders()
17
+ ImageModule.registerLoaders()
18
+ }
19
+
20
+ View(ImageView.self) {
21
+ Events(
22
+ "onLoadStart",
23
+ "onProgress",
24
+ "onError",
25
+ "onLoad"
26
+ )
27
+
28
+ Prop("source") { (view, sources: [ImageSource]?) in
29
+ view.sources = sources
30
+ }
31
+
32
+ Prop("placeholder") { (view, placeholders: [ImageSource]?) in
33
+ view.placeholderSources = placeholders ?? []
34
+ }
35
+
36
+ Prop("contentFit") { (view, contentFit: ContentFit?) in
37
+ view.contentFit = contentFit ?? .cover
38
+ }
39
+
40
+ Prop("placeholderContentFit") { (view, placeholderContentFit: ContentFit?) in
41
+ view.placeholderContentFit = placeholderContentFit ?? .scaleDown
42
+ }
43
+
44
+ Prop("contentPosition") { (view, contentPosition: ContentPosition?) in
45
+ view.contentPosition = contentPosition ?? .center
46
+ }
47
+
48
+ Prop("transition") { (view, transition: ImageTransition?) in
49
+ view.transition = transition
50
+ }
51
+
52
+ Prop("blurRadius") { (view, blurRadius: Double?) in
53
+ view.blurRadius = blurRadius ?? .zero
54
+ }
55
+
56
+ Prop("tintColor") { (view, tintColor: UIColor?) in
57
+ view.imageTintColor = tintColor
58
+ }
59
+
60
+ Prop("priority") { (view, priority: ImagePriority?) in
61
+ view.loadingOptions.remove([.lowPriority, .highPriority])
62
+
63
+ if let priority = priority?.toSDWebImageOptions() {
64
+ view.loadingOptions.insert(priority)
65
+ }
66
+ }
67
+
68
+ Prop("cachePolicy") { (view, cachePolicy: ImageCachePolicy?) in
69
+ view.cachePolicy = cachePolicy ?? .disk
70
+ }
71
+
72
+ Prop("enableLiveTextInteraction") { (view, enableLiveTextInteraction: Bool?) in
73
+ view.enableLiveTextInteraction = enableLiveTextInteraction ?? false
74
+ }
75
+
76
+ Prop("accessible") { (view, accessible: Bool?) in
77
+ view.sdImageView.isAccessibilityElement = accessible ?? false
78
+ }
79
+
80
+ Prop("accessibilityLabel") { (view, label: String?) in
81
+ view.sdImageView.accessibilityLabel = label
82
+ }
83
+
84
+ Prop("recyclingKey") { (view, key: String?) in
85
+ view.recyclingKey = key
86
+ }
87
+
88
+ OnViewDidUpdateProps { view in
89
+ view.reload()
90
+ }
91
+ }
92
+
93
+ Function("prefetch") { (urls: [URL]) in
94
+ SDWebImagePrefetcher.shared.prefetchURLs(urls)
95
+ }
96
+
97
+ AsyncFunction("clearMemoryCache") { () -> Bool in
98
+ SDImageCache.shared.clearMemory()
99
+ return true
100
+ }
101
+
102
+ AsyncFunction("clearDiskCache") { (promise: Promise) in
103
+ SDImageCache.shared.clearDisk {
104
+ promise.resolve(true)
105
+ }
106
+ }
107
+ }
108
+
109
+ static func registerCoders() {
110
+ if #available(iOS 14.0, *) {
111
+ // By default Animated WebP is not supported
112
+ SDImageCodersManager.shared.addCoder(SDImageAWebPCoder.shared)
113
+ } else {
114
+ // This coder is much slower, but it's the only one that works in iOS 13
115
+ SDImageCodersManager.shared.addCoder(SDImageWebPCoder.shared)
116
+ }
117
+ SDImageCodersManager.shared.addCoder(SDImageAVIFCoder.shared)
118
+ SDImageCodersManager.shared.addCoder(SDImageSVGCoder.shared)
119
+ SDImageCodersManager.shared.addCoder(SDImageHEICCoder.shared)
120
+ }
121
+
122
+ static func registerLoaders() {
123
+ SDImageLoadersManager.shared.addLoader(BlurhashLoader())
124
+ SDImageLoadersManager.shared.addLoader(ThumbhashLoader())
125
+ SDImageLoadersManager.shared.addLoader(PhotoLibraryAssetLoader())
126
+ }
127
+ }
@@ -0,0 +1,22 @@
1
+ import ExpoModulesCore
2
+ import SDWebImage
3
+
4
+ enum ImagePriority: String, Enumerable {
5
+ case low
6
+ case normal
7
+ case high
8
+
9
+ /**
10
+ Maps the priority to `SDWebImageOptions` which is a bitmask thus has only low and high priority options.
11
+ */
12
+ func toSDWebImageOptions() -> SDWebImageOptions? {
13
+ switch self {
14
+ case .low:
15
+ return .lowPriority
16
+ case .high:
17
+ return .highPriority
18
+ default:
19
+ return nil
20
+ }
21
+ }
22
+ }
@@ -0,0 +1,44 @@
1
+ // Copyright 2022-present 650 Industries. All rights reserved.
2
+
3
+ import ExpoModulesCore
4
+
5
+ struct ImageSource: Record {
6
+ @Field
7
+ var width: Double = 0.0
8
+
9
+ @Field
10
+ var height: Double = 0.0
11
+
12
+ @Field
13
+ var uri: URL? = nil
14
+
15
+ @Field
16
+ var scale: Double = 1.0
17
+
18
+ @Field
19
+ var headers: [String: String]?
20
+
21
+ @Field
22
+ var cacheKey: String?
23
+
24
+ var pixelCount: Double {
25
+ return width * height * scale * scale
26
+ }
27
+
28
+ var isBlurhash: Bool {
29
+ return uri?.scheme == "blurhash"
30
+ }
31
+
32
+ var isThumbhash: Bool {
33
+ return uri?.scheme == "thumbhash"
34
+ }
35
+
36
+ var isPhotoLibraryAsset: Bool {
37
+ return isPhotoLibraryAssetUrl(uri)
38
+ }
39
+
40
+ var isCachingAllowed: Bool {
41
+ // TODO: Don't cache other non-network requests (e.g. data URIs, local files)
42
+ return !isPhotoLibraryAsset
43
+ }
44
+ }
@@ -0,0 +1,67 @@
1
+ // Copyright 2022-present 650 Industries. All rights reserved.
2
+
3
+ import ExpoModulesCore
4
+
5
+ enum ImageTransitionTiming: String, Enumerable {
6
+ case easeInOut = "ease-in-out"
7
+ case easeIn = "ease-in"
8
+ case easeOut = "ease-out"
9
+ case linear = "linear"
10
+
11
+ func toAnimationOption() -> UIView.AnimationOptions {
12
+ switch self {
13
+ case .easeInOut:
14
+ return .curveEaseInOut
15
+ case .easeIn:
16
+ return .curveEaseIn
17
+ case .easeOut:
18
+ return .curveEaseOut
19
+ case .linear:
20
+ return .curveLinear
21
+ }
22
+ }
23
+ }
24
+
25
+ enum ImageTransitionEffect: String, Enumerable {
26
+ case crossDissolve = "cross-dissolve"
27
+ case flipFromTop = "flip-from-top"
28
+ case flipFromRight = "flip-from-right"
29
+ case flipFromBottom = "flip-from-bottom"
30
+ case flipFromLeft = "flip-from-left"
31
+ case curlUp = "curl-up"
32
+ case curlDown = "curl-down"
33
+
34
+ func toAnimationOption() -> UIView.AnimationOptions {
35
+ switch self {
36
+ case .crossDissolve:
37
+ return .transitionCrossDissolve
38
+ case .flipFromLeft:
39
+ return .transitionFlipFromLeft
40
+ case .flipFromRight:
41
+ return .transitionFlipFromRight
42
+ case .flipFromTop:
43
+ return .transitionFlipFromTop
44
+ case .flipFromBottom:
45
+ return .transitionFlipFromBottom
46
+ case .curlUp:
47
+ return .transitionCurlUp
48
+ case .curlDown:
49
+ return .transitionCurlDown
50
+ }
51
+ }
52
+ }
53
+
54
+ struct ImageTransition: Record {
55
+ @Field
56
+ var duration: Double = 100
57
+
58
+ @Field
59
+ var timing: ImageTransitionTiming = .easeInOut
60
+
61
+ @Field
62
+ var effect: ImageTransitionEffect = .crossDissolve
63
+
64
+ func toAnimationOptions() -> UIView.AnimationOptions {
65
+ return [timing.toAnimationOption(), effect.toAnimationOption()]
66
+ }
67
+ }
@@ -0,0 +1,227 @@
1
+ // Copyright 2022-present 650 Industries. All rights reserved.
2
+
3
+ import SDWebImage
4
+ import ExpoModulesCore
5
+
6
+ func cacheTypeToString(_ cacheType: SDImageCacheType) -> String {
7
+ switch cacheType {
8
+ case .none:
9
+ return "none"
10
+ case .disk:
11
+ return "disk"
12
+ case .memory, .all:
13
+ // `all` doesn't make much sense, so we treat it as `memory`.
14
+ return "memory"
15
+ }
16
+ }
17
+
18
+ func imageFormatToMediaType(_ format: SDImageFormat) -> String? {
19
+ switch format {
20
+ case .undefined:
21
+ return nil
22
+ case .JPEG:
23
+ return "image/jpeg"
24
+ case .PNG:
25
+ return "image/png"
26
+ case .GIF:
27
+ return "image/gif"
28
+ case .TIFF:
29
+ return "image/tiff"
30
+ case .webP:
31
+ return "image/webp"
32
+ case .HEIC:
33
+ return "image/heic"
34
+ case .HEIF:
35
+ return "image/heif"
36
+ case .PDF:
37
+ return "application/pdf"
38
+ case .SVG:
39
+ return "image/svg+xml"
40
+ default:
41
+ // On one hand we could remove this clause and always ensure that we have handled
42
+ // all supported formats (by erroring compilation otherwise).
43
+ // On the other hand, we do support overriding SDWebImage version,
44
+ // so we shouldn't fail to compile on SDWebImage versions with.
45
+ return nil
46
+ }
47
+ }
48
+
49
+ /**
50
+ Calculates the ideal size that fills in the container size while maintaining the source aspect ratio.
51
+ */
52
+ func idealSize(contentPixelSize: CGSize, containerSize: CGSize, scale: Double, contentFit: ContentFit) -> CGSize {
53
+ switch contentFit {
54
+ case .contain:
55
+ let aspectRatio = min(containerSize.width / contentPixelSize.width, containerSize.height / contentPixelSize.height)
56
+ return contentPixelSize * aspectRatio
57
+ case .cover:
58
+ let aspectRatio = max(containerSize.width / contentPixelSize.width, containerSize.height / contentPixelSize.height)
59
+ return contentPixelSize * aspectRatio
60
+ case .fill:
61
+ return containerSize
62
+ case .scaleDown:
63
+ if containerSize.width < contentPixelSize.width / scale || containerSize.height < contentPixelSize.height / scale {
64
+ // The container is smaller than the image — scale it down and behave like `contain`
65
+ let aspectRatio = min(containerSize.width / contentPixelSize.width, containerSize.height / contentPixelSize.height)
66
+ return contentPixelSize * aspectRatio
67
+ } else {
68
+ // The container is bigger than the image — don't scale it and behave like `none`
69
+ return contentPixelSize / scale
70
+ }
71
+ case .none:
72
+ return contentPixelSize / scale
73
+ }
74
+ }
75
+
76
+ /**
77
+ Returns a bool whether the image should be downscaled to the given size.
78
+ */
79
+ func shouldDownscale(image: UIImage, toSize size: CGSize, scale: Double) -> Bool {
80
+ if size.width <= 0 || size.height <= 0 {
81
+ // View is invisible, so no reason to keep the image in memory.
82
+ // This already ensures that we won't be diving by zero in ratio calculations.
83
+ return true
84
+ }
85
+ if size.width.isInfinite || size.height.isInfinite {
86
+ // Keep the image unscaled for infinite sizes.
87
+ return false
88
+ }
89
+ let imageSize = image.size * image.scale
90
+ return imageSize.width > (size.width * scale) && imageSize.height > (size.height * scale)
91
+ }
92
+
93
+ /**
94
+ Resizes the animated image to fit in the given size and scale.
95
+ */
96
+ func resize(animatedImage image: UIImage, toSize size: CGSize, scale: Double) async -> UIImage {
97
+ // For animated images, the `images` member is non-nil and represents an array of animation frames.
98
+ if let images = image.images {
99
+ // Resize each animation frame separately.
100
+ let resizedImages = await concurrentMap(images) { image in
101
+ return resize(image: image, toSize: size, scale: scale)
102
+ }
103
+
104
+ // `animatedImage(with:duration:)` can return `nil`, probably when scales are not the same
105
+ // so it should never happen in our case, but let's handle it gracefully.
106
+ if let animatedImage = UIImage.animatedImage(with: resizedImages, duration: image.duration) {
107
+ return animatedImage
108
+ }
109
+ }
110
+ return resize(image: image, toSize: size, scale: scale)
111
+ }
112
+
113
+ /**
114
+ Resizes a still image to fit in the given size and scale.
115
+ */
116
+ func resize(image: UIImage, toSize size: CGSize, scale: Double) -> UIImage {
117
+ let format = UIGraphicsImageRendererFormat()
118
+ format.scale = scale
119
+
120
+ return UIGraphicsImageRenderer(size: size, format: format).image { _ in
121
+ image.draw(in: CGRect(origin: .zero, size: size))
122
+ }
123
+ }
124
+
125
+ /**
126
+ The image source that fits best into the given size, that is the one with the closest number of pixels.
127
+ May be `nil` if there are no sources available or the size is zero.
128
+ */
129
+ func getBestSource(from sources: [ImageSource]?, forSize size: CGSize, scale: Double = 1.0) -> ImageSource? {
130
+ guard let sources = sources, !sources.isEmpty else {
131
+ return nil
132
+ }
133
+ if size.width <= 0 || size.height <= 0 {
134
+ return nil
135
+ }
136
+ if sources.count == 1 {
137
+ return sources.first
138
+ }
139
+ var bestSource: ImageSource?
140
+ var bestFit = Double.infinity
141
+ let targetPixelCount = size.width * size.height * scale * scale
142
+
143
+ for source in sources {
144
+ let fit = abs(1 - (source.pixelCount / targetPixelCount))
145
+
146
+ if fit < bestFit {
147
+ bestSource = source
148
+ bestFit = fit
149
+ }
150
+ }
151
+ return bestSource
152
+ }
153
+
154
+ /**
155
+ Creates the cache key filter that returns the specific string.
156
+ */
157
+ func createCacheKeyFilter(_ cacheKey: String?) -> SDWebImageCacheKeyFilter? {
158
+ guard let cacheKey = cacheKey else {
159
+ return nil
160
+ }
161
+ return SDWebImageCacheKeyFilter { _ in
162
+ return cacheKey
163
+ }
164
+ }
165
+
166
+ extension CGSize {
167
+ /**
168
+ Multiplies a size with a scalar.
169
+ */
170
+ static func * (size: CGSize, scalar: Double) -> CGSize {
171
+ return CGSize(width: size.width * scalar, height: size.height * scalar)
172
+ }
173
+
174
+ /**
175
+ Divides a size with a scalar.
176
+ */
177
+ static func / (size: CGSize, scalar: Double) -> CGSize {
178
+ return CGSize(width: size.width / scalar, height: size.height / scalar)
179
+ }
180
+
181
+ /**
182
+ Returns a new CGSize with width and height rounded to an integral value using the specified rounding rule.
183
+ */
184
+ func rounded(_ rule: FloatingPointRoundingRule) -> CGSize {
185
+ return CGSize(width: width.rounded(rule), height: height.rounded(rule))
186
+ }
187
+ }
188
+
189
+ func makeNSError(description: String) -> NSError {
190
+ let userInfo = [NSLocalizedDescriptionKey: description]
191
+ return NSError(domain: "expo.modules.image", code: 0, userInfo: userInfo)
192
+ }
193
+
194
+ // MARK: - Async helpers
195
+ // TODO: Add helpers like these to the modules core eventually
196
+
197
+ /**
198
+ Asynchronously maps the given sequence (sequentially).
199
+ */
200
+ func asyncMap<ItemsType: Sequence, ResultType>(
201
+ _ items: ItemsType,
202
+ _ transform: (ItemsType.Element) async throws -> ResultType
203
+ ) async rethrows -> [ResultType] {
204
+ var values = [ResultType]()
205
+
206
+ for item in items {
207
+ try await values.append(transform(item))
208
+ }
209
+ return values
210
+ }
211
+
212
+ /**
213
+ Concurrently maps the given sequence.
214
+ */
215
+ func concurrentMap<ItemsType: Sequence, ResultType>(
216
+ _ items: ItemsType,
217
+ _ transform: @escaping (ItemsType.Element) async throws -> ResultType
218
+ ) async rethrows -> [ResultType] {
219
+ let tasks = items.map { item in
220
+ Task {
221
+ try await transform(item)
222
+ }
223
+ }
224
+ return try await asyncMap(tasks) { task in
225
+ try await task.value
226
+ }
227
+ }