react-native-mask-segment-canvas 0.1.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 +904 -0
- package/dist/components/MaskSegmentCanvas.d.ts +6 -0
- package/dist/components/MaskSegmentCanvas.d.ts.map +1 -0
- package/dist/components/MaskSegmentCanvas.js +2012 -0
- package/dist/components/MaskSegmentCanvas.js.map +1 -0
- package/dist/components/MaskSegmentCanvas.types.d.ts +189 -0
- package/dist/components/MaskSegmentCanvas.types.d.ts.map +1 -0
- package/dist/components/MaskSegmentCanvas.types.js +2 -0
- package/dist/components/MaskSegmentCanvas.types.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/shaders/regionPaint.sksl.d.ts +3 -0
- package/dist/shaders/regionPaint.sksl.d.ts.map +1 -0
- package/dist/shaders/regionPaint.sksl.js +72 -0
- package/dist/shaders/regionPaint.sksl.js.map +1 -0
- package/dist/utils/compositePaintedImage.d.ts +44 -0
- package/dist/utils/compositePaintedImage.d.ts.map +1 -0
- package/dist/utils/compositePaintedImage.js +146 -0
- package/dist/utils/compositePaintedImage.js.map +1 -0
- package/dist/utils/exportUtils.d.ts +20 -0
- package/dist/utils/exportUtils.d.ts.map +1 -0
- package/dist/utils/exportUtils.js +32 -0
- package/dist/utils/exportUtils.js.map +1 -0
- package/dist/utils/freqLayerPrep.d.ts +23 -0
- package/dist/utils/freqLayerPrep.d.ts.map +1 -0
- package/dist/utils/freqLayerPrep.js +168 -0
- package/dist/utils/freqLayerPrep.js.map +1 -0
- package/dist/utils/maskSegmentRuntime.d.ts +43 -0
- package/dist/utils/maskSegmentRuntime.d.ts.map +1 -0
- package/dist/utils/maskSegmentRuntime.js +181 -0
- package/dist/utils/maskSegmentRuntime.js.map +1 -0
- package/dist/utils/maskSegmentation.d.ts +133 -0
- package/dist/utils/maskSegmentation.d.ts.map +1 -0
- package/dist/utils/maskSegmentation.js +1600 -0
- package/dist/utils/maskSegmentation.js.map +1 -0
- package/dist/utils/maskSemanticPalette.d.ts +31 -0
- package/dist/utils/maskSemanticPalette.d.ts.map +1 -0
- package/dist/utils/maskSemanticPalette.js +125 -0
- package/dist/utils/maskSemanticPalette.js.map +1 -0
- package/dist/utils/opencvAdapter.d.ts +116 -0
- package/dist/utils/opencvAdapter.d.ts.map +1 -0
- package/dist/utils/opencvAdapter.js +353 -0
- package/dist/utils/opencvAdapter.js.map +1 -0
- package/dist/utils/paintColorMapTexture.d.ts +5 -0
- package/dist/utils/paintColorMapTexture.d.ts.map +1 -0
- package/dist/utils/paintColorMapTexture.js +203 -0
- package/dist/utils/paintColorMapTexture.js.map +1 -0
- package/dist/utils/paintShaderRuntime.d.ts +40 -0
- package/dist/utils/paintShaderRuntime.d.ts.map +1 -0
- package/dist/utils/paintShaderRuntime.js +76 -0
- package/dist/utils/paintShaderRuntime.js.map +1 -0
- package/dist/utils/pickMapTexture.d.ts +4 -0
- package/dist/utils/pickMapTexture.d.ts.map +1 -0
- package/dist/utils/pickMapTexture.js +24 -0
- package/dist/utils/pickMapTexture.js.map +1 -0
- package/dist/utils/pngImage.d.ts +49 -0
- package/dist/utils/pngImage.d.ts.map +1 -0
- package/dist/utils/pngImage.js +438 -0
- package/dist/utils/pngImage.js.map +1 -0
- package/dist/utils/resolveAssetPath.d.ts +3 -0
- package/dist/utils/resolveAssetPath.d.ts.map +1 -0
- package/dist/utils/resolveAssetPath.js +56 -0
- package/dist/utils/resolveAssetPath.js.map +1 -0
- package/dist/utils/resolveImageUrl.d.ts +3 -0
- package/dist/utils/resolveImageUrl.d.ts.map +1 -0
- package/dist/utils/resolveImageUrl.js +51 -0
- package/dist/utils/resolveImageUrl.js.map +1 -0
- package/dist/utils/skiaImage.d.ts +4 -0
- package/dist/utils/skiaImage.d.ts.map +1 -0
- package/dist/utils/skiaImage.js +12 -0
- package/dist/utils/skiaImage.js.map +1 -0
- package/package.json +100 -0
- package/patches/react-native-fast-opencv+0.4.8.patch +122 -0
- package/src/components/MaskSegmentCanvas.tsx +2832 -0
- package/src/components/MaskSegmentCanvas.types.ts +216 -0
- package/src/globals.d.ts +19 -0
- package/src/index.ts +45 -0
- package/src/shaders/regionPaint.sksl.ts +71 -0
- package/src/upng-js.d.ts +33 -0
- package/src/utils/compositePaintedImage.ts +201 -0
- package/src/utils/exportUtils.ts +40 -0
- package/src/utils/freqLayerPrep.ts +267 -0
- package/src/utils/maskSegmentRuntime.ts +257 -0
- package/src/utils/maskSegmentation.ts +2294 -0
- package/src/utils/maskSemanticPalette.ts +187 -0
- package/src/utils/opencvAdapter.ts +539 -0
- package/src/utils/paintColorMapTexture.ts +239 -0
- package/src/utils/paintShaderRuntime.tsx +150 -0
- package/src/utils/pickMapTexture.ts +37 -0
- package/src/utils/pngImage.ts +591 -0
- package/src/utils/resolveAssetPath.ts +64 -0
- package/src/utils/resolveImageUrl.ts +63 -0
- package/src/utils/skiaImage.ts +25 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Image, Platform } from 'react-native';
|
|
2
|
+
import RNFS from 'react-native-fs';
|
|
3
|
+
import { ensurePngFile, toPngFileName } from './pngImage';
|
|
4
|
+
/** 将 require() 资源解析为 PNG 本地路径(OpenCV / RNFS 可读) */
|
|
5
|
+
export async function resolveAssetPath(assetModule, cacheFileName) {
|
|
6
|
+
const pngCacheName = toPngFileName(cacheFileName);
|
|
7
|
+
const source = Image.resolveAssetSource(assetModule);
|
|
8
|
+
if (!source?.uri) {
|
|
9
|
+
throw new Error('Cannot resolve image resource');
|
|
10
|
+
}
|
|
11
|
+
const { uri } = source;
|
|
12
|
+
if (uri.startsWith('file://')) {
|
|
13
|
+
return ensurePngFile(uri, pngCacheName);
|
|
14
|
+
}
|
|
15
|
+
if (Platform.OS === 'ios' && uri.startsWith('/')) {
|
|
16
|
+
return ensurePngFile(uri, pngCacheName);
|
|
17
|
+
}
|
|
18
|
+
if (Platform.OS === 'ios' && uri.startsWith('/')) {
|
|
19
|
+
return ensurePngFile(uri, pngCacheName);
|
|
20
|
+
}
|
|
21
|
+
if (uri.startsWith('http://') || uri.startsWith('https://')) {
|
|
22
|
+
const tmpDest = `${RNFS.CachesDirectoryPath}/tmp_${Date.now()}_${pngCacheName}`;
|
|
23
|
+
const { statusCode } = await RNFS.downloadFile({
|
|
24
|
+
fromUrl: uri,
|
|
25
|
+
toFile: tmpDest,
|
|
26
|
+
}).promise;
|
|
27
|
+
if (statusCode !== 200) {
|
|
28
|
+
throw new Error(`Download resource failed: ${pngCacheName}`);
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
return await ensurePngFile(tmpDest, pngCacheName);
|
|
32
|
+
}
|
|
33
|
+
finally {
|
|
34
|
+
if (await RNFS.exists(tmpDest)) {
|
|
35
|
+
await RNFS.unlink(tmpDest);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (Platform.OS === 'android') {
|
|
40
|
+
const assetPath = uri
|
|
41
|
+
.replace('asset:/', '')
|
|
42
|
+
.replace('file:///android_asset/', '');
|
|
43
|
+
const tmpDest = `${RNFS.CachesDirectoryPath}/tmp_${Date.now()}_${pngCacheName}`;
|
|
44
|
+
await RNFS.copyFileAssets(assetPath, tmpDest);
|
|
45
|
+
try {
|
|
46
|
+
return await ensurePngFile(tmpDest, pngCacheName);
|
|
47
|
+
}
|
|
48
|
+
finally {
|
|
49
|
+
if (await RNFS.exists(tmpDest)) {
|
|
50
|
+
await RNFS.unlink(tmpDest);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return ensurePngFile(uri, pngCacheName);
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=resolveAssetPath.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolveAssetPath.js","sourceRoot":"","sources":["../../src/utils/resolveAssetPath.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,IAAI,MAAM,iBAAiB,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE1D,mDAAmD;AACnD,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,WAAmB,EACnB,aAAqB;IAErB,MAAM,YAAY,GAAG,aAAa,CAAC,aAAa,CAAC,CAAC;IAClD,MAAM,MAAM,GAAG,KAAK,CAAC,kBAAkB,CAAC,WAAW,CAAC,CAAC;IACrD,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE;QAChB,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;KAClD;IAED,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,CAAC;IAEvB,IAAI,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE;QAC7B,OAAO,aAAa,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;KACzC;IAED,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE;QAChD,OAAO,aAAa,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;KACzC;IAED,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE;QAChD,OAAO,aAAa,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;KACzC;IAED,IAAI,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE;QAC3D,MAAM,OAAO,GAAG,GAAG,IAAI,CAAC,mBAAmB,QAAQ,IAAI,CAAC,GAAG,EAAE,IAAI,YAAY,EAAE,CAAC;QAChF,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC;YAC7C,OAAO,EAAE,GAAG;YACZ,MAAM,EAAE,OAAO;SAChB,CAAC,CAAC,OAAO,CAAC;QACX,IAAI,UAAU,KAAK,GAAG,EAAE;YACtB,MAAM,IAAI,KAAK,CAAC,6BAA6B,YAAY,EAAE,CAAC,CAAC;SAC9D;QACD,IAAI;YACF,OAAO,MAAM,aAAa,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;SACnD;gBAAS;YACR,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE;gBAC9B,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;aAC5B;SACF;KACF;IAED,IAAI,QAAQ,CAAC,EAAE,KAAK,SAAS,EAAE;QAC7B,MAAM,SAAS,GAAG,GAAG;aAClB,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC;aACtB,OAAO,CAAC,wBAAwB,EAAE,EAAE,CAAC,CAAC;QACzC,MAAM,OAAO,GAAG,GAAG,IAAI,CAAC,mBAAmB,QAAQ,IAAI,CAAC,GAAG,EAAE,IAAI,YAAY,EAAE,CAAC;QAChF,MAAM,IAAI,CAAC,cAAc,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAC9C,IAAI;YACF,OAAO,MAAM,aAAa,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;SACnD;gBAAS;YACR,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE;gBAC9B,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;aAC5B;SACF;KACF;IAED,OAAO,aAAa,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;AAC1C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolveImageUrl.d.ts","sourceRoot":"","sources":["../../src/utils/resolveImageUrl.ts"],"names":[],"mappings":"AAYA,kDAAkD;AAClD,wBAAsB,eAAe,CACnC,MAAM,EAAE,MAAM,EACd,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,MAAM,CAAC,CA8CjB"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Platform } from 'react-native';
|
|
2
|
+
import RNFS from 'react-native-fs';
|
|
3
|
+
import { ensurePngFile, isPngPath, normalizePath, toPngFileName } from './pngImage';
|
|
4
|
+
function hashUrl(url) {
|
|
5
|
+
let hash = 0;
|
|
6
|
+
for (let i = 0; i < url.length; i++) {
|
|
7
|
+
hash = (hash * 31 + url.charCodeAt(i)) | 0;
|
|
8
|
+
}
|
|
9
|
+
return Math.abs(hash).toString(36);
|
|
10
|
+
}
|
|
11
|
+
/** 将本地路径或远程 URL 解析为 OpenCV / RNFS 可读的 PNG 本地路径 */
|
|
12
|
+
export async function resolveImageUrl(source, cacheFileName) {
|
|
13
|
+
const trimmed = source.trim();
|
|
14
|
+
if (!trimmed) {
|
|
15
|
+
throw new Error('Image URL is empty');
|
|
16
|
+
}
|
|
17
|
+
const pngCacheName = toPngFileName(cacheFileName ?? `img_${hashUrl(trimmed)}.png`);
|
|
18
|
+
if (trimmed.startsWith('http://') || trimmed.startsWith('https://')) {
|
|
19
|
+
const tmpDest = `${RNFS.CachesDirectoryPath}/tmp_${Date.now()}_${pngCacheName}`;
|
|
20
|
+
const { statusCode } = await RNFS.downloadFile({
|
|
21
|
+
fromUrl: trimmed,
|
|
22
|
+
toFile: tmpDest,
|
|
23
|
+
}).promise;
|
|
24
|
+
if (statusCode !== 200) {
|
|
25
|
+
throw new Error(`Download image failed: ${trimmed}`);
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
return await ensurePngFile(tmpDest, pngCacheName);
|
|
29
|
+
}
|
|
30
|
+
finally {
|
|
31
|
+
if (await RNFS.exists(tmpDest)) {
|
|
32
|
+
await RNFS.unlink(tmpDest);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const normalized = normalizePath(trimmed);
|
|
37
|
+
if (await RNFS.exists(normalized) && isPngPath(normalized)) {
|
|
38
|
+
return normalized;
|
|
39
|
+
}
|
|
40
|
+
if (normalized.startsWith('file://')) {
|
|
41
|
+
return ensurePngFile(normalized, pngCacheName);
|
|
42
|
+
}
|
|
43
|
+
if (Platform.OS === 'ios' && normalized.startsWith('/')) {
|
|
44
|
+
return ensurePngFile(normalized, pngCacheName);
|
|
45
|
+
}
|
|
46
|
+
if (await RNFS.exists(normalized)) {
|
|
47
|
+
return ensurePngFile(normalized, pngCacheName);
|
|
48
|
+
}
|
|
49
|
+
return ensurePngFile(trimmed, pngCacheName);
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=resolveImageUrl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolveImageUrl.js","sourceRoot":"","sources":["../../src/utils/resolveImageUrl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,IAAI,MAAM,iBAAiB,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEpF,SAAS,OAAO,CAAC,GAAW;IAC1B,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;QACnC,IAAI,GAAG,CAAC,IAAI,GAAG,EAAE,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;KAC5C;IACD,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACrC,CAAC;AAED,kDAAkD;AAClD,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,MAAc,EACd,aAAsB;IAEtB,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;IAC9B,IAAI,CAAC,OAAO,EAAE;QACZ,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;KACvC;IAED,MAAM,YAAY,GAAG,aAAa,CAChC,aAAa,IAAI,OAAO,OAAO,CAAC,OAAO,CAAC,MAAM,CAC/C,CAAC;IAEF,IAAI,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE;QACnE,MAAM,OAAO,GAAG,GAAG,IAAI,CAAC,mBAAmB,QAAQ,IAAI,CAAC,GAAG,EAAE,IAAI,YAAY,EAAE,CAAC;QAChF,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC;YAC7C,OAAO,EAAE,OAAO;YAChB,MAAM,EAAE,OAAO;SAChB,CAAC,CAAC,OAAO,CAAC;QACX,IAAI,UAAU,KAAK,GAAG,EAAE;YACtB,MAAM,IAAI,KAAK,CAAC,0BAA0B,OAAO,EAAE,CAAC,CAAC;SACtD;QACD,IAAI;YACF,OAAO,MAAM,aAAa,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;SACnD;gBAAS;YACR,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE;gBAC9B,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;aAC5B;SACF;KACF;IAED,MAAM,UAAU,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IAC1C,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,SAAS,CAAC,UAAU,CAAC,EAAE;QAC1D,OAAO,UAAU,CAAC;KACnB;IAED,IAAI,UAAU,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE;QACpC,OAAO,aAAa,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;KAChD;IAED,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,IAAI,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE;QACvD,OAAO,aAAa,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;KAChD;IAED,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE;QACjC,OAAO,aAAa,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;KAChD;IAED,OAAO,aAAa,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;AAC9C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skiaImage.d.ts","sourceRoot":"","sources":["../../src/utils/skiaImage.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,OAAO,EACb,MAAM,4BAA4B,CAAC;AAEpC,wDAAwD;AACxD,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GACX,OAAO,GAAG,IAAI,CAYhB"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Skia, AlphaType, ColorType, } from '@shopify/react-native-skia';
|
|
2
|
+
/** 连续 RGBA 缓冲 → Skia 图像(高低频 / 工作分辨率原图内存直传,避免 PNG 落盘) */
|
|
3
|
+
export function rgbaBufferToSkiaImage(buffer, cols, rows) {
|
|
4
|
+
const data = Skia.Data.fromBytes(buffer);
|
|
5
|
+
return Skia.Image.MakeImage({
|
|
6
|
+
width: cols,
|
|
7
|
+
height: rows,
|
|
8
|
+
alphaType: AlphaType.Opaque,
|
|
9
|
+
colorType: ColorType.RGBA_8888,
|
|
10
|
+
}, data, cols * 4);
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=skiaImage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skiaImage.js","sourceRoot":"","sources":["../../src/utils/skiaImage.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,IAAI,EACJ,SAAS,EACT,SAAS,GAEV,MAAM,4BAA4B,CAAC;AAEpC,wDAAwD;AACxD,MAAM,UAAU,qBAAqB,CACnC,MAAkB,EAClB,IAAY,EACZ,IAAY;IAEZ,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACzC,OAAO,IAAI,CAAC,KAAK,CAAC,SAAS,CACzB;QACE,KAAK,EAAE,IAAI;QACX,MAAM,EAAE,IAAI;QACZ,SAAS,EAAE,SAAS,CAAC,MAAM;QAC3B,SAAS,EAAE,SAAS,CAAC,SAAS;KAC/B,EACD,IAAI,EACJ,IAAI,GAAG,CAAC,CACT,CAAC;AACJ,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "react-native-mask-segment-canvas",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "React Native 掩码分区交互库:OpenCV 语义分割 + SkSL Shader 上色",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"src",
|
|
17
|
+
"patches",
|
|
18
|
+
"README.md"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"android": "react-native run-android",
|
|
22
|
+
"ios": "react-native run-ios",
|
|
23
|
+
"lint": "eslint .",
|
|
24
|
+
"pod:check": "bash ios/scripts/setup_vendor_pods.sh",
|
|
25
|
+
"pod:install": "cd ios && pod install",
|
|
26
|
+
"postinstall": "patch-package",
|
|
27
|
+
"start": "react-native start",
|
|
28
|
+
"test": "jest",
|
|
29
|
+
"build": "tsc -p tsconfig.build.json",
|
|
30
|
+
"prepare": "npm run build"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"buffer": "^6.0.3",
|
|
34
|
+
"upng-js": "^2.1.0"
|
|
35
|
+
},
|
|
36
|
+
"peerDependencies": {
|
|
37
|
+
"@shopify/react-native-skia": ">=2.0.0",
|
|
38
|
+
"react": ">=18",
|
|
39
|
+
"react-native": ">=0.74",
|
|
40
|
+
"react-native-fast-opencv": ">=0.4.8",
|
|
41
|
+
"react-native-fs": ">=2.20.0",
|
|
42
|
+
"react-native-gesture-handler": ">=2.16.0",
|
|
43
|
+
"react-native-image-picker": ">=7.0.0",
|
|
44
|
+
"react-native-reanimated": ">=3.0.0",
|
|
45
|
+
"react-native-safe-area-context": ">=4.0.0"
|
|
46
|
+
},
|
|
47
|
+
"peerDependenciesMeta": {
|
|
48
|
+
"react-native-image-picker": {
|
|
49
|
+
"optional": true
|
|
50
|
+
},
|
|
51
|
+
"react-native-safe-area-context": {
|
|
52
|
+
"optional": true
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@babel/core": "^7.25.2",
|
|
57
|
+
"@babel/preset-env": "^7.25.3",
|
|
58
|
+
"@babel/runtime": "^7.25.0",
|
|
59
|
+
"@react-native-community/cli": "18.0.0",
|
|
60
|
+
"@react-native-community/cli-platform-android": "18.0.0",
|
|
61
|
+
"@react-native-community/cli-platform-ios": "18.0.0",
|
|
62
|
+
"@react-native/babel-preset": "0.79.4",
|
|
63
|
+
"@react-native/eslint-config": "0.79.4",
|
|
64
|
+
"@react-native/metro-config": "0.79.4",
|
|
65
|
+
"@react-native/typescript-config": "0.79.4",
|
|
66
|
+
"@shopify/react-native-skia": "^2.6.4",
|
|
67
|
+
"@types/jest": "^29.5.13",
|
|
68
|
+
"@types/react": "^19.0.0",
|
|
69
|
+
"@types/react-test-renderer": "^19.0.0",
|
|
70
|
+
"eslint": "^8.19.0",
|
|
71
|
+
"jest": "^29.6.3",
|
|
72
|
+
"patch-package": "^8.0.1",
|
|
73
|
+
"prettier": "2.8.8",
|
|
74
|
+
"react": "19.0.0",
|
|
75
|
+
"react-native": "0.79.4",
|
|
76
|
+
"react-native-fast-opencv": "^0.4.8",
|
|
77
|
+
"react-native-fs": "^2.20.0",
|
|
78
|
+
"react-native-gesture-handler": "^2.16.0",
|
|
79
|
+
"react-native-image-picker": "^8.2.1",
|
|
80
|
+
"react-native-reanimated": "^3.19.5",
|
|
81
|
+
"react-native-safe-area-context": "^5.8.0",
|
|
82
|
+
"react-test-renderer": "19.0.0",
|
|
83
|
+
"typescript": "5.0.4"
|
|
84
|
+
},
|
|
85
|
+
"engines": {
|
|
86
|
+
"node": ">=18"
|
|
87
|
+
},
|
|
88
|
+
"keywords": [
|
|
89
|
+
"react-native",
|
|
90
|
+
"mask-segmentation",
|
|
91
|
+
"semantic-segmentation",
|
|
92
|
+
"opencv",
|
|
93
|
+
"skia",
|
|
94
|
+
"shader",
|
|
95
|
+
"image-editing",
|
|
96
|
+
"canvas",
|
|
97
|
+
"paint"
|
|
98
|
+
],
|
|
99
|
+
"license": "MIT"
|
|
100
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
diff --git a/node_modules/react-native-fast-opencv/cpp/ConvertImage.cpp b/node_modules/react-native-fast-opencv/cpp/ConvertImage.cpp
|
|
2
|
+
index ea50bc0..729d648 100644
|
|
3
|
+
--- a/node_modules/react-native-fast-opencv/cpp/ConvertImage.cpp
|
|
4
|
+
+++ b/node_modules/react-native-fast-opencv/cpp/ConvertImage.cpp
|
|
5
|
+
@@ -149,6 +149,39 @@ string ImageConverter::mat2str(const Mat& m, std::string &format)
|
|
6
|
+
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
+Mat ImageConverter::ensure8U(const Mat& img)
|
|
10
|
+
+{
|
|
11
|
+
+ if (img.empty() || img.depth() == CV_8U) {
|
|
12
|
+
+ return img;
|
|
13
|
+
+ }
|
|
14
|
+
+
|
|
15
|
+
+ // Semantic mask PNG: 16-bit RGB stores 8-bit labels as value×257.
|
|
16
|
+
+ if (img.depth() == CV_16U && img.channels() >= 3) {
|
|
17
|
+
+ cv::Mat img8;
|
|
18
|
+
+ if (img.channels() == 4) {
|
|
19
|
+
+ cv::Mat bgr16;
|
|
20
|
+
+ cv::cvtColor(img, bgr16, cv::COLOR_BGRA2BGR);
|
|
21
|
+
+ bgr16.convertTo(img8, CV_8U, 1.0 / 257.0);
|
|
22
|
+
+ } else {
|
|
23
|
+
+ img.convertTo(img8, CV_8U, 1.0 / 257.0);
|
|
24
|
+
+ }
|
|
25
|
+
+ return img8;
|
|
26
|
+
+ }
|
|
27
|
+
+
|
|
28
|
+
+ Mat dst;
|
|
29
|
+
+ const int outType = CV_MAKETYPE(CV_8U, img.channels());
|
|
30
|
+
+ double alpha = 1.0;
|
|
31
|
+
+
|
|
32
|
+
+ if (img.depth() == CV_16U || img.depth() == CV_16S) {
|
|
33
|
+
+ alpha = 255.0 / 65535.0;
|
|
34
|
+
+ } else if (img.depth() == CV_32F || img.depth() == CV_64F) {
|
|
35
|
+
+ alpha = 255.0;
|
|
36
|
+
+ }
|
|
37
|
+
+
|
|
38
|
+
+ img.convertTo(dst, outType, alpha);
|
|
39
|
+
+ return dst;
|
|
40
|
+
+}
|
|
41
|
+
+
|
|
42
|
+
Mat ImageConverter::str2mat(const string& s)
|
|
43
|
+
{
|
|
44
|
+
// Decode data
|
|
45
|
+
@@ -157,5 +190,5 @@ Mat ImageConverter::str2mat(const string& s)
|
|
46
|
+
|
|
47
|
+
cv::Mat img = cv::imdecode(data, IMREAD_UNCHANGED);
|
|
48
|
+
|
|
49
|
+
- return img;
|
|
50
|
+
+ return ensure8U(img);
|
|
51
|
+
}
|
|
52
|
+
diff --git a/node_modules/react-native-fast-opencv/cpp/ConvertImage.hpp b/node_modules/react-native-fast-opencv/cpp/ConvertImage.hpp
|
|
53
|
+
index 79df697..9bd84f2 100644
|
|
54
|
+
--- a/node_modules/react-native-fast-opencv/cpp/ConvertImage.hpp
|
|
55
|
+
+++ b/node_modules/react-native-fast-opencv/cpp/ConvertImage.hpp
|
|
56
|
+
@@ -23,6 +23,8 @@ class ImageConverter {
|
|
57
|
+
public:
|
|
58
|
+
static cv::Mat str2mat(const string& imageBase64);
|
|
59
|
+
static string mat2str(const Mat& img, std::string &format);
|
|
60
|
+
+ /** 16-bit / float PNG 等非常规 depth 统一缩放到 8-bit,避免 matToBuffer(uint8) 误读 */
|
|
61
|
+
+ static cv::Mat ensure8U(const Mat& img);
|
|
62
|
+
|
|
63
|
+
private:
|
|
64
|
+
static std::string base64_encode(uchar const* bytesToEncode, unsigned int inLen);
|
|
65
|
+
diff --git a/node_modules/react-native-fast-opencv/cpp/FOCV_Object.cpp b/node_modules/react-native-fast-opencv/cpp/FOCV_Object.cpp
|
|
66
|
+
index e83166d..5d3268e 100644
|
|
67
|
+
--- a/node_modules/react-native-fast-opencv/cpp/FOCV_Object.cpp
|
|
68
|
+
+++ b/node_modules/react-native-fast-opencv/cpp/FOCV_Object.cpp
|
|
69
|
+
@@ -183,20 +183,20 @@ jsi::Object FOCV_Object::convertToJSI(jsi::Runtime& runtime, const jsi::Value* a
|
|
70
|
+
|
|
71
|
+
switch(hashString(objectType.c_str(), objectType.size())) {
|
|
72
|
+
case hashString("mat", 3): {
|
|
73
|
+
- auto mat = *FOCV_Storage::get<cv::Mat>(id);
|
|
74
|
+
+ const cv::Mat& stored = *FOCV_Storage::get<cv::Mat>(id);
|
|
75
|
+
std::string format = "jpeg";
|
|
76
|
+
|
|
77
|
+
if(arguments[1].isString()) {
|
|
78
|
+
format = arguments[1].asString(runtime).utf8(runtime);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
- mat.convertTo(mat, CV_8U);
|
|
82
|
+
+ const cv::Mat exportMat = ImageConverter::ensure8U(stored);
|
|
83
|
+
|
|
84
|
+
- value.setProperty(runtime, "base64", jsi::String::createFromUtf8(runtime, ImageConverter::mat2str(mat, format)));
|
|
85
|
+
- value.setProperty(runtime, "size", jsi::Value(mat.size));
|
|
86
|
+
- value.setProperty(runtime, "cols", jsi::Value(mat.cols));
|
|
87
|
+
- value.setProperty(runtime, "rows", jsi::Value(mat.rows));
|
|
88
|
+
- value.setProperty(runtime, "type", jsi::Value(mat.type()));
|
|
89
|
+
+ value.setProperty(runtime, "base64", jsi::String::createFromUtf8(runtime, ImageConverter::mat2str(exportMat, format)));
|
|
90
|
+
+ value.setProperty(runtime, "size", jsi::Value(stored.size));
|
|
91
|
+
+ value.setProperty(runtime, "cols", jsi::Value(stored.cols));
|
|
92
|
+
+ value.setProperty(runtime, "rows", jsi::Value(stored.rows));
|
|
93
|
+
+ value.setProperty(runtime, "type", jsi::Value(stored.type()));
|
|
94
|
+
} break;
|
|
95
|
+
case hashString("mat_vector", 10): {
|
|
96
|
+
auto mats = *FOCV_Storage::get<std::vector<cv::Mat>>(id);
|
|
97
|
+
diff --git a/node_modules/react-native-fast-opencv/cpp/react-native-fast-opencv.cpp b/node_modules/react-native-fast-opencv/cpp/react-native-fast-opencv.cpp
|
|
98
|
+
index f0186e5..1289d57 100644
|
|
99
|
+
--- a/node_modules/react-native-fast-opencv/cpp/react-native-fast-opencv.cpp
|
|
100
|
+
+++ b/node_modules/react-native-fast-opencv/cpp/react-native-fast-opencv.cpp
|
|
101
|
+
@@ -160,7 +160,8 @@ jsi::Value OpenCVPlugin::get(jsi::Runtime& runtime, const jsi::PropNameID& propN
|
|
102
|
+
size_t count) -> jsi::Object {
|
|
103
|
+
|
|
104
|
+
auto id = FOCV_JsiObject::id_from_wrap(runtime, arguments[0]);
|
|
105
|
+
- auto mat = *FOCV_Storage::get<cv::Mat>(id);
|
|
106
|
+
+ const cv::Mat& stored = *FOCV_Storage::get<cv::Mat>(id);
|
|
107
|
+
+ cv::Mat mat = stored.isContinuous() ? stored : stored.clone();
|
|
108
|
+
|
|
109
|
+
jsi::Object value(runtime);
|
|
110
|
+
|
|
111
|
+
@@ -169,6 +170,11 @@ jsi::Value OpenCVPlugin::get(jsi::Runtime& runtime, const jsi::PropNameID& propN
|
|
112
|
+
value.setProperty(runtime, "channels", jsi::Value(mat.channels()));
|
|
113
|
+
|
|
114
|
+
auto type = arguments[1].asString(runtime).utf8(runtime);
|
|
115
|
+
+
|
|
116
|
+
+ if(type == "uint8" && mat.depth() != CV_8U) {
|
|
117
|
+
+ mat = ImageConverter::ensure8U(mat);
|
|
118
|
+
+ }
|
|
119
|
+
+
|
|
120
|
+
auto size = mat.cols * mat.rows * mat.channels();
|
|
121
|
+
|
|
122
|
+
if(type == "uint8") {
|