react-native-nitro-image-pipeline 1.3.2 → 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 +31 -6
- package/android/src/main/java/com/margelo/nitro/nitroimagepipeline/HybridNitroImagePipeline.kt +12 -0
- package/ios/HybridNitroImagePipeline.swift +16 -0
- 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
|
@@ -306,6 +306,20 @@ RenderScript's true Gaussian, downscaling first when sigma exceeds the single-pa
|
|
|
306
306
|
~10.6px and compensating the radius so the result is unchanged. Both clamp at the edges, so blurred
|
|
307
307
|
images keep their borders instead of fading out.
|
|
308
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
|
+
|
|
309
323
|
### `clearCache()`
|
|
310
324
|
|
|
311
325
|
Removes all cached images from memory and disk. Returns `Promise<void>` that resolves once both caches are cleared.
|
|
@@ -320,12 +334,23 @@ The pipeline is set up so RAM scales with what you display, not with what you do
|
|
|
320
334
|
48 MP photo decompresses to ~190 MB of bitmap no matter how small you display it.
|
|
321
335
|
- **Prefetching stores bytes, not bitmaps.** `preLoadImage(s)` writes the download to the disk
|
|
322
336
|
cache and skips decoding entirely.
|
|
323
|
-
- **The in-memory cache is capped** (128 MB on iOS, 25% of the app's memory
|
|
324
|
-
holds decoded bitmaps for instant re-display
|
|
325
|
-
response to memory warnings and backgrounding. Memory
|
|
326
|
-
a plateau at the cap is expected and evictable, not a
|
|
327
|
-
|
|
328
|
-
everything.
|
|
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.
|
|
329
354
|
|
|
330
355
|
## Upgrading from 0.3.x
|
|
331
356
|
|
package/android/src/main/java/com/margelo/nitro/nitroimagepipeline/HybridNitroImagePipeline.kt
CHANGED
|
@@ -157,6 +157,18 @@ class HybridNitroImagePipeline : HybridNitroImagePipelineSpec() {
|
|
|
157
157
|
}
|
|
158
158
|
}
|
|
159
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
|
+
|
|
160
172
|
override fun clearCache(): Promise<Unit> = Promise.async {
|
|
161
173
|
imageLoader.memoryCache?.clear()
|
|
162
174
|
// DiskCache.clear() does file I/O; keep it off the JS thread but await
|
|
@@ -228,6 +228,22 @@ class HybridNitroImagePipeline: HybridNitroImagePipelineSpec {
|
|
|
228
228
|
}
|
|
229
229
|
}
|
|
230
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
|
+
|
|
231
247
|
func clearCache() throws -> Promise<Void> {
|
|
232
248
|
return Promise.async {
|
|
233
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
|
}
|