react-native-nitro-image-pipeline 1.3.1 → 1.4.0
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.
- package/README.md +50 -2
- package/android/src/main/java/com/margelo/nitro/nitroimagepipeline/HybridNitroImagePipeline.kt +29 -10
- package/ios/HybridNitroImagePipeline.swift +59 -4
- package/lib/typescript/src/specs/nitro-image-toolkit.nitro.d.ts +10 -0
- package/lib/typescript/src/specs/nitro-image-toolkit.nitro.d.ts.map +1 -1
- package/nitrogen/generated/android/c++/JHybridNitroImagePipelineSpec.cpp +4 -0
- package/nitrogen/generated/android/c++/JHybridNitroImagePipelineSpec.hpp +1 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroimagepipeline/HybridNitroImagePipelineSpec.kt +4 -0
- package/nitrogen/generated/ios/NitroImagePipeline-Swift-Cxx-Bridge.hpp +9 -0
- package/nitrogen/generated/ios/c++/HybridNitroImagePipelineSpecSwift.hpp +6 -0
- package/nitrogen/generated/ios/swift/HybridNitroImagePipelineSpec.swift +1 -0
- package/nitrogen/generated/ios/swift/HybridNitroImagePipelineSpec_cxx.swift +11 -0
- package/nitrogen/generated/shared/c++/HybridNitroImagePipelineSpec.cpp +1 -0
- package/nitrogen/generated/shared/c++/HybridNitroImagePipelineSpec.hpp +1 -0
- package/package.json +1 -1
- package/src/specs/nitro-image-toolkit.nitro.ts +11 -0
package/README.md
CHANGED
|
@@ -259,11 +259,17 @@ omitted.
|
|
|
259
259
|
|
|
260
260
|
### `preLoadImage(url)`
|
|
261
261
|
|
|
262
|
-
Prefetches a single image into the cache. Returns `Promise<void>`.
|
|
262
|
+
Prefetches a single image into the **disk cache**, without decoding it. Returns `Promise<void>`.
|
|
263
|
+
|
|
264
|
+
Prefetching only pays the network and disk I/O cost up front — no bitmap is decoded or held in
|
|
265
|
+
memory, so prefetching a long list of URLs doesn't balloon RAM. The image is decoded (at the
|
|
266
|
+
`resize` target size, when one is given) the first time `loadImage`/`useImage`/`<PipelineImage>`
|
|
267
|
+
actually displays it.
|
|
263
268
|
|
|
264
269
|
### `preLoadImages(urls)`
|
|
265
270
|
|
|
266
|
-
Prefetches multiple images into the cache
|
|
271
|
+
Prefetches multiple images into the disk cache — same behavior as `preLoadImage`, for a batch.
|
|
272
|
+
Returns `Promise<void>`.
|
|
267
273
|
|
|
268
274
|
### `gaussianBlur(image, radius)`
|
|
269
275
|
|
|
@@ -300,10 +306,52 @@ RenderScript's true Gaussian, downscaling first when sigma exceeds the single-pa
|
|
|
300
306
|
~10.6px and compensating the radius so the result is unchanged. Both clamp at the edges, so blurred
|
|
301
307
|
images keep their borders instead of fading out.
|
|
302
308
|
|
|
309
|
+
### `setMemoryCacheLimit(bytes)`
|
|
310
|
+
|
|
311
|
+
Caps the in-memory cache of decoded bitmaps at `bytes`, evicting least-recently-used entries
|
|
312
|
+
immediately if the cache is currently larger. Pass `0` to disable in-memory caching entirely — the
|
|
313
|
+
disk cache keeps working. Synchronous; throws on negative or non-finite values.
|
|
314
|
+
|
|
315
|
+
```ts
|
|
316
|
+
// Keep at most 32 MB of decoded bitmaps in RAM
|
|
317
|
+
NitroImagePipeline.setMemoryCacheLimit(32 * 1024 * 1024);
|
|
318
|
+
|
|
319
|
+
// Or opt out of decoded-bitmap caching altogether
|
|
320
|
+
NitroImagePipeline.setMemoryCacheLimit(0);
|
|
321
|
+
```
|
|
322
|
+
|
|
303
323
|
### `clearCache()`
|
|
304
324
|
|
|
305
325
|
Removes all cached images from memory and disk. Returns `Promise<void>` that resolves once both caches are cleared.
|
|
306
326
|
|
|
327
|
+
## Memory usage
|
|
328
|
+
|
|
329
|
+
The pipeline is set up so RAM scales with what you display, not with what you download:
|
|
330
|
+
|
|
331
|
+
- **Pass `resize` (or just use `<PipelineImage>`, which derives it from layout).** With a target
|
|
332
|
+
size known, both platforms decode the source *near that size* instead of at full resolution —
|
|
333
|
+
iOS via a downsampled thumbnail decode, Android via Coil's subsampling. Without `resize`, a
|
|
334
|
+
48 MP photo decompresses to ~190 MB of bitmap no matter how small you display it.
|
|
335
|
+
- **Prefetching stores bytes, not bitmaps.** `preLoadImage(s)` writes the download to the disk
|
|
336
|
+
cache and skips decoding entirely.
|
|
337
|
+
- **The in-memory cache is capped and tunable** (defaults: 128 MB on iOS, 25% of the app's memory
|
|
338
|
+
class on Android). It holds decoded bitmaps for instant re-display and evicts
|
|
339
|
+
least-recently-used entries — also in response to memory warnings and backgrounding. Memory
|
|
340
|
+
profilers attribute this cache to the app; a plateau at the cap is expected and evictable, not a
|
|
341
|
+
leak. Lower the cap with [`setMemoryCacheLimit`](#setmemorycachelimitbytes), use `cache: 'disk'`
|
|
342
|
+
or `cache: 'none'` on images you won't show again soon, and `clearCache()` to drop everything.
|
|
343
|
+
- **Coming from a setup with no decoded-image cache** (e.g. loading files you downloaded
|
|
344
|
+
yourself)? Steady-state RAM will read higher here *by design*: after screens unmount, the cache
|
|
345
|
+
keeps their bitmaps around for instant re-display. For the old memory profile with the
|
|
346
|
+
pipeline's features intact, pass `cache: 'disk'` on your requests or call
|
|
347
|
+
`setMemoryCacheLimit(0)` once — RAM then holds only the images currently referenced, and
|
|
348
|
+
re-displays decode from the disk cache (cheap, since decodes are subsampled to the target size).
|
|
349
|
+
- **Android + `Image.dispose()`:** only call `dispose()` on images loaded with `cache: 'disk'` /
|
|
350
|
+
`cache: 'none'` (or with the memory cache disabled). With the memory cache on, the returned
|
|
351
|
+
image shares its bitmap with the cache, and disposing recycles a bitmap the cache may serve
|
|
352
|
+
again. Without `dispose()`, images are freed by the JS garbage collector — their bitmap size is
|
|
353
|
+
reported to it, so unreferenced images do get collected under pressure.
|
|
354
|
+
|
|
307
355
|
## Upgrading from 0.3.x
|
|
308
356
|
|
|
309
357
|
`blur` and `gaussianBlur(image, radius)` changed meaning in 1.0. They used to hand the number
|
package/android/src/main/java/com/margelo/nitro/nitroimagepipeline/HybridNitroImagePipeline.kt
CHANGED
|
@@ -3,8 +3,11 @@ package com.margelo.nitro.nitroimagepipeline
|
|
|
3
3
|
import android.content.Context
|
|
4
4
|
import androidx.core.graphics.drawable.toBitmap
|
|
5
5
|
import coil3.BitmapImage
|
|
6
|
+
import coil3.ColorImage
|
|
6
7
|
import coil3.DrawableImage
|
|
7
8
|
import coil3.ImageLoader
|
|
9
|
+
import coil3.decode.DecodeResult
|
|
10
|
+
import coil3.decode.Decoder
|
|
8
11
|
import coil3.disk.DiskCache
|
|
9
12
|
import coil3.memory.MemoryCache
|
|
10
13
|
import coil3.network.okhttp.OkHttpNetworkFetcherFactory
|
|
@@ -117,21 +120,25 @@ class HybridNitroImagePipeline : HybridNitroImagePipelineSpec() {
|
|
|
117
120
|
}
|
|
118
121
|
}
|
|
119
122
|
|
|
123
|
+
// Preloading warms the disk cache only: the memory cache is skipped and the
|
|
124
|
+
// decode step is replaced with a no-op (Coil's documented preload pattern),
|
|
125
|
+
// so prefetching N URLs costs network + disk I/O instead of N full-resolution
|
|
126
|
+
// bitmaps on the heap. The image is decoded — subsampled to the requested
|
|
127
|
+
// size — only when a loadImage actually displays it.
|
|
128
|
+
private fun preloadRequest(url: String): ImageRequest =
|
|
129
|
+
ImageRequest.Builder(context)
|
|
130
|
+
.data(url)
|
|
131
|
+
.memoryCachePolicy(CachePolicy.DISABLED)
|
|
132
|
+
.decoderFactory { _, _, _ -> Decoder { DecodeResult(ColorImage(), false) } }
|
|
133
|
+
.build()
|
|
134
|
+
|
|
120
135
|
override fun preLoadImage(url: String): Promise<Unit> = Promise.async {
|
|
121
|
-
|
|
122
|
-
imageLoader.execute(request)
|
|
136
|
+
imageLoader.execute(preloadRequest(url))
|
|
123
137
|
}
|
|
124
138
|
|
|
125
139
|
override fun preLoadImages(urls: Array<String>): Promise<Unit> = Promise.async {
|
|
126
140
|
coroutineScope {
|
|
127
|
-
urls
|
|
128
|
-
.map { url ->
|
|
129
|
-
async {
|
|
130
|
-
val request = ImageRequest.Builder(context).data(url).build()
|
|
131
|
-
imageLoader.execute(request)
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
.awaitAll()
|
|
141
|
+
urls.map { url -> async { imageLoader.execute(preloadRequest(url)) } }.awaitAll()
|
|
135
142
|
}
|
|
136
143
|
Unit
|
|
137
144
|
}
|
|
@@ -150,6 +157,18 @@ class HybridNitroImagePipeline : HybridNitroImagePipelineSpec() {
|
|
|
150
157
|
}
|
|
151
158
|
}
|
|
152
159
|
|
|
160
|
+
override fun setMemoryCacheLimit(bytes: Double) {
|
|
161
|
+
require(bytes >= 0 && bytes.isFinite()) {
|
|
162
|
+
"Memory cache limit must be a non-negative, finite number of bytes (got $bytes)"
|
|
163
|
+
}
|
|
164
|
+
imageLoader.memoryCache?.apply {
|
|
165
|
+
maxSize = bytes.toLong()
|
|
166
|
+
// Setting maxSize only affects future inserts; evict down to it now so
|
|
167
|
+
// the call frees memory immediately.
|
|
168
|
+
trimToSize(bytes.toLong())
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
153
172
|
override fun clearCache(): Promise<Unit> = Promise.async {
|
|
154
173
|
imageLoader.memoryCache?.clear()
|
|
155
174
|
// DiskCache.clear() does file I/O; keep it off the JS thread but await
|
|
@@ -95,10 +95,28 @@ class HybridNitroImagePipeline: HybridNitroImagePipelineSpec {
|
|
|
95
95
|
// the original download, so they survive memory eviction and
|
|
96
96
|
// restarts without dropping the original for other variants.
|
|
97
97
|
configuration.dataCachePolicy = .storeAll
|
|
98
|
+
// A private, capped memory cache. The default (ImageCache.shared)
|
|
99
|
+
// sizes itself at 15% of physical RAM — up to 768 MB of decoded
|
|
100
|
+
// bitmaps on modern devices before anything is evicted, which shows
|
|
101
|
+
// up as "high RAM usage" even though it is all evictable cache.
|
|
102
|
+
// 128 MB still holds ~10 full-screen bitmaps or hundreds of list
|
|
103
|
+
// thumbnails, and the LRU cache keeps trimming itself on memory
|
|
104
|
+
// warnings and when the app enters the background.
|
|
105
|
+
configuration.imageCache = ImageCache(
|
|
106
|
+
costLimit: min(ImageCache.defaultCostLimit, 128 * 1024 * 1024)
|
|
107
|
+
)
|
|
98
108
|
return ImagePipeline(configuration: configuration)
|
|
99
109
|
}()
|
|
100
110
|
|
|
101
|
-
|
|
111
|
+
// `.diskCache` stores the downloaded data without decoding it, so
|
|
112
|
+
// prefetching N URLs costs network + disk I/O instead of N decoded
|
|
113
|
+
// full-resolution bitmaps parked in the memory cache (the default
|
|
114
|
+
// `.memoryCache` destination). The image is decoded — at the requested
|
|
115
|
+
// target size — only when a loadImage actually displays it.
|
|
116
|
+
private static let sharedPrefetcher = ImagePrefetcher(
|
|
117
|
+
pipeline: sharedPipeline,
|
|
118
|
+
destination: .diskCache
|
|
119
|
+
)
|
|
102
120
|
|
|
103
121
|
private var pipeline: ImagePipeline { Self.sharedPipeline }
|
|
104
122
|
private var prefetcher: ImagePrefetcher { Self.sharedPrefetcher }
|
|
@@ -133,13 +151,21 @@ class HybridNitroImagePipeline: HybridNitroImagePipelineSpec {
|
|
|
133
151
|
}
|
|
134
152
|
}
|
|
135
153
|
|
|
154
|
+
/// The target size in pixels, or `nil` when no (valid) resize was requested.
|
|
155
|
+
private static func resizeSize(for options: Options?) -> CGSize? {
|
|
156
|
+
guard let resize = options?.resize, resize.width > 0, resize.height > 0 else {
|
|
157
|
+
return nil
|
|
158
|
+
}
|
|
159
|
+
return CGSize(width: resize.width, height: resize.height)
|
|
160
|
+
}
|
|
161
|
+
|
|
136
162
|
private static func processors(for options: Options?) -> [any ImageProcessing] {
|
|
137
163
|
var processors: [any ImageProcessing] = []
|
|
138
164
|
// Resize first: blur sigma and corner radii are defined in pixels
|
|
139
165
|
// of the bitmap they run on, so they must see the final size.
|
|
140
|
-
if let
|
|
166
|
+
if let size = resizeSize(for: options) {
|
|
141
167
|
processors.append(ImageProcessors.Resize(
|
|
142
|
-
size:
|
|
168
|
+
size: size,
|
|
143
169
|
unit: .pixels,
|
|
144
170
|
contentMode: .aspectFill,
|
|
145
171
|
crop: true,
|
|
@@ -161,11 +187,24 @@ class HybridNitroImagePipeline: HybridNitroImagePipelineSpec {
|
|
|
161
187
|
throw RuntimeError.error(withMessage: "Invalid URL: \(url)")
|
|
162
188
|
}
|
|
163
189
|
|
|
164
|
-
|
|
190
|
+
var imgRequest = ImageRequest(
|
|
165
191
|
url: imageUrl,
|
|
166
192
|
processors: Self.processors(for: options),
|
|
167
193
|
options: Self.cacheOptions(for: options?.cache)
|
|
168
194
|
)
|
|
195
|
+
// With a target size known, decode near it (aspect-fill, so the
|
|
196
|
+
// decoded image always covers the target) instead of at full
|
|
197
|
+
// resolution — a 48 MP photo displayed as a 300 pt card would
|
|
198
|
+
// otherwise decompress to ~190 MB before Resize shrinks it.
|
|
199
|
+
// Matches Android, where the request's size() drives subsampling;
|
|
200
|
+
// the exact size and crop still come from the Resize processor.
|
|
201
|
+
if let size = Self.resizeSize(for: options) {
|
|
202
|
+
imgRequest.thumbnail = ImageRequest.ThumbnailOptions(
|
|
203
|
+
size: size,
|
|
204
|
+
unit: .pixels,
|
|
205
|
+
contentMode: .aspectFill
|
|
206
|
+
)
|
|
207
|
+
}
|
|
169
208
|
|
|
170
209
|
let image = try await self.pipeline.image(for: imgRequest)
|
|
171
210
|
return HybridImage(uiImage: image)
|
|
@@ -189,6 +228,22 @@ class HybridNitroImagePipeline: HybridNitroImagePipelineSpec {
|
|
|
189
228
|
}
|
|
190
229
|
}
|
|
191
230
|
|
|
231
|
+
func setMemoryCacheLimit(bytes: Double) throws {
|
|
232
|
+
guard bytes >= 0, bytes.isFinite else {
|
|
233
|
+
throw RuntimeError.error(
|
|
234
|
+
withMessage: "Memory cache limit must be a non-negative, finite number of bytes (got \(bytes))"
|
|
235
|
+
)
|
|
236
|
+
}
|
|
237
|
+
guard let cache = pipeline.configuration.imageCache as? ImageCache else { return }
|
|
238
|
+
// Double(Int.max) rounds up to 2^63, so Int(_:) of the clamped value
|
|
239
|
+
// would trap; branch instead of min-ing.
|
|
240
|
+
let limit = bytes >= Double(Int.max) ? Int.max : Int(bytes)
|
|
241
|
+
cache.costLimit = limit
|
|
242
|
+
// Setting the limit only affects future inserts; evict down to it now
|
|
243
|
+
// so the call frees memory immediately.
|
|
244
|
+
cache.trim(toCost: limit)
|
|
245
|
+
}
|
|
246
|
+
|
|
192
247
|
func clearCache() throws -> Promise<Void> {
|
|
193
248
|
return Promise.async {
|
|
194
249
|
self.pipeline.cache.removeAll()
|
|
@@ -73,6 +73,16 @@ export interface NitroImagePipeline extends HybridObject<{
|
|
|
73
73
|
* {@linkcode Options.blur}.
|
|
74
74
|
*/
|
|
75
75
|
gaussianBlur(image: Image, radius: number): Promise<Image>;
|
|
76
|
+
/**
|
|
77
|
+
* Caps the in-memory cache of decoded bitmaps at `bytes`, evicting
|
|
78
|
+
* least-recently-used entries immediately if it is currently larger. Pass
|
|
79
|
+
* `0` to disable in-memory caching entirely (the disk cache still works).
|
|
80
|
+
*
|
|
81
|
+
* Defaults: 128 MB on iOS, 25% of the app's memory class on Android. The
|
|
82
|
+
* cache trades RAM for instant re-display; lower it (or use
|
|
83
|
+
* `cache: 'disk'` per request) in memory-constrained apps.
|
|
84
|
+
*/
|
|
85
|
+
setMemoryCacheLimit(bytes: number): void;
|
|
76
86
|
clearCache(): Promise<void>;
|
|
77
87
|
}
|
|
78
88
|
//# sourceMappingURL=nitro-image-toolkit.nitro.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nitro-image-toolkit.nitro.d.ts","sourceRoot":"","sources":["../../../../src/specs/nitro-image-toolkit.nitro.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE/D,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;AAErD;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,OAAO,GAAG;IACpB;;;;;;;;;;;OAWG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB;;;;;;;;;;;;;OAaG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC;IACpC;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB,CAAC;AAEF,MAAM,WAAW,kBAAmB,SAAQ,YAAY,CAAC;IACvD,GAAG,EAAE,OAAO,CAAC;IACb,OAAO,EAAE,QAAQ,CAAC;CACnB,CAAC;IACA,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAC1D,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C;;;;OAIG;IACH,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAG3D,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7B"}
|
|
1
|
+
{"version":3,"file":"nitro-image-toolkit.nitro.d.ts","sourceRoot":"","sources":["../../../../src/specs/nitro-image-toolkit.nitro.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE/D,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;AAErD;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,OAAO,GAAG;IACpB;;;;;;;;;;;OAWG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB;;;;;;;;;;;;;OAaG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC;IACpC;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB,CAAC;AAEF,MAAM,WAAW,kBAAmB,SAAQ,YAAY,CAAC;IACvD,GAAG,EAAE,OAAO,CAAC;IACb,OAAO,EAAE,QAAQ,CAAC;CACnB,CAAC;IACA,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAC1D,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C;;;;OAIG;IACH,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAG3D;;;;;;;;OAQG;IACH,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAEzC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7B"}
|
|
@@ -142,6 +142,10 @@ namespace margelo::nitro::nitroimagepipeline {
|
|
|
142
142
|
return __promise;
|
|
143
143
|
}();
|
|
144
144
|
}
|
|
145
|
+
void JHybridNitroImagePipelineSpec::setMemoryCacheLimit(double bytes) {
|
|
146
|
+
static const auto method = _javaPart->javaClassStatic()->getMethod<void(double /* bytes */)>("setMemoryCacheLimit");
|
|
147
|
+
method(_javaPart, bytes);
|
|
148
|
+
}
|
|
145
149
|
std::shared_ptr<Promise<void>> JHybridNitroImagePipelineSpec::clearCache() {
|
|
146
150
|
static const auto method = _javaPart->javaClassStatic()->getMethod<jni::local_ref<JPromise::javaobject>()>("clearCache");
|
|
147
151
|
auto __result = method(_javaPart);
|
|
@@ -58,6 +58,7 @@ namespace margelo::nitro::nitroimagepipeline {
|
|
|
58
58
|
std::shared_ptr<Promise<void>> preLoadImage(const std::string& url) override;
|
|
59
59
|
std::shared_ptr<Promise<void>> preLoadImages(const std::vector<std::string>& urls) override;
|
|
60
60
|
std::shared_ptr<Promise<std::shared_ptr<margelo::nitro::image::HybridImageSpec>>> gaussianBlur(const std::shared_ptr<margelo::nitro::image::HybridImageSpec>& image, double radius) override;
|
|
61
|
+
void setMemoryCacheLimit(double bytes) override;
|
|
61
62
|
std::shared_ptr<Promise<void>> clearCache() override;
|
|
62
63
|
|
|
63
64
|
private:
|
|
@@ -47,6 +47,10 @@ abstract class HybridNitroImagePipelineSpec: HybridObject() {
|
|
|
47
47
|
@Keep
|
|
48
48
|
abstract fun gaussianBlur(image: com.margelo.nitro.image.HybridImageSpec, radius: Double): Promise<com.margelo.nitro.image.HybridImageSpec>
|
|
49
49
|
|
|
50
|
+
@DoNotStrip
|
|
51
|
+
@Keep
|
|
52
|
+
abstract fun setMemoryCacheLimit(bytes: Double): Unit
|
|
53
|
+
|
|
50
54
|
@DoNotStrip
|
|
51
55
|
@Keep
|
|
52
56
|
abstract fun clearCache(): Promise<Unit>
|
|
@@ -297,5 +297,14 @@ namespace margelo::nitro::nitroimagepipeline::bridge::swift {
|
|
|
297
297
|
inline Result_std__shared_ptr_Promise_void___ create_Result_std__shared_ptr_Promise_void___(const std::exception_ptr& error) noexcept {
|
|
298
298
|
return Result<std::shared_ptr<Promise<void>>>::withError(error);
|
|
299
299
|
}
|
|
300
|
+
|
|
301
|
+
// pragma MARK: Result<void>
|
|
302
|
+
using Result_void_ = Result<void>;
|
|
303
|
+
inline Result_void_ create_Result_void_() noexcept {
|
|
304
|
+
return Result<void>::withValue();
|
|
305
|
+
}
|
|
306
|
+
inline Result_void_ create_Result_void_(const std::exception_ptr& error) noexcept {
|
|
307
|
+
return Result<void>::withError(error);
|
|
308
|
+
}
|
|
300
309
|
|
|
301
310
|
} // namespace margelo::nitro::nitroimagepipeline::bridge::swift
|
|
@@ -117,6 +117,12 @@ namespace margelo::nitro::nitroimagepipeline {
|
|
|
117
117
|
auto __value = std::move(__result.value());
|
|
118
118
|
return __value;
|
|
119
119
|
}
|
|
120
|
+
inline void setMemoryCacheLimit(double bytes) override {
|
|
121
|
+
auto __result = _swiftPart.setMemoryCacheLimit(std::forward<decltype(bytes)>(bytes));
|
|
122
|
+
if (__result.hasError()) [[unlikely]] {
|
|
123
|
+
std::rethrow_exception(__result.error());
|
|
124
|
+
}
|
|
125
|
+
}
|
|
120
126
|
inline std::shared_ptr<Promise<void>> clearCache() override {
|
|
121
127
|
auto __result = _swiftPart.clearCache();
|
|
122
128
|
if (__result.hasError()) [[unlikely]] {
|
|
@@ -18,6 +18,7 @@ public protocol HybridNitroImagePipelineSpec_protocol: HybridObject {
|
|
|
18
18
|
func preLoadImage(url: String) throws -> Promise<Void>
|
|
19
19
|
func preLoadImages(urls: [String]) throws -> Promise<Void>
|
|
20
20
|
func gaussianBlur(image: (any HybridImageSpec), radius: Double) throws -> Promise<(any HybridImageSpec)>
|
|
21
|
+
func setMemoryCacheLimit(bytes: Double) throws -> Void
|
|
21
22
|
func clearCache() throws -> Promise<Void>
|
|
22
23
|
}
|
|
23
24
|
|
|
@@ -211,6 +211,17 @@ open class HybridNitroImagePipelineSpec_cxx {
|
|
|
211
211
|
}
|
|
212
212
|
}
|
|
213
213
|
|
|
214
|
+
@inline(__always)
|
|
215
|
+
public final func setMemoryCacheLimit(bytes: Double) -> bridge.Result_void_ {
|
|
216
|
+
do {
|
|
217
|
+
try self.__implementation.setMemoryCacheLimit(bytes: bytes)
|
|
218
|
+
return bridge.create_Result_void_()
|
|
219
|
+
} catch (let __error) {
|
|
220
|
+
let __exceptionPtr = __error.toCpp()
|
|
221
|
+
return bridge.create_Result_void_(__exceptionPtr)
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
214
225
|
@inline(__always)
|
|
215
226
|
public final func clearCache() -> bridge.Result_std__shared_ptr_Promise_void___ {
|
|
216
227
|
do {
|
|
@@ -18,6 +18,7 @@ namespace margelo::nitro::nitroimagepipeline {
|
|
|
18
18
|
prototype.registerHybridMethod("preLoadImage", &HybridNitroImagePipelineSpec::preLoadImage);
|
|
19
19
|
prototype.registerHybridMethod("preLoadImages", &HybridNitroImagePipelineSpec::preLoadImages);
|
|
20
20
|
prototype.registerHybridMethod("gaussianBlur", &HybridNitroImagePipelineSpec::gaussianBlur);
|
|
21
|
+
prototype.registerHybridMethod("setMemoryCacheLimit", &HybridNitroImagePipelineSpec::setMemoryCacheLimit);
|
|
21
22
|
prototype.registerHybridMethod("clearCache", &HybridNitroImagePipelineSpec::clearCache);
|
|
22
23
|
});
|
|
23
24
|
}
|
|
@@ -61,6 +61,7 @@ namespace margelo::nitro::nitroimagepipeline {
|
|
|
61
61
|
virtual std::shared_ptr<Promise<void>> preLoadImage(const std::string& url) = 0;
|
|
62
62
|
virtual std::shared_ptr<Promise<void>> preLoadImages(const std::vector<std::string>& urls) = 0;
|
|
63
63
|
virtual std::shared_ptr<Promise<std::shared_ptr<margelo::nitro::image::HybridImageSpec>>> gaussianBlur(const std::shared_ptr<margelo::nitro::image::HybridImageSpec>& image, double radius) = 0;
|
|
64
|
+
virtual void setMemoryCacheLimit(double bytes) = 0;
|
|
64
65
|
virtual std::shared_ptr<Promise<void>> clearCache() = 0;
|
|
65
66
|
|
|
66
67
|
protected:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-nitro-image-pipeline",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "High-performance image loading, caching, and processing for React Native, built with Nitro Modules",
|
|
5
5
|
"main": "./lib/commonjs/index.js",
|
|
6
6
|
"module": "./lib/module/index.js",
|
|
@@ -80,5 +80,16 @@ export interface NitroImagePipeline extends HybridObject<{
|
|
|
80
80
|
gaussianBlur(image: Image, radius: number): Promise<Image>;
|
|
81
81
|
// Future: brightness, saturation, tint, etc.
|
|
82
82
|
|
|
83
|
+
/**
|
|
84
|
+
* Caps the in-memory cache of decoded bitmaps at `bytes`, evicting
|
|
85
|
+
* least-recently-used entries immediately if it is currently larger. Pass
|
|
86
|
+
* `0` to disable in-memory caching entirely (the disk cache still works).
|
|
87
|
+
*
|
|
88
|
+
* Defaults: 128 MB on iOS, 25% of the app's memory class on Android. The
|
|
89
|
+
* cache trades RAM for instant re-display; lower it (or use
|
|
90
|
+
* `cache: 'disk'` per request) in memory-constrained apps.
|
|
91
|
+
*/
|
|
92
|
+
setMemoryCacheLimit(bytes: number): void;
|
|
93
|
+
|
|
83
94
|
clearCache(): Promise<void>;
|
|
84
95
|
}
|