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,142 @@
1
+ import type { ViewProps } from 'react-native';
2
+ export type FacefusionPreviewProps = ViewProps;
3
+ /**
4
+ * A live view of the frame [swapPhoto]/[swapVideo] just produced — the result the instant
5
+ * it's ready for a photo, and one frame at a time while a video swap is running.
6
+ *
7
+ * No prop carries pixels and none of this crosses the JS bridge: the native side
8
+ * (`PreviewSurfaceHolder.kt`) draws straight into this view's own `Surface` from whichever
9
+ * swap is running. Mount it, give it a size with `style`, and it shows whatever the native
10
+ * layer is currently drawing — there is nothing else to wire up. At most one swap runs at a
11
+ * time (`PipeGuard`), so at most one `<FacefusionPreview />` needs to be mounted to see it.
12
+ */
13
+ export declare const FacefusionPreview: import("react-native").HostComponent<Readonly<Omit<Readonly<{
14
+ onAccessibilityAction?: ((event: import("react-native").AccessibilityActionEvent) => unknown) | undefined;
15
+ onAccessibilityTap?: (() => unknown) | undefined;
16
+ onLayout?: ((event: import("react-native").LayoutChangeEvent) => unknown) | undefined;
17
+ onMagicTap?: (() => unknown) | undefined;
18
+ onAccessibilityEscape?: (() => unknown) | undefined;
19
+ }>, "onMoveShouldSetResponder" | "onMoveShouldSetResponderCapture" | "onResponderGrant" | "onResponderMove" | "onResponderReject" | "onResponderRelease" | "onResponderStart" | "onResponderEnd" | "onResponderTerminate" | "onResponderTerminationRequest" | "onStartShouldSetResponder" | "onStartShouldSetResponderCapture" | "onMouseEnter" | "onMouseLeave" | "onClick" | "onClickCapture" | "onPointerEnter" | "onPointerEnterCapture" | "onPointerLeave" | "onPointerLeaveCapture" | "onPointerMove" | "onPointerMoveCapture" | "onPointerCancel" | "onPointerCancelCapture" | "onPointerDown" | "onPointerDownCapture" | "onPointerUp" | "onPointerUpCapture" | "onPointerOver" | "onPointerOverCapture" | "onPointerOut" | "onPointerOutCapture" | "onGotPointerCapture" | "onGotPointerCaptureCapture" | "onLostPointerCapture" | "onLostPointerCaptureCapture" | "onBlur" | "onBlurCapture" | "onFocus" | "onFocusCapture" | "onKeyDown" | "onKeyDownCapture" | "onKeyUp" | "onKeyUpCapture" | "onTouchCancel" | "onTouchCancelCapture" | "onTouchEnd" | "onTouchEndCapture" | "onTouchMove" | "onTouchMoveCapture" | "onTouchStart" | "onTouchStartCapture" | "nativeBackgroundAndroid" | "nativeForegroundAndroid" | "renderToHardwareTextureAndroid" | "hasTVPreferredFocus" | "nextFocusDown" | "nextFocusForward" | "nextFocusLeft" | "nextFocusRight" | "nextFocusUp" | "focusable" | "tabIndex" | "shouldRasterizeIOS" | "accessibilityIgnoresInvertColors" | "accessibilityViewIsModal" | "accessibilityShowsLargeContentViewer" | "accessibilityLargeContentTitle" | "aria-modal" | "accessibilityElementsHidden" | "accessibilityLanguage" | "accessibilityRespondsToUserInteraction" | "accessible" | "accessibilityLabel" | "accessibilityHint" | "aria-label" | "accessibilityRole" | "role" | "accessibilityState" | "accessibilityValue" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "accessibilityActions" | "aria-busy" | "aria-checked" | "aria-disabled" | "aria-expanded" | "aria-selected" | "aria-hidden" | "accessibilityLabelledBy" | "aria-labelledby" | "accessibilityLiveRegion" | "aria-live" | "importantForAccessibility" | "screenReaderFocusable" | "children" | "style" | "collapsable" | "collapsableChildren" | "id" | "testID" | "nativeID" | "needsOffscreenAlphaCompositing" | "hitSlop" | "pointerEvents" | "removeClippedSubviews" | "experimental_accessibilityOrder"> & Omit<Readonly<{
20
+ onMoveShouldSetResponder?: ((e: import("react-native").GestureResponderEvent) => boolean) | undefined;
21
+ onMoveShouldSetResponderCapture?: ((e: import("react-native").GestureResponderEvent) => boolean) | undefined;
22
+ onResponderGrant?: ((e: import("react-native").GestureResponderEvent) => void | boolean) | undefined;
23
+ onResponderMove?: ((e: import("react-native").GestureResponderEvent) => void) | undefined;
24
+ onResponderReject?: ((e: import("react-native").GestureResponderEvent) => void) | undefined;
25
+ onResponderRelease?: ((e: import("react-native").GestureResponderEvent) => void) | undefined;
26
+ onResponderStart?: ((e: import("react-native").GestureResponderEvent) => void) | undefined;
27
+ onResponderEnd?: ((e: import("react-native").GestureResponderEvent) => void) | undefined;
28
+ onResponderTerminate?: ((e: import("react-native").GestureResponderEvent) => void) | undefined;
29
+ onResponderTerminationRequest?: ((e: import("react-native").GestureResponderEvent) => boolean) | undefined;
30
+ onStartShouldSetResponder?: ((e: import("react-native").GestureResponderEvent) => boolean) | undefined;
31
+ onStartShouldSetResponderCapture?: ((e: import("react-native").GestureResponderEvent) => boolean) | undefined;
32
+ }>, "onMouseEnter" | "onMouseLeave" | "onClick" | "onClickCapture" | "onPointerEnter" | "onPointerEnterCapture" | "onPointerLeave" | "onPointerLeaveCapture" | "onPointerMove" | "onPointerMoveCapture" | "onPointerCancel" | "onPointerCancelCapture" | "onPointerDown" | "onPointerDownCapture" | "onPointerUp" | "onPointerUpCapture" | "onPointerOver" | "onPointerOverCapture" | "onPointerOut" | "onPointerOutCapture" | "onGotPointerCapture" | "onGotPointerCaptureCapture" | "onLostPointerCapture" | "onLostPointerCaptureCapture" | "onBlur" | "onBlurCapture" | "onFocus" | "onFocusCapture" | "onKeyDown" | "onKeyDownCapture" | "onKeyUp" | "onKeyUpCapture" | "onTouchCancel" | "onTouchCancelCapture" | "onTouchEnd" | "onTouchEndCapture" | "onTouchMove" | "onTouchMoveCapture" | "onTouchStart" | "onTouchStartCapture" | "nativeBackgroundAndroid" | "nativeForegroundAndroid" | "renderToHardwareTextureAndroid" | "hasTVPreferredFocus" | "nextFocusDown" | "nextFocusForward" | "nextFocusLeft" | "nextFocusRight" | "nextFocusUp" | "focusable" | "tabIndex" | "shouldRasterizeIOS" | "accessibilityIgnoresInvertColors" | "accessibilityViewIsModal" | "accessibilityShowsLargeContentViewer" | "accessibilityLargeContentTitle" | "aria-modal" | "accessibilityElementsHidden" | "accessibilityLanguage" | "accessibilityRespondsToUserInteraction" | "accessible" | "accessibilityLabel" | "accessibilityHint" | "aria-label" | "accessibilityRole" | "role" | "accessibilityState" | "accessibilityValue" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "accessibilityActions" | "aria-busy" | "aria-checked" | "aria-disabled" | "aria-expanded" | "aria-selected" | "aria-hidden" | "accessibilityLabelledBy" | "aria-labelledby" | "accessibilityLiveRegion" | "aria-live" | "importantForAccessibility" | "screenReaderFocusable" | "children" | "style" | "collapsable" | "collapsableChildren" | "id" | "testID" | "nativeID" | "needsOffscreenAlphaCompositing" | "hitSlop" | "pointerEvents" | "removeClippedSubviews" | "experimental_accessibilityOrder"> & Omit<Readonly<{
33
+ onMouseEnter?: ((event: import("react-native").MouseEvent) => void) | undefined;
34
+ onMouseLeave?: ((event: import("react-native").MouseEvent) => void) | undefined;
35
+ }>, "onClick" | "onClickCapture" | "onPointerEnter" | "onPointerEnterCapture" | "onPointerLeave" | "onPointerLeaveCapture" | "onPointerMove" | "onPointerMoveCapture" | "onPointerCancel" | "onPointerCancelCapture" | "onPointerDown" | "onPointerDownCapture" | "onPointerUp" | "onPointerUpCapture" | "onPointerOver" | "onPointerOverCapture" | "onPointerOut" | "onPointerOutCapture" | "onGotPointerCapture" | "onGotPointerCaptureCapture" | "onLostPointerCapture" | "onLostPointerCaptureCapture" | "onBlur" | "onBlurCapture" | "onFocus" | "onFocusCapture" | "onKeyDown" | "onKeyDownCapture" | "onKeyUp" | "onKeyUpCapture" | "onTouchCancel" | "onTouchCancelCapture" | "onTouchEnd" | "onTouchEndCapture" | "onTouchMove" | "onTouchMoveCapture" | "onTouchStart" | "onTouchStartCapture" | "nativeBackgroundAndroid" | "nativeForegroundAndroid" | "renderToHardwareTextureAndroid" | "hasTVPreferredFocus" | "nextFocusDown" | "nextFocusForward" | "nextFocusLeft" | "nextFocusRight" | "nextFocusUp" | "focusable" | "tabIndex" | "shouldRasterizeIOS" | "accessibilityIgnoresInvertColors" | "accessibilityViewIsModal" | "accessibilityShowsLargeContentViewer" | "accessibilityLargeContentTitle" | "aria-modal" | "accessibilityElementsHidden" | "accessibilityLanguage" | "accessibilityRespondsToUserInteraction" | "accessible" | "accessibilityLabel" | "accessibilityHint" | "aria-label" | "accessibilityRole" | "role" | "accessibilityState" | "accessibilityValue" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "accessibilityActions" | "aria-busy" | "aria-checked" | "aria-disabled" | "aria-expanded" | "aria-selected" | "aria-hidden" | "accessibilityLabelledBy" | "aria-labelledby" | "accessibilityLiveRegion" | "aria-live" | "importantForAccessibility" | "screenReaderFocusable" | "children" | "style" | "collapsable" | "collapsableChildren" | "id" | "testID" | "nativeID" | "needsOffscreenAlphaCompositing" | "hitSlop" | "pointerEvents" | "removeClippedSubviews" | "experimental_accessibilityOrder"> & Omit<Readonly<{
36
+ onClick?: ((event: import("react-native").PointerEvent) => void) | undefined;
37
+ onClickCapture?: ((event: import("react-native").PointerEvent) => void) | undefined;
38
+ onPointerEnter?: ((event: import("react-native").PointerEvent) => void) | undefined;
39
+ onPointerEnterCapture?: ((event: import("react-native").PointerEvent) => void) | undefined;
40
+ onPointerLeave?: ((event: import("react-native").PointerEvent) => void) | undefined;
41
+ onPointerLeaveCapture?: ((event: import("react-native").PointerEvent) => void) | undefined;
42
+ onPointerMove?: ((event: import("react-native").PointerEvent) => void) | undefined;
43
+ onPointerMoveCapture?: ((event: import("react-native").PointerEvent) => void) | undefined;
44
+ onPointerCancel?: ((e: import("react-native").PointerEvent) => void) | undefined;
45
+ onPointerCancelCapture?: ((e: import("react-native").PointerEvent) => void) | undefined;
46
+ onPointerDown?: ((e: import("react-native").PointerEvent) => void) | undefined;
47
+ onPointerDownCapture?: ((e: import("react-native").PointerEvent) => void) | undefined;
48
+ onPointerUp?: ((e: import("react-native").PointerEvent) => void) | undefined;
49
+ onPointerUpCapture?: ((e: import("react-native").PointerEvent) => void) | undefined;
50
+ onPointerOver?: ((e: import("react-native").PointerEvent) => void) | undefined;
51
+ onPointerOverCapture?: ((e: import("react-native").PointerEvent) => void) | undefined;
52
+ onPointerOut?: ((e: import("react-native").PointerEvent) => void) | undefined;
53
+ onPointerOutCapture?: ((e: import("react-native").PointerEvent) => void) | undefined;
54
+ onGotPointerCapture?: ((e: import("react-native").PointerEvent) => void) | undefined;
55
+ onGotPointerCaptureCapture?: ((e: import("react-native").PointerEvent) => void) | undefined;
56
+ onLostPointerCapture?: ((e: import("react-native").PointerEvent) => void) | undefined;
57
+ onLostPointerCaptureCapture?: ((e: import("react-native").PointerEvent) => void) | undefined;
58
+ }>, "onClick" | "onBlur" | "onBlurCapture" | "onFocus" | "onFocusCapture" | "onKeyDown" | "onKeyDownCapture" | "onKeyUp" | "onKeyUpCapture" | "onTouchCancel" | "onTouchCancelCapture" | "onTouchEnd" | "onTouchEndCapture" | "onTouchMove" | "onTouchMoveCapture" | "onTouchStart" | "onTouchStartCapture" | "nativeBackgroundAndroid" | "nativeForegroundAndroid" | "renderToHardwareTextureAndroid" | "hasTVPreferredFocus" | "nextFocusDown" | "nextFocusForward" | "nextFocusLeft" | "nextFocusRight" | "nextFocusUp" | "focusable" | "tabIndex" | "shouldRasterizeIOS" | "accessibilityIgnoresInvertColors" | "accessibilityViewIsModal" | "accessibilityShowsLargeContentViewer" | "accessibilityLargeContentTitle" | "aria-modal" | "accessibilityElementsHidden" | "accessibilityLanguage" | "accessibilityRespondsToUserInteraction" | "accessible" | "accessibilityLabel" | "accessibilityHint" | "aria-label" | "accessibilityRole" | "role" | "accessibilityState" | "accessibilityValue" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "accessibilityActions" | "aria-busy" | "aria-checked" | "aria-disabled" | "aria-expanded" | "aria-selected" | "aria-hidden" | "accessibilityLabelledBy" | "aria-labelledby" | "accessibilityLiveRegion" | "aria-live" | "importantForAccessibility" | "screenReaderFocusable" | "children" | "style" | "collapsable" | "collapsableChildren" | "id" | "testID" | "nativeID" | "needsOffscreenAlphaCompositing" | "hitSlop" | "pointerEvents" | "removeClippedSubviews" | "experimental_accessibilityOrder"> & Omit<Readonly<{
59
+ onBlur?: ((event: import("react-native").BlurEvent) => void) | undefined;
60
+ onBlurCapture?: ((event: import("react-native").BlurEvent) => void) | undefined;
61
+ onFocus?: ((event: import("react-native").FocusEvent) => void) | undefined;
62
+ onFocusCapture?: ((event: import("react-native").FocusEvent) => void) | undefined;
63
+ }>, "onClick" | "onKeyDown" | "onKeyDownCapture" | "onKeyUp" | "onKeyUpCapture" | "onTouchCancel" | "onTouchCancelCapture" | "onTouchEnd" | "onTouchEndCapture" | "onTouchMove" | "onTouchMoveCapture" | "onTouchStart" | "onTouchStartCapture" | "nativeBackgroundAndroid" | "nativeForegroundAndroid" | "renderToHardwareTextureAndroid" | "hasTVPreferredFocus" | "nextFocusDown" | "nextFocusForward" | "nextFocusLeft" | "nextFocusRight" | "nextFocusUp" | "focusable" | "tabIndex" | "shouldRasterizeIOS" | "accessibilityIgnoresInvertColors" | "accessibilityViewIsModal" | "accessibilityShowsLargeContentViewer" | "accessibilityLargeContentTitle" | "aria-modal" | "accessibilityElementsHidden" | "accessibilityLanguage" | "accessibilityRespondsToUserInteraction" | "accessible" | "accessibilityLabel" | "accessibilityHint" | "aria-label" | "accessibilityRole" | "role" | "accessibilityState" | "accessibilityValue" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "accessibilityActions" | "aria-busy" | "aria-checked" | "aria-disabled" | "aria-expanded" | "aria-selected" | "aria-hidden" | "accessibilityLabelledBy" | "aria-labelledby" | "accessibilityLiveRegion" | "aria-live" | "importantForAccessibility" | "screenReaderFocusable" | "children" | "style" | "collapsable" | "collapsableChildren" | "id" | "testID" | "nativeID" | "needsOffscreenAlphaCompositing" | "hitSlop" | "pointerEvents" | "removeClippedSubviews" | "experimental_accessibilityOrder"> & Omit<Readonly<{
64
+ onKeyDown?: ((event: import("react-native").KeyDownEvent) => void) | undefined;
65
+ onKeyDownCapture?: ((event: import("react-native").KeyDownEvent) => void) | undefined;
66
+ onKeyUp?: ((event: import("react-native").KeyUpEvent) => void) | undefined;
67
+ onKeyUpCapture?: ((event: import("react-native").KeyUpEvent) => void) | undefined;
68
+ }>, "onClick" | "onTouchCancel" | "onTouchCancelCapture" | "onTouchEnd" | "onTouchEndCapture" | "onTouchMove" | "onTouchMoveCapture" | "onTouchStart" | "onTouchStartCapture" | "nativeBackgroundAndroid" | "nativeForegroundAndroid" | "renderToHardwareTextureAndroid" | "hasTVPreferredFocus" | "nextFocusDown" | "nextFocusForward" | "nextFocusLeft" | "nextFocusRight" | "nextFocusUp" | "focusable" | "tabIndex" | "shouldRasterizeIOS" | "accessibilityIgnoresInvertColors" | "accessibilityViewIsModal" | "accessibilityShowsLargeContentViewer" | "accessibilityLargeContentTitle" | "aria-modal" | "accessibilityElementsHidden" | "accessibilityLanguage" | "accessibilityRespondsToUserInteraction" | "accessible" | "accessibilityLabel" | "accessibilityHint" | "aria-label" | "accessibilityRole" | "role" | "accessibilityState" | "accessibilityValue" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "accessibilityActions" | "aria-busy" | "aria-checked" | "aria-disabled" | "aria-expanded" | "aria-selected" | "aria-hidden" | "accessibilityLabelledBy" | "aria-labelledby" | "accessibilityLiveRegion" | "aria-live" | "importantForAccessibility" | "screenReaderFocusable" | "children" | "style" | "collapsable" | "collapsableChildren" | "id" | "testID" | "nativeID" | "needsOffscreenAlphaCompositing" | "hitSlop" | "pointerEvents" | "removeClippedSubviews" | "experimental_accessibilityOrder"> & Omit<Readonly<{
69
+ onTouchCancel?: ((e: import("react-native").GestureResponderEvent) => void) | undefined;
70
+ onTouchCancelCapture?: ((e: import("react-native").GestureResponderEvent) => void) | undefined;
71
+ onTouchEnd?: ((e: import("react-native").GestureResponderEvent) => void) | undefined;
72
+ onTouchEndCapture?: ((e: import("react-native").GestureResponderEvent) => void) | undefined;
73
+ onTouchMove?: ((e: import("react-native").GestureResponderEvent) => void) | undefined;
74
+ onTouchMoveCapture?: ((e: import("react-native").GestureResponderEvent) => void) | undefined;
75
+ onTouchStart?: ((e: import("react-native").GestureResponderEvent) => void) | undefined;
76
+ onTouchStartCapture?: ((e: import("react-native").GestureResponderEvent) => void) | undefined;
77
+ }>, "onClick" | "nativeBackgroundAndroid" | "nativeForegroundAndroid" | "renderToHardwareTextureAndroid" | "hasTVPreferredFocus" | "nextFocusDown" | "nextFocusForward" | "nextFocusLeft" | "nextFocusRight" | "nextFocusUp" | "focusable" | "tabIndex" | "shouldRasterizeIOS" | "accessibilityIgnoresInvertColors" | "accessibilityViewIsModal" | "accessibilityShowsLargeContentViewer" | "accessibilityLargeContentTitle" | "aria-modal" | "accessibilityElementsHidden" | "accessibilityLanguage" | "accessibilityRespondsToUserInteraction" | "accessible" | "accessibilityLabel" | "accessibilityHint" | "aria-label" | "accessibilityRole" | "role" | "accessibilityState" | "accessibilityValue" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "accessibilityActions" | "aria-busy" | "aria-checked" | "aria-disabled" | "aria-expanded" | "aria-selected" | "aria-hidden" | "accessibilityLabelledBy" | "aria-labelledby" | "accessibilityLiveRegion" | "aria-live" | "importantForAccessibility" | "screenReaderFocusable" | "children" | "style" | "collapsable" | "collapsableChildren" | "id" | "testID" | "nativeID" | "needsOffscreenAlphaCompositing" | "hitSlop" | "pointerEvents" | "removeClippedSubviews" | "experimental_accessibilityOrder"> & Omit<Readonly<{
78
+ nativeBackgroundAndroid?: import("react-native/types_generated/Libraries/Components/View/ViewPropTypes").AndroidDrawable | undefined;
79
+ nativeForegroundAndroid?: import("react-native/types_generated/Libraries/Components/View/ViewPropTypes").AndroidDrawable | undefined;
80
+ renderToHardwareTextureAndroid?: boolean | undefined;
81
+ hasTVPreferredFocus?: boolean | undefined;
82
+ nextFocusDown?: number | undefined;
83
+ nextFocusForward?: number | undefined;
84
+ nextFocusLeft?: number | undefined;
85
+ nextFocusRight?: number | undefined;
86
+ nextFocusUp?: number | undefined;
87
+ focusable?: boolean | undefined;
88
+ tabIndex?: 0 | -1;
89
+ onClick?: ((event: import("react-native").GestureResponderEvent) => unknown) | undefined;
90
+ }>, "shouldRasterizeIOS" | "accessibilityIgnoresInvertColors" | "accessibilityViewIsModal" | "accessibilityShowsLargeContentViewer" | "accessibilityLargeContentTitle" | "aria-modal" | "accessibilityElementsHidden" | "accessibilityLanguage" | "accessibilityRespondsToUserInteraction" | "accessible" | "accessibilityLabel" | "accessibilityHint" | "aria-label" | "accessibilityRole" | "role" | "accessibilityState" | "accessibilityValue" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "accessibilityActions" | "aria-busy" | "aria-checked" | "aria-disabled" | "aria-expanded" | "aria-selected" | "aria-hidden" | "accessibilityLabelledBy" | "aria-labelledby" | "accessibilityLiveRegion" | "aria-live" | "importantForAccessibility" | "screenReaderFocusable" | "children" | "style" | "collapsable" | "collapsableChildren" | "id" | "testID" | "nativeID" | "needsOffscreenAlphaCompositing" | "hitSlop" | "pointerEvents" | "removeClippedSubviews" | "experimental_accessibilityOrder"> & Omit<Readonly<{
91
+ shouldRasterizeIOS?: boolean | undefined;
92
+ }>, "accessibilityIgnoresInvertColors" | "accessibilityViewIsModal" | "accessibilityShowsLargeContentViewer" | "accessibilityLargeContentTitle" | "aria-modal" | "accessibilityElementsHidden" | "accessibilityLanguage" | "accessibilityRespondsToUserInteraction" | "accessible" | "accessibilityLabel" | "accessibilityHint" | "aria-label" | "accessibilityRole" | "role" | "accessibilityState" | "accessibilityValue" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "accessibilityActions" | "aria-busy" | "aria-checked" | "aria-disabled" | "aria-expanded" | "aria-selected" | "aria-hidden" | "accessibilityLabelledBy" | "aria-labelledby" | "accessibilityLiveRegion" | "aria-live" | "importantForAccessibility" | "screenReaderFocusable" | "children" | "style" | "collapsable" | "collapsableChildren" | "id" | "testID" | "nativeID" | "needsOffscreenAlphaCompositing" | "hitSlop" | "pointerEvents" | "removeClippedSubviews" | "experimental_accessibilityOrder"> & Omit<Readonly<Omit<Readonly<{
93
+ accessibilityLabelledBy?: (string | undefined) | (Array<string> | undefined);
94
+ "aria-labelledby"?: string | undefined;
95
+ accessibilityLiveRegion?: ("none" | "polite" | "assertive") | undefined;
96
+ "aria-live"?: ("polite" | "assertive" | "off") | undefined;
97
+ importantForAccessibility?: ("auto" | "yes" | "no" | "no-hide-descendants") | undefined;
98
+ screenReaderFocusable?: boolean;
99
+ }>, "accessibilityIgnoresInvertColors" | "accessibilityViewIsModal" | "accessibilityShowsLargeContentViewer" | "accessibilityLargeContentTitle" | "aria-modal" | "accessibilityElementsHidden" | "accessibilityLanguage" | "accessibilityRespondsToUserInteraction" | "accessible" | "accessibilityLabel" | "accessibilityHint" | "aria-label" | "accessibilityRole" | "role" | "accessibilityState" | "accessibilityValue" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "accessibilityActions" | "aria-busy" | "aria-checked" | "aria-disabled" | "aria-expanded" | "aria-selected" | "aria-hidden"> & Omit<Readonly<{
100
+ accessibilityIgnoresInvertColors?: boolean | undefined;
101
+ accessibilityViewIsModal?: boolean | undefined;
102
+ accessibilityShowsLargeContentViewer?: boolean | undefined;
103
+ accessibilityLargeContentTitle?: string | undefined;
104
+ "aria-modal"?: boolean | undefined;
105
+ accessibilityElementsHidden?: boolean | undefined;
106
+ accessibilityLanguage?: string | undefined;
107
+ accessibilityRespondsToUserInteraction?: boolean | undefined;
108
+ }>, "accessible" | "accessibilityLabel" | "accessibilityHint" | "aria-label" | "accessibilityRole" | "role" | "accessibilityState" | "accessibilityValue" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "accessibilityActions" | "aria-busy" | "aria-checked" | "aria-disabled" | "aria-expanded" | "aria-selected" | "aria-hidden"> & {
109
+ accessible?: boolean | undefined;
110
+ accessibilityLabel?: string | undefined;
111
+ accessibilityHint?: string | undefined;
112
+ "aria-label"?: string | undefined;
113
+ accessibilityRole?: import("react-native").AccessibilityRole | undefined;
114
+ role?: import("react-native").Role | undefined;
115
+ accessibilityState?: import("react-native").AccessibilityState | undefined;
116
+ accessibilityValue?: import("react-native").AccessibilityValue | undefined;
117
+ "aria-valuemax"?: import("react-native").AccessibilityValue["max"] | undefined;
118
+ "aria-valuemin"?: import("react-native").AccessibilityValue["min"] | undefined;
119
+ "aria-valuenow"?: import("react-native").AccessibilityValue["now"] | undefined;
120
+ "aria-valuetext"?: import("react-native").AccessibilityValue["text"] | undefined;
121
+ accessibilityActions?: ReadonlyArray<import("react-native/types_generated/Libraries/Components/View/ViewAccessibility").AccessibilityActionInfo> | undefined;
122
+ "aria-busy"?: boolean | undefined;
123
+ "aria-checked"?: (boolean | undefined) | "mixed";
124
+ "aria-disabled"?: boolean | undefined;
125
+ "aria-expanded"?: boolean | undefined;
126
+ "aria-selected"?: boolean | undefined;
127
+ "aria-hidden"?: boolean | undefined;
128
+ }>, "children" | "style" | "collapsable" | "collapsableChildren" | "id" | "testID" | "nativeID" | "needsOffscreenAlphaCompositing" | "hitSlop" | "pointerEvents" | "removeClippedSubviews" | "experimental_accessibilityOrder"> & Omit<Readonly<{
129
+ children?: React.ReactNode;
130
+ style?: import("react-native/types_generated/Libraries/StyleSheet/StyleSheet").ViewStyleProp | undefined;
131
+ collapsable?: boolean | undefined;
132
+ collapsableChildren?: boolean | undefined;
133
+ id?: string;
134
+ testID?: string | undefined;
135
+ nativeID?: string | undefined;
136
+ needsOffscreenAlphaCompositing?: boolean | undefined;
137
+ hitSlop?: import("react-native/types_generated/Libraries/StyleSheet/EdgeInsetsPropType").EdgeInsetsOrSizeProp | undefined;
138
+ pointerEvents?: ("auto" | "box-none" | "box-only" | "none") | undefined;
139
+ removeClippedSubviews?: boolean | undefined;
140
+ experimental_accessibilityOrder?: Array<string> | undefined;
141
+ }>, never>>>;
142
+ //# sourceMappingURL=FacefusionPreview.native.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FacefusionPreview.native.d.ts","sourceRoot":"","sources":["../../../src/FacefusionPreview.native.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,MAAM,MAAM,sBAAsB,GAAG,SAAS,CAAC;AAE/C;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAE7B,CAAC"}
@@ -0,0 +1,291 @@
1
+ import { type CodegenTypes, type TurboModule } from 'react-native';
2
+ /**
3
+ * What the device's Hexagon NPU reports about itself.
4
+ *
5
+ * `ok` is the field that decides whether the rest mean anything. `false` means the probe
6
+ * could not run — no Qualcomm NPU, no QNN runtime, an emulator — and *not* that the chip
7
+ * is too old. `tier` and `tierChain` are still usable in that case: they fall back to
8
+ * `v68`, the build that runs on every Hexagon.
9
+ */
10
+ export type DeviceProbeResult = {
11
+ /** True only when the NPU was actually measured. */
12
+ ok: boolean;
13
+ /** The context-binary tier this chip should download — `v68` … `v81`. */
14
+ tier: string;
15
+ /** Every tier that would load here, best first. The downloader wants this one. */
16
+ tierChain: string[];
17
+ /** Hexagon architecture number: 68, 73, 79, 81. `0` when unmeasured. */
18
+ arch: number;
19
+ /** Tightly-coupled memory in MB. The v73/v79/v81 builds need 8. */
20
+ vtcmMb: number;
21
+ /** Qualcomm's SoC id — 69 is SM8750, the 8 Elite. */
22
+ socModel: number;
23
+ signedPd: boolean;
24
+ dlbc: boolean;
25
+ /** Why the probe failed. Empty when `ok`. */
26
+ error: string;
27
+ };
28
+ /**
29
+ * What is on disk, and what the pipeline would load right now.
30
+ *
31
+ * `tier` is resolved against the **files present**, not against the chip: a phone whose
32
+ * best architecture has no published models runs the best tier that does. So this can
33
+ * legitimately differ from `DeviceProbeResult.tier`, and this is the one that matters for
34
+ * "can it run".
35
+ */
36
+ export type ModelStatus = {
37
+ /** The tier that will actually be loaded — best tier whose files are on disk. */
38
+ tier: string;
39
+ /** Every tier this chip could load, best first. */
40
+ tierChain: string[];
41
+ /** Absolute path of the models directory. */
42
+ dir: string;
43
+ /** True when every model the pipeline requires is present and verified. */
44
+ ready: boolean;
45
+ /** Base names of the required models still absent, e.g. `['hyperswap', 'nsfw']`. */
46
+ missing: string[];
47
+ /** Whether the optional face enhancer (`gpen`) is present. */
48
+ hasEnhancer: boolean;
49
+ /** True when the current connection is metered — worth a warning before ~317 MB. */
50
+ metered: boolean;
51
+ };
52
+ /**
53
+ * Tunable knobs for a swap. Every field is optional and defaults to upstream's own default
54
+ * for the `hyperswap` swapper — see `ffpipe::Config` in the vendored C++.
55
+ */
56
+ export type SwapOptions = {
57
+ /** Blends the two identity embeddings before the generator sees them. 0.5 = source,
58
+ * unmodified; above it strengthens the source identity, below it blends the target's
59
+ * identity back in. Default `0.5`. */
60
+ swapperWeight?: number;
61
+ /** Softness of the paste-back mask edge, `0..1`. Default `0.3`. */
62
+ maskBlur?: number;
63
+ /** `[top, right, bottom, left]`, each `0..100` percent. Default `[0, 0, 0, 0]`. */
64
+ maskPadding?: number[];
65
+ /** Minimum detector confidence to count as a face, `0..1`. Default `0.5`. */
66
+ detectorScore?: number;
67
+ /** Minimum landmarker confidence, `0..1`. Default `0.5`. */
68
+ landmarkerScore?: number;
69
+ /** Per-axis upscale of the swap crop: 1 = 256px, 2 = 512px, 3 = 768px, 4 = 1024px. Costs
70
+ * `pixelBoost²` swapper invocations. Default `1`. */
71
+ pixelBoost?: number;
72
+ /** Swap only the largest face instead of every face found. Default `false`. */
73
+ largestFaceOnly?: boolean;
74
+ /** Run the face enhancer after swapping. Silently has no effect if the enhancer model is
75
+ * not on disk — check {@link ModelStatus.hasEnhancer} before offering this. Default
76
+ * `false`. */
77
+ faceEnhance?: boolean;
78
+ /** How much of the enhancer to blend in, `0..1`. `0` is the swapper's output untouched.
79
+ * Default `0.8`. */
80
+ faceEnhancerBlend?: number;
81
+ /**
82
+ * Which face in the source photo to use as the identity, as `[left, top, right,
83
+ * bottom]` from {@link detectSourceFaces} — in the source image's own pixel
84
+ * coordinates, not normalised. Omit for the default: the largest face in the source,
85
+ * same as every swap before this option existed.
86
+ */
87
+ sourceFaceBox?: number[];
88
+ /**
89
+ * Which face in the target to swap, as `[left, top, right, bottom]` from
90
+ * {@link detectTargetFaces} — in the target's own pixel coordinates (for a video, the
91
+ * clip's upright orientation). Omit to swap every face found (subject to
92
+ * {@link SwapOptions.largestFaceOnly}), same as every swap before this option existed.
93
+ * For a video, the box is picked once and held fixed for the whole clip — it is not
94
+ * re-detected frame to frame, so a subject who moves far out of it stops being swapped.
95
+ */
96
+ targetFaceBox?: number[];
97
+ /**
98
+ * `swapVideo` only. Caps how many of the source's frames actually get swapped and
99
+ * encoded — the rest are decoded and dropped, not held back or slowed down, so the
100
+ * output plays at the same real-world duration, just choppier. Omit, or set `>=` the
101
+ * source's own frame rate, to process every frame (default). Lowering this is a direct
102
+ * wall-clock speed lever: half the frames is roughly half the NPU + encode work.
103
+ */
104
+ targetFps?: number;
105
+ };
106
+ /**
107
+ * Tunable knobs for a detect-only pass — the same two thresholds {@link SwapOptions}
108
+ * carries, and they mean exactly the same thing.
109
+ *
110
+ * **Pass the same values here that you pass to the swap.** Two reasons. The obvious one is
111
+ * that a face picker which finds a face the following swap then rejects is a picker that
112
+ * lies. The non-obvious one is cost: these thresholds reach the native pipeline through
113
+ * `initEx`, so changing one re-opens every model graph. Detecting at the defaults and then
114
+ * swapping at your own values pays that reload twice per swap.
115
+ *
116
+ * Lowering {@link detectorScore} is the fix for "it finds the face on one phone and not on
117
+ * another with the same photo" — see the note on that field.
118
+ */
119
+ export type DetectOptions = {
120
+ /**
121
+ * Minimum detector confidence to count as a face, `0..1`. Default `0.5`, which is
122
+ * upstream FaceFusion's own default.
123
+ *
124
+ * **This is the knob that differs by chip.** Every tier ships the same 4.0 MB yoloface
125
+ * graph, but as a *separately compiled* QNN context binary per Hexagon architecture, so
126
+ * the same photo scores differently on a v68 chip than on a v79 one. The cutoff is hard
127
+ * (`score <= detectorScore` is dropped outright), so a face scoring 0.46 on an older
128
+ * chip and 0.58 on a newer one is found on exactly one of them. Offer this as a control
129
+ * rather than treating "no faces" as final; ~0.3 recovers most of the gap.
130
+ */
131
+ detectorScore?: number;
132
+ /** Minimum landmarker confidence, `0..1`. Default `0.5`. */
133
+ landmarkerScore?: number;
134
+ };
135
+ /** One face found in a source photo, in the image's own pixel coordinates. */
136
+ export type DetectedFace = {
137
+ left: number;
138
+ top: number;
139
+ right: number;
140
+ bottom: number;
141
+ /** Detector confidence, `0..1`. */
142
+ score: number;
143
+ /**
144
+ * Width of the image **as actually analysed** — the coordinate space `left`/`right`
145
+ * are in, which is *not* the size of the file on disk.
146
+ *
147
+ * Large photos are subsampled during decode so they fit in memory (a 50 MP photo
148
+ * needs ~950 MB uncapped), and a video target is analysed at its own frame size with
149
+ * no cap at all. So the scale factor differs by input type and cannot be worked out
150
+ * from the file — use these two fields.
151
+ *
152
+ * You do not need them to pick a face: pass a box straight back as
153
+ * `SwapOptions.targetFaceBox`/`sourceFaceBox` and it lines up, because the swap crops
154
+ * in this same space. You *do* need them to draw the box over the original image or
155
+ * crop a thumbnail from it:
156
+ *
157
+ * ```ts
158
+ * const scaleX = displayedWidth / face.imageWidth;
159
+ * const scaleY = displayedHeight / face.imageHeight;
160
+ * const rect = {
161
+ * left: face.left * scaleX,
162
+ * top: face.top * scaleY,
163
+ * width: (face.right - face.left) * scaleX,
164
+ * height: (face.bottom - face.top) * scaleY,
165
+ * };
166
+ * ```
167
+ */
168
+ imageWidth: number;
169
+ /** Height of the image as actually analysed — see {@link DetectedFace.imageWidth}. */
170
+ imageHeight: number;
171
+ };
172
+ /** The result of one still-photo swap. */
173
+ export type SwapPhotoResult = {
174
+ /** Same as the `outputPath` passed in — returned for convenience. */
175
+ outputPath: string;
176
+ /** Faces found in the target. `0` means the swap ran but found nothing to swap, and
177
+ * `outputPath` is then an untouched copy of the target. */
178
+ faceCount: number;
179
+ /** The tier that ran — see {@link ModelStatus.tier}. */
180
+ tier: string;
181
+ };
182
+ /** The result of one video swap. */
183
+ export type SwapVideoResult = {
184
+ /** Same as the `outputPath` passed in — returned for convenience. */
185
+ outputPath: string;
186
+ /** Frames decoded, swapped and re-encoded — the real count. */
187
+ frameCount: number;
188
+ /** Of `frameCount`, how many had at least one face swapped. */
189
+ faceFrameCount: number;
190
+ /** The tier that ran — see {@link ModelStatus.tier}. */
191
+ tier: string;
192
+ /** Measured wall-clock frames/second across the decode-swap-encode loop. Not upstream's
193
+ * per-graph figure — see `docs/MEMORY.md` rule 11. */
194
+ fps: number;
195
+ /** Whether the source clip had an audio track — if so, it was copied to `outputPath`
196
+ * unmodified. */
197
+ hasAudio: boolean;
198
+ };
199
+ /** A tick of progress through a video swap. */
200
+ export type VideoSwapProgress = {
201
+ /** Frames decoded, swapped and encoded so far. */
202
+ frameIndex: number;
203
+ /** Estimated from the container's duration and frame rate. `0` when it could not be
204
+ * estimated — a variable-frame-rate source has no true count until the last frame. */
205
+ estimatedFrameCount: number;
206
+ /** Wall-clock frames/second so far. */
207
+ fps: number;
208
+ };
209
+ /** A download in flight. Byte counts are across the whole set, not the current file. */
210
+ export type ModelDownloadProgress = {
211
+ /** The tier being fetched. May differ from the chip's best tier — see [ModelStatus]. */
212
+ tier: string;
213
+ /** 1-based index of the file being fetched, of `fileCount`. */
214
+ fileIndex: number;
215
+ /** How many files this run has to fetch. Already-present files are not counted. */
216
+ fileCount: number;
217
+ /** File name being fetched, e.g. `hyperswap_v79.bin`. Empty on the final tick. */
218
+ name: string;
219
+ /** Bytes transferred so far across the run, including a resumed `.part`. */
220
+ doneBytes: number;
221
+ /** Bytes this run has to transfer in total. */
222
+ totalBytes: number;
223
+ };
224
+ export interface Spec extends TurboModule {
225
+ probeDevice(): Promise<DeviceProbeResult>;
226
+ getModelStatus(): Promise<ModelStatus>;
227
+ downloadModels(): Promise<ModelStatus>;
228
+ cancelModelDownload(): void;
229
+ readonly onModelDownloadProgress: CodegenTypes.EventEmitter<ModelDownloadProgress>;
230
+ /**
231
+ * Swaps the face from `sourcePath` into every face found in `targetPath`, writing the
232
+ * result to `outputPath`. Paths in, path out — no pixels cross the bridge.
233
+ *
234
+ * Rejects with `E_BUSY` if a swap or video job is already running, `E_MODELS` if the
235
+ * required models are not on disk yet, `E_CONTENT` if the target was refused by the
236
+ * content gate, and `E_SWAP` otherwise.
237
+ */
238
+ swapPhoto(sourcePath: string, targetPath: string, outputPath: string, options?: SwapOptions): Promise<SwapPhotoResult>;
239
+ /**
240
+ * Swaps the face from `sourcePath` into every frame of the video at `targetPath`,
241
+ * writing the result to `outputPath`. Runs behind a foreground service (Android requires
242
+ * one for a job this long) and reports progress via {@link onVideoSwapProgress}.
243
+ *
244
+ * Rejects with `E_BUSY` if a swap or another video job is already running, `E_MODELS` if
245
+ * the required models are not on disk yet, `E_CANCELLED` if {@link cancelVideoSwap} was
246
+ * called, `E_CONTENT` if the target was refused by the content gate, and `E_SWAP`
247
+ * otherwise.
248
+ */
249
+ swapVideo(sourcePath: string, targetPath: string, outputPath: string, options?: SwapOptions): Promise<SwapVideoResult>;
250
+ /** Asks the video swap in flight to stop. Fire-and-forget — the answer arrives as the
251
+ * `E_CANCELLED` rejection of the {@link swapVideo} promise, not from here. */
252
+ cancelVideoSwap(): void;
253
+ readonly onVideoSwapProgress: CodegenTypes.EventEmitter<VideoSwapProgress>;
254
+ /**
255
+ * Every face detected in the photo at `sourcePath`, for a UI to let the user pick one
256
+ * before swapping — pass the chosen face's box back as {@link SwapOptions.sourceFaceBox}.
257
+ * Does not swap or modify anything.
258
+ *
259
+ * Rejects with `E_BUSY` if a swap or video job is already running, `E_MODELS` if the
260
+ * required models are not on disk yet, and `E_DETECT` otherwise.
261
+ */
262
+ detectSourceFaces(sourcePath: string, options?: DetectOptions): Promise<DetectedFace[]>;
263
+ /**
264
+ * Every face detected in the target at `targetPath` — a photo, or a video (its first
265
+ * frame, already upright) — for a UI to let the user pick one before swapping. Pass the
266
+ * chosen face's box back as {@link SwapOptions.targetFaceBox}. Does not swap or modify
267
+ * anything.
268
+ *
269
+ * Rejects with `E_BUSY` if a swap or video job is already running, `E_MODELS` if the
270
+ * required models are not on disk yet, and `E_DETECT` otherwise.
271
+ */
272
+ detectTargetFaces(targetPath: string, options?: DetectOptions): Promise<DetectedFace[]>;
273
+ /**
274
+ * Copies the file at `path` — a `swapPhoto`/`swapVideo` output, typically — into the
275
+ * system's Photos/Gallery app, under a `Facefusion` album. Returns the resulting
276
+ * `content://` URI as a string.
277
+ *
278
+ * `path` and the app that owns it stay exactly as they were; this is a copy, not a move.
279
+ * `mimeType` must be `image/*` or `video/*` — pass the real one for the file (`image/jpeg`
280
+ * for `swapPhoto`'s default output, `video/mp4` for `swapVideo`'s), since there is no safe
281
+ * way to guess it from an arbitrary path. `displayName` defaults to `path`'s own filename.
282
+ *
283
+ * No storage permission is needed for this on Android — inserting new media an app itself
284
+ * created has never required one under scoped storage (API 29+). Rejects with `E_MIME` for
285
+ * an unsupported `mimeType` and `E_SAVE` for anything else, naming what failed.
286
+ */
287
+ saveToGallery(path: string, mimeType: string, displayName?: string): Promise<string>;
288
+ }
289
+ declare const _default: Spec;
290
+ export default _default;
291
+ //# sourceMappingURL=NativeFacefusion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NativeFacefusion.d.ts","sourceRoot":"","sources":["../../../src/NativeFacefusion.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { DetectedFace, DetectOptions } from './NativeFacefusion.js';
2
+ export declare function detectSourceFaces(_sourcePath: string, _options?: DetectOptions): Promise<DetectedFace[]>;
3
+ //# sourceMappingURL=detectSourceFaces.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detectSourceFaces.d.ts","sourceRoot":"","sources":["../../../src/detectSourceFaces.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAoB,CAAC;AAEtE,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,MAAM,EACnB,QAAQ,CAAC,EAAE,aAAa,GACvB,OAAO,CAAC,YAAY,EAAE,CAAC,CAIzB"}
@@ -0,0 +1,11 @@
1
+ import type { DetectedFace, DetectOptions } from './NativeFacefusion.js';
2
+ /**
3
+ * Every face detected in the photo at `sourcePath`, for a UI to let the user pick one
4
+ * before swapping — pass the chosen face's box back as `sourceFaceBox` in `SwapOptions`.
5
+ * Does not swap or modify anything.
6
+ *
7
+ * Rejects with `E_BUSY` if a swap or video job is already running, `E_MODELS` if the
8
+ * required models are not on disk yet, and `E_DETECT` otherwise.
9
+ */
10
+ export declare function detectSourceFaces(sourcePath: string, options?: DetectOptions): Promise<DetectedFace[]>;
11
+ //# sourceMappingURL=detectSourceFaces.native.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detectSourceFaces.native.d.ts","sourceRoot":"","sources":["../../../src/detectSourceFaces.native.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAoB,CAAC;AAEtE;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,aAAa,GACtB,OAAO,CAAC,YAAY,EAAE,CAAC,CAEzB"}
@@ -0,0 +1,3 @@
1
+ import type { DetectedFace, DetectOptions } from './NativeFacefusion.js';
2
+ export declare function detectTargetFaces(_targetPath: string, _options?: DetectOptions): Promise<DetectedFace[]>;
3
+ //# sourceMappingURL=detectTargetFaces.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detectTargetFaces.d.ts","sourceRoot":"","sources":["../../../src/detectTargetFaces.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAoB,CAAC;AAEtE,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,MAAM,EACnB,QAAQ,CAAC,EAAE,aAAa,GACvB,OAAO,CAAC,YAAY,EAAE,CAAC,CAIzB"}
@@ -0,0 +1,9 @@
1
+ import type { DetectedFace, DetectOptions } from './NativeFacefusion.js';
2
+ /**
3
+ * Every face detected in the target at `targetPath` — a photo, or a video (its first
4
+ * frame, already upright) — for a UI to let the user pick one before swapping — pass the
5
+ * chosen face's box back as `targetFaceBox` in `SwapOptions`. Does not swap or modify
6
+ * anything.
7
+ */
8
+ export declare function detectTargetFaces(targetPath: string, options?: DetectOptions): Promise<DetectedFace[]>;
9
+ //# sourceMappingURL=detectTargetFaces.native.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detectTargetFaces.native.d.ts","sourceRoot":"","sources":["../../../src/detectTargetFaces.native.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAoB,CAAC;AAEtE;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,aAAa,GACtB,OAAO,CAAC,YAAY,EAAE,CAAC,CAEzB"}
@@ -0,0 +1,11 @@
1
+ export { probeDevice } from './probeDevice';
2
+ export { getModelStatus, downloadModels, cancelModelDownload, onModelDownloadProgress, } from './models';
3
+ export { swapPhoto } from './swapPhoto';
4
+ export { swapVideo, cancelVideoSwap, onVideoSwapProgress } from './swapVideo';
5
+ export { detectSourceFaces } from './detectSourceFaces';
6
+ export { detectTargetFaces } from './detectTargetFaces';
7
+ export { saveToGallery } from './saveToGallery';
8
+ export { FacefusionPreview } from './FacefusionPreview';
9
+ export type { FacefusionPreviewProps } from './FacefusionPreview';
10
+ export type { DeviceProbeResult, ModelStatus, ModelDownloadProgress, SwapOptions, DetectOptions, SwapPhotoResult, SwapVideoResult, VideoSwapProgress, DetectedFace, } from './NativeFacefusion.js';
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EACL,cAAc,EACd,cAAc,EACd,mBAAmB,EACnB,uBAAuB,GACxB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,YAAY,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAClE,YAAY,EACV,iBAAiB,EACjB,WAAW,EACX,qBAAqB,EACrB,WAAW,EACX,aAAa,EACb,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,YAAY,GACb,MAAM,uBAAoB,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { EventSubscription } from 'react-native';
2
+ import type { ModelStatus, ModelDownloadProgress } from './NativeFacefusion.js';
3
+ export declare function getModelStatus(): Promise<ModelStatus>;
4
+ export declare function downloadModels(): Promise<ModelStatus>;
5
+ export declare function cancelModelDownload(): void;
6
+ export declare function onModelDownloadProgress(_listener: (progress: ModelDownloadProgress) => void): EventSubscription;
7
+ //# sourceMappingURL=models.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../../src/models.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,uBAAoB,CAAC;AAK7E,wBAAgB,cAAc,IAAI,OAAO,CAAC,WAAW,CAAC,CAErD;AAED,wBAAgB,cAAc,IAAI,OAAO,CAAC,WAAW,CAAC,CAErD;AAED,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C;AAED,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,CAAC,QAAQ,EAAE,qBAAqB,KAAK,IAAI,GACnD,iBAAiB,CAEnB"}
@@ -0,0 +1,31 @@
1
+ import type { EventSubscription } from 'react-native';
2
+ import type { ModelStatus, ModelDownloadProgress } from './NativeFacefusion.js';
3
+ /**
4
+ * What is on disk and whether a swap could run right now. Reads the filesystem only —
5
+ * no network, cheap enough to call whenever a screen appears.
6
+ */
7
+ export declare function getModelStatus(): Promise<ModelStatus>;
8
+ /**
9
+ * Download every model this device still needs, resolving with the resulting status.
10
+ *
11
+ * ~317 MB on a fresh install, and minutes on a phone connection. Resumable: an interrupted
12
+ * run leaves `.part` files and calling this again continues from where it stopped, so a
13
+ * retry after a dropped connection is cheap. Files already present and the right size are
14
+ * skipped, so calling it when everything is downloaded costs one manifest request.
15
+ *
16
+ * Rejects with `E_CANCELLED` after {@link cancelModelDownload}, `E_BUSY` if a download is
17
+ * already running, and `E_DOWNLOAD` naming the file that failed otherwise.
18
+ */
19
+ export declare function downloadModels(): Promise<ModelStatus>;
20
+ /**
21
+ * Stop the download in flight. The promise from {@link downloadModels} rejects with
22
+ * `E_CANCELLED`; partial files are kept for a later resume.
23
+ */
24
+ export declare function cancelModelDownload(): void;
25
+ /**
26
+ * Subscribe to download progress. Emits about four times a second while a download runs.
27
+ *
28
+ * Returns the subscription — call `.remove()` on unmount.
29
+ */
30
+ export declare function onModelDownloadProgress(listener: (progress: ModelDownloadProgress) => void): EventSubscription;
31
+ //# sourceMappingURL=models.native.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.native.d.ts","sourceRoot":"","sources":["../../../src/models.native.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,uBAAoB,CAAC;AAE7E;;;GAGG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAAC,WAAW,CAAC,CAErD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAAC,WAAW,CAAC,CAErD;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,CAAC,QAAQ,EAAE,qBAAqB,KAAK,IAAI,GAClD,iBAAiB,CAEnB"}
@@ -0,0 +1,3 @@
1
+ import type { DeviceProbeResult } from './NativeFacefusion.js';
2
+ export declare function probeDevice(): Promise<DeviceProbeResult>;
3
+ //# sourceMappingURL=probeDevice.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"probeDevice.d.ts","sourceRoot":"","sources":["../../../src/probeDevice.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAoB,CAAC;AAE5D,wBAAgB,WAAW,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAIxD"}
@@ -0,0 +1,10 @@
1
+ import type { DeviceProbeResult } from './NativeFacefusion.js';
2
+ /**
3
+ * Ask the device which NPU it has and which model tier it needs.
4
+ *
5
+ * Cheap enough to call on startup, and safe on hardware that has no NPU at all — it
6
+ * resolves with `ok: false` rather than rejecting. It rejects only when the native
7
+ * library itself is missing or unloadable.
8
+ */
9
+ export declare function probeDevice(): Promise<DeviceProbeResult>;
10
+ //# sourceMappingURL=probeDevice.native.d.ts.map