react-native-nitro-image-pipeline 1.2.0 → 1.3.1
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 +147 -5
- package/android/src/main/java/com/margelo/nitro/nitroimagepipeline/HybridNitroImagePipeline.kt +17 -15
- package/android/src/main/java/com/margelo/nitro/nitroimagepipeline/transform/ResizeTransformation.kt +1 -2
- package/ios/HybridNitroImagePipeline.swift +54 -38
- package/ios/RoundedCornersProcessor.swift +1 -1
- package/lib/commonjs/NitroImagePipeline.js +9 -0
- package/lib/commonjs/NitroImagePipeline.js.map +1 -0
- package/lib/commonjs/PipelineImage.js +126 -0
- package/lib/commonjs/PipelineImage.js.map +1 -0
- package/lib/commonjs/index.js +40 -88
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/resizeForStyle.js +68 -0
- package/lib/commonjs/resizeForStyle.js.map +1 -0
- package/lib/commonjs/useImage.js +95 -0
- package/lib/commonjs/useImage.js.map +1 -0
- package/lib/module/NitroImagePipeline.js +5 -0
- package/lib/module/NitroImagePipeline.js.map +1 -0
- package/lib/module/PipelineImage.js +122 -0
- package/lib/module/PipelineImage.js.map +1 -0
- package/lib/module/index.js +4 -86
- package/lib/module/index.js.map +1 -1
- package/lib/module/resizeForStyle.js +62 -0
- package/lib/module/resizeForStyle.js.map +1 -0
- package/lib/module/useImage.js +91 -0
- package/lib/module/useImage.js.map +1 -0
- package/lib/typescript/src/NitroImagePipeline.d.ts +3 -0
- package/lib/typescript/src/NitroImagePipeline.d.ts.map +1 -0
- package/lib/typescript/src/PipelineImage.d.ts +73 -0
- package/lib/typescript/src/PipelineImage.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +5 -45
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/resizeForStyle.d.ts +30 -0
- package/lib/typescript/src/resizeForStyle.d.ts.map +1 -0
- package/lib/typescript/src/useImage.d.ts +53 -0
- package/lib/typescript/src/useImage.d.ts.map +1 -0
- package/package.json +3 -2
- package/src/NitroImagePipeline.ts +6 -0
- package/src/PipelineImage.tsx +183 -0
- package/src/index.ts +13 -139
- package/src/resizeForStyle.ts +96 -0
- package/src/useImage.ts +149 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.cornerRadiusForStyle = cornerRadiusForStyle;
|
|
7
|
+
exports.resizeForLayout = resizeForLayout;
|
|
8
|
+
exports.resizeForStyle = resizeForStyle;
|
|
9
|
+
var _reactNative = require("react-native");
|
|
10
|
+
/**
|
|
11
|
+
* Converts a layout size in points (dp) to the pipeline's `resize` option in
|
|
12
|
+
* whole bitmap pixels using `PixelRatio.getPixelSizeForLayoutSize`. Returns
|
|
13
|
+
* `undefined` unless both values are positive numbers.
|
|
14
|
+
*/
|
|
15
|
+
function resizeForLayout(width, height) {
|
|
16
|
+
if (typeof width !== 'number' || typeof height !== 'number') {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
const pixelWidth = _reactNative.PixelRatio.getPixelSizeForLayoutSize(width);
|
|
20
|
+
const pixelHeight = _reactNative.PixelRatio.getPixelSizeForLayoutSize(height);
|
|
21
|
+
return pixelWidth > 0 && pixelHeight > 0 ? {
|
|
22
|
+
width: pixelWidth,
|
|
23
|
+
height: pixelHeight
|
|
24
|
+
} : undefined;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Derives the pipeline's `resize` option from a view style whose `width` and
|
|
29
|
+
* `height` are numeric points, so the bitmap matches the display size on
|
|
30
|
+
* every screen density:
|
|
31
|
+
* ```ts
|
|
32
|
+
* useImage({ url, resize: resizeForStyle(styles.image) });
|
|
33
|
+
* ```
|
|
34
|
+
* Arrays and registered styles are flattened. Returns `undefined` when either
|
|
35
|
+
* dimension is missing or not a number (`'50%'`, `'auto'`, flex-driven) —
|
|
36
|
+
* use `<PipelineImage>` for those, which measures the view instead.
|
|
37
|
+
*/
|
|
38
|
+
function resizeForStyle(style) {
|
|
39
|
+
const flat = _reactNative.StyleSheet.flatten(style);
|
|
40
|
+
return resizeForLayout(flat?.width, flat?.height);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Derives a `cornerRadius` option from a view style's `borderRadius` /
|
|
45
|
+
* `borderTopLeftRadius` / `borderTopRightRadius` / `borderBottomLeftRadius` /
|
|
46
|
+
* `borderBottomRightRadius`, in points. Per-corner properties override
|
|
47
|
+
* `borderRadius` for that corner; a corner with neither set stays square.
|
|
48
|
+
* Non-numeric values (percentages, animated values) are ignored, like
|
|
49
|
+
* {@linkcode resizeForStyle}. Returns `undefined` when none are set.
|
|
50
|
+
*/
|
|
51
|
+
function cornerRadiusForStyle(style) {
|
|
52
|
+
const flat = _reactNative.StyleSheet.flatten(style);
|
|
53
|
+
const base = typeof flat?.borderRadius === 'number' ? flat.borderRadius : undefined;
|
|
54
|
+
const topLeft = typeof flat?.borderTopLeftRadius === 'number' ? flat.borderTopLeftRadius : undefined;
|
|
55
|
+
const topRight = typeof flat?.borderTopRightRadius === 'number' ? flat.borderTopRightRadius : undefined;
|
|
56
|
+
const bottomLeft = typeof flat?.borderBottomLeftRadius === 'number' ? flat.borderBottomLeftRadius : undefined;
|
|
57
|
+
const bottomRight = typeof flat?.borderBottomRightRadius === 'number' ? flat.borderBottomRightRadius : undefined;
|
|
58
|
+
if (topLeft === undefined && topRight === undefined && bottomLeft === undefined && bottomRight === undefined) {
|
|
59
|
+
return base;
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
topLeft: topLeft ?? base,
|
|
63
|
+
topRight: topRight ?? base,
|
|
64
|
+
bottomLeft: bottomLeft ?? base,
|
|
65
|
+
bottomRight: bottomRight ?? base
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=resizeForStyle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_reactNative","require","resizeForLayout","width","height","undefined","pixelWidth","PixelRatio","getPixelSizeForLayoutSize","pixelHeight","resizeForStyle","style","flat","StyleSheet","flatten","cornerRadiusForStyle","base","borderRadius","topLeft","borderTopLeftRadius","topRight","borderTopRightRadius","bottomLeft","borderBottomLeftRadius","bottomRight","borderBottomRightRadius"],"sourceRoot":"../../src","sources":["resizeForStyle.ts"],"mappings":";;;;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AAYA;AACA;AACA;AACA;AACA;AACO,SAASC,eAAeA,CAC7BC,KAAc,EACdC,MAAe,EACY;EAC3B,IAAI,OAAOD,KAAK,KAAK,QAAQ,IAAI,OAAOC,MAAM,KAAK,QAAQ,EAAE;IAC3D,OAAOC,SAAS;EAClB;EACA,MAAMC,UAAU,GAAGC,uBAAU,CAACC,yBAAyB,CAACL,KAAK,CAAC;EAC9D,MAAMM,WAAW,GAAGF,uBAAU,CAACC,yBAAyB,CAACJ,MAAM,CAAC;EAChE,OAAOE,UAAU,GAAG,CAAC,IAAIG,WAAW,GAAG,CAAC,GACpC;IAAEN,KAAK,EAAEG,UAAU;IAAEF,MAAM,EAAEK;EAAY,CAAC,GAC1CJ,SAAS;AACf;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASK,cAAcA,CAC5BC,KAA2B,EACA;EAC3B,MAAMC,IAAI,GAAGC,uBAAU,CAACC,OAAO,CAACH,KAAK,CAAC;EACtC,OAAOT,eAAe,CAACU,IAAI,EAAET,KAAK,EAAES,IAAI,EAAER,MAAM,CAAC;AACnD;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASW,oBAAoBA,CAClCJ,KAA2B,EACO;EAClC,MAAMC,IAAI,GAAGC,uBAAU,CAACC,OAAO,CAACH,KAAK,CAAC;EACtC,MAAMK,IAAI,GACR,OAAOJ,IAAI,EAAEK,YAAY,KAAK,QAAQ,GAAGL,IAAI,CAACK,YAAY,GAAGZ,SAAS;EACxE,MAAMa,OAAO,GACX,OAAON,IAAI,EAAEO,mBAAmB,KAAK,QAAQ,GACzCP,IAAI,CAACO,mBAAmB,GACxBd,SAAS;EACf,MAAMe,QAAQ,GACZ,OAAOR,IAAI,EAAES,oBAAoB,KAAK,QAAQ,GAC1CT,IAAI,CAACS,oBAAoB,GACzBhB,SAAS;EACf,MAAMiB,UAAU,GACd,OAAOV,IAAI,EAAEW,sBAAsB,KAAK,QAAQ,GAC5CX,IAAI,CAACW,sBAAsB,GAC3BlB,SAAS;EACf,MAAMmB,WAAW,GACf,OAAOZ,IAAI,EAAEa,uBAAuB,KAAK,QAAQ,GAC7Cb,IAAI,CAACa,uBAAuB,GAC5BpB,SAAS;EAEf,IACEa,OAAO,KAAKb,SAAS,IACrBe,QAAQ,KAAKf,SAAS,IACtBiB,UAAU,KAAKjB,SAAS,IACxBmB,WAAW,KAAKnB,SAAS,EACzB;IACA,OAAOW,IAAI;EACb;EAEA,OAAO;IACLE,OAAO,EAAEA,OAAO,IAAIF,IAAI;IACxBI,QAAQ,EAAEA,QAAQ,IAAIJ,IAAI;IAC1BM,UAAU,EAAEA,UAAU,IAAIN,IAAI;IAC9BQ,WAAW,EAAEA,WAAW,IAAIR;EAC9B,CAAC;AACH","ignoreList":[]}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.useImage = useImage;
|
|
7
|
+
var _react = require("react");
|
|
8
|
+
var _NitroImagePipeline = require("./NitroImagePipeline");
|
|
9
|
+
/**
|
|
10
|
+
* A hook to asynchronously load an image from the
|
|
11
|
+
* given {@linkcode AsyncImageSource} into memory.
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* const { image, error } = useImage({ filePath: '/tmp/image.jpg' })
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
function useImage({
|
|
18
|
+
url,
|
|
19
|
+
blur = 0,
|
|
20
|
+
cornerRadius = 0,
|
|
21
|
+
resize,
|
|
22
|
+
cache,
|
|
23
|
+
enabled = true
|
|
24
|
+
}) {
|
|
25
|
+
const [image, setImage] = (0, _react.useState)({
|
|
26
|
+
image: undefined,
|
|
27
|
+
error: undefined
|
|
28
|
+
});
|
|
29
|
+
const loadedUrlRef = (0, _react.useRef)(url);
|
|
30
|
+
|
|
31
|
+
// Split the option into primitives so an inline `{ topLeft: 24, ... }`
|
|
32
|
+
// literal (new identity every render) doesn't re-trigger the effect.
|
|
33
|
+
const isUniformRadius = typeof cornerRadius === 'number';
|
|
34
|
+
const uniformRadius = isUniformRadius ? cornerRadius : 0;
|
|
35
|
+
const {
|
|
36
|
+
topLeft = 0,
|
|
37
|
+
topRight = 0,
|
|
38
|
+
bottomLeft = 0,
|
|
39
|
+
bottomRight = 0
|
|
40
|
+
} = isUniformRadius ? {} : cornerRadius;
|
|
41
|
+
const resizeWidth = resize?.width ?? 0;
|
|
42
|
+
const resizeHeight = resize?.height ?? 0;
|
|
43
|
+
(0, _react.useEffect)(() => {
|
|
44
|
+
let cancelled = false;
|
|
45
|
+
// Only reset to the loading state when the URL changes; for same-URL
|
|
46
|
+
// param tweaks (blur/cornerRadius/cache) keep showing the current image
|
|
47
|
+
// until the new variant resolves, to avoid flashing empty.
|
|
48
|
+
if (loadedUrlRef.current !== url) {
|
|
49
|
+
loadedUrlRef.current = url;
|
|
50
|
+
setImage({
|
|
51
|
+
image: undefined,
|
|
52
|
+
error: undefined
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
if (enabled) {
|
|
56
|
+
(async () => {
|
|
57
|
+
try {
|
|
58
|
+
const result = await _NitroImagePipeline.NitroImagePipeline.loadImage(url, {
|
|
59
|
+
blur,
|
|
60
|
+
cornerRadius: isUniformRadius ? uniformRadius : {
|
|
61
|
+
topLeft,
|
|
62
|
+
topRight,
|
|
63
|
+
bottomLeft,
|
|
64
|
+
bottomRight
|
|
65
|
+
},
|
|
66
|
+
resize: resizeWidth > 0 && resizeHeight > 0 ? {
|
|
67
|
+
width: resizeWidth,
|
|
68
|
+
height: resizeHeight
|
|
69
|
+
} : undefined,
|
|
70
|
+
cache
|
|
71
|
+
});
|
|
72
|
+
if (!cancelled) {
|
|
73
|
+
setImage({
|
|
74
|
+
image: result,
|
|
75
|
+
error: undefined
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
} catch (e) {
|
|
79
|
+
const error = e instanceof Error ? e : new Error(`${e}`);
|
|
80
|
+
if (!cancelled) {
|
|
81
|
+
setImage({
|
|
82
|
+
image: undefined,
|
|
83
|
+
error: error
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
})();
|
|
88
|
+
}
|
|
89
|
+
return () => {
|
|
90
|
+
cancelled = true;
|
|
91
|
+
};
|
|
92
|
+
}, [url, blur, isUniformRadius, uniformRadius, topLeft, topRight, bottomLeft, bottomRight, resizeWidth, resizeHeight, cache, enabled]);
|
|
93
|
+
return image;
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=useImage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_react","require","_NitroImagePipeline","useImage","url","blur","cornerRadius","resize","cache","enabled","image","setImage","useState","undefined","error","loadedUrlRef","useRef","isUniformRadius","uniformRadius","topLeft","topRight","bottomLeft","bottomRight","resizeWidth","width","resizeHeight","height","useEffect","cancelled","current","result","NitroImagePipeline","loadImage","e","Error"],"sourceRoot":"../../src","sources":["useImage.ts"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,OAAA;AAGA,IAAAC,mBAAA,GAAAD,OAAA;AAwBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASE,QAAQA,CAAC;EACvBC,GAAG;EACHC,IAAI,GAAG,CAAC;EACRC,YAAY,GAAG,CAAC;EAChBC,MAAM;EACNC,KAAK;EACLC,OAAO,GAAG;AA+BZ,CAAC,EAAU;EACT,MAAM,CAACC,KAAK,EAAEC,QAAQ,CAAC,GAAG,IAAAC,eAAQ,EAAS;IACzCF,KAAK,EAAEG,SAAS;IAChBC,KAAK,EAAED;EACT,CAAC,CAAC;EACF,MAAME,YAAY,GAAG,IAAAC,aAAM,EAACZ,GAAG,CAAC;;EAEhC;EACA;EACA,MAAMa,eAAe,GAAG,OAAOX,YAAY,KAAK,QAAQ;EACxD,MAAMY,aAAa,GAAGD,eAAe,GAAGX,YAAY,GAAG,CAAC;EACxD,MAAM;IACJa,OAAO,GAAG,CAAC;IACXC,QAAQ,GAAG,CAAC;IACZC,UAAU,GAAG,CAAC;IACdC,WAAW,GAAG;EAChB,CAAC,GAAGL,eAAe,GAAG,CAAC,CAAC,GAAGX,YAAY;EACvC,MAAMiB,WAAW,GAAGhB,MAAM,EAAEiB,KAAK,IAAI,CAAC;EACtC,MAAMC,YAAY,GAAGlB,MAAM,EAAEmB,MAAM,IAAI,CAAC;EAExC,IAAAC,gBAAS,EAAC,MAAM;IACd,IAAIC,SAAS,GAAG,KAAK;IACrB;IACA;IACA;IACA,IAAIb,YAAY,CAACc,OAAO,KAAKzB,GAAG,EAAE;MAChCW,YAAY,CAACc,OAAO,GAAGzB,GAAG;MAC1BO,QAAQ,CAAC;QAAED,KAAK,EAAEG,SAAS;QAAEC,KAAK,EAAED;MAAU,CAAC,CAAC;IAClD;IAEA,IAAIJ,OAAO,EAAE;MACX,CAAC,YAAY;QACX,IAAI;UACF,MAAMqB,MAAM,GAAG,MAAMC,sCAAkB,CAACC,SAAS,CAAC5B,GAAG,EAAE;YACrDC,IAAI;YACJC,YAAY,EAAEW,eAAe,GACzBC,aAAa,GACb;cAAEC,OAAO;cAAEC,QAAQ;cAAEC,UAAU;cAAEC;YAAY,CAAC;YAClDf,MAAM,EACJgB,WAAW,GAAG,CAAC,IAAIE,YAAY,GAAG,CAAC,GAC/B;cAAED,KAAK,EAAED,WAAW;cAAEG,MAAM,EAAED;YAAa,CAAC,GAC5CZ,SAAS;YACfL;UACF,CAAC,CAAC;UAEF,IAAI,CAACoB,SAAS,EAAE;YACdjB,QAAQ,CAAC;cAAED,KAAK,EAAEoB,MAAM;cAAEhB,KAAK,EAAED;YAAU,CAAC,CAAC;UAC/C;QACF,CAAC,CAAC,OAAOoB,CAAC,EAAE;UACV,MAAMnB,KAAK,GAAGmB,CAAC,YAAYC,KAAK,GAAGD,CAAC,GAAG,IAAIC,KAAK,CAAC,GAAGD,CAAC,EAAE,CAAC;UACxD,IAAI,CAACL,SAAS,EAAE;YACdjB,QAAQ,CAAC;cAAED,KAAK,EAAEG,SAAS;cAAEC,KAAK,EAAEA;YAAM,CAAC,CAAC;UAC9C;QACF;MACF,CAAC,EAAE,CAAC;IACN;IAEA,OAAO,MAAM;MACXc,SAAS,GAAG,IAAI;IAClB,CAAC;EACH,CAAC,EAAE,CACDxB,GAAG,EACHC,IAAI,EACJY,eAAe,EACfC,aAAa,EACbC,OAAO,EACPC,QAAQ,EACRC,UAAU,EACVC,WAAW,EACXC,WAAW,EACXE,YAAY,EACZjB,KAAK,EACLC,OAAO,CACR,CAAC;EAEF,OAAOC,KAAK;AACd","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["NitroModules","NitroImagePipeline","createHybridObject"],"sourceRoot":"../../src","sources":["NitroImagePipeline.ts"],"mappings":";;AAAA,SAASA,YAAY,QAAQ,4BAA4B;AAIzD,OAAO,MAAMC,kBAAkB,GAC7BD,YAAY,CAACE,kBAAkB,CAAyB,oBAAoB,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { forwardRef, useEffect, useRef, useState } from 'react';
|
|
4
|
+
import { PixelRatio } from 'react-native';
|
|
5
|
+
import { NativeNitroImage } from 'react-native-nitro-image';
|
|
6
|
+
import { cornerRadiusForStyle, resizeForLayout, resizeForStyle } from './resizeForStyle';
|
|
7
|
+
import { useImage } from './useImage';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The instance `<PipelineImage>` exposes through its `ref` — the underlying
|
|
11
|
+
* `NativeNitroImage` host view, with the usual native-view methods
|
|
12
|
+
* (`measure`, …).
|
|
13
|
+
*/
|
|
14
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
15
|
+
function sameSize(a, b) {
|
|
16
|
+
return a?.width === b?.width && a?.height === b?.height;
|
|
17
|
+
}
|
|
18
|
+
function scaleRadius(cornerRadius, scale) {
|
|
19
|
+
if (typeof cornerRadius === 'number') {
|
|
20
|
+
return cornerRadius * scale;
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
topLeft: (cornerRadius.topLeft ?? 0) * scale,
|
|
24
|
+
topRight: (cornerRadius.topRight ?? 0) * scale,
|
|
25
|
+
bottomLeft: (cornerRadius.bottomLeft ?? 0) * scale,
|
|
26
|
+
bottomRight: (cornerRadius.bottomRight ?? 0) * scale
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* A `NativeNitroImage` that loads `url` through the pipeline at exactly the
|
|
32
|
+
* size it is displayed: the bitmap is resized to the view's size in points ×
|
|
33
|
+
* `PixelRatio.get()`, so `blur` and `cornerRadius` (both in points here) apply
|
|
34
|
+
* 1:1 to what is on screen and large sources are never decoded at full size.
|
|
35
|
+
*
|
|
36
|
+
* A numeric `width`/`height` in `style` starts loading immediately; otherwise
|
|
37
|
+
* (`'50%'`, `flex`, `aspectRatio`, …) loading waits for the first `onLayout`.
|
|
38
|
+
* If the layout size later changes, a new variant is loaded and swapped in
|
|
39
|
+
* without flashing. Without an explicit `cornerRadius` prop, `style`'s
|
|
40
|
+
* `borderRadius`-family properties are baked into the bitmap instead — no
|
|
41
|
+
* separate view-layer rounding needed.
|
|
42
|
+
*
|
|
43
|
+
* The `ref` is forwarded to the underlying `NativeNitroImage` host view, so
|
|
44
|
+
* the component works with `Animated.createAnimatedComponent` (Reanimated or
|
|
45
|
+
* React Native's built-in `Animated`).
|
|
46
|
+
* @example
|
|
47
|
+
* ```tsx
|
|
48
|
+
* <PipelineImage
|
|
49
|
+
* url="https://example.com/photo.jpg"
|
|
50
|
+
* style={{ width: 300, height: 200 }}
|
|
51
|
+
* cornerRadius={24}
|
|
52
|
+
* />
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export const PipelineImage = /*#__PURE__*/forwardRef(function PipelineImage({
|
|
56
|
+
url,
|
|
57
|
+
blur = 0,
|
|
58
|
+
cornerRadius,
|
|
59
|
+
cache,
|
|
60
|
+
onLoad,
|
|
61
|
+
onError,
|
|
62
|
+
style,
|
|
63
|
+
onLayout,
|
|
64
|
+
...viewProps
|
|
65
|
+
}, ref) {
|
|
66
|
+
const scale = PixelRatio.get();
|
|
67
|
+
const styleSize = resizeForStyle(style);
|
|
68
|
+
const [layoutSize, setLayoutSize] = useState(undefined);
|
|
69
|
+
// A numeric style is what the caller declared, so it wins and starts the
|
|
70
|
+
// request a frame earlier; the measured layout is the fallback.
|
|
71
|
+
const resize = styleSize ?? layoutSize;
|
|
72
|
+
// Same precedence: an explicit prop wins over what style implies.
|
|
73
|
+
const effectiveCornerRadius = cornerRadius ?? cornerRadiusForStyle(style) ?? 0;
|
|
74
|
+
const {
|
|
75
|
+
image,
|
|
76
|
+
error
|
|
77
|
+
} = useImage({
|
|
78
|
+
url,
|
|
79
|
+
blur: blur * scale,
|
|
80
|
+
cornerRadius: scaleRadius(effectiveCornerRadius, scale),
|
|
81
|
+
cache,
|
|
82
|
+
resize,
|
|
83
|
+
enabled: resize !== undefined
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// Latest callbacks in refs so inline arrow props don't re-fire the effects.
|
|
87
|
+
const onLoadRef = useRef(onLoad);
|
|
88
|
+
const onErrorRef = useRef(onError);
|
|
89
|
+
useEffect(() => {
|
|
90
|
+
onLoadRef.current = onLoad;
|
|
91
|
+
onErrorRef.current = onError;
|
|
92
|
+
});
|
|
93
|
+
useEffect(() => {
|
|
94
|
+
if (image) onLoadRef.current?.(image);
|
|
95
|
+
}, [image]);
|
|
96
|
+
useEffect(() => {
|
|
97
|
+
if (error) onErrorRef.current?.(error);
|
|
98
|
+
}, [error]);
|
|
99
|
+
const handleLayout = event => {
|
|
100
|
+
onLayout?.(event);
|
|
101
|
+
const {
|
|
102
|
+
width,
|
|
103
|
+
height
|
|
104
|
+
} = event.nativeEvent.layout;
|
|
105
|
+
const next = resizeForLayout(width, height);
|
|
106
|
+
// Always record it (even when a numeric style is in charge) so a later
|
|
107
|
+
// switch to a non-numeric style has a size to fall back on.
|
|
108
|
+
setLayoutSize(prev => sameSize(prev, next) ? prev : next);
|
|
109
|
+
};
|
|
110
|
+
return /*#__PURE__*/_jsx(NativeNitroImage, {
|
|
111
|
+
...viewProps,
|
|
112
|
+
ref: ref,
|
|
113
|
+
style: style,
|
|
114
|
+
onLayout: handleLayout,
|
|
115
|
+
image: image
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// Reanimated and DevTools read the display name; the forwardRef wrapper
|
|
120
|
+
// would otherwise report as anonymous.
|
|
121
|
+
PipelineImage.displayName = 'PipelineImage';
|
|
122
|
+
//# sourceMappingURL=PipelineImage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["forwardRef","useEffect","useRef","useState","PixelRatio","NativeNitroImage","cornerRadiusForStyle","resizeForLayout","resizeForStyle","useImage","jsx","_jsx","sameSize","a","b","width","height","scaleRadius","cornerRadius","scale","topLeft","topRight","bottomLeft","bottomRight","PipelineImage","url","blur","cache","onLoad","onError","style","onLayout","viewProps","ref","get","styleSize","layoutSize","setLayoutSize","undefined","resize","effectiveCornerRadius","image","error","enabled","onLoadRef","onErrorRef","current","handleLayout","event","nativeEvent","layout","next","prev","displayName"],"sourceRoot":"../../src","sources":["PipelineImage.tsx"],"mappings":"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","ignoreList":[]}
|
package/lib/module/index.js
CHANGED
|
@@ -1,89 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
* A hook to asynchronously load an image from the
|
|
8
|
-
* given {@linkcode AsyncImageSource} into memory.
|
|
9
|
-
* @example
|
|
10
|
-
* ```ts
|
|
11
|
-
* const { image, error } = useImage({ filePath: '/tmp/image.jpg' })
|
|
12
|
-
* ```
|
|
13
|
-
*/
|
|
14
|
-
export function useImage({
|
|
15
|
-
url,
|
|
16
|
-
blur = 0,
|
|
17
|
-
cornerRadius = 0,
|
|
18
|
-
resize,
|
|
19
|
-
cache
|
|
20
|
-
}) {
|
|
21
|
-
const [image, setImage] = useState({
|
|
22
|
-
image: undefined,
|
|
23
|
-
error: undefined
|
|
24
|
-
});
|
|
25
|
-
const loadedUrlRef = useRef(url);
|
|
26
|
-
|
|
27
|
-
// Split the option into primitives so an inline `{ topLeft: 24, ... }`
|
|
28
|
-
// literal (new identity every render) doesn't re-trigger the effect.
|
|
29
|
-
const isUniformRadius = typeof cornerRadius === 'number';
|
|
30
|
-
const uniformRadius = isUniformRadius ? cornerRadius : 0;
|
|
31
|
-
const {
|
|
32
|
-
topLeft = 0,
|
|
33
|
-
topRight = 0,
|
|
34
|
-
bottomLeft = 0,
|
|
35
|
-
bottomRight = 0
|
|
36
|
-
} = isUniformRadius ? {} : cornerRadius;
|
|
37
|
-
const resizeWidth = resize?.width ?? 0;
|
|
38
|
-
const resizeHeight = resize?.height ?? 0;
|
|
39
|
-
useEffect(() => {
|
|
40
|
-
let cancelled = false;
|
|
41
|
-
// Only reset to the loading state when the URL changes; for same-URL
|
|
42
|
-
// param tweaks (blur/cornerRadius/cache) keep showing the current image
|
|
43
|
-
// until the new variant resolves, to avoid flashing empty.
|
|
44
|
-
if (loadedUrlRef.current !== url) {
|
|
45
|
-
loadedUrlRef.current = url;
|
|
46
|
-
setImage({
|
|
47
|
-
image: undefined,
|
|
48
|
-
error: undefined
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
(async () => {
|
|
52
|
-
try {
|
|
53
|
-
const result = await NitroImagePipeline.loadImage(url, {
|
|
54
|
-
blur,
|
|
55
|
-
cornerRadius: isUniformRadius ? uniformRadius : {
|
|
56
|
-
topLeft,
|
|
57
|
-
topRight,
|
|
58
|
-
bottomLeft,
|
|
59
|
-
bottomRight
|
|
60
|
-
},
|
|
61
|
-
resize: resizeWidth > 0 && resizeHeight > 0 ? {
|
|
62
|
-
width: resizeWidth,
|
|
63
|
-
height: resizeHeight
|
|
64
|
-
} : undefined,
|
|
65
|
-
cache
|
|
66
|
-
});
|
|
67
|
-
if (!cancelled) {
|
|
68
|
-
setImage({
|
|
69
|
-
image: result,
|
|
70
|
-
error: undefined
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
} catch (e) {
|
|
74
|
-
const error = e instanceof Error ? e : new Error(`${e}`);
|
|
75
|
-
if (!cancelled) {
|
|
76
|
-
setImage({
|
|
77
|
-
image: undefined,
|
|
78
|
-
error: error
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
})();
|
|
83
|
-
return () => {
|
|
84
|
-
cancelled = true;
|
|
85
|
-
};
|
|
86
|
-
}, [url, blur, isUniformRadius, uniformRadius, topLeft, topRight, bottomLeft, bottomRight, resizeWidth, resizeHeight, cache]);
|
|
87
|
-
return image;
|
|
88
|
-
}
|
|
3
|
+
export { NitroImagePipeline } from './NitroImagePipeline';
|
|
4
|
+
export { PipelineImage } from './PipelineImage';
|
|
5
|
+
export { cornerRadiusForStyle, resizeForLayout, resizeForStyle } from './resizeForStyle';
|
|
6
|
+
export { useImage } from './useImage';
|
|
89
7
|
//# sourceMappingURL=index.js.map
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["
|
|
1
|
+
{"version":3,"names":["NitroImagePipeline","PipelineImage","cornerRadiusForStyle","resizeForLayout","resizeForStyle","useImage"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":";;AAAA,SAASA,kBAAkB,QAAQ,sBAAsB;AACzD,SACEC,aAAa,QAGR,iBAAiB;AACxB,SACEC,oBAAoB,EACpBC,eAAe,EACfC,cAAc,QACT,kBAAkB;AAOzB,SAASC,QAAQ,QAAQ,YAAY","ignoreList":[]}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { PixelRatio, StyleSheet } from 'react-native';
|
|
4
|
+
/**
|
|
5
|
+
* Converts a layout size in points (dp) to the pipeline's `resize` option in
|
|
6
|
+
* whole bitmap pixels using `PixelRatio.getPixelSizeForLayoutSize`. Returns
|
|
7
|
+
* `undefined` unless both values are positive numbers.
|
|
8
|
+
*/
|
|
9
|
+
export function resizeForLayout(width, height) {
|
|
10
|
+
if (typeof width !== 'number' || typeof height !== 'number') {
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
const pixelWidth = PixelRatio.getPixelSizeForLayoutSize(width);
|
|
14
|
+
const pixelHeight = PixelRatio.getPixelSizeForLayoutSize(height);
|
|
15
|
+
return pixelWidth > 0 && pixelHeight > 0 ? {
|
|
16
|
+
width: pixelWidth,
|
|
17
|
+
height: pixelHeight
|
|
18
|
+
} : undefined;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Derives the pipeline's `resize` option from a view style whose `width` and
|
|
23
|
+
* `height` are numeric points, so the bitmap matches the display size on
|
|
24
|
+
* every screen density:
|
|
25
|
+
* ```ts
|
|
26
|
+
* useImage({ url, resize: resizeForStyle(styles.image) });
|
|
27
|
+
* ```
|
|
28
|
+
* Arrays and registered styles are flattened. Returns `undefined` when either
|
|
29
|
+
* dimension is missing or not a number (`'50%'`, `'auto'`, flex-driven) —
|
|
30
|
+
* use `<PipelineImage>` for those, which measures the view instead.
|
|
31
|
+
*/
|
|
32
|
+
export function resizeForStyle(style) {
|
|
33
|
+
const flat = StyleSheet.flatten(style);
|
|
34
|
+
return resizeForLayout(flat?.width, flat?.height);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Derives a `cornerRadius` option from a view style's `borderRadius` /
|
|
39
|
+
* `borderTopLeftRadius` / `borderTopRightRadius` / `borderBottomLeftRadius` /
|
|
40
|
+
* `borderBottomRightRadius`, in points. Per-corner properties override
|
|
41
|
+
* `borderRadius` for that corner; a corner with neither set stays square.
|
|
42
|
+
* Non-numeric values (percentages, animated values) are ignored, like
|
|
43
|
+
* {@linkcode resizeForStyle}. Returns `undefined` when none are set.
|
|
44
|
+
*/
|
|
45
|
+
export function cornerRadiusForStyle(style) {
|
|
46
|
+
const flat = StyleSheet.flatten(style);
|
|
47
|
+
const base = typeof flat?.borderRadius === 'number' ? flat.borderRadius : undefined;
|
|
48
|
+
const topLeft = typeof flat?.borderTopLeftRadius === 'number' ? flat.borderTopLeftRadius : undefined;
|
|
49
|
+
const topRight = typeof flat?.borderTopRightRadius === 'number' ? flat.borderTopRightRadius : undefined;
|
|
50
|
+
const bottomLeft = typeof flat?.borderBottomLeftRadius === 'number' ? flat.borderBottomLeftRadius : undefined;
|
|
51
|
+
const bottomRight = typeof flat?.borderBottomRightRadius === 'number' ? flat.borderBottomRightRadius : undefined;
|
|
52
|
+
if (topLeft === undefined && topRight === undefined && bottomLeft === undefined && bottomRight === undefined) {
|
|
53
|
+
return base;
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
topLeft: topLeft ?? base,
|
|
57
|
+
topRight: topRight ?? base,
|
|
58
|
+
bottomLeft: bottomLeft ?? base,
|
|
59
|
+
bottomRight: bottomRight ?? base
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=resizeForStyle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["PixelRatio","StyleSheet","resizeForLayout","width","height","undefined","pixelWidth","getPixelSizeForLayoutSize","pixelHeight","resizeForStyle","style","flat","flatten","cornerRadiusForStyle","base","borderRadius","topLeft","borderTopLeftRadius","topRight","borderTopRightRadius","bottomLeft","borderBottomLeftRadius","bottomRight","borderBottomRightRadius"],"sourceRoot":"../../src","sources":["resizeForStyle.ts"],"mappings":";;AAAA,SACEA,UAAU,EAEVC,UAAU,QAEL,cAAc;AAOrB;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,eAAeA,CAC7BC,KAAc,EACdC,MAAe,EACY;EAC3B,IAAI,OAAOD,KAAK,KAAK,QAAQ,IAAI,OAAOC,MAAM,KAAK,QAAQ,EAAE;IAC3D,OAAOC,SAAS;EAClB;EACA,MAAMC,UAAU,GAAGN,UAAU,CAACO,yBAAyB,CAACJ,KAAK,CAAC;EAC9D,MAAMK,WAAW,GAAGR,UAAU,CAACO,yBAAyB,CAACH,MAAM,CAAC;EAChE,OAAOE,UAAU,GAAG,CAAC,IAAIE,WAAW,GAAG,CAAC,GACpC;IAAEL,KAAK,EAAEG,UAAU;IAAEF,MAAM,EAAEI;EAAY,CAAC,GAC1CH,SAAS;AACf;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASI,cAAcA,CAC5BC,KAA2B,EACA;EAC3B,MAAMC,IAAI,GAAGV,UAAU,CAACW,OAAO,CAACF,KAAK,CAAC;EACtC,OAAOR,eAAe,CAACS,IAAI,EAAER,KAAK,EAAEQ,IAAI,EAAEP,MAAM,CAAC;AACnD;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASS,oBAAoBA,CAClCH,KAA2B,EACO;EAClC,MAAMC,IAAI,GAAGV,UAAU,CAACW,OAAO,CAACF,KAAK,CAAC;EACtC,MAAMI,IAAI,GACR,OAAOH,IAAI,EAAEI,YAAY,KAAK,QAAQ,GAAGJ,IAAI,CAACI,YAAY,GAAGV,SAAS;EACxE,MAAMW,OAAO,GACX,OAAOL,IAAI,EAAEM,mBAAmB,KAAK,QAAQ,GACzCN,IAAI,CAACM,mBAAmB,GACxBZ,SAAS;EACf,MAAMa,QAAQ,GACZ,OAAOP,IAAI,EAAEQ,oBAAoB,KAAK,QAAQ,GAC1CR,IAAI,CAACQ,oBAAoB,GACzBd,SAAS;EACf,MAAMe,UAAU,GACd,OAAOT,IAAI,EAAEU,sBAAsB,KAAK,QAAQ,GAC5CV,IAAI,CAACU,sBAAsB,GAC3BhB,SAAS;EACf,MAAMiB,WAAW,GACf,OAAOX,IAAI,EAAEY,uBAAuB,KAAK,QAAQ,GAC7CZ,IAAI,CAACY,uBAAuB,GAC5BlB,SAAS;EAEf,IACEW,OAAO,KAAKX,SAAS,IACrBa,QAAQ,KAAKb,SAAS,IACtBe,UAAU,KAAKf,SAAS,IACxBiB,WAAW,KAAKjB,SAAS,EACzB;IACA,OAAOS,IAAI;EACb;EAEA,OAAO;IACLE,OAAO,EAAEA,OAAO,IAAIF,IAAI;IACxBI,QAAQ,EAAEA,QAAQ,IAAIJ,IAAI;IAC1BM,UAAU,EAAEA,UAAU,IAAIN,IAAI;IAC9BQ,WAAW,EAAEA,WAAW,IAAIR;EAC9B,CAAC;AACH","ignoreList":[]}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { useEffect, useRef, useState } from 'react';
|
|
4
|
+
import { NitroImagePipeline } from './NitroImagePipeline';
|
|
5
|
+
/**
|
|
6
|
+
* A hook to asynchronously load an image from the
|
|
7
|
+
* given {@linkcode AsyncImageSource} into memory.
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* const { image, error } = useImage({ filePath: '/tmp/image.jpg' })
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
export function useImage({
|
|
14
|
+
url,
|
|
15
|
+
blur = 0,
|
|
16
|
+
cornerRadius = 0,
|
|
17
|
+
resize,
|
|
18
|
+
cache,
|
|
19
|
+
enabled = true
|
|
20
|
+
}) {
|
|
21
|
+
const [image, setImage] = useState({
|
|
22
|
+
image: undefined,
|
|
23
|
+
error: undefined
|
|
24
|
+
});
|
|
25
|
+
const loadedUrlRef = useRef(url);
|
|
26
|
+
|
|
27
|
+
// Split the option into primitives so an inline `{ topLeft: 24, ... }`
|
|
28
|
+
// literal (new identity every render) doesn't re-trigger the effect.
|
|
29
|
+
const isUniformRadius = typeof cornerRadius === 'number';
|
|
30
|
+
const uniformRadius = isUniformRadius ? cornerRadius : 0;
|
|
31
|
+
const {
|
|
32
|
+
topLeft = 0,
|
|
33
|
+
topRight = 0,
|
|
34
|
+
bottomLeft = 0,
|
|
35
|
+
bottomRight = 0
|
|
36
|
+
} = isUniformRadius ? {} : cornerRadius;
|
|
37
|
+
const resizeWidth = resize?.width ?? 0;
|
|
38
|
+
const resizeHeight = resize?.height ?? 0;
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
let cancelled = false;
|
|
41
|
+
// Only reset to the loading state when the URL changes; for same-URL
|
|
42
|
+
// param tweaks (blur/cornerRadius/cache) keep showing the current image
|
|
43
|
+
// until the new variant resolves, to avoid flashing empty.
|
|
44
|
+
if (loadedUrlRef.current !== url) {
|
|
45
|
+
loadedUrlRef.current = url;
|
|
46
|
+
setImage({
|
|
47
|
+
image: undefined,
|
|
48
|
+
error: undefined
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
if (enabled) {
|
|
52
|
+
(async () => {
|
|
53
|
+
try {
|
|
54
|
+
const result = await NitroImagePipeline.loadImage(url, {
|
|
55
|
+
blur,
|
|
56
|
+
cornerRadius: isUniformRadius ? uniformRadius : {
|
|
57
|
+
topLeft,
|
|
58
|
+
topRight,
|
|
59
|
+
bottomLeft,
|
|
60
|
+
bottomRight
|
|
61
|
+
},
|
|
62
|
+
resize: resizeWidth > 0 && resizeHeight > 0 ? {
|
|
63
|
+
width: resizeWidth,
|
|
64
|
+
height: resizeHeight
|
|
65
|
+
} : undefined,
|
|
66
|
+
cache
|
|
67
|
+
});
|
|
68
|
+
if (!cancelled) {
|
|
69
|
+
setImage({
|
|
70
|
+
image: result,
|
|
71
|
+
error: undefined
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
} catch (e) {
|
|
75
|
+
const error = e instanceof Error ? e : new Error(`${e}`);
|
|
76
|
+
if (!cancelled) {
|
|
77
|
+
setImage({
|
|
78
|
+
image: undefined,
|
|
79
|
+
error: error
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
})();
|
|
84
|
+
}
|
|
85
|
+
return () => {
|
|
86
|
+
cancelled = true;
|
|
87
|
+
};
|
|
88
|
+
}, [url, blur, isUniformRadius, uniformRadius, topLeft, topRight, bottomLeft, bottomRight, resizeWidth, resizeHeight, cache, enabled]);
|
|
89
|
+
return image;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=useImage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["useEffect","useRef","useState","NitroImagePipeline","useImage","url","blur","cornerRadius","resize","cache","enabled","image","setImage","undefined","error","loadedUrlRef","isUniformRadius","uniformRadius","topLeft","topRight","bottomLeft","bottomRight","resizeWidth","width","resizeHeight","height","cancelled","current","result","loadImage","e","Error"],"sourceRoot":"../../src","sources":["useImage.ts"],"mappings":";;AAAA,SAASA,SAAS,EAAEC,MAAM,EAAEC,QAAQ,QAAQ,OAAO;AAGnD,SAASC,kBAAkB,QAAQ,sBAAsB;AAwBzD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,QAAQA,CAAC;EACvBC,GAAG;EACHC,IAAI,GAAG,CAAC;EACRC,YAAY,GAAG,CAAC;EAChBC,MAAM;EACNC,KAAK;EACLC,OAAO,GAAG;AA+BZ,CAAC,EAAU;EACT,MAAM,CAACC,KAAK,EAAEC,QAAQ,CAAC,GAAGV,QAAQ,CAAS;IACzCS,KAAK,EAAEE,SAAS;IAChBC,KAAK,EAAED;EACT,CAAC,CAAC;EACF,MAAME,YAAY,GAAGd,MAAM,CAACI,GAAG,CAAC;;EAEhC;EACA;EACA,MAAMW,eAAe,GAAG,OAAOT,YAAY,KAAK,QAAQ;EACxD,MAAMU,aAAa,GAAGD,eAAe,GAAGT,YAAY,GAAG,CAAC;EACxD,MAAM;IACJW,OAAO,GAAG,CAAC;IACXC,QAAQ,GAAG,CAAC;IACZC,UAAU,GAAG,CAAC;IACdC,WAAW,GAAG;EAChB,CAAC,GAAGL,eAAe,GAAG,CAAC,CAAC,GAAGT,YAAY;EACvC,MAAMe,WAAW,GAAGd,MAAM,EAAEe,KAAK,IAAI,CAAC;EACtC,MAAMC,YAAY,GAAGhB,MAAM,EAAEiB,MAAM,IAAI,CAAC;EAExCzB,SAAS,CAAC,MAAM;IACd,IAAI0B,SAAS,GAAG,KAAK;IACrB;IACA;IACA;IACA,IAAIX,YAAY,CAACY,OAAO,KAAKtB,GAAG,EAAE;MAChCU,YAAY,CAACY,OAAO,GAAGtB,GAAG;MAC1BO,QAAQ,CAAC;QAAED,KAAK,EAAEE,SAAS;QAAEC,KAAK,EAAED;MAAU,CAAC,CAAC;IAClD;IAEA,IAAIH,OAAO,EAAE;MACX,CAAC,YAAY;QACX,IAAI;UACF,MAAMkB,MAAM,GAAG,MAAMzB,kBAAkB,CAAC0B,SAAS,CAACxB,GAAG,EAAE;YACrDC,IAAI;YACJC,YAAY,EAAES,eAAe,GACzBC,aAAa,GACb;cAAEC,OAAO;cAAEC,QAAQ;cAAEC,UAAU;cAAEC;YAAY,CAAC;YAClDb,MAAM,EACJc,WAAW,GAAG,CAAC,IAAIE,YAAY,GAAG,CAAC,GAC/B;cAAED,KAAK,EAAED,WAAW;cAAEG,MAAM,EAAED;YAAa,CAAC,GAC5CX,SAAS;YACfJ;UACF,CAAC,CAAC;UAEF,IAAI,CAACiB,SAAS,EAAE;YACdd,QAAQ,CAAC;cAAED,KAAK,EAAEiB,MAAM;cAAEd,KAAK,EAAED;YAAU,CAAC,CAAC;UAC/C;QACF,CAAC,CAAC,OAAOiB,CAAC,EAAE;UACV,MAAMhB,KAAK,GAAGgB,CAAC,YAAYC,KAAK,GAAGD,CAAC,GAAG,IAAIC,KAAK,CAAC,GAAGD,CAAC,EAAE,CAAC;UACxD,IAAI,CAACJ,SAAS,EAAE;YACdd,QAAQ,CAAC;cAAED,KAAK,EAAEE,SAAS;cAAEC,KAAK,EAAEA;YAAM,CAAC,CAAC;UAC9C;QACF;MACF,CAAC,EAAE,CAAC;IACN;IAEA,OAAO,MAAM;MACXY,SAAS,GAAG,IAAI;IAClB,CAAC;EACH,CAAC,EAAE,CACDrB,GAAG,EACHC,IAAI,EACJU,eAAe,EACfC,aAAa,EACbC,OAAO,EACPC,QAAQ,EACRC,UAAU,EACVC,WAAW,EACXC,WAAW,EACXE,YAAY,EACZf,KAAK,EACLC,OAAO,CACR,CAAC;EAEF,OAAOC,KAAK;AACd","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NitroImagePipeline.d.ts","sourceRoot":"","sources":["../../../src/NitroImagePipeline.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,IAAI,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AAEtG,eAAO,MAAM,kBAAkB,wBACgD,CAAC"}
|