@legendapp/spark 0.0.1-next.2 → 0.0.1-next.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +10 -4
- package/ai-codex.ts +1 -0
- package/ai.ts +1 -0
- package/app-documents.ts +1 -0
- package/camera.ts +13 -0
- package/config-plugin.d.cts +2 -0
- package/contracts.ts +2 -0
- package/diagnostics.ts +1 -0
- package/expo-config.d.cts +1 -0
- package/metro.cjs +4 -1
- package/metro.d.cts +12 -0
- package/native.cjs +3 -1
- package/native.d.cts +6 -0
- package/package.json +93 -15
- package/patches/camera/react-native-nitro-image.patch +320 -0
- package/patches/camera/react-native-nitro-modules.patch +50 -0
- package/patches/camera/react-native-vision-camera.patch +2662 -0
- package/patches/camera/upstream.json +22 -0
- package/patches/dependencies.json +8 -0
- package/patches/react-native-enriched-markdown@1.0.2.patch +8684 -0
- package/postinstall.cjs +1 -0
- package/schema.json +276 -58
- package/settings-observable.ts +1 -0
- package/settings-window.ts +1 -0
- package/shortcuts-commands.ts +1 -0
- package/shortcuts-keyboard.ts +3 -0
- package/ui-classnames.ts +1 -0
- package/ui-glass.ts +1 -0
- package/ui-search.ts +1 -0
- package/ui-sidebar.ts +1 -0
- package/ui-split-view.ts +1 -0
- package/ui-swipe.ts +1 -0
- package/ui-symbol.ts +1 -0
- package/vendor/node_modules/@legendapp/spark-ai/package.json +19 -0
- package/vendor/node_modules/@legendapp/spark-ai/src/availability.ts +17 -0
- package/vendor/node_modules/@legendapp/spark-ai/src/index.ts +15 -0
- package/vendor/node_modules/@legendapp/spark-ai/src/invocations.ts +34 -0
- package/vendor/node_modules/@legendapp/spark-ai/src/output.ts +62 -0
- package/vendor/node_modules/@legendapp/spark-ai/src/run.ts +12 -0
- package/vendor/node_modules/@legendapp/spark-ai/src/types.ts +16 -0
- package/vendor/node_modules/@legendapp/spark-audio/macos/RNSparkAudio.h +2 -1
- package/vendor/node_modules/@legendapp/spark-audio/macos/RNSparkAudio.mm +126 -24
- package/vendor/node_modules/@legendapp/spark-audio/package.json +5 -2
- package/vendor/node_modules/@legendapp/spark-audio/src/NativeSparkAudio.ts +5 -1
- package/vendor/node_modules/@legendapp/spark-audio/src/desktop.ts +36 -32
- package/vendor/node_modules/@legendapp/spark-audio/src/events.ts +11 -0
- package/vendor/node_modules/@legendapp/spark-audio/src/hooks.ts +65 -0
- package/vendor/node_modules/@legendapp/spark-audio/src/index.web.ts +92 -33
- package/vendor/node_modules/@legendapp/spark-audio/src/media-session-unavailable.ts +6 -4
- package/vendor/node_modules/@legendapp/spark-audio/src/media-session.ts +52 -19
- package/vendor/node_modules/@legendapp/spark-audio/src/media-session.web.ts +18 -10
- package/vendor/node_modules/@legendapp/spark-audio/src/media-types.ts +40 -13
- package/vendor/node_modules/@legendapp/spark-audio/src/mobile.ts +40 -32
- package/vendor/node_modules/@legendapp/spark-audio/src/player.ts +97 -0
- package/vendor/node_modules/@legendapp/spark-audio/src/status-listeners.ts +21 -15
- package/vendor/node_modules/@legendapp/spark-audio/src/types.ts +9 -4
- package/vendor/node_modules/@legendapp/spark-audio/windows/SparkAudio/SparkAudio.h +67 -20
- package/vendor/node_modules/@legendapp/spark-auth-session/package.json +4 -3
- package/vendor/node_modules/@legendapp/spark-auth-session/src/core.ts +60 -42
- package/vendor/node_modules/@legendapp/spark-auth-session/src/index.ts +28 -12
- package/vendor/node_modules/@legendapp/spark-auth-session/src/mobile.ts +97 -41
- package/vendor/node_modules/@legendapp/spark-auth-session/src/types.ts +20 -9
- package/vendor/node_modules/@legendapp/spark-cli/dist/add-desktop.js +50 -7
- package/vendor/node_modules/@legendapp/spark-cli/dist/build-mode.js +1 -1
- package/vendor/node_modules/@legendapp/spark-cli/dist/build.js +145 -59
- package/vendor/node_modules/@legendapp/spark-cli/dist/cli-arguments.js +61 -0
- package/vendor/node_modules/@legendapp/spark-cli/dist/commands.js +10 -4
- package/vendor/node_modules/@legendapp/spark-cli/dist/create.js +37 -8
- package/vendor/node_modules/@legendapp/spark-cli/dist/credentials.js +86 -25
- package/vendor/node_modules/@legendapp/spark-cli/dist/dependency-pins.js +132 -0
- package/vendor/node_modules/@legendapp/spark-cli/dist/dev-command.js +13 -4
- package/vendor/node_modules/@legendapp/spark-cli/dist/dev.js +13 -10
- package/vendor/node_modules/@legendapp/spark-cli/dist/errors.js +100 -0
- package/vendor/node_modules/@legendapp/spark-cli/dist/examples.js +2 -2
- package/vendor/node_modules/@legendapp/spark-cli/dist/expo-dev-patch.cjs +4 -2
- package/vendor/node_modules/@legendapp/spark-cli/dist/expo-metro.cjs +1 -1
- package/vendor/node_modules/@legendapp/spark-cli/dist/expo-native.cjs +5 -1
- package/vendor/node_modules/@legendapp/spark-cli/dist/expo-node.js +3 -3
- package/vendor/node_modules/@legendapp/spark-cli/dist/helpers.js +1 -1
- package/vendor/node_modules/@legendapp/spark-cli/dist/index.js +52 -44
- package/vendor/node_modules/@legendapp/spark-cli/dist/json.js +16 -0
- package/vendor/node_modules/@legendapp/spark-cli/dist/local.js +1 -1
- package/vendor/node_modules/@legendapp/spark-cli/dist/metro.cjs +26 -5
- package/vendor/node_modules/@legendapp/spark-cli/dist/native-metadata.js +26 -0
- package/vendor/node_modules/@legendapp/spark-cli/dist/native-patch-preflight.js +86 -0
- package/vendor/node_modules/@legendapp/spark-cli/dist/native-preparation.js +88 -0
- package/vendor/node_modules/@legendapp/spark-cli/dist/notary-profiles.js +75 -0
- package/vendor/node_modules/@legendapp/spark-cli/dist/package.js +4 -2
- package/vendor/node_modules/@legendapp/spark-cli/dist/platform.js +16 -2
- package/vendor/node_modules/@legendapp/spark-cli/dist/process.js +7 -0
- package/vendor/node_modules/@legendapp/spark-cli/dist/project.js +90 -32
- package/vendor/node_modules/@legendapp/spark-cli/dist/release.js +86 -5
- package/vendor/node_modules/@legendapp/spark-cli/dist/release.json +23 -18
- package/vendor/node_modules/@legendapp/spark-cli/dist/runner-install.js +145 -31
- package/vendor/node_modules/@legendapp/spark-cli/dist/signing.js +4 -3
- package/vendor/node_modules/@legendapp/spark-cli/dist/universal.cjs +2 -1
- package/vendor/node_modules/@legendapp/spark-cli/dist/updates.js +41 -4
- package/vendor/node_modules/@legendapp/spark-cli/dist/windows.js +5 -9
- package/vendor/node_modules/@legendapp/spark-cli/package.json +7 -6
- package/vendor/node_modules/@legendapp/spark-cli/templates/blank-typescript/App.tsx +6 -12
- package/vendor/node_modules/@legendapp/spark-cli/templates/blank-typescript/desktop.config.json +5 -3
- package/vendor/node_modules/@legendapp/spark-cli/templates/blank-typescript/package.json +12 -10
- package/vendor/node_modules/@legendapp/spark-cli/templates/diff-lite/Git.macos.tsx +2 -2
- package/vendor/node_modules/@legendapp/spark-cli/templates/document-editor/Integration.macos.tsx +23 -21
- package/vendor/node_modules/@legendapp/spark-cli/templates/document-editor/Integration.windows.tsx +23 -21
- package/vendor/node_modules/@legendapp/spark-cli/templates/document-editor/io.desktop.ts +11 -8
- package/vendor/node_modules/@legendapp/spark-cli/templates/document-editor/io.macos.ts +3 -3
- package/vendor/node_modules/@legendapp/spark-cli/templates/example-shared/Lifecycle.desktop.tsx +8 -14
- package/vendor/node_modules/@legendapp/spark-cli/templates/example-shared/OpenFiles.desktop.tsx +5 -10
- package/vendor/node_modules/@legendapp/spark-cli/templates/example-shared/io.desktop.ts +11 -8
- package/vendor/node_modules/@legendapp/spark-cli/templates/example-shared/io.macos.ts +3 -3
- package/vendor/node_modules/@legendapp/spark-cli/templates/music-lite/assets.desktop.ts +2 -2
- package/vendor/node_modules/@legendapp/spark-cli/templates/notes-lite/Activation.desktop.tsx +2 -2
- package/vendor/node_modules/@legendapp/spark-cli/templates/notes-lite/Desktop.desktop.ts +37 -15
- package/vendor/node_modules/@legendapp/spark-cli/templates/notes-lite/session.ts +5 -6
- package/vendor/node_modules/@legendapp/spark-cli/templates/notes-lite/window-session.ts +5 -4
- package/vendor/node_modules/@legendapp/spark-cli/templates/universal/desktop.config.json +5 -3
- package/vendor/node_modules/@legendapp/spark-cli/templates/universal/metro.config.js +1 -1
- package/vendor/node_modules/@legendapp/spark-cli/templates/universal/package.json +14 -12
- package/vendor/node_modules/@legendapp/spark-cli/templates/universal/react-native.config.js +1 -1
- package/vendor/node_modules/@legendapp/spark-cli/templates/windows/package.json +14 -12
- package/vendor/node_modules/@legendapp/spark-cli/templates/windows/react-native.config.js +1 -1
- package/vendor/node_modules/@legendapp/spark-clipboard/macos/RNDesktopClipboard.mm +10 -16
- package/vendor/node_modules/@legendapp/spark-clipboard/package.json +2 -2
- package/vendor/node_modules/@legendapp/spark-clipboard/src/NativeDesktopClipboard.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-clipboard/src/desktop.ts +55 -31
- package/vendor/node_modules/@legendapp/spark-clipboard/src/expo.ts +21 -11
- package/vendor/node_modules/@legendapp/spark-clipboard/src/options.ts +8 -0
- package/vendor/node_modules/@legendapp/spark-clipboard/src/types.ts +10 -0
- package/vendor/node_modules/@legendapp/spark-clipboard/windows/SparkClipboard/SparkClipboard.h +38 -15
- package/vendor/node_modules/@legendapp/spark-clipboard/windows/SparkClipboard/SparkClipboard.vcxproj +2 -0
- package/vendor/node_modules/@legendapp/spark-codex/RNCodex.podspec +22 -0
- package/vendor/node_modules/@legendapp/spark-codex/cpp/HybridCodexAppServer.hpp +23 -0
- package/vendor/node_modules/@legendapp/spark-codex/cpp/HybridCodexAppServer.mm +1529 -0
- package/vendor/node_modules/@legendapp/spark-codex/nitro.json +21 -0
- package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/.gitattributes +1 -0
- package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/ios/RNCodex+autolinking.rb +62 -0
- package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/ios/RNCodex-Swift-Cxx-Bridge.cpp +17 -0
- package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/ios/RNCodex-Swift-Cxx-Bridge.hpp +27 -0
- package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/ios/RNCodex-Swift-Cxx-Umbrella.hpp +38 -0
- package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/ios/RNCodexAutolinking.mm +35 -0
- package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/ios/RNCodexAutolinking.swift +16 -0
- package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/shared/c++/CodexAvailability.hpp +95 -0
- package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/shared/c++/CodexRunResult.hpp +99 -0
- package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/shared/c++/HybridCodexAppServerSpec.cpp +24 -0
- package/vendor/node_modules/@legendapp/spark-codex/nitrogen/generated/shared/c++/HybridCodexAppServerSpec.hpp +71 -0
- package/vendor/node_modules/@legendapp/spark-codex/package.json +35 -0
- package/vendor/node_modules/@legendapp/spark-codex/react-native.config.js +11 -0
- package/vendor/node_modules/@legendapp/spark-codex/src/Codex.nitro.ts +30 -0
- package/vendor/node_modules/@legendapp/spark-codex/src/index.ts +65 -0
- package/vendor/node_modules/@legendapp/spark-codex/src/native.ts +6 -0
- package/vendor/node_modules/@legendapp/spark-commands/package.json +21 -0
- package/vendor/node_modules/@legendapp/spark-commands/src/bindings.ts +90 -0
- package/vendor/node_modules/@legendapp/spark-commands/src/index.tsx +400 -0
- package/vendor/node_modules/@legendapp/spark-commands/src/router.ts +138 -0
- package/vendor/node_modules/@legendapp/spark-commands/src/storage.ts +20 -0
- package/vendor/node_modules/@legendapp/spark-context-menu/macos/RNContextMenu.mm +7 -8
- package/vendor/node_modules/@legendapp/spark-context-menu/package.json +4 -3
- package/vendor/node_modules/@legendapp/spark-context-menu/src/NativeContextMenu.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-context-menu/src/index.ts +26 -26
- package/vendor/node_modules/@legendapp/spark-context-menu/windows/SparkContextMenu/SparkContextMenu.h +3 -2
- package/vendor/node_modules/@legendapp/spark-desktop-app/RNDesktopApp.podspec +2 -1
- package/vendor/node_modules/@legendapp/spark-desktop-app/cpp/SparkBinaryJSI.hpp +89 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/cpp/SparkBinaryWindows.hpp +22 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/macos/RNDesktopApp.mm +13 -7
- package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkBinaryJSI.h +48 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkDesktop.h +4 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkDesktop.mm +33 -33
- package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkDesktopError.h +20 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkLifecycle.h +26 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkLifecycle.mm +49 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkQuitCoordinator.h +9 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkQuitCoordinator.mm +70 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/macos/SparkWindow.mm +9 -6
- package/vendor/node_modules/@legendapp/spark-desktop-app/macos/recent-documents/RNRecentDocumentController.mm +55 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/package.json +5 -3
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/NativeDesktopApp.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/api.ts +86 -40
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/contracts/accelerator.ts +40 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/contracts/index.ts +56 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/contracts/menu.ts +116 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/contracts/native-buffer.ts +22 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/contracts/path.ts +24 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/events.ts +75 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/index.ts +2 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/index.windows.ts +2 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/open-requests.ts +43 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/restoration.ts +11 -0
- package/vendor/node_modules/@legendapp/spark-desktop-app/src/transport.ts +10 -0
- package/vendor/node_modules/@legendapp/spark-desktop-config/app.plugin.cjs +10 -5
- package/vendor/node_modules/@legendapp/spark-desktop-config/app.plugin.d.cts +3 -0
- package/vendor/node_modules/@legendapp/spark-desktop-config/autolinking.cjs +35 -0
- package/vendor/node_modules/@legendapp/spark-desktop-config/config.cjs +18 -3
- package/vendor/node_modules/@legendapp/spark-desktop-config/config.d.cts +89 -9
- package/vendor/node_modules/@legendapp/spark-desktop-config/expo.cjs +1 -0
- package/vendor/node_modules/@legendapp/spark-desktop-config/expo.d.cts +3 -0
- package/vendor/node_modules/@legendapp/spark-desktop-config/identity.cjs +3 -2
- package/vendor/node_modules/@legendapp/spark-desktop-config/lifecycle.cjs +20 -0
- package/vendor/node_modules/@legendapp/spark-desktop-config/native-patches.cjs +106 -0
- package/vendor/node_modules/@legendapp/spark-desktop-config/native-patches.d.cts +1 -0
- package/vendor/node_modules/@legendapp/spark-desktop-config/package.json +7 -5
- package/vendor/node_modules/@legendapp/spark-desktop-config/schema.json +276 -58
- package/vendor/node_modules/@legendapp/spark-desktop-config/updates.cjs +1 -0
- package/vendor/node_modules/@legendapp/spark-desktop-config/validation.cjs +35 -0
- package/vendor/node_modules/@legendapp/spark-desktop-config/windows.plugin.cjs +2 -1
- package/vendor/node_modules/@legendapp/spark-desktop-host/AppDelegate.mm +129 -11
- package/vendor/node_modules/@legendapp/spark-desktop-host/package.json +2 -2
- package/vendor/node_modules/@legendapp/spark-desktop-host/windows/application.inc +277 -121
- package/vendor/node_modules/@legendapp/spark-desktop-links/common/AuthLoopback.h +5 -7
- package/vendor/node_modules/@legendapp/spark-desktop-links/macos/RNDesktopLinks.mm +10 -9
- package/vendor/node_modules/@legendapp/spark-desktop-links/package.json +2 -2
- package/vendor/node_modules/@legendapp/spark-desktop-links/src/NativeDesktopLinks.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-desktop-links/src/api.ts +27 -33
- package/vendor/node_modules/@legendapp/spark-desktop-links/src/expo.ts +3 -4
- package/vendor/node_modules/@legendapp/spark-desktop-links/src/native.ts +9 -0
- package/vendor/node_modules/@legendapp/spark-desktop-links/windows/SparkLinks/SparkLinks.h +22 -22
- package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/RNDesktopShortcuts.podspec +1 -0
- package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/macos/RNDesktopShortcuts.mm +1 -1
- package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/macos/keyboard-manager/RNKeyboardManager.h +9 -0
- package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/macos/keyboard-manager/RNKeyboardManager.mm +307 -0
- package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/package.json +8 -5
- package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/src/NativeDesktopShortcuts.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/src/api.ts +39 -14
- package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/src/keyboard-manager/NativeKeyboardManager.ts +12 -0
- package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/src/keyboard-manager/codes.ts +108 -0
- package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/src/keyboard-manager/index.ts +99 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/RNDesktopWindows.podspec +2 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/RNDesktopWindows.mm +229 -103
- package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/SparkWindowGeometry.h +63 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/window-manager/LegendWindowRegistry.h +20 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/window-manager/LegendWindowRegistry.mm +27 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/window-manager/RNWindowManager.h +12 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/window-manager/RNWindowManager.mm +3169 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/window-manager/RNWindowManagerStartup.mm +31 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/macos/window-manager/SidebarStartupFallbacks.mm +14 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/package.json +10 -6
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/NativeDesktopWindowManager.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/api.ts +146 -70
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/diagnostics.ts +17 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/index.ts +3 -1
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/index.windows.ts +3 -1
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/macos-adapter.ts +53 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/macos.ts +51 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/transport.ts +41 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/types.ts +140 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/validation.ts +162 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/window-manager/NativeWindowManager.ts +28 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/WindowProvider.tsx +20 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/createWindowsNavigator.tsx +78 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/index.ts +6 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/primaryWindowLifecycle.ts +34 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/types.ts +11 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/usePrimaryWindowLifecycle.ts +18 -0
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows/useWindowFocusEffect.ts +17 -0
- package/vendor/node_modules/@legendapp/spark-documents/package.json +22 -0
- package/vendor/node_modules/@legendapp/spark-documents/src/controller.ts +97 -0
- package/vendor/node_modules/@legendapp/spark-documents/src/documentTransition.ts +13 -0
- package/vendor/node_modules/@legendapp/spark-documents/src/hooks.ts +139 -0
- package/vendor/node_modules/@legendapp/spark-documents/src/index.tsx +50 -0
- package/vendor/node_modules/@legendapp/spark-documents/src/reload.ts +39 -0
- package/vendor/node_modules/@legendapp/spark-documents/src/requests.ts +15 -0
- package/vendor/node_modules/@legendapp/spark-drag-drop/package.json +4 -3
- package/vendor/node_modules/@legendapp/spark-drag-drop/src/DesktopDragViewNativeComponent.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-drag-drop/src/contracts.ts +73 -18
- package/vendor/node_modules/@legendapp/spark-drag-drop/src/index.tsx +58 -15
- package/vendor/node_modules/@legendapp/spark-drag-drop/windows/SparkDragDrop/SparkDragDrop.h +14 -8
- package/vendor/node_modules/@legendapp/spark-file-dialog/ios/RNFileDialog.mm +34 -121
- package/vendor/node_modules/@legendapp/spark-file-dialog/package.json +12 -5
- package/vendor/node_modules/@legendapp/spark-file-dialog/src/NativeFileDialog.ts +1 -5
- package/vendor/node_modules/@legendapp/spark-file-dialog/src/index.ts +19 -84
- package/vendor/node_modules/@legendapp/spark-file-dialog/src/native.ts +12 -0
- package/vendor/node_modules/@legendapp/spark-file-dialog/src/options.ts +34 -14
- package/vendor/node_modules/@legendapp/spark-file-dialog/src/types.ts +26 -0
- package/vendor/node_modules/@legendapp/spark-file-dialog/windows/SparkFileDialog/SparkFileDialog.h +42 -58
- package/vendor/node_modules/@legendapp/spark-file-system/RNDesktopFileSystem.podspec +1 -0
- package/vendor/node_modules/@legendapp/spark-file-system/macos/RNDesktopFileSystem.mm +32 -21
- package/vendor/node_modules/@legendapp/spark-file-system/macos/SparkFileMutations.h +24 -0
- package/vendor/node_modules/@legendapp/spark-file-system/macos/SparkFileMutations.mm +215 -0
- package/vendor/node_modules/@legendapp/spark-file-system/macos/file-scanner/RNFileScanner.h +9 -0
- package/vendor/node_modules/@legendapp/spark-file-system/macos/file-scanner/RNFileScanner.mm +82 -0
- package/vendor/node_modules/@legendapp/spark-file-system/macos/file-scanner/RNFileScannerCore.h +47 -0
- package/vendor/node_modules/@legendapp/spark-file-system/macos/file-scanner/RNFileScannerCore.mm +306 -0
- package/vendor/node_modules/@legendapp/spark-file-system/package.json +8 -6
- package/vendor/node_modules/@legendapp/spark-file-system/src/NativeDesktopFileSystem.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-file-system/src/file-scanner/NativeFileScanner.ts +11 -0
- package/vendor/node_modules/@legendapp/spark-file-system/src/file-scanner/index.ts +93 -0
- package/vendor/node_modules/@legendapp/spark-file-system/src/handles.ts +48 -14
- package/vendor/node_modules/@legendapp/spark-file-system/src/index.ts +134 -45
- package/vendor/node_modules/@legendapp/spark-file-system/src/path.ts +1 -9
- package/vendor/node_modules/@legendapp/spark-file-system/windows/SparkFileSystem/SparkFileSystem.h +102 -26
- package/vendor/node_modules/@legendapp/spark-file-system/windows/SparkFileSystem/SparkFileSystem.vcxproj +2 -0
- package/vendor/node_modules/@legendapp/spark-global-shortcuts/RNDesktopGlobalShortcuts.podspec +1 -0
- package/vendor/node_modules/@legendapp/spark-global-shortcuts/macos/RNDesktopGlobalShortcuts.mm +7 -4
- package/vendor/node_modules/@legendapp/spark-global-shortcuts/package.json +4 -3
- package/vendor/node_modules/@legendapp/spark-global-shortcuts/src/NativeDesktopGlobalShortcuts.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-global-shortcuts/src/index.ts +39 -10
- package/vendor/node_modules/@legendapp/spark-global-shortcuts/windows/SparkGlobalShortcuts/SparkGlobalShortcuts.h +5 -4
- package/vendor/node_modules/@legendapp/spark-message-dialog/macos/RNDesktopMessageDialog.mm +2 -2
- package/vendor/node_modules/@legendapp/spark-message-dialog/package.json +2 -2
- package/vendor/node_modules/@legendapp/spark-message-dialog/src/NativeDesktopMessageDialog.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-message-dialog/src/index.ts +48 -11
- package/vendor/node_modules/@legendapp/spark-native-menu/ios/RNNativeMenu.mm +141 -609
- package/vendor/node_modules/@legendapp/spark-native-menu/package.json +9 -4
- package/vendor/node_modules/@legendapp/spark-native-menu/src/NativeMenu.ts +2 -7
- package/vendor/node_modules/@legendapp/spark-native-menu/src/api.ts +76 -121
- package/vendor/node_modules/@legendapp/spark-native-menu/src/hooks.ts +97 -0
- package/vendor/node_modules/@legendapp/spark-native-menu/src/windows-menus.ts +43 -37
- package/vendor/node_modules/@legendapp/spark-notifications/macos/RNDesktopNotifications.mm +75 -30
- package/vendor/node_modules/@legendapp/spark-notifications/package.json +2 -2
- package/vendor/node_modules/@legendapp/spark-notifications/src/NativeDesktopNotifications.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-notifications/src/index.ts +130 -42
- package/vendor/node_modules/@legendapp/spark-notifications/windows/SparkNotifications/SparkNotifications.h +51 -8
- package/vendor/node_modules/@legendapp/spark-processes/macos/RNDesktopProcesses.mm +94 -21
- package/vendor/node_modules/@legendapp/spark-processes/package.json +4 -3
- package/vendor/node_modules/@legendapp/spark-processes/src/NativeDesktopProcesses.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-processes/src/index.ts +124 -28
- package/vendor/node_modules/@legendapp/spark-processes/src/types.ts +34 -0
- package/vendor/node_modules/@legendapp/spark-processes/windows/SparkProcesses/SparkProcesses.h +83 -34
- package/vendor/node_modules/@legendapp/spark-processes/windows/SparkProcesses/SparkProcesses.vcxproj +2 -0
- package/vendor/node_modules/@legendapp/spark-secure-storage/macos/RNDesktopSecureStorage.mm +49 -40
- package/vendor/node_modules/@legendapp/spark-secure-storage/package.json +2 -2
- package/vendor/node_modules/@legendapp/spark-secure-storage/src/NativeDesktopSecureStorage.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-secure-storage/src/desktop.ts +16 -14
- package/vendor/node_modules/@legendapp/spark-secure-storage/src/expo.ts +0 -1
- package/vendor/node_modules/@legendapp/spark-secure-storage/src/options.ts +3 -2
- package/vendor/node_modules/@legendapp/spark-secure-storage/src/unavailable.ts +6 -3
- package/vendor/node_modules/@legendapp/spark-settings/package.json +10 -3
- package/vendor/node_modules/@legendapp/spark-settings/src/fileStorage.ts +11 -0
- package/vendor/node_modules/@legendapp/spark-settings/src/index.ts +7 -9
- package/vendor/node_modules/@legendapp/spark-settings/src/storage/index.ts +142 -0
- package/vendor/node_modules/@legendapp/spark-settings/src/store.ts +63 -21
- package/vendor/node_modules/@legendapp/spark-settings-ui/package.json +20 -0
- package/vendor/node_modules/@legendapp/spark-settings-ui/src/index.tsx +436 -0
- package/vendor/node_modules/@legendapp/spark-settings-ui/src/options.ts +10 -0
- package/vendor/node_modules/@legendapp/spark-sqlite/package.json +3 -3
- package/vendor/node_modules/@legendapp/spark-sqlite/src/database.ts +182 -0
- package/vendor/node_modules/@legendapp/spark-sqlite/src/index.ts +19 -6
- package/vendor/node_modules/@legendapp/spark-sqlite/src/types.ts +22 -0
- package/vendor/node_modules/@legendapp/spark-system/macos/RNDesktopSystem.mm +36 -11
- package/vendor/node_modules/@legendapp/spark-system/package.json +2 -2
- package/vendor/node_modules/@legendapp/spark-system/src/NativeDesktopSystem.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-system/src/index.ts +89 -32
- package/vendor/node_modules/@legendapp/spark-system/windows/SparkSystem/SparkSystem.h +8 -4
- package/vendor/node_modules/@legendapp/spark-tray/macos/RNDesktopTray.mm +20 -8
- package/vendor/node_modules/@legendapp/spark-tray/package.json +2 -2
- package/vendor/node_modules/@legendapp/spark-tray/src/NativeDesktopTray.ts +1 -1
- package/vendor/node_modules/@legendapp/spark-tray/src/index.ts +91 -34
- package/vendor/node_modules/@legendapp/spark-tray/windows/SparkTray/SparkTray.h +45 -15
- package/vendor/node_modules/@legendapp/spark-ui/macos/RNSparkButton.mm +2 -1
- package/vendor/node_modules/@legendapp/spark-ui/macos/RNSparkTextInput.mm +10 -2
- package/vendor/node_modules/@legendapp/spark-ui/macos/appkit-split-view/RNSidebarSplitViewComponent.h +15 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/appkit-split-view/RNSidebarSplitViewComponent.mm +1419 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/glass-effect-view/RNGlassEffectView.mm +72 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/native-select/RNNativeSegmentedControl.h +15 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/native-select/RNNativeSegmentedControl.mm +194 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/native-select/RNNativeSelect.h +15 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/native-select/RNNativeSelect.mm +180 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/sf-symbol/RNSFSymbol.h +15 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/sf-symbol/RNSFSymbol.mm +155 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/sidebar/RNSidebar.h +18 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/sidebar/RNSidebar.mm +645 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/swipe-actions/RNSwipeActions.h +10 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/swipe-actions/RNSwipeActions.mm +422 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/text-input-search/RNTextInputSearch.h +15 -0
- package/vendor/node_modules/@legendapp/spark-ui/macos/text-input-search/RNTextInputSearch.mm +164 -0
- package/vendor/node_modules/@legendapp/spark-ui/package.json +17 -4
- package/vendor/node_modules/@legendapp/spark-ui/src/SparkSelectNativeComponent.ts +3 -1
- package/vendor/node_modules/@legendapp/spark-ui/src/SparkTextInputNativeComponent.ts +6 -2
- package/vendor/node_modules/@legendapp/spark-ui/src/appkit-split-view/SidebarSplitViewNativeComponent.ts +37 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/appkit-split-view/index.tsx +86 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/availability.ts +10 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/classnames/index.ts +8 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/control.ts +42 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/desktop.tsx +56 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/glass-effect-view/index.tsx +15 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/index.android.tsx +35 -21
- package/vendor/node_modules/@legendapp/spark-ui/src/index.ios.tsx +55 -26
- package/vendor/node_modules/@legendapp/spark-ui/src/index.tsx +1 -27
- package/vendor/node_modules/@legendapp/spark-ui/src/index.web.tsx +45 -14
- package/vendor/node_modules/@legendapp/spark-ui/src/index.windows.tsx +1 -42
- package/vendor/node_modules/@legendapp/spark-ui/src/mobile-input.tsx +11 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/native-select/NativeSegmentedControlNativeComponent.ts +17 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/native-select/NativeSelectNativeComponent.ts +17 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/select.ts +5 -3
- package/vendor/node_modules/@legendapp/spark-ui/src/sf-symbol/SFSymbolNativeComponent.ts +13 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/sf-symbol/index.tsx +27 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/sidebar/SidebarItemNativeComponent.ts +25 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/sidebar/SidebarNativeComponent.ts +24 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/sidebar/index.tsx +104 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/specialized.ts +22 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/swipe-actions/SwipeActionsNativeComponent.ts +11 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/swipe-actions/index.tsx +41 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/text-input-search/TextInputSearchNativeComponent.ts +33 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/text-input-search/index.tsx +34 -0
- package/vendor/node_modules/@legendapp/spark-ui/src/types.ts +30 -19
- package/vendor/node_modules/@legendapp/spark-ui/uniwind.ts +3 -1
- package/vendor/node_modules/@legendapp/spark-ui/uniwind.web.ts +3 -1
- package/vendor/node_modules/@legendapp/spark-ui/windows/SparkUI/SparkUI.h +16 -11
- package/vendor/node_modules/@legendapp/spark-updates/macos/RNDesktopUpdates.mm +21 -8
- package/vendor/node_modules/@legendapp/spark-updates/package.json +2 -2
- package/vendor/node_modules/@legendapp/spark-updates/src/NativeDesktopUpdates.ts +3 -2
- package/vendor/node_modules/@legendapp/spark-updates/src/index.ts +71 -15
- package/vendor/node_modules/@legendapp/spark-webview/package.json +2 -2
- package/vendor/node_modules/@legendapp/spark-webview/src/WebView.tsx +11 -0
- package/vendor/node_modules/@legendapp/spark-webview/src/adapter.ts +55 -0
- package/vendor/node_modules/@legendapp/spark-webview/src/index.ts +2 -2
- package/vendor/node_modules/@legendapp/spark-webview/src/types.ts +32 -0
- package/vendor/node_modules/@legendapp/spark-webview/src/view-props.ts +28 -0
- package/vendor/node_modules/@legendapp/spark-window-options/index.cjs +51 -14
- package/vendor/node_modules/@legendapp/spark-window-options/index.d.ts +21 -8
- package/vendor/node_modules/@legendapp/spark-window-options/package.json +1 -1
- package/windows-macos.ts +1 -0
- package/expo-metro.cjs +0 -1
- package/message-dialog.ts +0 -1
- package/universal.cjs +0 -1
- package/vendor/node_modules/@legendapp/spark-desktop-shortcuts/src/accelerator.ts +0 -22
- package/vendor/node_modules/@legendapp/spark-desktop-windows/src/windows-options.ts +0 -11
- package/vendor/node_modules/@legendapp/spark-file-dialog/src/index.windows.ts +0 -15
- package/vendor/node_modules/@legendapp/spark-global-shortcuts/src/accelerator.ts +0 -22
- package/vendor/node_modules/@legendapp/spark-ui/macos/RNSparkSelect.h +0 -4
- package/vendor/node_modules/@legendapp/spark-ui/macos/RNSparkSelect.mm +0 -53
|
@@ -0,0 +1,2662 @@
|
|
|
1
|
+
diff --git a/VisionCamera.podspec b/VisionCamera.podspec
|
|
2
|
+
index e798a1d..5a0daf9 100644
|
|
3
|
+
--- a/VisionCamera.podspec
|
|
4
|
+
+++ b/VisionCamera.podspec
|
|
5
|
+
@@ -10,7 +10,8 @@ Pod::Spec.new do |s|
|
|
6
|
+
s.license = package["license"]
|
|
7
|
+
s.authors = package["author"]
|
|
8
|
+
|
|
9
|
+
- s.platforms = { :ios => min_ios_version_supported, :visionos => 1.0 }
|
|
10
|
+
+ s.platforms = { :ios => min_ios_version_supported, :visionos => 1.0, :osx => "14.0" }
|
|
11
|
+
+ s.osx.prefix_header_contents = "#include <CoreGraphics/CoreGraphics.h>"
|
|
12
|
+
s.source = { :git => "https://github.com/mrousavy/nitro.git", :tag => "#{s.version}" }
|
|
13
|
+
|
|
14
|
+
s.source_files = [
|
|
15
|
+
diff --git a/ios/Delegates/CapturePhotoDelegate.swift b/ios/Delegates/CapturePhotoDelegate.swift
|
|
16
|
+
index 58fdb4e..023bbf5 100644
|
|
17
|
+
--- a/ios/Delegates/CapturePhotoDelegate.swift
|
|
18
|
+
+++ b/ios/Delegates/CapturePhotoDelegate.swift
|
|
19
|
+
@@ -88,6 +88,9 @@ final class CapturePhotoDelegate: NSObject, AVCapturePhotoCaptureDelegate {
|
|
20
|
+
CapturePhotoDelegate.delegates.removeAll { $0 == self }
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
+#if os(macOS)
|
|
24
|
+
+
|
|
25
|
+
+#else
|
|
26
|
+
@available(iOS 17.0, *)
|
|
27
|
+
func photoOutput(
|
|
28
|
+
_ output: AVCapturePhotoOutput,
|
|
29
|
+
@@ -95,5 +98,6 @@ final class CapturePhotoDelegate: NSObject, AVCapturePhotoCaptureDelegate {
|
|
30
|
+
error: (any Error)?
|
|
31
|
+
) {
|
|
32
|
+
logger.warning("didFinishCapturingDeferredPhotoProxy is not implemented!")
|
|
33
|
+
- }
|
|
34
|
+
+ }#endif
|
|
35
|
+
+
|
|
36
|
+
}
|
|
37
|
+
diff --git a/ios/Delegates/DepthFrameDelegate.swift b/ios/Delegates/DepthFrameDelegate.swift
|
|
38
|
+
index 8d3d0b5..cff3568 100644
|
|
39
|
+
--- a/ios/Delegates/DepthFrameDelegate.swift
|
|
40
|
+
+++ b/ios/Delegates/DepthFrameDelegate.swift
|
|
41
|
+
@@ -1,3 +1,4 @@
|
|
42
|
+
+#if !os(macOS)
|
|
43
|
+
//
|
|
44
|
+
// DepthFrameDelegate.swift
|
|
45
|
+
// VisionCamera
|
|
46
|
+
@@ -30,3 +31,5 @@ final class DepthFrameDelegate: NSObject, AVCaptureDepthDataOutputDelegate {
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
+
|
|
51
|
+
+#endif
|
|
52
|
+
diff --git a/ios/Delegates/SynchronizedOutputDelegate.swift b/ios/Delegates/SynchronizedOutputDelegate.swift
|
|
53
|
+
index 16bb97f..938c4f1 100644
|
|
54
|
+
--- a/ios/Delegates/SynchronizedOutputDelegate.swift
|
|
55
|
+
+++ b/ios/Delegates/SynchronizedOutputDelegate.swift
|
|
56
|
+
@@ -1,3 +1,4 @@
|
|
57
|
+
+#if !os(macOS)
|
|
58
|
+
//
|
|
59
|
+
// SynchronizedOutputDelegate.swift
|
|
60
|
+
// VisionCamera
|
|
61
|
+
@@ -108,3 +109,5 @@ final class SynchronizedOutputDelegate: NSObject, AVCaptureDataOutputSynchronize
|
|
62
|
+
return SynchronizedDataFrame(data: .depth(buffer), metadata: metadata)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
+
|
|
66
|
+
+#endif
|
|
67
|
+
diff --git a/ios/Extensions/AVFoundation/AVCaptureConnection+orientation.swift b/ios/Extensions/AVFoundation/AVCaptureConnection+orientation.swift
|
|
68
|
+
index 36181e9..112d08e 100644
|
|
69
|
+
--- a/ios/Extensions/AVFoundation/AVCaptureConnection+orientation.swift
|
|
70
|
+
+++ b/ios/Extensions/AVFoundation/AVCaptureConnection+orientation.swift
|
|
71
|
+
@@ -10,10 +10,18 @@ import NitroModules
|
|
72
|
+
|
|
73
|
+
extension AVCaptureConnection {
|
|
74
|
+
var orientation: CameraOrientation {
|
|
75
|
+
+#if os(macOS)
|
|
76
|
+
+ return .up
|
|
77
|
+
+#else
|
|
78
|
+
return CameraOrientation(avOrientation: videoOrientation)
|
|
79
|
+
+#endif
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
func setOrientation(_ orientation: CameraOrientation) throws {
|
|
83
|
+
+#if os(macOS)
|
|
84
|
+
+ // Desktop cameras supply upright buffers; portrait is an iOS screen convention.
|
|
85
|
+
+ guard orientation == .up else { throw RuntimeError.error(withMessage: "Custom capture orientation is not supported by the macOS prototype") }
|
|
86
|
+
+#else
|
|
87
|
+
guard self.isVideoOrientationSupported else {
|
|
88
|
+
throw RuntimeError.error(
|
|
89
|
+
withMessage:
|
|
90
|
+
@@ -21,5 +29,6 @@ extension AVCaptureConnection {
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
self.videoOrientation = orientation.toAVCaptureVideoOrientation()
|
|
94
|
+
+#endif
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
diff --git a/ios/Extensions/AVFoundation/AVCaptureDevice.DeviceType+all.swift b/ios/Extensions/AVFoundation/AVCaptureDevice.DeviceType+all.swift
|
|
98
|
+
index 1f5adb8..adbfd55 100644
|
|
99
|
+
--- a/ios/Extensions/AVFoundation/AVCaptureDevice.DeviceType+all.swift
|
|
100
|
+
+++ b/ios/Extensions/AVFoundation/AVCaptureDevice.DeviceType+all.swift
|
|
101
|
+
@@ -14,6 +14,9 @@ extension AVCaptureDevice.DeviceType {
|
|
102
|
+
* This list should be kept up to date by just adding new device types here.
|
|
103
|
+
*/
|
|
104
|
+
static var all: [AVCaptureDevice.DeviceType] {
|
|
105
|
+
+#if os(macOS)
|
|
106
|
+
+ return [.builtInWideAngleCamera, .external, .continuityCamera, .deskViewCamera]
|
|
107
|
+
+#else
|
|
108
|
+
var devices: [AVCaptureDevice.DeviceType] = []
|
|
109
|
+
|
|
110
|
+
devices.append(.builtInWideAngleCamera)
|
|
111
|
+
@@ -38,5 +41,6 @@ extension AVCaptureDevice.DeviceType {
|
|
112
|
+
devices.append(.builtInTrueDepthCamera)
|
|
113
|
+
|
|
114
|
+
return devices
|
|
115
|
+
+#endif
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
diff --git a/ios/Extensions/AVFoundation/AVCaptureDevice.Format+supportedResolutionsFor.swift b/ios/Extensions/AVFoundation/AVCaptureDevice.Format+supportedResolutionsFor.swift
|
|
119
|
+
index 7adc7fd..13fdbde 100644
|
|
120
|
+
--- a/ios/Extensions/AVFoundation/AVCaptureDevice.Format+supportedResolutionsFor.swift
|
|
121
|
+
+++ b/ios/Extensions/AVFoundation/AVCaptureDevice.Format+supportedResolutionsFor.swift
|
|
122
|
+
@@ -13,11 +13,16 @@ extension AVCaptureDevice.Format {
|
|
123
|
+
return [self.formatDescription.dimensions]
|
|
124
|
+
}
|
|
125
|
+
private var photoDimensions: [CMVideoDimensions] {
|
|
126
|
+
+#if os(macOS)
|
|
127
|
+
+ let dimensions = self.supportedMaxPhotoDimensions
|
|
128
|
+
+ return dimensions.isEmpty ? self.videoDimensions : dimensions
|
|
129
|
+
+#else
|
|
130
|
+
if #available(iOS 16.0, *) {
|
|
131
|
+
return self.supportedMaxPhotoDimensions
|
|
132
|
+
} else {
|
|
133
|
+
return [self.highResolutionStillImageDimensions]
|
|
134
|
+
}
|
|
135
|
+
+#endif
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
@@ -29,6 +34,9 @@ extension AVCaptureDevice.Format {
|
|
140
|
+
return self.videoDimensions
|
|
141
|
+
case .photo:
|
|
142
|
+
return self.photoDimensions
|
|
143
|
+
+#if os(macOS)
|
|
144
|
+
+ case .depthVideo, .depthPhoto: return []
|
|
145
|
+
+#else
|
|
146
|
+
case .depthVideo:
|
|
147
|
+
return self.supportedDepthDataFormats
|
|
148
|
+
.flatMap { $0.videoDimensions }
|
|
149
|
+
@@ -37,6 +45,7 @@ extension AVCaptureDevice.Format {
|
|
150
|
+
return self.supportedDepthDataFormats
|
|
151
|
+
.flatMap { $0.photoDimensions }
|
|
152
|
+
.withoutDuplicates()
|
|
153
|
+
+#endif
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
diff --git a/ios/Extensions/AVFoundation/AVCaptureDevice.Format+supportsOutput.swift b/ios/Extensions/AVFoundation/AVCaptureDevice.Format+supportsOutput.swift
|
|
158
|
+
index 5a496ce..cd71719 100644
|
|
159
|
+
--- a/ios/Extensions/AVFoundation/AVCaptureDevice.Format+supportsOutput.swift
|
|
160
|
+
+++ b/ios/Extensions/AVFoundation/AVCaptureDevice.Format+supportsOutput.swift
|
|
161
|
+
@@ -9,7 +9,11 @@ import Foundation
|
|
162
|
+
|
|
163
|
+
extension AVCaptureDevice.Format {
|
|
164
|
+
func supportsOutput(_ output: AVCaptureOutput) -> Bool {
|
|
165
|
+
+#if os(macOS)
|
|
166
|
+
+ return output is AVCapturePhotoOutput || output is AVCaptureMovieFileOutput || output is AVCaptureVideoDataOutput
|
|
167
|
+
+#else
|
|
168
|
+
let targetOutputClass = type(of: output)
|
|
169
|
+
return self.unsupportedCaptureOutputClasses.allSatisfy { $0 != targetOutputClass }
|
|
170
|
+
+#endif
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
diff --git a/ios/Extensions/AVFoundation/AVCapturePhoto+getMediaSampleMetadata.swift b/ios/Extensions/AVFoundation/AVCapturePhoto+getMediaSampleMetadata.swift
|
|
174
|
+
index 066ae6d..f5140d5 100644
|
|
175
|
+
--- a/ios/Extensions/AVFoundation/AVCapturePhoto+getMediaSampleMetadata.swift
|
|
176
|
+
+++ b/ios/Extensions/AVFoundation/AVCapturePhoto+getMediaSampleMetadata.swift
|
|
177
|
+
@@ -6,10 +6,20 @@
|
|
178
|
+
|
|
179
|
+
import AVFoundation
|
|
180
|
+
import Foundation
|
|
181
|
+
+import ImageIO
|
|
182
|
+
import NitroModules
|
|
183
|
+
|
|
184
|
+
extension AVCapturePhoto {
|
|
185
|
+
func getMediaSampleMetadata() throws -> MediaSampleMetadata {
|
|
186
|
+
+#if os(macOS)
|
|
187
|
+
+ var exif: UInt32 = 1
|
|
188
|
+
+ if let data = fileDataRepresentation(), let source = CGImageSourceCreateWithData(data as CFData, nil), let properties = CGImageSourceCopyPropertiesAtIndex(source, 0, nil) as? [CFString: Any] {
|
|
189
|
+
+ exif = (properties[kCGImagePropertyOrientation] as? NSNumber)?.uint32Value ?? 1
|
|
190
|
+
+ }
|
|
191
|
+
+ let orientation: CameraOrientation
|
|
192
|
+
+ switch exif { case 3, 4: orientation = .down; case 5, 8: orientation = .left; case 6, 7: orientation = .right; default: orientation = .up }
|
|
193
|
+
+ return MediaSampleMetadata(timestamp: timestamp, orientation: orientation, isMirrored: [2, 4, 5, 7].contains(exif))
|
|
194
|
+
+#else
|
|
195
|
+
guard let orientationAny = self.metadata[kCGImagePropertyOrientation as String],
|
|
196
|
+
let exifOrientation = orientationAny as? UInt32
|
|
197
|
+
else {
|
|
198
|
+
@@ -24,5 +34,6 @@ extension AVCapturePhoto {
|
|
199
|
+
timestamp: timestamp,
|
|
200
|
+
orientation: orientation,
|
|
201
|
+
isMirrored: isMirrored)
|
|
202
|
+
+#endif
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
diff --git a/ios/Extensions/AVFoundation/AVCapturePhoto+memorySize.swift b/ios/Extensions/AVFoundation/AVCapturePhoto+memorySize.swift
|
|
206
|
+
index d1f8ea7..8e366c1 100644
|
|
207
|
+
--- a/ios/Extensions/AVFoundation/AVCapturePhoto+memorySize.swift
|
|
208
|
+
+++ b/ios/Extensions/AVFoundation/AVCapturePhoto+memorySize.swift
|
|
209
|
+
@@ -14,7 +14,7 @@ extension AVCapturePhoto {
|
|
210
|
+
|
|
211
|
+
// base native buffer (width * height * RGB)
|
|
212
|
+
let width = resolvedSettings.photoDimensions.width
|
|
213
|
+
- let height = resolvedSettings.photoDimensions.width
|
|
214
|
+
+ let height = resolvedSettings.photoDimensions.height
|
|
215
|
+
let bytesPerPixel = 3 // RGB
|
|
216
|
+
estimate += Int(width) * Int(height) * bytesPerPixel
|
|
217
|
+
|
|
218
|
+
@@ -23,6 +23,7 @@ extension AVCapturePhoto {
|
|
219
|
+
estimate += pixelBuffer.memorySize
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
+#if !os(macOS)
|
|
223
|
+
// raw preview buffer
|
|
224
|
+
if let previewPixelBuffer {
|
|
225
|
+
estimate += previewPixelBuffer.memorySize
|
|
226
|
+
@@ -32,6 +33,7 @@ extension AVCapturePhoto {
|
|
227
|
+
if let depthData {
|
|
228
|
+
estimate += depthData.depthDataMap.memorySize
|
|
229
|
+
}
|
|
230
|
+
+#endif
|
|
231
|
+
return estimate
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
diff --git a/ios/Extensions/AVFoundation/AVDepthData+toUIImage.swift b/ios/Extensions/AVFoundation/AVDepthData+toUIImage.swift
|
|
235
|
+
index 6f48cd8..0be886f 100644
|
|
236
|
+
--- a/ios/Extensions/AVFoundation/AVDepthData+toUIImage.swift
|
|
237
|
+
+++ b/ios/Extensions/AVFoundation/AVDepthData+toUIImage.swift
|
|
238
|
+
@@ -7,10 +7,13 @@
|
|
239
|
+
import AVFoundation
|
|
240
|
+
import CoreImage
|
|
241
|
+
import Foundation
|
|
242
|
+
+#if os(macOS)
|
|
243
|
+
+import ImageIO
|
|
244
|
+
+#endif
|
|
245
|
+
import NitroModules
|
|
246
|
+
|
|
247
|
+
extension AVDepthData {
|
|
248
|
+
- func toUIImage(orientation: UIImage.Orientation) throws -> UIImage {
|
|
249
|
+
+ func toUIImage(orientation: CameraImageOrientation) throws -> CameraPlatformImage {
|
|
250
|
+
// No-copy create CIImage from AVDepthData
|
|
251
|
+
guard let ciImage = CIImage(depthData: self) else {
|
|
252
|
+
throw RuntimeError.error(withMessage: "Failed to convert Depth to Image!")
|
|
253
|
+
diff --git a/ios/Extensions/CIImage+toUIImage.swift b/ios/Extensions/CIImage+toUIImage.swift
|
|
254
|
+
index 22ee164..3277a1b 100644
|
|
255
|
+
--- a/ios/Extensions/CIImage+toUIImage.swift
|
|
256
|
+
+++ b/ios/Extensions/CIImage+toUIImage.swift
|
|
257
|
+
@@ -7,12 +7,15 @@
|
|
258
|
+
import AVFoundation
|
|
259
|
+
import CoreImage
|
|
260
|
+
import Foundation
|
|
261
|
+
+#if os(macOS)
|
|
262
|
+
+import ImageIO
|
|
263
|
+
+#endif
|
|
264
|
+
import NitroModules
|
|
265
|
+
|
|
266
|
+
extension CIImage {
|
|
267
|
+
private static let context = CIContext(options: [.useSoftwareRenderer: false])
|
|
268
|
+
|
|
269
|
+
- func toUIImage(orientation: UIImage.Orientation) throws -> UIImage {
|
|
270
|
+
+ func toUIImage(orientation: CameraImageOrientation) throws -> CameraPlatformImage {
|
|
271
|
+
// Copy the CIImage into a CGImage (render)
|
|
272
|
+
guard
|
|
273
|
+
let cgImage = Self.context.createCGImage(
|
|
274
|
+
@@ -21,10 +24,16 @@ extension CIImage {
|
|
275
|
+
else {
|
|
276
|
+
throw RuntimeError.error(withMessage: "Failed to copy CIImage into CGImage!")
|
|
277
|
+
}
|
|
278
|
+
+ #if os(macOS)
|
|
279
|
+
+ let oriented = CIImage(cgImage: cgImage).oriented(orientation)
|
|
280
|
+
+ guard let result = Self.context.createCGImage(oriented, from: oriented.extent) else { throw RuntimeError.error(withMessage: "Failed to orient image") }
|
|
281
|
+
+ return result
|
|
282
|
+
+ #else
|
|
283
|
+
// No-copy wrap the CGImage in a UIImage
|
|
284
|
+
return UIImage(
|
|
285
|
+
cgImage: cgImage,
|
|
286
|
+
scale: 1,
|
|
287
|
+
orientation: orientation)
|
|
288
|
+
+ #endif
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
diff --git a/ios/Extensions/Converters/AV+CapturePhotoSettings.swift b/ios/Extensions/Converters/AV+CapturePhotoSettings.swift
|
|
292
|
+
index e9490e1..0e89e79 100644
|
|
293
|
+
--- a/ios/Extensions/Converters/AV+CapturePhotoSettings.swift
|
|
294
|
+
+++ b/ios/Extensions/Converters/AV+CapturePhotoSettings.swift
|
|
295
|
+
@@ -10,10 +10,18 @@ import NitroModules
|
|
296
|
+
|
|
297
|
+
extension AVCapturePhotoSettings {
|
|
298
|
+
private var isRAWFormat: Bool {
|
|
299
|
+
+#if os(macOS)
|
|
300
|
+
+ return false
|
|
301
|
+
+#else
|
|
302
|
+
return self.rawPhotoPixelFormatType != 0
|
|
303
|
+
+#endif
|
|
304
|
+
}
|
|
305
|
+
private var isAppleProRAWFormat: Bool {
|
|
306
|
+
+#if os(macOS)
|
|
307
|
+
+ return false
|
|
308
|
+
+#else
|
|
309
|
+
return AVCapturePhotoOutput.isAppleProRAWPixelFormat(self.rawPhotoPixelFormatType)
|
|
310
|
+
+#endif
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
var supportsQualityPrioritization: Bool {
|
|
314
|
+
@@ -37,6 +45,9 @@ extension AVCapturePhotoSettings {
|
|
315
|
+
|
|
316
|
+
extension AVCapturePhotoOutput {
|
|
317
|
+
var bestRawPixelFormat: OSType? {
|
|
318
|
+
+#if os(macOS)
|
|
319
|
+
+ return self.availableRawPhotoPixelFormatTypes.first
|
|
320
|
+
+#else
|
|
321
|
+
if self.isAppleProRAWEnabled {
|
|
322
|
+
if let appleProRawFormat = self.availableRawPhotoPixelFormatTypes.first(where: {
|
|
323
|
+
AVCapturePhotoOutput.isAppleProRAWPixelFormat($0)
|
|
324
|
+
@@ -47,6 +58,7 @@ extension AVCapturePhotoOutput {
|
|
325
|
+
}
|
|
326
|
+
// No Apple ProRAW enabled or available, just use the first available default RAW format (or nil if there is none)
|
|
327
|
+
return self.availableRawPhotoPixelFormatTypes.first
|
|
328
|
+
+#endif
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
@@ -78,6 +90,9 @@ extension CapturePhotoSettings {
|
|
333
|
+
],
|
|
334
|
+
])
|
|
335
|
+
case .dng:
|
|
336
|
+
+#if os(macOS)
|
|
337
|
+
+ throw RuntimeError.error(withMessage: "RAW photo capture is not supported on macOS")
|
|
338
|
+
+#else
|
|
339
|
+
// For RAW, we need to get the first available RAW format (often Bayer14)
|
|
340
|
+
guard let rawFormat = output.bestRawPixelFormat else {
|
|
341
|
+
throw RuntimeError.error(
|
|
342
|
+
@@ -86,9 +101,14 @@ extension CapturePhotoSettings {
|
|
343
|
+
)
|
|
344
|
+
}
|
|
345
|
+
return AVCapturePhotoSettings(rawPixelFormatType: rawFormat)
|
|
346
|
+
+#endif
|
|
347
|
+
case .native:
|
|
348
|
+
+#if os(macOS)
|
|
349
|
+
+ return try getBaseAVCapturePhotoSettings(for: output, in: .jpeg, quality: quality)
|
|
350
|
+
+#else
|
|
351
|
+
// Apple's default processed photo format is HEIC.
|
|
352
|
+
return try getBaseAVCapturePhotoSettings(for: output, in: .heic, quality: quality)
|
|
353
|
+
+#endif
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
@@ -109,7 +129,9 @@ extension CapturePhotoSettings {
|
|
358
|
+
|
|
359
|
+
// Shoot in max resolution
|
|
360
|
+
if #available(iOS 16.0, *) {
|
|
361
|
+
- settings.maxPhotoDimensions = output.maxPhotoDimensions
|
|
362
|
+
+ if output.maxPhotoDimensions.width > 0 && output.maxPhotoDimensions.height > 0 {
|
|
363
|
+
+ settings.maxPhotoDimensions = output.maxPhotoDimensions
|
|
364
|
+
+ }
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// photoQualityPrioritization can only be set on processed photos.
|
|
368
|
+
@@ -125,6 +147,11 @@ extension CapturePhotoSettings {
|
|
369
|
+
settings.flashMode = avFlashMode
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
+#if os(macOS)
|
|
373
|
+
+ if enableDepthData == true || enableCameraCalibrationDataDelivery == true || options.previewImageTargetSize != nil {
|
|
374
|
+
+ throw RuntimeError.error(withMessage: "Depth, calibration and preview thumbnails are not supported on macOS")
|
|
375
|
+
+ }
|
|
376
|
+
+#else
|
|
377
|
+
// enableShutterSound={...}
|
|
378
|
+
if let enableShutterSound {
|
|
379
|
+
if #available(iOS 18.0, *) {
|
|
380
|
+
@@ -188,6 +215,10 @@ extension CapturePhotoSettings {
|
|
381
|
+
]
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
+#endif
|
|
385
|
+
+#if os(macOS)
|
|
386
|
+
+ if location != nil { throw RuntimeError.error(withMessage: "Photo location metadata is not supported on macOS") }
|
|
387
|
+
+#else
|
|
388
|
+
// metadata
|
|
389
|
+
settings.addLibraryMetadataTag()
|
|
390
|
+
if let location {
|
|
391
|
+
@@ -197,10 +228,12 @@ extension CapturePhotoSettings {
|
|
392
|
+
settings.addLocationMetadataTag(location)
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
+#endif
|
|
396
|
+
return settings
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
+#if !os(macOS)
|
|
401
|
+
extension AVCapturePhotoSettings {
|
|
402
|
+
fileprivate func addLibraryMetadataTag() {
|
|
403
|
+
var metadataCopy = metadata
|
|
404
|
+
@@ -216,3 +249,5 @@ extension AVCapturePhotoSettings {
|
|
405
|
+
self.metadata = metadataCopy
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
+
|
|
409
|
+
+#endif
|
|
410
|
+
diff --git a/ios/Extensions/Converters/AV+DeviceType.swift b/ios/Extensions/Converters/AV+DeviceType.swift
|
|
411
|
+
index 79b869c..77c87f3 100644
|
|
412
|
+
--- a/ios/Extensions/Converters/AV+DeviceType.swift
|
|
413
|
+
+++ b/ios/Extensions/Converters/AV+DeviceType.swift
|
|
414
|
+
@@ -10,6 +10,14 @@ import NitroModules
|
|
415
|
+
|
|
416
|
+
extension DeviceType {
|
|
417
|
+
init(type: AVCaptureDevice.DeviceType) {
|
|
418
|
+
+#if os(macOS)
|
|
419
|
+
+ switch type {
|
|
420
|
+
+ case .builtInWideAngleCamera: self = .wideAngle
|
|
421
|
+
+ case .continuityCamera: self = .continuity
|
|
422
|
+
+ case .external, .deskViewCamera: self = .external
|
|
423
|
+
+ default: self = .unknown
|
|
424
|
+
+ }
|
|
425
|
+
+#else
|
|
426
|
+
switch type {
|
|
427
|
+
case .builtInWideAngleCamera:
|
|
428
|
+
self = .wideAngle
|
|
429
|
+
@@ -45,5 +53,6 @@ extension DeviceType {
|
|
430
|
+
logger.error("VisionCamera: Unknown DeviceType: \(type.rawValue)!")
|
|
431
|
+
self = .unknown
|
|
432
|
+
}
|
|
433
|
+
+#endif
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
diff --git a/ios/Extensions/Converters/AV+InterruptionReason.swift b/ios/Extensions/Converters/AV+InterruptionReason.swift
|
|
437
|
+
index 7f1d93b..d94dd83 100644
|
|
438
|
+
--- a/ios/Extensions/Converters/AV+InterruptionReason.swift
|
|
439
|
+
+++ b/ios/Extensions/Converters/AV+InterruptionReason.swift
|
|
440
|
+
@@ -1,3 +1,4 @@
|
|
441
|
+
+#if !os(macOS)
|
|
442
|
+
///
|
|
443
|
+
/// AV+InterruptionReason.swift
|
|
444
|
+
/// VisionCamera
|
|
445
|
+
@@ -28,3 +29,5 @@ extension InterruptionReason {
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
+
|
|
450
|
+
+#endif
|
|
451
|
+
diff --git a/ios/Extensions/Converters/AV+MediaType.swift b/ios/Extensions/Converters/AV+MediaType.swift
|
|
452
|
+
index 2321198..88ac77b 100644
|
|
453
|
+
--- a/ios/Extensions/Converters/AV+MediaType.swift
|
|
454
|
+
+++ b/ios/Extensions/Converters/AV+MediaType.swift
|
|
455
|
+
@@ -15,8 +15,10 @@ extension MediaType {
|
|
456
|
+
self = .video
|
|
457
|
+
case .depthData:
|
|
458
|
+
self = .depth
|
|
459
|
+
+#if !os(macOS)
|
|
460
|
+
case .metadataObject:
|
|
461
|
+
self = .metadata
|
|
462
|
+
+#endif
|
|
463
|
+
default:
|
|
464
|
+
self = .other
|
|
465
|
+
}
|
|
466
|
+
@@ -29,7 +31,11 @@ extension MediaType {
|
|
467
|
+
case .depth:
|
|
468
|
+
return .depthData
|
|
469
|
+
case .metadata:
|
|
470
|
+
+#if os(macOS)
|
|
471
|
+
+ return AVMediaType(rawValue: "meta")
|
|
472
|
+
+#else
|
|
473
|
+
return .metadataObject
|
|
474
|
+
+#endif
|
|
475
|
+
case .other:
|
|
476
|
+
fatalError("Cannot convert 'other' to AVMediaType!")
|
|
477
|
+
}
|
|
478
|
+
diff --git a/ios/Extensions/Converters/AV+PhotoContainerFormat.swift b/ios/Extensions/Converters/AV+PhotoContainerFormat.swift
|
|
479
|
+
index d54d635..e9255ac 100644
|
|
480
|
+
--- a/ios/Extensions/Converters/AV+PhotoContainerFormat.swift
|
|
481
|
+
+++ b/ios/Extensions/Converters/AV+PhotoContainerFormat.swift
|
|
482
|
+
@@ -20,7 +20,7 @@ extension PhotoContainerFormat {
|
|
483
|
+
case .tif:
|
|
484
|
+
self = .tiff
|
|
485
|
+
default:
|
|
486
|
+
- if #available(iOS 26.0, *) {
|
|
487
|
+
+ if #available(iOS 26.0, macOS 26.0, *) {
|
|
488
|
+
if avFileType == .dcm {
|
|
489
|
+
self = .dcm
|
|
490
|
+
return
|
|
491
|
+
@@ -62,7 +62,7 @@ extension PhotoContainerFormat {
|
|
492
|
+
}
|
|
493
|
+
return type
|
|
494
|
+
case .dng:
|
|
495
|
+
- guard #available(iOS 18.0, *) else {
|
|
496
|
+
+ guard #available(iOS 18.0, macOS 15.0, *) else {
|
|
497
|
+
throw RuntimeError.error(
|
|
498
|
+
withMessage: "PhotoContainerFormat \"dng\" is only available on iOS 18.0 or newer!")
|
|
499
|
+
}
|
|
500
|
+
diff --git a/ios/Extensions/Converters/AV+ScannedObjectType.swift b/ios/Extensions/Converters/AV+ScannedObjectType.swift
|
|
501
|
+
index ce76ac2..d3f34f3 100644
|
|
502
|
+
--- a/ios/Extensions/Converters/AV+ScannedObjectType.swift
|
|
503
|
+
+++ b/ios/Extensions/Converters/AV+ScannedObjectType.swift
|
|
504
|
+
@@ -62,9 +62,9 @@ extension ScannedObjectType {
|
|
505
|
+
self = .microQr
|
|
506
|
+
} else if #available(iOS 17.0, *), type == .humanFullBody {
|
|
507
|
+
self = .humanFullBody
|
|
508
|
+
- } else if #available(iOS 26.0, *), type == .dogHead {
|
|
509
|
+
+ } else if #available(iOS 26.0, macOS 26.0, *), type == .dogHead {
|
|
510
|
+
self = .dogHead
|
|
511
|
+
- } else if #available(iOS 26.0, *), type == .catHead {
|
|
512
|
+
+ } else if #available(iOS 26.0, macOS 26.0, *), type == .catHead {
|
|
513
|
+
self = .catHead
|
|
514
|
+
} else {
|
|
515
|
+
logger.error("Unknown AVMetadataObject.ObjectType: \(type.rawValue)")
|
|
516
|
+
@@ -146,7 +146,7 @@ extension ScannedObjectType {
|
|
517
|
+
return nil
|
|
518
|
+
}
|
|
519
|
+
case .dogHead:
|
|
520
|
+
- if #available(iOS 26.0, *) {
|
|
521
|
+
+ if #available(iOS 26.0, macOS 26.0, *) {
|
|
522
|
+
return .dogHead
|
|
523
|
+
} else {
|
|
524
|
+
return nil
|
|
525
|
+
@@ -154,7 +154,7 @@ extension ScannedObjectType {
|
|
526
|
+
case .dogBody:
|
|
527
|
+
return .dogBody
|
|
528
|
+
case .catHead:
|
|
529
|
+
- if #available(iOS 26.0, *) {
|
|
530
|
+
+ if #available(iOS 26.0, macOS 26.0, *) {
|
|
531
|
+
return .catHead
|
|
532
|
+
} else {
|
|
533
|
+
return nil
|
|
534
|
+
diff --git a/ios/Extensions/Converters/AV+TargetColorSpace.swift b/ios/Extensions/Converters/AV+TargetColorSpace.swift
|
|
535
|
+
index 10762ca..f585051 100644
|
|
536
|
+
--- a/ios/Extensions/Converters/AV+TargetColorSpace.swift
|
|
537
|
+
+++ b/ios/Extensions/Converters/AV+TargetColorSpace.swift
|
|
538
|
+
@@ -10,6 +10,12 @@ import NitroModules
|
|
539
|
+
|
|
540
|
+
extension TargetColorSpace {
|
|
541
|
+
func toAVCaptureColorSpace() -> AVCaptureColorSpace {
|
|
542
|
+
+#if os(macOS)
|
|
543
|
+
+ switch self {
|
|
544
|
+
+ case .p3D65: return .P3_D65
|
|
545
|
+
+ default: return .sRGB
|
|
546
|
+
+ }
|
|
547
|
+
+#else
|
|
548
|
+
switch self {
|
|
549
|
+
case .srgb:
|
|
550
|
+
return .sRGB
|
|
551
|
+
@@ -35,5 +41,6 @@ extension TargetColorSpace {
|
|
552
|
+
// Dolby Vision is not supported on iOS
|
|
553
|
+
return .HLG_BT2020
|
|
554
|
+
}
|
|
555
|
+
+#endif
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
diff --git a/ios/Extensions/Converters/AV+TargetStabilizationMode.swift b/ios/Extensions/Converters/AV+TargetStabilizationMode.swift
|
|
559
|
+
index 6809612..0330e72 100644
|
|
560
|
+
--- a/ios/Extensions/Converters/AV+TargetStabilizationMode.swift
|
|
561
|
+
+++ b/ios/Extensions/Converters/AV+TargetStabilizationMode.swift
|
|
562
|
+
@@ -1,3 +1,4 @@
|
|
563
|
+
+#if !os(macOS)
|
|
564
|
+
///
|
|
565
|
+
/// AV+TargetStabilizationMode.swift
|
|
566
|
+
/// VisionCamera
|
|
567
|
+
@@ -42,3 +43,5 @@ extension TargetStabilizationMode {
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
+
|
|
572
|
+
+#endif
|
|
573
|
+
diff --git a/ios/Extensions/Converters/AV+VideoCodec.swift b/ios/Extensions/Converters/AV+VideoCodec.swift
|
|
574
|
+
index 894bc6e..6e9d5f0 100644
|
|
575
|
+
--- a/ios/Extensions/Converters/AV+VideoCodec.swift
|
|
576
|
+
+++ b/ios/Extensions/Converters/AV+VideoCodec.swift
|
|
577
|
+
@@ -30,13 +30,13 @@ extension VideoCodec {
|
|
578
|
+
case .jpeg:
|
|
579
|
+
self = .jpeg
|
|
580
|
+
default:
|
|
581
|
+
- if #available(iOS 18.0, *) {
|
|
582
|
+
+ if #available(iOS 18.0, macOS 15.0, *) {
|
|
583
|
+
if avCodec == .appleProRes4444XQ {
|
|
584
|
+
self = .proRes4444Xq
|
|
585
|
+
return
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
- if #available(iOS 26.0, *) {
|
|
589
|
+
+ if #available(iOS 26.0, macOS 26.0, *) {
|
|
590
|
+
if avCodec == .proResRAW {
|
|
591
|
+
self = .proResRaw
|
|
592
|
+
return
|
|
593
|
+
@@ -84,19 +84,19 @@ extension VideoCodec {
|
|
594
|
+
case .jpeg:
|
|
595
|
+
return .jpeg
|
|
596
|
+
case .proRes4444Xq:
|
|
597
|
+
- guard #available(iOS 18.0, *) else {
|
|
598
|
+
+ guard #available(iOS 18.0, macOS 15.0, *) else {
|
|
599
|
+
throw RuntimeError.error(
|
|
600
|
+
withMessage: "VideoCodec \"pro-res-4444-xq\" is only available on iOS 18.0 or higher!")
|
|
601
|
+
}
|
|
602
|
+
return .appleProRes4444XQ
|
|
603
|
+
case .proResRaw:
|
|
604
|
+
- guard #available(iOS 26.0, *) else {
|
|
605
|
+
+ guard #available(iOS 26.0, macOS 26.0, *) else {
|
|
606
|
+
throw RuntimeError.error(
|
|
607
|
+
withMessage: "VideoCodec \"pro-res-raw\" is only available on iOS 18.0 or higher!")
|
|
608
|
+
}
|
|
609
|
+
return .proResRAW
|
|
610
|
+
case .proResRawHq:
|
|
611
|
+
- guard #available(iOS 26.0, *) else {
|
|
612
|
+
+ guard #available(iOS 26.0, macOS 26.0, *) else {
|
|
613
|
+
throw RuntimeError.error(
|
|
614
|
+
withMessage: "VideoCodec \"pro-res-raw-hq\" is only available on iOS 18.0 or higher!")
|
|
615
|
+
}
|
|
616
|
+
diff --git a/ios/Extensions/Converters/UI+CameraOrientation.swift b/ios/Extensions/Converters/UI+CameraOrientation.swift
|
|
617
|
+
index 97757ed..2eb6bb8 100644
|
|
618
|
+
--- a/ios/Extensions/Converters/UI+CameraOrientation.swift
|
|
619
|
+
+++ b/ios/Extensions/Converters/UI+CameraOrientation.swift
|
|
620
|
+
@@ -1,3 +1,6 @@
|
|
621
|
+
+#if os(macOS)
|
|
622
|
+
+
|
|
623
|
+
+#else
|
|
624
|
+
///
|
|
625
|
+
/// UI+CameraOrientation.swift
|
|
626
|
+
/// VisionCamera
|
|
627
|
+
@@ -53,3 +56,5 @@ extension CameraOrientation {
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
+
|
|
632
|
+
+#endif
|
|
633
|
+
diff --git a/ios/Extensions/CoreMedia/CMAccelerometerData+deviceOrientation.swift b/ios/Extensions/CoreMedia/CMAccelerometerData+deviceOrientation.swift
|
|
634
|
+
index 1eecf74..1989d0f 100644
|
|
635
|
+
--- a/ios/Extensions/CoreMedia/CMAccelerometerData+deviceOrientation.swift
|
|
636
|
+
+++ b/ios/Extensions/CoreMedia/CMAccelerometerData+deviceOrientation.swift
|
|
637
|
+
@@ -1,3 +1,4 @@
|
|
638
|
+
+#if !os(macOS)
|
|
639
|
+
//
|
|
640
|
+
// CMAccelerometerData+deviceOrientation.swift
|
|
641
|
+
// VisionCamera
|
|
642
|
+
@@ -38,3 +39,5 @@ extension CMAccelerometerData {
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
+
|
|
647
|
+
+#endif
|
|
648
|
+
diff --git a/ios/Extensions/CoreMedia/CMSampleBuffer+toUIImage.swift b/ios/Extensions/CoreMedia/CMSampleBuffer+toUIImage.swift
|
|
649
|
+
index 5fa9814..ef5dc43 100644
|
|
650
|
+
--- a/ios/Extensions/CoreMedia/CMSampleBuffer+toUIImage.swift
|
|
651
|
+
+++ b/ios/Extensions/CoreMedia/CMSampleBuffer+toUIImage.swift
|
|
652
|
+
@@ -7,10 +7,13 @@
|
|
653
|
+
import AVFoundation
|
|
654
|
+
import CoreImage
|
|
655
|
+
import Foundation
|
|
656
|
+
+#if os(macOS)
|
|
657
|
+
+import ImageIO
|
|
658
|
+
+#endif
|
|
659
|
+
import NitroModules
|
|
660
|
+
|
|
661
|
+
extension CMSampleBuffer {
|
|
662
|
+
- func toUIImage(orientation: UIImage.Orientation) throws -> UIImage {
|
|
663
|
+
+ func toUIImage(orientation: CameraImageOrientation) throws -> CameraPlatformImage {
|
|
664
|
+
guard let imageBuffer else {
|
|
665
|
+
throw RuntimeError.error(withMessage: "This Frame does not have a PixelBuffer!")
|
|
666
|
+
}
|
|
667
|
+
diff --git a/ios/Extensions/UIApplication+interfaceOrientation.swift b/ios/Extensions/UIApplication+interfaceOrientation.swift
|
|
668
|
+
index 96464fa..396961a 100644
|
|
669
|
+
--- a/ios/Extensions/UIApplication+interfaceOrientation.swift
|
|
670
|
+
+++ b/ios/Extensions/UIApplication+interfaceOrientation.swift
|
|
671
|
+
@@ -1,3 +1,6 @@
|
|
672
|
+
+#if os(macOS)
|
|
673
|
+
+
|
|
674
|
+
+#else
|
|
675
|
+
//
|
|
676
|
+
// UIApplication+interfaceOrientation.swift
|
|
677
|
+
// VisionCamera
|
|
678
|
+
@@ -28,3 +31,5 @@ extension UIApplication {
|
|
679
|
+
return windowScene.interfaceOrientation
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
+
|
|
683
|
+
+#endif
|
|
684
|
+
diff --git a/ios/Extensions/UIImageOrientation+exif.swift b/ios/Extensions/UIImageOrientation+exif.swift
|
|
685
|
+
index 53506e0..98a404f 100644
|
|
686
|
+
--- a/ios/Extensions/UIImageOrientation+exif.swift
|
|
687
|
+
+++ b/ios/Extensions/UIImageOrientation+exif.swift
|
|
688
|
+
@@ -1,3 +1,4 @@
|
|
689
|
+
+#if !os(macOS)
|
|
690
|
+
///
|
|
691
|
+
/// CIImage+toUIImage.swift
|
|
692
|
+
/// VisionCamera
|
|
693
|
+
@@ -44,3 +45,5 @@ extension UIImage.Orientation {
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
+
|
|
698
|
+
+#endif
|
|
699
|
+
diff --git a/ios/Hybrid Objects/Constraints/ConstraintResolver.swift b/ios/Hybrid Objects/Constraints/ConstraintResolver.swift
|
|
700
|
+
index 22a5793..dd37721 100644
|
|
701
|
+
--- a/ios/Hybrid Objects/Constraints/ConstraintResolver.swift
|
|
702
|
+
+++ b/ios/Hybrid Objects/Constraints/ConstraintResolver.swift
|
|
703
|
+
@@ -103,7 +103,11 @@ enum ConstraintResolver {
|
|
704
|
+
// If we need depth data, also find the best depth format
|
|
705
|
+
let needsDepth = outputs.contains { $0.requiresDepthFormat }
|
|
706
|
+
// TODO: Don't just choose the first format, but also negotiate depth data format in our constraint resolution.
|
|
707
|
+
+#if os(macOS)
|
|
708
|
+
+ let bestDepthFormat: AVCaptureDevice.Format? = nil
|
|
709
|
+
+#else
|
|
710
|
+
let bestDepthFormat = needsDepth ? best.format.supportedDepthDataFormats.first : nil
|
|
711
|
+
+#endif
|
|
712
|
+
|
|
713
|
+
return ResolvedConstraints(
|
|
714
|
+
device: device,
|
|
715
|
+
@@ -174,6 +178,11 @@ enum ConstraintResolver {
|
|
716
|
+
throw RuntimeError.error(withMessage: "The given `device` does not have any `formats`!")
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
+#if os(macOS)
|
|
720
|
+
+ if isMultiCam || outputs.contains(where: { $0.requiresDepthFormat }) {
|
|
721
|
+
+ throw RuntimeError.error(withMessage: "Depth and multi-camera sessions are not supported on macOS")
|
|
722
|
+
+ }
|
|
723
|
+
+#else
|
|
724
|
+
// 1. If we need a Depth Output, filter out formats without depth support
|
|
725
|
+
let needsDepth = outputs.contains { $0.requiresDepthFormat }
|
|
726
|
+
if needsDepth {
|
|
727
|
+
@@ -197,6 +206,7 @@ enum ConstraintResolver {
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
+#endif
|
|
732
|
+
// 3. Ensure formats support all target outputs
|
|
733
|
+
formats = formats.filter { format in
|
|
734
|
+
outputs.allSatisfy { format.supportsOutput($0.output) }
|
|
735
|
+
@@ -277,7 +287,11 @@ extension InternalConstraint {
|
|
736
|
+
let r = afSystem.resolve(for: format)
|
|
737
|
+
return ConstraintEvaluation(penalty: r.penalty, resolved: .formatOnly)
|
|
738
|
+
case .preferHighestPhotoQuality:
|
|
739
|
+
+#if os(macOS)
|
|
740
|
+
+ let penalty = 0.0
|
|
741
|
+
+#else
|
|
742
|
+
let penalty = format.isHighestPhotoQualitySupported ? 0.0 : 1.0
|
|
743
|
+
+#endif
|
|
744
|
+
return ConstraintEvaluation(
|
|
745
|
+
penalty: ConstraintPenalty(distance: penalty),
|
|
746
|
+
resolved: .formatOnly)
|
|
747
|
+
diff --git a/ios/Hybrid Objects/Constraints/HybridCameraSessionConfig.swift b/ios/Hybrid Objects/Constraints/HybridCameraSessionConfig.swift
|
|
748
|
+
index 0ae6b5c..8a7863e 100644
|
|
749
|
+
--- a/ios/Hybrid Objects/Constraints/HybridCameraSessionConfig.swift
|
|
750
|
+
+++ b/ios/Hybrid Objects/Constraints/HybridCameraSessionConfig.swift
|
|
751
|
+
@@ -35,7 +35,11 @@ final class HybridCameraSessionConfig: HybridCameraSessionConfigSpec, NativeCame
|
|
752
|
+
|
|
753
|
+
var isPhotoHDREnabled: Bool {
|
|
754
|
+
// Highest Photo Quality implies Smart HDR, this is not directly controllable.
|
|
755
|
+
+#if os(macOS)
|
|
756
|
+
+ return false
|
|
757
|
+
+#else
|
|
758
|
+
return negotiatedFormat.format.isHighestPhotoQualitySupported
|
|
759
|
+
+#endif
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
var nativePixelFormat: PixelFormat {
|
|
763
|
+
@@ -49,7 +53,11 @@ final class HybridCameraSessionConfig: HybridCameraSessionConfigSpec, NativeCame
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
var isBinned: Bool {
|
|
767
|
+
+#if os(macOS)
|
|
768
|
+
+ return false
|
|
769
|
+
+#else
|
|
770
|
+
return negotiatedFormat.format.isVideoBinned
|
|
771
|
+
+#endif
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
func toString() -> String {
|
|
775
|
+
diff --git a/ios/Hybrid Objects/Constraints/ResolvableConstraint/ResolvableConstraint+BinnedConstraint.swift b/ios/Hybrid Objects/Constraints/ResolvableConstraint/ResolvableConstraint+BinnedConstraint.swift
|
|
776
|
+
index 22c0e23..4366a55 100644
|
|
777
|
+
--- a/ios/Hybrid Objects/Constraints/ResolvableConstraint/ResolvableConstraint+BinnedConstraint.swift
|
|
778
|
+
+++ b/ios/Hybrid Objects/Constraints/ResolvableConstraint/ResolvableConstraint+BinnedConstraint.swift
|
|
779
|
+
@@ -11,7 +11,12 @@ extension BinnedConstraint: ResolvableConstraint {
|
|
780
|
+
|
|
781
|
+
func resolve(for format: AVCaptureDevice.Format) -> ConstraintResolution<Void> {
|
|
782
|
+
let penalty: Double
|
|
783
|
+
- switch (format.isVideoBinned, self.binned) {
|
|
784
|
+
+#if os(macOS)
|
|
785
|
+
+ let isBinned = false
|
|
786
|
+
+#else
|
|
787
|
+
+ let isBinned = format.isVideoBinned
|
|
788
|
+
+#endif
|
|
789
|
+
+ switch (isBinned, self.binned) {
|
|
790
|
+
case (true, true), (false, false):
|
|
791
|
+
penalty = 0.0
|
|
792
|
+
case (true, false):
|
|
793
|
+
diff --git a/ios/Hybrid Objects/Constraints/ResolvableConstraint/ResolvableConstraint+StabilizationModeConstraint.swift b/ios/Hybrid Objects/Constraints/ResolvableConstraint/ResolvableConstraint+StabilizationModeConstraint.swift
|
|
794
|
+
index 1494372..c1eaa3c 100644
|
|
795
|
+
--- a/ios/Hybrid Objects/Constraints/ResolvableConstraint/ResolvableConstraint+StabilizationModeConstraint.swift
|
|
796
|
+
+++ b/ios/Hybrid Objects/Constraints/ResolvableConstraint/ResolvableConstraint+StabilizationModeConstraint.swift
|
|
797
|
+
@@ -49,6 +49,9 @@ extension TargetStabilizationMode {
|
|
798
|
+
/// Walks the fallback chain until we find a mode the format supports.
|
|
799
|
+
/// Returns both the penalty (number of fallback steps) and the resolved mode.
|
|
800
|
+
func resolve(for format: AVCaptureDevice.Format) -> ConstraintResolution<TargetStabilizationMode> {
|
|
801
|
+
+#if os(macOS)
|
|
802
|
+
+ return ConstraintResolution(penalty: ConstraintPenalty(distance: self == .off ? 0 : 1), resolvedValue: .off)
|
|
803
|
+
+#else
|
|
804
|
+
var penalty = 0
|
|
805
|
+
var currentMode = self
|
|
806
|
+
while currentMode != .off {
|
|
807
|
+
@@ -61,5 +64,6 @@ extension TargetStabilizationMode {
|
|
808
|
+
return ConstraintResolution(
|
|
809
|
+
penalty: ConstraintPenalty(distance: Double(penalty)),
|
|
810
|
+
resolvedValue: currentMode)
|
|
811
|
+
+#endif
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
diff --git a/ios/Hybrid Objects/Constraints/ResolvableConstraint/ResolvableConstraint+VideoDynamicRangeConstraint.swift b/ios/Hybrid Objects/Constraints/ResolvableConstraint/ResolvableConstraint+VideoDynamicRangeConstraint.swift
|
|
815
|
+
index f250bab..c8d4e0b 100644
|
|
816
|
+
--- a/ios/Hybrid Objects/Constraints/ResolvableConstraint/ResolvableConstraint+VideoDynamicRangeConstraint.swift
|
|
817
|
+
+++ b/ios/Hybrid Objects/Constraints/ResolvableConstraint/ResolvableConstraint+VideoDynamicRangeConstraint.swift
|
|
818
|
+
@@ -69,7 +69,12 @@ extension TargetColorSpace {
|
|
819
|
+
var penalty = 0
|
|
820
|
+
var currentColorSpace = self
|
|
821
|
+
while currentColorSpace != .srgb {
|
|
822
|
+
- if format.supportedColorSpaces.contains(currentColorSpace.toAVCaptureColorSpace()) {
|
|
823
|
+
+#if os(macOS)
|
|
824
|
+
+ let supported = (currentColorSpace == .srgb || currentColorSpace == .p3D65) && format.supportedColorSpaces.contains(currentColorSpace.toAVCaptureColorSpace())
|
|
825
|
+
+#else
|
|
826
|
+
+ let supported = format.supportedColorSpaces.contains(currentColorSpace.toAVCaptureColorSpace())
|
|
827
|
+
+#endif
|
|
828
|
+
+ if supported {
|
|
829
|
+
break
|
|
830
|
+
}
|
|
831
|
+
currentColorSpace = currentColorSpace.nextBestMode()
|
|
832
|
+
diff --git a/ios/Hybrid Objects/Gestures/HybridTapToFocusGestureController.swift b/ios/Hybrid Objects/Gestures/HybridTapToFocusGestureController.swift
|
|
833
|
+
index 79cdcfc..a1a8199 100644
|
|
834
|
+
--- a/ios/Hybrid Objects/Gestures/HybridTapToFocusGestureController.swift
|
|
835
|
+
+++ b/ios/Hybrid Objects/Gestures/HybridTapToFocusGestureController.swift
|
|
836
|
+
@@ -7,23 +7,34 @@
|
|
837
|
+
|
|
838
|
+
import AVFoundation
|
|
839
|
+
import NitroModules
|
|
840
|
+
+#if os(macOS)
|
|
841
|
+
+import AppKit
|
|
842
|
+
+typealias CameraTapGestureRecognizer = NSClickGestureRecognizer
|
|
843
|
+
+#else
|
|
844
|
+
import UIKit
|
|
845
|
+
+typealias CameraTapGestureRecognizer = UITapGestureRecognizer
|
|
846
|
+
+#endif
|
|
847
|
+
|
|
848
|
+
final class HybridTapToFocusGestureController: HybridTapToFocusGestureControllerSpec,
|
|
849
|
+
NativeGestureController
|
|
850
|
+
{
|
|
851
|
+
- let gestureRecognizer = UITapGestureRecognizer()
|
|
852
|
+
+ let gestureRecognizer = CameraTapGestureRecognizer()
|
|
853
|
+
weak var controller: (any HybridCameraControllerSpec)? = nil
|
|
854
|
+
|
|
855
|
+
private weak var previewView: (any HybridPreviewViewSpec)? = nil
|
|
856
|
+
|
|
857
|
+
override init() {
|
|
858
|
+
super.init()
|
|
859
|
+
+ #if os(macOS)
|
|
860
|
+
+ gestureRecognizer.target = self
|
|
861
|
+
+ gestureRecognizer.action = #selector(onTap(_:))
|
|
862
|
+
+ #else
|
|
863
|
+
gestureRecognizer.cancelsTouchesInView = false
|
|
864
|
+
gestureRecognizer.addTarget(self, action: #selector(onTap(_:)))
|
|
865
|
+
+ #endif
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
- @objc private func onTap(_ gestureRecognizer: UITapGestureRecognizer) {
|
|
869
|
+
+ @objc private func onTap(_ gestureRecognizer: CameraTapGestureRecognizer) {
|
|
870
|
+
guard let controller, let previewView else {
|
|
871
|
+
return
|
|
872
|
+
}
|
|
873
|
+
diff --git a/ios/Hybrid Objects/Gestures/HybridZoomGestureController.swift b/ios/Hybrid Objects/Gestures/HybridZoomGestureController.swift
|
|
874
|
+
index e2f5ab5..c1a791c 100644
|
|
875
|
+
--- a/ios/Hybrid Objects/Gestures/HybridZoomGestureController.swift
|
|
876
|
+
+++ b/ios/Hybrid Objects/Gestures/HybridZoomGestureController.swift
|
|
877
|
+
@@ -1,3 +1,21 @@
|
|
878
|
+
+#if os(macOS)
|
|
879
|
+
+import AppKit
|
|
880
|
+
+import NitroModules
|
|
881
|
+
+final class HybridZoomGestureController: HybridZoomGestureControllerSpec, NativeGestureController {
|
|
882
|
+
+ let gestureRecognizer = NSMagnificationGestureRecognizer()
|
|
883
|
+
+ weak var controller: (any HybridCameraControllerSpec)?
|
|
884
|
+
+ private var initialZoom = 1.0
|
|
885
|
+
+ override init() { super.init(); gestureRecognizer.target = self; gestureRecognizer.action = #selector(onZoom(_:)) }
|
|
886
|
+
+ @objc private func onZoom(_ gesture: NSMagnificationGestureRecognizer) {
|
|
887
|
+
+ guard let controller else { return }
|
|
888
|
+
+ if gesture.state == .began { initialZoom = controller.zoom }
|
|
889
|
+
+ if gesture.state == .changed {
|
|
890
|
+
+ let zoom = min(controller.maxZoom, max(controller.minZoom, initialZoom * (1 + gesture.magnification)))
|
|
891
|
+
+ do { _ = try controller.setZoom(zoom: zoom) } catch { logger.error("Zoom failed: \(error)") }
|
|
892
|
+
+ }
|
|
893
|
+
+ }
|
|
894
|
+
+}
|
|
895
|
+
+#else
|
|
896
|
+
///
|
|
897
|
+
/// HybridCameraPhotoOutput.swift
|
|
898
|
+
/// VisionCamera
|
|
899
|
+
@@ -51,3 +69,5 @@ final class HybridZoomGestureController: HybridZoomGestureControllerSpec, Native
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
+
|
|
904
|
+
+#endif
|
|
905
|
+
diff --git a/ios/Hybrid Objects/HybridCameraController.swift b/ios/Hybrid Objects/HybridCameraController.swift
|
|
906
|
+
index ff48fd9..2036a30 100644
|
|
907
|
+
--- a/ios/Hybrid Objects/HybridCameraController.swift
|
|
908
|
+
+++ b/ios/Hybrid Objects/HybridCameraController.swift
|
|
909
|
+
@@ -51,46 +51,82 @@ final class HybridCameraController: HybridCameraControllerSpec, NativeCameraCont
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
var whiteBalanceGains: WhiteBalanceGains {
|
|
913
|
+
+#if os(macOS)
|
|
914
|
+
+ return WhiteBalanceGains(redGain: 1, blueGain: 1, greenGain: 1)
|
|
915
|
+
+#else
|
|
916
|
+
let gains = captureDevice.deviceWhiteBalanceGains
|
|
917
|
+
return WhiteBalanceGains(
|
|
918
|
+
redGain: Double(gains.redGain),
|
|
919
|
+
blueGain: Double(gains.blueGain),
|
|
920
|
+
greenGain: Double(gains.greenGain))
|
|
921
|
+
+#endif
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
var isLowLightBoostEnabled: Bool {
|
|
925
|
+
+#if os(macOS)
|
|
926
|
+
+ return false
|
|
927
|
+
+#else
|
|
928
|
+
return captureDevice.automaticallyEnablesLowLightBoostWhenAvailable
|
|
929
|
+
+#endif
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
var isSmoothAutoFocusEnabled: Bool {
|
|
933
|
+
+#if os(macOS)
|
|
934
|
+
+ return false
|
|
935
|
+
+#else
|
|
936
|
+
return captureDevice.isSmoothAutoFocusEnabled
|
|
937
|
+
+#endif
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
var isDistortionCorrectionEnabled: Bool {
|
|
941
|
+
+#if os(macOS)
|
|
942
|
+
+ return false
|
|
943
|
+
+#else
|
|
944
|
+
return captureDevice.isGeometricDistortionCorrectionEnabled
|
|
945
|
+
+#endif
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
var zoom: Double {
|
|
949
|
+
+#if os(macOS)
|
|
950
|
+
+ return 1
|
|
951
|
+
+#else
|
|
952
|
+
return captureDevice.videoZoomFactor
|
|
953
|
+
+#endif
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
var minZoom: Double {
|
|
957
|
+
+#if os(macOS)
|
|
958
|
+
+ return 1
|
|
959
|
+
+#else
|
|
960
|
+
return captureDevice.minAvailableVideoZoomFactor
|
|
961
|
+
+#endif
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
var maxZoom: Double {
|
|
965
|
+
+#if os(macOS)
|
|
966
|
+
+ return 1
|
|
967
|
+
+#else
|
|
968
|
+
return captureDevice.maxAvailableVideoZoomFactor
|
|
969
|
+
+#endif
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
var displayableZoomFactor: Double {
|
|
973
|
+
+#if os(macOS)
|
|
974
|
+
+ return 1
|
|
975
|
+
+#else
|
|
976
|
+
guard #available(iOS 18.0, *) else {
|
|
977
|
+
return zoom
|
|
978
|
+
}
|
|
979
|
+
return zoom * captureDevice.displayVideoZoomFactorMultiplier
|
|
980
|
+
+#endif
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
var torchStrength: Double {
|
|
984
|
+
+#if os(macOS)
|
|
985
|
+
+ return 0
|
|
986
|
+
+#else
|
|
987
|
+
return Double(captureDevice.torchLevel)
|
|
988
|
+
+#endif
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
var torchMode: TorchMode {
|
|
992
|
+
@@ -98,26 +134,52 @@ final class HybridCameraController: HybridCameraControllerSpec, NativeCameraCont
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
var lensPosition: Double {
|
|
996
|
+
+#if os(macOS)
|
|
997
|
+
+ return 0
|
|
998
|
+
+#else
|
|
999
|
+
return Double(captureDevice.lensPosition)
|
|
1000
|
+
+#endif
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
var exposureDuration: Double {
|
|
1004
|
+
+#if os(macOS)
|
|
1005
|
+
+ return 0
|
|
1006
|
+
+#else
|
|
1007
|
+
return captureDevice.exposureDuration.seconds
|
|
1008
|
+
+#endif
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
var activeMaxExposureDuration: Double {
|
|
1012
|
+
+#if os(macOS)
|
|
1013
|
+
+ return 0
|
|
1014
|
+
+#else
|
|
1015
|
+
return captureDevice.activeMaxExposureDuration.seconds
|
|
1016
|
+
+#endif
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
var exposureBias: Double {
|
|
1020
|
+
+#if os(macOS)
|
|
1021
|
+
+ return 0
|
|
1022
|
+
+#else
|
|
1023
|
+
return Double(captureDevice.exposureTargetBias)
|
|
1024
|
+
+#endif
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
var iso: Double {
|
|
1028
|
+
+#if os(macOS)
|
|
1029
|
+
+ return 0
|
|
1030
|
+
+#else
|
|
1031
|
+
return Double(captureDevice.iso)
|
|
1032
|
+
+#endif
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
func configure(config: CameraControllerConfiguration) -> Promise<Void> {
|
|
1036
|
+
+#if os(macOS)
|
|
1037
|
+
+ if config.enableLowLightBoost != nil || config.enableSmoothAutoFocus != nil || config.enableDistortionCorrection != nil {
|
|
1038
|
+
+ return .rejected(withError: RuntimeError.error(withMessage: "These controller options are not supported on macOS"))
|
|
1039
|
+
+ }
|
|
1040
|
+
+ return .resolved()
|
|
1041
|
+
+#else
|
|
1042
|
+
return captureDevice.withLock(queue) {
|
|
1043
|
+
let device = self.captureDevice
|
|
1044
|
+
|
|
1045
|
+
@@ -148,9 +210,13 @@ final class HybridCameraController: HybridCameraControllerSpec, NativeCameraCont
|
|
1046
|
+
device.isGeometricDistortionCorrectionEnabled = enableDistortionCorrection
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
+#endif
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
func setZoom(zoom: Double) -> Promise<Void> {
|
|
1053
|
+
+#if os(macOS)
|
|
1054
|
+
+ return .rejected(withError: RuntimeError.error(withMessage: "setZoom is not supported on macOS"))
|
|
1055
|
+
+#else
|
|
1056
|
+
return captureDevice.withLock(queue) {
|
|
1057
|
+
// 1. Ensure zoom is within valid range
|
|
1058
|
+
let device = self.captureDevice
|
|
1059
|
+
@@ -166,6 +232,7 @@ final class HybridCameraController: HybridCameraControllerSpec, NativeCameraCont
|
|
1060
|
+
// 3. Apply zoom
|
|
1061
|
+
device.videoZoomFactor = clampedForFormat
|
|
1062
|
+
}
|
|
1063
|
+
+#endif
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
func focusTo(
|
|
1067
|
+
@@ -268,10 +335,14 @@ final class HybridCameraController: HybridCameraControllerSpec, NativeCameraCont
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
- func addSubjectAreaChangedListener(onSubjectAreaChanged: @escaping () -> Void) -> ListenerSubscription {
|
|
1072
|
+
+ func addSubjectAreaChangedListener(onSubjectAreaChanged: @escaping () -> Void) throws -> ListenerSubscription {
|
|
1073
|
+
+#if os(macOS)
|
|
1074
|
+
+ throw RuntimeError.error(withMessage: "Subject-area monitoring is not supported on macOS")
|
|
1075
|
+
+#else
|
|
1076
|
+
return SubjectAreaMonitor.addObserver(
|
|
1077
|
+
device: captureDevice,
|
|
1078
|
+
onSubjectAreaDidChange: onSubjectAreaChanged)
|
|
1079
|
+
+#endif
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
func setTorchMode(mode: TorchMode) -> Promise<Void> {
|
|
1083
|
+
@@ -299,6 +370,9 @@ final class HybridCameraController: HybridCameraControllerSpec, NativeCameraCont
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
func enableTorchWithStrength(strength: Double) -> Promise<Void> {
|
|
1087
|
+
+#if os(macOS)
|
|
1088
|
+
+ return .rejected(withError: RuntimeError.error(withMessage: "enableTorchWithStrength is not supported on macOS"))
|
|
1089
|
+
+#else
|
|
1090
|
+
return captureDevice.withLock(queue) {
|
|
1091
|
+
guard self.device.supportsTorchStrength else {
|
|
1092
|
+
throw RuntimeError.error(
|
|
1093
|
+
@@ -314,9 +388,13 @@ final class HybridCameraController: HybridCameraControllerSpec, NativeCameraCont
|
|
1094
|
+
}
|
|
1095
|
+
try self.captureDevice.setTorchModeOn(level: Float(strength))
|
|
1096
|
+
}
|
|
1097
|
+
+#endif
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
func startZoomAnimation(zoom: Double, rate: Double) -> Promise<Void> {
|
|
1101
|
+
+#if os(macOS)
|
|
1102
|
+
+ return .rejected(withError: RuntimeError.error(withMessage: "startZoomAnimation is not supported on macOS"))
|
|
1103
|
+
+#else
|
|
1104
|
+
return captureDevice.withLock(queue) { completion in
|
|
1105
|
+
if self.captureDevice.videoZoomFactor == zoom {
|
|
1106
|
+
// We are already exactly on our target value
|
|
1107
|
+
@@ -337,15 +415,23 @@ final class HybridCameraController: HybridCameraControllerSpec, NativeCameraCont
|
|
1108
|
+
|
|
1109
|
+
self.captureDevice.ramp(toVideoZoomFactor: zoom, withRate: Float(rate))
|
|
1110
|
+
}
|
|
1111
|
+
+#endif
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
func cancelZoomAnimation() -> Promise<Void> {
|
|
1115
|
+
+#if os(macOS)
|
|
1116
|
+
+ return .rejected(withError: RuntimeError.error(withMessage: "cancelZoomAnimation is not supported on macOS"))
|
|
1117
|
+
+#else
|
|
1118
|
+
return captureDevice.withLock(queue) {
|
|
1119
|
+
self.captureDevice.cancelVideoZoomRamp()
|
|
1120
|
+
}
|
|
1121
|
+
+#endif
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
func setExposureBias(exposure: Double) -> Promise<Void> {
|
|
1125
|
+
+#if os(macOS)
|
|
1126
|
+
+ return .rejected(withError: RuntimeError.error(withMessage: "setExposureBias is not supported on macOS"))
|
|
1127
|
+
+#else
|
|
1128
|
+
return captureDevice.withLock(queue) { completion in
|
|
1129
|
+
// 1. Ensure exposureBias is within range
|
|
1130
|
+
let device = self.captureDevice
|
|
1131
|
+
@@ -362,9 +448,13 @@ final class HybridCameraController: HybridCameraControllerSpec, NativeCameraCont
|
|
1132
|
+
completion()
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
+#endif
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
func setFocusLocked(lensPosition: Double) -> Promise<Void> {
|
|
1139
|
+
+#if os(macOS)
|
|
1140
|
+
+ return .rejected(withError: RuntimeError.error(withMessage: "setFocusLocked is not supported on macOS"))
|
|
1141
|
+
+#else
|
|
1142
|
+
return captureDevice.withLock(queue) { completion in
|
|
1143
|
+
// 1. Ensure values are within valid range
|
|
1144
|
+
guard lensPosition >= 0 && lensPosition <= 1 else {
|
|
1145
|
+
@@ -378,34 +468,61 @@ final class HybridCameraController: HybridCameraControllerSpec, NativeCameraCont
|
|
1146
|
+
completion()
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
+#endif
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
func lockCurrentFocus() -> Promise<Void> {
|
|
1153
|
+
+#if os(macOS)
|
|
1154
|
+
+ return captureDevice.withLock(queue) {
|
|
1155
|
+
+ guard self.captureDevice.isFocusModeSupported(.locked) else { throw RuntimeError.error(withMessage: "lockCurrentFocus is unsupported by this camera") }
|
|
1156
|
+
+ self.captureDevice.focusMode = .locked
|
|
1157
|
+
+ }
|
|
1158
|
+
+#else
|
|
1159
|
+
return captureDevice.withLock(queue) { completion in
|
|
1160
|
+
self.captureDevice.setFocusModeLocked(lensPosition: AVCaptureDevice.currentLensPosition) {
|
|
1161
|
+
_ in
|
|
1162
|
+
completion()
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
+#endif
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
var minExposureDuration: Double {
|
|
1169
|
+
+#if os(macOS)
|
|
1170
|
+
+ return 0
|
|
1171
|
+
+#else
|
|
1172
|
+
return captureDevice.activeFormat.minExposureDuration.seconds
|
|
1173
|
+
+#endif
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
var maxExposureDuration: Double {
|
|
1177
|
+
+#if os(macOS)
|
|
1178
|
+
+ return 0
|
|
1179
|
+
+#else
|
|
1180
|
+
return captureDevice.activeFormat.maxExposureDuration.seconds
|
|
1181
|
+
+#endif
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
var minISO: Double {
|
|
1185
|
+
+#if os(macOS)
|
|
1186
|
+
+ return 0
|
|
1187
|
+
+#else
|
|
1188
|
+
return Double(captureDevice.activeFormat.minISO)
|
|
1189
|
+
+#endif
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
var maxISO: Double {
|
|
1193
|
+
+#if os(macOS)
|
|
1194
|
+
+ return 0
|
|
1195
|
+
+#else
|
|
1196
|
+
return Double(captureDevice.activeFormat.maxISO)
|
|
1197
|
+
+#endif
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
func setExposureLocked(duration: Double, iso: Double) -> Promise<Void> {
|
|
1201
|
+
+#if os(macOS)
|
|
1202
|
+
+ return .rejected(withError: RuntimeError.error(withMessage: "setExposureLocked is not supported on macOS"))
|
|
1203
|
+
+#else
|
|
1204
|
+
return captureDevice.withLock(queue) { completion in
|
|
1205
|
+
let device = self.captureDevice
|
|
1206
|
+
// 1. Ensure values are within valid range
|
|
1207
|
+
@@ -433,9 +550,16 @@ final class HybridCameraController: HybridCameraControllerSpec, NativeCameraCont
|
|
1208
|
+
completion()
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
+#endif
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
func lockCurrentExposure() -> Promise<Void> {
|
|
1215
|
+
+#if os(macOS)
|
|
1216
|
+
+ return captureDevice.withLock(queue) {
|
|
1217
|
+
+ guard self.captureDevice.isExposureModeSupported(.locked) else { throw RuntimeError.error(withMessage: "lockCurrentExposure is unsupported by this camera") }
|
|
1218
|
+
+ self.captureDevice.exposureMode = .locked
|
|
1219
|
+
+ }
|
|
1220
|
+
+#else
|
|
1221
|
+
return captureDevice.withLock(queue) { completion in
|
|
1222
|
+
self.captureDevice.setExposureModeCustom(
|
|
1223
|
+
duration: AVCaptureDevice.currentExposureDuration,
|
|
1224
|
+
@@ -444,11 +568,15 @@ final class HybridCameraController: HybridCameraControllerSpec, NativeCameraCont
|
|
1225
|
+
completion()
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
+#endif
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
func convertWhiteBalanceTemperatureAndTintValues(
|
|
1232
|
+
whiteBalanceTemperatureAndTint: WhiteBalanceTemperatureAndTint
|
|
1233
|
+
) throws -> WhiteBalanceGains {
|
|
1234
|
+
+#if os(macOS)
|
|
1235
|
+
+ throw RuntimeError.error(withMessage: "Manual white balance gains are not supported on macOS")
|
|
1236
|
+
+#else
|
|
1237
|
+
// 1. Convert our type to the AVFoundation type
|
|
1238
|
+
let tintValues = AVCaptureDevice.WhiteBalanceTemperatureAndTintValues(
|
|
1239
|
+
temperature: Float(whiteBalanceTemperatureAndTint.temperature),
|
|
1240
|
+
@@ -460,9 +588,13 @@ final class HybridCameraController: HybridCameraControllerSpec, NativeCameraCont
|
|
1241
|
+
redGain: Double(gains.redGain),
|
|
1242
|
+
blueGain: Double(gains.blueGain),
|
|
1243
|
+
greenGain: Double(gains.greenGain))
|
|
1244
|
+
+#endif
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
func setWhiteBalanceLocked(whiteBalanceGains: WhiteBalanceGains) -> Promise<Void> {
|
|
1248
|
+
+#if os(macOS)
|
|
1249
|
+
+ return .rejected(withError: RuntimeError.error(withMessage: "setWhiteBalanceLocked is not supported on macOS"))
|
|
1250
|
+
+#else
|
|
1251
|
+
return captureDevice.withLock(queue) { completion in
|
|
1252
|
+
// 1. Ensure values are within valid range
|
|
1253
|
+
let device = self.captureDevice
|
|
1254
|
+
@@ -498,14 +630,22 @@ final class HybridCameraController: HybridCameraControllerSpec, NativeCameraCont
|
|
1255
|
+
completion()
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
+#endif
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
func lockCurrentWhiteBalance() -> Promise<Void> {
|
|
1262
|
+
+#if os(macOS)
|
|
1263
|
+
+ return captureDevice.withLock(queue) {
|
|
1264
|
+
+ guard self.captureDevice.isWhiteBalanceModeSupported(.locked) else { throw RuntimeError.error(withMessage: "lockCurrentWhiteBalance is unsupported by this camera") }
|
|
1265
|
+
+ self.captureDevice.whiteBalanceMode = .locked
|
|
1266
|
+
+ }
|
|
1267
|
+
+#else
|
|
1268
|
+
return captureDevice.withLock(queue) { completion in
|
|
1269
|
+
self.captureDevice.setWhiteBalanceModeLocked(with: AVCaptureDevice.currentWhiteBalanceGains) {
|
|
1270
|
+
_ in
|
|
1271
|
+
completion()
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
+#endif
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
diff --git a/ios/Hybrid Objects/HybridCameraDeviceFactory.swift b/ios/Hybrid Objects/HybridCameraDeviceFactory.swift
|
|
1278
|
+
index 013833c..9e8d1d0 100644
|
|
1279
|
+
--- a/ios/Hybrid Objects/HybridCameraDeviceFactory.swift
|
|
1280
|
+
+++ b/ios/Hybrid Objects/HybridCameraDeviceFactory.swift
|
|
1281
|
+
@@ -23,9 +23,13 @@ final class HybridCameraDeviceFactory: HybridCameraDeviceFactorySpec {
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
var supportedMultiCamDeviceCombinations: [[any HybridCameraDeviceSpec]] {
|
|
1285
|
+
+#if os(macOS)
|
|
1286
|
+
+ return []
|
|
1287
|
+
+#else
|
|
1288
|
+
return discoverySession.supportedMultiCamDeviceSets.map { devices in
|
|
1289
|
+
return devices.map { HybridCameraDevice(device: $0) }
|
|
1290
|
+
}
|
|
1291
|
+
+#endif
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
var userPreferredCamera: (any HybridCameraDeviceSpec)? {
|
|
1295
|
+
@@ -53,7 +57,7 @@ final class HybridCameraDeviceFactory: HybridCameraDeviceFactorySpec {
|
|
1296
|
+
-> ListenerSubscription
|
|
1297
|
+
{
|
|
1298
|
+
// 1. Attach a listener using KVO
|
|
1299
|
+
- let observation = discoverySession.observe(\.devices) { _, change in
|
|
1300
|
+
+ let observation = discoverySession.observe(\.devices, options: [.old, .new]) { _, change in
|
|
1301
|
+
guard let newDevices = change.newValue else { return }
|
|
1302
|
+
logger.info("Devices changed! \(change.oldValue?.count ?? 0) -> \(newDevices.count)")
|
|
1303
|
+
let devices = newDevices.map { HybridCameraDevice(device: $0) }
|
|
1304
|
+
diff --git a/ios/Hybrid Objects/HybridCameraFactory.swift b/ios/Hybrid Objects/HybridCameraFactory.swift
|
|
1305
|
+
index 3f35188..637fff3 100644
|
|
1306
|
+
--- a/ios/Hybrid Objects/HybridCameraFactory.swift
|
|
1307
|
+
+++ b/ios/Hybrid Objects/HybridCameraFactory.swift
|
|
1308
|
+
@@ -44,7 +44,11 @@ final class VisionCamera: HybridCameraFactorySpec {
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
var supportsMultiCamSessions: Bool {
|
|
1312
|
+
+#if os(macOS)
|
|
1313
|
+
+ return false
|
|
1314
|
+
+#else
|
|
1315
|
+
return AVCaptureMultiCamSession.isMultiCamSupported
|
|
1316
|
+
+#endif
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
func createCameraSession(enableMultiCam: Bool) -> Promise<any HybridCameraSessionSpec> {
|
|
1320
|
+
@@ -71,7 +75,10 @@ final class VisionCamera: HybridCameraFactorySpec {
|
|
1321
|
+
return try HybridCameraPhotoOutput(options: options)
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
- func createVideoOutput(options: VideoOutputOptions) -> any HybridCameraVideoOutputSpec {
|
|
1325
|
+
+ func createVideoOutput(options: VideoOutputOptions) throws -> any HybridCameraVideoOutputSpec {
|
|
1326
|
+
+#if os(macOS)
|
|
1327
|
+
+ if options.targetBitRate != nil { throw RuntimeError.error(withMessage: "Custom movie bit rate is not supported by the macOS prototype") }
|
|
1328
|
+
+#endif
|
|
1329
|
+
if options.enablePersistentRecorder == true {
|
|
1330
|
+
// On iOS, the `AVCaptureMovieFileOutput` does not allow flipping the Camera while
|
|
1331
|
+
// recording, which is a feature we call "enablePersistentRecorder".
|
|
1332
|
+
@@ -88,13 +95,21 @@ final class VisionCamera: HybridCameraFactorySpec {
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
func createDepthFrameOutput(options: DepthFrameOutputOptions)
|
|
1336
|
+
- -> any HybridCameraDepthFrameOutputSpec
|
|
1337
|
+
+ throws -> any HybridCameraDepthFrameOutputSpec
|
|
1338
|
+
{
|
|
1339
|
+
+#if os(macOS)
|
|
1340
|
+
+ throw RuntimeError.error(withMessage: "createDepthFrameOutput is not supported on macOS")
|
|
1341
|
+
+#else
|
|
1342
|
+
return HybridCameraDepthFrameOutput(options: options)
|
|
1343
|
+
+#endif
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1346
|
+
- func createObjectOutput(options: ObjectOutputOptions) -> any HybridCameraObjectOutputSpec {
|
|
1347
|
+
+ func createObjectOutput(options: ObjectOutputOptions) throws -> any HybridCameraObjectOutputSpec {
|
|
1348
|
+
+#if os(macOS)
|
|
1349
|
+
+ throw RuntimeError.error(withMessage: "createObjectOutput is not supported on macOS")
|
|
1350
|
+
+#else
|
|
1351
|
+
return HybridCameraObjectOutput(options: options)
|
|
1352
|
+
+#endif
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
func createPreviewOutput() -> any HybridCameraPreviewOutputSpec {
|
|
1356
|
+
@@ -104,7 +119,11 @@ final class VisionCamera: HybridCameraFactorySpec {
|
|
1357
|
+
func createOutputSynchronizer(outputs: [any HybridCameraOutputSpec]) throws
|
|
1358
|
+
-> any HybridCameraOutputSynchronizerSpec
|
|
1359
|
+
{
|
|
1360
|
+
+#if os(macOS)
|
|
1361
|
+
+ throw RuntimeError.error(withMessage: "createOutputSynchronizer is not supported on macOS")
|
|
1362
|
+
+#else
|
|
1363
|
+
return try HybridCameraOutputSynchronizer(outputs: outputs)
|
|
1364
|
+
+#endif
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
func createZoomGestureController() -> any HybridZoomGestureControllerSpec {
|
|
1368
|
+
diff --git a/ios/Hybrid Objects/HybridCameraSession.swift b/ios/Hybrid Objects/HybridCameraSession.swift
|
|
1369
|
+
index c74356e..23574b7 100644
|
|
1370
|
+
--- a/ios/Hybrid Objects/HybridCameraSession.swift
|
|
1371
|
+
+++ b/ios/Hybrid Objects/HybridCameraSession.swift
|
|
1372
|
+
@@ -18,14 +18,20 @@ final class HybridCameraSession: HybridCameraSessionSpec {
|
|
1373
|
+
target: nil)
|
|
1374
|
+
|
|
1375
|
+
init(enableMultiCam: Bool) {
|
|
1376
|
+
+#if os(macOS)
|
|
1377
|
+
+ self.session = AVCaptureSession()
|
|
1378
|
+
+#else
|
|
1379
|
+
if enableMultiCam {
|
|
1380
|
+
self.session = AVCaptureMultiCamSession()
|
|
1381
|
+
} else {
|
|
1382
|
+
self.session = AVCaptureSession()
|
|
1383
|
+
}
|
|
1384
|
+
+#endif
|
|
1385
|
+
// We manage formats manually via `device.activeFormat`, so opt out of the
|
|
1386
|
+
// session's preset-based format selection upfront.
|
|
1387
|
+
+#if !os(macOS)
|
|
1388
|
+
self.session.sessionPreset = .inputPriority
|
|
1389
|
+
+#endif
|
|
1390
|
+
super.init()
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
@@ -45,11 +51,15 @@ final class HybridCameraSession: HybridCameraSessionSpec {
|
|
1394
|
+
// Ensure multi-cam is enabled if we have multiple inputs
|
|
1395
|
+
let isMultiCam = connections.count > 1
|
|
1396
|
+
if isMultiCam {
|
|
1397
|
+
+#if os(macOS)
|
|
1398
|
+
+ throw RuntimeError.error(withMessage: "Multi-camera sessions are not supported on macOS")
|
|
1399
|
+
+#else
|
|
1400
|
+
guard self.session is AVCaptureMultiCamSession else {
|
|
1401
|
+
throw RuntimeError(
|
|
1402
|
+
"Cannot add multiple inputs (\(connections)) to a single-cam CameraSession! "
|
|
1403
|
+
+ "Create your CameraSession as a multi-cam session (`enableMultiCamSupport = true`) to add multiple camera inputs.")
|
|
1404
|
+
}
|
|
1405
|
+
+#endif
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
logger.info("Reconfiguring CameraSession with \(connections.count) connection(s)...")
|
|
1409
|
+
@@ -90,8 +100,11 @@ final class HybridCameraSession: HybridCameraSessionSpec {
|
|
1410
|
+
return constraint.isType(VideoDynamicRangeConstraint.self)
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
+#if !os(macOS)
|
|
1414
|
+
self.session.automaticallyConfiguresCaptureDeviceForWideColor = !hasCustomDynamicRangeConstraint
|
|
1415
|
+
+#endif
|
|
1416
|
+
|
|
1417
|
+
+#if !os(macOS)
|
|
1418
|
+
// Haptics and System Sounds Playback
|
|
1419
|
+
if let allowHapticsAndSystemSoundsPlayback = config?.allowHapticsAndSystemSoundsPlayback {
|
|
1420
|
+
let audioSession = AVAudioSession.sharedInstance()
|
|
1421
|
+
@@ -106,6 +119,7 @@ final class HybridCameraSession: HybridCameraSessionSpec {
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
+#endif
|
|
1426
|
+
// Return CameraControllers per connection to adjust camera settings (focus, etc)
|
|
1427
|
+
return try connections.map { connection in
|
|
1428
|
+
return try HybridCameraController(device: connection.input, queue: Self.queue)
|
|
1429
|
+
@@ -146,6 +160,9 @@ final class HybridCameraSession: HybridCameraSessionSpec {
|
|
1430
|
+
if device.activeFormat != resolved.negotiatedFormat.format {
|
|
1431
|
+
device.activeFormat = resolved.negotiatedFormat.format
|
|
1432
|
+
}
|
|
1433
|
+
+#if os(macOS)
|
|
1434
|
+
+
|
|
1435
|
+
+#else
|
|
1436
|
+
if let depthFormat = resolved.negotiatedFormat.depthFormat {
|
|
1437
|
+
// On devices that support depth, `device.activeDepthDataFormat`
|
|
1438
|
+
// cannot be set to `nil`, so we only set the depth format when
|
|
1439
|
+
@@ -156,6 +173,7 @@ final class HybridCameraSession: HybridCameraSessionSpec {
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
+#endif
|
|
1444
|
+
// TODO: Do we want to do any sanity checks here? Or assume that the negotiated format is properly validated before being set here?
|
|
1445
|
+
|
|
1446
|
+
// TODO: We could add a `allowFpsThrottling` flag in the future to run at variable frame rate.
|
|
1447
|
+
@@ -165,6 +183,9 @@ final class HybridCameraSession: HybridCameraSessionSpec {
|
|
1448
|
+
device.activeVideoMinFrameDuration = CMTime(value: 1, timescale: Int32(fps))
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
+#if os(macOS)
|
|
1452
|
+
+
|
|
1453
|
+
+#else
|
|
1454
|
+
// Video Stabilization
|
|
1455
|
+
if let videoStabilizationMode = resolved.enabledConstraints.selectedVideoStabilizationMode {
|
|
1456
|
+
for connection in self.session.connections where !connection.isConnectedToPreview {
|
|
1457
|
+
@@ -180,10 +201,14 @@ final class HybridCameraSession: HybridCameraSessionSpec {
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
+#endif
|
|
1462
|
+
// Dynamic Range
|
|
1463
|
+
if let dynamicRange = resolved.enabledConstraints.selectedVideoDynamicRange {
|
|
1464
|
+
device.activeColorSpace = dynamicRange.colorSpace.toAVCaptureColorSpace()
|
|
1465
|
+
// Bit-Depth + ColorRange is implicitly set via `activeFormat`'s pixel format
|
|
1466
|
+
+#if os(macOS)
|
|
1467
|
+
+
|
|
1468
|
+
+#else
|
|
1469
|
+
if device.activeFormat.isVideoHDRSupported {
|
|
1470
|
+
if dynamicRange.isHDR {
|
|
1471
|
+
// TODO: If we refactor `TargetDynamicRange` to an enum, `EDR` (which `isVideoHDREnabled` effectively is) could be a separate value.
|
|
1472
|
+
@@ -195,6 +220,7 @@ final class HybridCameraSession: HybridCameraSessionSpec {
|
|
1473
|
+
device.isVideoHDREnabled = false
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
+#endif
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
@@ -289,6 +315,9 @@ final class HybridCameraSession: HybridCameraSessionSpec {
|
|
1481
|
+
if !containsInput {
|
|
1482
|
+
// 2.1. It doesn't exist yet - add it to the session..
|
|
1483
|
+
let deviceInput = try AVCaptureDeviceInput(device: device)
|
|
1484
|
+
+ guard self.session.canAddInput(deviceInput) else {
|
|
1485
|
+
+ throw RuntimeError.error(withMessage: "This camera input cannot be added to the capture session")
|
|
1486
|
+
+ }
|
|
1487
|
+
self.session.addInputWithNoConnections(deviceInput)
|
|
1488
|
+
// 2.2. Configure the input with initial settings
|
|
1489
|
+
if connection.initialZoom != nil || connection.initialExposureBias != nil {
|
|
1490
|
+
@@ -391,6 +420,11 @@ final class HybridCameraSession: HybridCameraSessionSpec {
|
|
1491
|
+
) throws {
|
|
1492
|
+
try device.lockForConfiguration()
|
|
1493
|
+
defer { device.unlockForConfiguration() }
|
|
1494
|
+
+#if os(macOS)
|
|
1495
|
+
+ if initialZoom != nil || initialExposureBias != nil {
|
|
1496
|
+
+ throw RuntimeError.error(withMessage: "Initial zoom and exposure bias are not supported on macOS")
|
|
1497
|
+
+ }
|
|
1498
|
+
+#else
|
|
1499
|
+
if let initialZoom = initialZoom {
|
|
1500
|
+
let clamped = max(
|
|
1501
|
+
min(initialZoom, device.maxAvailableVideoZoomFactor), device.minAvailableVideoZoomFactor)
|
|
1502
|
+
@@ -401,6 +435,7 @@ final class HybridCameraSession: HybridCameraSessionSpec {
|
|
1503
|
+
min(Float(initialExposure), device.maxExposureTargetBias), device.minExposureTargetBias)
|
|
1504
|
+
device.setExposureTargetBias(clamped)
|
|
1505
|
+
}
|
|
1506
|
+
+#endif
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1509
|
+
// pragma MARK: On Started/Stopped Listeners
|
|
1510
|
+
@@ -440,6 +475,9 @@ final class HybridCameraSession: HybridCameraSessionSpec {
|
|
1511
|
+
) throws -> ListenerSubscription {
|
|
1512
|
+
return self.session.addListener(for: AVCaptureSession.wasInterruptedNotification) {
|
|
1513
|
+
notification in
|
|
1514
|
+
+#if os(macOS)
|
|
1515
|
+
+ onInterruptionStarted(.unknown)
|
|
1516
|
+
+#else
|
|
1517
|
+
if let reasonAny = notification.userInfo?[AVCaptureSessionInterruptionReasonKey],
|
|
1518
|
+
let reasonRawValue = reasonAny as? NSNumber,
|
|
1519
|
+
let avReason = AVCaptureSession.InterruptionReason(rawValue: reasonRawValue.intValue)
|
|
1520
|
+
@@ -449,6 +487,7 @@ final class HybridCameraSession: HybridCameraSessionSpec {
|
|
1521
|
+
} else {
|
|
1522
|
+
onInterruptionStarted(.unknown)
|
|
1523
|
+
}
|
|
1524
|
+
+#endif
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
diff --git a/ios/Hybrid Objects/Image Types/HybridPhoto.swift b/ios/Hybrid Objects/Image Types/HybridPhoto.swift
|
|
1529
|
+
index 03129f1..ff11de2 100644
|
|
1530
|
+
--- a/ios/Hybrid Objects/Image Types/HybridPhoto.swift
|
|
1531
|
+
+++ b/ios/Hybrid Objects/Image Types/HybridPhoto.swift
|
|
1532
|
+
@@ -7,6 +7,8 @@
|
|
1533
|
+
|
|
1534
|
+
import AVFoundation
|
|
1535
|
+
import Foundation
|
|
1536
|
+
+import CoreImage
|
|
1537
|
+
+import ImageIO
|
|
1538
|
+
import NitroImage
|
|
1539
|
+
import NitroModules
|
|
1540
|
+
|
|
1541
|
+
@@ -43,24 +45,36 @@ final class HybridPhoto: HybridPhotoSpec, NativePhoto {
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
var isRawPhoto: Bool {
|
|
1545
|
+
+#if os(macOS)
|
|
1546
|
+
+ return false
|
|
1547
|
+
+#else
|
|
1548
|
+
return photo.isRawPhoto
|
|
1549
|
+
+#endif
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
var depth: (any HybridDepthSpec)? {
|
|
1553
|
+
+#if os(macOS)
|
|
1554
|
+
+ return nil
|
|
1555
|
+
+#else
|
|
1556
|
+
guard let depthData = photo.depthData else {
|
|
1557
|
+
return nil
|
|
1558
|
+
}
|
|
1559
|
+
return HybridDepth(
|
|
1560
|
+
depthData: depthData,
|
|
1561
|
+
metadata: metadata)
|
|
1562
|
+
+#endif
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
var size: CMVideoDimensions {
|
|
1566
|
+
+#if os(macOS)
|
|
1567
|
+
+ return photo.resolvedSettings.photoDimensions
|
|
1568
|
+
+#else
|
|
1569
|
+
if isRawPhoto {
|
|
1570
|
+
return photo.resolvedSettings.rawPhotoDimensions
|
|
1571
|
+
} else {
|
|
1572
|
+
return photo.resolvedSettings.photoDimensions
|
|
1573
|
+
}
|
|
1574
|
+
+#endif
|
|
1575
|
+
}
|
|
1576
|
+
var width: Double {
|
|
1577
|
+
return Double(size.width)
|
|
1578
|
+
@@ -70,10 +84,14 @@ final class HybridPhoto: HybridPhotoSpec, NativePhoto {
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
var calibrationData: (any HybridCameraCalibrationDataSpec)? {
|
|
1582
|
+
+#if os(macOS)
|
|
1583
|
+
+ return nil
|
|
1584
|
+
+#else
|
|
1585
|
+
guard let calibrationData = photo.cameraCalibrationData else {
|
|
1586
|
+
return nil
|
|
1587
|
+
}
|
|
1588
|
+
return HybridCameraCalibrationData(calibrationData: calibrationData)
|
|
1589
|
+
+#endif
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
// pragma MARK: Pixel Buffer access
|
|
1593
|
+
@@ -135,6 +153,14 @@ final class HybridPhoto: HybridPhotoSpec, NativePhoto {
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
func toImage() throws -> any HybridImageSpec {
|
|
1597
|
+
+#if os(macOS)
|
|
1598
|
+
+ guard !isRawPhoto, let data = photo.fileDataRepresentation(),
|
|
1599
|
+
+ let source = CGImageSourceCreateWithData(data as CFData, nil),
|
|
1600
|
+
+ let cgImage = CGImageSourceCreateThumbnailAtIndex(source, 0, [kCGImageSourceCreateThumbnailFromImageAlways: true, kCGImageSourceCreateThumbnailWithTransform: true, kCGImageSourceThumbnailMaxPixelSize: max(width, height)] as CFDictionary) else {
|
|
1601
|
+
+ throw RuntimeError.error(withMessage: "Could not decode captured photo")
|
|
1602
|
+
+ }
|
|
1603
|
+
+ return HybridCGImage(cgImage: cgImage)
|
|
1604
|
+
+#else
|
|
1605
|
+
guard let cgImage = photo.cgImageRepresentation() else {
|
|
1606
|
+
if isRawPhoto {
|
|
1607
|
+
throw RuntimeError.error(
|
|
1608
|
+
@@ -143,9 +169,15 @@ final class HybridPhoto: HybridPhotoSpec, NativePhoto {
|
|
1609
|
+
throw RuntimeError.error(withMessage: "Failed to get Image data!")
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
+ #if os(macOS)
|
|
1613
|
+
+ let image = try CIImage(cgImage: cgImage).toUIImage(orientation: orientation.toImageOrientation(isMirrored: isMirrored))
|
|
1614
|
+
+ return HybridCGImage(cgImage: image)
|
|
1615
|
+
+ #else
|
|
1616
|
+
let uiOrientation = orientation.toUIImageOrientation(isMirrored: isMirrored)
|
|
1617
|
+
let uiImage = UIImage(cgImage: cgImage, scale: 1, orientation: uiOrientation)
|
|
1618
|
+
return HybridUIImage(uiImage: uiImage)
|
|
1619
|
+
+ #endif
|
|
1620
|
+
+#endif
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1623
|
+
func toImageAsync() throws -> Promise<any HybridImageSpec> {
|
|
1624
|
+
diff --git a/ios/Hybrid Objects/Image Types/HybridUIImage.swift b/ios/Hybrid Objects/Image Types/HybridUIImage.swift
|
|
1625
|
+
index bcc192a..69ed299 100644
|
|
1626
|
+
--- a/ios/Hybrid Objects/Image Types/HybridUIImage.swift
|
|
1627
|
+
+++ b/ios/Hybrid Objects/Image Types/HybridUIImage.swift
|
|
1628
|
+
@@ -1,3 +1,6 @@
|
|
1629
|
+
+#if os(macOS)
|
|
1630
|
+
+
|
|
1631
|
+
+#else
|
|
1632
|
+
//
|
|
1633
|
+
// HybridPhoto.swift
|
|
1634
|
+
// VisionCamera
|
|
1635
|
+
@@ -18,3 +21,5 @@ internal final class HybridUIImage: HybridImageSpec, NativeImage {
|
|
1636
|
+
super.init()
|
|
1637
|
+
}
|
|
1638
|
+
}
|
|
1639
|
+
+
|
|
1640
|
+
+#endif
|
|
1641
|
+
diff --git a/ios/Hybrid Objects/Inputs/HybridCameraDevice.swift b/ios/Hybrid Objects/Inputs/HybridCameraDevice.swift
|
|
1642
|
+
index bf7bafa..ecb567c 100644
|
|
1643
|
+
--- a/ios/Hybrid Objects/Inputs/HybridCameraDevice.swift
|
|
1644
|
+
+++ b/ios/Hybrid Objects/Inputs/HybridCameraDevice.swift
|
|
1645
|
+
@@ -17,7 +17,11 @@ final class HybridCameraDevice: HybridCameraDeviceSpec, NativeCameraDevice {
|
|
1646
|
+
|
|
1647
|
+
lazy var supportedPixelFormats: [PixelFormat] = {
|
|
1648
|
+
let videoFormats = device.formats
|
|
1649
|
+
+#if os(macOS)
|
|
1650
|
+
+ let depthFormats: [AVCaptureDevice.Format] = []
|
|
1651
|
+
+#else
|
|
1652
|
+
let depthFormats = device.formats.flatMap { $0.supportedDepthDataFormats }
|
|
1653
|
+
+#endif
|
|
1654
|
+
let allFormats = videoFormats + depthFormats
|
|
1655
|
+
return
|
|
1656
|
+
allFormats
|
|
1657
|
+
@@ -95,8 +99,12 @@ final class HybridCameraDevice: HybridCameraDeviceSpec, NativeCameraDevice {
|
|
1658
|
+
}
|
|
1659
|
+
|
|
1660
|
+
func supportsVideoStabilizationMode(videoStabilizationMode: TargetStabilizationMode) throws -> Bool {
|
|
1661
|
+
+#if os(macOS)
|
|
1662
|
+
+ return videoStabilizationMode == .off
|
|
1663
|
+
+#else
|
|
1664
|
+
let stabilizationMode = videoStabilizationMode.toAVCaptureVideoStabilizationMode()
|
|
1665
|
+
return device.formats.contains { $0.isVideoStabilizationModeSupported(stabilizationMode) }
|
|
1666
|
+
+#endif
|
|
1667
|
+
}
|
|
1668
|
+
|
|
1669
|
+
func supportsPreviewStabilizationMode(previewStabilizationMode: TargetStabilizationMode) throws -> Bool {
|
|
1670
|
+
@@ -134,22 +142,38 @@ final class HybridCameraDevice: HybridCameraDeviceSpec, NativeCameraDevice {
|
|
1671
|
+
return CameraPosition(position: device.position)
|
|
1672
|
+
}
|
|
1673
|
+
|
|
1674
|
+
+#if os(macOS)
|
|
1675
|
+
+ let physicalDevices: [any HybridCameraDeviceSpec] = []
|
|
1676
|
+
+#else
|
|
1677
|
+
lazy var physicalDevices: [any HybridCameraDeviceSpec] =
|
|
1678
|
+
device.constituentDevices.map { HybridCameraDevice(device: $0) }
|
|
1679
|
+
+#endif
|
|
1680
|
+
|
|
1681
|
+
var isVirtualDevice: Bool {
|
|
1682
|
+
+#if os(macOS)
|
|
1683
|
+
+ return false
|
|
1684
|
+
+#else
|
|
1685
|
+
return device.isVirtualDevice
|
|
1686
|
+
+#endif
|
|
1687
|
+
}
|
|
1688
|
+
|
|
1689
|
+
var focalLength: Double? {
|
|
1690
|
+
+#if os(macOS)
|
|
1691
|
+
+ return nil
|
|
1692
|
+
+#else
|
|
1693
|
+
guard #available(iOS 26.0, *) else {
|
|
1694
|
+
return nil
|
|
1695
|
+
}
|
|
1696
|
+
return Double(device.nominalFocalLengthIn35mmFilm)
|
|
1697
|
+
+#endif
|
|
1698
|
+
}
|
|
1699
|
+
|
|
1700
|
+
var lensAperture: Double {
|
|
1701
|
+
+#if os(macOS)
|
|
1702
|
+
+ return 0
|
|
1703
|
+
+#else
|
|
1704
|
+
return Double(device.lensAperture)
|
|
1705
|
+
+#endif
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
var isContinuityCamera: Bool {
|
|
1709
|
+
@@ -170,7 +194,11 @@ final class HybridCameraDevice: HybridCameraDeviceSpec, NativeCameraDevice {
|
|
1710
|
+
}
|
|
1711
|
+
|
|
1712
|
+
var supportsSmoothAutoFocus: Bool {
|
|
1713
|
+
+#if os(macOS)
|
|
1714
|
+
+ return false
|
|
1715
|
+
+#else
|
|
1716
|
+
return device.isSmoothAutoFocusSupported
|
|
1717
|
+
+#endif
|
|
1718
|
+
}
|
|
1719
|
+
|
|
1720
|
+
var supportsSpeedQualityPrioritization: Bool {
|
|
1721
|
+
@@ -179,13 +207,25 @@ final class HybridCameraDevice: HybridCameraDeviceSpec, NativeCameraDevice {
|
|
1722
|
+
}
|
|
1723
|
+
|
|
1724
|
+
var supportsExposureBias: Bool {
|
|
1725
|
+
+#if os(macOS)
|
|
1726
|
+
+ return false
|
|
1727
|
+
+#else
|
|
1728
|
+
return true
|
|
1729
|
+
+#endif
|
|
1730
|
+
}
|
|
1731
|
+
var minExposureBias: Double {
|
|
1732
|
+
+#if os(macOS)
|
|
1733
|
+
+ return 0
|
|
1734
|
+
+#else
|
|
1735
|
+
return Double(device.minExposureTargetBias)
|
|
1736
|
+
+#endif
|
|
1737
|
+
}
|
|
1738
|
+
var maxExposureBias: Double {
|
|
1739
|
+
+#if os(macOS)
|
|
1740
|
+
+ return 0
|
|
1741
|
+
+#else
|
|
1742
|
+
return Double(device.maxExposureTargetBias)
|
|
1743
|
+
+#endif
|
|
1744
|
+
}
|
|
1745
|
+
|
|
1746
|
+
var hasFlash: Bool {
|
|
1747
|
+
@@ -197,8 +237,12 @@ final class HybridCameraDevice: HybridCameraDeviceSpec, NativeCameraDevice {
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1750
|
+
var supportsTorchStrength: Bool {
|
|
1751
|
+
+#if os(macOS)
|
|
1752
|
+
+ return false
|
|
1753
|
+
+#else
|
|
1754
|
+
// On iOS any device with a torch also supports custom torch level/strength
|
|
1755
|
+
return device.hasTorch
|
|
1756
|
+
+#endif
|
|
1757
|
+
}
|
|
1758
|
+
|
|
1759
|
+
var minTorchStrength: Double {
|
|
1760
|
+
@@ -210,27 +254,51 @@ final class HybridCameraDevice: HybridCameraDeviceSpec, NativeCameraDevice {
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
var supportsLowLightBoost: Bool {
|
|
1764
|
+
+#if os(macOS)
|
|
1765
|
+
+ return false
|
|
1766
|
+
+#else
|
|
1767
|
+
return device.isLowLightBoostSupported
|
|
1768
|
+
+#endif
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
var minZoom: Double {
|
|
1772
|
+
+#if os(macOS)
|
|
1773
|
+
+ return 1
|
|
1774
|
+
+#else
|
|
1775
|
+
return device.minAvailableVideoZoomFactor
|
|
1776
|
+
+#endif
|
|
1777
|
+
}
|
|
1778
|
+
|
|
1779
|
+
var maxZoom: Double {
|
|
1780
|
+
+#if os(macOS)
|
|
1781
|
+
+ return 1
|
|
1782
|
+
+#else
|
|
1783
|
+
return device.maxAvailableVideoZoomFactor
|
|
1784
|
+
+#endif
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1787
|
+
var zoomLensSwitchFactors: [Double] {
|
|
1788
|
+
+#if os(macOS)
|
|
1789
|
+
+ return []
|
|
1790
|
+
+#else
|
|
1791
|
+
return device.virtualDeviceSwitchOverVideoZoomFactors.map { $0.doubleValue }
|
|
1792
|
+
+#endif
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
var supportsDistortionCorrection: Bool {
|
|
1796
|
+
+#if os(macOS)
|
|
1797
|
+
+ return false
|
|
1798
|
+
+#else
|
|
1799
|
+
return device.isGeometricDistortionCorrectionSupported
|
|
1800
|
+
+#endif
|
|
1801
|
+
}
|
|
1802
|
+
|
|
1803
|
+
var supportsPreviewImage: Bool {
|
|
1804
|
+
+#if os(macOS)
|
|
1805
|
+
+ return false
|
|
1806
|
+
+#else
|
|
1807
|
+
return true
|
|
1808
|
+
+#endif
|
|
1809
|
+
}
|
|
1810
|
+
|
|
1811
|
+
var supportsFocusMetering: Bool {
|
|
1812
|
+
@@ -239,7 +307,11 @@ final class HybridCameraDevice: HybridCameraDeviceSpec, NativeCameraDevice {
|
|
1813
|
+
}
|
|
1814
|
+
|
|
1815
|
+
var supportsFocusLocking: Bool {
|
|
1816
|
+
+#if os(macOS)
|
|
1817
|
+
+ return false
|
|
1818
|
+
+#else
|
|
1819
|
+
return device.isLockingFocusWithCustomLensPositionSupported
|
|
1820
|
+
+#endif
|
|
1821
|
+
}
|
|
1822
|
+
|
|
1823
|
+
var supportsExposureMetering: Bool {
|
|
1824
|
+
@@ -248,7 +320,11 @@ final class HybridCameraDevice: HybridCameraDeviceSpec, NativeCameraDevice {
|
|
1825
|
+
}
|
|
1826
|
+
|
|
1827
|
+
var supportsExposureLocking: Bool {
|
|
1828
|
+
+#if os(macOS)
|
|
1829
|
+
+ return false
|
|
1830
|
+
+#else
|
|
1831
|
+
return device.isExposureModeSupported(.custom)
|
|
1832
|
+
+#endif
|
|
1833
|
+
}
|
|
1834
|
+
|
|
1835
|
+
var supportsWhiteBalanceMetering: Bool {
|
|
1836
|
+
@@ -257,16 +333,28 @@ final class HybridCameraDevice: HybridCameraDeviceSpec, NativeCameraDevice {
|
|
1837
|
+
}
|
|
1838
|
+
|
|
1839
|
+
var supportsWhiteBalanceLocking: Bool {
|
|
1840
|
+
+#if os(macOS)
|
|
1841
|
+
+ return false
|
|
1842
|
+
+#else
|
|
1843
|
+
return device.isLockingWhiteBalanceWithCustomDeviceGainsSupported
|
|
1844
|
+
+#endif
|
|
1845
|
+
}
|
|
1846
|
+
|
|
1847
|
+
var maxWhiteBalanceGain: Double {
|
|
1848
|
+
+#if os(macOS)
|
|
1849
|
+
+ return 1
|
|
1850
|
+
+#else
|
|
1851
|
+
return Double(device.maxWhiteBalanceGain)
|
|
1852
|
+
+#endif
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1855
|
+
var mediaTypes: [MediaType] {
|
|
1856
|
+
+#if os(macOS)
|
|
1857
|
+
+ return [.video]
|
|
1858
|
+
+#else
|
|
1859
|
+
let allMediaTypes: [MediaType] = [.video, .depth, .metadata]
|
|
1860
|
+
return allMediaTypes.filter { device.hasMediaType($0.toAVMediaType()) }
|
|
1861
|
+
+#endif
|
|
1862
|
+
}
|
|
1863
|
+
|
|
1864
|
+
func isSessionConfigSupported(config: any HybridCameraSessionConfigSpec) throws -> Bool {
|
|
1865
|
+
@@ -280,6 +368,9 @@ final class HybridCameraDevice: HybridCameraDeviceSpec, NativeCameraDevice {
|
|
1866
|
+
return false
|
|
1867
|
+
}
|
|
1868
|
+
|
|
1869
|
+
+#if os(macOS)
|
|
1870
|
+
+ if config.negotiatedFormat.depthFormat != nil { return false }
|
|
1871
|
+
+#else
|
|
1872
|
+
if let depthFormat = config.negotiatedFormat.depthFormat {
|
|
1873
|
+
guard format.supportedDepthDataFormats.contains(depthFormat) else {
|
|
1874
|
+
// Format is from a different `AVCaptureDevice.Format`
|
|
1875
|
+
@@ -287,6 +378,7 @@ final class HybridCameraDevice: HybridCameraDeviceSpec, NativeCameraDevice {
|
|
1876
|
+
}
|
|
1877
|
+
}
|
|
1878
|
+
|
|
1879
|
+
+#endif
|
|
1880
|
+
// TODO: Re-use the logic from `ConstraintResolver` for resolving the actual enabled
|
|
1881
|
+
// constraints (like FPS or HDR settings) so we have a single source of truth
|
|
1882
|
+
// when we modify anything in the future.
|
|
1883
|
+
diff --git a/ios/Hybrid Objects/Orientation/HybridDeviceOrientationManager.swift b/ios/Hybrid Objects/Orientation/HybridDeviceOrientationManager.swift
|
|
1884
|
+
index 2759093..3fdbb55 100644
|
|
1885
|
+
--- a/ios/Hybrid Objects/Orientation/HybridDeviceOrientationManager.swift
|
|
1886
|
+
+++ b/ios/Hybrid Objects/Orientation/HybridDeviceOrientationManager.swift
|
|
1887
|
+
@@ -1,3 +1,12 @@
|
|
1888
|
+
+#if os(macOS)
|
|
1889
|
+
+import NitroModules
|
|
1890
|
+
+final class HybridDeviceOrientationManager: HybridOrientationManagerSpec {
|
|
1891
|
+
+ let source: OrientationSource = .device
|
|
1892
|
+
+ var currentOrientation: CameraOrientation? { .up }
|
|
1893
|
+
+ func startOrientationUpdates(onChanged: @escaping (CameraOrientation) -> Void) { onChanged(.up) }
|
|
1894
|
+
+ func stopOrientationUpdates() { }
|
|
1895
|
+
+}
|
|
1896
|
+
+#else
|
|
1897
|
+
///
|
|
1898
|
+
/// HybridDeviceOrientationManager.swift
|
|
1899
|
+
/// VisionCamera
|
|
1900
|
+
@@ -58,3 +67,5 @@ final class HybridDeviceOrientationManager: HybridOrientationManagerSpec {
|
|
1901
|
+
}
|
|
1902
|
+
}
|
|
1903
|
+
}
|
|
1904
|
+
+
|
|
1905
|
+
+#endif
|
|
1906
|
+
diff --git a/ios/Hybrid Objects/Orientation/HybridInterfaceOrientationManager.swift b/ios/Hybrid Objects/Orientation/HybridInterfaceOrientationManager.swift
|
|
1907
|
+
index 29b1017..8a3a2c9 100644
|
|
1908
|
+
--- a/ios/Hybrid Objects/Orientation/HybridInterfaceOrientationManager.swift
|
|
1909
|
+
+++ b/ios/Hybrid Objects/Orientation/HybridInterfaceOrientationManager.swift
|
|
1910
|
+
@@ -1,3 +1,12 @@
|
|
1911
|
+
+#if os(macOS)
|
|
1912
|
+
+import NitroModules
|
|
1913
|
+
+final class HybridInterfaceOrientationManager: HybridOrientationManagerSpec {
|
|
1914
|
+
+ let source: OrientationSource = .interface
|
|
1915
|
+
+ var currentOrientation: CameraOrientation? { .up }
|
|
1916
|
+
+ func startOrientationUpdates(onChanged: @escaping (CameraOrientation) -> Void) { onChanged(.up) }
|
|
1917
|
+
+ func stopOrientationUpdates() { }
|
|
1918
|
+
+}
|
|
1919
|
+
+#else
|
|
1920
|
+
///
|
|
1921
|
+
/// HybridInterfaceOrientationManager.swift
|
|
1922
|
+
/// VisionCamera
|
|
1923
|
+
@@ -73,3 +82,5 @@ final class HybridInterfaceOrientationManager: HybridOrientationManagerSpec {
|
|
1924
|
+
}
|
|
1925
|
+
}
|
|
1926
|
+
}
|
|
1927
|
+
+
|
|
1928
|
+
+#endif
|
|
1929
|
+
diff --git a/ios/Hybrid Objects/Outputs/HybridCameraDepthFrameOutput.swift b/ios/Hybrid Objects/Outputs/HybridCameraDepthFrameOutput.swift
|
|
1930
|
+
index 0be7d9d..279b949 100644
|
|
1931
|
+
--- a/ios/Hybrid Objects/Outputs/HybridCameraDepthFrameOutput.swift
|
|
1932
|
+
+++ b/ios/Hybrid Objects/Outputs/HybridCameraDepthFrameOutput.swift
|
|
1933
|
+
@@ -1,3 +1,4 @@
|
|
1934
|
+
+#if !os(macOS)
|
|
1935
|
+
///
|
|
1936
|
+
/// HybridCameraDepthFrameOutput.swift
|
|
1937
|
+
/// VisionCamera
|
|
1938
|
+
@@ -144,3 +145,5 @@ final class HybridCameraDepthFrameOutput: HybridCameraDepthFrameOutputSpec, Nati
|
|
1939
|
+
}
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
+
|
|
1943
|
+
+#endif
|
|
1944
|
+
diff --git a/ios/Hybrid Objects/Outputs/HybridCameraFrameOutput.swift b/ios/Hybrid Objects/Outputs/HybridCameraFrameOutput.swift
|
|
1945
|
+
index 17c7a5f..377bd3a 100644
|
|
1946
|
+
--- a/ios/Hybrid Objects/Outputs/HybridCameraFrameOutput.swift
|
|
1947
|
+
+++ b/ios/Hybrid Objects/Outputs/HybridCameraFrameOutput.swift
|
|
1948
|
+
@@ -60,8 +60,10 @@ final class HybridCameraFrameOutput: HybridCameraFrameOutputSpec, NativeCameraOu
|
|
1949
|
+
// If the pipeline stalls, drop frames to avoid blowing up RAM
|
|
1950
|
+
output.alwaysDiscardsLateVideoFrames = options.dropFramesWhileBusy
|
|
1951
|
+
// JS configures the video resolution, we don't want to downscale here by default.
|
|
1952
|
+
+#if !os(macOS)
|
|
1953
|
+
output.automaticallyConfiguresOutputBufferDimensions = false
|
|
1954
|
+
- if #available(iOS 26.0, *), output.isDeferredStartSupported {
|
|
1955
|
+
+#endif
|
|
1956
|
+
+ if #available(iOS 26.0, macOS 26.0, *), output.isDeferredStartSupported {
|
|
1957
|
+
// Deferred start allows the Session to delay this output's startup in favor
|
|
1958
|
+
// of preview-related outputs to make preview appear faster.
|
|
1959
|
+
output.isDeferredStartEnabled = options.allowDeferredStart
|
|
1960
|
+
@@ -71,10 +73,14 @@ final class HybridCameraFrameOutput: HybridCameraFrameOutputSpec, NativeCameraOu
|
|
1961
|
+
// and `targetResolution` to `.any` (to not participate in resolution negotiations).
|
|
1962
|
+
// If `allowBufferResizing` is false, we don't set `.videoSettings` ("native" resolution), and reflect our
|
|
1963
|
+
// target resolution via `targetResolution` to participate in resolution negotiations.
|
|
1964
|
+
+#if os(macOS)
|
|
1965
|
+
+
|
|
1966
|
+
+#else
|
|
1967
|
+
if #available(iOS 17.0, *), options.enablePreviewSizedOutputBuffers {
|
|
1968
|
+
output.deliversPreviewSizedOutputBuffers = true
|
|
1969
|
+
}
|
|
1970
|
+
- if #available(iOS 26.0, *) {
|
|
1971
|
+
+#endif
|
|
1972
|
+
+ if #available(iOS 26.0, macOS 26.0, *) {
|
|
1973
|
+
// We don't need HDR metadata, as that's only useful for encoders.
|
|
1974
|
+
output.preservesDynamicHDRMetadata = false
|
|
1975
|
+
}
|
|
1976
|
+
@@ -93,12 +99,16 @@ final class HybridCameraFrameOutput: HybridCameraFrameOutputSpec, NativeCameraOu
|
|
1977
|
+
try? connection.setOrientation(outputOrientation)
|
|
1978
|
+
try? connection.setMirrorMode(config.mirrorMode)
|
|
1979
|
+
}
|
|
1980
|
+
+#if os(macOS)
|
|
1981
|
+
+
|
|
1982
|
+
+#else
|
|
1983
|
+
if options.enableCameraMatrixDelivery {
|
|
1984
|
+
// Pipeline should deliver camera matrix (via attachment on `CMSampleBuffer`)
|
|
1985
|
+
if connection.isCameraIntrinsicMatrixDeliverySupported {
|
|
1986
|
+
connection.isCameraIntrinsicMatrixDeliveryEnabled = true
|
|
1987
|
+
}
|
|
1988
|
+
}
|
|
1989
|
+
+#endif
|
|
1990
|
+
}
|
|
1991
|
+
|
|
1992
|
+
private func videoSettingsForPixelFormat(_ targetPixelFormat: TargetVideoPixelFormat) -> [String:
|
|
1993
|
+
diff --git a/ios/Hybrid Objects/Outputs/HybridCameraObjectOutput.swift b/ios/Hybrid Objects/Outputs/HybridCameraObjectOutput.swift
|
|
1994
|
+
index 9e9270a..f9ff425 100644
|
|
1995
|
+
--- a/ios/Hybrid Objects/Outputs/HybridCameraObjectOutput.swift
|
|
1996
|
+
+++ b/ios/Hybrid Objects/Outputs/HybridCameraObjectOutput.swift
|
|
1997
|
+
@@ -1,3 +1,4 @@
|
|
1998
|
+
+#if !os(macOS)
|
|
1999
|
+
///
|
|
2000
|
+
/// HybridCameraObjectOutput.swift
|
|
2001
|
+
/// VisionCamera
|
|
2002
|
+
@@ -82,3 +83,5 @@ final class HybridCameraObjectOutput: HybridCameraObjectOutputSpec, NativeCamera
|
|
2003
|
+
}
|
|
2004
|
+
}
|
|
2005
|
+
}
|
|
2006
|
+
+
|
|
2007
|
+
+#endif
|
|
2008
|
+
diff --git a/ios/Hybrid Objects/Outputs/HybridCameraOutputSynchronizer.swift b/ios/Hybrid Objects/Outputs/HybridCameraOutputSynchronizer.swift
|
|
2009
|
+
index ba07982..b69d560 100644
|
|
2010
|
+
--- a/ios/Hybrid Objects/Outputs/HybridCameraOutputSynchronizer.swift
|
|
2011
|
+
+++ b/ios/Hybrid Objects/Outputs/HybridCameraOutputSynchronizer.swift
|
|
2012
|
+
@@ -1,3 +1,4 @@
|
|
2013
|
+
+#if !os(macOS)
|
|
2014
|
+
///
|
|
2015
|
+
/// HybridCameraDepthFrameOutput.swift
|
|
2016
|
+
/// VisionCamera
|
|
2017
|
+
@@ -91,3 +92,5 @@ extension SynchronizedDataFrame {
|
|
2018
|
+
}
|
|
2019
|
+
}
|
|
2020
|
+
}
|
|
2021
|
+
+
|
|
2022
|
+
+#endif
|
|
2023
|
+
diff --git a/ios/Hybrid Objects/Outputs/HybridCameraPhotoOutput.swift b/ios/Hybrid Objects/Outputs/HybridCameraPhotoOutput.swift
|
|
2024
|
+
index e5249f2..3b20de6 100644
|
|
2025
|
+
--- a/ios/Hybrid Objects/Outputs/HybridCameraPhotoOutput.swift
|
|
2026
|
+
+++ b/ios/Hybrid Objects/Outputs/HybridCameraPhotoOutput.swift
|
|
2027
|
+
@@ -18,11 +18,19 @@ final class HybridCameraPhotoOutput: HybridCameraPhotoOutputSpec, NativeCameraOu
|
|
2028
|
+
let output: AVCapturePhotoOutput
|
|
2029
|
+
|
|
2030
|
+
var supportsDepthDataDelivery: Bool {
|
|
2031
|
+
+#if os(macOS)
|
|
2032
|
+
+ return false
|
|
2033
|
+
+#else
|
|
2034
|
+
return output.isDepthDataDeliverySupported
|
|
2035
|
+
+#endif
|
|
2036
|
+
}
|
|
2037
|
+
|
|
2038
|
+
var supportsCameraCalibrationDataDelivery: Bool {
|
|
2039
|
+
+#if os(macOS)
|
|
2040
|
+
+ return false
|
|
2041
|
+
+#else
|
|
2042
|
+
return output.isCameraCalibrationDataDeliverySupported
|
|
2043
|
+
+#endif
|
|
2044
|
+
}
|
|
2045
|
+
var outputOrientation: CameraOrientation = .up {
|
|
2046
|
+
didSet {
|
|
2047
|
+
@@ -38,11 +46,15 @@ final class HybridCameraPhotoOutput: HybridCameraPhotoOutputSpec, NativeCameraOu
|
|
2048
|
+
let dims = output.maxPhotoDimensions
|
|
2049
|
+
return Size(width: Double(dims.width), height: Double(dims.height))
|
|
2050
|
+
}
|
|
2051
|
+
+#if os(macOS)
|
|
2052
|
+
+ return nil
|
|
2053
|
+
+#else
|
|
2054
|
+
guard let device = output.connections.first?.deviceInput?.device else {
|
|
2055
|
+
return nil
|
|
2056
|
+
}
|
|
2057
|
+
let dims = device.activeFormat.highResolutionStillImageDimensions
|
|
2058
|
+
return Size(width: Double(dims.width), height: Double(dims.height))
|
|
2059
|
+
+#endif
|
|
2060
|
+
}
|
|
2061
|
+
|
|
2062
|
+
var streamType: StreamType = .photo
|
|
2063
|
+
@@ -57,6 +69,9 @@ final class HybridCameraPhotoOutput: HybridCameraPhotoOutputSpec, NativeCameraOu
|
|
2064
|
+
|
|
2065
|
+
output.maxPhotoQualityPrioritization = options.qualityPrioritization.toAVQualityPrioritization()
|
|
2066
|
+
|
|
2067
|
+
+#if os(macOS)
|
|
2068
|
+
+
|
|
2069
|
+
+#else
|
|
2070
|
+
if options.containerFormat == .dng {
|
|
2071
|
+
// If we capture RAW photos, try using Apple ProRAW. If not, Bayer14 RAW will be used.
|
|
2072
|
+
output.isAppleProRAWEnabled = output.isAppleProRAWSupported
|
|
2073
|
+
@@ -69,6 +84,7 @@ final class HybridCameraPhotoOutput: HybridCameraPhotoOutputSpec, NativeCameraOu
|
|
2074
|
+
output.isCameraSensorOrientationCompensationEnabled = false
|
|
2075
|
+
}
|
|
2076
|
+
|
|
2077
|
+
+#endif
|
|
2078
|
+
// Prepare the default Photo Settings to make the pipeline ready - some things (like flashMode)
|
|
2079
|
+
// might change on a per-capture basis, but containerFormat and preview size is already known
|
|
2080
|
+
// and can be prepared already.
|
|
2081
|
+
@@ -112,7 +128,9 @@ final class HybridCameraPhotoOutput: HybridCameraPhotoOutputSpec, NativeCameraOu
|
|
2082
|
+
location: nil)
|
|
2083
|
+
let avSettings = try settings.toAVCapturePhotoSettings(for: output, withOptions: options)
|
|
2084
|
+
// Prepare the AVCapturePhotoOutput for those settings so coming up captures are faster
|
|
2085
|
+
+#if !os(macOS)
|
|
2086
|
+
self.output.setPreparedPhotoSettingsArray([avSettings])
|
|
2087
|
+
+#endif
|
|
2088
|
+
}
|
|
2089
|
+
|
|
2090
|
+
func capturePhoto(
|
|
2091
|
+
@@ -135,17 +153,23 @@ final class HybridCameraPhotoOutput: HybridCameraPhotoOutputSpec, NativeCameraOu
|
|
2092
|
+
if self.options.previewImageTargetSize != nil,
|
|
2093
|
+
let onPreviewImageAvailable = callbacks.onPreviewImageAvailable
|
|
2094
|
+
{
|
|
2095
|
+
+#if !os(macOS)
|
|
2096
|
+
Task {
|
|
2097
|
+
// On a separate Thread, start decoding the Preview Image Data
|
|
2098
|
+
- guard let cgPreviewImage = photo.previewCGImageRepresentation() else {
|
|
2099
|
+
+ guard let cgPreviewImage = photo.previewCGImageRepresentation() as CGImage? else {
|
|
2100
|
+
return
|
|
2101
|
+
}
|
|
2102
|
+
// Wrap the `CGImage` in a `HybridUIImage` and notify the callback
|
|
2103
|
+
+ #if os(macOS)
|
|
2104
|
+
+ let image = HybridCGImage(cgImage: cgPreviewImage)
|
|
2105
|
+
+ #else
|
|
2106
|
+
let uiImage = UIImage(
|
|
2107
|
+
cgImage: cgPreviewImage, scale: 1.0, orientation: metadata.uiImageOrientation)
|
|
2108
|
+
let image = HybridUIImage(uiImage: uiImage)
|
|
2109
|
+
+ #endif
|
|
2110
|
+
onPreviewImageAvailable(image)
|
|
2111
|
+
}
|
|
2112
|
+
+#endif
|
|
2113
|
+
}
|
|
2114
|
+
// 2. Wrap the `AVCapturePhoto` in a `HybridPhoto` and resolve the Promise
|
|
2115
|
+
let image = HybridPhoto(
|
|
2116
|
+
@@ -189,6 +213,10 @@ final class HybridCameraPhotoOutput: HybridCameraPhotoOutputSpec, NativeCameraOu
|
|
2117
|
+
let captureSettings = try settings.map {
|
|
2118
|
+
try $0.toAVCapturePhotoSettings(for: self.output, withOptions: self.options)
|
|
2119
|
+
}
|
|
2120
|
+
+#if os(macOS)
|
|
2121
|
+
+ // macOS has no preparation API; validate settings synchronously.
|
|
2122
|
+
+ promise.resolve()
|
|
2123
|
+
+#else
|
|
2124
|
+
self.output.setPreparedPhotoSettingsArray(captureSettings) { prepared, error in
|
|
2125
|
+
if let error {
|
|
2126
|
+
promise.reject(withError: error)
|
|
2127
|
+
@@ -200,6 +228,7 @@ final class HybridCameraPhotoOutput: HybridCameraPhotoOutputSpec, NativeCameraOu
|
|
2128
|
+
}
|
|
2129
|
+
}
|
|
2130
|
+
}
|
|
2131
|
+
+#endif
|
|
2132
|
+
return promise
|
|
2133
|
+
}
|
|
2134
|
+
}
|
|
2135
|
+
diff --git a/ios/Hybrid Objects/Outputs/HybridCameraPreviewOutput.swift b/ios/Hybrid Objects/Outputs/HybridCameraPreviewOutput.swift
|
|
2136
|
+
index 9f63db3..056646e 100644
|
|
2137
|
+
--- a/ios/Hybrid Objects/Outputs/HybridCameraPreviewOutput.swift
|
|
2138
|
+
+++ b/ios/Hybrid Objects/Outputs/HybridCameraPreviewOutput.swift
|
|
2139
|
+
@@ -6,6 +6,9 @@
|
|
2140
|
+
|
|
2141
|
+
import AVFoundation
|
|
2142
|
+
import Foundation
|
|
2143
|
+
+#if os(macOS)
|
|
2144
|
+
+import AppKit
|
|
2145
|
+
+#endif
|
|
2146
|
+
import NitroModules
|
|
2147
|
+
|
|
2148
|
+
final class HybridCameraPreviewOutput: HybridCameraPreviewOutputSpec, NativePreviewViewOutput {
|
|
2149
|
+
@@ -38,8 +41,13 @@ final class HybridCameraPreviewOutput: HybridCameraPreviewOutputSpec, NativePrev
|
|
2150
|
+
/// because the view might not even be laid out yet at the time
|
|
2151
|
+
/// the resolution negotiation runs.
|
|
2152
|
+
var targetResolution: ResolutionRule {
|
|
2153
|
+
+ #if os(macOS)
|
|
2154
|
+
+ let screenSizeDp = CGSize(width: 1920, height: 1080)
|
|
2155
|
+
+ let pixelRatio: CGFloat = 1
|
|
2156
|
+
+ #else
|
|
2157
|
+
let screenSizeDp = UIScreen.main.bounds.size
|
|
2158
|
+
let pixelRatio = UIScreen.main.scale
|
|
2159
|
+
+ #endif
|
|
2160
|
+
let screenSizePx = Size(
|
|
2161
|
+
width: screenSizeDp.width * pixelRatio,
|
|
2162
|
+
height: screenSizeDp.height * pixelRatio)
|
|
2163
|
+
diff --git a/ios/Hybrid Objects/Outputs/HybridCameraVideoFrameOutput.swift b/ios/Hybrid Objects/Outputs/HybridCameraVideoFrameOutput.swift
|
|
2164
|
+
index ddf5895..d713b9c 100644
|
|
2165
|
+
--- a/ios/Hybrid Objects/Outputs/HybridCameraVideoFrameOutput.swift
|
|
2166
|
+
+++ b/ios/Hybrid Objects/Outputs/HybridCameraVideoFrameOutput.swift
|
|
2167
|
+
@@ -62,8 +62,10 @@ final class HybridCameraVideoFrameOutput: HybridCameraVideoOutputSpec, NativeCam
|
|
2168
|
+
// Queue up Frames if there are any hiccups in AVAssetWriter so we don't lose Frames.
|
|
2169
|
+
output.alwaysDiscardsLateVideoFrames = false
|
|
2170
|
+
// JS configures the video resolution, we don't want to downscale here.
|
|
2171
|
+
+#if !os(macOS)
|
|
2172
|
+
output.automaticallyConfiguresOutputBufferDimensions = false
|
|
2173
|
+
- if #available(iOS 26.0, *) {
|
|
2174
|
+
+#endif
|
|
2175
|
+
+ if #available(iOS 26.0, macOS 26.0, *) {
|
|
2176
|
+
// We only use this output for recording, allowing it to start deferred makes the session start faster.
|
|
2177
|
+
if output.isDeferredStartSupported {
|
|
2178
|
+
output.isDeferredStartEnabled = true
|
|
2179
|
+
@@ -141,7 +143,7 @@ final class HybridCameraVideoFrameOutput: HybridCameraVideoOutputSpec, NativeCam
|
|
2180
|
+
try recorder.initializeVideoTrack(withSettings: videoSettings)
|
|
2181
|
+
|
|
2182
|
+
// 3. Set video metadata
|
|
2183
|
+
- if #available(iOS 26.0, *) {
|
|
2184
|
+
+ if #available(iOS 26.0, macOS 26.0, *) {
|
|
2185
|
+
// 2.1.a. Set video timescale if available. This avoids audio/video sync-drift in super long videos.
|
|
2186
|
+
recorder.setTimescale(self.output.recommendedMediaTimeScaleForAssetWriter)
|
|
2187
|
+
let codec = self.getCurrentVideoCodec()
|
|
2188
|
+
diff --git a/ios/Hybrid Objects/Outputs/HybridCameraVideoOutput.swift b/ios/Hybrid Objects/Outputs/HybridCameraVideoOutput.swift
|
|
2189
|
+
index 0353452..32cc690 100644
|
|
2190
|
+
--- a/ios/Hybrid Objects/Outputs/HybridCameraVideoOutput.swift
|
|
2191
|
+
+++ b/ios/Hybrid Objects/Outputs/HybridCameraVideoOutput.swift
|
|
2192
|
+
@@ -71,6 +71,9 @@ final class HybridCameraVideoOutput: HybridCameraVideoOutputSpec, NativeCameraOu
|
|
2193
|
+
}
|
|
2194
|
+
|
|
2195
|
+
func getSupportedVideoCodecs() throws -> [VideoCodec] {
|
|
2196
|
+
+#if os(macOS)
|
|
2197
|
+
+ throw RuntimeError.error(withMessage: "Movie output codec enumeration is not available on macOS")
|
|
2198
|
+
+#else
|
|
2199
|
+
guard output.connection(with: .video) != nil else {
|
|
2200
|
+
throw RuntimeError.error(
|
|
2201
|
+
withMessage:
|
|
2202
|
+
@@ -78,9 +81,13 @@ final class HybridCameraVideoOutput: HybridCameraVideoOutputSpec, NativeCameraOu
|
|
2203
|
+
)
|
|
2204
|
+
}
|
|
2205
|
+
return output.availableVideoCodecTypes.map { VideoCodec(avCodec: $0) }
|
|
2206
|
+
+#endif
|
|
2207
|
+
}
|
|
2208
|
+
|
|
2209
|
+
func setOutputSettings(settings: VideoOutputSettings) -> Promise<Void> {
|
|
2210
|
+
+#if os(macOS)
|
|
2211
|
+
+ return .rejected(withError: RuntimeError.error(withMessage: "Custom movie encoding settings are not supported by this macOS prototype"))
|
|
2212
|
+
+#else
|
|
2213
|
+
return Promise.parallel(queue) {
|
|
2214
|
+
guard let connection = self.output.connection(with: .video) else {
|
|
2215
|
+
throw RuntimeError.error(
|
|
2216
|
+
@@ -118,6 +125,7 @@ final class HybridCameraVideoOutput: HybridCameraVideoOutputSpec, NativeCameraOu
|
|
2217
|
+
}
|
|
2218
|
+
}
|
|
2219
|
+
}
|
|
2220
|
+
+#endif
|
|
2221
|
+
}
|
|
2222
|
+
|
|
2223
|
+
func createRecorder(settings: RecorderSettings) -> Promise<any HybridRecorderSpec> {
|
|
2224
|
+
@@ -145,6 +153,7 @@ final class HybridCameraVideoOutput: HybridCameraVideoOutputSpec, NativeCameraOu
|
|
2225
|
+
}
|
|
2226
|
+
|
|
2227
|
+
private func setOutputSettings(bitRate: Int, codec: AVVideoCodecType, for connection: AVCaptureConnection) {
|
|
2228
|
+
+#if !os(macOS)
|
|
2229
|
+
let supportedKeys = output.supportedOutputSettingsKeys(for: connection)
|
|
2230
|
+
guard supportedKeys.contains(AVVideoCompressionPropertiesKey) else {
|
|
2231
|
+
logger.error(
|
|
2232
|
+
@@ -152,6 +161,7 @@ final class HybridCameraVideoOutput: HybridCameraVideoOutputSpec, NativeCameraOu
|
|
2233
|
+
return
|
|
2234
|
+
}
|
|
2235
|
+
|
|
2236
|
+
+#endif
|
|
2237
|
+
let settings: [String: Any] = [
|
|
2238
|
+
AVVideoCodecKey: codec,
|
|
2239
|
+
AVVideoCompressionPropertiesKey: [
|
|
2240
|
+
diff --git a/ios/Hybrid Objects/Utils/HybridFrameConverter.swift b/ios/Hybrid Objects/Utils/HybridFrameConverter.swift
|
|
2241
|
+
index 803fd8c..265f780 100644
|
|
2242
|
+
--- a/ios/Hybrid Objects/Utils/HybridFrameConverter.swift
|
|
2243
|
+
+++ b/ios/Hybrid Objects/Utils/HybridFrameConverter.swift
|
|
2244
|
+
@@ -19,7 +19,11 @@ final class HybridFrameConverter: HybridFrameConverterSpec {
|
|
2245
|
+
}
|
|
2246
|
+
let uiOrientation = frame.metadata.uiImageOrientation
|
|
2247
|
+
let uiImage = try sampleBuffer.toUIImage(orientation: uiOrientation)
|
|
2248
|
+
+ #if os(macOS)
|
|
2249
|
+
+ return HybridCGImage(cgImage: uiImage)
|
|
2250
|
+
+ #else
|
|
2251
|
+
return HybridUIImage(uiImage: uiImage)
|
|
2252
|
+
+ #endif
|
|
2253
|
+
}
|
|
2254
|
+
|
|
2255
|
+
func convertFrameToImageAsync(frame: any HybridFrameSpec) throws -> Promise<any HybridImageSpec> {
|
|
2256
|
+
@@ -37,7 +41,11 @@ final class HybridFrameConverter: HybridFrameConverterSpec {
|
|
2257
|
+
}
|
|
2258
|
+
let uiOrientation = depth.metadata.uiImageOrientation
|
|
2259
|
+
let uiImage = try depthData.toUIImage(orientation: uiOrientation)
|
|
2260
|
+
+ #if os(macOS)
|
|
2261
|
+
+ return HybridCGImage(cgImage: uiImage)
|
|
2262
|
+
+ #else
|
|
2263
|
+
return HybridUIImage(uiImage: uiImage)
|
|
2264
|
+
+ #endif
|
|
2265
|
+
}
|
|
2266
|
+
|
|
2267
|
+
func convertDepthToImageAsync(depth: any HybridDepthSpec) throws -> Promise<any HybridImageSpec> {
|
|
2268
|
+
diff --git a/ios/Hybrid Objects/Views/HybridFrameRendererView.swift b/ios/Hybrid Objects/Views/HybridFrameRendererView.swift
|
|
2269
|
+
index d113a56..8d2a753 100644
|
|
2270
|
+
--- a/ios/Hybrid Objects/Views/HybridFrameRendererView.swift
|
|
2271
|
+
+++ b/ios/Hybrid Objects/Views/HybridFrameRendererView.swift
|
|
2272
|
+
@@ -9,7 +9,7 @@ import Foundation
|
|
2273
|
+
import NitroModules
|
|
2274
|
+
|
|
2275
|
+
final class HybridFrameRendererView: HybridFrameRendererViewSpec {
|
|
2276
|
+
- var view: UIView = AutoLayerResizingView()
|
|
2277
|
+
+ var view = AutoLayerResizingView()
|
|
2278
|
+
var renderer: (any HybridFrameRendererSpec)? {
|
|
2279
|
+
didSet {
|
|
2280
|
+
updateRendererLayer()
|
|
2281
|
+
@@ -18,9 +18,9 @@ final class HybridFrameRendererView: HybridFrameRendererViewSpec {
|
|
2282
|
+
|
|
2283
|
+
private func updateRendererLayer() {
|
|
2284
|
+
DispatchQueue.main.async {
|
|
2285
|
+
- self.view.layer.sublayers?.removeAll()
|
|
2286
|
+
+ self.view.contentLayer.sublayers?.removeAll()
|
|
2287
|
+
if let renderer = self.renderer as? any NativeFrameRenderer {
|
|
2288
|
+
- self.view.layer.addSublayer(renderer.layer)
|
|
2289
|
+
+ self.view.contentLayer.addSublayer(renderer.layer)
|
|
2290
|
+
renderer.layer.frame = self.view.bounds
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
diff --git a/ios/Hybrid Objects/Views/HybridPreviewView.swift b/ios/Hybrid Objects/Views/HybridPreviewView.swift
|
|
2294
|
+
index 00d7532..722a5cf 100644
|
|
2295
|
+
--- a/ios/Hybrid Objects/Views/HybridPreviewView.swift
|
|
2296
|
+
+++ b/ios/Hybrid Objects/Views/HybridPreviewView.swift
|
|
2297
|
+
@@ -10,7 +10,7 @@ import NitroImage
|
|
2298
|
+
import NitroModules
|
|
2299
|
+
|
|
2300
|
+
final class HybridPreviewView: HybridPreviewViewSpec {
|
|
2301
|
+
- var view: UIView = AutoLayerResizingView()
|
|
2302
|
+
+ var view = AutoLayerResizingView()
|
|
2303
|
+
var previewOutput: (any HybridCameraPreviewOutputSpec)? {
|
|
2304
|
+
didSet {
|
|
2305
|
+
updatePreviewLayer()
|
|
2306
|
+
@@ -86,6 +86,9 @@ final class HybridPreviewView: HybridPreviewViewSpec {
|
|
2307
|
+
func convertScannedObjectCoordinatesToViewCoordinates(
|
|
2308
|
+
scannedObject: (any HybridScannedObjectSpec)
|
|
2309
|
+
) throws -> (any HybridScannedObjectSpec) {
|
|
2310
|
+
+#if os(macOS)
|
|
2311
|
+
+ throw RuntimeError.error(withMessage: "Object scanning is not supported on macOS")
|
|
2312
|
+
+#else
|
|
2313
|
+
guard let previewLayer else {
|
|
2314
|
+
throw RuntimeError.error(
|
|
2315
|
+
withMessage:
|
|
2316
|
+
@@ -100,6 +103,7 @@ final class HybridPreviewView: HybridPreviewViewSpec {
|
|
2317
|
+
withMessage: "Failed to transform the Scanned Object's coordinates into view coordinates!")
|
|
2318
|
+
}
|
|
2319
|
+
return HybridCameraObjectOutput.createHybridScannedObject(from: transformedObject)
|
|
2320
|
+
+#endif
|
|
2321
|
+
}
|
|
2322
|
+
|
|
2323
|
+
func createMeteringPoint(viewX: Double, viewY: Double, size: Double?) throws
|
|
2324
|
+
@@ -127,10 +131,10 @@ final class HybridPreviewView: HybridPreviewViewSpec {
|
|
2325
|
+
DispatchQueue.main.async {
|
|
2326
|
+
if let previewLayer = self.previewLayer {
|
|
2327
|
+
// Remove all sublayers that are not our AVCaptureVideoPreviewLayer
|
|
2328
|
+
- self.view.layer.sublayers?.removeAll { $0 != previewLayer }
|
|
2329
|
+
- if self.view.layer.sublayers?.contains(previewLayer) != true {
|
|
2330
|
+
+ self.view.contentLayer.sublayers?.removeAll { $0 != previewLayer }
|
|
2331
|
+
+ if self.view.contentLayer.sublayers?.contains(previewLayer) != true {
|
|
2332
|
+
// If we don't have the preview layer, we add it here
|
|
2333
|
+
- self.view.layer.addSublayer(previewLayer)
|
|
2334
|
+
+ self.view.contentLayer.addSublayer(previewLayer)
|
|
2335
|
+
}
|
|
2336
|
+
previewLayer.frame = self.view.bounds
|
|
2337
|
+
|
|
2338
|
+
@@ -138,6 +142,7 @@ final class HybridPreviewView: HybridPreviewViewSpec {
|
|
2339
|
+
let resizeMode = self.resizeMode ?? .cover
|
|
2340
|
+
previewLayer.videoGravity = resizeMode.toAVLayerVideoGravity()
|
|
2341
|
+
|
|
2342
|
+
+#if !os(macOS)
|
|
2343
|
+
// Add listener to `isPreviewing`
|
|
2344
|
+
self.isPreviewingObserver = previewLayer.observe(
|
|
2345
|
+
\.isPreviewing,
|
|
2346
|
+
@@ -156,9 +161,10 @@ final class HybridPreviewView: HybridPreviewViewSpec {
|
|
2347
|
+
self.onPreviewStopped?()
|
|
2348
|
+
}
|
|
2349
|
+
})
|
|
2350
|
+
+#endif
|
|
2351
|
+
} else {
|
|
2352
|
+
// Remove all sublayers (including the AVCaptureVideoPreviewLayer)
|
|
2353
|
+
- self.view.layer.sublayers?.removeAll()
|
|
2354
|
+
+ self.view.contentLayer.sublayers?.removeAll()
|
|
2355
|
+
// Remove listener to `isPreviewing`
|
|
2356
|
+
self.onPreviewStopped?()
|
|
2357
|
+
self.isPreviewingObserver = nil
|
|
2358
|
+
diff --git a/ios/Public/MediaSampleMetadata.swift b/ios/Public/MediaSampleMetadata.swift
|
|
2359
|
+
index 4917891..b6af8b6 100644
|
|
2360
|
+
--- a/ios/Public/MediaSampleMetadata.swift
|
|
2361
|
+
+++ b/ios/Public/MediaSampleMetadata.swift
|
|
2362
|
+
@@ -8,7 +8,11 @@
|
|
2363
|
+
import AVFoundation
|
|
2364
|
+
import Foundation
|
|
2365
|
+
import NitroModules
|
|
2366
|
+
+#if os(macOS)
|
|
2367
|
+
+import ImageIO
|
|
2368
|
+
+#else
|
|
2369
|
+
import UIKit
|
|
2370
|
+
+#endif
|
|
2371
|
+
|
|
2372
|
+
public struct MediaSampleMetadata {
|
|
2373
|
+
let timestamp: CMTime
|
|
2374
|
+
@@ -32,7 +36,11 @@ public struct MediaSampleMetadata {
|
|
2375
|
+
self.isMirrored = isMirrored
|
|
2376
|
+
}
|
|
2377
|
+
|
|
2378
|
+
+ #if os(macOS)
|
|
2379
|
+
+ var uiImageOrientation: CGImagePropertyOrientation { orientation.toImageOrientation(isMirrored: isMirrored) }
|
|
2380
|
+
+ #else
|
|
2381
|
+
var uiImageOrientation: UIImage.Orientation {
|
|
2382
|
+
return orientation.toUIImageOrientation(isMirrored: isMirrored)
|
|
2383
|
+
}
|
|
2384
|
+
+ #endif
|
|
2385
|
+
}
|
|
2386
|
+
diff --git a/ios/Public/NativeGestureController.swift b/ios/Public/NativeGestureController.swift
|
|
2387
|
+
index 7ff5397..ddbf76d 100644
|
|
2388
|
+
--- a/ios/Public/NativeGestureController.swift
|
|
2389
|
+
+++ b/ios/Public/NativeGestureController.swift
|
|
2390
|
+
@@ -6,10 +6,16 @@
|
|
2391
|
+
//
|
|
2392
|
+
|
|
2393
|
+
import Foundation
|
|
2394
|
+
+#if os(macOS)
|
|
2395
|
+
+import AppKit
|
|
2396
|
+
+public typealias CameraGestureRecognizer = NSGestureRecognizer
|
|
2397
|
+
+#else
|
|
2398
|
+
import UIKit
|
|
2399
|
+
+public typealias CameraGestureRecognizer = UIGestureRecognizer
|
|
2400
|
+
+#endif
|
|
2401
|
+
|
|
2402
|
+
public protocol NativeGestureController: AnyObject {
|
|
2403
|
+
- associatedtype GestureRecognizer: UIGestureRecognizer
|
|
2404
|
+
+ associatedtype GestureRecognizer: CameraGestureRecognizer
|
|
2405
|
+
|
|
2406
|
+
/**
|
|
2407
|
+
* Gets the underlying `UIGestureRecognizer`.
|
|
2408
|
+
diff --git a/ios/Utils/CameraPlatformImage.swift b/ios/Utils/CameraPlatformImage.swift
|
|
2409
|
+
new file mode 100644
|
|
2410
|
+
index 0000000..ff64ce6
|
|
2411
|
+
--- /dev/null
|
|
2412
|
+
+++ b/ios/Utils/CameraPlatformImage.swift
|
|
2413
|
+
@@ -0,0 +1,17 @@
|
|
2414
|
+
+import AVFoundation
|
|
2415
|
+
+import CoreImage
|
|
2416
|
+
+import Foundation
|
|
2417
|
+
+import NitroImage
|
|
2418
|
+
+#if os(macOS)
|
|
2419
|
+
+import ImageIO
|
|
2420
|
+
+typealias CameraImageOrientation = CGImagePropertyOrientation
|
|
2421
|
+
+typealias CameraPlatformImage = CGImage
|
|
2422
|
+
+extension CameraOrientation {
|
|
2423
|
+
+ func toImageOrientation(isMirrored: Bool) -> CGImagePropertyOrientation {
|
|
2424
|
+
+ switch self { case .up: return isMirrored ? .upMirrored : .up; case .down: return isMirrored ? .downMirrored : .down; case .left: return isMirrored ? .leftMirrored : .left; case .right: return isMirrored ? .rightMirrored : .right }
|
|
2425
|
+
+ }
|
|
2426
|
+
+}
|
|
2427
|
+
+#else
|
|
2428
|
+
+typealias CameraImageOrientation = UIImage.Orientation
|
|
2429
|
+
+typealias CameraPlatformImage = UIImage
|
|
2430
|
+
+#endif
|
|
2431
|
+
diff --git a/ios/Utils/LazyLockablePixelBuffer.swift b/ios/Utils/LazyLockablePixelBuffer.swift
|
|
2432
|
+
index 89434ed..bfa5edc 100644
|
|
2433
|
+
--- a/ios/Utils/LazyLockablePixelBuffer.swift
|
|
2434
|
+
+++ b/ios/Utils/LazyLockablePixelBuffer.swift
|
|
2435
|
+
@@ -8,7 +8,7 @@
|
|
2436
|
+
import AVFoundation
|
|
2437
|
+
import Foundation
|
|
2438
|
+
import NitroModules
|
|
2439
|
+
-import UIKit
|
|
2440
|
+
+import CoreGraphics
|
|
2441
|
+
|
|
2442
|
+
protocol LazyLockableBuffer: AnyObject {
|
|
2443
|
+
var isLocked: Bool { get set }
|
|
2444
|
+
diff --git a/ios/Utils/SubjectAreaMonitor.swift b/ios/Utils/SubjectAreaMonitor.swift
|
|
2445
|
+
index 3be310e..4eb4938 100644
|
|
2446
|
+
--- a/ios/Utils/SubjectAreaMonitor.swift
|
|
2447
|
+
+++ b/ios/Utils/SubjectAreaMonitor.swift
|
|
2448
|
+
@@ -1,3 +1,4 @@
|
|
2449
|
+
+#if !os(macOS)
|
|
2450
|
+
//
|
|
2451
|
+
// SubjectAreaMonitor.swift
|
|
2452
|
+
// VisionCamera
|
|
2453
|
+
@@ -89,3 +90,5 @@ enum SubjectAreaMonitor {
|
|
2454
|
+
}
|
|
2455
|
+
}
|
|
2456
|
+
}
|
|
2457
|
+
+
|
|
2458
|
+
+#endif
|
|
2459
|
+
diff --git a/ios/Views/AutoLayerResizingView.swift b/ios/Views/AutoLayerResizingView.swift
|
|
2460
|
+
index 65f6dd9..566bdbc 100644
|
|
2461
|
+
--- a/ios/Views/AutoLayerResizingView.swift
|
|
2462
|
+
+++ b/ios/Views/AutoLayerResizingView.swift
|
|
2463
|
+
@@ -1,3 +1,14 @@
|
|
2464
|
+
+#if os(macOS)
|
|
2465
|
+
+import AppKit
|
|
2466
|
+
+import QuartzCore
|
|
2467
|
+
+final class AutoLayerResizingView: NSView {
|
|
2468
|
+
+ override var isFlipped: Bool { true }
|
|
2469
|
+
+ var contentLayer: CALayer { layer! }
|
|
2470
|
+
+ override init(frame: NSRect) { super.init(frame: frame); wantsLayer = true }
|
|
2471
|
+
+ required init?(coder: NSCoder) { super.init(coder: coder); wantsLayer = true }
|
|
2472
|
+
+ override func layout() { super.layout(); contentLayer.sublayers?.forEach { $0.frame = bounds } }
|
|
2473
|
+
+}
|
|
2474
|
+
+#else
|
|
2475
|
+
//
|
|
2476
|
+
// AutoLayerResizingView.swift
|
|
2477
|
+
// VisionCamera
|
|
2478
|
+
@@ -10,6 +21,7 @@ import Foundation
|
|
2479
|
+
|
|
2480
|
+
/// A view that auto-resizes its sublayers each time
|
|
2481
|
+
final class AutoLayerResizingView: UIView {
|
|
2482
|
+
+ var contentLayer: CALayer { layer }
|
|
2483
|
+
override func layoutSubviews() {
|
|
2484
|
+
super.layoutSubviews()
|
|
2485
|
+
layer.sublayers?.forEach { layer in
|
|
2486
|
+
@@ -17,3 +29,5 @@ final class AutoLayerResizingView: UIView {
|
|
2487
|
+
}
|
|
2488
|
+
}
|
|
2489
|
+
}
|
|
2490
|
+
+
|
|
2491
|
+
+#endif
|
|
2492
|
+
diff --git a/nitrogen/generated/ios/VisionCamera+autolinking.rb b/nitrogen/generated/ios/VisionCamera+autolinking.rb
|
|
2493
|
+
index c1a02e7..518a0f8 100644
|
|
2494
|
+
--- a/nitrogen/generated/ios/VisionCamera+autolinking.rb
|
|
2495
|
+
+++ b/nitrogen/generated/ios/VisionCamera+autolinking.rb
|
|
2496
|
+
@@ -54,6 +54,8 @@ def add_nitrogen_files(spec)
|
|
2497
|
+
"CLANG_CXX_LANGUAGE_STANDARD" => "c++20",
|
|
2498
|
+
# Enables C++ <-> Swift interop (by default it's only ObjC)
|
|
2499
|
+
"SWIFT_OBJC_INTEROP_MODE" => "objcxx",
|
|
2500
|
+
+ # Nitro's Fabric-only templates must not enter its Swift umbrella.
|
|
2501
|
+
+ "HEADER_SEARCH_PATHS" => "$(inherited) $(PODS_ROOT)/Headers/Private",
|
|
2502
|
+
# Enables stricter modular headers
|
|
2503
|
+
"DEFINES_MODULE" => "YES",
|
|
2504
|
+
# Disable auto-generated ObjC header for Swift (Static linkage on Xcode 26.4 breaks here)
|
|
2505
|
+
diff --git a/nitrogen/generated/ios/c++/views/HybridFrameRendererViewComponent.mm b/nitrogen/generated/ios/c++/views/HybridFrameRendererViewComponent.mm
|
|
2506
|
+
index 3b6dda4..361f192 100644
|
|
2507
|
+
--- a/nitrogen/generated/ios/c++/views/HybridFrameRendererViewComponent.mm
|
|
2508
|
+
+++ b/nitrogen/generated/ios/c++/views/HybridFrameRendererViewComponent.mm
|
|
2509
|
+
@@ -12,7 +12,12 @@
|
|
2510
|
+
#import <React/RCTComponentViewFactory.h>
|
|
2511
|
+
#import <React/UIView+ComponentViewProtocol.h>
|
|
2512
|
+
#import <NitroModules/NitroDefines.hpp>
|
|
2513
|
+
+#import <TargetConditionals.h>
|
|
2514
|
+
+#if TARGET_OS_OSX
|
|
2515
|
+
+#import <AppKit/AppKit.h>
|
|
2516
|
+
+#else
|
|
2517
|
+
#import <UIKit/UIKit.h>
|
|
2518
|
+
+#endif
|
|
2519
|
+
|
|
2520
|
+
#import "HybridFrameRendererViewSpecSwift.hpp"
|
|
2521
|
+
#import "VisionCamera-Swift-Cxx-Umbrella.hpp"
|
|
2522
|
+
@@ -65,12 +70,21 @@ - (void) updateView {
|
|
2523
|
+
|
|
2524
|
+
// 2. Get UIView*
|
|
2525
|
+
void* viewUnsafe = swiftPart.getView();
|
|
2526
|
+
+ #if TARGET_OS_OSX
|
|
2527
|
+
+ NSView* view = (__bridge_transfer NSView*) viewUnsafe;
|
|
2528
|
+
+#else
|
|
2529
|
+
UIView* view = (__bridge_transfer UIView*) viewUnsafe;
|
|
2530
|
+
+#endif
|
|
2531
|
+
|
|
2532
|
+
// 3. Update RCTViewComponentView's [contentView]
|
|
2533
|
+
[self setContentView:view];
|
|
2534
|
+
}
|
|
2535
|
+
|
|
2536
|
+
+// RN < 0.82 does not call invalidate for views which opt out of recycling.
|
|
2537
|
+
+- (void) dealloc {
|
|
2538
|
+
+ if (_hybridView != nullptr) [self notifyOnDropView];
|
|
2539
|
+
+}
|
|
2540
|
+
+
|
|
2541
|
+
- (void) notifyOnDropView {
|
|
2542
|
+
// A recycled component can later be invalidated. Notify only once per mount.
|
|
2543
|
+
if (_didDropView) {
|
|
2544
|
+
diff --git a/nitrogen/generated/ios/c++/views/HybridPreviewViewComponent.mm b/nitrogen/generated/ios/c++/views/HybridPreviewViewComponent.mm
|
|
2545
|
+
index 3251d7b..ce0265b 100644
|
|
2546
|
+
--- a/nitrogen/generated/ios/c++/views/HybridPreviewViewComponent.mm
|
|
2547
|
+
+++ b/nitrogen/generated/ios/c++/views/HybridPreviewViewComponent.mm
|
|
2548
|
+
@@ -12,7 +12,12 @@
|
|
2549
|
+
#import <React/RCTComponentViewFactory.h>
|
|
2550
|
+
#import <React/UIView+ComponentViewProtocol.h>
|
|
2551
|
+
#import <NitroModules/NitroDefines.hpp>
|
|
2552
|
+
+#import <TargetConditionals.h>
|
|
2553
|
+
+#if TARGET_OS_OSX
|
|
2554
|
+
+#import <AppKit/AppKit.h>
|
|
2555
|
+
+#else
|
|
2556
|
+
#import <UIKit/UIKit.h>
|
|
2557
|
+
+#endif
|
|
2558
|
+
|
|
2559
|
+
#import "HybridPreviewViewSpecSwift.hpp"
|
|
2560
|
+
#import "VisionCamera-Swift-Cxx-Umbrella.hpp"
|
|
2561
|
+
@@ -65,12 +70,21 @@ - (void) updateView {
|
|
2562
|
+
|
|
2563
|
+
// 2. Get UIView*
|
|
2564
|
+
void* viewUnsafe = swiftPart.getView();
|
|
2565
|
+
+ #if TARGET_OS_OSX
|
|
2566
|
+
+ NSView* view = (__bridge_transfer NSView*) viewUnsafe;
|
|
2567
|
+
+#else
|
|
2568
|
+
UIView* view = (__bridge_transfer UIView*) viewUnsafe;
|
|
2569
|
+
+#endif
|
|
2570
|
+
|
|
2571
|
+
// 3. Update RCTViewComponentView's [contentView]
|
|
2572
|
+
[self setContentView:view];
|
|
2573
|
+
}
|
|
2574
|
+
|
|
2575
|
+
+// RN < 0.82 does not call invalidate for views which opt out of recycling.
|
|
2576
|
+
+- (void) dealloc {
|
|
2577
|
+
+ if (_hybridView != nullptr) [self notifyOnDropView];
|
|
2578
|
+
+}
|
|
2579
|
+
+
|
|
2580
|
+
- (void) notifyOnDropView {
|
|
2581
|
+
// A recycled component can later be invalidated. Notify only once per mount.
|
|
2582
|
+
if (_didDropView) {
|
|
2583
|
+
diff --git a/nitrogen/generated/shared/c++/views/HybridFrameRendererViewComponent.cpp b/nitrogen/generated/shared/c++/views/HybridFrameRendererViewComponent.cpp
|
|
2584
|
+
index 5255f8e..ca364f4 100644
|
|
2585
|
+
--- a/nitrogen/generated/shared/c++/views/HybridFrameRendererViewComponent.cpp
|
|
2586
|
+
+++ b/nitrogen/generated/shared/c++/views/HybridFrameRendererViewComponent.cpp
|
|
2587
|
+
@@ -7,6 +7,9 @@
|
|
2588
|
+
|
|
2589
|
+
#include "HybridFrameRendererViewComponent.hpp"
|
|
2590
|
+
|
|
2591
|
+
+#if defined(__APPLE__)
|
|
2592
|
+
+#include <TargetConditionals.h>
|
|
2593
|
+
+#endif
|
|
2594
|
+
#include <NitroModules/NitroHash.hpp>
|
|
2595
|
+
#include <NitroModules/ReactProp.hpp>
|
|
2596
|
+
|
|
2597
|
+
@@ -19,7 +22,11 @@ namespace margelo::nitro::camera::views {
|
|
2598
|
+
HybridFrameRendererViewProps::HybridFrameRendererViewProps(const react::PropsParserContext& context,
|
|
2599
|
+
const HybridFrameRendererViewProps& sourceProps,
|
|
2600
|
+
const react::RawProps& rawProps):
|
|
2601
|
+
- react::ViewProps(context, sourceProps, rawProps, filterObjectKeys),
|
|
2602
|
+
+ react::ViewProps(context, sourceProps, rawProps
|
|
2603
|
+
+ #if !TARGET_OS_OSX
|
|
2604
|
+
+ , filterObjectKeys
|
|
2605
|
+
+ #endif
|
|
2606
|
+
+ ),
|
|
2607
|
+
renderer(nitro::ReactProp<std::optional<std::shared_ptr<HybridFrameRendererSpec>>>::fromRawValue("FrameRendererView", "renderer", rawProps, sourceProps.renderer)),
|
|
2608
|
+
hybridRef(nitro::ReactProp<std::optional<std::function<void(const std::shared_ptr<HybridFrameRendererViewSpec>& /* ref */)>>>::fromRawValue("FrameRendererView", "hybridRef", rawProps, sourceProps.hybridRef)) { }
|
|
2609
|
+
|
|
2610
|
+
diff --git a/nitrogen/generated/shared/c++/views/HybridPreviewViewComponent.cpp b/nitrogen/generated/shared/c++/views/HybridPreviewViewComponent.cpp
|
|
2611
|
+
index 7e6f73b..e5ac262 100644
|
|
2612
|
+
--- a/nitrogen/generated/shared/c++/views/HybridPreviewViewComponent.cpp
|
|
2613
|
+
+++ b/nitrogen/generated/shared/c++/views/HybridPreviewViewComponent.cpp
|
|
2614
|
+
@@ -7,6 +7,9 @@
|
|
2615
|
+
|
|
2616
|
+
#include "HybridPreviewViewComponent.hpp"
|
|
2617
|
+
|
|
2618
|
+
+#if defined(__APPLE__)
|
|
2619
|
+
+#include <TargetConditionals.h>
|
|
2620
|
+
+#endif
|
|
2621
|
+
#include <NitroModules/NitroHash.hpp>
|
|
2622
|
+
#include <NitroModules/ReactProp.hpp>
|
|
2623
|
+
|
|
2624
|
+
@@ -19,7 +22,11 @@ namespace margelo::nitro::camera::views {
|
|
2625
|
+
HybridPreviewViewProps::HybridPreviewViewProps(const react::PropsParserContext& context,
|
|
2626
|
+
const HybridPreviewViewProps& sourceProps,
|
|
2627
|
+
const react::RawProps& rawProps):
|
|
2628
|
+
- react::ViewProps(context, sourceProps, rawProps, filterObjectKeys),
|
|
2629
|
+
+ react::ViewProps(context, sourceProps, rawProps
|
|
2630
|
+
+ #if !TARGET_OS_OSX
|
|
2631
|
+
+ , filterObjectKeys
|
|
2632
|
+
+ #endif
|
|
2633
|
+
+ ),
|
|
2634
|
+
previewOutput(nitro::ReactProp<std::optional<std::shared_ptr<HybridCameraPreviewOutputSpec>>>::fromRawValue("PreviewView", "previewOutput", rawProps, sourceProps.previewOutput)),
|
|
2635
|
+
resizeMode(nitro::ReactProp<std::optional<PreviewResizeMode>>::fromRawValue("PreviewView", "resizeMode", rawProps, sourceProps.resizeMode)),
|
|
2636
|
+
implementationMode(nitro::ReactProp<std::optional<PreviewImplementationMode>>::fromRawValue("PreviewView", "implementationMode", rawProps, sourceProps.implementationMode)),
|
|
2637
|
+
diff --git a/package.json b/package.json
|
|
2638
|
+
index 341aa56..306f6a1 100644
|
|
2639
|
+
--- a/package.json
|
|
2640
|
+
+++ b/package.json
|
|
2641
|
+
@@ -27,7 +27,8 @@
|
|
2642
|
+
"cpp/**/*.cpp",
|
|
2643
|
+
"nitro.json",
|
|
2644
|
+
"*.podspec",
|
|
2645
|
+
- "README.md"
|
|
2646
|
+
+ "README.md",
|
|
2647
|
+
+ "macos/**/*.swift"
|
|
2648
|
+
],
|
|
2649
|
+
"scripts": {
|
|
2650
|
+
"typecheck": "tsc --noEmit",
|
|
2651
|
+
diff --git a/react-native.config.js b/react-native.config.js
|
|
2652
|
+
index 3fdf8ea..e2ad767 100644
|
|
2653
|
+
--- a/react-native.config.js
|
|
2654
|
+
+++ b/react-native.config.js
|
|
2655
|
+
@@ -7,6 +7,7 @@ module.exports = {
|
|
2656
|
+
* @type {import('@react-native-community/cli-types').IOSDependencyParams}
|
|
2657
|
+
*/
|
|
2658
|
+
ios: {},
|
|
2659
|
+
+ macos: { podspecPath: __dirname + "/VisionCamera.podspec" },
|
|
2660
|
+
/**
|
|
2661
|
+
* @type {import('@react-native-community/cli-types').AndroidDependencyParams}
|
|
2662
|
+
*/
|