react-native-nitro-image-pipeline 1.5.0 → 1.7.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 +142 -18
- package/android/src/main/java/com/margelo/nitro/nitroimagepipeline/HybridNitroImagePipeline.kt +72 -16
- package/android/src/main/java/com/margelo/nitro/nitroimagepipeline/PipelineImageLoader.kt +47 -8
- package/android/src/main/java/com/margelo/nitro/nitroimagepipeline/transform/FitGeometry.kt +104 -0
- package/android/src/main/java/com/margelo/nitro/nitroimagepipeline/transform/PipelineRoundedCornersTransformation.kt +103 -0
- package/android/src/main/java/com/margelo/nitro/nitroimagepipeline/transform/ResizeTransformation.kt +69 -16
- package/ios/FitResizeProcessor.swift +127 -0
- package/ios/HybridNitroImagePipeline.swift +88 -24
- package/ios/PipelineImageLoader.swift +108 -18
- package/lib/commonjs/NativePipelineImage.js +20 -4
- package/lib/commonjs/NativePipelineImage.js.map +1 -1
- package/lib/commonjs/PipelineImage.js +13 -1
- package/lib/commonjs/PipelineImage.js.map +1 -1
- package/lib/commonjs/index.js +13 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/resizeForStyle.js +3 -1
- package/lib/commonjs/resizeForStyle.js.map +1 -1
- package/lib/commonjs/resolveImageSource.js +89 -0
- package/lib/commonjs/resolveImageSource.js.map +1 -0
- package/lib/commonjs/useImage.js +14 -6
- package/lib/commonjs/useImage.js.map +1 -1
- package/lib/commonjs/usePipelineImageLoader.js +114 -11
- package/lib/commonjs/usePipelineImageLoader.js.map +1 -1
- package/lib/module/NativePipelineImage.js +20 -4
- package/lib/module/NativePipelineImage.js.map +1 -1
- package/lib/module/PipelineImage.js +13 -1
- package/lib/module/PipelineImage.js.map +1 -1
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/resizeForStyle.js +3 -1
- package/lib/module/resizeForStyle.js.map +1 -1
- package/lib/module/resolveImageSource.js +83 -0
- package/lib/module/resolveImageSource.js.map +1 -0
- package/lib/module/useImage.js +14 -6
- package/lib/module/useImage.js.map +1 -1
- package/lib/module/usePipelineImageLoader.js +115 -12
- package/lib/module/usePipelineImageLoader.js.map +1 -1
- package/lib/typescript/src/NativePipelineImage.d.ts +51 -5
- package/lib/typescript/src/NativePipelineImage.d.ts.map +1 -1
- package/lib/typescript/src/PipelineImage.d.ts +35 -3
- package/lib/typescript/src/PipelineImage.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +2 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/resizeForStyle.d.ts +3 -1
- package/lib/typescript/src/resizeForStyle.d.ts.map +1 -1
- package/lib/typescript/src/resolveImageSource.d.ts +56 -0
- package/lib/typescript/src/resolveImageSource.d.ts.map +1 -0
- package/lib/typescript/src/specs/nitro-image-toolkit.nitro.d.ts +95 -8
- package/lib/typescript/src/specs/nitro-image-toolkit.nitro.d.ts.map +1 -1
- package/lib/typescript/src/useImage.d.ts +13 -6
- package/lib/typescript/src/useImage.d.ts.map +1 -1
- package/lib/typescript/src/usePipelineImageLoader.d.ts +7 -3
- package/lib/typescript/src/usePipelineImageLoader.d.ts.map +1 -1
- package/nitrogen/generated/android/NitroImagePipelineOnLoad.cpp +4 -0
- package/nitrogen/generated/android/c++/JFunc_void_double_double.hpp +75 -0
- package/nitrogen/generated/android/c++/JFunc_void_std__string.hpp +76 -0
- package/nitrogen/generated/android/c++/JHybridNitroImagePipelineSpec.cpp +8 -0
- package/nitrogen/generated/android/c++/JOptions.hpp +2 -0
- package/nitrogen/generated/android/c++/JResizeFit.hpp +64 -0
- package/nitrogen/generated/android/c++/JResizeOptions.hpp +14 -4
- package/nitrogen/generated/android/c++/JViewOptions.hpp +42 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroimagepipeline/Func_void_double_double.kt +78 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroimagepipeline/Func_void_std__string.kt +78 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroimagepipeline/ResizeFit.kt +25 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroimagepipeline/ResizeOptions.kt +14 -4
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroimagepipeline/ViewOptions.kt +29 -5
- package/nitrogen/generated/ios/NitroImagePipeline-Swift-Cxx-Bridge.cpp +16 -0
- package/nitrogen/generated/ios/NitroImagePipeline-Swift-Cxx-Bridge.hpp +107 -0
- package/nitrogen/generated/ios/NitroImagePipeline-Swift-Cxx-Umbrella.hpp +4 -0
- package/nitrogen/generated/ios/c++/HybridNitroImagePipelineSpecSwift.hpp +4 -0
- package/nitrogen/generated/ios/swift/Func_void_double_double.swift +46 -0
- package/nitrogen/generated/ios/swift/Func_void_std__string.swift +46 -0
- package/nitrogen/generated/ios/swift/ResizeFit.swift +48 -0
- package/nitrogen/generated/ios/swift/ResizeOptions.swift +31 -2
- package/nitrogen/generated/ios/swift/ViewOptions.swift +82 -1
- package/nitrogen/generated/shared/c++/ResizeFit.hpp +84 -0
- package/nitrogen/generated/shared/c++/ResizeOptions.hpp +14 -4
- package/nitrogen/generated/shared/c++/ViewOptions.hpp +24 -3
- package/package.json +1 -1
- package/src/NativePipelineImage.tsx +75 -6
- package/src/PipelineImage.tsx +46 -3
- package/src/index.ts +6 -0
- package/src/resizeForStyle.ts +3 -1
- package/src/resolveImageSource.ts +83 -0
- package/src/specs/nitro-image-toolkit.nitro.ts +96 -8
- package/src/useImage.ts +38 -17
- package/src/usePipelineImageLoader.ts +126 -11
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
///
|
|
2
|
+
/// ResizeFit.hpp
|
|
3
|
+
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
|
+
/// https://github.com/mrousavy/nitro
|
|
5
|
+
/// Copyright © Marc Rousavy @ Margelo
|
|
6
|
+
///
|
|
7
|
+
|
|
8
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
#if __has_include(<NitroModules/NitroHash.hpp>)
|
|
11
|
+
#include <NitroModules/NitroHash.hpp>
|
|
12
|
+
#else
|
|
13
|
+
#error NitroModules cannot be found! Are you sure you installed NitroModules properly?
|
|
14
|
+
#endif
|
|
15
|
+
#if __has_include(<NitroModules/JSIConverter.hpp>)
|
|
16
|
+
#include <NitroModules/JSIConverter.hpp>
|
|
17
|
+
#else
|
|
18
|
+
#error NitroModules cannot be found! Are you sure you installed NitroModules properly?
|
|
19
|
+
#endif
|
|
20
|
+
#if __has_include(<NitroModules/NitroDefines.hpp>)
|
|
21
|
+
#include <NitroModules/NitroDefines.hpp>
|
|
22
|
+
#else
|
|
23
|
+
#error NitroModules cannot be found! Are you sure you installed NitroModules properly?
|
|
24
|
+
#endif
|
|
25
|
+
|
|
26
|
+
namespace margelo::nitro::nitroimagepipeline {
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* An enum which can be represented as a JavaScript union (ResizeFit).
|
|
30
|
+
*/
|
|
31
|
+
enum class ResizeFit {
|
|
32
|
+
COVER SWIFT_NAME(cover) = 0,
|
|
33
|
+
CONTAIN SWIFT_NAME(contain) = 1,
|
|
34
|
+
STRETCH SWIFT_NAME(stretch) = 2,
|
|
35
|
+
CENTER SWIFT_NAME(center) = 3,
|
|
36
|
+
} CLOSED_ENUM;
|
|
37
|
+
|
|
38
|
+
} // namespace margelo::nitro::nitroimagepipeline
|
|
39
|
+
|
|
40
|
+
namespace margelo::nitro {
|
|
41
|
+
|
|
42
|
+
// C++ ResizeFit <> JS ResizeFit (union)
|
|
43
|
+
template <>
|
|
44
|
+
struct JSIConverter<margelo::nitro::nitroimagepipeline::ResizeFit> final {
|
|
45
|
+
static inline margelo::nitro::nitroimagepipeline::ResizeFit fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
|
|
46
|
+
std::string unionValue = JSIConverter<std::string>::fromJSI(runtime, arg);
|
|
47
|
+
switch (hashString(unionValue.c_str(), unionValue.size())) {
|
|
48
|
+
case hashString("cover"): return margelo::nitro::nitroimagepipeline::ResizeFit::COVER;
|
|
49
|
+
case hashString("contain"): return margelo::nitro::nitroimagepipeline::ResizeFit::CONTAIN;
|
|
50
|
+
case hashString("stretch"): return margelo::nitro::nitroimagepipeline::ResizeFit::STRETCH;
|
|
51
|
+
case hashString("center"): return margelo::nitro::nitroimagepipeline::ResizeFit::CENTER;
|
|
52
|
+
default: [[unlikely]]
|
|
53
|
+
throw std::invalid_argument("Cannot convert \"" + unionValue + "\" to enum ResizeFit - invalid value!");
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
static inline jsi::Value toJSI(jsi::Runtime& runtime, margelo::nitro::nitroimagepipeline::ResizeFit arg) {
|
|
57
|
+
switch (arg) {
|
|
58
|
+
case margelo::nitro::nitroimagepipeline::ResizeFit::COVER: return JSIConverter<std::string>::toJSI(runtime, "cover");
|
|
59
|
+
case margelo::nitro::nitroimagepipeline::ResizeFit::CONTAIN: return JSIConverter<std::string>::toJSI(runtime, "contain");
|
|
60
|
+
case margelo::nitro::nitroimagepipeline::ResizeFit::STRETCH: return JSIConverter<std::string>::toJSI(runtime, "stretch");
|
|
61
|
+
case margelo::nitro::nitroimagepipeline::ResizeFit::CENTER: return JSIConverter<std::string>::toJSI(runtime, "center");
|
|
62
|
+
default: [[unlikely]]
|
|
63
|
+
throw std::invalid_argument("Cannot convert ResizeFit to JS - invalid value: "
|
|
64
|
+
+ std::to_string(static_cast<int>(arg)) + "!");
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
|
|
68
|
+
if (!value.isString()) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
std::string unionValue = JSIConverter<std::string>::fromJSI(runtime, value);
|
|
72
|
+
switch (hashString(unionValue.c_str(), unionValue.size())) {
|
|
73
|
+
case hashString("cover"):
|
|
74
|
+
case hashString("contain"):
|
|
75
|
+
case hashString("stretch"):
|
|
76
|
+
case hashString("center"):
|
|
77
|
+
return true;
|
|
78
|
+
default:
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
} // namespace margelo::nitro
|
|
@@ -28,9 +28,11 @@
|
|
|
28
28
|
#error NitroModules cannot be found! Are you sure you installed NitroModules properly?
|
|
29
29
|
#endif
|
|
30
30
|
|
|
31
|
+
// Forward declaration of `ResizeFit` to properly resolve imports.
|
|
32
|
+
namespace margelo::nitro::nitroimagepipeline { enum class ResizeFit; }
|
|
31
33
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
#include "ResizeFit.hpp"
|
|
35
|
+
#include <optional>
|
|
34
36
|
|
|
35
37
|
namespace margelo::nitro::nitroimagepipeline {
|
|
36
38
|
|
|
@@ -41,10 +43,12 @@ namespace margelo::nitro::nitroimagepipeline {
|
|
|
41
43
|
public:
|
|
42
44
|
double width SWIFT_PRIVATE;
|
|
43
45
|
double height SWIFT_PRIVATE;
|
|
46
|
+
std::optional<ResizeFit> fit SWIFT_PRIVATE;
|
|
47
|
+
std::optional<bool> allowUpscale SWIFT_PRIVATE;
|
|
44
48
|
|
|
45
49
|
public:
|
|
46
50
|
ResizeOptions() = default;
|
|
47
|
-
explicit ResizeOptions(double width, double height): width(width), height(height) {}
|
|
51
|
+
explicit ResizeOptions(double width, double height, std::optional<ResizeFit> fit, std::optional<bool> allowUpscale): width(width), height(height), fit(fit), allowUpscale(allowUpscale) {}
|
|
48
52
|
|
|
49
53
|
public:
|
|
50
54
|
friend bool operator==(const ResizeOptions& lhs, const ResizeOptions& rhs) = default;
|
|
@@ -61,13 +65,17 @@ namespace margelo::nitro {
|
|
|
61
65
|
jsi::Object obj = arg.asObject(runtime);
|
|
62
66
|
return margelo::nitro::nitroimagepipeline::ResizeOptions(
|
|
63
67
|
JSIConverter<double>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "width"))),
|
|
64
|
-
JSIConverter<double>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "height")))
|
|
68
|
+
JSIConverter<double>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "height"))),
|
|
69
|
+
JSIConverter<std::optional<margelo::nitro::nitroimagepipeline::ResizeFit>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "fit"))),
|
|
70
|
+
JSIConverter<std::optional<bool>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "allowUpscale")))
|
|
65
71
|
);
|
|
66
72
|
}
|
|
67
73
|
static inline jsi::Value toJSI(jsi::Runtime& runtime, const margelo::nitro::nitroimagepipeline::ResizeOptions& arg) {
|
|
68
74
|
jsi::Object obj(runtime);
|
|
69
75
|
obj.setProperty(runtime, PropNameIDCache::get(runtime, "width"), JSIConverter<double>::toJSI(runtime, arg.width));
|
|
70
76
|
obj.setProperty(runtime, PropNameIDCache::get(runtime, "height"), JSIConverter<double>::toJSI(runtime, arg.height));
|
|
77
|
+
obj.setProperty(runtime, PropNameIDCache::get(runtime, "fit"), JSIConverter<std::optional<margelo::nitro::nitroimagepipeline::ResizeFit>>::toJSI(runtime, arg.fit));
|
|
78
|
+
obj.setProperty(runtime, PropNameIDCache::get(runtime, "allowUpscale"), JSIConverter<std::optional<bool>>::toJSI(runtime, arg.allowUpscale));
|
|
71
79
|
return obj;
|
|
72
80
|
}
|
|
73
81
|
static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
|
|
@@ -80,6 +88,8 @@ namespace margelo::nitro {
|
|
|
80
88
|
}
|
|
81
89
|
if (!JSIConverter<double>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "width")))) return false;
|
|
82
90
|
if (!JSIConverter<double>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "height")))) return false;
|
|
91
|
+
if (!JSIConverter<std::optional<margelo::nitro::nitroimagepipeline::ResizeFit>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "fit")))) return false;
|
|
92
|
+
if (!JSIConverter<std::optional<bool>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "allowUpscale")))) return false;
|
|
83
93
|
return true;
|
|
84
94
|
}
|
|
85
95
|
};
|
|
@@ -34,12 +34,17 @@ namespace margelo::nitro::nitroimagepipeline { enum class CacheOption; }
|
|
|
34
34
|
namespace margelo::nitro::nitroimagepipeline { struct CornerRadii; }
|
|
35
35
|
// Forward declaration of `ResizeOptions` to properly resolve imports.
|
|
36
36
|
namespace margelo::nitro::nitroimagepipeline { struct ResizeOptions; }
|
|
37
|
+
// Forward declaration of `ResizeFit` to properly resolve imports.
|
|
38
|
+
namespace margelo::nitro::nitroimagepipeline { enum class ResizeFit; }
|
|
37
39
|
|
|
38
40
|
#include <optional>
|
|
39
41
|
#include "CacheOption.hpp"
|
|
40
42
|
#include "CornerRadii.hpp"
|
|
41
43
|
#include <variant>
|
|
42
44
|
#include "ResizeOptions.hpp"
|
|
45
|
+
#include "ResizeFit.hpp"
|
|
46
|
+
#include <functional>
|
|
47
|
+
#include <string>
|
|
43
48
|
|
|
44
49
|
namespace margelo::nitro::nitroimagepipeline {
|
|
45
50
|
|
|
@@ -52,13 +57,17 @@ namespace margelo::nitro::nitroimagepipeline {
|
|
|
52
57
|
std::optional<CacheOption> cache SWIFT_PRIVATE;
|
|
53
58
|
std::optional<std::variant<double, CornerRadii>> cornerRadius SWIFT_PRIVATE;
|
|
54
59
|
std::optional<ResizeOptions> resize SWIFT_PRIVATE;
|
|
60
|
+
std::optional<ResizeFit> fit SWIFT_PRIVATE;
|
|
61
|
+
std::optional<bool> allowUpscale SWIFT_PRIVATE;
|
|
62
|
+
std::optional<std::function<void(double /* width */, double /* height */)>> onLoad SWIFT_PRIVATE;
|
|
63
|
+
std::optional<std::function<void(const std::string& /* message */)>> onError SWIFT_PRIVATE;
|
|
55
64
|
|
|
56
65
|
public:
|
|
57
66
|
ViewOptions() = default;
|
|
58
|
-
explicit ViewOptions(std::optional<double> blur, std::optional<CacheOption> cache, std::optional<std::variant<double, CornerRadii>> cornerRadius, std::optional<ResizeOptions> resize): blur(blur), cache(cache), cornerRadius(cornerRadius), resize(resize) {}
|
|
67
|
+
explicit ViewOptions(std::optional<double> blur, std::optional<CacheOption> cache, std::optional<std::variant<double, CornerRadii>> cornerRadius, std::optional<ResizeOptions> resize, std::optional<ResizeFit> fit, std::optional<bool> allowUpscale, std::optional<std::function<void(double /* width */, double /* height */)>> onLoad, std::optional<std::function<void(const std::string& /* message */)>> onError): blur(blur), cache(cache), cornerRadius(cornerRadius), resize(resize), fit(fit), allowUpscale(allowUpscale), onLoad(onLoad), onError(onError) {}
|
|
59
68
|
|
|
60
69
|
public:
|
|
61
|
-
|
|
70
|
+
// ViewOptions is not equatable because these properties are not equatable: onLoad, onError
|
|
62
71
|
};
|
|
63
72
|
|
|
64
73
|
} // namespace margelo::nitro::nitroimagepipeline
|
|
@@ -74,7 +83,11 @@ namespace margelo::nitro {
|
|
|
74
83
|
JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "blur"))),
|
|
75
84
|
JSIConverter<std::optional<margelo::nitro::nitroimagepipeline::CacheOption>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "cache"))),
|
|
76
85
|
JSIConverter<std::optional<std::variant<double, margelo::nitro::nitroimagepipeline::CornerRadii>>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "cornerRadius"))),
|
|
77
|
-
JSIConverter<std::optional<margelo::nitro::nitroimagepipeline::ResizeOptions>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "resize")))
|
|
86
|
+
JSIConverter<std::optional<margelo::nitro::nitroimagepipeline::ResizeOptions>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "resize"))),
|
|
87
|
+
JSIConverter<std::optional<margelo::nitro::nitroimagepipeline::ResizeFit>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "fit"))),
|
|
88
|
+
JSIConverter<std::optional<bool>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "allowUpscale"))),
|
|
89
|
+
JSIConverter<std::optional<std::function<void(double, double)>>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "onLoad"))),
|
|
90
|
+
JSIConverter<std::optional<std::function<void(const std::string&)>>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "onError")))
|
|
78
91
|
);
|
|
79
92
|
}
|
|
80
93
|
static inline jsi::Value toJSI(jsi::Runtime& runtime, const margelo::nitro::nitroimagepipeline::ViewOptions& arg) {
|
|
@@ -83,6 +96,10 @@ namespace margelo::nitro {
|
|
|
83
96
|
obj.setProperty(runtime, PropNameIDCache::get(runtime, "cache"), JSIConverter<std::optional<margelo::nitro::nitroimagepipeline::CacheOption>>::toJSI(runtime, arg.cache));
|
|
84
97
|
obj.setProperty(runtime, PropNameIDCache::get(runtime, "cornerRadius"), JSIConverter<std::optional<std::variant<double, margelo::nitro::nitroimagepipeline::CornerRadii>>>::toJSI(runtime, arg.cornerRadius));
|
|
85
98
|
obj.setProperty(runtime, PropNameIDCache::get(runtime, "resize"), JSIConverter<std::optional<margelo::nitro::nitroimagepipeline::ResizeOptions>>::toJSI(runtime, arg.resize));
|
|
99
|
+
obj.setProperty(runtime, PropNameIDCache::get(runtime, "fit"), JSIConverter<std::optional<margelo::nitro::nitroimagepipeline::ResizeFit>>::toJSI(runtime, arg.fit));
|
|
100
|
+
obj.setProperty(runtime, PropNameIDCache::get(runtime, "allowUpscale"), JSIConverter<std::optional<bool>>::toJSI(runtime, arg.allowUpscale));
|
|
101
|
+
obj.setProperty(runtime, PropNameIDCache::get(runtime, "onLoad"), JSIConverter<std::optional<std::function<void(double, double)>>>::toJSI(runtime, arg.onLoad));
|
|
102
|
+
obj.setProperty(runtime, PropNameIDCache::get(runtime, "onError"), JSIConverter<std::optional<std::function<void(const std::string&)>>>::toJSI(runtime, arg.onError));
|
|
86
103
|
return obj;
|
|
87
104
|
}
|
|
88
105
|
static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
|
|
@@ -97,6 +114,10 @@ namespace margelo::nitro {
|
|
|
97
114
|
if (!JSIConverter<std::optional<margelo::nitro::nitroimagepipeline::CacheOption>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "cache")))) return false;
|
|
98
115
|
if (!JSIConverter<std::optional<std::variant<double, margelo::nitro::nitroimagepipeline::CornerRadii>>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "cornerRadius")))) return false;
|
|
99
116
|
if (!JSIConverter<std::optional<margelo::nitro::nitroimagepipeline::ResizeOptions>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "resize")))) return false;
|
|
117
|
+
if (!JSIConverter<std::optional<margelo::nitro::nitroimagepipeline::ResizeFit>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "fit")))) return false;
|
|
118
|
+
if (!JSIConverter<std::optional<bool>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "allowUpscale")))) return false;
|
|
119
|
+
if (!JSIConverter<std::optional<std::function<void(double, double)>>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "onLoad")))) return false;
|
|
120
|
+
if (!JSIConverter<std::optional<std::function<void(const std::string&)>>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "onError")))) return false;
|
|
100
121
|
return true;
|
|
101
122
|
}
|
|
102
123
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-nitro-image-pipeline",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.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",
|
|
@@ -3,9 +3,11 @@ import type { HostComponent } from 'react-native';
|
|
|
3
3
|
import { NativeNitroImage } from 'react-native-nitro-image';
|
|
4
4
|
|
|
5
5
|
import { cornerRadiusForStyle } from './resizeForStyle';
|
|
6
|
+
import { type ImageSource, recyclingKeyFor } from './resolveImageSource';
|
|
6
7
|
import type {
|
|
7
8
|
CacheOption,
|
|
8
9
|
CornerRadii,
|
|
10
|
+
ResizeFit,
|
|
9
11
|
ResizeOptions,
|
|
10
12
|
} from './specs/nitro-image-toolkit.nitro';
|
|
11
13
|
import { usePipelineImageLoader } from './usePipelineImageLoader';
|
|
@@ -24,8 +26,12 @@ export interface NativePipelineImageProps extends Omit<
|
|
|
24
26
|
NativeImageProps,
|
|
25
27
|
'image'
|
|
26
28
|
> {
|
|
27
|
-
/**
|
|
28
|
-
|
|
29
|
+
/**
|
|
30
|
+
* The image to load through the pipeline: a URL string (`https://`,
|
|
31
|
+
* `file://`, an absolute path) or a `require()`d asset — see
|
|
32
|
+
* {@linkcode ImageSource}.
|
|
33
|
+
*/
|
|
34
|
+
url: ImageSource;
|
|
29
35
|
/**
|
|
30
36
|
* Gaussian blur sigma in **points** (density-independent), like
|
|
31
37
|
* `PipelineImage`. Applied natively with the screen scale.
|
|
@@ -46,6 +52,46 @@ export interface NativePipelineImageProps extends Omit<
|
|
|
46
52
|
* @default undefined (measure the view natively)
|
|
47
53
|
*/
|
|
48
54
|
resize?: ResizeOptions;
|
|
55
|
+
/**
|
|
56
|
+
* How the source is fitted into the measured view size when the bitmap is
|
|
57
|
+
* produced — see {@linkcode ResizeFit}. When omitted it follows
|
|
58
|
+
* `resizeMode`, like `PipelineImage`. Set this to decouple the two.
|
|
59
|
+
* @default undefined (derived from `resizeMode`, or `'cover'` if unset)
|
|
60
|
+
*/
|
|
61
|
+
fit?: ResizeFit;
|
|
62
|
+
/**
|
|
63
|
+
* `false` never enlarges a source smaller than the view when the
|
|
64
|
+
* **bitmap** is produced — see {@linkcode ResizeOptions.allowUpscale}: it
|
|
65
|
+
* stays at its own pixel size, so nothing is decoded or blurred larger
|
|
66
|
+
* than the source. The **view** still displays that bitmap per
|
|
67
|
+
* `resizeMode`, so `cover`/`contain`/`stretch` scale it up on screen (and
|
|
68
|
+
* a baked `blur`/`cornerRadius` with it); `resizeMode="center"` shows it
|
|
69
|
+
* pixel for pixel instead, on both platforms.
|
|
70
|
+
* @default true
|
|
71
|
+
*/
|
|
72
|
+
allowUpscale?: boolean;
|
|
73
|
+
/**
|
|
74
|
+
* Called when the view has displayed the image, with the size of the bitmap
|
|
75
|
+
* it displays in **pixels**.
|
|
76
|
+
*
|
|
77
|
+
* Unlike `PipelineImage`'s `onLoad` this doesn't hand you the `Image` — the
|
|
78
|
+
* bitmap stays native, which is the point of this component — and it means
|
|
79
|
+
* "the view is now showing this image" rather than firing exactly once: a
|
|
80
|
+
* recycled cell re-attaching calls it again, and a single view may call it
|
|
81
|
+
* more than once for the same image. Make it idempotent.
|
|
82
|
+
*
|
|
83
|
+
* Setting it means there is per-image JS work again; leave it unset and the
|
|
84
|
+
* component stays free of JS round trips.
|
|
85
|
+
*/
|
|
86
|
+
onLoad?: (width: number, height: number) => void;
|
|
87
|
+
/**
|
|
88
|
+
* Called when loading fails, with the underlying error's message. A load
|
|
89
|
+
* cancelled by the view detaching is not a failure and doesn't call this.
|
|
90
|
+
*
|
|
91
|
+
* Without it, failures on this component are silent — there is no `Image`
|
|
92
|
+
* and no promise to surface them.
|
|
93
|
+
*/
|
|
94
|
+
onError?: (message: string) => void;
|
|
49
95
|
}
|
|
50
96
|
|
|
51
97
|
/**
|
|
@@ -57,8 +103,9 @@ export interface NativePipelineImageProps extends Omit<
|
|
|
57
103
|
* the same pipeline and caches as `useImage`/`preLoadImage`.
|
|
58
104
|
*
|
|
59
105
|
* Compared to `PipelineImage`:
|
|
60
|
-
* -
|
|
61
|
-
* JS
|
|
106
|
+
* - `onLoad` reports the bitmap's pixel size rather than the `Image` itself,
|
|
107
|
+
* which never crosses into JS, and can fire more than once for a view. Use
|
|
108
|
+
* `PipelineImage` (or `useImage`) when you need the `Image`.
|
|
62
109
|
* - The bitmap is loaded once at the size the view first has; if the view is
|
|
63
110
|
* resized later, the bitmap scales with it instead of reloading.
|
|
64
111
|
* @example
|
|
@@ -74,25 +121,47 @@ export const NativePipelineImage = forwardRef<
|
|
|
74
121
|
NativePipelineImageRef,
|
|
75
122
|
NativePipelineImageProps
|
|
76
123
|
>(function NativePipelineImage(
|
|
77
|
-
{
|
|
124
|
+
{
|
|
125
|
+
url,
|
|
126
|
+
blur,
|
|
127
|
+
cornerRadius,
|
|
128
|
+
cache,
|
|
129
|
+
resize,
|
|
130
|
+
fit,
|
|
131
|
+
allowUpscale,
|
|
132
|
+
onLoad,
|
|
133
|
+
onError,
|
|
134
|
+
style,
|
|
135
|
+
resizeMode,
|
|
136
|
+
...viewProps
|
|
137
|
+
},
|
|
78
138
|
ref,
|
|
79
139
|
) {
|
|
80
140
|
// Same precedence as PipelineImage: an explicit prop wins over style.
|
|
81
141
|
const effectiveCornerRadius = cornerRadius ?? cornerRadiusForStyle(style);
|
|
142
|
+
// Inline arrows are fine here — the hook keeps the callbacks in a ref, so a
|
|
143
|
+
// new identity doesn't recreate the loader (which would reload the image).
|
|
82
144
|
const loader = usePipelineImageLoader(url, {
|
|
83
145
|
blur,
|
|
84
146
|
cornerRadius: effectiveCornerRadius,
|
|
85
147
|
cache,
|
|
86
148
|
resize,
|
|
149
|
+
// Same four values as the view's resizeMode; an explicit `fit` decouples
|
|
150
|
+
// them.
|
|
151
|
+
fit: fit ?? resizeMode,
|
|
152
|
+
allowUpscale,
|
|
153
|
+
onLoad,
|
|
154
|
+
onError,
|
|
87
155
|
});
|
|
88
156
|
|
|
89
157
|
return (
|
|
90
158
|
<NativeNitroImage
|
|
91
159
|
// Before the spread so a caller-provided recyclingKey wins.
|
|
92
|
-
recyclingKey={url}
|
|
160
|
+
recyclingKey={recyclingKeyFor(url)}
|
|
93
161
|
{...viewProps}
|
|
94
162
|
ref={ref}
|
|
95
163
|
style={style}
|
|
164
|
+
resizeMode={resizeMode}
|
|
96
165
|
image={loader}
|
|
97
166
|
/>
|
|
98
167
|
);
|
package/src/PipelineImage.tsx
CHANGED
|
@@ -17,9 +17,11 @@ import {
|
|
|
17
17
|
resizeForLayout,
|
|
18
18
|
resizeForStyle,
|
|
19
19
|
} from './resizeForStyle';
|
|
20
|
+
import type { ImageSource } from './resolveImageSource';
|
|
20
21
|
import type {
|
|
21
22
|
CacheOption,
|
|
22
23
|
CornerRadii,
|
|
24
|
+
ResizeFit,
|
|
23
25
|
ResizeOptions,
|
|
24
26
|
} from './specs/nitro-image-toolkit.nitro';
|
|
25
27
|
import { useImage } from './useImage';
|
|
@@ -35,8 +37,12 @@ type NativeImageProps = ReactProps<typeof NativeNitroImage>;
|
|
|
35
37
|
export type PipelineImageRef = ComponentRef<typeof NativeNitroImage>;
|
|
36
38
|
|
|
37
39
|
export interface PipelineImageProps extends Omit<NativeImageProps, 'image'> {
|
|
38
|
-
/**
|
|
39
|
-
|
|
40
|
+
/**
|
|
41
|
+
* The image to load through the pipeline: a URL string (`https://`,
|
|
42
|
+
* `file://`, an absolute path) or a `require()`d asset — see
|
|
43
|
+
* {@linkcode ImageSource}.
|
|
44
|
+
*/
|
|
45
|
+
url: ImageSource;
|
|
40
46
|
/**
|
|
41
47
|
* Gaussian blur sigma in **points** (density-independent). Unlike
|
|
42
48
|
* `useImage`/`loadImage`, where it is bitmap pixels, the component
|
|
@@ -57,6 +63,33 @@ export interface PipelineImageProps extends Omit<NativeImageProps, 'image'> {
|
|
|
57
63
|
*/
|
|
58
64
|
cornerRadius?: number | CornerRadii;
|
|
59
65
|
cache?: CacheOption;
|
|
66
|
+
/**
|
|
67
|
+
* How the source is fitted into the display size when the bitmap is
|
|
68
|
+
* produced — see {@linkcode ResizeFit}. When omitted it follows
|
|
69
|
+
* `resizeMode`, so `resizeMode="contain"` decodes an aspect-fitted bitmap
|
|
70
|
+
* (no crop, no padding) instead of a center-cropped one the view then
|
|
71
|
+
* letterboxes. Set this to decouple the two.
|
|
72
|
+
*
|
|
73
|
+
* One iOS caveat, inherited from nitro-image's `Image`: an `Image` handed
|
|
74
|
+
* to the view is a scale-1 image, which `resizeMode="center"` — the one
|
|
75
|
+
* mode that draws an image at its own size — shows at 1 pt per pixel,
|
|
76
|
+
* i.e. `PixelRatio.get()`× larger than Android draws it. The bitmap is
|
|
77
|
+
* right; the display is not. `NativePipelineImage` draws `center` pixel
|
|
78
|
+
* for pixel on both platforms; use it when you need that mode.
|
|
79
|
+
* @default undefined (derived from `resizeMode`, or `'cover'` if unset)
|
|
80
|
+
*/
|
|
81
|
+
fit?: ResizeFit;
|
|
82
|
+
/**
|
|
83
|
+
* `false` never enlarges a source smaller than the display size when the
|
|
84
|
+
* **bitmap** is produced — see {@linkcode ResizeOptions.allowUpscale}: it
|
|
85
|
+
* stays at its own pixel size, so nothing is decoded or blurred larger
|
|
86
|
+
* than the source. The **view** still displays that bitmap per
|
|
87
|
+
* `resizeMode`, so `cover`/`contain`/`stretch` scale it up on screen (and
|
|
88
|
+
* a baked `blur`/`cornerRadius` with it); `resizeMode="center"` shows it
|
|
89
|
+
* at its natural size instead.
|
|
90
|
+
* @default true
|
|
91
|
+
*/
|
|
92
|
+
allowUpscale?: boolean;
|
|
60
93
|
/** Called with the processed `Image` each time a new variant resolves. */
|
|
61
94
|
onLoad?: (image: Image) => void;
|
|
62
95
|
/** Called when loading fails. */
|
|
@@ -114,10 +147,13 @@ export const PipelineImage = forwardRef<PipelineImageRef, PipelineImageProps>(
|
|
|
114
147
|
blur = 0,
|
|
115
148
|
cornerRadius,
|
|
116
149
|
cache,
|
|
150
|
+
fit,
|
|
151
|
+
allowUpscale,
|
|
117
152
|
onLoad,
|
|
118
153
|
onError,
|
|
119
154
|
style,
|
|
120
155
|
onLayout,
|
|
156
|
+
resizeMode,
|
|
121
157
|
...viewProps
|
|
122
158
|
},
|
|
123
159
|
ref,
|
|
@@ -129,7 +165,13 @@ export const PipelineImage = forwardRef<PipelineImageRef, PipelineImageProps>(
|
|
|
129
165
|
);
|
|
130
166
|
// A numeric style is what the caller declared, so it wins and starts the
|
|
131
167
|
// request a frame earlier; the measured layout is the fallback.
|
|
132
|
-
const
|
|
168
|
+
const size = styleSize ?? layoutSize;
|
|
169
|
+
// The view's resizeMode and the bitmap's fit are the same four values;
|
|
170
|
+
// an explicit `fit` decouples them.
|
|
171
|
+
const effectiveFit = fit ?? resizeMode;
|
|
172
|
+
const resize: ResizeOptions | undefined = size
|
|
173
|
+
? { ...size, fit: effectiveFit, allowUpscale }
|
|
174
|
+
: undefined;
|
|
133
175
|
// Same precedence: an explicit prop wins over what style implies.
|
|
134
176
|
const effectiveCornerRadius =
|
|
135
177
|
cornerRadius ?? cornerRadiusForStyle(style) ?? 0;
|
|
@@ -171,6 +213,7 @@ export const PipelineImage = forwardRef<PipelineImageRef, PipelineImageProps>(
|
|
|
171
213
|
{...viewProps}
|
|
172
214
|
ref={ref}
|
|
173
215
|
style={style}
|
|
216
|
+
resizeMode={resizeMode}
|
|
174
217
|
onLayout={handleLayout}
|
|
175
218
|
image={image}
|
|
176
219
|
/>
|
package/src/index.ts
CHANGED
|
@@ -9,6 +9,11 @@ export {
|
|
|
9
9
|
type PipelineImageProps,
|
|
10
10
|
type PipelineImageRef,
|
|
11
11
|
} from './PipelineImage';
|
|
12
|
+
export {
|
|
13
|
+
type ImageSource,
|
|
14
|
+
resolveImageUrl,
|
|
15
|
+
UNREGISTERED_ASSET_URL,
|
|
16
|
+
} from './resolveImageSource';
|
|
12
17
|
export {
|
|
13
18
|
cornerRadiusForStyle,
|
|
14
19
|
resizeForLayout,
|
|
@@ -18,6 +23,7 @@ export type {
|
|
|
18
23
|
CacheOption,
|
|
19
24
|
CornerRadii,
|
|
20
25
|
Options,
|
|
26
|
+
ResizeFit,
|
|
21
27
|
ResizeOptions,
|
|
22
28
|
ViewOptions,
|
|
23
29
|
} from './specs/nitro-image-toolkit.nitro';
|
package/src/resizeForStyle.ts
CHANGED
|
@@ -13,7 +13,9 @@ import type {
|
|
|
13
13
|
/**
|
|
14
14
|
* Converts a layout size in points (dp) to the pipeline's `resize` option in
|
|
15
15
|
* whole bitmap pixels using `PixelRatio.getPixelSizeForLayoutSize`. Returns
|
|
16
|
-
* `undefined` unless both values are positive numbers.
|
|
16
|
+
* `undefined` unless both values are positive numbers. Spread a `fit` into
|
|
17
|
+
* the result for the other resize modes — under `contain` and `center` the
|
|
18
|
+
* size is the box the bitmap fits in, not necessarily its final size.
|
|
17
19
|
*/
|
|
18
20
|
export function resizeForLayout(
|
|
19
21
|
width: unknown,
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { Image as RNImage } from 'react-native';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* What the pipeline can load: a URL string, or the id a `require()`d image
|
|
5
|
+
* asset evaluates to.
|
|
6
|
+
*
|
|
7
|
+
* As a string, `url` is passed to the native loader as-is. Accepted forms:
|
|
8
|
+
*
|
|
9
|
+
* - `https://` / `http://` — fetched over the network and cached on disk.
|
|
10
|
+
* - `file://` URLs and plain absolute paths (`/var/…/photo.jpg`) — read from
|
|
11
|
+
* the file system. The result is cached in memory only; there is nothing
|
|
12
|
+
* to gain from copying a local file into the disk cache.
|
|
13
|
+
* - Android also accepts `content://` URIs and, from a release build's
|
|
14
|
+
* resources, a bare drawable name — which is what `require()` resolves to
|
|
15
|
+
* there. iOS resolves `require()` to a `file://` URL into the app bundle.
|
|
16
|
+
*
|
|
17
|
+
* A `require('./photo.png')` is resolved with `Image.resolveAssetSource`, so
|
|
18
|
+
* it works the same in debug (streamed from Metro) and release (bundled).
|
|
19
|
+
*/
|
|
20
|
+
export type ImageSource = string | number;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Turns an {@linkcode ImageSource} into the URL string the native pipeline
|
|
24
|
+
* loads: strings pass through unchanged, a `require()`d asset is resolved via
|
|
25
|
+
* `Image.resolveAssetSource` (the scale-matched variant, like `<Image>`).
|
|
26
|
+
*
|
|
27
|
+
* The components and hooks call this for you; use it when calling
|
|
28
|
+
* `NitroImagePipeline.loadImage`/`preLoadImage` directly with a `require()`.
|
|
29
|
+
* @throws If `source` is a number that is not a registered asset.
|
|
30
|
+
* @example
|
|
31
|
+
* ```ts
|
|
32
|
+
* const image = await NitroImagePipeline.loadImage(
|
|
33
|
+
* resolveImageUrl(require('./photo.png')),
|
|
34
|
+
* { blur: 4 },
|
|
35
|
+
* );
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export function resolveImageUrl(source: ImageSource): string {
|
|
39
|
+
if (typeof source === 'string') {
|
|
40
|
+
return source;
|
|
41
|
+
}
|
|
42
|
+
const resolved = RNImage.resolveAssetSource(source);
|
|
43
|
+
if (resolved == null) {
|
|
44
|
+
throw new Error(`Not a registered image asset: require() id ${source}`);
|
|
45
|
+
}
|
|
46
|
+
return resolved.uri;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* A URL no loader can resolve, standing in for a `require()` id that is not
|
|
51
|
+
* a registered asset. Its scheme has no fetcher on either platform, so the
|
|
52
|
+
* request fails at load time — the same way a missing file does — instead of
|
|
53
|
+
* throwing from a component's render.
|
|
54
|
+
*/
|
|
55
|
+
export const UNREGISTERED_ASSET_URL = 'unregistered-asset://';
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* {@linkcode resolveImageUrl} for code that runs during render: an
|
|
59
|
+
* unregistered `require()` id yields {@linkcode UNREGISTERED_ASSET_URL} (and
|
|
60
|
+
* a warning in development) rather than throwing.
|
|
61
|
+
*/
|
|
62
|
+
export function resolveImageUrlOrFallback(source: ImageSource): string {
|
|
63
|
+
try {
|
|
64
|
+
return resolveImageUrl(source);
|
|
65
|
+
} catch (error) {
|
|
66
|
+
if (__DEV__) {
|
|
67
|
+
console.warn(
|
|
68
|
+
`[react-native-nitro-image-pipeline] ${(error as Error).message}`,
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
return UNREGISTERED_ASSET_URL;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* A stable, per-source `recyclingKey` for `<NativeNitroImage>`: the URL
|
|
77
|
+
* itself for strings, and a tag derived from the asset id for a `require()`
|
|
78
|
+
* (resolving it would cost an asset-registry lookup per render for nothing
|
|
79
|
+
* more than a distinct key).
|
|
80
|
+
*/
|
|
81
|
+
export function recyclingKeyFor(source: ImageSource): string {
|
|
82
|
+
return typeof source === 'string' ? source : `asset:${source}`;
|
|
83
|
+
}
|