react-native-facefusion 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.
Files changed (122) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +259 -0
  3. package/android/build.gradle +129 -0
  4. package/android/src/main/AndroidManifest.xml +66 -0
  5. package/android/src/main/cpp/CMakeLists.txt +73 -0
  6. package/android/src/main/java/com/facefusion/BitmapDecode.kt +112 -0
  7. package/android/src/main/java/com/facefusion/ContentGate.kt +86 -0
  8. package/android/src/main/java/com/facefusion/DeviceProbe.kt +158 -0
  9. package/android/src/main/java/com/facefusion/FaceCrop.kt +57 -0
  10. package/android/src/main/java/com/facefusion/FacefusionModule.kt +396 -0
  11. package/android/src/main/java/com/facefusion/FacefusionPackage.kt +37 -0
  12. package/android/src/main/java/com/facefusion/FacefusionPreviewView.kt +30 -0
  13. package/android/src/main/java/com/facefusion/FacefusionPreviewViewManager.kt +25 -0
  14. package/android/src/main/java/com/facefusion/GallerySave.kt +82 -0
  15. package/android/src/main/java/com/facefusion/ModelDownload.kt +351 -0
  16. package/android/src/main/java/com/facefusion/ModelPaths.kt +120 -0
  17. package/android/src/main/java/com/facefusion/PhotoSwap.kt +125 -0
  18. package/android/src/main/java/com/facefusion/PipeGuard.kt +74 -0
  19. package/android/src/main/java/com/facefusion/PreviewSurfaceHolder.kt +104 -0
  20. package/android/src/main/java/com/facefusion/SourceFaces.kt +125 -0
  21. package/android/src/main/java/com/facefusion/SwapConfig.kt +31 -0
  22. package/android/src/main/java/com/facefusion/TargetFaces.kt +88 -0
  23. package/android/src/main/java/com/facefusion/VideoSwap.kt +501 -0
  24. package/android/src/main/java/com/facefusion/VideoSwapService.kt +85 -0
  25. package/android/src/main/java/com/facefusion/mobile/NativePipe.kt +192 -0
  26. package/lib/module/FacefusionPreview.js +6 -0
  27. package/lib/module/FacefusionPreview.js.map +1 -0
  28. package/lib/module/FacefusionPreview.native.js +15 -0
  29. package/lib/module/FacefusionPreview.native.js.map +1 -0
  30. package/lib/module/NativeFacefusion.js +53 -0
  31. package/lib/module/NativeFacefusion.js.map +1 -0
  32. package/lib/module/detectSourceFaces.js +6 -0
  33. package/lib/module/detectSourceFaces.js.map +1 -0
  34. package/lib/module/detectSourceFaces.native.js +15 -0
  35. package/lib/module/detectSourceFaces.native.js.map +1 -0
  36. package/lib/module/detectTargetFaces.js +6 -0
  37. package/lib/module/detectTargetFaces.js.map +1 -0
  38. package/lib/module/detectTargetFaces.native.js +13 -0
  39. package/lib/module/detectTargetFaces.native.js.map +1 -0
  40. package/lib/module/index.js +11 -0
  41. package/lib/module/index.js.map +1 -0
  42. package/lib/module/models.js +16 -0
  43. package/lib/module/models.js.map +1 -0
  44. package/lib/module/models.native.js +43 -0
  45. package/lib/module/models.native.js.map +1 -0
  46. package/lib/module/package.json +1 -0
  47. package/lib/module/probeDevice.js +6 -0
  48. package/lib/module/probeDevice.js.map +1 -0
  49. package/lib/module/probeDevice.native.js +14 -0
  50. package/lib/module/probeDevice.native.js.map +1 -0
  51. package/lib/module/saveToGallery.js +6 -0
  52. package/lib/module/saveToGallery.js.map +1 -0
  53. package/lib/module/saveToGallery.native.js +15 -0
  54. package/lib/module/saveToGallery.native.js.map +1 -0
  55. package/lib/module/swapPhoto.js +6 -0
  56. package/lib/module/swapPhoto.js.map +1 -0
  57. package/lib/module/swapPhoto.native.js +16 -0
  58. package/lib/module/swapPhoto.native.js.map +1 -0
  59. package/lib/module/swapVideo.js +12 -0
  60. package/lib/module/swapVideo.js.map +1 -0
  61. package/lib/module/swapVideo.native.js +29 -0
  62. package/lib/module/swapVideo.native.js.map +1 -0
  63. package/lib/typescript/package.json +1 -0
  64. package/lib/typescript/src/FacefusionPreview.d.ts +4 -0
  65. package/lib/typescript/src/FacefusionPreview.d.ts.map +1 -0
  66. package/lib/typescript/src/FacefusionPreview.native.d.ts +142 -0
  67. package/lib/typescript/src/FacefusionPreview.native.d.ts.map +1 -0
  68. package/lib/typescript/src/NativeFacefusion.d.ts +291 -0
  69. package/lib/typescript/src/NativeFacefusion.d.ts.map +1 -0
  70. package/lib/typescript/src/detectSourceFaces.d.ts +3 -0
  71. package/lib/typescript/src/detectSourceFaces.d.ts.map +1 -0
  72. package/lib/typescript/src/detectSourceFaces.native.d.ts +11 -0
  73. package/lib/typescript/src/detectSourceFaces.native.d.ts.map +1 -0
  74. package/lib/typescript/src/detectTargetFaces.d.ts +3 -0
  75. package/lib/typescript/src/detectTargetFaces.d.ts.map +1 -0
  76. package/lib/typescript/src/detectTargetFaces.native.d.ts +9 -0
  77. package/lib/typescript/src/detectTargetFaces.native.d.ts.map +1 -0
  78. package/lib/typescript/src/index.d.ts +11 -0
  79. package/lib/typescript/src/index.d.ts.map +1 -0
  80. package/lib/typescript/src/models.d.ts +7 -0
  81. package/lib/typescript/src/models.d.ts.map +1 -0
  82. package/lib/typescript/src/models.native.d.ts +31 -0
  83. package/lib/typescript/src/models.native.d.ts.map +1 -0
  84. package/lib/typescript/src/probeDevice.d.ts +3 -0
  85. package/lib/typescript/src/probeDevice.d.ts.map +1 -0
  86. package/lib/typescript/src/probeDevice.native.d.ts +10 -0
  87. package/lib/typescript/src/probeDevice.native.d.ts.map +1 -0
  88. package/lib/typescript/src/saveToGallery.d.ts +2 -0
  89. package/lib/typescript/src/saveToGallery.d.ts.map +1 -0
  90. package/lib/typescript/src/saveToGallery.native.d.ts +9 -0
  91. package/lib/typescript/src/saveToGallery.native.d.ts.map +1 -0
  92. package/lib/typescript/src/swapPhoto.d.ts +3 -0
  93. package/lib/typescript/src/swapPhoto.d.ts.map +1 -0
  94. package/lib/typescript/src/swapPhoto.native.d.ts +12 -0
  95. package/lib/typescript/src/swapPhoto.native.d.ts.map +1 -0
  96. package/lib/typescript/src/swapVideo.d.ts +6 -0
  97. package/lib/typescript/src/swapVideo.d.ts.map +1 -0
  98. package/lib/typescript/src/swapVideo.native.d.ts +20 -0
  99. package/lib/typescript/src/swapVideo.native.d.ts.map +1 -0
  100. package/package.json +132 -0
  101. package/patches/ffjni-analyse-faces.patch +63 -0
  102. package/scripts/check-tarball.sh +68 -0
  103. package/scripts/fetch-upstream.sh +91 -0
  104. package/src/FacefusionPreview.native.tsx +18 -0
  105. package/src/FacefusionPreview.tsx +9 -0
  106. package/src/NativeFacefusion.ts +324 -0
  107. package/src/detectSourceFaces.native.tsx +17 -0
  108. package/src/detectSourceFaces.tsx +10 -0
  109. package/src/detectTargetFaces.native.tsx +15 -0
  110. package/src/detectTargetFaces.tsx +10 -0
  111. package/src/index.tsx +25 -0
  112. package/src/models.native.tsx +45 -0
  113. package/src/models.tsx +23 -0
  114. package/src/probeDevice.native.tsx +13 -0
  115. package/src/probeDevice.tsx +7 -0
  116. package/src/saveToGallery.native.tsx +16 -0
  117. package/src/saveToGallery.tsx +9 -0
  118. package/src/swapPhoto.native.tsx +20 -0
  119. package/src/swapPhoto.tsx +12 -0
  120. package/src/swapVideo.native.tsx +40 -0
  121. package/src/swapVideo.tsx +31 -0
  122. package/third_party/facefusion-mobile/NOTICE +49 -0
@@ -0,0 +1,192 @@
1
+ package com.facefusion.mobile
2
+
3
+ /**
4
+ * The JNI surface of `libffnative.so`.
5
+ *
6
+ * **The package name is load-bearing.** JNI binds a Java/Kotlin `external fun` to a C
7
+ * symbol by *name*: `ffjni.cpp` exports `Java_com_facefusion_mobile_NativePipe_probeTier`,
8
+ * which resolves only to a method called `probeTier` on a class called `NativePipe` in
9
+ * the package `com.facefusion.mobile`. Move or rename any part of that and the call
10
+ * fails at runtime with `UnsatisfiedLinkError`, not at build time. So this one file
11
+ * lives outside our own `com.facefusion` package, on purpose, and stays there.
12
+ *
13
+ * This is a Kotlin `object`, so the methods are instance methods on the singleton while
14
+ * `ffjni.cpp` declares its second parameter as `jclass` (the static form). That is fine:
15
+ * the mangled symbol name is identical either way, `jclass` and `jobject` are the same
16
+ * pointer, and every one of these functions ignores that argument.
17
+ *
18
+ * Nothing but `external fun` declarations and the library load belongs here. All of our
19
+ * own logic — path resolution, threading, parsing — lives in `com.facefusion`.
20
+ *
21
+ * Only the functions a shipped phase actually calls are declared. The rest of
22
+ * `ffjni.cpp` (init, setSource, processFrame, the colour converters) arrives with the
23
+ * phase that needs it.
24
+ */
25
+ object NativePipe {
26
+
27
+ /**
28
+ * Null when `libffnative.so` loaded. Otherwise the reason it did not.
29
+ *
30
+ * The load is caught rather than thrown because a throw inside an `object` initialiser
31
+ * poisons the class forever: the first access dies with `ExceptionInInitializerError`
32
+ * and every access after it with a `NoClassDefFoundError` that no longer mentions the
33
+ * real cause. A device without the library should get a clear message, not that.
34
+ */
35
+ var loadError: String? = null
36
+ private set
37
+
38
+ init {
39
+ try {
40
+ System.loadLibrary("ffnative")
41
+ } catch (e: UnsatisfiedLinkError) {
42
+ loadError = e.message ?: e.toString()
43
+ }
44
+ }
45
+
46
+ /** The last error the native layer recorded. Empty when there has not been one. */
47
+ external fun lastError(): String
48
+
49
+ /**
50
+ * The context-binary tier this chip needs — `"v68"` … `"v81"`.
51
+ *
52
+ * `libDir` must hold `libQnnHtp.so` and `libQnnSystem.so`; `skelDir` the matching
53
+ * `libQnnHtpV<n>Skel.so`. In this package both are the app's `nativeLibraryDir`.
54
+ *
55
+ * Never throws and never returns empty: if the QNN backend cannot come up at all it
56
+ * answers `"v68"`, the floor that runs everywhere. Check [probeDeviceInfo] to tell a
57
+ * measured `v68` from a fallback one.
58
+ */
59
+ external fun probeTier(libDir: String, skelDir: String): String
60
+
61
+ /** Every tier this chip can load, best first, comma-joined: `"v81,v73,v68"`. */
62
+ external fun probeTierChain(libDir: String, skelDir: String): String
63
+
64
+ /**
65
+ * What the HTP reports, as `key=value;` pairs — `ok=1;arch=79;vtcm=8;soc=69;…`.
66
+ *
67
+ * `ok=0` means the probe **failed** and every other field is absent. It does not mean
68
+ * the chip is old, and the two must never be collapsed into one answer.
69
+ */
70
+ external fun probeDeviceInfo(libDir: String, skelDir: String): String
71
+
72
+ /**
73
+ * Brings up the pipeline: QNN backend, every required context binary, the swap config.
74
+ *
75
+ * `modelDir` must hold `<name>_<tier>.bin` for the tier this chip measures internally —
76
+ * the same resolution [com.facefusion.ModelPaths.tier] does against disk, so the two
77
+ * are expected to agree (see that file's class doc). `padding` is `[top, right, bottom,
78
+ * left]`, each `0..100`, or null for no padding.
79
+ *
80
+ * Expensive — `dlopen`s the QNN backend and finalises every graph — so callers keep the
81
+ * pipeline warm across calls rather than calling this per swap. See [PipeGuard].
82
+ */
83
+ external fun initEx(
84
+ libDir: String,
85
+ skelDir: String,
86
+ modelDir: String,
87
+ swapperName: String,
88
+ weight: Float,
89
+ maskBlur: Float,
90
+ padding: IntArray?,
91
+ detectorScore: Float,
92
+ landmarkerScore: Float,
93
+ pixelBoost: Int,
94
+ largestOnly: Boolean,
95
+ faceEnhance: Boolean,
96
+ enhanceBlend: Float,
97
+ ): Boolean
98
+
99
+ /** Tears down the pipeline built by [initEx]. Safe to call when nothing is initialised. */
100
+ external fun release()
101
+
102
+ /** Sets the source identity from one BGR image: the largest face's embedding only. */
103
+ external fun setSource(bgr: ByteArray, w: Int, h: Int): Boolean
104
+
105
+ /** Swaps every face in `bgr`, in place. Returns the face count found, or -1 on error. */
106
+ external fun processFrame(bgr: ByteArray, w: Int, h: Int): Int
107
+
108
+ /**
109
+ * Detects every face in `bgr` without swapping — box and confidence only, no embeddings.
110
+ * Flat, 5 floats per face: `[left, top, right, bottom, score] x N`, in `bgr`'s own pixel
111
+ * coordinates. Returns `null` on error (check [lastError]); an empty array is a real
112
+ * answer (no face found), not a failure.
113
+ *
114
+ * The one function in this file that is not upstream's — see
115
+ * `third_party/facefusion-mobile/NOTICE` and `docs/02-upstream.md` "Patches". Lets a
116
+ * multi-face source photo be shown to the user before [setSource] commits to one; the
117
+ * caller picks a face by cropping to its box and calling [setSource] on the crop, not by
118
+ * any parameter here.
119
+ */
120
+ external fun analyseFaces(bgr: ByteArray, w: Int, h: Int): FloatArray?
121
+
122
+ /**
123
+ * Upstream's NSFW content gate on one BGR frame (content_analyser.py:detect_with_nsfw_2).
124
+ * Returns the raw decision statistic `logit[0] - logit[1]` -- the threshold is policy and
125
+ * lives in [com.facefusion.ContentGate], not here -- or `NaN` if the graph did not run
126
+ * (check [lastError]). `NaN` must never be treated as "allow": there is no in-band float
127
+ * that could be mistaken for a real score, which is the point of returning it this way
128
+ * instead of a boolean.
129
+ */
130
+ external fun contentScore(bgr: ByteArray, w: Int, h: Int): Float
131
+
132
+ /**
133
+ * Whether the loaded tier's gate is the quantised build (every tier except v79). The
134
+ * quantised gate sits ~0.087 mean closer to flagging than the fp32 one, measured 16 of 16
135
+ * frames in the same direction -- see `docs/02-upstream.md` "The content gate". Reported
136
+ * alongside a refusal, never compensated for here.
137
+ */
138
+ external fun contentGateIsQuantised(): Boolean
139
+
140
+ /** `Bitmap.getPixels()` output (packed ARGB ints) -> packed BGR bytes for the pipeline. */
141
+ external fun argbToBgr(argb: IntArray, w: Int, h: Int): ByteArray
142
+
143
+ /**
144
+ * Packed BGR bytes -> packed ARGB ints for `Bitmap.setPixels()`, optionally resampling to
145
+ * `dstW`x`dstH`. Pass the source size for both to get an unscaled conversion.
146
+ */
147
+ external fun bgrToArgb(bgr: ByteArray, w: Int, h: Int, dstW: Int, dstH: Int): IntArray
148
+
149
+ /**
150
+ * `YUV_420_888` planes (a MediaCodec decoder's output image) -> packed BGR bytes.
151
+ *
152
+ * `yRow`/`uRow`/`vRow` are each plane's row stride and `uPix`/`vPix` the chroma pixel
153
+ * stride — MediaCodec hands back arbitrary values for both, and semi-planar (NV12/NV21)
154
+ * output is a pixel stride of 2, so passing the raw `Image.Plane` values through
155
+ * unmodified is required; assuming tightly packed I420 renders as green and magenta.
156
+ */
157
+ external fun yuvToBgr(
158
+ y: ByteArray, yRow: Int,
159
+ u: ByteArray, uRow: Int, uPix: Int,
160
+ v: ByteArray, vRow: Int, vPix: Int,
161
+ w: Int, h: Int,
162
+ ): ByteArray
163
+
164
+ /**
165
+ * Rotates a packed BGR frame by 0/90/180/270 degrees clockwise.
166
+ *
167
+ * A portrait clip is stored as LANDSCAPE frames plus a rotation flag in the container —
168
+ * MediaExtractor exposes it as `MediaFormat.KEY_ROTATION` but MediaCodec does not apply
169
+ * it, so a decoded frame is on its side and the detector would find nothing. Rotate
170
+ * upright before [processFrame], then rotate back by `360 - degrees` before encoding so
171
+ * the output keeps the source's own orientation (the muxer still carries the rotation
172
+ * hint). 90/270 swap width and height — callers must resize everything downstream.
173
+ */
174
+ external fun rotateBgr(bgr: ByteArray, w: Int, h: Int, degrees: Int): ByteArray?
175
+
176
+ /**
177
+ * Packed BGR -> the ENCODER's own input planes, honouring its real row/pixel strides.
178
+ *
179
+ * `COLOR_FormatYUV420Flexible` does not mean planar I420 — on-device AVC encoders are
180
+ * commonly semi-planar (NV12), chroma interleaved with pixel stride 2. Writing planar
181
+ * I420 into that puts luma right and chroma wrong, which renders as a grey image with
182
+ * green/pink blobs — closer to right than obviously broken, which is what makes it easy
183
+ * to miss. `yBuf`/`uBuf`/`vBuf` must be the direct `ByteBuffer`s from the encoder's own
184
+ * `Image.getPlanes()` (`getInputImage()`), not caller-allocated buffers.
185
+ */
186
+ external fun bgrToImagePlanes(
187
+ bgr: ByteArray, w: Int, h: Int,
188
+ yBuf: java.nio.ByteBuffer, yRow: Int, yPix: Int,
189
+ uBuf: java.nio.ByteBuffer, uRow: Int, uPix: Int,
190
+ vBuf: java.nio.ByteBuffer, vRow: Int, vPix: Int,
191
+ ): Boolean
192
+ }
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+
3
+ export function FacefusionPreview(_props) {
4
+ throw new Error("'react-native-facefusion' is only supported on native platforms.");
5
+ }
6
+ //# sourceMappingURL=FacefusionPreview.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["FacefusionPreview","_props","Error"],"sourceRoot":"../../src","sources":["FacefusionPreview.tsx"],"mappings":";;AAIA,OAAO,SAASA,iBAAiBA,CAACC,MAA8B,EAAS;EACvE,MAAM,IAAIC,KAAK,CACb,kEACF,CAAC;AACH","ignoreList":[]}
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+
3
+ import { requireNativeComponent } from 'react-native';
4
+ /**
5
+ * A live view of the frame [swapPhoto]/[swapVideo] just produced — the result the instant
6
+ * it's ready for a photo, and one frame at a time while a video swap is running.
7
+ *
8
+ * No prop carries pixels and none of this crosses the JS bridge: the native side
9
+ * (`PreviewSurfaceHolder.kt`) draws straight into this view's own `Surface` from whichever
10
+ * swap is running. Mount it, give it a size with `style`, and it shows whatever the native
11
+ * layer is currently drawing — there is nothing else to wire up. At most one swap runs at a
12
+ * time (`PipeGuard`), so at most one `<FacefusionPreview />` needs to be mounted to see it.
13
+ */
14
+ export const FacefusionPreview = requireNativeComponent('FacefusionPreviewView');
15
+ //# sourceMappingURL=FacefusionPreview.native.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["requireNativeComponent","FacefusionPreview"],"sourceRoot":"../../src","sources":["FacefusionPreview.native.tsx"],"mappings":";;AAAA,SAASA,sBAAsB,QAAQ,cAAc;AAKrD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,iBAAiB,GAAGD,sBAAsB,CACrD,uBACF,CAAC","ignoreList":[]}
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+
3
+ import { TurboModuleRegistry } from 'react-native';
4
+
5
+ /**
6
+ * What the device's Hexagon NPU reports about itself.
7
+ *
8
+ * `ok` is the field that decides whether the rest mean anything. `false` means the probe
9
+ * could not run — no Qualcomm NPU, no QNN runtime, an emulator — and *not* that the chip
10
+ * is too old. `tier` and `tierChain` are still usable in that case: they fall back to
11
+ * `v68`, the build that runs on every Hexagon.
12
+ */
13
+
14
+ /**
15
+ * What is on disk, and what the pipeline would load right now.
16
+ *
17
+ * `tier` is resolved against the **files present**, not against the chip: a phone whose
18
+ * best architecture has no published models runs the best tier that does. So this can
19
+ * legitimately differ from `DeviceProbeResult.tier`, and this is the one that matters for
20
+ * "can it run".
21
+ */
22
+
23
+ /**
24
+ * Tunable knobs for a swap. Every field is optional and defaults to upstream's own default
25
+ * for the `hyperswap` swapper — see `ffpipe::Config` in the vendored C++.
26
+ */
27
+
28
+ /**
29
+ * Tunable knobs for a detect-only pass — the same two thresholds {@link SwapOptions}
30
+ * carries, and they mean exactly the same thing.
31
+ *
32
+ * **Pass the same values here that you pass to the swap.** Two reasons. The obvious one is
33
+ * that a face picker which finds a face the following swap then rejects is a picker that
34
+ * lies. The non-obvious one is cost: these thresholds reach the native pipeline through
35
+ * `initEx`, so changing one re-opens every model graph. Detecting at the defaults and then
36
+ * swapping at your own values pays that reload twice per swap.
37
+ *
38
+ * Lowering {@link detectorScore} is the fix for "it finds the face on one phone and not on
39
+ * another with the same photo" — see the note on that field.
40
+ */
41
+
42
+ /** One face found in a source photo, in the image's own pixel coordinates. */
43
+
44
+ /** The result of one still-photo swap. */
45
+
46
+ /** The result of one video swap. */
47
+
48
+ /** A tick of progress through a video swap. */
49
+
50
+ /** A download in flight. Byte counts are across the whole set, not the current file. */
51
+
52
+ export default TurboModuleRegistry.getEnforcing('Facefusion');
53
+ //# sourceMappingURL=NativeFacefusion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeFacefusion.ts"],"mappings":";;AAAA,SACEA,mBAAmB,QAGd,cAAc;;AAErB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAoBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAkBA;AACA;AACA;AACA;;AAoDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAkBA;;AAsCA;;AAWA;;AAkBA;;AAWA;;AAsGA,eAAeA,mBAAmB,CAACC,YAAY,CAAO,YAAY,CAAC","ignoreList":[]}
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+
3
+ export function detectSourceFaces(_sourcePath, _options) {
4
+ throw new Error("'react-native-facefusion' is only supported on native platforms.");
5
+ }
6
+ //# sourceMappingURL=detectSourceFaces.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["detectSourceFaces","_sourcePath","_options","Error"],"sourceRoot":"../../src","sources":["detectSourceFaces.tsx"],"mappings":";;AAEA,OAAO,SAASA,iBAAiBA,CAC/BC,WAAmB,EACnBC,QAAwB,EACC;EACzB,MAAM,IAAIC,KAAK,CACb,kEACF,CAAC;AACH","ignoreList":[]}
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+
3
+ import Facefusion from "./NativeFacefusion.js";
4
+ /**
5
+ * Every face detected in the photo at `sourcePath`, for a UI to let the user pick one
6
+ * before swapping — pass the chosen face's box back as `sourceFaceBox` in `SwapOptions`.
7
+ * Does not swap or modify anything.
8
+ *
9
+ * Rejects with `E_BUSY` if a swap or video job is already running, `E_MODELS` if the
10
+ * required models are not on disk yet, and `E_DETECT` otherwise.
11
+ */
12
+ export function detectSourceFaces(sourcePath, options) {
13
+ return Facefusion.detectSourceFaces(sourcePath, options);
14
+ }
15
+ //# sourceMappingURL=detectSourceFaces.native.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["Facefusion","detectSourceFaces","sourcePath","options"],"sourceRoot":"../../src","sources":["detectSourceFaces.native.tsx"],"mappings":";;AAAA,OAAOA,UAAU,MAAM,uBAAoB;AAG3C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,iBAAiBA,CAC/BC,UAAkB,EAClBC,OAAuB,EACE;EACzB,OAAOH,UAAU,CAACC,iBAAiB,CAACC,UAAU,EAAEC,OAAO,CAAC;AAC1D","ignoreList":[]}
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+
3
+ export function detectTargetFaces(_targetPath, _options) {
4
+ throw new Error("'react-native-facefusion' is only supported on native platforms.");
5
+ }
6
+ //# sourceMappingURL=detectTargetFaces.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["detectTargetFaces","_targetPath","_options","Error"],"sourceRoot":"../../src","sources":["detectTargetFaces.tsx"],"mappings":";;AAEA,OAAO,SAASA,iBAAiBA,CAC/BC,WAAmB,EACnBC,QAAwB,EACC;EACzB,MAAM,IAAIC,KAAK,CACb,kEACF,CAAC;AACH","ignoreList":[]}
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+
3
+ import Facefusion from "./NativeFacefusion.js";
4
+ /**
5
+ * Every face detected in the target at `targetPath` — a photo, or a video (its first
6
+ * frame, already upright) — for a UI to let the user pick one before swapping — pass the
7
+ * chosen face's box back as `targetFaceBox` in `SwapOptions`. Does not swap or modify
8
+ * anything.
9
+ */
10
+ export function detectTargetFaces(targetPath, options) {
11
+ return Facefusion.detectTargetFaces(targetPath, options);
12
+ }
13
+ //# sourceMappingURL=detectTargetFaces.native.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["Facefusion","detectTargetFaces","targetPath","options"],"sourceRoot":"../../src","sources":["detectTargetFaces.native.tsx"],"mappings":";;AAAA,OAAOA,UAAU,MAAM,uBAAoB;AAG3C;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,iBAAiBA,CAC/BC,UAAkB,EAClBC,OAAuB,EACE;EACzB,OAAOH,UAAU,CAACC,iBAAiB,CAACC,UAAU,EAAEC,OAAO,CAAC;AAC1D","ignoreList":[]}
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+
3
+ export { probeDevice } from './probeDevice';
4
+ export { getModelStatus, downloadModels, cancelModelDownload, onModelDownloadProgress } from './models';
5
+ export { swapPhoto } from './swapPhoto';
6
+ export { swapVideo, cancelVideoSwap, onVideoSwapProgress } from './swapVideo';
7
+ export { detectSourceFaces } from './detectSourceFaces';
8
+ export { detectTargetFaces } from './detectTargetFaces';
9
+ export { saveToGallery } from './saveToGallery';
10
+ export { FacefusionPreview } from './FacefusionPreview';
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["probeDevice","getModelStatus","downloadModels","cancelModelDownload","onModelDownloadProgress","swapPhoto","swapVideo","cancelVideoSwap","onVideoSwapProgress","detectSourceFaces","detectTargetFaces","saveToGallery","FacefusionPreview"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,SAASA,WAAW,QAAQ,eAAe;AAC3C,SACEC,cAAc,EACdC,cAAc,EACdC,mBAAmB,EACnBC,uBAAuB,QAClB,UAAU;AACjB,SAASC,SAAS,QAAQ,aAAa;AACvC,SAASC,SAAS,EAAEC,eAAe,EAAEC,mBAAmB,QAAQ,aAAa;AAC7E,SAASC,iBAAiB,QAAQ,qBAAqB;AACvD,SAASC,iBAAiB,QAAQ,qBAAqB;AACvD,SAASC,aAAa,QAAQ,iBAAiB;AAC/C,SAASC,iBAAiB,QAAQ,qBAAqB","ignoreList":[]}
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+
3
+ const unsupported = () => new Error("'react-native-facefusion' is only supported on native platforms.");
4
+ export function getModelStatus() {
5
+ throw unsupported();
6
+ }
7
+ export function downloadModels() {
8
+ throw unsupported();
9
+ }
10
+ export function cancelModelDownload() {
11
+ throw unsupported();
12
+ }
13
+ export function onModelDownloadProgress(_listener) {
14
+ throw unsupported();
15
+ }
16
+ //# sourceMappingURL=models.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["unsupported","Error","getModelStatus","downloadModels","cancelModelDownload","onModelDownloadProgress","_listener"],"sourceRoot":"../../src","sources":["models.tsx"],"mappings":";;AAGA,MAAMA,WAAW,GAAGA,CAAA,KAClB,IAAIC,KAAK,CAAC,kEAAkE,CAAC;AAE/E,OAAO,SAASC,cAAcA,CAAA,EAAyB;EACrD,MAAMF,WAAW,CAAC,CAAC;AACrB;AAEA,OAAO,SAASG,cAAcA,CAAA,EAAyB;EACrD,MAAMH,WAAW,CAAC,CAAC;AACrB;AAEA,OAAO,SAASI,mBAAmBA,CAAA,EAAS;EAC1C,MAAMJ,WAAW,CAAC,CAAC;AACrB;AAEA,OAAO,SAASK,uBAAuBA,CACrCC,SAAoD,EACjC;EACnB,MAAMN,WAAW,CAAC,CAAC;AACrB","ignoreList":[]}
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+
3
+ import Facefusion from "./NativeFacefusion.js";
4
+ /**
5
+ * What is on disk and whether a swap could run right now. Reads the filesystem only —
6
+ * no network, cheap enough to call whenever a screen appears.
7
+ */
8
+ export function getModelStatus() {
9
+ return Facefusion.getModelStatus();
10
+ }
11
+
12
+ /**
13
+ * Download every model this device still needs, resolving with the resulting status.
14
+ *
15
+ * ~317 MB on a fresh install, and minutes on a phone connection. Resumable: an interrupted
16
+ * run leaves `.part` files and calling this again continues from where it stopped, so a
17
+ * retry after a dropped connection is cheap. Files already present and the right size are
18
+ * skipped, so calling it when everything is downloaded costs one manifest request.
19
+ *
20
+ * Rejects with `E_CANCELLED` after {@link cancelModelDownload}, `E_BUSY` if a download is
21
+ * already running, and `E_DOWNLOAD` naming the file that failed otherwise.
22
+ */
23
+ export function downloadModels() {
24
+ return Facefusion.downloadModels();
25
+ }
26
+
27
+ /**
28
+ * Stop the download in flight. The promise from {@link downloadModels} rejects with
29
+ * `E_CANCELLED`; partial files are kept for a later resume.
30
+ */
31
+ export function cancelModelDownload() {
32
+ Facefusion.cancelModelDownload();
33
+ }
34
+
35
+ /**
36
+ * Subscribe to download progress. Emits about four times a second while a download runs.
37
+ *
38
+ * Returns the subscription — call `.remove()` on unmount.
39
+ */
40
+ export function onModelDownloadProgress(listener) {
41
+ return Facefusion.onModelDownloadProgress(listener);
42
+ }
43
+ //# sourceMappingURL=models.native.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["Facefusion","getModelStatus","downloadModels","cancelModelDownload","onModelDownloadProgress","listener"],"sourceRoot":"../../src","sources":["models.native.tsx"],"mappings":";;AAAA,OAAOA,UAAU,MAAM,uBAAoB;AAI3C;AACA;AACA;AACA;AACA,OAAO,SAASC,cAAcA,CAAA,EAAyB;EACrD,OAAOD,UAAU,CAACC,cAAc,CAAC,CAAC;AACpC;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,cAAcA,CAAA,EAAyB;EACrD,OAAOF,UAAU,CAACE,cAAc,CAAC,CAAC;AACpC;;AAEA;AACA;AACA;AACA;AACA,OAAO,SAASC,mBAAmBA,CAAA,EAAS;EAC1CH,UAAU,CAACG,mBAAmB,CAAC,CAAC;AAClC;;AAEA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,uBAAuBA,CACrCC,QAAmD,EAChC;EACnB,OAAOL,UAAU,CAACI,uBAAuB,CAACC,QAAQ,CAAC;AACrD","ignoreList":[]}
@@ -0,0 +1 @@
1
+ {"type":"module"}
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+
3
+ export function probeDevice() {
4
+ throw new Error("'react-native-facefusion' is only supported on native platforms.");
5
+ }
6
+ //# sourceMappingURL=probeDevice.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["probeDevice","Error"],"sourceRoot":"../../src","sources":["probeDevice.tsx"],"mappings":";;AAEA,OAAO,SAASA,WAAWA,CAAA,EAA+B;EACxD,MAAM,IAAIC,KAAK,CACb,kEACF,CAAC;AACH","ignoreList":[]}
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+
3
+ import Facefusion from "./NativeFacefusion.js";
4
+ /**
5
+ * Ask the device which NPU it has and which model tier it needs.
6
+ *
7
+ * Cheap enough to call on startup, and safe on hardware that has no NPU at all — it
8
+ * resolves with `ok: false` rather than rejecting. It rejects only when the native
9
+ * library itself is missing or unloadable.
10
+ */
11
+ export function probeDevice() {
12
+ return Facefusion.probeDevice();
13
+ }
14
+ //# sourceMappingURL=probeDevice.native.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["Facefusion","probeDevice"],"sourceRoot":"../../src","sources":["probeDevice.native.tsx"],"mappings":";;AAAA,OAAOA,UAAU,MAAM,uBAAoB;AAG3C;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,WAAWA,CAAA,EAA+B;EACxD,OAAOD,UAAU,CAACC,WAAW,CAAC,CAAC;AACjC","ignoreList":[]}
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+
3
+ export function saveToGallery(_path, _mimeType, _displayName) {
4
+ throw new Error("'react-native-facefusion' is only supported on native platforms.");
5
+ }
6
+ //# sourceMappingURL=saveToGallery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["saveToGallery","_path","_mimeType","_displayName","Error"],"sourceRoot":"../../src","sources":["saveToGallery.tsx"],"mappings":";;AAAA,OAAO,SAASA,aAAaA,CAC3BC,KAAa,EACbC,SAAiB,EACjBC,YAAqB,EACJ;EACjB,MAAM,IAAIC,KAAK,CACb,kEACF,CAAC;AACH","ignoreList":[]}
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+
3
+ import Facefusion from "./NativeFacefusion.js";
4
+
5
+ /**
6
+ * Copies a `swapPhoto`/`swapVideo` output into the system's Photos/Gallery app, so it
7
+ * survives beyond this app's own private storage. Returns the resulting `content://` URI.
8
+ *
9
+ * `mimeType` must be `image/*` or `video/*` — pass the real one, there's no safe way to
10
+ * guess it from a path alone. No storage permission is needed on Android.
11
+ */
12
+ export function saveToGallery(path, mimeType, displayName) {
13
+ return Facefusion.saveToGallery(path, mimeType, displayName);
14
+ }
15
+ //# sourceMappingURL=saveToGallery.native.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["Facefusion","saveToGallery","path","mimeType","displayName"],"sourceRoot":"../../src","sources":["saveToGallery.native.tsx"],"mappings":";;AAAA,OAAOA,UAAU,MAAM,uBAAoB;;AAE3C;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,aAAaA,CAC3BC,IAAY,EACZC,QAAgB,EAChBC,WAAoB,EACH;EACjB,OAAOJ,UAAU,CAACC,aAAa,CAACC,IAAI,EAAEC,QAAQ,EAAEC,WAAW,CAAC;AAC9D","ignoreList":[]}
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+
3
+ export function swapPhoto(_sourcePath, _targetPath, _outputPath, _options) {
4
+ throw new Error("'react-native-facefusion' is only supported on native platforms.");
5
+ }
6
+ //# sourceMappingURL=swapPhoto.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["swapPhoto","_sourcePath","_targetPath","_outputPath","_options","Error"],"sourceRoot":"../../src","sources":["swapPhoto.tsx"],"mappings":";;AAEA,OAAO,SAASA,SAASA,CACvBC,WAAmB,EACnBC,WAAmB,EACnBC,WAAmB,EACnBC,QAAsB,EACI;EAC1B,MAAM,IAAIC,KAAK,CACb,kEACF,CAAC;AACH","ignoreList":[]}
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+
3
+ import Facefusion from "./NativeFacefusion.js";
4
+ /**
5
+ * Swaps the face from `sourcePath` into every face found in `targetPath`, writing the
6
+ * result to `outputPath`.
7
+ *
8
+ * Both images are decoded and re-encoded natively — nothing but paths and options crosses
9
+ * the JS bridge. Rejects with `E_BUSY` if another swap (or, from Phase 7, a video job) is
10
+ * already running, `E_MODELS` if the required models are not downloaded yet, and `E_SWAP`
11
+ * for anything else, naming what failed.
12
+ */
13
+ export function swapPhoto(sourcePath, targetPath, outputPath, options) {
14
+ return Facefusion.swapPhoto(sourcePath, targetPath, outputPath, options);
15
+ }
16
+ //# sourceMappingURL=swapPhoto.native.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["Facefusion","swapPhoto","sourcePath","targetPath","outputPath","options"],"sourceRoot":"../../src","sources":["swapPhoto.native.tsx"],"mappings":";;AAAA,OAAOA,UAAU,MAAM,uBAAoB;AAG3C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,SAASA,CACvBC,UAAkB,EAClBC,UAAkB,EAClBC,UAAkB,EAClBC,OAAqB,EACK;EAC1B,OAAOL,UAAU,CAACC,SAAS,CAACC,UAAU,EAAEC,UAAU,EAAEC,UAAU,EAAEC,OAAO,CAAC;AAC1E","ignoreList":[]}
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+
3
+ export function swapVideo(_sourcePath, _targetPath, _outputPath, _options) {
4
+ throw new Error("'react-native-facefusion' is only supported on native platforms.");
5
+ }
6
+ export function cancelVideoSwap() {
7
+ throw new Error("'react-native-facefusion' is only supported on native platforms.");
8
+ }
9
+ export function onVideoSwapProgress(_listener) {
10
+ throw new Error("'react-native-facefusion' is only supported on native platforms.");
11
+ }
12
+ //# sourceMappingURL=swapVideo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["swapVideo","_sourcePath","_targetPath","_outputPath","_options","Error","cancelVideoSwap","onVideoSwapProgress","_listener"],"sourceRoot":"../../src","sources":["swapVideo.tsx"],"mappings":";;AAOA,OAAO,SAASA,SAASA,CACvBC,WAAmB,EACnBC,WAAmB,EACnBC,WAAmB,EACnBC,QAAsB,EACI;EAC1B,MAAM,IAAIC,KAAK,CACb,kEACF,CAAC;AACH;AAEA,OAAO,SAASC,eAAeA,CAAA,EAAS;EACtC,MAAM,IAAID,KAAK,CACb,kEACF,CAAC;AACH;AAEA,OAAO,SAASE,mBAAmBA,CACjCC,SAAgD,EAC7B;EACnB,MAAM,IAAIH,KAAK,CACb,kEACF,CAAC;AACH","ignoreList":[]}
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+
3
+ import Facefusion from "./NativeFacefusion.js";
4
+ /**
5
+ * Swaps the face from `sourcePath` into every frame of the video at `targetPath`, writing
6
+ * the result to `outputPath`.
7
+ *
8
+ * Runs behind a foreground service — Android kills a plain background process partway
9
+ * through a job this long. Rejects with `E_BUSY` if a photo or another video swap is
10
+ * already running, `E_MODELS` if the required models are not downloaded yet, `E_CANCELLED`
11
+ * if `cancelVideoSwap()` was called, and `E_SWAP` for anything else, naming what failed.
12
+ */
13
+ export function swapVideo(sourcePath, targetPath, outputPath, options) {
14
+ return Facefusion.swapVideo(sourcePath, targetPath, outputPath, options);
15
+ }
16
+
17
+ /** Asks the video swap in flight to stop. Fire-and-forget — see `swapVideo`'s doc. */
18
+ export function cancelVideoSwap() {
19
+ Facefusion.cancelVideoSwap();
20
+ }
21
+
22
+ /**
23
+ * Subscribe to video swap progress. Returns the subscription — call `.remove()` on
24
+ * unmount.
25
+ */
26
+ export function onVideoSwapProgress(listener) {
27
+ return Facefusion.onVideoSwapProgress(listener);
28
+ }
29
+ //# sourceMappingURL=swapVideo.native.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["Facefusion","swapVideo","sourcePath","targetPath","outputPath","options","cancelVideoSwap","onVideoSwapProgress","listener"],"sourceRoot":"../../src","sources":["swapVideo.native.tsx"],"mappings":";;AAAA,OAAOA,UAAU,MAAM,uBAAoB;AAQ3C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,SAASA,CACvBC,UAAkB,EAClBC,UAAkB,EAClBC,UAAkB,EAClBC,OAAqB,EACK;EAC1B,OAAOL,UAAU,CAACC,SAAS,CAACC,UAAU,EAAEC,UAAU,EAAEC,UAAU,EAAEC,OAAO,CAAC;AAC1E;;AAEA;AACA,OAAO,SAASC,eAAeA,CAAA,EAAS;EACtCN,UAAU,CAACM,eAAe,CAAC,CAAC;AAC9B;;AAEA;AACA;AACA;AACA;AACA,OAAO,SAASC,mBAAmBA,CACjCC,QAA+C,EAC5B;EACnB,OAAOR,UAAU,CAACO,mBAAmB,CAACC,QAAQ,CAAC;AACjD","ignoreList":[]}
@@ -0,0 +1 @@
1
+ {"type":"module"}
@@ -0,0 +1,4 @@
1
+ import type { ViewProps } from 'react-native';
2
+ export type FacefusionPreviewProps = ViewProps;
3
+ export declare function FacefusionPreview(_props: FacefusionPreviewProps): never;
4
+ //# sourceMappingURL=FacefusionPreview.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FacefusionPreview.d.ts","sourceRoot":"","sources":["../../../src/FacefusionPreview.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,MAAM,MAAM,sBAAsB,GAAG,SAAS,CAAC;AAE/C,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,sBAAsB,GAAG,KAAK,CAIvE"}