diff --git a/README.md b/README.md index 79131085af..7690677dd7 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,23 @@ +# LightOS fork for finer focus control + +To run the example app: + +``` +cd package +yarn install +cd example +yarn install +run android +------ +run start +``` + +# Building a new release for LightOS + +We have a script in this repo so that the package builds after being installed - see `scripts/prepare-package.js`. + +After making changes to this repo, update the version in `package.json` and create a new tag - you can then update the tag in /LightOS/package.json + diff --git a/package.json b/package.json index 12416a855d..9de929da99 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-vision-camera", - "version": "4.6.19", + "version": "4.6.20", "description": "A powerful, high-performance React Native Camera library.", "main": "lib/commonjs/index", "module": "lib/module/index", diff --git a/package/.gitignore b/package/.gitignore index a225286e04..7aaca6a0cf 100644 --- a/package/.gitignore +++ b/package/.gitignore @@ -74,7 +74,6 @@ yarn-error.log !.yarn/versions # TypeScript output -/lib /example/lib # Gems diff --git a/package/android/build.gradle b/package/android/build.gradle index 0f78c9a6ba..886eb7f500 100644 --- a/package/android/build.gradle +++ b/package/android/build.gradle @@ -100,6 +100,16 @@ android { namespace "com.mrousavy.camera" } + flavorDimensions "version" + productFlavors { + "lp2" { + dimension "version" + } + "lp3" { + dimension "version" + } + } + // Used to override the NDK path/version on internal CI or by allowing // users to customize the NDK path/version from their root project (e.g. for M1 support) if (rootProject.hasProperty("ndkPath")) { @@ -193,6 +203,9 @@ dependencies { // Some Coroutines extension functions implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1" + // Include light jar files + lp3Implementation files('../../../../framework_all/lp3.jar') + if (enableCodeScanner) { // User enabled code-scanner, so we bundle the 2.4 MB model in the app. implementation 'com.google.mlkit:barcode-scanning:17.3.0' @@ -242,3 +255,13 @@ tasks.configureEach { task -> task.dependsOn(deleteCmakeCache) } } + +gradle.projectsEvaluated { + tasks.withType(JavaCompile) { task -> + def isLp3 = task.toString().indexOf("Lp3") != -1 + if (!isLp3) { + return; + } + options.compilerArgs.add("-Xbootclasspath/p:${rootDir}/../../framework_all/lp3.jar") + } +} diff --git a/package/android/src/lp2/java/com/mrousavy/camera/core/CameraSession+EIS.kt b/package/android/src/lp2/java/com/mrousavy/camera/core/CameraSession+EIS.kt new file mode 100644 index 0000000000..867a1754d1 --- /dev/null +++ b/package/android/src/lp2/java/com/mrousavy/camera/core/CameraSession+EIS.kt @@ -0,0 +1,5 @@ +package com.mrousavy.camera.core + +fun CameraSession.setEISMode(newMode: String) { + return +} diff --git a/package/android/src/lp3/java/com/mrousavy/camera/core/CameraSession+EIS.kt b/package/android/src/lp3/java/com/mrousavy/camera/core/CameraSession+EIS.kt new file mode 100644 index 0000000000..94adfdbf78 --- /dev/null +++ b/package/android/src/lp3/java/com/mrousavy/camera/core/CameraSession+EIS.kt @@ -0,0 +1,15 @@ +package com.mrousavy.camera.core + +import android.os.SystemProperties +import android.util.Log + +fun CameraSession.setEISMode(newMode: String) { + try { + Log.i(CameraSession.TAG, "EIS: changed from: " + SystemProperties.get("persist.vendor.camera.enableEIS")); + SystemProperties.set("persist.vendor.camera.enableEIS", newMode); + Log.i(CameraSession.TAG, "EIS: changed to: " + SystemProperties.get("persist.vendor.camera.enableEIS")); + } + catch (e: Exception) { + Log.e(CameraSession.TAG, "Unable to set EIS mode ${e.message}") + } +} diff --git a/package/android/src/main/java/com/mrousavy/camera/core/CameraConfiguration.kt b/package/android/src/main/java/com/mrousavy/camera/core/CameraConfiguration.kt index 745ed9d214..c3c81e0c3f 100644 --- a/package/android/src/main/java/com/mrousavy/camera/core/CameraConfiguration.kt +++ b/package/android/src/main/java/com/mrousavy/camera/core/CameraConfiguration.kt @@ -47,7 +47,7 @@ data class CameraConfiguration( ) { // Output types, those need to be comparable data class CodeScanner(val codeTypes: List) - data class Photo(val isMirrored: Boolean, val enableHdr: Boolean, val photoQualityBalance: QualityBalance) + data class Photo(val isMirrored: Boolean, val enableHdr: Boolean, val photoQualityBalance: QualityBalance, val jpegCompressionQuality: Int) data class Video(val isMirrored: Boolean, val enableHdr: Boolean) data class FrameProcessor(val isMirrored: Boolean, val pixelFormat: PixelFormat) data class Audio(val nothing: Unit) diff --git a/package/android/src/main/java/com/mrousavy/camera/core/CameraSession+Configuration.kt b/package/android/src/main/java/com/mrousavy/camera/core/CameraSession+Configuration.kt index 381e9481b5..a5a966bd19 100644 --- a/package/android/src/main/java/com/mrousavy/camera/core/CameraSession+Configuration.kt +++ b/package/android/src/main/java/com/mrousavy/camera/core/CameraSession+Configuration.kt @@ -20,9 +20,12 @@ import androidx.camera.video.VideoCapture import androidx.lifecycle.Lifecycle import com.mrousavy.camera.core.extensions.* import com.mrousavy.camera.core.types.CameraDeviceFormat +import com.mrousavy.camera.core.types.QualityBalance import com.mrousavy.camera.core.types.Torch import com.mrousavy.camera.core.types.VideoStabilizationMode import kotlin.math.roundToInt +import androidx.camera.camera2.interop.Camera2Interop +import android.hardware.camera2.CaptureRequest private fun assertFormatRequirement( propName: String, @@ -91,8 +94,22 @@ internal fun CameraSession.configureOutputs(configuration: CameraConfiguration) if (photoConfig != null) { Log.i(CameraSession.TAG, "Creating Photo output...") val photo = ImageCapture.Builder().also { photo -> + // Set exposure metering based on SnapdragonCamera + val camera2Extender = Camera2Interop.Extender(photo) + camera2Extender.setCaptureRequestOption( + CaptureRequest.Key( + "org.codeaurora.qcamera3.exposure_metering.exposure_metering_mode", + Integer::class.java + ), + Integer(1) + ) + // Configure Photo Output photo.setCaptureMode(photoConfig.config.photoQualityBalance.toCaptureMode()) + Log.i("LP3_PROFILER", "Mode: ${photoConfig.config.photoQualityBalance}") + Log.i("LP3_PROFILER", "Quality: ${photoConfig.config.jpegCompressionQuality}") + Log.i(LP3_TAG, "Setting jpeg compression to ${photoConfig.config.jpegCompressionQuality}") + photo.setJpegQuality(photoConfig.config.jpegCompressionQuality) if (format != null) { Log.i(CameraSession.TAG, "Photo size: ${format.photoSize}") val resolutionSelector = ResolutionSelector.Builder() @@ -107,6 +124,34 @@ internal fun CameraSession.configureOutputs(configuration: CameraConfiguration) photoOutput = null } + /* + * LP3: The aim with this was to provide a second Photo UseCase which would be used for when we lock the focus + * This use case is set to aim for fastest shutter speed + * Unfortunately, we can't bind two Photo UseCases at once and so this fails to initialize + * And if we don't bind it, photo taking fails + * Trying to dynamically rebind which UseCase is being used at runtime also seems to be full of pitfalls and complications + * Rebinding takes time and passing in the appropriate + // 2.1 Image Capture with Locked Focus + if (photoConfig != null) { + Log.i(CameraSession.TAG, "Creating Photo output...") + val photo = ImageCapture.Builder().also { photo -> + // Configure Photo Output + photo.setCaptureMode(QualityBalance.BALANCED.toCaptureMode()) + if (format != null) { + Log.i(CameraSession.TAG, "Photo size: ${format.photoSize}") + val resolutionSelector = ResolutionSelector.Builder() + .forSize(format.photoSize) + .setAllowedResolutionMode(ResolutionSelector.PREFER_CAPTURE_RATE_OVER_HIGHER_RESOLUTION) + .build() + photo.setResolutionSelector(resolutionSelector) + } + }.build() + photoOutputLockedFocus = photo + } else { + photoOutputLockedFocus = null + } + */ + // 3. Video Capture if (videoConfig != null) { Log.i(CameraSession.TAG, "Creating Video output...") @@ -129,6 +174,16 @@ internal fun CameraSession.configureOutputs(configuration: CameraConfiguration) } val video = VideoCapture.Builder(recorder).also { video -> + // Set exposure metering based on SnapdragonCamera + val camera2Extender = Camera2Interop.Extender(video) + camera2Extender.setCaptureRequestOption( + CaptureRequest.Key( + "org.codeaurora.qcamera3.exposure_metering.exposure_metering_mode", + Integer::class.java + ), + Integer(1) + ) + // Configure Video Output if (videoConfig.config.isMirrored) { video.setMirrorMode(MirrorMode.MIRROR_MODE_ON) @@ -219,6 +274,7 @@ internal suspend fun CameraSession.configureCamera(provider: ProcessCameraProvid checkCameraPermission() // Outputs + // val useCases = listOfNotNull(previewOutput, photoOutput, photoOutputLockedFocus, videoOutput, frameProcessorOutput, codeScannerOutput) val useCases = listOfNotNull(previewOutput, photoOutput, videoOutput, frameProcessorOutput, codeScannerOutput) if (useCases.isEmpty()) { throw NoOutputsError() diff --git a/package/android/src/main/java/com/mrousavy/camera/core/CameraSession+FocusExposureControl.kt b/package/android/src/main/java/com/mrousavy/camera/core/CameraSession+FocusExposureControl.kt new file mode 100644 index 0000000000..39aa0ea3d1 --- /dev/null +++ b/package/android/src/main/java/com/mrousavy/camera/core/CameraSession+FocusExposureControl.kt @@ -0,0 +1,93 @@ +package com.mrousavy.camera.core + +import android.annotation.SuppressLint +import android.util.Log +import androidx.camera.core.CameraControl +import android.hardware.camera2.CaptureRequest +import androidx.annotation.OptIn +import androidx.camera.camera2.interop.CaptureRequestOptions +import androidx.camera.core.FocusMeteringAction +import androidx.camera.core.MeteringPoint +import com.mrousavy.camera.core.extensions.await +import androidx.camera.camera2.interop.Camera2CameraControl +import androidx.camera.camera2.interop.ExperimentalCamera2Interop + +// There are a few different focus control modes available in the docs: +// https://developer.android.com/reference/android/hardware/camera2/CaptureRequest#CONTROL_AF_MODE +// The relevant to us are: +// - CONTROL_AF_MODE_AUTO - allows us to manually tell the camera where to focus +// - CONTROL_AF_MODE_CONTINUOUS_PICTURE - tells the camera to continuously autofocus +@OptIn(ExperimentalCamera2Interop::class) +fun CameraSession.setFocusMode(mode: Int) { + val camera = camera ?: throw CameraNotReadyError() + + Camera2CameraControl.from(camera.cameraControl).setCaptureRequestOptions( + CaptureRequestOptions.Builder().setCaptureRequestOption(CaptureRequest.CONTROL_AF_MODE, mode).build() + ) + Log.i(CameraSession.TAG, "LP3: set focus mode: $mode") +} + +/* + * LP3: Trying to rebind the photoOutput at runtime. + * Pulling up all the necessary context such as the cameraSelector doesn't seem possible without rebuilding it + * This approach also seems vulnerable to race conditions since we can't easily guarantee it being executed before + * a photo request is made as this is async +suspend fun CameraSession.bindNormal() { + val provider = cameraProvider.await(mainExecutor) + + provider.unbind(currentlyBoundPhotoOutput) + provider.bindToLifecycle(list, cameraSelector, listOf(photoOutputLockedFocus)) + currentlyBoundPhotoOutput = photoOutputLockedFocus +}*/ + +// For exposure we can just set it to be locked +@OptIn(ExperimentalCamera2Interop::class) +fun CameraSession.setExposureLock(setLocked: Boolean) { + val camera = camera ?: throw CameraNotReadyError() + + Camera2CameraControl.from(camera.cameraControl).setCaptureRequestOptions( + CaptureRequestOptions.Builder().setCaptureRequestOption(CaptureRequest.CONTROL_AE_LOCK, setLocked).build() + ) +} + +fun CameraSession.freeFocusAndExposure() { + + setExposureLock(false) + setFocusMode(CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE) +} + +@SuppressLint("RestrictedApi") +suspend fun CameraSession.lockFocusAndExposureToPoint(meteringPoint: MeteringPoint): Boolean { + val camera = camera ?: throw CameraNotReadyError() + + setFocusMode(CaptureRequest.CONTROL_AF_MODE_AUTO) + + // So it seems like using, disableAutoCancel might actually be the solution + // Hidden in this obscure SO post + // https://stackoverflow.com/questions/66633338/disable-autofocus-in-android-camerax-camera-2 + val action = FocusMeteringAction.Builder(meteringPoint, + FocusMeteringAction.FLAG_AF or FocusMeteringAction.FLAG_AE).apply { + disableAutoCancel() + }.build() + + if (!camera.cameraInfo.isFocusMeteringSupported(action)) { + throw FocusNotSupportedError() + } + + try { + Log.i(CameraSession.TAG, "LP3: Focusing to ${action.meteringPointsAf.joinToString { "(${it.x}, ${it.y})" }}...") + val future = camera.cameraControl.startFocusAndMetering(action) + val result = future.await(CameraQueues.cameraExecutor) + if (result.isFocusSuccessful) { + Log.i(CameraSession.TAG, "LP3: Focused successfully") + setExposureLock(true) + return true + } else { + Log.i(CameraSession.TAG, "LP3: Failed to focus") + freeFocusAndExposure() + } + } catch (e: CameraControl.OperationCanceledException) { + throw FocusCanceledError() + } + return false +} diff --git a/package/android/src/main/java/com/mrousavy/camera/core/CameraSession+Photo.kt b/package/android/src/main/java/com/mrousavy/camera/core/CameraSession+Photo.kt index 6ef88b2d11..f9976c21fa 100644 --- a/package/android/src/main/java/com/mrousavy/camera/core/CameraSession+Photo.kt +++ b/package/android/src/main/java/com/mrousavy/camera/core/CameraSession+Photo.kt @@ -1,44 +1,209 @@ package com.mrousavy.camera.core +import android.annotation.SuppressLint import android.media.AudioManager -import com.mrousavy.camera.core.extensions.takePicture import com.mrousavy.camera.core.types.Flash import com.mrousavy.camera.core.types.Orientation import com.mrousavy.camera.core.types.TakePhotoOptions -import com.mrousavy.camera.core.utils.FileUtils -suspend fun CameraSession.takePhoto(options: TakePhotoOptions): Photo { +import androidx.camera.core.ImageCapture.OnImageCapturedCallback +import androidx.camera.core.ImageCaptureException +import androidx.camera.core.ImageProxy +import android.os.Looper +import android.util.Log +import android.provider.MediaStore +import android.content.ContentValues +import android.content.Context +import android.content.Intent +import android.graphics.Bitmap +import java.io.File +import android.os.Environment +import java.io.FileOutputStream +import androidx.camera.core.ImageCapture.Metadata +import androidx.camera.core.internal.compat.workaround.ExifRotationAvailability +import android.media.MediaActionSound +import androidx.exifinterface.media.ExifInterface +import com.mrousavy.camera.core.types.ShutterType +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.suspendCancellableCoroutine +import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException +import kotlin.random.Random + +fun isOnMainThread() = Looper.myLooper() == Looper.getMainLooper() +fun ensureBackgroundThread(callback: () -> Unit) { + if (isOnMainThread()) { + Thread { + callback() + }.start() + } else { + callback() + } +} + +fun removeStubFile(file: File) { + if (file.exists()) { + file.delete() + } +} +fun broadcastImageProcessingCompleteIntent(context: Context, file: File) { + val intent = Intent("com.mrousavy.camera.PHOTO_PROCESSED") + intent.putExtra("filename", file.absolutePath) + context.sendBroadcast(intent) +} + +val TAG = "CameraSession+Photo" + +suspend fun CameraSession.takePhoto(options: TakePhotoOptions): Photo = suspendCancellableCoroutine { continuation -> + + photosBeingProcessed++ + val camera = camera ?: throw CameraNotReadyError() val configuration = configuration ?: throw CameraNotReadyError() val photoConfig = configuration.photo as? CameraConfiguration.Output.Enabled ?: throw PhotoNotEnabledError() val photoOutput = photoOutput ?: throw PhotoNotEnabledError() - // Flash if (options.flash != Flash.OFF && !camera.cameraInfo.hasFlashUnit()) { throw FlashUnavailableError() } photoOutput.flashMode = options.flash.toFlashMode() - // Shutter sound + val enableShutterSound = options.enableShutterSound && !audioManager.isSilent - // isMirrored (EXIF) + val shutterSound = if (enableShutterSound) MediaActionSound() else null + shutterSound?.load(MediaActionSound.SHUTTER_CLICK) + val isMirrored = photoConfig.config.isMirrored + val metadata = Metadata().apply { + isReversedHorizontal = isMirrored + } - // Shoot photo! - val photoFile = photoOutput.takePicture( - options.file.file, - isMirrored, - enableShutterSound, - metadataProvider, - callback, - CameraQueues.cameraExecutor + val startTime = System.currentTimeMillis() + var profilerOutput = "" + Log.i(LP3_TAG, "starting take") + + val directory = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "Light") + if (!directory.exists()) { + directory.mkdirs() + } + val capturedAt = System.currentTimeMillis(); + val filename = "img_${capturedAt}.jpg" + + val outputFile = File(directory, filename) + val returnVal = Photo( + outputFile.absolutePath, + 0, + 0, + Orientation.fromSurfaceRotation(photoOutput.targetRotation), + isMirrored ) + Log.i(LP3_TAG, "stub file created") + + + + photoOutput.takePicture(CameraQueues.cameraExecutor, object : OnImageCapturedCallback() { + override fun onCaptureStarted() { + Log.i(LP3_TAG, "onCaptureStarted called") + profilerOutput += "${(System.currentTimeMillis() - startTime)/1000.0}, " + + // We need to wait for this callback before unlocking the focus lock + // Otherwise we risk the camera having time to refocus before shooting + freeFocusAndExposure(); + + outputFile.createNewFile() + // Add the temp image to MediaStore so it appears in the gallery + val values = ContentValues().apply { + put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg") + put(MediaStore.Images.Media.DATE_ADDED, capturedAt / 1000) + put(MediaStore.Images.Media.DATE_TAKEN, capturedAt) + put(MediaStore.Images.Media.DATA, outputFile.absolutePath) + } + + // we want to return the contentUri so the frontend can handle it through the mediastore + val mediaUri = context.contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values) + returnVal.path = mediaUri.toString() + + callback.onShutter(ShutterType.PHOTO) + + if (options.resolveOnCaptureStarted && continuation.isActive) { + // resolve the promise + continuation.resume(returnVal) + } + } + + // doesn't get called on LP3 + override fun onCaptureProcessProgressed(progress: Int) { + Log.i(LP3_TAG, "onCaptureProcessProgressed called: $progress") + } + // doesn't get called on LP3 + override fun onPostviewBitmapAvailable(bitmap: Bitmap) { + Log.i(LP3_TAG, "onPostviewBitmapAvailable called") + } + @SuppressLint("RestrictedApi") + override fun onCaptureSuccess(image: ImageProxy) { + Log.i(LP3_TAG, "onCaptureSuccess called") + profilerOutput += "${(System.currentTimeMillis() - startTime)/1000.0}, " + ensureBackgroundThread { + image.use { + if (enableShutterSound) { + shutterSound?.play(MediaActionSound.SHUTTER_CLICK) + } + + try { + Log.i(LP3_TAG, "Writing image") + val buffer = image.planes[0].buffer + val bytes = ByteArray(buffer.remaining()).apply { + buffer.get(this) + } + FileOutputStream(outputFile).use { output -> + output.write(bytes) + } + Log.i(LP3_TAG, "Image saved successfully to: ${outputFile.absolutePath}, height: ${image.height}, width: ${image.width}, format: ${image.format}") + + val exif = ExifInterface(outputFile.absolutePath) + // Overwrite the original orientation if the quirk exists. + if (!ExifRotationAvailability().shouldUseExifOrientation(image)) { + exif.rotate(image.imageInfo.rotationDegrees) + } + if (metadata.isReversedHorizontal) { + exif.flipHorizontally() + } + if (metadata.isReversedVertical) { + exif.flipVertically() + } + exif.saveAttributes(); + Log.i(LP3_TAG, "EXIF data saved") + } catch (e: Exception) { + Log.e(LP3_TAG, "Error saving image: ${e.message}") + removeStubFile(outputFile) + e.printStackTrace() + } + + broadcastImageProcessingCompleteIntent(context, outputFile) + photosBeingProcessed-- + + profilerOutput += "${(System.currentTimeMillis() - startTime)/1000.0}, " + // output will be timings of onCaptureStarted, onCaptureSuccess, processing completion + Log.i("LP3_PROFILER", profilerOutput) + + if (!options.resolveOnCaptureStarted && continuation.isActive) { + // resolve the promise + continuation.resume(returnVal) + } + } + } + } + override fun onError(exception: ImageCaptureException) { - // Parse resulting photo (EXIF data) - val size = FileUtils.getImageSize(photoFile.uri.path) - val rotation = photoOutput.targetRotation - val orientation = Orientation.fromSurfaceRotation(rotation) + broadcastImageProcessingCompleteIntent(context, outputFile) + removeStubFile(outputFile) + photosBeingProcessed-- - return Photo(photoFile.uri.path, size.width, size.height, orientation, isMirrored) + Log.d(TAG, "onError: ${exception.message}") + if (continuation.isActive) { + continuation.resumeWithException(exception) + } + } + }) } private val AudioManager.isSilent: Boolean diff --git a/package/android/src/main/java/com/mrousavy/camera/core/CameraSession+Video.kt b/package/android/src/main/java/com/mrousavy/camera/core/CameraSession+Video.kt index fcc54b8e95..884787816a 100644 --- a/package/android/src/main/java/com/mrousavy/camera/core/CameraSession+Video.kt +++ b/package/android/src/main/java/com/mrousavy/camera/core/CameraSession+Video.kt @@ -10,6 +10,11 @@ import androidx.camera.video.VideoRecordEvent import com.mrousavy.camera.core.extensions.getCameraError import com.mrousavy.camera.core.types.RecordVideoOptions import com.mrousavy.camera.core.types.Video +import android.provider.Settings +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch @OptIn(ExperimentalPersistentRecording::class) @SuppressLint("MissingPermission", "RestrictedApi") @@ -23,6 +28,9 @@ fun CameraSession.startRecording( if (recording != null) throw RecordingInProgressError() val videoOutput = videoOutput ?: throw VideoNotEnabledError() + // Force EIS to be in the right mode in case an edge case has left it at 2 + restoreEndOfStream() + // Create output video file val outputOptions = FileOutputOptions.Builder(options.file.file).also { outputOptions -> metadataProvider.location?.let { location -> @@ -69,6 +77,7 @@ fun CameraSession.startRecording( if (error.wasVideoRecorded) { Log.e(CameraSession.TAG, "Video Recorder encountered an error, but the video was recorded anyways.", error) } else { + restoreEndOfStream() Log.e(CameraSession.TAG, "Video Recorder encountered a fatal error!", error) onError(error) return@start @@ -82,6 +91,14 @@ fun CameraSession.startRecording( val size = videoOutput.attachedSurfaceResolution ?: Size(0, 0) val video = Video(path, durationMs, size) callback(video) + val coroutineScope = CoroutineScope(Dispatchers.Main) + coroutineScope.launch { + Log.i(CameraSession.TAG, "starting delay") + // A small timeout is required or the camera freezes. + // Not sure on the minimum but 1/4s seems to work consistently + delay(250); + restoreEndOfStream(); + } } } } @@ -90,6 +107,7 @@ fun CameraSession.startRecording( fun CameraSession.stopRecording() { val recording = recording ?: throw NoRecordingInProgressError() + startEndOfStream() recording.stop() this.recording = null } @@ -108,3 +126,11 @@ fun CameraSession.resumeRecording() { val recording = recording ?: throw NoRecordingInProgressError() recording.resume() } + +fun CameraSession.startEndOfStream() { + setEISMode("2"); +} + +fun CameraSession.restoreEndOfStream() { + setEISMode(Settings.Global.getString(context.contentResolver, "enable_EIS")); +} diff --git a/package/android/src/main/java/com/mrousavy/camera/core/CameraSession.kt b/package/android/src/main/java/com/mrousavy/camera/core/CameraSession.kt index 862c03a146..c5c3f7b44d 100644 --- a/package/android/src/main/java/com/mrousavy/camera/core/CameraSession.kt +++ b/package/android/src/main/java/com/mrousavy/camera/core/CameraSession.kt @@ -27,9 +27,14 @@ import com.mrousavy.camera.core.types.Orientation import com.mrousavy.camera.core.types.ShutterType import com.mrousavy.camera.core.utils.runOnUiThread import com.mrousavy.camera.frameprocessors.Frame +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers import java.io.Closeable import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking class CameraSession(internal val context: Context, internal val callback: Callback) : Closeable, @@ -38,6 +43,7 @@ class CameraSession(internal val context: Context, internal val callback: Callba companion object { internal const val TAG = "CameraSession" } + internal val LP3_TAG = "LP3_Camera" // Camera Configuration internal var configuration: CameraConfiguration? = null @@ -72,6 +78,9 @@ class CameraSession(internal val context: Context, internal val callback: Callba val outputOrientation: Orientation get() = orientationManager.outputOrientation + // Used to keep prevent the camera being torn down on unmount until all photos are processed + internal var photosBeingProcessed = 0 + init { lifecycleRegistry.currentState = Lifecycle.State.CREATED lifecycle.addObserver(object : LifecycleEventObserver { @@ -83,10 +92,24 @@ class CameraSession(internal val context: Context, internal val callback: Callba override fun close() { Log.i(TAG, "Closing CameraSession...") - isDestroyed = true - orientationManager.stopOrientationUpdates() - runOnUiThread { - lifecycleRegistry.currentState = Lifecycle.State.DESTROYED + Log.i(LP3_TAG, "Closing CameraSession") + val coroutineScope = CoroutineScope(Dispatchers.Main) + coroutineScope.launch { + for (i in 1..10) { + Log.i(LP3_TAG, "photosBeingProcessed: ${photosBeingProcessed}") + if (photosBeingProcessed <= 0) { + break; + } + delay(500) + } + Log.i(LP3_TAG, "No more photos to process") + + isDestroyed = true + orientationManager.stopOrientationUpdates() + runOnUiThread { + lifecycleRegistry.currentState = Lifecycle.State.DESTROYED + } + Log.i(LP3_TAG, "Closed CameraSession") } } diff --git a/package/android/src/main/java/com/mrousavy/camera/core/Photo.kt b/package/android/src/main/java/com/mrousavy/camera/core/Photo.kt index b1353cef05..519d1357e7 100644 --- a/package/android/src/main/java/com/mrousavy/camera/core/Photo.kt +++ b/package/android/src/main/java/com/mrousavy/camera/core/Photo.kt @@ -2,4 +2,4 @@ package com.mrousavy.camera.core import com.mrousavy.camera.core.types.Orientation -data class Photo(val path: String, val width: Int, val height: Int, val orientation: Orientation, val isMirrored: Boolean) +data class Photo(var path: String, val width: Int, val height: Int, val orientation: Orientation, val isMirrored: Boolean) diff --git a/package/android/src/main/java/com/mrousavy/camera/core/types/TakePhotoOptions.kt b/package/android/src/main/java/com/mrousavy/camera/core/types/TakePhotoOptions.kt index 4c99c4b0e5..6421793614 100644 --- a/package/android/src/main/java/com/mrousavy/camera/core/types/TakePhotoOptions.kt +++ b/package/android/src/main/java/com/mrousavy/camera/core/types/TakePhotoOptions.kt @@ -5,16 +5,18 @@ import com.facebook.react.bridge.ReadableMap import com.mrousavy.camera.core.utils.FileUtils import com.mrousavy.camera.core.utils.OutputFile -data class TakePhotoOptions(val file: OutputFile, val flash: Flash, val enableShutterSound: Boolean) { +data class TakePhotoOptions(val file: OutputFile, val flash: Flash, val enableShutterSound: Boolean, val useFastMode: Boolean, val resolveOnCaptureStarted: Boolean) { companion object { fun fromJS(context: Context, map: ReadableMap): TakePhotoOptions { val flash = if (map.hasKey("flash")) Flash.fromUnionValue(map.getString("flash")) else Flash.OFF val enableShutterSound = if (map.hasKey("enableShutterSound")) map.getBoolean("enableShutterSound") else false val directory = if (map.hasKey("path")) FileUtils.getDirectory(map.getString("path")) else context.cacheDir + val useFastMode = if (map.hasKey("useFastMode")) map.getBoolean("useFastMode") else false + val resolveOnCaptureStarted = if (map.hasKey("resolveOnCaptureStarted")) map.getBoolean("resolveOnCaptureStarted") else false val outputFile = OutputFile(context, directory, ".jpg") - return TakePhotoOptions(outputFile, flash, enableShutterSound) + return TakePhotoOptions(outputFile, flash, enableShutterSound, useFastMode, resolveOnCaptureStarted) } } } diff --git a/package/android/src/main/java/com/mrousavy/camera/react/CameraView+FocusExposureControl.kt b/package/android/src/main/java/com/mrousavy/camera/react/CameraView+FocusExposureControl.kt new file mode 100644 index 0000000000..8ca2f28bfa --- /dev/null +++ b/package/android/src/main/java/com/mrousavy/camera/react/CameraView+FocusExposureControl.kt @@ -0,0 +1,24 @@ +package com.mrousavy.camera.react + +import android.content.res.Resources +import com.facebook.react.bridge.ReadableMap +import com.mrousavy.camera.core.FocusRequiresPreviewError +import com.mrousavy.camera.core.lockFocusAndExposureToPoint +import com.mrousavy.camera.core.freeFocusAndExposure +import com.mrousavy.camera.core.utils.runOnUiThreadAndWait + +suspend fun CameraView.lockFocusAndExposureToPoint(pointMap: ReadableMap): Boolean { + val x = pointMap.getDouble("x") + val y = pointMap.getDouble("y") + val previewView = previewView ?: throw FocusRequiresPreviewError() + + val point = runOnUiThreadAndWait { + val dp = Resources.getSystem().displayMetrics.density + previewView.meteringPointFactory.createPoint(x.toFloat() * dp, y.toFloat() * dp) + } + return cameraSession.lockFocusAndExposureToPoint(point) +} + +suspend fun CameraView.freeFocusAndExposure() { + cameraSession.freeFocusAndExposure() +} diff --git a/package/android/src/main/java/com/mrousavy/camera/react/CameraView.kt b/package/android/src/main/java/com/mrousavy/camera/react/CameraView.kt index f0eb5b90de..606fe88896 100644 --- a/package/android/src/main/java/com/mrousavy/camera/react/CameraView.kt +++ b/package/android/src/main/java/com/mrousavy/camera/react/CameraView.kt @@ -78,6 +78,7 @@ class CameraView(context: Context) : // TODO: Use .BALANCED once CameraX fixes it https://issuetracker.google.com/issues/337214687 var photoQualityBalance = QualityBalance.SPEED + var jpegCompressionQuality = 100 var lowLightBoost = false // other props @@ -173,7 +174,7 @@ class CameraView(context: Context) : // Photo if (photo) { - config.photo = CameraConfiguration.Output.Enabled.create(CameraConfiguration.Photo(isMirrored, photoHdr, photoQualityBalance)) + config.photo = CameraConfiguration.Output.Enabled.create(CameraConfiguration.Photo(isMirrored, photoHdr, photoQualityBalance, jpegCompressionQuality)) } else { config.photo = CameraConfiguration.Output.Disabled.create() } diff --git a/package/android/src/main/java/com/mrousavy/camera/react/CameraViewManager.kt b/package/android/src/main/java/com/mrousavy/camera/react/CameraViewManager.kt index d41300e57d..07f2d4ed98 100644 --- a/package/android/src/main/java/com/mrousavy/camera/react/CameraViewManager.kt +++ b/package/android/src/main/java/com/mrousavy/camera/react/CameraViewManager.kt @@ -186,6 +186,15 @@ class CameraViewManager : ViewGroupManager() { } } + @ReactProp(name = "jpegCompressionQuality") + fun setJpegCompressionQuality(view: CameraView, jpegCompressionQuality: Int?) { + if (jpegCompressionQuality != null && jpegCompressionQuality >= 0 && jpegCompressionQuality <= 100) { + view.jpegCompressionQuality = jpegCompressionQuality + } else { + view.jpegCompressionQuality = 100 + } + } + @ReactProp(name = "videoHdr") fun setVideoHdr(view: CameraView, videoHdr: Boolean) { view.videoHdr = videoHdr diff --git a/package/android/src/main/java/com/mrousavy/camera/react/CameraViewModule.kt b/package/android/src/main/java/com/mrousavy/camera/react/CameraViewModule.kt index 7ae420949d..91b29ed3e0 100644 --- a/package/android/src/main/java/com/mrousavy/camera/react/CameraViewModule.kt +++ b/package/android/src/main/java/com/mrousavy/camera/react/CameraViewModule.kt @@ -188,6 +188,27 @@ class CameraViewModule(reactContext: ReactApplicationContext) : ReactContextBase } } + @ReactMethod + fun lockFocusAndExposureToPoint(viewTag: Int, point: ReadableMap, promise: Promise) { + backgroundCoroutineScope.launch { + val view = findCameraView(viewTag) + withPromise(promise) { + view.lockFocusAndExposureToPoint(point) + } + } + } + + @ReactMethod + fun freeFocusAndExposure(viewTag: Int, promise: Promise) { + backgroundCoroutineScope.launch { + val view = findCameraView(viewTag) + withPromise(promise) { + view.freeFocusAndExposure() + return@withPromise null + } + } + } + private fun canRequestPermission(permission: String): Boolean { val activity = currentActivity as? PermissionAwareActivity return activity?.shouldShowRequestPermissionRationale(permission) ?: false diff --git a/package/example/android/.project b/package/example/android/.project index 3964dd3f5b..5ae6ef9af6 100644 --- a/package/example/android/.project +++ b/package/example/android/.project @@ -14,4 +14,15 @@ org.eclipse.buildship.core.gradleprojectnature + + + 1732622346871 + + 30 + + org.eclipse.core.resources.regexFilterMatcher + node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ + + + diff --git a/package/example/src/CameraPage.tsx b/package/example/src/CameraPage.tsx index af65e71462..d2839f0b71 100644 --- a/package/example/src/CameraPage.tsx +++ b/package/example/src/CameraPage.tsx @@ -51,6 +51,8 @@ export function CameraPage({ navigation }: Props): React.ReactElement { const isForeground = useIsForeground() const isActive = isFocussed && isForeground + const useFastMode = useRef(false) + const [cameraPosition, setCameraPosition] = useState<'front' | 'back'>('back') const [enableHdr, setEnableHdr] = useState(false) const [flash, setFlash] = useState<'off' | 'on'>('off') @@ -143,6 +145,17 @@ export function CameraPage({ navigation }: Props): React.ReactElement { }, [onFlipCameraPressed]) //#endregion + const lockFocus = async () => { + const s = await camera.current!.lockFocusAndExposureToPoint({ x: SCREEN_WIDTH/2, y: SCREEN_HEIGHT/2 }); + console.log("focus status: ", s); + useFastMode.current = true; + } + + const unlockFocus = () => { + camera.current!.freeFocusAndExposure() + useFastMode.current = false; + } + //#region Effects useEffect(() => { // Reset zoom to it's default everytime the `device` changes. @@ -248,6 +261,7 @@ export function CameraPage({ navigation }: Props): React.ReactElement { flash={supportsFlash ? flash : 'off'} enabled={isCameraInitialized && isActive} setIsPressingButton={setIsPressingButton} + useFastMode={true} /> @@ -282,6 +296,12 @@ export function CameraPage({ navigation }: Props): React.ReactElement { navigation.navigate('CodeScannerPage')}> + lockFocus()}> + + + unlockFocus()}> + + ) diff --git a/package/example/src/views/CaptureButton.tsx b/package/example/src/views/CaptureButton.tsx index 2476d8bdcb..b23e2ed79c 100644 --- a/package/example/src/views/CaptureButton.tsx +++ b/package/example/src/views/CaptureButton.tsx @@ -34,6 +34,8 @@ interface Props extends ViewProps { enabled: boolean setIsPressingButton: (isPressingButton: boolean) => void + + useFastMode: boolean } const _CaptureButton: React.FC = ({ @@ -45,6 +47,7 @@ const _CaptureButton: React.FC = ({ flash, enabled, setIsPressingButton, + useFastMode, style, ...props }): React.ReactElement => { @@ -62,6 +65,7 @@ const _CaptureButton: React.FC = ({ const photo = await camera.current.takePhoto({ flash: flash, enableShutterSound: false, + useFastMode: useFastMode, }) onMediaCaptured(photo, 'photo') } catch (e) { diff --git a/package/lib/commonjs/Camera.js b/package/lib/commonjs/Camera.js new file mode 100644 index 0000000000..94df0231f8 --- /dev/null +++ b/package/lib/commonjs/Camera.js @@ -0,0 +1,675 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.Camera = void 0; +var _react = _interopRequireDefault(require("react")); +var _reactNative = require("react-native"); +var _CameraError = require("./CameraError"); +var _NativeCameraModule = require("./NativeCameraModule"); +var _VisionCameraProxy = require("./frame-processors/VisionCameraProxy"); +var _CameraDevices = require("./CameraDevices"); +var _SkiaCameraCanvas = require("./skia/SkiaCameraCanvas"); +var _FpsGraph = require("./FpsGraph"); +var _NativeCameraView = require("./NativeCameraView"); +var _RotationHelper = require("./RotationHelper"); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } +//#region Types + +//#endregion + +function isSkiaFrameProcessor(frameProcessor) { + return frameProcessor?.type === 'drawable-skia'; +} + +//#region Camera Component +/** + * ### A powerful `` component. + * + * Read the [VisionCamera documentation](https://react-native-vision-camera.com/) for more information. + * + * The `` component's most important properties are: + * + * * {@linkcode CameraProps.device | device}: Specifies the {@linkcode CameraDevice} to use. Get a {@linkcode CameraDevice} by using + * the {@linkcode useCameraDevice | useCameraDevice(..)} hook, or manually by using + * the {@linkcode CameraDevices.getAvailableCameraDevices | CameraDevices.getAvailableCameraDevices()} function. + * * {@linkcode CameraProps.isActive | isActive}: A boolean value that specifies whether the Camera should + * actively stream video frames or not. This can be compared to a Video component, where `isActive` specifies whether the video + * is paused or not. If you fully unmount the `` component instead of using `isActive={false}`, the Camera will take a bit longer to start again. + * + * @example + * ```tsx + * function App() { + * const device = useCameraDevice('back') + * + * if (device == null) return + * return ( + * + * ) + * } + * ``` + * + * @component + */ +class Camera extends _react.default.PureComponent { + /** @internal */ + static displayName = 'Camera'; + /** @internal */ + displayName = Camera.displayName; + isNativeViewMounted = false; + lastUIRotation = undefined; + rotationHelper = new _RotationHelper.RotationHelper(); + /** @internal */ + constructor(props) { + super(props); + this.onViewReady = this.onViewReady.bind(this); + this.onAverageFpsChanged = this.onAverageFpsChanged.bind(this); + this.onInitialized = this.onInitialized.bind(this); + this.onStarted = this.onStarted.bind(this); + this.onStopped = this.onStopped.bind(this); + this.onPreviewStarted = this.onPreviewStarted.bind(this); + this.onPreviewStopped = this.onPreviewStopped.bind(this); + this.onShutter = this.onShutter.bind(this); + this.onOutputOrientationChanged = this.onOutputOrientationChanged.bind(this); + this.onPreviewOrientationChanged = this.onPreviewOrientationChanged.bind(this); + this.onError = this.onError.bind(this); + this.onCodeScanned = this.onCodeScanned.bind(this); + this.ref = /*#__PURE__*/_react.default.createRef(); + this.lastFrameProcessor = undefined; + this.state = { + isRecordingWithFlash: false, + averageFpsSamples: [] + }; + } + get handle() { + const nodeHandle = (0, _reactNative.findNodeHandle)(this.ref.current); + if (nodeHandle == null || nodeHandle === -1) { + throw new _CameraError.CameraRuntimeError('system/view-not-found', "Could not get the Camera's native view tag! Does the Camera View exist in the native view-tree?"); + } + return nodeHandle; + } + + //#region View-specific functions (UIViewManager) + /** + * Take a single photo and write it's content to a temporary file. + * + * @throws {@linkcode CameraCaptureError} When any kind of error occured while capturing the photo. + * Use the {@linkcode CameraCaptureError.code | code} property to get the actual error + * @example + * ```ts + * const photo = await camera.current.takePhoto({ + * flash: 'on', + * enableAutoRedEyeReduction: true + * }) + * ``` + */ + async takePhoto(options) { + try { + return await _NativeCameraModule.CameraModule.takePhoto(this.handle, options ?? {}); + } catch (e) { + throw (0, _CameraError.tryParseNativeCameraError)(e); + } + } + + /** + * Captures a snapshot of the Camera view and write it's content to a temporary file. + * + * - On iOS, `takeSnapshot` waits for a Frame from the video pipeline and therefore requires `video` to be enabled. + * - On Android, `takeSnapshot` performs a GPU view screenshot from the preview view. + * + * @throws {@linkcode CameraCaptureError} When any kind of error occured while capturing the photo. + * Use the {@linkcode CameraCaptureError.code | code} property to get the actual error + * @example + * ```ts + * const snapshot = await camera.current.takeSnapshot({ + * quality: 100 + * }) + * ``` + */ + async takeSnapshot(options) { + try { + return await _NativeCameraModule.CameraModule.takeSnapshot(this.handle, options ?? {}); + } catch (e) { + throw (0, _CameraError.tryParseNativeCameraError)(e); + } + } + getBitRateMultiplier(bitRate) { + if (typeof bitRate === 'number' || bitRate == null) return 1; + switch (bitRate) { + case 'extra-low': + return 0.6; + case 'low': + return 0.8; + case 'normal': + return 1; + case 'high': + return 1.2; + case 'extra-high': + return 1.4; + } + } + + /** + * Start a new video recording. + * + * @throws {@linkcode CameraCaptureError} When any kind of error occured while starting the video recording. + * Use the {@linkcode CameraCaptureError.code | code} property to get the actual error + * + * @example + * ```ts + * camera.current.startRecording({ + * onRecordingFinished: (video) => console.log(video), + * onRecordingError: (error) => console.error(error), + * }) + * setTimeout(() => { + * camera.current.stopRecording() + * }, 5000) + * ``` + */ + startRecording(options) { + const { + onRecordingError, + onRecordingFinished, + videoBitRate, + ...passThruOptions + } = options; + if (typeof onRecordingError !== 'function' || typeof onRecordingFinished !== 'function') throw new _CameraError.CameraRuntimeError('parameter/invalid-parameter', 'The onRecordingError or onRecordingFinished functions were not set!'); + if (options.flash === 'on') { + // Enable torch for video recording + this.setState({ + isRecordingWithFlash: true + }); + } + const nativeOptions = passThruOptions; + if (typeof videoBitRate === 'number') { + // If the user passed an absolute number as a bit-rate, we just use this as a full override. + nativeOptions.videoBitRateOverride = videoBitRate; + } else if (typeof videoBitRate === 'string' && videoBitRate !== 'normal') { + // If the user passed 'low'/'normal'/'high', we need to apply this as a multiplier to the native bitrate instead of absolutely setting it + nativeOptions.videoBitRateMultiplier = this.getBitRateMultiplier(videoBitRate); + } + const onRecordCallback = (video, error) => { + if (this.state.isRecordingWithFlash) { + // disable torch again if it was enabled + this.setState({ + isRecordingWithFlash: false + }); + } + if (error != null) return onRecordingError(error); + if (video != null) return onRecordingFinished(video); + }; + try { + // TODO: Use TurboModules to make this awaitable. + _NativeCameraModule.CameraModule.startRecording(this.handle, nativeOptions, onRecordCallback); + } catch (e) { + throw (0, _CameraError.tryParseNativeCameraError)(e); + } + } + + /** + * Pauses the current video recording. + * + * @throws {@linkcode CameraCaptureError} When any kind of error occured while pausing the video recording. + * Use the {@linkcode CameraCaptureError.code | code} property to get the actual error + * + * @example + * ```ts + * // Start + * await camera.current.startRecording({ + * onRecordingFinished: (video) => console.log(video), + * onRecordingError: (error) => console.error(error), + * }) + * await timeout(1000) + * // Pause + * await camera.current.pauseRecording() + * await timeout(500) + * // Resume + * await camera.current.resumeRecording() + * await timeout(2000) + * // Stop + * await camera.current.stopRecording() + * ``` + */ + async pauseRecording() { + try { + return await _NativeCameraModule.CameraModule.pauseRecording(this.handle); + } catch (e) { + throw (0, _CameraError.tryParseNativeCameraError)(e); + } + } + + /** + * Resumes a currently paused video recording. + * + * @throws {@linkcode CameraCaptureError} When any kind of error occured while resuming the video recording. + * Use the {@linkcode CameraCaptureError.code | code} property to get the actual error + * + * @example + * ```ts + * // Start + * await camera.current.startRecording({ + * onRecordingFinished: (video) => console.log(video), + * onRecordingError: (error) => console.error(error), + * }) + * await timeout(1000) + * // Pause + * await camera.current.pauseRecording() + * await timeout(500) + * // Resume + * await camera.current.resumeRecording() + * await timeout(2000) + * // Stop + * await camera.current.stopRecording() + * ``` + */ + async resumeRecording() { + try { + return await _NativeCameraModule.CameraModule.resumeRecording(this.handle); + } catch (e) { + throw (0, _CameraError.tryParseNativeCameraError)(e); + } + } + + /** + * Stop the current video recording. + * + * @throws {@linkcode CameraCaptureError} When any kind of error occured while stopping the video recording. + * Use the {@linkcode CameraCaptureError.code | code} property to get the actual error + * + * @example + * ```ts + * await camera.current.startRecording({ + * onRecordingFinished: (video) => console.log(video), + * onRecordingError: (error) => console.error(error), + * }) + * setTimeout(async () => { + * await camera.current.stopRecording() + * }, 5000) + * ``` + */ + async stopRecording() { + try { + return await _NativeCameraModule.CameraModule.stopRecording(this.handle); + } catch (e) { + throw (0, _CameraError.tryParseNativeCameraError)(e); + } + } + + /** + * Cancel the current video recording. The temporary video file will be deleted, + * and the `startRecording`'s `onRecordingError` callback will be invoked with a `capture/recording-canceled` error. + * + * @throws {@linkcode CameraCaptureError} When any kind of error occured while canceling the video recording. + * Use the {@linkcode CameraCaptureError.code | code} property to get the actual error + * + * @example + * ```ts + * await camera.current.startRecording({ + * onRecordingFinished: (video) => console.log(video), + * onRecordingError: (error) => { + * if (error.code === 'capture/recording-canceled') { + * // recording was canceled. + * } else { + * console.error(error) + * } + * }, + * }) + * setTimeout(async () => { + * await camera.current.cancelRecording() + * }, 5000) + * ``` + */ + async cancelRecording() { + try { + return await _NativeCameraModule.CameraModule.cancelRecording(this.handle); + } catch (e) { + throw (0, _CameraError.tryParseNativeCameraError)(e); + } + } + + /** + * Focus the camera to a specific point in the coordinate system. + * @param {Point} point The point to focus to. This should be relative + * to the Camera view's coordinate system and is expressed in points. + * * `(0, 0)` means **top left**. + * * `(CameraView.width, CameraView.height)` means **bottom right**. + * + * Make sure the value doesn't exceed the CameraView's dimensions. + * + * @throws {@linkcode CameraRuntimeError} When any kind of error occured while focussing. + * Use the {@linkcode CameraRuntimeError.code | code} property to get the actual error + * @example + * ```ts + * await camera.current.focus({ + * x: tapEvent.x, + * y: tapEvent.y + * }) + * ``` + */ + async focus(point) { + try { + return await _NativeCameraModule.CameraModule.focus(this.handle, point); + } catch (e) { + throw (0, _CameraError.tryParseNativeCameraError)(e); + } + } + //#endregion + + async lockFocusAndExposureToPoint(point) { + try { + return await _NativeCameraModule.CameraModule.lockFocusAndExposureToPoint(this.handle, point); + } catch (e) { + throw (0, _CameraError.tryParseNativeCameraError)(e); + } + } + async freeFocusAndExposure() { + try { + return await _NativeCameraModule.CameraModule.freeFocusAndExposure(this.handle); + } catch (e) { + throw (0, _CameraError.tryParseNativeCameraError)(e); + } + } + + //#region Static Functions (NativeModule) + /** + * Get a list of all available camera devices on the current phone. + * + * If you use Hooks, use the `useCameraDevices(..)` hook instead. + * + * * For Camera Devices attached to the phone, it is safe to assume that this will never change. + * * For external Camera Devices (USB cameras, Mac continuity cameras, etc.) the available Camera Devices + * could change over time when the external Camera device gets plugged in or plugged out, so + * use {@link addCameraDevicesChangedListener | addCameraDevicesChangedListener(...)} to listen for such changes. + * + * @example + * ```ts + * const devices = Camera.getAvailableCameraDevices() + * const backCameras = devices.filter((d) => d.position === "back") + * const frontCameras = devices.filter((d) => d.position === "front") + * ``` + */ + static getAvailableCameraDevices() { + return _CameraDevices.CameraDevices.getAvailableCameraDevices(); + } + /** + * Adds a listener that gets called everytime the Camera Devices change, for example + * when an external Camera Device (USB or continuity Camera) gets plugged in or plugged out. + * + * If you use Hooks, use the `useCameraDevices()` hook instead. + */ + static addCameraDevicesChangedListener(listener) { + return _CameraDevices.CameraDevices.addCameraDevicesChangedListener(listener); + } + /** + * Gets the current Camera Permission Status. Check this before mounting the Camera to ensure + * the user has permitted the app to use the camera. + * + * To actually prompt the user for camera permission, use {@linkcode Camera.requestCameraPermission | requestCameraPermission()}. + */ + static getCameraPermissionStatus() { + return _NativeCameraModule.CameraModule.getCameraPermissionStatus(); + } + /** + * Gets the current Microphone-Recording Permission Status. + * Check this before enabling the `audio={...}` property to make sure the + * user has permitted the app to use the microphone. + * + * To actually prompt the user for microphone permission, use {@linkcode Camera.requestMicrophonePermission | requestMicrophonePermission()}. + */ + static getMicrophonePermissionStatus() { + return _NativeCameraModule.CameraModule.getMicrophonePermissionStatus(); + } + /** + * Gets the current Location Permission Status. + * Check this before enabling the `location={...}` property to make sure the + * the user has permitted the app to use the location. + * + * To actually prompt the user for location permission, use {@linkcode Camera.requestLocationPermission | requestLocationPermission()}. + * + * Note: This method will throw a `system/location-not-enabled` error if the Location APIs are not enabled at build-time. + * See [the "GPS Location Tags" documentation](https://react-native-vision-camera.com/docs/guides/location) for more information. + */ + static getLocationPermissionStatus() { + return _NativeCameraModule.CameraModule.getLocationPermissionStatus(); + } + /** + * Shows a "request permission" alert to the user, and resolves with the new camera permission status. + * + * If the user has previously blocked the app from using the camera, the alert will not be shown + * and `"denied"` will be returned. + * + * @throws {@linkcode CameraRuntimeError} When any kind of error occured while requesting permission. + * Use the {@linkcode CameraRuntimeError.code | code} property to get the actual error + */ + static async requestCameraPermission() { + try { + return await _NativeCameraModule.CameraModule.requestCameraPermission(); + } catch (e) { + throw (0, _CameraError.tryParseNativeCameraError)(e); + } + } + /** + * Shows a "request permission" alert to the user, and resolves with the new microphone permission status. + * + * If the user has previously blocked the app from using the microphone, the alert will not be shown + * and `"denied"` will be returned. + * + * @throws {@linkcode CameraRuntimeError} When any kind of error occured while requesting permission. + * Use the {@linkcode CameraRuntimeError.code | code} property to get the actual error + */ + static async requestMicrophonePermission() { + try { + return await _NativeCameraModule.CameraModule.requestMicrophonePermission(); + } catch (e) { + throw (0, _CameraError.tryParseNativeCameraError)(e); + } + } + /** + * Shows a "request permission" alert to the user, and resolves with the new location permission status. + * + * If the user has previously blocked the app from using the location, the alert will not be shown + * and `"denied"` will be returned. + * + * @throws {@linkcode CameraRuntimeError} When any kind of error occured while requesting permission. + * Use the {@linkcode CameraRuntimeError.code | code} property to get the actual error + */ + static async requestLocationPermission() { + try { + return await _NativeCameraModule.CameraModule.requestLocationPermission(); + } catch (e) { + throw (0, _CameraError.tryParseNativeCameraError)(e); + } + } + //#endregion + + //#region Events (Wrapped to maintain reference equality) + onError(event) { + const error = event.nativeEvent; + const cause = (0, _CameraError.isErrorWithCause)(error.cause) ? error.cause : undefined; + // @ts-expect-error We're casting from unknown bridge types to TS unions, I expect it to hopefully work + const cameraError = new _CameraError.CameraRuntimeError(error.code, error.message, cause); + if (this.props.onError != null) { + this.props.onError(cameraError); + } else { + // User didn't pass an `onError` handler, so just log it to console + console.error(cameraError); + } + } + onInitialized() { + this.props.onInitialized?.(); + } + onStarted() { + this.props.onStarted?.(); + } + onStopped() { + this.props.onStopped?.(); + } + onPreviewStarted() { + this.props.onPreviewStarted?.(); + } + onPreviewStopped() { + this.props.onPreviewStopped?.(); + } + onShutter(event) { + this.props.onShutter?.(event.nativeEvent); + } + onOutputOrientationChanged({ + nativeEvent: { + outputOrientation + } + }) { + this.rotationHelper.outputOrientation = outputOrientation; + this.props.onOutputOrientationChanged?.(outputOrientation); + this.maybeUpdateUIRotation(); + } + onPreviewOrientationChanged({ + nativeEvent: { + previewOrientation + } + }) { + this.rotationHelper.previewOrientation = previewOrientation; + this.props.onPreviewOrientationChanged?.(previewOrientation); + this.maybeUpdateUIRotation(); + if (isSkiaFrameProcessor(this.props.frameProcessor)) { + // If we have a Skia Frame Processor, we need to update it's orientation so it knows how to render. + this.props.frameProcessor.previewOrientation.value = previewOrientation; + } + } + maybeUpdateUIRotation() { + const uiRotation = this.rotationHelper.uiRotation; + if (uiRotation !== this.lastUIRotation) { + this.props.onUIRotationChanged?.(uiRotation); + this.lastUIRotation = uiRotation; + } + } + //#endregion + + onCodeScanned(event) { + const codeScanner = this.props.codeScanner; + if (codeScanner == null) return; + codeScanner.onCodeScanned(event.nativeEvent.codes, event.nativeEvent.frame); + } + + //#region Lifecycle + setFrameProcessor(frameProcessor) { + _VisionCameraProxy.VisionCameraProxy.setFrameProcessor(this.handle, frameProcessor); + } + unsetFrameProcessor() { + _VisionCameraProxy.VisionCameraProxy.removeFrameProcessor(this.handle); + } + onViewReady() { + this.isNativeViewMounted = true; + if (this.props.frameProcessor != null) { + // user passed a `frameProcessor` but we didn't set it yet because the native view was not mounted yet. set it now. + this.setFrameProcessor(this.props.frameProcessor.frameProcessor); + this.lastFrameProcessor = this.props.frameProcessor.frameProcessor; + } + } + onAverageFpsChanged({ + nativeEvent: { + averageFps + } + }) { + this.setState(state => { + const averageFpsSamples = [...state.averageFpsSamples, averageFps]; + while (averageFpsSamples.length >= _FpsGraph.MAX_BARS + 1) { + // we keep a maximum of 30 FPS samples in our history + averageFpsSamples.shift(); + } + return { + ...state, + averageFpsSamples: averageFpsSamples + }; + }); + } + + /** @internal */ + componentDidUpdate() { + if (!this.isNativeViewMounted) return; + const frameProcessor = this.props.frameProcessor; + if (frameProcessor?.frameProcessor !== this.lastFrameProcessor) { + // frameProcessor argument identity changed. Update native to reflect the change. + if (frameProcessor != null) this.setFrameProcessor(frameProcessor.frameProcessor);else this.unsetFrameProcessor(); + this.lastFrameProcessor = frameProcessor?.frameProcessor; + } + } + //#endregion + + /** @internal */ + render() { + // We remove the big `device` object from the props because we only need to pass `cameraId` to native. + const { + device, + frameProcessor, + codeScanner, + enableFpsGraph, + fps, + ...props + } = this.props; + + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (device == null) { + throw new _CameraError.CameraRuntimeError('device/no-device', 'Camera: `device` is null! Select a valid Camera device. See: https://mrousavy.com/react-native-vision-camera/docs/guides/devices'); + } + const shouldEnableBufferCompression = props.video === true && frameProcessor == null; + const torch = this.state.isRecordingWithFlash ? 'on' : props.torch; + const isRenderingWithSkia = isSkiaFrameProcessor(frameProcessor); + const shouldBeMirrored = device.position === 'front'; + + // minFps/maxFps is either the fixed `fps` value, or a value from the [min, max] tuple + const minFps = fps == null ? undefined : typeof fps === 'number' ? fps : fps[0]; + const maxFps = fps == null ? undefined : typeof fps === 'number' ? fps : fps[1]; + return /*#__PURE__*/_react.default.createElement(_NativeCameraView.NativeCameraView, _extends({}, props, { + cameraId: device.id, + ref: this.ref, + torch: torch, + minFps: minFps, + maxFps: maxFps, + isMirrored: props.isMirrored ?? shouldBeMirrored, + onViewReady: this.onViewReady, + onAverageFpsChanged: enableFpsGraph ? this.onAverageFpsChanged : undefined, + onInitialized: this.onInitialized, + onCodeScanned: this.onCodeScanned, + onStarted: this.onStarted, + onStopped: this.onStopped, + onPreviewStarted: this.onPreviewStarted, + onPreviewStopped: this.onPreviewStopped, + onShutter: this.onShutter, + onOutputOrientationChanged: this.onOutputOrientationChanged, + onPreviewOrientationChanged: this.onPreviewOrientationChanged, + onError: this.onError, + codeScannerOptions: codeScanner, + enableFrameProcessor: frameProcessor != null, + enableBufferCompression: props.enableBufferCompression ?? shouldEnableBufferCompression, + preview: isRenderingWithSkia ? false : props.preview ?? true + }), isRenderingWithSkia && /*#__PURE__*/_react.default.createElement(_SkiaCameraCanvas.SkiaCameraCanvas, { + style: styles.customPreviewView, + offscreenTextures: frameProcessor.offscreenTextures, + resizeMode: props.resizeMode + }), enableFpsGraph && /*#__PURE__*/_react.default.createElement(_FpsGraph.FpsGraph, { + style: styles.fpsGraph, + averageFpsSamples: this.state.averageFpsSamples, + targetMaxFps: props.format?.maxFps ?? 60 + })); + } +} +//#endregion +exports.Camera = Camera; +const styles = _reactNative.StyleSheet.create({ + customPreviewView: { + flex: 1 + }, + fpsGraph: { + elevation: 1, + position: 'absolute', + left: 15, + top: 30 + } +}); +//# sourceMappingURL=Camera.js.map \ No newline at end of file diff --git a/package/lib/commonjs/Camera.js.map b/package/lib/commonjs/Camera.js.map new file mode 100644 index 0000000000..78852aa769 --- /dev/null +++ b/package/lib/commonjs/Camera.js.map @@ -0,0 +1 @@ +{"version":3,"names":["_react","_interopRequireDefault","require","_reactNative","_CameraError","_NativeCameraModule","_VisionCameraProxy","_CameraDevices","_SkiaCameraCanvas","_FpsGraph","_NativeCameraView","_RotationHelper","obj","__esModule","default","_extends","Object","assign","bind","target","i","arguments","length","source","key","prototype","hasOwnProperty","call","apply","isSkiaFrameProcessor","frameProcessor","type","Camera","React","PureComponent","displayName","isNativeViewMounted","lastUIRotation","undefined","rotationHelper","RotationHelper","constructor","props","onViewReady","onAverageFpsChanged","onInitialized","onStarted","onStopped","onPreviewStarted","onPreviewStopped","onShutter","onOutputOrientationChanged","onPreviewOrientationChanged","onError","onCodeScanned","ref","createRef","lastFrameProcessor","state","isRecordingWithFlash","averageFpsSamples","handle","nodeHandle","findNodeHandle","current","CameraRuntimeError","takePhoto","options","CameraModule","e","tryParseNativeCameraError","takeSnapshot","getBitRateMultiplier","bitRate","startRecording","onRecordingError","onRecordingFinished","videoBitRate","passThruOptions","flash","setState","nativeOptions","videoBitRateOverride","videoBitRateMultiplier","onRecordCallback","video","error","pauseRecording","resumeRecording","stopRecording","cancelRecording","focus","point","lockFocusAndExposureToPoint","freeFocusAndExposure","getAvailableCameraDevices","CameraDevices","addCameraDevicesChangedListener","listener","getCameraPermissionStatus","getMicrophonePermissionStatus","getLocationPermissionStatus","requestCameraPermission","requestMicrophonePermission","requestLocationPermission","event","nativeEvent","cause","isErrorWithCause","cameraError","code","message","console","outputOrientation","maybeUpdateUIRotation","previewOrientation","value","uiRotation","onUIRotationChanged","codeScanner","codes","frame","setFrameProcessor","VisionCameraProxy","unsetFrameProcessor","removeFrameProcessor","averageFps","MAX_BARS","shift","componentDidUpdate","render","device","enableFpsGraph","fps","shouldEnableBufferCompression","torch","isRenderingWithSkia","shouldBeMirrored","position","minFps","maxFps","createElement","NativeCameraView","cameraId","id","isMirrored","codeScannerOptions","enableFrameProcessor","enableBufferCompression","preview","SkiaCameraCanvas","style","styles","customPreviewView","offscreenTextures","resizeMode","FpsGraph","fpsGraph","targetMaxFps","format","exports","StyleSheet","create","flex","elevation","left","top"],"sourceRoot":"../../src","sources":["Camera.tsx"],"mappings":"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AC,EAAE;MACV,MAAM,IAAAC,sCAAyB,EAACD,CAAC,CAAC;IACpC;EACF;;EAEA;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACE,MAAamB,eAAeA,CAAA,EAAkB;IAC5C,IAAI;MACF,OAAO,MAAMpB,gCAAY,CAACoB,eAAe,CAAC,IAAI,CAAC3B,MAAM,CAAC;IACxD,CAAC,CAAC,OAAOQ,CAAC,EAAE;MACV,MAAM,IAAAC,sCAAyB,EAACD,CAAC,CAAC;IACpC;EACF;;EAEA;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACE,MAAaoB,aAAaA,CAAA,EAAkB;IAC1C,IAAI;MACF,OAAO,MAAMrB,gCAAY,CAACqB,aAAa,CAAC,IAAI,CAAC5B,MAAM,CAAC;IACtD,CAAC,CAAC,OAAOQ,CAAC,EAAE;MACV,MAAM,IAAAC,sCAAyB,EAACD,CAAC,CAAC;IACpC;EACF;;EAEA;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACE,MAAaqB,eAAeA,CAAA,EAAkB;IAC5C,IAAI;MACF,OAAO,MAAMtB,gCAAY,CAACsB,eAAe,CAAC,IAAI,CAAC7B,MAAM,CAAC;IACxD,CAAC,CAAC,OAAOQ,CAAC,EAAE;MACV,MAAM,IAAAC,sCAAyB,EAACD,CAAC,CAAC;IACpC;EACF;;EAEA;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACE,MAAasB,KAAKA,CAACC,KAAY,EAAiB;IAC9C,IAAI;MACF,OAAO,MAAMxB,gCAAY,CAACuB,KAAK,CAAC,IAAI,CAAC9B,MAAM,EAAE+B,KAAK,CAAC;IACrD,CAAC,CAAC,OAAOvB,CAAC,EAAE;MACV,MAAM,IAA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"} diff --git a/package/lib/commonjs/CameraDevices.js b/package/lib/commonjs/CameraDevices.js new file mode 100644 index 0000000000..5c919f1e34 --- /dev/null +++ b/package/lib/commonjs/CameraDevices.js @@ -0,0 +1,24 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.CameraDevices = void 0; +var _reactNative = require("react-native"); +const CameraDevicesManager = _reactNative.NativeModules.CameraDevices; +const constants = CameraDevicesManager.getConstants(); +let devices = constants.availableCameraDevices; +const DEVICES_CHANGED_NAME = 'CameraDevicesChanged'; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const eventEmitter = new _reactNative.NativeEventEmitter(CameraDevicesManager); +eventEmitter.addListener(DEVICES_CHANGED_NAME, newDevices => { + devices = newDevices; +}); +const CameraDevices = exports.CameraDevices = { + userPreferredCameraDevice: constants.userPreferredCameraDevice, + getAvailableCameraDevices: () => devices, + addCameraDevicesChangedListener: callback => { + return eventEmitter.addListener(DEVICES_CHANGED_NAME, callback); + } +}; +//# sourceMappingURL=CameraDevices.js.map \ No newline at end of file diff --git a/package/lib/commonjs/CameraDevices.js.map b/package/lib/commonjs/CameraDevices.js.map new file mode 100644 index 0000000000..d918e76d12 --- /dev/null +++ b/package/lib/commonjs/CameraDevices.js.map @@ -0,0 +1 @@ +{"version":3,"names":["_reactNative","require","CameraDevicesManager","NativeModules","CameraDevices","constants","getConstants","devices","availableCameraDevices","DEVICES_CHANGED_NAME","eventEmitter","NativeEventEmitter","addListener","newDevices","exports","userPreferredCameraDevice","getAvailableCameraDevices","addCameraDevicesChangedListener","callback"],"sourceRoot":"../../src","sources":["CameraDevices.ts"],"mappings":";;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AAGA,MAAMC,oBAAoB,GAAGC,0BAAa,CAACC,aAK1C;AAED,MAAMC,SAAS,GAAGH,oBAAoB,CAACI,YAAY,CAAC,CAAC;AACrD,IAAIC,OAAO,GAAGF,SAAS,CAACG,sBAAsB;AAE9C,MAAMC,oBAAoB,GAAG,sBAAsB;AACnD;AACA,MAAMC,YAAY,GAAG,IAAIC,+BAAkB,CAACT,oBAA2B,CAAC;AACxEQ,YAAY,CAACE,WAAW,CAACH,oBAAoB,EAAGI,UAA0B,IAAK;EAC7EN,OAAO,GAAGM,UAAU;AACtB,CAAC,CAAC;AAEK,MAAMT,aAAa,GAAAU,OAAA,CAAAV,aAAA,GAAG;EAC3BW,yBAAyB,EAAEV,SAAS,CAACU,yBAAyB;EAC9DC,yBAAyB,EAAEA,CAAA,KAAMT,OAAO;EACxCU,+BAA+B,EAAGC,QAA8C,IAAK;IACnF,OAAOR,YAAY,CAACE,WAAW,CAACH,oBAAoB,EAAES,QAAQ,CAAC;EACjE;AACF,CAAC"} diff --git a/package/lib/commonjs/CameraError.js b/package/lib/commonjs/CameraError.js new file mode 100644 index 0000000000..cf16b31253 --- /dev/null +++ b/package/lib/commonjs/CameraError.js @@ -0,0 +1,102 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.tryParseNativeCameraError = exports.isErrorWithCause = exports.CameraRuntimeError = exports.CameraCaptureError = void 0; +/** + * Represents a JSON-style error cause. This contains native `NSError`/`Throwable` information, and can have recursive {@linkcode ErrorWithCause.cause | .cause} properties until the ultimate cause has been found. + */ + +/** + * Represents any kind of error that occured in the {@linkcode Camera} View Module. + */ +class CameraError extends Error { + get code() { + return this._code; + } + get message() { + return this._message; + } + get cause() { + const c = this._cause; + if (c == null) return undefined; + return new Error(`[${c.code}]: ${c.message}`); + } + + /** + * @internal + */ + constructor(code, message, cause) { + super(`[${code}]: ${message}${cause != null ? ` (Cause: ${cause.message})` : ''}`); + super.name = code; + super.message = message; + this._code = code; + this._message = message; + this._cause = cause; + } + toString() { + let string = `[${this.code}]: ${this.message}`; + if (this._cause != null) string += ` (caused by ${JSON.stringify(this._cause)})`; + return string; + } +} + +/** + * Represents any kind of error that occured while trying to capture a video or photo. + * + * See the ["Camera Errors" documentation](https://react-native-vision-camera.com/docs/guides/errors) for more information about Camera Errors. + */ +class CameraCaptureError extends CameraError {} + +/** + * Represents any kind of error that occured in the Camera View Module. + * + * See the ["Camera Errors" documentation](https://react-native-vision-camera.com/docs/guides/errors) for more information about Camera Errors. + */ +exports.CameraCaptureError = CameraCaptureError; +class CameraRuntimeError extends CameraError {} + +/** + * Checks if the given `error` is of type {@linkcode ErrorWithCause} + * @param {unknown} error Any unknown object to validate + * @returns `true` if the given `error` is of type {@linkcode ErrorWithCause} + */ +exports.CameraRuntimeError = CameraRuntimeError; +const isErrorWithCause = error => typeof error === 'object' && error != null && +// @ts-expect-error error is still unknown +typeof error.message === 'string' && ( +// @ts-expect-error error is still unknown +typeof error.stacktrace === 'string' || error.stacktrace == null) && ( +// @ts-expect-error error is still unknown +isErrorWithCause(error.cause) || error.cause == null); +exports.isErrorWithCause = isErrorWithCause; +const isCameraErrorJson = error => typeof error === 'object' && error != null && +// @ts-expect-error error is still unknown +typeof error.code === 'string' && +// @ts-expect-error error is still unknown +typeof error.message === 'string' && ( +// @ts-expect-error error is still unknown +typeof error.cause === 'object' || error.cause == null); + +/** + * Tries to parse an error coming from native to a typed JS camera error. + * @param {CameraError} nativeError The native error instance. This is a JSON in the legacy native module architecture. + * @returns A {@linkcode CameraRuntimeError} or {@linkcode CameraCaptureError}, or the `nativeError` itself if it's not parsable + * @method + */ +const tryParseNativeCameraError = nativeError => { + if (isCameraErrorJson(nativeError)) { + if (nativeError.code.startsWith('capture')) { + return new CameraCaptureError(nativeError.code, nativeError.message, nativeError.cause); + } else { + return new CameraRuntimeError( + // @ts-expect-error the code is string, we narrow it down to TS union. + nativeError.code, nativeError.message, nativeError.cause); + } + } else { + return nativeError; + } +}; +exports.tryParseNativeCameraError = tryParseNativeCameraError; +//# sourceMappingURL=CameraError.js.map \ No newline at end of file diff --git a/package/lib/commonjs/CameraError.js.map b/package/lib/commonjs/CameraError.js.map new file mode 100644 index 0000000000..a58c6d014d --- /dev/null +++ b/package/lib/commonjs/CameraError.js.map @@ -0,0 +1 @@ +{"version":3,"names":["CameraError","Error","code","_code","message","_message","cause","c","_cause","undefined","constructor","name","toString","string","JSON","stringify","CameraCaptureError","exports","CameraRuntimeError","isErrorWithCause","error","stacktrace","isCameraErrorJson","tryParseNativeCameraError","nativeError","startsWith"],"sourceRoot":"../../src","sources":["CameraError.ts"],"mappings":"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"} diff --git a/package/lib/commonjs/FpsGraph.js b/package/lib/commonjs/FpsGraph.js new file mode 100644 index 0000000000..e221c202f9 --- /dev/null +++ b/package/lib/commonjs/FpsGraph.js @@ -0,0 +1,76 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.FpsGraph = FpsGraph; +exports.MAX_BARS = void 0; +var _react = _interopRequireWildcard(require("react")); +var _reactNative = require("react-native"); +function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } +function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } +function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } +const MAX_BARS = exports.MAX_BARS = 30; +const WIDTH = 100; +const HEIGHT = 65; +const BAR_WIDTH = WIDTH / MAX_BARS; +function FpsGraph({ + averageFpsSamples, + targetMaxFps, + style, + ...props +}) { + const maxFps = (0, _react.useMemo)(() => { + const currentMaxFps = averageFpsSamples.reduce((prev, curr) => Math.max(prev, curr), 0); + return Math.max(currentMaxFps, targetMaxFps); + }, [averageFpsSamples, targetMaxFps]); + const latestFps = averageFpsSamples[averageFpsSamples.length - 1]; + return /*#__PURE__*/_react.default.createElement(_reactNative.View, _extends({}, props, { + style: [styles.container, style] + }), averageFpsSamples.map((fps, index) => { + let height = fps / maxFps * HEIGHT; + if (Number.isNaN(height) || height < 0) { + // clamp to 0 if needed + height = 0; + } + return /*#__PURE__*/_react.default.createElement(_reactNative.View, { + key: index, + style: [styles.bar, { + height: height + }] + }); + }), latestFps != null && !Number.isNaN(latestFps) && /*#__PURE__*/_react.default.createElement(_reactNative.View, { + style: styles.centerContainer + }, /*#__PURE__*/_react.default.createElement(_reactNative.Text, { + style: styles.text + }, Math.round(latestFps), " FPS"))); +} +const styles = _reactNative.StyleSheet.create({ + container: { + width: WIDTH, + height: HEIGHT, + backgroundColor: 'rgba(0, 0, 0, 0.3)', + flexDirection: 'row', + justifyContent: 'flex-end', + alignItems: 'flex-end', + borderRadius: 5, + overflow: 'hidden' + }, + bar: { + width: BAR_WIDTH, + height: 5, + backgroundColor: 'rgb(243, 74, 77)' + }, + centerContainer: { + ..._reactNative.StyleSheet.absoluteFillObject, + justifyContent: 'center', + alignItems: 'center' + }, + text: { + position: 'absolute', + fontWeight: 'bold', + fontSize: 14, + color: 'rgb(255, 255, 255)' + } +}); +//# sourceMappingURL=FpsGraph.js.map \ No newline at end of file diff --git a/package/lib/commonjs/FpsGraph.js.map b/package/lib/commonjs/FpsGraph.js.map new file mode 100644 index 0000000000..eb835cc02a --- /dev/null +++ b/package/lib/commonjs/FpsGraph.js.map @@ -0,0 +1 @@ +{"version":3,"names":["_react","_interopRequireWildcard","require","_reactNative","_getRequireWildcardCache","e","WeakMap","r","t","__esModule","default","has","get","n","__proto__","a","Object","defineProperty","getOwnPropertyDescriptor","u","prototype","hasOwnProperty","call","i","set","_extends","assign","bind","target","arguments","length","source","key","apply","MAX_BARS","exports","WIDTH","HEIGHT","BAR_WIDTH","FpsGraph","averageFpsSamples","targetMaxFps","style","props","maxFps","useMemo","currentMaxFps","reduce","prev","curr","Math","max","latestFps","createElement","View","styles","container","map","fps","index","height","Number","isNaN","bar","centerContainer","Text","text","round","StyleSheet","create","width","backgroundColor","flexDirection","justifyContent","alignItems","borderRadius","overflow","absoluteFillObject","position","fontWeight","fontSize","color"],"sourceRoot":"../../src","sources":["FpsGraph.tsx"],"mappings":";;;;;;;AAAA,IAAAA,MAAA,GAAAC,uBAAA,CAAAC,OAAA;AAEA,IAAAC,YAAA,GAAAD,OAAA;AAA+C,SAAAE,yBAAAC,CAAA,6BAAAC,OAAA,mBAAAC,CAAA,OAAAD,OAAA,IAAAE,CAAA,OAAAF,OAAA,YAAAF,wBAAA,YAAAA,CAAAC,CAAA,WAAAA,CAAA,GAAAG,CAAA,GAAAD,CAAA,KAAAF,CAAA;AAAA,SAAAJ,wBAAAI,CAAA,EAAAE,CAAA,SAAAA,CAAA,IAAAF,CAAA,IAAAA,CAAA,CAAAI,UAAA,SAAAJ,CAAA,eAAAA,CAAA,uBAAAA,CAAA,yBAAAA,CAAA,WAAAK,OAAA,EAAAL,CAAA,QAAAG,CAAA,GAAAJ,wBAAA,CAAAG,CAAA,OAAAC,CAAA,IAAAA,CAAA,CAAAG,GAAA,CAAAN,CAAA,UAAAG,CAAA,CAAAI,GAAA,CAAAP,CAAA,OAAAQ,CAAA,KAAAC,SAAA,UAAAC,CAAA,GAAAC,MAAA,CAAAC,cAAA,IAAAD,MAAA,CAAAE,wBAAA,WAAAC,CAAA,IAAAd,CAAA,oBAAAc,CAAA,IAAAH,MAAA,CAAAI,SAAA,CAAAC,cAAA,CAAAC,IAAA,CAAAjB,CAAA,EAAAc,CAAA,SAAAI,CAAA,GAAAR,CAAA,GAAAC,MAAA,CAAAE,wBAAA,CAAAb,CAAA,EAAAc,CAAA,UAAAI,CAAA,KAAAA,CAAA,CAAAX,GAAA,IAAAW,CAAA,CAAAC,GAAA,IAAAR,MAAA,CAAAC,cAAA,CAAAJ,CAAA,EAAAM,CAAA,EAAAI,CAAA,IAAAV,CAAA,CAAAM,CAAA,IAAAd,CAAA,CAAAc,CAAA,YAAAN,CAAA,CAAAH,OAAA,GAAAL,CAAA,EAAAG,CAAA,IAAAA,CAAA,CAAAgB,GAAA,CAAAnB,CAAA,EAAAQ,CAAA,GAAAA,CAAA;AAAA,SAAAY,SAAA,IAAAA,QAAA,GAAAT,MAAA,CAAAU,MAAA,GAAAV,MAAA,CAAAU,MAAA,CAAAC,IAAA,eAAAC,MAAA,aAAAL,CAAA,MAAAA,CAAA,GAAAM,SAAA,CAAAC,MAAA,EAAAP,CAAA,UAAAQ,MAAA,GAAAF,SAAA,CAAAN,CAAA,YAAAS,GAAA,IAAAD,MAAA,QAAAf,MAAA,CAAAI,SAAA,CAAAC,cAAA,CAAAC,IAAA,CAAAS,MAAA,EAAAC,GAAA,KAAAJ,MAAA,CAAAI,GAAA,IAAAD,MAAA,CAAAC,GAAA,gBAAAJ,MAAA,YAAAH,QAAA,CAAAQ,KAAA,OAAAJ,SAAA;AAcxC,MAAMK,QAAQ,GAAAC,OAAA,CAAAD,QAAA,GAAG,EAAE;AAE1B,MAAME,KAAK,GAAG,GAAG;AACjB,MAAMC,MAAM,GAAG,EAAE;AACjB,MAAMC,SAAS,GAAGF,KAAK,GAAGF,QAAQ;AAE3B,SAASK,QAAQA,CAAC;EAAEC,iBAAiB;EAAEC,YAAY;EAAEC,KAAK;EAAE,GAAGC;AAAa,CAAC,EAAsB;EACxG,MAAMC,MAAM,GAAG,IAAAC,cAAO,EAAC,MAAM;IAC3B,MAAMC,aAAa,GAAGN,iBAAiB,CAACO,MAAM,CAAC,CAACC,IAAI,EAAEC,IAAI,KAAKC,IAAI,CAACC,GAAG,CAACH,IAAI,EAAEC,IAAI,CAAC,EAAE,CAAC,CAAC;IACvF,OAAOC,IAAI,CAACC,GAAG,CAACL,aAAa,EAAEL,YAAY,CAAC;EAC9C,CAAC,EAAE,CAACD,iBAAiB,EAAEC,YAAY,CAAC,CAAC;EACrC,MAAMW,SAAS,GAAGZ,iBAAiB,CAACA,iBAAiB,CAACV,MAAM,GAAG,CAAC,CAAC;EAEjE,oBACE9B,MAAA,CAAAU,OAAA,CAAA2C,aAAA,CAAClD,YAAA,CAAAmD,IAAI,EAAA7B,QAAA,KAAKkB,KAAK;IAAED,KAAK,EAAE,CAACa,MAAM,CAACC,SAAS,EAAEd,KAAK;EAAE,IAC/CF,iBAAiB,CAACiB,GAAG,CAAC,CAACC,GAAG,EAAEC,KAAK,KAAK;IACrC,IAAIC,MAAM,GAAIF,GAAG,GAAGd,MAAM,GAAIP,MAAM;IACpC,IAAIwB,MAAM,CAACC,KAAK,CAACF,MAAM,CAAC,IAAIA,MAAM,GAAG,CAAC,EAAE;MACtC;MACAA,MAAM,GAAG,CAAC;IACZ;IACA,oBAAO5D,MAAA,CAAAU,OAAA,CAAA2C,aAAA,CAAClD,YAAA,CAAAmD,IAAI;MAACtB,GAAG,EAAE2B,KAAM;MAACjB,KAAK,EAAE,CAACa,MAAM,CAACQ,GAAG,EAAE;QAAEH,MAAM,EAAEA;MAAO,CAAC;IAAE,CAAE,CAAC;EACtE,CAAC,CAAC,EACDR,SAAS,IAAI,IAAI,IAAI,CAACS,MAAM,CAACC,KAAK,CAACV,SAAS,CAAC,iBAC5CpD,MAAA,CAAAU,OAAA,CAAA2C,aAAA,CAAClD,YAAA,CAAAmD,IAAI;IAACZ,KAAK,EAAEa,MAAM,CAACS;EAAgB,gBAClChE,MAAA,CAAAU,OAAA,CAAA2C,aAAA,CAAClD,YAAA,CAAA8D,IAAI;IAACvB,KAAK,EAAEa,MAAM,CAACW;EAAK,GAAEhB,IAAI,CAACiB,KAAK,CAACf,SAAS,CAAC,EAAC,MAAU,CACvD,CAEJ,CAAC;AAEX;AAEA,MAAMG,MAAM,GAAGa,uBAAU,CAACC,MAAM,CAAC;EAC/Bb,SAAS,EAAE;IACTc,KAAK,EAAElC,KAAK;IACZwB,MAAM,EAAEvB,MAAM;IACdkC,eAAe,EAAE,oBAAoB;IACrCC,aAAa,EAAE,KAAK;IACpBC,cAAc,EAAE,UAAU;IAC1BC,UAAU,EAAE,UAAU;IACtBC,YAAY,EAAE,CAAC;IACfC,QAAQ,EAAE;EACZ,CAAC;EACDb,GAAG,EAAE;IACHO,KAAK,EAAEhC,SAAS;IAChBsB,MAAM,EAAE,CAAC;IACTW,eAAe,EAAE;EACnB,CAAC;EACDP,eAAe,EAAE;IACf,GAAGI,uBAAU,CAACS,kBAAkB;IAChCJ,cAAc,EAAE,QAAQ;IACxBC,UAAU,EAAE;EACd,CAAC;EACDR,IAAI,EAAE;IACJY,QAAQ,EAAE,UAAU;IACpBC,UAAU,EAAE,MAAM;IAClBC,QAAQ,EAAE,EAAE;IACZC,KAAK,EAAE;EACT;AACF,CAAC,CAAC"} diff --git a/package/lib/commonjs/JSIHelper.js b/package/lib/commonjs/JSIHelper.js new file mode 100644 index 0000000000..66c4b8b96b --- /dev/null +++ b/package/lib/commonjs/JSIHelper.js @@ -0,0 +1,15 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.assertJSIAvailable = assertJSIAvailable; +var _CameraError = require("./CameraError"); +function assertJSIAvailable() { + // Check if we are running on-device (JSI) + // @ts-expect-error JSI functions aren't typed + if (global.nativeCallSyncHook == null) { + throw new _CameraError.CameraRuntimeError('system/frame-processors-unavailable', 'Failed to initialize VisionCamera Frame Processors: React Native is not running on-device. Frame Processors can only be used when synchronous method invocations (JSI) are possible. If you are using a remote debugger (e.g. Chrome), switch to an on-device debugger (e.g. Flipper) instead.'); + } +} +//# sourceMappingURL=JSIHelper.js.map \ No newline at end of file diff --git a/package/lib/commonjs/JSIHelper.js.map b/package/lib/commonjs/JSIHelper.js.map new file mode 100644 index 0000000000..ee6510d421 --- /dev/null +++ b/package/lib/commonjs/JSIHelper.js.map @@ -0,0 +1 @@ +{"version":3,"names":["_CameraError","require","assertJSIAvailable","global","nativeCallSyncHook","CameraRuntimeError"],"sourceRoot":"../../src","sources":["JSIHelper.ts"],"mappings":";;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AAEO,SAASC,kBAAkBA,CAAA,EAAS;EACzC;EACA;EACA,IAAIC,MAAM,CAACC,kBAAkB,IAAI,IAAI,EAAE;IACrC,MAAM,IAAIC,+BAAkB,CAC1B,qCAAqC,EACrC,gSACF,CAAC;EACH;AACF"} diff --git a/package/lib/commonjs/NativeCameraModule.js b/package/lib/commonjs/NativeCameraModule.js new file mode 100644 index 0000000000..f56e786688 --- /dev/null +++ b/package/lib/commonjs/NativeCameraModule.js @@ -0,0 +1,39 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.CameraModule = void 0; +var _reactNative = require("react-native"); +var _CameraError = require("./CameraError"); +const supportedPlatforms = ['ios', 'android', 'macos']; + +// NativeModules automatically resolves 'CameraView' to 'CameraViewModule' +// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment +const CameraModule = exports.CameraModule = _reactNative.NativeModules.CameraView; +if (CameraModule == null) { + if (!supportedPlatforms.includes(_reactNative.Platform.OS)) { + throw new _CameraError.CameraRuntimeError('system/camera-module-not-found', `Failed to initialize VisionCamera: VisionCamera currently does not work on ${_reactNative.Platform.OS}.`); + } + let message = 'Failed to initialize VisionCamera: The native Camera Module (`NativeModules.CameraView`) could not be found.'; + message += '\n* Make sure react-native-vision-camera is correctly autolinked (run `npx react-native config` to verify)'; + if (_reactNative.Platform.OS === 'ios' || _reactNative.Platform.OS === 'macos') message += '\n* Make sure you ran `pod install` in the ios/ directory.'; + if (_reactNative.Platform.OS === 'android') message += '\n* Make sure gradle is synced.'; + + // check if Expo + // @ts-expect-error expo global JSI modules are not typed + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const ExpoConstants = global.expo?.modules?.ExponentConstants; + if (ExpoConstants != null) { + if (ExpoConstants.appOwnership === 'expo') { + // We're running Expo Go + throw new _CameraError.CameraRuntimeError('system/camera-module-not-found', `react-native-vision-camera is not supported in Expo Go! Use EAS/expo prebuild instead (\`expo run:${_reactNative.Platform.OS}\`). For more info, see https://docs.expo.dev/workflow/prebuild/.`); + } else { + // We're running Expo bare / standalone + message += '\n* Make sure you ran `expo prebuild`.'; + } + } + message += '\n* Make sure you rebuilt the app.'; + throw new _CameraError.CameraRuntimeError('system/camera-module-not-found', message); +} +//# sourceMappingURL=NativeCameraModule.js.map \ No newline at end of file diff --git a/package/lib/commonjs/NativeCameraModule.js.map b/package/lib/commonjs/NativeCameraModule.js.map new file mode 100644 index 0000000000..ce8fb5f11b --- /dev/null +++ b/package/lib/commonjs/NativeCameraModule.js.map @@ -0,0 +1 @@ +{"version":3,"names":["_reactNative","require","_CameraError","supportedPlatforms","CameraModule","exports","NativeModules","CameraView","includes","Platform","OS","CameraRuntimeError","message","ExpoConstants","global","expo","modules","ExponentConstants","appOwnership"],"sourceRoot":"../../src","sources":["NativeCameraModule.ts"],"mappings":";;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AACA,IAAAC,YAAA,GAAAD,OAAA;AAEA,MAAME,kBAAkB,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,CAAC;;AAEtD;AACA;AACO,MAAMC,YAAY,GAAAC,OAAA,CAAAD,YAAA,GAAGE,0BAAa,CAACC,UAAU;AACpD,IAAIH,YAAY,IAAI,IAAI,EAAE;EACxB,IAAI,CAACD,kBAAkB,CAACK,QAAQ,CAACC,qBAAQ,CAACC,EAAE,CAAC,EAAE;IAC7C,MAAM,IAAIC,+BAAkB,CAC1B,gCAAgC,EAC/B,8EAA6EF,qBAAQ,CAACC,EAAG,GAC5F,CAAC;EACH;EAEA,IAAIE,OAAO,GAAG,8GAA8G;EAC5HA,OAAO,IAAI,4GAA4G;EACvH,IAAIH,qBAAQ,CAACC,EAAE,KAAK,KAAK,IAAID,qBAAQ,CAACC,EAAE,KAAK,OAAO,EAAEE,OAAO,IAAI,4DAA4D;EAE7H,IAAIH,qBAAQ,CAACC,EAAE,KAAK,SAAS,EAAEE,OAAO,IAAI,iCAAiC;;EAE3E;EACA;EACA;EACA,MAAMC,aAAa,GAAGC,MAAM,CAACC,IAAI,EAAEC,OAAO,EAAEC,iBAAiB;EAC7D,IAAIJ,aAAa,IAAI,IAAI,EAAE;IACzB,IAAIA,aAAa,CAACK,YAAY,KAAK,MAAM,EAAE;MACzC;MACA,MAAM,IAAIP,+BAAkB,CAC1B,gCAAgC,EAC/B,qGAAoGF,qBAAQ,CAACC,EAAG,mEACnH,CAAC;IACH,CAAC,MAAM;MACL;MACAE,OAAO,IAAI,wCAAwC;IACrD;EACF;EAEAA,OAAO,IAAI,oCAAoC;EAC/C,MAAM,IAAID,+BAAkB,CAAC,gCAAgC,EAAEC,OAAO,CAAC;AACzE"} diff --git a/package/lib/commonjs/NativeCameraView.js b/package/lib/commonjs/NativeCameraView.js new file mode 100644 index 0000000000..7a3adc787d --- /dev/null +++ b/package/lib/commonjs/NativeCameraView.js @@ -0,0 +1,10 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.NativeCameraView = void 0; +var _reactNative = require("react-native"); +// requireNativeComponent automatically resolves 'CameraView' to 'CameraViewManager' +const NativeCameraView = exports.NativeCameraView = (0, _reactNative.requireNativeComponent)('CameraView'); +//# sourceMappingURL=NativeCameraView.js.map \ No newline at end of file diff --git a/package/lib/commonjs/NativeCameraView.js.map b/package/lib/commonjs/NativeCameraView.js.map new file mode 100644 index 0000000000..17014ad9e8 --- /dev/null +++ b/package/lib/commonjs/NativeCameraView.js.map @@ -0,0 +1 @@ +{"version":3,"names":["_reactNative","require","NativeCameraView","exports","requireNativeComponent"],"sourceRoot":"../../src","sources":["NativeCameraView.ts"],"mappings":";;;;;;AACA,IAAAA,YAAA,GAAAC,OAAA;AA0DA;AACO,MAAMC,gBAAgB,GAAAC,OAAA,CAAAD,gBAAA,GAAG,IAAAE,mCAAsB,EAAwB,YAAY,CAAC"} diff --git a/package/lib/commonjs/RotationHelper.js b/package/lib/commonjs/RotationHelper.js new file mode 100644 index 0000000000..13eee346eb --- /dev/null +++ b/package/lib/commonjs/RotationHelper.js @@ -0,0 +1,50 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.RotationHelper = void 0; +function orientationToDegrees(orientation) { + switch (orientation) { + case 'portrait': + return 0; + case 'landscape-right': + return 90; + case 'portrait-upside-down': + return 180; + case 'landscape-left': + return 270; + } +} +class RotationHelper { + /** + * Gets or sets the current preview orientation. + */ + previewOrientation = 'portrait'; + /** + * Gets or sets the current output orientation. + */ + outputOrientation = 'portrait'; + + /** + * Gets the current target rotation (in degrees) that needs to be applied + * to all UI elements so they appear up-right. + */ + get uiRotation() { + const previewDegrees = orientationToDegrees(this.previewOrientation); + const outputDegrees = orientationToDegrees(this.outputOrientation); + const diffDegrees = (outputDegrees - previewDegrees) % 360; + if (diffDegrees < -180) { + // Changes e.g. -270 to +90, so it is a shorter rotation on UI + return diffDegrees + 360; + } else if (diffDegrees > 180) { + // Changes e.g. +270 to -90, so it is a shorter rotation on UI + return diffDegrees - 360; + } else { + // It is a short rotation already, return it + return diffDegrees; + } + } +} +exports.RotationHelper = RotationHelper; +//# sourceMappingURL=RotationHelper.js.map \ No newline at end of file diff --git a/package/lib/commonjs/RotationHelper.js.map b/package/lib/commonjs/RotationHelper.js.map new file mode 100644 index 0000000000..c5b4bc2c97 --- /dev/null +++ b/package/lib/commonjs/RotationHelper.js.map @@ -0,0 +1 @@ +{"version":3,"names":["orientationToDegrees","orientation","RotationHelper","previewOrientation","outputOrientation","uiRotation","previewDegrees","outputDegrees","diffDegrees","exports"],"sourceRoot":"../../src","sources":["RotationHelper.ts"],"mappings":";;;;;;AAEA,SAASA,oBAAoBA,CAACC,WAAwB,EAAU;EAC9D,QAAQA,WAAW;IACjB,KAAK,UAAU;MACb,OAAO,CAAC;IACV,KAAK,iBAAiB;MACpB,OAAO,EAAE;IACX,KAAK,sBAAsB;MACzB,OAAO,GAAG;IACZ,KAAK,gBAAgB;MACnB,OAAO,GAAG;EACd;AACF;AAEO,MAAMC,cAAc,CAAC;EAC1B;AACF;AACA;EACEC,kBAAkB,GAAgB,UAAU;EAC5C;AACF;AACA;EACEC,iBAAiB,GAAgB,UAAU;;EAE3C;AACF;AACA;AACA;EACE,IAAIC,UAAUA,CAAA,EAAW;IACvB,MAAMC,cAAc,GAAGN,oBAAoB,CAAC,IAAI,CAACG,kBAAkB,CAAC;IACpE,MAAMI,aAAa,GAAGP,oBAAoB,CAAC,IAAI,CAACI,iBAAiB,CAAC;IAClE,MAAMI,WAAW,GAAG,CAACD,aAAa,GAAGD,cAAc,IAAI,GAAG;IAE1D,IAAIE,WAAW,GAAG,CAAC,GAAG,EAAE;MACtB;MACA,OAAOA,WAAW,GAAG,GAAG;IAC1B,CAAC,MAAM,IAAIA,WAAW,GAAG,GAAG,EAAE;MAC5B;MACA,OAAOA,WAAW,GAAG,GAAG;IAC1B,CAAC,MAAM;MACL;MACA,OAAOA,WAAW;IACpB;EACF;AACF;AAACC,OAAA,CAAAP,cAAA,GAAAA,cAAA"} diff --git a/package/lib/commonjs/dependencies/ModuleProxy.js b/package/lib/commonjs/dependencies/ModuleProxy.js new file mode 100644 index 0000000000..cfd96bb203 --- /dev/null +++ b/package/lib/commonjs/dependencies/ModuleProxy.js @@ -0,0 +1,43 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.createModuleProxy = exports.OptionalDependencyNotInstalledError = void 0; +/** + * Create a lazily-imported module proxy. + * This is useful for lazily requiring optional dependencies. + */ +const createModuleProxy = getModule => { + const holder = { + module: undefined + }; + const proxy = new Proxy(holder, { + get: (target, property) => { + if (property === '$$typeof') { + // If inlineRequires is enabled, Metro will look up all imports + // with the $$typeof operator. In this case, this will throw the + // `OptionalDependencyNotInstalledError` error because we try to access the module + // even though we are not using it (Metro does it), so instead we return undefined + // to bail out of inlineRequires here. + // See https://github.com/mrousavy/react-native-vision-camera/pull/2953 + return undefined; + } + if (target.module == null) { + // lazy initialize module via require() + // caller needs to make sure the require() call is wrapped in a try/catch + target.module = getModule(); + } + return target.module[property]; + } + }); + return proxy; +}; +exports.createModuleProxy = createModuleProxy; +class OptionalDependencyNotInstalledError extends Error { + constructor(name) { + super(`${name} is not installed!`); + } +} +exports.OptionalDependencyNotInstalledError = OptionalDependencyNotInstalledError; +//# sourceMappingURL=ModuleProxy.js.map \ No newline at end of file diff --git a/package/lib/commonjs/dependencies/ModuleProxy.js.map b/package/lib/commonjs/dependencies/ModuleProxy.js.map new file mode 100644 index 0000000000..dd580164ec --- /dev/null +++ b/package/lib/commonjs/dependencies/ModuleProxy.js.map @@ -0,0 +1 @@ +{"version":3,"names":["createModuleProxy","getModule","holder","module","undefined","proxy","Proxy","get","target","property","exports","OptionalDependencyNotInstalledError","Error","constructor","name"],"sourceRoot":"../../../src","sources":["dependencies/ModuleProxy.ts"],"mappings":";;;;;;AAEA;AACA;AACA;AACA;AACO,MAAMA,iBAAiB,GAAaC,SAA2B,IAAc;EAClF,MAAMC,MAAuC,GAAG;IAAEC,MAAM,EAAEC;EAAU,CAAC;EAErE,MAAMC,KAAK,GAAG,IAAIC,KAAK,CAACJ,MAAM,EAAE;IAC9BK,GAAG,EAAEA,CAACC,MAAM,EAAEC,QAAQ,KAAK;MACzB,IAAIA,QAAQ,KAAK,UAAU,EAAE;QAC3B;QACA;QACA;QACA;QACA;QACA;QACA,OAAOL,SAAS;MAClB;MAEA,IAAII,MAAM,CAACL,MAAM,IAAI,IAAI,EAAE;QACzB;QACA;QACAK,MAAM,CAACL,MAAM,GAAGF,SAAS,CAAC,CAAY;MACxC;MACA,OAAOO,MAAM,CAACL,MAAM,CAACM,QAAQ,CAA+B;IAC9D;EACF,CAAC,CAAC;EACF,OAAOJ,KAAK;AACd,CAAC;AAAAK,OAAA,CAAAV,iBAAA,GAAAA,iBAAA;AAEM,MAAMW,mCAAmC,SAASC,KAAK,CAAC;EAC7DC,WAAWA,CAACC,IAAY,EAAE;IACxB,KAAK,CAAE,GAAEA,IAAK,oBAAmB,CAAC;EACpC;AACF;AAACJ,OAAA,CAAAC,mCAAA,GAAAA,mCAAA"} diff --git a/package/lib/commonjs/dependencies/ReanimatedProxy.js b/package/lib/commonjs/dependencies/ReanimatedProxy.js new file mode 100644 index 0000000000..618f3387ec --- /dev/null +++ b/package/lib/commonjs/dependencies/ReanimatedProxy.js @@ -0,0 +1,22 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.ReanimatedProxy = void 0; +var _ModuleProxy = require("./ModuleProxy"); +/** + * A proxy object that lazy-imports react-native-reanimated as soon as the + * caller tries to access a property on {@linkcode ReanimatedProxy}. + * + * If react-native-reanimated is not installed, accessing anything on + * {@linkcode ReanimatedProxy} will throw. + */ +const ReanimatedProxy = exports.ReanimatedProxy = (0, _ModuleProxy.createModuleProxy)(() => { + try { + return require('react-native-reanimated'); + } catch (e) { + throw new _ModuleProxy.OptionalDependencyNotInstalledError('react-native-reanimated'); + } +}); +//# sourceMappingURL=ReanimatedProxy.js.map \ No newline at end of file diff --git a/package/lib/commonjs/dependencies/ReanimatedProxy.js.map b/package/lib/commonjs/dependencies/ReanimatedProxy.js.map new file mode 100644 index 0000000000..ec983bb120 --- /dev/null +++ b/package/lib/commonjs/dependencies/ReanimatedProxy.js.map @@ -0,0 +1 @@ +{"version":3,"names":["_ModuleProxy","require","ReanimatedProxy","exports","createModuleProxy","e","OptionalDependencyNotInstalledError"],"sourceRoot":"../../../src","sources":["dependencies/ReanimatedProxy.ts"],"mappings":";;;;;;AACA,IAAAA,YAAA,GAAAC,OAAA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAMC,eAAe,GAAAC,OAAA,CAAAD,eAAA,GAAG,IAAAE,8BAAiB,EAAc,MAAM;EAClE,IAAI;IACF,OAAOH,OAAO,CAAC,yBAAyB,CAAC;EAC3C,CAAC,CAAC,OAAOI,CAAC,EAAE;IACV,MAAM,IAAIC,gDAAmC,CAAC,yBAAyB,CAAC;EAC1E;AACF,CAAC,CAAC"} diff --git a/package/lib/commonjs/dependencies/SkiaProxy.js b/package/lib/commonjs/dependencies/SkiaProxy.js new file mode 100644 index 0000000000..7841f7d146 --- /dev/null +++ b/package/lib/commonjs/dependencies/SkiaProxy.js @@ -0,0 +1,22 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.SkiaProxy = void 0; +var _ModuleProxy = require("./ModuleProxy"); +/** + * A proxy object that lazy-imports @shopify/react-native-skia as soon as the + * caller tries to access a property on {@linkcode SkiaProxy}. + * + * If @shopify/react-native-skia is not installed, accessing anything on + * {@linkcode SkiaProxy} will throw. + */ +const SkiaProxy = exports.SkiaProxy = (0, _ModuleProxy.createModuleProxy)(() => { + try { + return require('@shopify/react-native-skia'); + } catch (e) { + throw new _ModuleProxy.OptionalDependencyNotInstalledError('@shopify/react-native-skia'); + } +}); +//# sourceMappingURL=SkiaProxy.js.map \ No newline at end of file diff --git a/package/lib/commonjs/dependencies/SkiaProxy.js.map b/package/lib/commonjs/dependencies/SkiaProxy.js.map new file mode 100644 index 0000000000..10d4bda6a0 --- /dev/null +++ b/package/lib/commonjs/dependencies/SkiaProxy.js.map @@ -0,0 +1 @@ +{"version":3,"names":["_ModuleProxy","require","SkiaProxy","exports","createModuleProxy","e","OptionalDependencyNotInstalledError"],"sourceRoot":"../../../src","sources":["dependencies/SkiaProxy.ts"],"mappings":";;;;;;AACA,IAAAA,YAAA,GAAAC,OAAA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAMC,SAAS,GAAAC,OAAA,CAAAD,SAAA,GAAG,IAAAE,8BAAiB,EAAQ,MAAM;EACtD,IAAI;IACF,OAAOH,OAAO,CAAC,4BAA4B,CAAC;EAC9C,CAAC,CAAC,OAAOI,CAAC,EAAE;IACV,MAAM,IAAIC,gDAAmC,CAAC,4BAA4B,CAAC;EAC7E;AACF,CAAC,CAAC"} diff --git a/package/lib/commonjs/dependencies/WorkletsProxy.js b/package/lib/commonjs/dependencies/WorkletsProxy.js new file mode 100644 index 0000000000..3cd29b4d88 --- /dev/null +++ b/package/lib/commonjs/dependencies/WorkletsProxy.js @@ -0,0 +1,22 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.WorkletsProxy = void 0; +var _ModuleProxy = require("./ModuleProxy"); +/** + * A proxy object that lazy-imports react-native-worklets-core as soon as the + * caller tries to access a property on {@linkcode WorkletsProxy}. + * + * If react-native-worklets-core is not installed, accessing anything on + * {@linkcode WorkletsProxy} will throw. + */ +const WorkletsProxy = exports.WorkletsProxy = (0, _ModuleProxy.createModuleProxy)(() => { + try { + return require('react-native-worklets-core'); + } catch (e) { + throw new _ModuleProxy.OptionalDependencyNotInstalledError('react-native-worklets-core'); + } +}); +//# sourceMappingURL=WorkletsProxy.js.map \ No newline at end of file diff --git a/package/lib/commonjs/dependencies/WorkletsProxy.js.map b/package/lib/commonjs/dependencies/WorkletsProxy.js.map new file mode 100644 index 0000000000..f6fc5bde1f --- /dev/null +++ b/package/lib/commonjs/dependencies/WorkletsProxy.js.map @@ -0,0 +1 @@ +{"version":3,"names":["_ModuleProxy","require","WorkletsProxy","exports","createModuleProxy","e","OptionalDependencyNotInstalledError"],"sourceRoot":"../../../src","sources":["dependencies/WorkletsProxy.ts"],"mappings":";;;;;;AACA,IAAAA,YAAA,GAAAC,OAAA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAMC,aAAa,GAAAC,OAAA,CAAAD,aAAA,GAAG,IAAAE,8BAAiB,EAAY,MAAM;EAC9D,IAAI;IACF,OAAOH,OAAO,CAAC,4BAA4B,CAAC;EAC9C,CAAC,CAAC,OAAOI,CAAC,EAAE;IACV,MAAM,IAAIC,gDAAmC,CAAC,4BAA4B,CAAC;EAC7E;AACF,CAAC,CAAC"} diff --git a/package/lib/commonjs/devices/Templates.js b/package/lib/commonjs/devices/Templates.js new file mode 100644 index 0000000000..22b6a36408 --- /dev/null +++ b/package/lib/commonjs/devices/Templates.js @@ -0,0 +1,106 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.Templates = void 0; +var _reactNative = require("react-native"); +const SnapchatResolution = { + width: 1920, + height: 1080 +}; +const InstagramResolution = { + width: 3840, + height: 2160 +}; +const ScreenAspectRatio = _reactNative.Dimensions.get('window').height / _reactNative.Dimensions.get('window').width; + +/** + * Predefined templates for use in `useCameraFormat`/`getCameraFormat`. + * @example + * ```ts + * const format = useCameraFormat(device, Templates.Snapchat) + * ``` + */ +const Templates = exports.Templates = { + /** + * Highest resolution video recordings (e.g. 4k) + */ + Video: [{ + videoResolution: 'max' + }], + /** + * High resolution 60 FPS video recordings (e.g. 1080@60 FPS) + */ + Video60Fps: [{ + fps: 60 + }, { + videoResolution: 'max' + }], + /** + * High-FPS video recordings (e.g. 720@240 FPS) + */ + VideoSlowMotion: [{ + fps: 240 + }, { + videoResolution: 'max' + }], + /** + * High resolution video recordings with cinematic video stabilization + */ + VideoStabilized: [{ + videoResolution: 'max' + }, { + videoStabilizationMode: 'cinematic-extended' + }], + /** + * Highest resolution photo capture (e.g. 4k) + */ + Photo: [{ + photoResolution: 'max' + }], + /** + * Highest resolution photo capture with portrait screen aspect ratio (e.g. 4k) + */ + PhotoPortrait: [{ + photoResolution: 'max' + }, { + photoAspectRatio: ScreenAspectRatio + }], + /** + * HD-quality for faster Frame Processing (e.g. 720p) + */ + FrameProcessing: [{ + videoResolution: { + width: 1080, + height: 720 + } + }], + /** + * Snapchat-style video recordings and photo capture + * Targets Full HD-quality for lower file sizes and portrait screen aspect ratio. + */ + Snapchat: [{ + videoAspectRatio: ScreenAspectRatio + }, { + videoResolution: SnapchatResolution + }, { + photoAspectRatio: ScreenAspectRatio + }, { + photoResolution: SnapchatResolution + }], + /** + * Instagram-style video recordings and photo capture. + * Targets 4k-quality and portrait screen aspect ratio. + */ + Instagram: [{ + videoAspectRatio: ScreenAspectRatio + }, { + videoResolution: InstagramResolution + }, { + photoAspectRatio: ScreenAspectRatio + }, { + photoResolution: InstagramResolution + }] +}; +//# sourceMappingURL=Templates.js.map \ No newline at end of file diff --git a/package/lib/commonjs/devices/Templates.js.map b/package/lib/commonjs/devices/Templates.js.map new file mode 100644 index 0000000000..f6cc9b0a02 --- /dev/null +++ b/package/lib/commonjs/devices/Templates.js.map @@ -0,0 +1 @@ +{"version":3,"names":["_reactNative","require","SnapchatResolution","width","height","InstagramResolution","ScreenAspectRatio","Dimensions","get","Templates","exports","Video","videoResolution","Video60Fps","fps","VideoSlowMotion","VideoStabilized","videoStabilizationMode","Photo","photoResolution","PhotoPortrait","photoAspectRatio","FrameProcessing","Snapchat","videoAspectRatio","Instagram"],"sourceRoot":"../../../src","sources":["devices/Templates.ts"],"mappings":";;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AAcA,MAAMC,kBAAkB,GAAG;EAAEC,KAAK,EAAE,IAAI;EAAEC,MAAM,EAAE;AAAK,CAAC;AACxD,MAAMC,mBAAmB,GAAG;EAAEF,KAAK,EAAE,IAAI;EAAEC,MAAM,EAAE;AAAK,CAAC;AACzD,MAAME,iBAAiB,GAAGC,uBAAU,CAACC,GAAG,CAAC,QAAQ,CAAC,CAACJ,MAAM,GAAGG,uBAAU,CAACC,GAAG,CAAC,QAAQ,CAAC,CAACL,KAAK;;AAE1F;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAMM,SAAsD,GAAAC,OAAA,CAAAD,SAAA,GAAG;EACpE;AACF;AACA;EACEE,KAAK,EAAE,CAAC;IAAEC,eAAe,EAAE;EAAM,CAAC,CAAC;EACnC;AACF;AACA;EACEC,UAAU,EAAE,CAAC;IAAEC,GAAG,EAAE;EAAG,CAAC,EAAE;IAAEF,eAAe,EAAE;EAAM,CAAC,CAAC;EACrD;AACF;AACA;EACEG,eAAe,EAAE,CAAC;IAAED,GAAG,EAAE;EAAI,CAAC,EAAE;IAAEF,eAAe,EAAE;EAAM,CAAC,CAAC;EAC3D;AACF;AACA;EACEI,eAAe,EAAE,CAAC;IAAEJ,eAAe,EAAE;EAAM,CAAC,EAAE;IAAEK,sBAAsB,EAAE;EAAqB,CAAC,CAAC;EAC/F;AACF;AACA;EACEC,KAAK,EAAE,CAAC;IAAEC,eAAe,EAAE;EAAM,CAAC,CAAC;EACnC;AACF;AACA;EACEC,aAAa,EAAE,CAAC;IAAED,eAAe,EAAE;EAAM,CAAC,EAAE;IAAEE,gBAAgB,EAAEf;EAAkB,CAAC,CAAC;EACpF;AACF;AACA;EACEgB,eAAe,EAAE,CAAC;IAAEV,eAAe,EAAE;MAAET,KAAK,EAAE,IAAI;MAAEC,MAAM,EAAE;IAAI;EAAE,CAAC,CAAC;EACpE;AACF;AACA;AACA;EACEmB,QAAQ,EAAE,CACR;IAAEC,gBAAgB,EAAElB;EAAkB,CAAC,EACvC;IAAEM,eAAe,EAAEV;EAAmB,CAAC,EACvC;IAAEmB,gBAAgB,EAAEf;EAAkB,CAAC,EACvC;IAAEa,eAAe,EAAEjB;EAAmB,CAAC,CACxC;EACD;AACF;AACA;AACA;EACEuB,SAAS,EAAE,CACT;IAAED,gBAAgB,EAAElB;EAAkB,CAAC,EACvC;IAAEM,eAAe,EAAEP;EAAoB,CAAC,EACxC;IAAEgB,gBAAgB,EAAEf;EAAkB,CAAC,EACvC;IAAEa,eAAe,EAAEd;EAAoB,CAAC;AAE5C,CAAC"} diff --git a/package/lib/commonjs/devices/getCameraDevice.js b/package/lib/commonjs/devices/getCameraDevice.js new file mode 100644 index 0000000000..498fa6cade --- /dev/null +++ b/package/lib/commonjs/devices/getCameraDevice.js @@ -0,0 +1,55 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.getCameraDevice = getCameraDevice; +/** + * Get the best matching Camera device that best satisfies your requirements using a sorting filter, or `undefined` if {@linkcode devices} does not contain any devices. + * @param position The position of the Camera device relative to the phone. + * @param filter The filter you want to use. The Camera device that matches your filter the closest will be returned + * @returns The Camera device that matches your filter the closest, or `undefined` if no such Camera Device exists on the given {@linkcode position}. + * @example + * ```ts + * const devices = Camera.getAvailableCameraDevices() + * const device = getCameraDevice(devices, 'back', { + * physicalDevices: ['wide-angle-camera'] + * }) + * ``` + */ +function getCameraDevice(devices, position, filter = {}) { + const filtered = devices.filter(d => d.position === position); + let bestDevice = filtered[0]; + if (bestDevice == null) return undefined; + + // Compare each device using a point scoring system + for (const device of filtered) { + let leftPoints = 0; + let rightPoints = 0; + + // prefer higher hardware-level + if (bestDevice.hardwareLevel === 'full') leftPoints += 4; + if (device.hardwareLevel === 'full') rightPoints += 4; + if (filter.physicalDevices != null) { + // user did pass a physical device filter, two possible scenarios: + // 1. user wants all cameras ([ultra-wide, wide, tele]) to zoom. prefer those devices that have all 3 cameras. + // 2. user wants only one ([wide]) for faster performance. prefer those devices that only have one camera, if they have more, we rank them lower. + for (const d of bestDevice.physicalDevices) { + if (filter.physicalDevices.includes(d)) leftPoints += 1;else leftPoints -= 1; + } + for (const d of device.physicalDevices) { + if (filter.physicalDevices.includes(d)) rightPoints += 1;else rightPoints -= 1; + } + } else { + // user did not pass a physical device filter. prefer wide-angle-camera as a default + if (bestDevice.physicalDevices.includes('wide-angle-camera')) leftPoints += 2; + if (device.physicalDevices.includes('wide-angle-camera')) rightPoints += 2; + // if we have more than one device, we rank it lower. we only want a simple camera + if (bestDevice.physicalDevices.length > device.physicalDevices.length) leftPoints -= 1; + if (device.physicalDevices.length > bestDevice.physicalDevices.length) rightPoints -= 1; + } + if (rightPoints > leftPoints) bestDevice = device; + } + return bestDevice; +} +//# sourceMappingURL=getCameraDevice.js.map \ No newline at end of file diff --git a/package/lib/commonjs/devices/getCameraDevice.js.map b/package/lib/commonjs/devices/getCameraDevice.js.map new file mode 100644 index 0000000000..683afdc8b3 --- /dev/null +++ b/package/lib/commonjs/devices/getCameraDevice.js.map @@ -0,0 +1 @@ +{"version":3,"names":["getCameraDevice","devices","position","filter","filtered","d","bestDevice","undefined","device","leftPoints","rightPoints","hardwareLevel","physicalDevices","includes","length"],"sourceRoot":"../../../src","sources":["devices/getCameraDevice.ts"],"mappings":";;;;;;AAwBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASA,eAAeA,CAACC,OAAuB,EAAEC,QAAwB,EAAEC,MAAoB,GAAG,CAAC,CAAC,EAA4B;EACtI,MAAMC,QAAQ,GAAGH,OAAO,CAACE,MAAM,CAAEE,CAAC,IAAKA,CAAC,CAACH,QAAQ,KAAKA,QAAQ,CAAC;EAE/D,IAAII,UAAU,GAAGF,QAAQ,CAAC,CAAC,CAAC;EAC5B,IAAIE,UAAU,IAAI,IAAI,EAAE,OAAOC,SAAS;;EAExC;EACA,KAAK,MAAMC,MAAM,IAAIJ,QAAQ,EAAE;IAC7B,IAAIK,UAAU,GAAG,CAAC;IAClB,IAAIC,WAAW,GAAG,CAAC;;IAEnB;IACA,IAAIJ,UAAU,CAACK,aAAa,KAAK,MAAM,EAAEF,UAAU,IAAI,CAAC;IACxD,IAAID,MAAM,CAACG,aAAa,KAAK,MAAM,EAAED,WAAW,IAAI,CAAC;IAErD,IAAIP,MAAM,CAACS,eAAe,IAAI,IAAI,EAAE;MAClC;MACA;MACA;MACA,KAAK,MAAMP,CAAC,IAAIC,UAAU,CAACM,eAAe,EAAE;QAC1C,IAAIT,MAAM,CAACS,eAAe,CAACC,QAAQ,CAACR,CAAC,CAAC,EAAEI,UAAU,IAAI,CAAC,MAClDA,UAAU,IAAI,CAAC;MACtB;MACA,KAAK,MAAMJ,CAAC,IAAIG,MAAM,CAACI,eAAe,EAAE;QACtC,IAAIT,MAAM,CAACS,eAAe,CAACC,QAAQ,CAACR,CAAC,CAAC,EAAEK,WAAW,IAAI,CAAC,MACnDA,WAAW,IAAI,CAAC;MACvB;IACF,CAAC,MAAM;MACL;MACA,IAAIJ,UAAU,CAACM,eAAe,CAACC,QAAQ,CAAC,mBAAmB,CAAC,EAAEJ,UAAU,IAAI,CAAC;MAC7E,IAAID,MAAM,CAACI,eAAe,CAACC,QAAQ,CAAC,mBAAmB,CAAC,EAAEH,WAAW,IAAI,CAAC;MAC1E;MACA,IAAIJ,UAAU,CAACM,eAAe,CAACE,MAAM,GAAGN,MAAM,CAACI,eAAe,CAACE,MAAM,EAAEL,UAAU,IAAI,CAAC;MACtF,IAAID,MAAM,CAACI,eAAe,CAACE,MAAM,GAAGR,UAAU,CAACM,eAAe,CAACE,MAAM,EAAEJ,WAAW,IAAI,CAAC;IACzF;IAEA,IAAIA,WAAW,GAAGD,UAAU,EAAEH,UAAU,GAAGE,MAAM;EACnD;EAEA,OAAOF,UAAU;AACnB"} diff --git a/package/lib/commonjs/devices/getCameraFormat.js b/package/lib/commonjs/devices/getCameraFormat.js new file mode 100644 index 0000000000..ae0c8f8a78 --- /dev/null +++ b/package/lib/commonjs/devices/getCameraFormat.js @@ -0,0 +1,160 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.getCameraFormat = getCameraFormat; +var _CameraError = require("../CameraError"); +function filtersToFilterMap(filters) { + return filters.reduce((map, curr, index) => { + for (const key in curr) { + // @ts-expect-error keys are untyped + map[key] = { + // @ts-expect-error keys are untyped + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + target: curr[key], + priority: filters.length - index + }; + } + return map; + }, {}); +} + +/** + * Get the best matching Camera format for the given device that satisfies your requirements using a sorting filter. By default, formats are sorted by highest to lowest resolution. + * + * The {@linkcode filters | filters} are ranked by priority, from highest to lowest. + * This means the first item you pass will have a higher priority than the second, and so on. + * + * @param device The Camera Device you're currently using + * @param filters The filters you want to use. The format that matches your filter the closest will be returned + * @returns The format that matches your filter the closest. + * + * @example + * ```ts + * const format = getCameraFormat(device, [ + * { videoResolution: { width: 3048, height: 2160 } }, + * { fps: 60 } + * ]) + * ``` + */ +function getCameraFormat(device, filters) { + // Combine filters into a single filter map for constant-time lookup + const filter = filtersToFilterMap(filters); + let bestFormat = device.formats[0]; + if (bestFormat == null) throw new _CameraError.CameraRuntimeError('device/invalid-device', `The given Camera Device (${device.id}) does not have any formats!`); + + // Compare each format using a point scoring system + for (const format of device.formats) { + let leftPoints = 0; + let rightPoints = 0; + + // Video Resolution + if (filter.videoResolution != null) { + const leftVideoResolution = bestFormat.videoWidth * bestFormat.videoHeight; + const rightVideoResolution = format.videoWidth * format.videoHeight; + if (filter.videoResolution.target === 'max') { + // We just want the maximum resolution + if (leftVideoResolution > rightVideoResolution) leftPoints += filter.videoResolution.priority; + if (rightVideoResolution > leftVideoResolution) rightPoints += filter.videoResolution.priority; + } else { + // Find video resolution closest to the filter (ignoring orientation) + const targetResolution = filter.videoResolution.target.width * filter.videoResolution.target.height; + const leftDiff = Math.abs(leftVideoResolution - targetResolution); + const rightDiff = Math.abs(rightVideoResolution - targetResolution); + if (leftDiff < rightDiff) leftPoints += filter.videoResolution.priority; + if (rightDiff < leftDiff) rightPoints += filter.videoResolution.priority; + } + } + + // Photo Resolution + if (filter.photoResolution != null) { + const leftPhotoResolution = bestFormat.photoWidth * bestFormat.photoHeight; + const rightPhotoResolution = format.photoWidth * format.photoHeight; + if (filter.photoResolution.target === 'max') { + // We just want the maximum resolution + if (leftPhotoResolution > rightPhotoResolution) leftPoints += filter.photoResolution.priority; + if (rightPhotoResolution > leftPhotoResolution) rightPoints += filter.photoResolution.priority; + } else { + // Find closest photo resolution to the filter (ignoring orientation) + const targetResolution = filter.photoResolution.target.width * filter.photoResolution.target.height; + const leftDiff = Math.abs(leftPhotoResolution - targetResolution); + const rightDiff = Math.abs(rightPhotoResolution - targetResolution); + if (leftDiff < rightDiff) leftPoints += filter.photoResolution.priority; + if (rightDiff < leftDiff) rightPoints += filter.photoResolution.priority; + } + } + + // Find closest aspect ratio (video) + if (filter.videoAspectRatio != null) { + const leftAspect = bestFormat.videoWidth / bestFormat.videoHeight; + const rightAspect = format.videoWidth / format.videoHeight; + const leftDiff = Math.abs(leftAspect - filter.videoAspectRatio.target); + const rightDiff = Math.abs(rightAspect - filter.videoAspectRatio.target); + if (leftDiff < rightDiff) leftPoints += filter.videoAspectRatio.priority; + if (rightDiff < leftDiff) rightPoints += filter.videoAspectRatio.priority; + } + + // Find closest aspect ratio (photo) + if (filter.photoAspectRatio != null) { + const leftAspect = bestFormat.photoWidth / bestFormat.photoHeight; + const rightAspect = format.photoWidth / format.photoHeight; + const leftDiff = Math.abs(leftAspect - filter.photoAspectRatio.target); + const rightDiff = Math.abs(rightAspect - filter.photoAspectRatio.target); + if (leftDiff < rightDiff) leftPoints += filter.photoAspectRatio.priority; + if (rightDiff < leftDiff) rightPoints += filter.photoAspectRatio.priority; + } + + // Find closest max FPS + if (filter.fps != null) { + if (filter.fps.target === 'max') { + if (bestFormat.maxFps > format.maxFps) leftPoints += filter.fps.priority; + if (format.maxFps > bestFormat.maxFps) rightPoints += filter.fps.priority; + } else { + if (bestFormat.maxFps >= filter.fps.target) leftPoints += filter.fps.priority; + if (format.maxFps >= filter.fps.target) rightPoints += filter.fps.priority; + } + } + + // Find closest ISO + if (filter.iso != null) { + if (filter.iso.target === 'max') { + if (bestFormat.maxISO > format.maxISO) leftPoints += filter.iso.priority; + if (format.maxISO > bestFormat.maxISO) rightPoints += filter.iso.priority; + } else if (filter.iso.target === 'min') { + if (bestFormat.minISO < format.minISO) leftPoints += filter.iso.priority; + if (format.minISO < bestFormat.minISO) rightPoints += filter.iso.priority; + } else { + if (filter.iso.target >= bestFormat.minISO && filter.iso.target <= bestFormat.maxISO) leftPoints += filter.iso.priority; + if (filter.iso.target >= format.minISO && filter.iso.target <= format.maxISO) rightPoints += filter.iso.priority; + } + } + + // Find video stabilization mode + if (filter.videoStabilizationMode != null) { + if (bestFormat.videoStabilizationModes.includes(filter.videoStabilizationMode.target)) leftPoints += filter.videoStabilizationMode.priority; + if (format.videoStabilizationModes.includes(filter.videoStabilizationMode.target)) rightPoints += filter.videoStabilizationMode.priority; + } + + // Find Photo HDR formats + if (filter.photoHdr != null) { + if (bestFormat.supportsPhotoHdr === filter.photoHdr.target) leftPoints += filter.photoHdr.priority; + if (format.supportsPhotoHdr === filter.photoHdr.target) rightPoints += filter.photoHdr.priority; + } + + // Find Video HDR formats + if (filter.videoHdr != null) { + if (bestFormat.supportsVideoHdr === filter.videoHdr.target) leftPoints += filter.videoHdr.priority; + if (format.supportsVideoHdr === filter.videoHdr.target) rightPoints += filter.videoHdr.priority; + } + + // Find matching AF system + if (filter.autoFocusSystem != null) { + if (bestFormat.autoFocusSystem === filter.autoFocusSystem.target) leftPoints += filter.autoFocusSystem.priority; + if (format.autoFocusSystem === filter.autoFocusSystem.target) rightPoints += filter.autoFocusSystem.priority; + } + if (rightPoints > leftPoints) bestFormat = format; + } + return bestFormat; +} +//# sourceMappingURL=getCameraFormat.js.map \ No newline at end of file diff --git a/package/lib/commonjs/devices/getCameraFormat.js.map b/package/lib/commonjs/devices/getCameraFormat.js.map new file mode 100644 index 0000000000..74a383b50f --- /dev/null +++ b/package/lib/commonjs/devices/getCameraFormat.js.map @@ -0,0 +1 @@ +{"version":3,"names":["_CameraError","require","filtersToFilterMap","filters","reduce","map","curr","index","key","target","priority","length","getCameraFormat","device","filter","bestFormat","formats","CameraRuntimeError","id","format","leftPoints","rightPoints","videoResolution","leftVideoResolution","videoWidth","videoHeight","rightVideoResolution","targetResolution","width","height","leftDiff","Math","abs","rightDiff","photoResolution","leftPhotoResolution","photoWidth","photoHeight","rightPhotoResolution","videoAspectRatio","leftAspect","rightAspect","photoAspectRatio","fps","maxFps","iso","maxISO","minISO","videoStabilizationMode","videoStabilizationModes","includes","photoHdr","supportsPhotoHdr","videoHdr","supportsVideoHdr","autoFocusSystem"],"sourceRoot":"../../../src","sources":["devices/getCameraFormat.ts"],"mappings":"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"} diff --git a/package/lib/commonjs/expo-plugin/@types.js b/package/lib/commonjs/expo-plugin/@types.js new file mode 100644 index 0000000000..389ea6fee6 --- /dev/null +++ b/package/lib/commonjs/expo-plugin/@types.js @@ -0,0 +1,2 @@ +"use strict"; +//# sourceMappingURL=@types.js.map \ No newline at end of file diff --git a/package/lib/commonjs/expo-plugin/@types.js.map b/package/lib/commonjs/expo-plugin/@types.js.map new file mode 100644 index 0000000000..02dff7e44e --- /dev/null +++ b/package/lib/commonjs/expo-plugin/@types.js.map @@ -0,0 +1 @@ +{"version":3,"names":[],"sourceRoot":"../../../src","sources":["expo-plugin/@types.ts"],"mappings":""} diff --git a/package/lib/commonjs/expo-plugin/withAndroidMLKitVisionModel.js b/package/lib/commonjs/expo-plugin/withAndroidMLKitVisionModel.js new file mode 100644 index 0000000000..44bdf60bed --- /dev/null +++ b/package/lib/commonjs/expo-plugin/withAndroidMLKitVisionModel.js @@ -0,0 +1,28 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.withAndroidMLKitVisionModel = void 0; +var _configPlugins = require("@expo/config-plugins"); +/** + * Set the `VisionCamera_enableCodeScanner` value in the static `gradle.properties` file. + * This is used to add the full MLKit dependency to the project. + */ +const withAndroidMLKitVisionModel = c => { + const key = 'VisionCamera_enableCodeScanner'; + return (0, _configPlugins.withGradleProperties)(c, config => { + config.modResults = config.modResults.filter(item => { + if (item.type === 'property' && item.key === key) return false; + return true; + }); + config.modResults.push({ + type: 'property', + key: key, + value: 'true' + }); + return config; + }); +}; +exports.withAndroidMLKitVisionModel = withAndroidMLKitVisionModel; +//# sourceMappingURL=withAndroidMLKitVisionModel.js.map \ No newline at end of file diff --git a/package/lib/commonjs/expo-plugin/withAndroidMLKitVisionModel.js.map b/package/lib/commonjs/expo-plugin/withAndroidMLKitVisionModel.js.map new file mode 100644 index 0000000000..8f80372bba --- /dev/null +++ b/package/lib/commonjs/expo-plugin/withAndroidMLKitVisionModel.js.map @@ -0,0 +1 @@ +{"version":3,"names":["_configPlugins","require","withAndroidMLKitVisionModel","c","key","withGradleProperties","config","modResults","filter","item","type","push","value","exports"],"sourceRoot":"../../../src","sources":["expo-plugin/withAndroidMLKitVisionModel.ts"],"mappings":";;;;;;AACA,IAAAA,cAAA,GAAAC,OAAA;AAGA;AACA;AACA;AACA;AACO,MAAMC,2BAAsD,GAAIC,CAAC,IAAK;EAC3E,MAAMC,GAAG,GAAG,gCAAgC;EAC5C,OAAO,IAAAC,mCAAoB,EAACF,CAAC,EAAGG,MAAM,IAAK;IACzCA,MAAM,CAACC,UAAU,GAAGD,MAAM,CAACC,UAAU,CAACC,MAAM,CAAEC,IAAI,IAAK;MACrD,IAAIA,IAAI,CAACC,IAAI,KAAK,UAAU,IAAID,IAAI,CAACL,GAAG,KAAKA,GAAG,EAAE,OAAO,KAAK;MAC9D,OAAO,IAAI;IACb,CAAC,CAAC;IAEFE,MAAM,CAACC,UAAU,CAACI,IAAI,CAAC;MACrBD,IAAI,EAAE,UAAU;MAChBN,GAAG,EAAEA,GAAG;MACRQ,KAAK,EAAE;IACT,CAAC,CAAC;IAEF,OAAON,MAAM;EACf,CAAC,CAAC;AACJ,CAAC;AAAAO,OAAA,CAAAX,2BAAA,GAAAA,2BAAA"} diff --git a/package/lib/commonjs/expo-plugin/withEnableFrameProcessorsAndroid.js b/package/lib/commonjs/expo-plugin/withEnableFrameProcessorsAndroid.js new file mode 100644 index 0000000000..2522cd0963 --- /dev/null +++ b/package/lib/commonjs/expo-plugin/withEnableFrameProcessorsAndroid.js @@ -0,0 +1,28 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.withEnableFrameProcessorsAndroid = void 0; +var _configPlugins = require("@expo/config-plugins"); +/** + * Set the `VisionCamera_enableFrameProcessors` value in the static `gradle.properties` file. + * This is used to disable frame processors if you don't need it for android. + */ +const withEnableFrameProcessorsAndroid = (c, enableFrameProcessors) => { + const enableFrameProcessorsKey = 'VisionCamera_enableFrameProcessors'; + return (0, _configPlugins.withGradleProperties)(c, config => { + config.modResults = config.modResults.filter(item => { + if (item.type === 'property' && item.key === enableFrameProcessorsKey) return false; + return true; + }); + config.modResults.push({ + type: 'property', + key: enableFrameProcessorsKey, + value: String(enableFrameProcessors) + }); + return config; + }); +}; +exports.withEnableFrameProcessorsAndroid = withEnableFrameProcessorsAndroid; +//# sourceMappingURL=withEnableFrameProcessorsAndroid.js.map \ No newline at end of file diff --git a/package/lib/commonjs/expo-plugin/withEnableFrameProcessorsAndroid.js.map b/package/lib/commonjs/expo-plugin/withEnableFrameProcessorsAndroid.js.map new file mode 100644 index 0000000000..27467c637d --- /dev/null +++ b/package/lib/commonjs/expo-plugin/withEnableFrameProcessorsAndroid.js.map @@ -0,0 +1 @@ +{"version":3,"names":["_configPlugins","require","withEnableFrameProcessorsAndroid","c","enableFrameProcessors","enableFrameProcessorsKey","withGradleProperties","config","modResults","filter","item","type","key","push","value","String","exports"],"sourceRoot":"../../../src","sources":["expo-plugin/withEnableFrameProcessorsAndroid.ts"],"mappings":";;;;;;AACA,IAAAA,cAAA,GAAAC,OAAA;AAEA;AACA;AACA;AACA;AACO,MAAMC,gCAAuD,GAAGA,CAACC,CAAC,EAAEC,qBAAqB,KAAK;EACnG,MAAMC,wBAAwB,GAAG,oCAAoC;EACrE,OAAO,IAAAC,mCAAoB,EAACH,CAAC,EAAGI,MAAM,IAAK;IACzCA,MAAM,CAACC,UAAU,GAAGD,MAAM,CAACC,UAAU,CAACC,MAAM,CAAEC,IAAI,IAAK;MACrD,IAAIA,IAAI,CAACC,IAAI,KAAK,UAAU,IAAID,IAAI,CAACE,GAAG,KAAKP,wBAAwB,EAAE,OAAO,KAAK;MACnF,OAAO,IAAI;IACb,CAAC,CAAC;IAEFE,MAAM,CAACC,UAAU,CAACK,IAAI,CAAC;MACrBF,IAAI,EAAE,UAAU;MAChBC,GAAG,EAAEP,wBAAwB;MAC7BS,KAAK,EAAEC,MAAM,CAACX,qBAAqB;IACrC,CAAC,CAAC;IAEF,OAAOG,MAAM;EACf,CAAC,CAAC;AACJ,CAAC;AAAAS,OAAA,CAAAd,gCAAA,GAAAA,gCAAA"} diff --git a/package/lib/commonjs/expo-plugin/withEnableFrameProcessorsIOS.js b/package/lib/commonjs/expo-plugin/withEnableFrameProcessorsIOS.js new file mode 100644 index 0000000000..7db3a490b3 --- /dev/null +++ b/package/lib/commonjs/expo-plugin/withEnableFrameProcessorsIOS.js @@ -0,0 +1,20 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.withEnableFrameProcessorsIOS = void 0; +var _configPlugins = require("@expo/config-plugins"); +var _writeToPodfile = require("./writeToPodfile"); +/** + * Set the `enableFrameProcessors` flag inside of the XcodeProject. + * This is used to disable frame processors if you don't need it on iOS. (will save CPU and Memory) + */ +const withEnableFrameProcessorsIOS = (c, enableFrameProcessors) => { + return (0, _configPlugins.withDangerousMod)(c, ['ios', config => { + (0, _writeToPodfile.writeToPodfile)(config.modRequest.projectRoot, '$VCEnableFrameProcessors', String(enableFrameProcessors)); + return config; + }]); +}; +exports.withEnableFrameProcessorsIOS = withEnableFrameProcessorsIOS; +//# sourceMappingURL=withEnableFrameProcessorsIOS.js.map \ No newline at end of file diff --git a/package/lib/commonjs/expo-plugin/withEnableFrameProcessorsIOS.js.map b/package/lib/commonjs/expo-plugin/withEnableFrameProcessorsIOS.js.map new file mode 100644 index 0000000000..0b6749cd96 --- /dev/null +++ b/package/lib/commonjs/expo-plugin/withEnableFrameProcessorsIOS.js.map @@ -0,0 +1 @@ +{"version":3,"names":["_configPlugins","require","_writeToPodfile","withEnableFrameProcessorsIOS","c","enableFrameProcessors","withDangerousMod","config","writeToPodfile","modRequest","projectRoot","String","exports"],"sourceRoot":"../../../src","sources":["expo-plugin/withEnableFrameProcessorsIOS.ts"],"mappings":";;;;;;AACA,IAAAA,cAAA,GAAAC,OAAA;AACA,IAAAC,eAAA,GAAAD,OAAA;AAEA;AACA;AACA;AACA;AACO,MAAME,4BAAmD,GAAGA,CAACC,CAAC,EAAEC,qBAAqB,KAAK;EAC/F,OAAO,IAAAC,+BAAgB,EAACF,CAAC,EAAE,CACzB,KAAK,EACJG,MAAM,IAAK;IACV,IAAAC,8BAAc,EAACD,MAAM,CAACE,UAAU,CAACC,WAAW,EAAE,0BAA0B,EAAEC,MAAM,CAACN,qBAAqB,CAAC,CAAC;IACxG,OAAOE,MAAM;EACf,CAAC,CACF,CAAC;AACJ,CAAC;AAAAK,OAAA,CAAAT,4BAAA,GAAAA,4BAAA"} diff --git a/package/lib/commonjs/expo-plugin/withEnableLocationIOS.js b/package/lib/commonjs/expo-plugin/withEnableLocationIOS.js new file mode 100644 index 0000000000..6bc688750f --- /dev/null +++ b/package/lib/commonjs/expo-plugin/withEnableLocationIOS.js @@ -0,0 +1,22 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.withEnableLocationIOS = void 0; +var _configPlugins = require("@expo/config-plugins"); +var _writeToPodfile = require("./writeToPodfile"); +/** + * Set the `enableLocation` flag inside of the XcodeProject. + * This is used to enable location APIs. + * If location is disabled, the CLLocation APIs are not used in the codebase. + * This is useful if you don't use Location and apple review is unhappy about CLLocation usage. + */ +const withEnableLocationIOS = (c, enableLocation) => { + return (0, _configPlugins.withDangerousMod)(c, ['ios', config => { + (0, _writeToPodfile.writeToPodfile)(config.modRequest.projectRoot, '$VCEnableLocation', String(enableLocation)); + return config; + }]); +}; +exports.withEnableLocationIOS = withEnableLocationIOS; +//# sourceMappingURL=withEnableLocationIOS.js.map \ No newline at end of file diff --git a/package/lib/commonjs/expo-plugin/withEnableLocationIOS.js.map b/package/lib/commonjs/expo-plugin/withEnableLocationIOS.js.map new file mode 100644 index 0000000000..fbe78a7131 --- /dev/null +++ b/package/lib/commonjs/expo-plugin/withEnableLocationIOS.js.map @@ -0,0 +1 @@ +{"version":3,"names":["_configPlugins","require","_writeToPodfile","withEnableLocationIOS","c","enableLocation","withDangerousMod","config","writeToPodfile","modRequest","projectRoot","String","exports"],"sourceRoot":"../../../src","sources":["expo-plugin/withEnableLocationIOS.ts"],"mappings":";;;;;;AACA,IAAAA,cAAA,GAAAC,OAAA;AACA,IAAAC,eAAA,GAAAD,OAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACO,MAAME,qBAA4C,GAAGA,CAACC,CAAC,EAAEC,cAAc,KAAK;EACjF,OAAO,IAAAC,+BAAgB,EAACF,CAAC,EAAE,CACzB,KAAK,EACJG,MAAM,IAAK;IACV,IAAAC,8BAAc,EAACD,MAAM,CAACE,UAAU,CAACC,WAAW,EAAE,mBAAmB,EAAEC,MAAM,CAACN,cAAc,CAAC,CAAC;IAC1F,OAAOE,MAAM;EACf,CAAC,CACF,CAAC;AACJ,CAAC;AAAAK,OAAA,CAAAT,qBAAA,GAAAA,qBAAA"} diff --git a/package/lib/commonjs/expo-plugin/withVisionCamera.js b/package/lib/commonjs/expo-plugin/withVisionCamera.js new file mode 100644 index 0000000000..a1707b8c12 --- /dev/null +++ b/package/lib/commonjs/expo-plugin/withVisionCamera.js @@ -0,0 +1,46 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; +var _configPlugins = require("@expo/config-plugins"); +var _withEnableFrameProcessorsAndroid = require("./withEnableFrameProcessorsAndroid"); +var _withEnableFrameProcessorsIOS = require("./withEnableFrameProcessorsIOS"); +var _withAndroidMLKitVisionModel = require("./withAndroidMLKitVisionModel"); +var _withEnableLocationIOS = require("./withEnableLocationIOS"); +// eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-assignment +const pkg = require('../../../package.json'); +const CAMERA_USAGE = 'Allow $(PRODUCT_NAME) to access your camera'; +const MICROPHONE_USAGE = 'Allow $(PRODUCT_NAME) to access your microphone'; +const LOCATION_USAGE = 'Allow $(PRODUCT_NAME) to access your location'; +const withCamera = (config, props = {}) => { + if (config.ios == null) config.ios = {}; + if (config.ios.infoPlist == null) config.ios.infoPlist = {}; + // Camera permission + config.ios.infoPlist.NSCameraUsageDescription = props.cameraPermissionText ?? config.ios.infoPlist.NSCameraUsageDescription ?? CAMERA_USAGE; + if (props.enableMicrophonePermission) { + // Microphone permission + config.ios.infoPlist.NSMicrophoneUsageDescription = props.microphonePermissionText ?? config.ios.infoPlist.NSMicrophoneUsageDescription ?? MICROPHONE_USAGE; + } + if (props.enableLocation) { + // Location permission + config.ios.infoPlist.NSLocationWhenInUseUsageDescription = props.locationPermissionText ?? config.ios.infoPlist.NSLocationWhenInUseUsageDescription ?? LOCATION_USAGE; + } + const androidPermissions = ['android.permission.CAMERA']; + if (props.enableMicrophonePermission) androidPermissions.push('android.permission.RECORD_AUDIO'); + if (props.enableLocation) androidPermissions.push('android.permission.ACCESS_FINE_LOCATION'); + if (props.enableLocation != null) { + // set Podfile property to build location-related stuff + config = (0, _withEnableLocationIOS.withEnableLocationIOS)(config, props.enableLocation); + } + if (props.enableFrameProcessors != null) { + // set Podfile property to build frame-processor-related stuff + config = (0, _withEnableFrameProcessorsAndroid.withEnableFrameProcessorsAndroid)(config, props.enableFrameProcessors); + config = (0, _withEnableFrameProcessorsIOS.withEnableFrameProcessorsIOS)(config, props.enableFrameProcessors); + } + if (props.enableCodeScanner) config = (0, _withAndroidMLKitVisionModel.withAndroidMLKitVisionModel)(config, props); + return (0, _configPlugins.withPlugins)(config, [[_configPlugins.AndroidConfig.Permissions.withPermissions, androidPermissions]]); +}; +var _default = exports.default = (0, _configPlugins.createRunOncePlugin)(withCamera, pkg.name, pkg.version); +//# sourceMappingURL=withVisionCamera.js.map \ No newline at end of file diff --git a/package/lib/commonjs/expo-plugin/withVisionCamera.js.map b/package/lib/commonjs/expo-plugin/withVisionCamera.js.map new file mode 100644 index 0000000000..b57d735995 --- /dev/null +++ b/package/lib/commonjs/expo-plugin/withVisionCamera.js.map @@ -0,0 +1 @@ +{"version":3,"names":["_configPlugins","require","_withEnableFrameProcessorsAndroid","_withEnableFrameProcessorsIOS","_withAndroidMLKitVisionModel","_withEnableLocationIOS","pkg","CAMERA_USAGE","MICROPHONE_USAGE","LOCATION_USAGE","withCamera","config","props","ios","infoPlist","NSCameraUsageDescription","cameraPermissionText","enableMicrophonePermission","NSMicrophoneUsageDescription","microphonePermissionText","enableLocation","NSLocationWhenInUseUsageDescription","locationPermissionText","androidPermissions","push","withEnableLocationIOS","enableFrameProcessors","withEnableFrameProcessorsAndroid","withEnableFrameProcessorsIOS","enableCodeScanner","withAndroidMLKitVisionModel","withPlugins","AndroidConfig","Permissions","withPermissions","_default","exports","default","createRunOncePlugin","name","version"],"sourceRoot":"../../../src","sources":["expo-plugin/withVisionCamera.ts"],"mappings":";;;;;;AACA,IAAAA,cAAA,GAAAC,OAAA;AACA,IAAAC,iCAAA,GAAAD,OAAA;AACA,IAAAE,6BAAA,GAAAF,OAAA;AACA,IAAAG,4BAAA,GAAAH,OAAA;AAEA,IAAAI,sBAAA,GAAAJ,OAAA;AACA;AACA,MAAMK,GAAG,GAAGL,OAAO,CAAC,uBAAuB,CAAC;AAE5C,MAAMM,YAAY,GAAG,6CAA6C;AAClE,MAAMC,gBAAgB,GAAG,iDAAiD;AAC1E,MAAMC,cAAc,GAAG,+CAA+C;AAEtE,MAAMC,UAAqC,GAAGA,CAACC,MAAM,EAAEC,KAAK,GAAG,CAAC,CAAC,KAAK;EACpE,IAAID,MAAM,CAACE,GAAG,IAAI,IAAI,EAAEF,MAAM,CAACE,GAAG,GAAG,CAAC,CAAC;EACvC,IAAIF,MAAM,CAACE,GAAG,CAACC,SAAS,IAAI,IAAI,EAAEH,MAAM,CAACE,GAAG,CAACC,SAAS,GAAG,CAAC,CAAC;EAC3D;EACAH,MAAM,CAACE,GAAG,CAACC,SAAS,CAACC,wBAAwB,GAC3CH,KAAK,CAACI,oBAAoB,IAAKL,MAAM,CAACE,GAAG,CAACC,SAAS,CAACC,wBAA+C,IAAIR,YAAY;EACrH,IAAIK,KAAK,CAACK,0BAA0B,EAAE;IACpC;IACAN,MAAM,CAACE,GAAG,CAACC,SAAS,CAACI,4BAA4B,GAC/CN,KAAK,CAACO,wBAAwB,IAAKR,MAAM,CAACE,GAAG,CAACC,SAAS,CAACI,4BAAmD,IAAIV,gBAAgB;EACnI;EACA,IAAII,KAAK,CAACQ,cAAc,EAAE;IACxB;IACAT,MAAM,CAACE,GAAG,CAACC,SAAS,CAACO,mCAAmC,GACtDT,KAAK,CAACU,sBAAsB,IAAKX,MAAM,CAACE,GAAG,CAACC,SAAS,CAACO,mCAA0D,IAAIZ,cAAc;EACtI;EACA,MAAMc,kBAAkB,GAAG,CAAC,2BAA2B,CAAC;EACxD,IAAIX,KAAK,CAACK,0BAA0B,EAAEM,kBAAkB,CAACC,IAAI,CAAC,iCAAiC,CAAC;EAChG,IAAIZ,KAAK,CAACQ,cAAc,EAAEG,kBAAkB,CAACC,IAAI,CAAC,yCAAyC,CAAC;EAE5F,IAAIZ,KAAK,CAACQ,cAAc,IAAI,IAAI,EAAE;IAChC;IACAT,MAAM,GAAG,IAAAc,4CAAqB,EAACd,MAAM,EAAEC,KAAK,CAACQ,cAAc,CAAC;EAC9D;EACA,IAAIR,KAAK,CAACc,qBAAqB,IAAI,IAAI,EAAE;IACvC;IACAf,MAAM,GAAG,IAAAgB,kEAAgC,EAAChB,MAAM,EAAEC,KAAK,CAACc,qBAAqB,CAAC;IAC9Ef,MAAM,GAAG,IAAAiB,0DAA4B,EAACjB,MAAM,EAAEC,KAAK,CAACc,qBAAqB,CAAC;EAC5E;EAEA,IAAId,KAAK,CAACiB,iBAAiB,EAAElB,MAAM,GAAG,IAAAmB,wDAA2B,EAACnB,MAAM,EAAEC,KAAK,CAAC;EAEhF,OAAO,IAAAmB,0BAAW,EAACpB,MAAM,EAAE,CAAC,CAACqB,4BAAa,CAACC,WAAW,CAACC,eAAe,EAAEX,kBAAkB,CAAC,CAAC,CAAC;AAC/F,CAAC;AAAA,IAAAY,QAAA,GAAAC,OAAA,CAAAC,OAAA,GAEc,IAAAC,kCAAmB,EAAC5B,UAAU,EAAEJ,GAAG,CAACiC,IAAI,EAAEjC,GAAG,CAACkC,OAAO,CAAC"} diff --git a/package/lib/commonjs/expo-plugin/writeToPodfile.js b/package/lib/commonjs/expo-plugin/writeToPodfile.js new file mode 100644 index 0000000000..90c4e621bf --- /dev/null +++ b/package/lib/commonjs/expo-plugin/writeToPodfile.js @@ -0,0 +1,23 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.writeToPodfile = writeToPodfile; +var _fs = _interopRequireDefault(require("fs")); +var _path = _interopRequireDefault(require("path")); +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } +function writeToPodfile(projectRoot, key, value) { + const podfilePath = _path.default.join(projectRoot, 'ios', 'Podfile'); + // get Podfile content as individual lines + let lines = _fs.default.readFileSync(podfilePath, 'utf8').split('\n'); + // filter out any lines where the given key is already set + lines = lines.filter(l => !l.includes(key)); + // set the key as the first item in the array so its at the top of the file + lines.unshift(`${key}=${value}`); + + // write the file back + const fileContent = lines.join('\n'); + _fs.default.writeFileSync(podfilePath, fileContent, 'utf8'); +} +//# sourceMappingURL=writeToPodfile.js.map \ No newline at end of file diff --git a/package/lib/commonjs/expo-plugin/writeToPodfile.js.map b/package/lib/commonjs/expo-plugin/writeToPodfile.js.map new file mode 100644 index 0000000000..a03d88bc33 --- /dev/null +++ b/package/lib/commonjs/expo-plugin/writeToPodfile.js.map @@ -0,0 +1 @@ +{"version":3,"names":["_fs","_interopRequireDefault","require","_path","obj","__esModule","default","writeToPodfile","projectRoot","key","value","podfilePath","path","join","lines","fs","readFileSync","split","filter","l","includes","unshift","fileContent","writeFileSync"],"sourceRoot":"../../../src","sources":["expo-plugin/writeToPodfile.ts"],"mappings":";;;;;;AAAA,IAAAA,GAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,KAAA,GAAAF,sBAAA,CAAAC,OAAA;AAAuB,SAAAD,uBAAAG,GAAA,WAAAA,GAAA,IAAAA,GAAA,CAAAC,UAAA,GAAAD,GAAA,KAAAE,OAAA,EAAAF,GAAA;AAEhB,SAASG,cAAcA,CAACC,WAAmB,EAAEC,GAAW,EAAEC,KAAa,EAAQ;EACpF,MAAMC,WAAW,GAAGC,aAAI,CAACC,IAAI,CAACL,WAAW,EAAE,KAAK,EAAE,SAAS,CAAC;EAC5D;EACA,IAAIM,KAAK,GAAGC,WAAE,CAACC,YAAY,CAACL,WAAW,EAAE,MAAM,CAAC,CAACM,KAAK,CAAC,IAAI,CAAC;EAC5D;EACAH,KAAK,GAAGA,KAAK,CAACI,MAAM,CAAEC,CAAC,IAAK,CAACA,CAAC,CAACC,QAAQ,CAACX,GAAG,CAAC,CAAC;EAC7C;EACAK,KAAK,CAACO,OAAO,CAAE,GAAEZ,GAAI,IAAGC,KAAM,EAAC,CAAC;;EAEhC;EACA,MAAMY,WAAW,GAAGR,KAAK,CAACD,IAAI,CAAC,IAAI,CAAC;EACpCE,WAAE,CAACQ,aAAa,CAACZ,WAAW,EAAEW,WAAW,EAAE,MAAM,CAAC;AACpD"} diff --git a/package/lib/commonjs/frame-processors/FrameProcessorsUnavailableError.js b/package/lib/commonjs/frame-processors/FrameProcessorsUnavailableError.js new file mode 100644 index 0000000000..ec7e001eaf --- /dev/null +++ b/package/lib/commonjs/frame-processors/FrameProcessorsUnavailableError.js @@ -0,0 +1,14 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.FrameProcessorsUnavailableError = void 0; +var _CameraError = require("../CameraError"); +class FrameProcessorsUnavailableError extends _CameraError.CameraRuntimeError { + constructor(reason) { + super('system/frame-processors-unavailable', 'Frame Processors are not available, react-native-worklets-core is not installed! ' + `Error: ${reason instanceof Error ? reason.message : reason}`); + } +} +exports.FrameProcessorsUnavailableError = FrameProcessorsUnavailableError; +//# sourceMappingURL=FrameProcessorsUnavailableError.js.map \ No newline at end of file diff --git a/package/lib/commonjs/frame-processors/FrameProcessorsUnavailableError.js.map b/package/lib/commonjs/frame-processors/FrameProcessorsUnavailableError.js.map new file mode 100644 index 0000000000..89d0e6cd37 --- /dev/null +++ b/package/lib/commonjs/frame-processors/FrameProcessorsUnavailableError.js.map @@ -0,0 +1 @@ +{"version":3,"names":["_CameraError","require","FrameProcessorsUnavailableError","CameraRuntimeError","constructor","reason","Error","message","exports"],"sourceRoot":"../../../src","sources":["frame-processors/FrameProcessorsUnavailableError.ts"],"mappings":";;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AAEO,MAAMC,+BAA+B,SAASC,+BAAkB,CAAC;EACtEC,WAAWA,CAACC,MAAe,EAAE;IAC3B,KAAK,CACH,qCAAqC,EACrC,mFAAmF,GAChF,UAASA,MAAM,YAAYC,KAAK,GAAGD,MAAM,CAACE,OAAO,GAAGF,MAAO,EAChE,CAAC;EACH;AACF;AAACG,OAAA,CAAAN,+BAAA,GAAAA,+BAAA"} diff --git a/package/lib/commonjs/frame-processors/VisionCameraProxy.js b/package/lib/commonjs/frame-processors/VisionCameraProxy.js new file mode 100644 index 0000000000..fbbf9fcd59 --- /dev/null +++ b/package/lib/commonjs/frame-processors/VisionCameraProxy.js @@ -0,0 +1,50 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.VisionCameraProxy = void 0; +var _NativeCameraModule = require("../NativeCameraModule"); +var _FrameProcessorsUnavailableError = require("./FrameProcessorsUnavailableError"); +/** + * An initialized native instance of a FrameProcessorPlugin. + * All memory allocated by this plugin will be deleted once this value goes out of scope. + */ + +let proxy; +try { + // 1. Load react-native-worklets-core + require('react-native-worklets-core'); + // 2. If react-native-worklets-core could be loaded, try to install Frame Processor bindings + const result = _NativeCameraModule.CameraModule.installFrameProcessorBindings(); + if (result !== true) throw new Error(`Failed to install Frame Processor JSI bindings! installFrameProcessorBindings() returned ${result}`); + + // 3. Get global.VisionCameraProxy which was just installed by installFrameProcessorBindings() + // @ts-expect-error it's a global JSI variable injected by native + const globalProxy = global.VisionCameraProxy; + if (globalProxy == null) throw new Error('global.VisionCameraProxy is not installed! Was installFrameProcessorBindings() called?'); + proxy = globalProxy; +} catch (e) { + // global.VisionCameraProxy is not injected! + // Just use dummy implementations that will throw when the user tries to use Frame Processors. + proxy = { + initFrameProcessorPlugin: () => { + throw new _FrameProcessorsUnavailableError.FrameProcessorsUnavailableError(e); + }, + removeFrameProcessor: () => { + throw new _FrameProcessorsUnavailableError.FrameProcessorsUnavailableError(e); + }, + setFrameProcessor: () => { + throw new _FrameProcessorsUnavailableError.FrameProcessorsUnavailableError(e); + }, + workletContext: undefined + }; +} + +/** + * The JSI Proxy for the Frame Processors Runtime. + * + * This will be replaced with a CxxTurboModule in the future. + */ +const VisionCameraProxy = exports.VisionCameraProxy = proxy; +//# sourceMappingURL=VisionCameraProxy.js.map \ No newline at end of file diff --git a/package/lib/commonjs/frame-processors/VisionCameraProxy.js.map b/package/lib/commonjs/frame-processors/VisionCameraProxy.js.map new file mode 100644 index 0000000000..7a7451361b --- /dev/null +++ b/package/lib/commonjs/frame-processors/VisionCameraProxy.js.map @@ -0,0 +1 @@ +{"version":3,"names":["_NativeCameraModule","require","_FrameProcessorsUnavailableError","proxy","result","CameraModule","installFrameProcessorBindings","Error","globalProxy","global","VisionCameraProxy","e","initFrameProcessorPlugin","FrameProcessorsUnavailableError","removeFrameProcessor","setFrameProcessor","workletContext","undefined","exports"],"sourceRoot":"../../../src","sources":["frame-processors/VisionCameraProxy.ts"],"mappings":";;;;;;AACA,IAAAA,mBAAA,GAAAC,OAAA;AAEA,IAAAC,gCAAA,GAAAD,OAAA;AAKA;AACA;AACA;AACA;;AA4CA,IAAIE,KAAyB;AAE7B,IAAI;EACF;EACAF,OAAO,CAAC,4BAA4B,CAAC;EACrC;EACA,MAAMG,MAAM,GAAGC,gCAAY,CAACC,6BAA6B,CAAC,CAAY;EACtE,IAAIF,MAAM,KAAK,IAAI,EAAE,MAAM,IAAIG,KAAK,CAAE,4FAA2FH,MAAO,EAAC,CAAC;;EAE1I;EACA;EACA,MAAMI,WAAW,GAAGC,MAAM,CAACC,iBAAmD;EAC9E,IAAIF,WAAW,IAAI,IAAI,EAAE,MAAM,IAAID,KAAK,CAAC,wFAAwF,CAAC;EAElIJ,KAAK,GAAGK,WAAW;AACrB,CAAC,CAAC,OAAOG,CAAC,EAAE;EACV;EACA;EACAR,KAAK,GAAG;IACNS,wBAAwB,EAAEA,CAAA,KAAM;MAC9B,MAAM,IAAIC,gEAA+B,CAACF,CAAC,CAAC;IAC9C,CAAC;IACDG,oBAAoB,EAAEA,CAAA,KAAM;MAC1B,MAAM,IAAID,gEAA+B,CAACF,CAAC,CAAC;IAC9C,CAAC;IACDI,iBAAiB,EAAEA,CAAA,KAAM;MACvB,MAAM,IAAIF,gEAA+B,CAACF,CAAC,CAAC;IAC9C,CAAC;IACDK,cAAc,EAAEC;EAClB,CAAC;AACH;;AAEA;AACA;AACA;AACA;AACA;AACO,MAAMP,iBAAiB,GAAAQ,OAAA,CAAAR,iBAAA,GAAGP,KAAK"} diff --git a/package/lib/commonjs/frame-processors/runAsync.js b/package/lib/commonjs/frame-processors/runAsync.js new file mode 100644 index 0000000000..22717ccf2d --- /dev/null +++ b/package/lib/commonjs/frame-processors/runAsync.js @@ -0,0 +1,105 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.runAsync = runAsync; +var _WorkletsProxy = require("../dependencies/WorkletsProxy"); +var _FrameProcessorsUnavailableError = require("./FrameProcessorsUnavailableError"); +var _throwErrorOnJS = require("./throwErrorOnJS"); +/** + * A synchronized Shared Value to indicate whether the async context is currently executing + */ +let isAsyncContextBusy; +/** + * Runs the given function on the async context, and sets {@linkcode isAsyncContextBusy} to false after it finished executing. + */ +let runOnAsyncContext; +try { + const Worklets = _WorkletsProxy.WorkletsProxy.Worklets; + isAsyncContextBusy = Worklets.createSharedValue(false); + const asyncContext = Worklets.createContext('VisionCamera.async'); + runOnAsyncContext = asyncContext.createRunAsync((frame, func) => { + 'worklet'; + + try { + // Call long-running function + func(); + } catch (e) { + // Re-throw error on JS Thread + (0, _throwErrorOnJS.throwErrorOnJS)(e); + } finally { + // Potentially delete Frame if we were the last ref + const internal = frame; + internal.decrementRefCount(); + + // free up async context again, new calls can be made + isAsyncContextBusy.value = false; + } + }); +} catch (e) { + // react-native-worklets-core is not installed! + // Just use dummy implementations that will throw when the user tries to use Frame Processors. + isAsyncContextBusy = { + value: false + }; + runOnAsyncContext = () => { + throw new _FrameProcessorsUnavailableError.FrameProcessorsUnavailableError(e); + }; +} + +/** + * Runs the given {@linkcode func} asynchronously on a separate thread, + * allowing the Frame Processor to continue executing without dropping a Frame. + * + * Only one {@linkcode runAsync} call will execute at the same time, + * so {@linkcode runAsync} is **not parallel**, **but asynchronous**. + * + * + * For example, if your Camera is running at 60 FPS (16ms per frame), and a + * heavy ML face detection Frame Processor Plugin takes 500ms to execute, + * you have two options: + * - Run the plugin normally (synchronously in `useFrameProcessor`) + * but drop a lot of Frames, as we can only run at 2 FPS (500ms per frame) + * - Call the plugin inside {@linkcode runAsync} to allow the Camera to still + * run at 60 FPS, but offload the heavy ML face detection plugin to the + * asynchronous context, where it will run at 2 FPS. + * + * @note {@linkcode runAsync} cannot be used to draw to a Frame in a Skia Frame Processor. + * @param frame The current Frame of the Frame Processor. + * @param func The function to execute. + * @worklet + * @example + * + * ```ts + * const frameProcessor = useFrameProcessor((frame) => { + * 'worklet' + * console.log('New Frame arrived!') + * + * runAsync(frame, () => { + * 'worklet' + * const faces = detectFaces(frame) + * const face = [faces0] + * console.log(`Detected a new face: ${face}`) + * }) + * }) + * ``` + */ +function runAsync(frame, func) { + 'worklet'; + + if (isAsyncContextBusy.value) { + // async context is currently busy, we cannot schedule new work in time. + // drop this frame/runAsync call. + return; + } + + // Increment ref count by one + const internal = frame; + internal.incrementRefCount(); + isAsyncContextBusy.value = true; + + // Call in separate background context + runOnAsyncContext(frame, func); +} +//# sourceMappingURL=runAsync.js.map \ No newline at end of file diff --git a/package/lib/commonjs/frame-processors/runAsync.js.map b/package/lib/commonjs/frame-processors/runAsync.js.map new file mode 100644 index 0000000000..4d1c880022 --- /dev/null +++ b/package/lib/commonjs/frame-processors/runAsync.js.map @@ -0,0 +1 @@ +{"version":3,"names":["_WorkletsProxy","require","_FrameProcessorsUnavailableError","_throwErrorOnJS","isAsyncContextBusy","runOnAsyncContext","Worklets","WorkletsProxy","createSharedValue","asyncContext","createContext","createRunAsync","frame","func","e","throwErrorOnJS","internal","decrementRefCount","value","FrameProcessorsUnavailableError","runAsync","incrementRefCount"],"sourceRoot":"../../../src","sources":["frame-processors/runAsync.ts"],"mappings":";;;;;;AAAA,IAAAA,cAAA,GAAAC,OAAA;AAEA,IAAAC,gCAAA,GAAAD,OAAA;AACA,IAAAE,eAAA,GAAAF,OAAA;AAEA;AACA;AACA;AACA,IAAIG,kBAAsC;AAC1C;AACA;AACA;AACA,IAAIC,iBAA2D;AAE/D,IAAI;EACF,MAAMC,QAAQ,GAAGC,4BAAa,CAACD,QAAQ;EACvCF,kBAAkB,GAAGE,QAAQ,CAACE,iBAAiB,CAAC,KAAK,CAAC;EAEtD,MAAMC,YAAY,GAAGH,QAAQ,CAACI,aAAa,CAAC,oBAAoB,CAAC;EACjEL,iBAAiB,GAAGI,YAAY,CAACE,cAAc,CAAC,CAACC,KAAY,EAAEC,IAAgB,KAAK;IAClF,SAAS;;IACT,IAAI;MACF;MACAA,IAAI,CAAC,CAAC;IACR,CAAC,CAAC,OAAOC,CAAC,EAAE;MACV;MACA,IAAAC,8BAAc,EAACD,CAAC,CAAC;IACnB,CAAC,SAAS;MACR;MACA,MAAME,QAAQ,GAAGJ,KAAsB;MACvCI,QAAQ,CAACC,iBAAiB,CAAC,CAAC;;MAE5B;MACAb,kBAAkB,CAACc,KAAK,GAAG,KAAK;IAClC;EACF,CAAC,CAAC;AACJ,CAAC,CAAC,OAAOJ,CAAC,EAAE;EACV;EACA;EACAV,kBAAkB,GAAG;IAAEc,KAAK,EAAE;EAAM,CAAC;EACrCb,iBAAiB,GAAGA,CAAA,KAAM;IACxB,MAAM,IAAIc,gEAA+B,CAACL,CAAC,CAAC;EAC9C,CAAC;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASM,QAAQA,CAACR,KAAY,EAAEC,IAAgB,EAAQ;EAC7D,SAAS;;EAET,IAAIT,kBAAkB,CAACc,KAAK,EAAE;IAC5B;IACA;IACA;EACF;;EAEA;EACA,MAAMF,QAAQ,GAAGJ,KAAsB;EACvCI,QAAQ,CAACK,iBAAiB,CAAC,CAAC;EAE5BjB,kBAAkB,CAACc,KAAK,GAAG,IAAI;;EAE/B;EACAb,iBAAiB,CAACO,KAAK,EAAEC,IAAI,CAAC;AAChC"} diff --git a/package/lib/commonjs/frame-processors/runAtTargetFps.js b/package/lib/commonjs/frame-processors/runAtTargetFps.js new file mode 100644 index 0000000000..17b973969a --- /dev/null +++ b/package/lib/commonjs/frame-processors/runAtTargetFps.js @@ -0,0 +1,62 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.runAtTargetFps = runAtTargetFps; +function getLastFrameProcessorCall(frameProcessorFuncId) { + 'worklet'; + + return global.__frameProcessorRunAtTargetFpsMap?.[frameProcessorFuncId] ?? 0; +} +function setLastFrameProcessorCall(frameProcessorFuncId, value) { + 'worklet'; + + if (global.__frameProcessorRunAtTargetFpsMap == null) global.__frameProcessorRunAtTargetFpsMap = {}; + global.__frameProcessorRunAtTargetFpsMap[frameProcessorFuncId] = value; +} + +/** + * Runs the given {@linkcode func} at the given target {@linkcode fps} rate. + * + * {@linkcode runAtTargetFps} still executes the given {@linkcode func} synchronously, + * so this is only useful for throttling calls to a plugin or logger. + * + * For example, if you want to scan faces only once per second to avoid excessive + * CPU usage, use {@linkcode runAtTargetFps runAtTargetFps(1, ...)}. + * + * @param fps The target FPS rate at which the given function should be executed + * @param func The function to execute. + * @returns The result of the function if it was executed, or `undefined` otherwise. + * @worklet + * @example + * + * ```ts + * const frameProcessor = useFrameProcessor((frame) => { + * 'worklet' + * console.log('New Frame') + * runAtTargetFps(5, () => { + * 'worklet' + * const faces = detectFaces(frame) + * console.log(`Detected a new face: ${faces[0]}`) + * }) + * }) + * ``` + */ +function runAtTargetFps(fps, func) { + 'worklet'; + + // @ts-expect-error + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const funcId = func.__workletHash ?? '1'; + const targetIntervalMs = 1000 / fps; // <-- 60 FPS => 16,6667ms interval + const now = performance.now(); + const diffToLastCall = now - getLastFrameProcessorCall(funcId); + if (diffToLastCall >= targetIntervalMs) { + setLastFrameProcessorCall(funcId, now); + // Last Frame Processor call is already so long ago that we want to make a new call + return func(); + } + return undefined; +} +//# sourceMappingURL=runAtTargetFps.js.map \ No newline at end of file diff --git a/package/lib/commonjs/frame-processors/runAtTargetFps.js.map b/package/lib/commonjs/frame-processors/runAtTargetFps.js.map new file mode 100644 index 0000000000..78d5b50df2 --- /dev/null +++ b/package/lib/commonjs/frame-processors/runAtTargetFps.js.map @@ -0,0 +1 @@ +{"version":3,"names":["getLastFrameProcessorCall","frameProcessorFuncId","global","__frameProcessorRunAtTargetFpsMap","setLastFrameProcessorCall","value","runAtTargetFps","fps","func","funcId","__workletHash","targetIntervalMs","now","performance","diffToLastCall","undefined"],"sourceRoot":"../../../src","sources":["frame-processors/runAtTargetFps.ts"],"mappings":";;;;;;AAKA,SAASA,yBAAyBA,CAACC,oBAA4B,EAAU;EACvE,SAAS;;EACT,OAAOC,MAAM,CAACC,iCAAiC,GAAGF,oBAAoB,CAAC,IAAI,CAAC;AAC9E;AACA,SAASG,yBAAyBA,CAACH,oBAA4B,EAAEI,KAAa,EAAQ;EACpF,SAAS;;EACT,IAAIH,MAAM,CAACC,iCAAiC,IAAI,IAAI,EAAED,MAAM,CAACC,iCAAiC,GAAG,CAAC,CAAC;EACnGD,MAAM,CAACC,iCAAiC,CAACF,oBAAoB,CAAC,GAAGI,KAAK;AACxE;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,cAAcA,CAAIC,GAAW,EAAEC,IAAa,EAAiB;EAC3E,SAAS;;EACT;EACA;EACA,MAAMC,MAAM,GAAGD,IAAI,CAACE,aAAa,IAAI,GAAG;EAExC,MAAMC,gBAAgB,GAAG,IAAI,GAAGJ,GAAG,EAAC;EACpC,MAAMK,GAAG,GAAGC,WAAW,CAACD,GAAG,CAAC,CAAC;EAC7B,MAAME,cAAc,GAAGF,GAAG,GAAGZ,yBAAyB,CAACS,MAAM,CAAC;EAC9D,IAAIK,cAAc,IAAIH,gBAAgB,EAAE;IACtCP,yBAAyB,CAACK,MAAM,EAAEG,GAAG,CAAC;IACtC;IACA,OAAOJ,IAAI,CAAC,CAAC;EACf;EACA,OAAOO,SAAS;AAClB"} diff --git a/package/lib/commonjs/frame-processors/throwErrorOnJS.js b/package/lib/commonjs/frame-processors/throwErrorOnJS.js new file mode 100644 index 0000000000..d0772d823e --- /dev/null +++ b/package/lib/commonjs/frame-processors/throwErrorOnJS.js @@ -0,0 +1,53 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.throwErrorOnJS = throwErrorOnJS; +var _WorkletsProxy = require("../dependencies/WorkletsProxy"); +var _FrameProcessorsUnavailableError = require("./FrameProcessorsUnavailableError"); +/** + * Rethrows the given message and stack as a JS Error on the JS Thread. + */ +let rethrowErrorOnJS; +try { + const Worklets = _WorkletsProxy.WorkletsProxy.Worklets; + rethrowErrorOnJS = Worklets.createRunOnJS((message, stack) => { + const error = new Error(); + error.message = message; + error.stack = stack; + error.name = 'Frame Processor Error'; + // @ts-expect-error this is react-native specific + error.jsEngine = 'VisionCamera'; + + // From react-native: + // @ts-expect-error it's untyped + const errorUtils = global.ErrorUtils ?? global.__ErrorUtils; + if (errorUtils != null && typeof errorUtils.reportFatalError === 'function') { + // we can use the JS error reporter view from react native + errorUtils.reportFatalError(error); + } else { + // just log it to console.error as a fallback + console.error('Frame Processor Error:', error); + } + }); +} catch (e) { + // react-native-worklets-core is not installed! + // Just use dummy implementations that will throw when the user tries to use Frame Processors. + rethrowErrorOnJS = () => { + throw new _FrameProcessorsUnavailableError.FrameProcessorsUnavailableError(e); + }; +} + +/** + * Throws the given Error on the JS Thread using React Native's error reporter. + * @param error An {@linkcode Error}, or an object with a `message` property, otherwise a default messageg will be thrown. + */ +function throwErrorOnJS(error) { + 'worklet'; + + const safeError = error; + const message = safeError != null && 'message' in safeError ? safeError.message : 'Frame Processor threw an error.'; + rethrowErrorOnJS(message, safeError?.stack); +} +//# sourceMappingURL=throwErrorOnJS.js.map \ No newline at end of file diff --git a/package/lib/commonjs/frame-processors/throwErrorOnJS.js.map b/package/lib/commonjs/frame-processors/throwErrorOnJS.js.map new file mode 100644 index 0000000000..caec3174ca --- /dev/null +++ b/package/lib/commonjs/frame-processors/throwErrorOnJS.js.map @@ -0,0 +1 @@ +{"version":3,"names":["_WorkletsProxy","require","_FrameProcessorsUnavailableError","rethrowErrorOnJS","Worklets","WorkletsProxy","createRunOnJS","message","stack","error","Error","name","jsEngine","errorUtils","global","ErrorUtils","__ErrorUtils","reportFatalError","console","e","FrameProcessorsUnavailableError","throwErrorOnJS","safeError"],"sourceRoot":"../../../src","sources":["frame-processors/throwErrorOnJS.ts"],"mappings":";;;;;;AAAA,IAAAA,cAAA,GAAAC,OAAA;AACA,IAAAC,gCAAA,GAAAD,OAAA;AAMA;AACA;AACA;AACA,IAAIE,gBAAsE;AAE1E,IAAI;EACF,MAAMC,QAAQ,GAAGC,4BAAa,CAACD,QAAQ;EACvCD,gBAAgB,GAAGC,QAAQ,CAACE,aAAa,CAAC,CAACC,OAAe,EAAEC,KAAyB,KAAK;IACxF,MAAMC,KAAK,GAAG,IAAIC,KAAK,CAAC,CAAC;IACzBD,KAAK,CAACF,OAAO,GAAGA,OAAO;IACvBE,KAAK,CAACD,KAAK,GAAGA,KAAK;IACnBC,KAAK,CAACE,IAAI,GAAG,uBAAuB;IACpC;IACAF,KAAK,CAACG,QAAQ,GAAG,cAAc;;IAE/B;IACA;IACA,MAAMC,UAAU,GAAIC,MAAM,CAACC,UAAU,IAAID,MAAM,CAACE,YAAwC;IACxF,IAAIH,UAAU,IAAI,IAAI,IAAI,OAAOA,UAAU,CAACI,gBAAgB,KAAK,UAAU,EAAE;MAC3E;MACAJ,UAAU,CAACI,gBAAgB,CAACR,KAAK,CAAC;IACpC,CAAC,MAAM;MACL;MACAS,OAAO,CAACT,KAAK,CAAC,wBAAwB,EAAEA,KAAK,CAAC;IAChD;EACF,CAAC,CAAC;AACJ,CAAC,CAAC,OAAOU,CAAC,EAAE;EACV;EACA;EACAhB,gBAAgB,GAAGA,CAAA,KAAM;IACvB,MAAM,IAAIiB,gEAA+B,CAACD,CAAC,CAAC;EAC9C,CAAC;AACH;;AAEA;AACA;AACA;AACA;AACO,SAASE,cAAcA,CAACZ,KAAc,EAAQ;EACnD,SAAS;;EACT,MAAMa,SAAS,GAAGb,KAA0B;EAC5C,MAAMF,OAAO,GAAGe,SAAS,IAAI,IAAI,IAAI,SAAS,IAAIA,SAAS,GAAGA,SAAS,CAACf,OAAO,GAAG,iCAAiC;EACnHJ,gBAAgB,CAACI,OAAO,EAAEe,SAAS,EAAEd,KAAK,CAAC;AAC7C"} diff --git a/package/lib/commonjs/frame-processors/withFrameRefCounting.js b/package/lib/commonjs/frame-processors/withFrameRefCounting.js new file mode 100644 index 0000000000..2505d68639 --- /dev/null +++ b/package/lib/commonjs/frame-processors/withFrameRefCounting.js @@ -0,0 +1,32 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.withFrameRefCounting = withFrameRefCounting; +var _throwErrorOnJS = require("./throwErrorOnJS"); +/** + * A private API to wrap a Frame Processor with a ref-counting mechanism + * @worklet + * @internal + */ +function withFrameRefCounting(frameProcessor) { + return frame => { + 'worklet'; + + // Increment ref-count by one + const internal = frame; + internal.incrementRefCount(); + try { + // Call sync frame processor + frameProcessor(frame); + } catch (e) { + // Re-throw error on JS Thread + (0, _throwErrorOnJS.throwErrorOnJS)(e); + } finally { + // Potentially delete Frame if we were the last ref (no runAsync) + internal.decrementRefCount(); + } + }; +} +//# sourceMappingURL=withFrameRefCounting.js.map \ No newline at end of file diff --git a/package/lib/commonjs/frame-processors/withFrameRefCounting.js.map b/package/lib/commonjs/frame-processors/withFrameRefCounting.js.map new file mode 100644 index 0000000000..8cc764e04d --- /dev/null +++ b/package/lib/commonjs/frame-processors/withFrameRefCounting.js.map @@ -0,0 +1 @@ +{"version":3,"names":["_throwErrorOnJS","require","withFrameRefCounting","frameProcessor","frame","internal","incrementRefCount","e","throwErrorOnJS","decrementRefCount"],"sourceRoot":"../../../src","sources":["frame-processors/withFrameRefCounting.ts"],"mappings":";;;;;;AACA,IAAAA,eAAA,GAAAC,OAAA;AAEA;AACA;AACA;AACA;AACA;AACO,SAASC,oBAAoBA,CAACC,cAAsC,EAA0B;EACnG,OAAQC,KAAK,IAAK;IAChB,SAAS;;IACT;IACA,MAAMC,QAAQ,GAAGD,KAAsB;IACvCC,QAAQ,CAACC,iBAAiB,CAAC,CAAC;IAC5B,IAAI;MACF;MACAH,cAAc,CAACC,KAAK,CAAC;IACvB,CAAC,CAAC,OAAOG,CAAC,EAAE;MACV;MACA,IAAAC,8BAAc,EAACD,CAAC,CAAC;IACnB,CAAC,SAAS;MACR;MACAF,QAAQ,CAACI,iBAAiB,CAAC,CAAC;IAC9B;EACF,CAAC;AACH"} diff --git a/package/lib/commonjs/hooks/useCameraDevice.js b/package/lib/commonjs/hooks/useCameraDevice.js new file mode 100644 index 0000000000..5ddb16facd --- /dev/null +++ b/package/lib/commonjs/hooks/useCameraDevice.js @@ -0,0 +1,29 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.useCameraDevice = useCameraDevice; +var _react = require("react"); +var _getCameraDevice = require("../devices/getCameraDevice"); +var _useCameraDevices = require("./useCameraDevices"); +/** + * Get the best matching Camera device that best satisfies your requirements using a sorting filter. + * @param position The position of the Camera device relative to the phone. + * @param filter The filter you want to use. The Camera device that matches your filter the closest will be returned + * @returns The Camera device that matches your filter the closest, or `undefined` if no such Camera Device exists on the given {@linkcode position}. + * @example + * ```ts + * const device = useCameraDevice('back', { + * physicalDevices: ['wide-angle-camera'] + * }) + * ``` + */ +function useCameraDevice(position, filter) { + const devices = (0, _useCameraDevices.useCameraDevices)(); + const device = (0, _react.useMemo)(() => (0, _getCameraDevice.getCameraDevice)(devices, position, filter), + // eslint-disable-next-line react-hooks/exhaustive-deps + [devices, position, JSON.stringify(filter)]); + return device; +} +//# sourceMappingURL=useCameraDevice.js.map \ No newline at end of file diff --git a/package/lib/commonjs/hooks/useCameraDevice.js.map b/package/lib/commonjs/hooks/useCameraDevice.js.map new file mode 100644 index 0000000000..61a476743f --- /dev/null +++ b/package/lib/commonjs/hooks/useCameraDevice.js.map @@ -0,0 +1 @@ +{"version":3,"names":["_react","require","_getCameraDevice","_useCameraDevices","useCameraDevice","position","filter","devices","useCameraDevices","device","useMemo","getCameraDevice","JSON","stringify"],"sourceRoot":"../../../src","sources":["hooks/useCameraDevice.ts"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,OAAA;AAGA,IAAAC,gBAAA,GAAAD,OAAA;AACA,IAAAE,iBAAA,GAAAF,OAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASG,eAAeA,CAACC,QAAwB,EAAEC,MAAqB,EAA4B;EACzG,MAAMC,OAAO,GAAG,IAAAC,kCAAgB,EAAC,CAAC;EAElC,MAAMC,MAAM,GAAG,IAAAC,cAAO,EACpB,MAAM,IAAAC,gCAAe,EAACJ,OAAO,EAAEF,QAAQ,EAAEC,MAAM,CAAC;EAChD;EACA,CAACC,OAAO,EAAEF,QAAQ,EAAEO,IAAI,CAACC,SAAS,CAACP,MAAM,CAAC,CAC5C,CAAC;EAED,OAAOG,MAAM;AACf"} diff --git a/package/lib/commonjs/hooks/useCameraDevices.js b/package/lib/commonjs/hooks/useCameraDevices.js new file mode 100644 index 0000000000..94b2c80bdb --- /dev/null +++ b/package/lib/commonjs/hooks/useCameraDevices.js @@ -0,0 +1,26 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.useCameraDevices = useCameraDevices; +var _react = require("react"); +var _CameraDevices = require("../CameraDevices"); +/** + * Get all available Camera Devices this phone has. + * + * Camera Devices attached to this phone (`back` or `front`) are always available, + * while `external` devices might be plugged in or out at any point, + * so the result of this function might update over time. + */ +function useCameraDevices() { + const [devices, setDevices] = (0, _react.useState)(() => _CameraDevices.CameraDevices.getAvailableCameraDevices()); + (0, _react.useEffect)(() => { + const listener = _CameraDevices.CameraDevices.addCameraDevicesChangedListener(newDevices => { + setDevices(newDevices); + }); + return () => listener.remove(); + }, []); + return devices; +} +//# sourceMappingURL=useCameraDevices.js.map \ No newline at end of file diff --git a/package/lib/commonjs/hooks/useCameraDevices.js.map b/package/lib/commonjs/hooks/useCameraDevices.js.map new file mode 100644 index 0000000000..cffc76ef23 --- /dev/null +++ b/package/lib/commonjs/hooks/useCameraDevices.js.map @@ -0,0 +1 @@ +{"version":3,"names":["_react","require","_CameraDevices","useCameraDevices","devices","setDevices","useState","CameraDevices","getAvailableCameraDevices","useEffect","listener","addCameraDevicesChangedListener","newDevices","remove"],"sourceRoot":"../../../src","sources":["hooks/useCameraDevices.ts"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,OAAA;AAEA,IAAAC,cAAA,GAAAD,OAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASE,gBAAgBA,CAAA,EAAmB;EACjD,MAAM,CAACC,OAAO,EAAEC,UAAU,CAAC,GAAG,IAAAC,eAAQ,EAAC,MAAMC,4BAAa,CAACC,yBAAyB,CAAC,CAAC,CAAC;EAEvF,IAAAC,gBAAS,EAAC,MAAM;IACd,MAAMC,QAAQ,GAAGH,4BAAa,CAACI,+BAA+B,CAAEC,UAAU,IAAK;MAC7EP,UAAU,CAACO,UAAU,CAAC;IACxB,CAAC,CAAC;IACF,OAAO,MAAMF,QAAQ,CAACG,MAAM,CAAC,CAAC;EAChC,CAAC,EAAE,EAAE,CAAC;EAEN,OAAOT,OAAO;AAChB"} diff --git a/package/lib/commonjs/hooks/useCameraFormat.js b/package/lib/commonjs/hooks/useCameraFormat.js new file mode 100644 index 0000000000..e197707568 --- /dev/null +++ b/package/lib/commonjs/hooks/useCameraFormat.js @@ -0,0 +1,35 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.useCameraFormat = useCameraFormat; +var _react = require("react"); +var _getCameraFormat = require("../devices/getCameraFormat"); +/** + * Get the best matching Camera format for the given device that satisfies your requirements using a sorting filter. By default, formats are sorted by highest to lowest resolution. + * + * The {@linkcode filters | filters} are ranked by priority, from highest to lowest. + * This means the first item you pass will have a higher priority than the second, and so on. + * + * @param device The Camera Device you're currently using + * @param filters The filters you want to use. The format that matches your filter the closest will be returned + * @returns The format that matches your filter the closest. + * @example + * ```ts + * const device = useCameraDevice(...) + * const format = useCameraFormat(device, [ + * { videoResolution: { width: 3048, height: 2160 } }, + * { fps: 60 } + * ]) + * ``` + */ +function useCameraFormat(device, filters) { + const format = (0, _react.useMemo)(() => { + if (device == null) return undefined; + return (0, _getCameraFormat.getCameraFormat)(device, filters); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [device, JSON.stringify(filters)]); + return format; +} +//# sourceMappingURL=useCameraFormat.js.map \ No newline at end of file diff --git a/package/lib/commonjs/hooks/useCameraFormat.js.map b/package/lib/commonjs/hooks/useCameraFormat.js.map new file mode 100644 index 0000000000..85afa39f62 --- /dev/null +++ b/package/lib/commonjs/hooks/useCameraFormat.js.map @@ -0,0 +1 @@ +{"version":3,"names":["_react","require","_getCameraFormat","useCameraFormat","device","filters","format","useMemo","undefined","getCameraFormat","JSON","stringify"],"sourceRoot":"../../../src","sources":["hooks/useCameraFormat.ts"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,OAAA;AAGA,IAAAC,gBAAA,GAAAD,OAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASE,eAAeA,CAACC,MAAgC,EAAEC,OAAuB,EAAkC;EACzH,MAAMC,MAAM,GAAG,IAAAC,cAAO,EAAC,MAAM;IAC3B,IAAIH,MAAM,IAAI,IAAI,EAAE,OAAOI,SAAS;IACpC,OAAO,IAAAC,gCAAe,EAACL,MAAM,EAAEC,OAAO,CAAC;IACvC;EACF,CAAC,EAAE,CAACD,MAAM,EAAEM,IAAI,CAACC,SAAS,CAACN,OAAO,CAAC,CAAC,CAAC;EAErC,OAAOC,MAAM;AACf"} diff --git a/package/lib/commonjs/hooks/useCameraPermission.js b/package/lib/commonjs/hooks/useCameraPermission.js new file mode 100644 index 0000000000..5e23540bcf --- /dev/null +++ b/package/lib/commonjs/hooks/useCameraPermission.js @@ -0,0 +1,88 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.useCameraPermission = useCameraPermission; +exports.useLocationPermission = useLocationPermission; +exports.useMicrophonePermission = useMicrophonePermission; +var _react = require("react"); +var _Camera = require("../Camera"); +var _reactNative = require("react-native"); +function usePermission(get, request) { + const [hasPermission, setHasPermission] = (0, _react.useState)(() => get() === 'granted'); + const requestPermission = (0, _react.useCallback)(async () => { + const result = await request(); + const hasPermissionNow = result === 'granted'; + setHasPermission(hasPermissionNow); + return hasPermissionNow; + }, [request]); + (0, _react.useEffect)(() => { + // Refresh permission when app state changes, as user might have allowed it in Settings + const listener = _reactNative.AppState.addEventListener('change', () => { + setHasPermission(get() === 'granted'); + }); + return () => listener.remove(); + }, [get]); + return (0, _react.useMemo)(() => ({ + hasPermission, + requestPermission + }), [hasPermission, requestPermission]); +} + +/** + * Returns whether the user has granted permission to use the Camera, or not. + * + * If the user doesn't grant Camera Permission, you cannot use the ``. + * + * @example + * ```tsx + * const { hasPermission, requestPermission } = useCameraPermission() + * + * if (!hasPermission) { + * return + * } else { + * return + * } + * ``` + */ +function useCameraPermission() { + return usePermission(_Camera.Camera.getCameraPermissionStatus, _Camera.Camera.requestCameraPermission); +} + +/** + * Returns whether the user has granted permission to use the Microphone, or not. + * + * If the user doesn't grant Audio Permission, you can use the `` but you cannot + * record videos with audio (the `audio={..}` prop). + * + * @example + * ```tsx + * const { hasPermission, requestPermission } = useMicrophonePermission() + * const canRecordAudio = hasPermission + * + * return + * ``` + */ +function useMicrophonePermission() { + return usePermission(_Camera.Camera.getMicrophonePermissionStatus, _Camera.Camera.requestMicrophonePermission); +} + +/** + * Returns whether the user has granted permission to use the Location, or not. + * + * If the user doesn't grant Location Permission, you can use the `` but you cannot + * capture photos or videos with GPS EXIF tags (the `location={..}` prop). + * + * @example + * ```tsx + * const { hasPermission, requestPermission } = useLocationPermission() + * const canCaptureLocation = hasPermission + * + * return + * ``` + */ +function useLocationPermission() { + return usePermission(_Camera.Camera.getLocationPermissionStatus, _Camera.Camera.requestLocationPermission); +} +//# sourceMappingURL=useCameraPermission.js.map \ No newline at end of file diff --git a/package/lib/commonjs/hooks/useCameraPermission.js.map b/package/lib/commonjs/hooks/useCameraPermission.js.map new file mode 100644 index 0000000000..773925f437 --- /dev/null +++ b/package/lib/commonjs/hooks/useCameraPermission.js.map @@ -0,0 +1 @@ +{"version":3,"names":["_react","require","_Camera","_reactNative","usePermission","get","request","hasPermission","setHasPermission","useState","requestPermission","useCallback","result","hasPermissionNow","useEffect","listener","AppState","addEventListener","remove","useMemo","useCameraPermission","Camera","getCameraPermissionStatus","requestCameraPermission","useMicrophonePermission","getMicrophonePermissionStatus","requestMicrophonePermission","useLocationPermission","getLocationPermissionStatus","requestLocationPermission"],"sourceRoot":"../../../src","sources":["hooks/useCameraPermission.ts"],"mappings":";;;;;;;;AAAA,IAAAA,MAAA,GAAAC,OAAA;AAEA,IAAAC,OAAA,GAAAD,OAAA;AACA,IAAAE,YAAA,GAAAF,OAAA;AAeA,SAASG,aAAaA,CAACC,GAAiC,EAAEC,OAAqD,EAAmB;EAChI,MAAM,CAACC,aAAa,EAAEC,gBAAgB,CAAC,GAAG,IAAAC,eAAQ,EAAC,MAAMJ,GAAG,CAAC,CAAC,KAAK,SAAS,CAAC;EAE7E,MAAMK,iBAAiB,GAAG,IAAAC,kBAAW,EAAC,YAAY;IAChD,MAAMC,MAAM,GAAG,MAAMN,OAAO,CAAC,CAAC;IAC9B,MAAMO,gBAAgB,GAAGD,MAAM,KAAK,SAAS;IAC7CJ,gBAAgB,CAACK,gBAAgB,CAAC;IAClC,OAAOA,gBAAgB;EACzB,CAAC,EAAE,CAACP,OAAO,CAAC,CAAC;EAEb,IAAAQ,gBAAS,EAAC,MAAM;IACd;IACA,MAAMC,QAAQ,GAAGC,qBAAQ,CAACC,gBAAgB,CAAC,QAAQ,EAAE,MAAM;MACzDT,gBAAgB,CAACH,GAAG,CAAC,CAAC,KAAK,SAAS,CAAC;IACvC,CAAC,CAAC;IACF,OAAO,MAAMU,QAAQ,CAACG,MAAM,CAAC,CAAC;EAChC,CAAC,EAAE,CAACb,GAAG,CAAC,CAAC;EAET,OAAO,IAAAc,cAAO,EACZ,OAAO;IACLZ,aAAa;IACbG;EACF,CAAC,CAAC,EACF,CAACH,aAAa,EAAEG,iBAAiB,CACnC,CAAC;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASU,mBAAmBA,CAAA,EAAoB;EACrD,OAAOhB,aAAa,CAACiB,cAAM,CAACC,yBAAyB,EAAED,cAAM,CAACE,uBAAuB,CAAC;AACxF;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,uBAAuBA,CAAA,EAAoB;EACzD,OAAOpB,aAAa,CAACiB,cAAM,CAACI,6BAA6B,EAAEJ,cAAM,CAACK,2BAA2B,CAAC;AAChG;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,qBAAqBA,CAAA,EAAoB;EACvD,OAAOvB,aAAa,CAACiB,cAAM,CAACO,2BAA2B,EAAEP,cAAM,CAACQ,yBAAyB,CAAC;AAC5F"} diff --git a/package/lib/commonjs/hooks/useCodeScanner.js b/package/lib/commonjs/hooks/useCodeScanner.js new file mode 100644 index 0000000000..687024f7f0 --- /dev/null +++ b/package/lib/commonjs/hooks/useCodeScanner.js @@ -0,0 +1,29 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.useCodeScanner = useCodeScanner; +var _react = require("react"); +function useCodeScanner(codeScanner) { + const { + onCodeScanned, + ...codeScannerOptions + } = codeScanner; + + // Memoize the function once and use a ref on any identity changes + const ref = (0, _react.useRef)(onCodeScanned); + ref.current = onCodeScanned; + const callback = (0, _react.useCallback)((codes, frame) => { + ref.current(codes, frame); + }, []); + + // CodeScanner needs to be memoized so it doesn't trigger a Camera Session re-build + return (0, _react.useMemo)(() => ({ + ...codeScannerOptions, + onCodeScanned: callback + }), + // eslint-disable-next-line react-hooks/exhaustive-deps + [JSON.stringify(codeScannerOptions), callback]); +} +//# sourceMappingURL=useCodeScanner.js.map \ No newline at end of file diff --git a/package/lib/commonjs/hooks/useCodeScanner.js.map b/package/lib/commonjs/hooks/useCodeScanner.js.map new file mode 100644 index 0000000000..ee199e32ab --- /dev/null +++ b/package/lib/commonjs/hooks/useCodeScanner.js.map @@ -0,0 +1 @@ +{"version":3,"names":["_react","require","useCodeScanner","codeScanner","onCodeScanned","codeScannerOptions","ref","useRef","current","callback","useCallback","codes","frame","useMemo","JSON","stringify"],"sourceRoot":"../../../src","sources":["hooks/useCodeScanner.ts"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,OAAA;AAGO,SAASC,cAAcA,CAACC,WAAwB,EAAe;EACpE,MAAM;IAAEC,aAAa;IAAE,GAAGC;EAAmB,CAAC,GAAGF,WAAW;;EAE5D;EACA,MAAMG,GAAG,GAAG,IAAAC,aAAM,EAACH,aAAa,CAAC;EACjCE,GAAG,CAACE,OAAO,GAAGJ,aAAa;EAC3B,MAAMK,QAAQ,GAAG,IAAAC,kBAAW,EAAC,CAACC,KAAa,EAAEC,KAAuB,KAAK;IACvEN,GAAG,CAACE,OAAO,CAACG,KAAK,EAAEC,KAAK,CAAC;EAC3B,CAAC,EAAE,EAAE,CAAC;;EAEN;EACA,OAAO,IAAAC,cAAO,EACZ,OAAO;IACL,GAAGR,kBAAkB;IACrBD,aAAa,EAAEK;EACjB,CAAC,CAAC;EACF;EACA,CAACK,IAAI,CAACC,SAAS,CAACV,kBAAkB,CAAC,EAAEI,QAAQ,CAC/C,CAAC;AACH"} diff --git a/package/lib/commonjs/hooks/useFrameProcessor.js b/package/lib/commonjs/hooks/useFrameProcessor.js new file mode 100644 index 0000000000..219b1ca1c1 --- /dev/null +++ b/package/lib/commonjs/hooks/useFrameProcessor.js @@ -0,0 +1,49 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.createFrameProcessor = createFrameProcessor; +exports.useFrameProcessor = useFrameProcessor; +var _react = require("react"); +var _withFrameRefCounting = require("../frame-processors/withFrameRefCounting"); +/** + * Create a new Frame Processor function which you can pass to the ``. + * (See ["Frame Processors"](https://react-native-vision-camera.com/docs/guides/frame-processors)) + * + * Make sure to add the `'worklet'` directive to the top of the Frame Processor function, otherwise it will not get compiled into a worklet. + * + * Also make sure to memoize the returned object, so that the Camera doesn't reset the Frame Processor Context each time. + * @worklet + */ +function createFrameProcessor(frameProcessor) { + return { + frameProcessor: (0, _withFrameRefCounting.withFrameRefCounting)(frameProcessor), + type: 'readonly' + }; +} + +/** + * Returns a memoized Frame Processor function wich you can pass to the ``. + * (See ["Frame Processors"](https://react-native-vision-camera.com/docs/guides/frame-processors)) + * + * Make sure to add the `'worklet'` directive to the top of the Frame Processor function, otherwise it will not get compiled into a worklet. + * + * @worklet + * @param frameProcessor The Frame Processor + * @param dependencies The React dependencies which will be copied into the VisionCamera JS-Runtime. + * @returns The memoized Frame Processor. + * @example + * ```ts + * const frameProcessor = useFrameProcessor((frame) => { + * 'worklet' + * const faces = scanFaces(frame) + * console.log(`Faces: ${faces}`) + * }, []) + * ``` + */ +function useFrameProcessor(frameProcessor, dependencies) { + // eslint-disable-next-line react-hooks/exhaustive-deps + return (0, _react.useMemo)(() => createFrameProcessor(frameProcessor), dependencies); +} +//# sourceMappingURL=useFrameProcessor.js.map \ No newline at end of file diff --git a/package/lib/commonjs/hooks/useFrameProcessor.js.map b/package/lib/commonjs/hooks/useFrameProcessor.js.map new file mode 100644 index 0000000000..691e87f7b4 --- /dev/null +++ b/package/lib/commonjs/hooks/useFrameProcessor.js.map @@ -0,0 +1 @@ +{"version":3,"names":["_react","require","_withFrameRefCounting","createFrameProcessor","frameProcessor","withFrameRefCounting","type","useFrameProcessor","dependencies","useMemo"],"sourceRoot":"../../../src","sources":["hooks/useFrameProcessor.ts"],"mappings":";;;;;;;AACA,IAAAA,MAAA,GAAAC,OAAA;AACA,IAAAC,qBAAA,GAAAD,OAAA;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASE,oBAAoBA,CAACC,cAAsC,EAA0B;EACnG,OAAO;IACLA,cAAc,EAAE,IAAAC,0CAAoB,EAACD,cAAc,CAAC;IACpDE,IAAI,EAAE;EACR,CAAC;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,iBAAiBA,CAACH,cAAsC,EAAEI,YAA4B,EAA0B;EAC9H;EACA,OAAO,IAAAC,cAAO,EAAC,MAAMN,oBAAoB,CAACC,cAAc,CAAC,EAAEI,YAAY,CAAC;AAC1E"} diff --git a/package/lib/commonjs/index.js b/package/lib/commonjs/index.js new file mode 100644 index 0000000000..186286571e --- /dev/null +++ b/package/lib/commonjs/index.js @@ -0,0 +1,292 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +var _Camera = require("./Camera"); +Object.keys(_Camera).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + if (key in exports && exports[key] === _Camera[key]) return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _Camera[key]; + } + }); +}); +var _CameraError = require("./CameraError"); +Object.keys(_CameraError).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + if (key in exports && exports[key] === _CameraError[key]) return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _CameraError[key]; + } + }); +}); +var _CameraDevice = require("./types/CameraDevice"); +Object.keys(_CameraDevice).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + if (key in exports && exports[key] === _CameraDevice[key]) return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _CameraDevice[key]; + } + }); +}); +var _CameraProps = require("./types/CameraProps"); +Object.keys(_CameraProps).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + if (key in exports && exports[key] === _CameraProps[key]) return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _CameraProps[key]; + } + }); +}); +var _Frame = require("./types/Frame"); +Object.keys(_Frame).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + if (key in exports && exports[key] === _Frame[key]) return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _Frame[key]; + } + }); +}); +var _Orientation = require("./types/Orientation"); +Object.keys(_Orientation).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + if (key in exports && exports[key] === _Orientation[key]) return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _Orientation[key]; + } + }); +}); +var _OutputOrientation = require("./types/OutputOrientation"); +Object.keys(_OutputOrientation).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + if (key in exports && exports[key] === _OutputOrientation[key]) return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _OutputOrientation[key]; + } + }); +}); +var _PhotoFile = require("./types/PhotoFile"); +Object.keys(_PhotoFile).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + if (key in exports && exports[key] === _PhotoFile[key]) return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _PhotoFile[key]; + } + }); +}); +var _Snapshot = require("./types/Snapshot"); +Object.keys(_Snapshot).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + if (key in exports && exports[key] === _Snapshot[key]) return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _Snapshot[key]; + } + }); +}); +var _PixelFormat = require("./types/PixelFormat"); +Object.keys(_PixelFormat).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + if (key in exports && exports[key] === _PixelFormat[key]) return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _PixelFormat[key]; + } + }); +}); +var _Point = require("./types/Point"); +Object.keys(_Point).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + if (key in exports && exports[key] === _Point[key]) return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _Point[key]; + } + }); +}); +var _VideoFile = require("./types/VideoFile"); +Object.keys(_VideoFile).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + if (key in exports && exports[key] === _VideoFile[key]) return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _VideoFile[key]; + } + }); +}); +var _CodeScanner = require("./types/CodeScanner"); +Object.keys(_CodeScanner).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + if (key in exports && exports[key] === _CodeScanner[key]) return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _CodeScanner[key]; + } + }); +}); +var _getCameraFormat = require("./devices/getCameraFormat"); +Object.keys(_getCameraFormat).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + if (key in exports && exports[key] === _getCameraFormat[key]) return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _getCameraFormat[key]; + } + }); +}); +var _getCameraDevice = require("./devices/getCameraDevice"); +Object.keys(_getCameraDevice).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + if (key in exports && exports[key] === _getCameraDevice[key]) return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _getCameraDevice[key]; + } + }); +}); +var _Templates = require("./devices/Templates"); +Object.keys(_Templates).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + if (key in exports && exports[key] === _Templates[key]) return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _Templates[key]; + } + }); +}); +var _useCameraDevice = require("./hooks/useCameraDevice"); +Object.keys(_useCameraDevice).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + if (key in exports && exports[key] === _useCameraDevice[key]) return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _useCameraDevice[key]; + } + }); +}); +var _useCameraDevices = require("./hooks/useCameraDevices"); +Object.keys(_useCameraDevices).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + if (key in exports && exports[key] === _useCameraDevices[key]) return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _useCameraDevices[key]; + } + }); +}); +var _useCameraFormat = require("./hooks/useCameraFormat"); +Object.keys(_useCameraFormat).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + if (key in exports && exports[key] === _useCameraFormat[key]) return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _useCameraFormat[key]; + } + }); +}); +var _useCameraPermission = require("./hooks/useCameraPermission"); +Object.keys(_useCameraPermission).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + if (key in exports && exports[key] === _useCameraPermission[key]) return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _useCameraPermission[key]; + } + }); +}); +var _useCodeScanner = require("./hooks/useCodeScanner"); +Object.keys(_useCodeScanner).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + if (key in exports && exports[key] === _useCodeScanner[key]) return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _useCodeScanner[key]; + } + }); +}); +var _useFrameProcessor = require("./hooks/useFrameProcessor"); +Object.keys(_useFrameProcessor).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + if (key in exports && exports[key] === _useFrameProcessor[key]) return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _useFrameProcessor[key]; + } + }); +}); +var _runAsync = require("./frame-processors/runAsync"); +Object.keys(_runAsync).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + if (key in exports && exports[key] === _runAsync[key]) return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _runAsync[key]; + } + }); +}); +var _runAtTargetFps = require("./frame-processors/runAtTargetFps"); +Object.keys(_runAtTargetFps).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + if (key in exports && exports[key] === _runAtTargetFps[key]) return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _runAtTargetFps[key]; + } + }); +}); +var _VisionCameraProxy = require("./frame-processors/VisionCameraProxy"); +Object.keys(_VisionCameraProxy).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + if (key in exports && exports[key] === _VisionCameraProxy[key]) return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _VisionCameraProxy[key]; + } + }); +}); +var _useSkiaFrameProcessor = require("./skia/useSkiaFrameProcessor"); +Object.keys(_useSkiaFrameProcessor).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + if (key in exports && exports[key] === _useSkiaFrameProcessor[key]) return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _useSkiaFrameProcessor[key]; + } + }); +}); +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/package/lib/commonjs/index.js.map b/package/lib/commonjs/index.js.map new file mode 100644 index 0000000000..37d257230e --- /dev/null +++ b/package/lib/commonjs/index.js.map @@ -0,0 +1 @@ +{"version":3,"names":["_Camera","require","Object","keys","forEach","key","exports","defineProperty","enumerable","get","_CameraError","_CameraDevice","_CameraProps","_Frame","_Orientation","_OutputOrientation","_PhotoFile","_Snapshot","_PixelFormat","_Point","_VideoFile","_CodeScanner","_getCameraFormat","_getCameraDevice","_Templates","_useCameraDevice","_useCameraDevices","_useCameraFormat","_useCameraPermission","_useCodeScanner","_useFrameProcessor","_runAsync","_runAtTargetFps","_VisionCameraProxy","_useSkiaFrameProcessor"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":"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"} diff --git a/package/lib/commonjs/skia/SkiaCameraCanvas.js b/package/lib/commonjs/skia/SkiaCameraCanvas.js new file mode 100644 index 0000000000..886615d6e3 --- /dev/null +++ b/package/lib/commonjs/skia/SkiaCameraCanvas.js @@ -0,0 +1,59 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.SkiaCameraCanvas = void 0; +var _react = _interopRequireWildcard(require("react")); +var _ReanimatedProxy = require("../dependencies/ReanimatedProxy"); +var _SkiaProxy = require("../dependencies/SkiaProxy"); +function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } +function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } +function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } +function SkiaCameraCanvasImpl({ + offscreenTextures, + resizeMode = 'cover', + children, + ...props +}) { + const texture = _ReanimatedProxy.ReanimatedProxy.useSharedValue(null); + const [width, setWidth] = (0, _react.useState)(0); + const [height, setHeight] = (0, _react.useState)(0); + _ReanimatedProxy.ReanimatedProxy.useFrameCallback(() => { + 'worklet'; + + // 1. atomically pop() the latest rendered frame/texture from our queue + const latestTexture = offscreenTextures.value.pop(); + if (latestTexture == null) { + // we don't have a new Frame from the Camera yet, skip this render. + return; + } + + // 2. dispose the last rendered frame + texture.value?.dispose(); + + // 3. set a new one which will be rendered then + texture.value = latestTexture; + }); + const onLayout = (0, _react.useCallback)(({ + nativeEvent: { + layout + } + }) => { + setWidth(Math.round(layout.width)); + setHeight(Math.round(layout.height)); + }, []); + return /*#__PURE__*/_react.default.createElement(_SkiaProxy.SkiaProxy.Canvas, _extends({}, props, { + onLayout: onLayout, + pointerEvents: "none" + }), children, /*#__PURE__*/_react.default.createElement(_SkiaProxy.SkiaProxy.Image, { + x: 0, + y: 0, + width: width, + height: height, + fit: resizeMode, + image: texture + })); +} +const SkiaCameraCanvas = exports.SkiaCameraCanvas = /*#__PURE__*/_react.default.memo(SkiaCameraCanvasImpl); +//# sourceMappingURL=SkiaCameraCanvas.js.map \ No newline at end of file diff --git a/package/lib/commonjs/skia/SkiaCameraCanvas.js.map b/package/lib/commonjs/skia/SkiaCameraCanvas.js.map new file mode 100644 index 0000000000..b2b896f759 --- /dev/null +++ b/package/lib/commonjs/skia/SkiaCameraCanvas.js.map @@ -0,0 +1 @@ +{"version":3,"names":["_react","_interopRequireWildcard","require","_ReanimatedProxy","_SkiaProxy","_getRequireWildcardCache","e","WeakMap","r","t","__esModule","default","has","get","n","__proto__","a","Object","defineProperty","getOwnPropertyDescriptor","u","prototype","hasOwnProperty","call","i","set","_extends","assign","bind","target","arguments","length","source","key","apply","SkiaCameraCanvasImpl","offscreenTextures","resizeMode","children","props","texture","ReanimatedProxy","useSharedValue","width","setWidth","useState","height","setHeight","useFrameCallback","latestTexture","value","pop","dispose","onLayout","useCallback","nativeEvent","layout","Math","round","createElement","SkiaProxy","Canvas","pointerEvents","Image","x","y","fit","image","SkiaCameraCanvas","exports","React","memo"],"sourceRoot":"../../../src","sources":["skia/SkiaCameraCanvas.tsx"],"mappings":"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"} diff --git a/package/lib/commonjs/skia/useSkiaFrameProcessor.js b/package/lib/commonjs/skia/useSkiaFrameProcessor.js new file mode 100644 index 0000000000..63dcb71b47 --- /dev/null +++ b/package/lib/commonjs/skia/useSkiaFrameProcessor.js @@ -0,0 +1,316 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.createSkiaFrameProcessor = createSkiaFrameProcessor; +exports.useSkiaFrameProcessor = useSkiaFrameProcessor; +var _react = require("react"); +var _WorkletsProxy = require("../dependencies/WorkletsProxy"); +var _SkiaProxy = require("../dependencies/SkiaProxy"); +var _withFrameRefCounting = require("../frame-processors/withFrameRefCounting"); +var _VisionCameraProxy = require("../frame-processors/VisionCameraProxy"); +/** + * Represents a Camera Frame that can be directly drawn to using Skia. + * + * @see {@linkcode useSkiaFrameProcessor} + * @see {@linkcode render} + */ + +function getDegrees(orientation) { + 'worklet'; + + switch (orientation) { + case 'portrait': + return 0; + case 'landscape-left': + return 90; + case 'portrait-upside-down': + return 180; + case 'landscape-right': + return 270; + } +} +function getOrientation(degrees) { + 'worklet'; + + const clamped = (degrees + 360) % 360; + if (clamped >= 315 || clamped <= 45) return 'portrait';else if (clamped >= 45 && clamped <= 135) return 'landscape-left';else if (clamped >= 135 && clamped <= 225) return 'portrait-upside-down';else if (clamped >= 225 && clamped <= 315) return 'landscape-right';else throw new Error(`Invalid degrees! ${degrees}`); +} +function relativeTo(a, b) { + 'worklet'; + + return getOrientation(getDegrees(a) - getDegrees(b)); +} + +/** + * Counter-rotates the {@linkcode canvas} by the {@linkcode frame}'s {@linkcode Frame.orientation orientation} + * to ensure the Frame will be drawn upright. + */ +function withRotatedFrame(frame, canvas, previewOrientation, func) { + 'worklet'; + + // 1. save current translation matrix + canvas.save(); + try { + // 2. properly rotate canvas so Frame is rendered up-right. + const orientation = relativeTo(frame.orientation, previewOrientation); + switch (orientation) { + case 'portrait': + // do nothing + break; + case 'landscape-left': + // rotate two flips on (0,0) origin and move X + Y into view again + canvas.translate(frame.height, frame.width); + canvas.rotate(270, 0, 0); + break; + case 'portrait-upside-down': + // rotate three flips on (0,0) origin and move Y into view again + canvas.translate(frame.width, frame.height); + canvas.rotate(180, 0, 0); + break; + case 'landscape-right': + // rotate one flip on (0,0) origin and move X into view again + canvas.translate(frame.height, 0); + canvas.rotate(90, 0, 0); + break; + default: + throw new Error(`Invalid frame.orientation: ${frame.orientation}!`); + } + + // 3. call actual processing code + func(); + } finally { + // 4. restore matrix again to original base + canvas.restore(); + } +} +/** + * Get the size of the surface that will be used for rendering, which already accounts + * for the Frame's {@linkcode Frame.orientation orientation}. + */ +function getSurfaceSize(frame) { + 'worklet'; + + switch (frame.orientation) { + case 'portrait': + case 'portrait-upside-down': + return { + width: frame.width, + height: frame.height + }; + case 'landscape-left': + case 'landscape-right': + return { + width: frame.height, + height: frame.width + }; + } +} + +/** + * Create a new Frame Processor function which you can pass to the ``. + * (See ["Frame Processors"](https://react-native-vision-camera.com/docs/guides/frame-processors)) + * + * Make sure to add the `'worklet'` directive to the top of the Frame Processor function, otherwise it will not get compiled into a worklet. + * + * Also make sure to memoize the returned object, so that the Camera doesn't reset the Frame Processor Context each time. + * + * @worklet + * @example + * ```ts + * const surfaceHolder = Worklets.createSharedValue({}) + * const offscreenTextures = Worklets.createSharedValue([]) + * const frameProcessor = createSkiaFrameProcessor((frame) => { + * 'worklet' + * const faces = scanFaces(frame) + * + * frame.render() + * for (const face of faces) { + * const rect = Skia.XYWHRect(face.x, face.y, face.width, face.height) + * frame.drawRect(rect) + * } + * }, surfaceHolder, offscreenTextures) + * ``` + */ +function createSkiaFrameProcessor(frameProcessor, surfaceHolder, offscreenTextures, previewOrientation) { + const Skia = _SkiaProxy.SkiaProxy.Skia; + const Worklets = _WorkletsProxy.WorkletsProxy.Worklets; + const getSkiaSurface = frame => { + 'worklet'; + + // 1. The Frame Processor runs on an iOS `DispatchQueue`, which might use + // multiple C++ Threads between runs (it's still serial though - not concurrent!) + // 2. react-native-skia uses `thread_local` Skia Contexts (`GrDirectContext`), + // which means if a new Thread calls a Skia method, it also uses a new + // Skia Context. + // + // This will cause issues if we cache the `SkSurface` between renders, + // as the next render might be on a different C++ Thread. + // When the next render uses a different C++ Thread, it will also use a + // different Skia Context (`GrDirectContext`) for creating the SkImage, + // than the one used for creating the `SkSurface` in the first render. + // This will cause the render to fail, as an SkImage can only be rendered + // to an SkSurface if both were created on the same Skia Context. + // To prevent this, we cache the SkSurface on a per-thread basis, + // so in my tests the DispatchQueue uses up to 10 different Threads, + // causing 10 different Surfaces to exist in memory. + // A true workaround would be to expose Skia Contexts to JS in RN Skia, + // but for now this is fine. + const threadId = Worklets.getCurrentThreadId(); + const size = getSurfaceSize(frame); + if (surfaceHolder.value[threadId] == null || surfaceHolder.value[threadId]?.width !== size.width || surfaceHolder.value[threadId]?.height !== size.height) { + const surface = Skia.Surface.MakeOffscreen(size.width, size.height); + if (surface == null) { + // skia surface couldn't be allocated + throw new Error(`Failed to create ${size.width}x${size.height} Skia Surface!`); + } + surfaceHolder.value[threadId]?.surface.dispose(); + delete surfaceHolder.value[threadId]; + surfaceHolder.value[threadId] = { + surface: surface, + width: size.width, + height: size.height + }; + } + const surface = surfaceHolder.value[threadId]?.surface; + if (surface == null) throw new Error(`Couldn't find Surface in Thread-cache! ID: ${threadId}`); + return surface; + }; + const createDrawableProxy = (frame, canvas) => { + 'worklet'; + + // Convert Frame to SkImage/Texture + const nativeBuffer = frame.getNativeBuffer(); + const image = Skia.Image.MakeImageFromNativeBuffer(nativeBuffer.pointer); + + // Creates a `Proxy` that holds the SkCanvas, but also adds additional methods such as render() and dispose(). + const canvasProxy = new Proxy(canvas, { + get(_, property) { + switch (property) { + case '__skImage': + return image; + case 'render': + return paint => { + 'worklet'; + + if (paint != null) canvas.drawImage(image, 0, 0, paint);else canvas.drawImage(image, 0, 0); + }; + case 'dispose': + return () => { + 'worklet'; + + // dispose the Frame and the SkImage/Texture + image.dispose(); + nativeBuffer.delete(); + }; + } + return canvas[property]; + } + }); + return frame.withBaseClass(canvasProxy); + }; + return { + frameProcessor: (0, _withFrameRefCounting.withFrameRefCounting)(frame => { + 'worklet'; + + // 1. Set up Skia Surface with size of Frame + const surface = getSkiaSurface(frame); + + // 2. Create DrawableFrame proxy which internally creates an SkImage/Texture + const canvas = surface.getCanvas(); + const drawableFrame = createDrawableProxy(frame, canvas); + try { + // 3. Clear the current Canvas + const black = Skia.Color('black'); + canvas.clear(black); + + // 4. rotate the frame properly to make sure it's upright + withRotatedFrame(frame, canvas, previewOrientation.value, () => { + // 5. Run any user drawing operations + frameProcessor(drawableFrame); + }); + + // 6. Flush draw operations and submit to GPU + surface.flush(); + } finally { + // 7. Delete the SkImage/Texture that holds the Frame + drawableFrame.dispose(); + } + + // 8. Capture rendered results as a Texture/SkImage to later render to screen + const snapshot = surface.makeImageSnapshot(); + const snapshotCopy = snapshot.makeNonTextureImage(); + snapshot.dispose(); + offscreenTextures.value.push(snapshotCopy); + + // 9. Close old textures that are still in the queue. + while (offscreenTextures.value.length > 1) { + // shift() atomically removes the first element, and is therefore thread-safe. + const texture = offscreenTextures.value.shift(); + if (texture == null) break; + texture.dispose(); + } + }), + type: 'drawable-skia', + offscreenTextures: offscreenTextures, + previewOrientation: previewOrientation + }; +} + +/** + * Returns a memoized Skia Frame Processor function wich you can pass to the ``. + * + * The Skia Frame Processor alows you to draw ontop of the Frame, and will manage it's internal offscreen Skia Canvas + * and onscreen Skia preview view. + * + * (See ["Frame Processors"](https://react-native-vision-camera.com/docs/guides/frame-processors)) + * + * Make sure to add the `'worklet'` directive to the top of the Frame Processor function, otherwise it will not get compiled into a worklet. + * + * @worklet + * @param frameProcessor The Frame Processor + * @param dependencies The React dependencies which will be copied into the VisionCamera JS-Runtime. + * @returns The memoized Skia Frame Processor. + * @example + * ```ts + * const frameProcessor = useSkiaFrameProcessor((frame) => { + * 'worklet' + * const faces = scanFaces(frame) + * + * frame.render() + * for (const face of faces) { + * const rect = Skia.XYWHRect(face.x, face.y, face.width, face.height) + * frame.drawRect(rect) + * } + * }, []) + * ``` + */ +function useSkiaFrameProcessor(frameProcessor, dependencies) { + const surface = _WorkletsProxy.WorkletsProxy.useSharedValue({}); + const offscreenTextures = _WorkletsProxy.WorkletsProxy.useSharedValue([]); + const previewOrientation = _WorkletsProxy.WorkletsProxy.useSharedValue('portrait'); + (0, _react.useEffect)(() => { + return () => { + // on unmount, we clean up the resources on the Worklet Context. + // this causes it to run _after_ the Frame Processor has finished executing, + // if it is currently executing - so we avoid race conditions here. + _VisionCameraProxy.VisionCameraProxy.workletContext?.runAsync(() => { + 'worklet'; + + const surfaces = Object.values(surface.value).map(v => v.surface); + surface.value = {}; + surfaces.forEach(s => s.dispose()); + while (offscreenTextures.value.length > 0) { + const texture = offscreenTextures.value.shift(); + if (texture == null) break; + texture.dispose(); + } + }); + }; + }, [offscreenTextures, surface]); + return (0, _react.useMemo)(() => createSkiaFrameProcessor(frameProcessor, surface, offscreenTextures, previewOrientation), + // eslint-disable-next-line react-hooks/exhaustive-deps + dependencies); +} +//# sourceMappingURL=useSkiaFrameProcessor.js.map \ No newline at end of file diff --git a/package/lib/commonjs/skia/useSkiaFrameProcessor.js.map b/package/lib/commonjs/skia/useSkiaFrameProcessor.js.map new file mode 100644 index 0000000000..fa3890615d --- /dev/null +++ b/package/lib/commonjs/skia/useSkiaFrameProcessor.js.map @@ -0,0 +1 @@ +{"version":3,"names":["_react","require","_WorkletsProxy","_SkiaProxy","_withFrameRefCounting","_VisionCameraProxy","getDegrees","orientation","getOrientation","degrees","clamped","Error","relativeTo","a","b","withRotatedFrame","frame","canvas","previewOrientation","func","save","translate","height","width","rotate","restore","getSurfaceSize","createSkiaFrameProcessor","frameProcessor","surfaceHolder","offscreenTextures","Skia","SkiaProxy","Worklets","WorkletsProxy","getSkiaSurface","threadId","getCurrentThreadId","size","value","surface","Surface","MakeOffscreen","dispose","createDrawableProxy","nativeBuffer","getNativeBuffer","image","Image","MakeImageFromNativeBuffer","pointer","canvasProxy","Proxy","get","_","property","paint","drawImage","delete","withBaseClass","withFrameRefCounting","getCanvas","drawableFrame","black","Color","clear","flush","snapshot","makeImageSnapshot","snapshotCopy","makeNonTextureImage","push","length","texture","shift","type","useSkiaFrameProcessor","dependencies","useSharedValue","useEffect","VisionCameraProxy","workletContext","runAsync","surfaces","Object","values","map","v","forEach","s","useMemo"],"sourceRoot":"../../../src","sources":["skia/useSkiaFrameProcessor.ts"],"mappings":"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"} diff --git a/package/lib/commonjs/types/CameraDevice.js b/package/lib/commonjs/types/CameraDevice.js new file mode 100644 index 0000000000..9cedbe983d --- /dev/null +++ b/package/lib/commonjs/types/CameraDevice.js @@ -0,0 +1,6 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +//# sourceMappingURL=CameraDevice.js.map \ No newline at end of file diff --git a/package/lib/commonjs/types/CameraDevice.js.map b/package/lib/commonjs/types/CameraDevice.js.map new file mode 100644 index 0000000000..3fe41bde9d --- /dev/null +++ b/package/lib/commonjs/types/CameraDevice.js.map @@ -0,0 +1 @@ +{"version":3,"names":[],"sourceRoot":"../../../src","sources":["types/CameraDevice.ts"],"mappings":""} diff --git a/package/lib/commonjs/types/CameraProps.js b/package/lib/commonjs/types/CameraProps.js new file mode 100644 index 0000000000..27a47e0375 --- /dev/null +++ b/package/lib/commonjs/types/CameraProps.js @@ -0,0 +1,6 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +//# sourceMappingURL=CameraProps.js.map \ No newline at end of file diff --git a/package/lib/commonjs/types/CameraProps.js.map b/package/lib/commonjs/types/CameraProps.js.map new file mode 100644 index 0000000000..806ac28929 --- /dev/null +++ b/package/lib/commonjs/types/CameraProps.js.map @@ -0,0 +1 @@ +{"version":3,"names":[],"sourceRoot":"../../../src","sources":["types/CameraProps.ts"],"mappings":""} diff --git a/package/lib/commonjs/types/CodeScanner.js b/package/lib/commonjs/types/CodeScanner.js new file mode 100644 index 0000000000..4b3c5ae6a5 --- /dev/null +++ b/package/lib/commonjs/types/CodeScanner.js @@ -0,0 +1,6 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +//# sourceMappingURL=CodeScanner.js.map \ No newline at end of file diff --git a/package/lib/commonjs/types/CodeScanner.js.map b/package/lib/commonjs/types/CodeScanner.js.map new file mode 100644 index 0000000000..0d8321e0f3 --- /dev/null +++ b/package/lib/commonjs/types/CodeScanner.js.map @@ -0,0 +1 @@ +{"version":3,"names":[],"sourceRoot":"../../../src","sources":["types/CodeScanner.ts"],"mappings":""} diff --git a/package/lib/commonjs/types/Frame.js b/package/lib/commonjs/types/Frame.js new file mode 100644 index 0000000000..898b663e99 --- /dev/null +++ b/package/lib/commonjs/types/Frame.js @@ -0,0 +1,6 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +//# sourceMappingURL=Frame.js.map \ No newline at end of file diff --git a/package/lib/commonjs/types/Frame.js.map b/package/lib/commonjs/types/Frame.js.map new file mode 100644 index 0000000000..ef9b29c008 --- /dev/null +++ b/package/lib/commonjs/types/Frame.js.map @@ -0,0 +1 @@ +{"version":3,"names":[],"sourceRoot":"../../../src","sources":["types/Frame.ts"],"mappings":""} diff --git a/package/lib/commonjs/types/Orientation.js b/package/lib/commonjs/types/Orientation.js new file mode 100644 index 0000000000..a790197f0d --- /dev/null +++ b/package/lib/commonjs/types/Orientation.js @@ -0,0 +1,2 @@ +"use strict"; +//# sourceMappingURL=Orientation.js.map \ No newline at end of file diff --git a/package/lib/commonjs/types/Orientation.js.map b/package/lib/commonjs/types/Orientation.js.map new file mode 100644 index 0000000000..300dc6eef9 --- /dev/null +++ b/package/lib/commonjs/types/Orientation.js.map @@ -0,0 +1 @@ +{"version":3,"names":[],"sourceRoot":"../../../src","sources":["types/Orientation.ts"],"mappings":""} diff --git a/package/lib/commonjs/types/OutputOrientation.js b/package/lib/commonjs/types/OutputOrientation.js new file mode 100644 index 0000000000..872503633e --- /dev/null +++ b/package/lib/commonjs/types/OutputOrientation.js @@ -0,0 +1,2 @@ +"use strict"; +//# sourceMappingURL=OutputOrientation.js.map \ No newline at end of file diff --git a/package/lib/commonjs/types/OutputOrientation.js.map b/package/lib/commonjs/types/OutputOrientation.js.map new file mode 100644 index 0000000000..65e6a56734 --- /dev/null +++ b/package/lib/commonjs/types/OutputOrientation.js.map @@ -0,0 +1 @@ +{"version":3,"names":[],"sourceRoot":"../../../src","sources":["types/OutputOrientation.ts"],"mappings":""} diff --git a/package/lib/commonjs/types/PhotoFile.js b/package/lib/commonjs/types/PhotoFile.js new file mode 100644 index 0000000000..651d6d9718 --- /dev/null +++ b/package/lib/commonjs/types/PhotoFile.js @@ -0,0 +1,6 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +//# sourceMappingURL=PhotoFile.js.map \ No newline at end of file diff --git a/package/lib/commonjs/types/PhotoFile.js.map b/package/lib/commonjs/types/PhotoFile.js.map new file mode 100644 index 0000000000..aff0304f5a --- /dev/null +++ b/package/lib/commonjs/types/PhotoFile.js.map @@ -0,0 +1 @@ +{"version":3,"names":[],"sourceRoot":"../../../src","sources":["types/PhotoFile.ts"],"mappings":""} diff --git a/package/lib/commonjs/types/PixelFormat.js b/package/lib/commonjs/types/PixelFormat.js new file mode 100644 index 0000000000..331bd8f8b3 --- /dev/null +++ b/package/lib/commonjs/types/PixelFormat.js @@ -0,0 +1,2 @@ +"use strict"; +//# sourceMappingURL=PixelFormat.js.map \ No newline at end of file diff --git a/package/lib/commonjs/types/PixelFormat.js.map b/package/lib/commonjs/types/PixelFormat.js.map new file mode 100644 index 0000000000..0ce5129416 --- /dev/null +++ b/package/lib/commonjs/types/PixelFormat.js.map @@ -0,0 +1 @@ +{"version":3,"names":[],"sourceRoot":"../../../src","sources":["types/PixelFormat.ts"],"mappings":""} diff --git a/package/lib/commonjs/types/Point.js b/package/lib/commonjs/types/Point.js new file mode 100644 index 0000000000..211a341088 --- /dev/null +++ b/package/lib/commonjs/types/Point.js @@ -0,0 +1,2 @@ +"use strict"; +//# sourceMappingURL=Point.js.map \ No newline at end of file diff --git a/package/lib/commonjs/types/Point.js.map b/package/lib/commonjs/types/Point.js.map new file mode 100644 index 0000000000..baa69dec46 --- /dev/null +++ b/package/lib/commonjs/types/Point.js.map @@ -0,0 +1 @@ +{"version":3,"names":[],"sourceRoot":"../../../src","sources":["types/Point.ts"],"mappings":""} diff --git a/package/lib/commonjs/types/Snapshot.js b/package/lib/commonjs/types/Snapshot.js new file mode 100644 index 0000000000..2e96c91d4e --- /dev/null +++ b/package/lib/commonjs/types/Snapshot.js @@ -0,0 +1,6 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +//# sourceMappingURL=Snapshot.js.map \ No newline at end of file diff --git a/package/lib/commonjs/types/Snapshot.js.map b/package/lib/commonjs/types/Snapshot.js.map new file mode 100644 index 0000000000..7c051279f5 --- /dev/null +++ b/package/lib/commonjs/types/Snapshot.js.map @@ -0,0 +1 @@ +{"version":3,"names":[],"sourceRoot":"../../../src","sources":["types/Snapshot.ts"],"mappings":""} diff --git a/package/lib/commonjs/types/TemporaryFile.js b/package/lib/commonjs/types/TemporaryFile.js new file mode 100644 index 0000000000..e81bbdd46d --- /dev/null +++ b/package/lib/commonjs/types/TemporaryFile.js @@ -0,0 +1,2 @@ +"use strict"; +//# sourceMappingURL=TemporaryFile.js.map \ No newline at end of file diff --git a/package/lib/commonjs/types/TemporaryFile.js.map b/package/lib/commonjs/types/TemporaryFile.js.map new file mode 100644 index 0000000000..2383b61ab8 --- /dev/null +++ b/package/lib/commonjs/types/TemporaryFile.js.map @@ -0,0 +1 @@ +{"version":3,"names":[],"sourceRoot":"../../../src","sources":["types/TemporaryFile.ts"],"mappings":""} diff --git a/package/lib/commonjs/types/VideoFile.js b/package/lib/commonjs/types/VideoFile.js new file mode 100644 index 0000000000..e0fb060cb0 --- /dev/null +++ b/package/lib/commonjs/types/VideoFile.js @@ -0,0 +1,6 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +//# sourceMappingURL=VideoFile.js.map \ No newline at end of file diff --git a/package/lib/commonjs/types/VideoFile.js.map b/package/lib/commonjs/types/VideoFile.js.map new file mode 100644 index 0000000000..d437623ef9 --- /dev/null +++ b/package/lib/commonjs/types/VideoFile.js.map @@ -0,0 +1 @@ +{"version":3,"names":[],"sourceRoot":"../../../src","sources":["types/VideoFile.ts"],"mappings":""} diff --git a/package/lib/module/Camera.js b/package/lib/module/Camera.js new file mode 100644 index 0000000000..317a37471c --- /dev/null +++ b/package/lib/module/Camera.js @@ -0,0 +1,669 @@ +function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } +import React from 'react'; +import { findNodeHandle, StyleSheet } from 'react-native'; +import { CameraRuntimeError, tryParseNativeCameraError, isErrorWithCause } from './CameraError'; +import { CameraModule } from './NativeCameraModule'; +import { VisionCameraProxy } from './frame-processors/VisionCameraProxy'; +import { CameraDevices } from './CameraDevices'; +import { SkiaCameraCanvas } from './skia/SkiaCameraCanvas'; +import { FpsGraph, MAX_BARS } from './FpsGraph'; +import { NativeCameraView } from './NativeCameraView'; +import { RotationHelper } from './RotationHelper'; + +//#region Types + +//#endregion + +function isSkiaFrameProcessor(frameProcessor) { + return frameProcessor?.type === 'drawable-skia'; +} + +//#region Camera Component +/** + * ### A powerful `` component. + * + * Read the [VisionCamera documentation](https://react-native-vision-camera.com/) for more information. + * + * The `` component's most important properties are: + * + * * {@linkcode CameraProps.device | device}: Specifies the {@linkcode CameraDevice} to use. Get a {@linkcode CameraDevice} by using + * the {@linkcode useCameraDevice | useCameraDevice(..)} hook, or manually by using + * the {@linkcode CameraDevices.getAvailableCameraDevices | CameraDevices.getAvailableCameraDevices()} function. + * * {@linkcode CameraProps.isActive | isActive}: A boolean value that specifies whether the Camera should + * actively stream video frames or not. This can be compared to a Video component, where `isActive` specifies whether the video + * is paused or not. If you fully unmount the `` component instead of using `isActive={false}`, the Camera will take a bit longer to start again. + * + * @example + * ```tsx + * function App() { + * const device = useCameraDevice('back') + * + * if (device == null) return + * return ( + * + * ) + * } + * ``` + * + * @component + */ +export class Camera extends React.PureComponent { + /** @internal */ + static displayName = 'Camera'; + /** @internal */ + displayName = Camera.displayName; + isNativeViewMounted = false; + lastUIRotation = undefined; + rotationHelper = new RotationHelper(); + /** @internal */ + constructor(props) { + super(props); + this.onViewReady = this.onViewReady.bind(this); + this.onAverageFpsChanged = this.onAverageFpsChanged.bind(this); + this.onInitialized = this.onInitialized.bind(this); + this.onStarted = this.onStarted.bind(this); + this.onStopped = this.onStopped.bind(this); + this.onPreviewStarted = this.onPreviewStarted.bind(this); + this.onPreviewStopped = this.onPreviewStopped.bind(this); + this.onShutter = this.onShutter.bind(this); + this.onOutputOrientationChanged = this.onOutputOrientationChanged.bind(this); + this.onPreviewOrientationChanged = this.onPreviewOrientationChanged.bind(this); + this.onError = this.onError.bind(this); + this.onCodeScanned = this.onCodeScanned.bind(this); + this.ref = /*#__PURE__*/React.createRef(); + this.lastFrameProcessor = undefined; + this.state = { + isRecordingWithFlash: false, + averageFpsSamples: [] + }; + } + get handle() { + const nodeHandle = findNodeHandle(this.ref.current); + if (nodeHandle == null || nodeHandle === -1) { + throw new CameraRuntimeError('system/view-not-found', "Could not get the Camera's native view tag! Does the Camera View exist in the native view-tree?"); + } + return nodeHandle; + } + + //#region View-specific functions (UIViewManager) + /** + * Take a single photo and write it's content to a temporary file. + * + * @throws {@linkcode CameraCaptureError} When any kind of error occured while capturing the photo. + * Use the {@linkcode CameraCaptureError.code | code} property to get the actual error + * @example + * ```ts + * const photo = await camera.current.takePhoto({ + * flash: 'on', + * enableAutoRedEyeReduction: true + * }) + * ``` + */ + async takePhoto(options) { + try { + return await CameraModule.takePhoto(this.handle, options ?? {}); + } catch (e) { + throw tryParseNativeCameraError(e); + } + } + + /** + * Captures a snapshot of the Camera view and write it's content to a temporary file. + * + * - On iOS, `takeSnapshot` waits for a Frame from the video pipeline and therefore requires `video` to be enabled. + * - On Android, `takeSnapshot` performs a GPU view screenshot from the preview view. + * + * @throws {@linkcode CameraCaptureError} When any kind of error occured while capturing the photo. + * Use the {@linkcode CameraCaptureError.code | code} property to get the actual error + * @example + * ```ts + * const snapshot = await camera.current.takeSnapshot({ + * quality: 100 + * }) + * ``` + */ + async takeSnapshot(options) { + try { + return await CameraModule.takeSnapshot(this.handle, options ?? {}); + } catch (e) { + throw tryParseNativeCameraError(e); + } + } + getBitRateMultiplier(bitRate) { + if (typeof bitRate === 'number' || bitRate == null) return 1; + switch (bitRate) { + case 'extra-low': + return 0.6; + case 'low': + return 0.8; + case 'normal': + return 1; + case 'high': + return 1.2; + case 'extra-high': + return 1.4; + } + } + + /** + * Start a new video recording. + * + * @throws {@linkcode CameraCaptureError} When any kind of error occured while starting the video recording. + * Use the {@linkcode CameraCaptureError.code | code} property to get the actual error + * + * @example + * ```ts + * camera.current.startRecording({ + * onRecordingFinished: (video) => console.log(video), + * onRecordingError: (error) => console.error(error), + * }) + * setTimeout(() => { + * camera.current.stopRecording() + * }, 5000) + * ``` + */ + startRecording(options) { + const { + onRecordingError, + onRecordingFinished, + videoBitRate, + ...passThruOptions + } = options; + if (typeof onRecordingError !== 'function' || typeof onRecordingFinished !== 'function') throw new CameraRuntimeError('parameter/invalid-parameter', 'The onRecordingError or onRecordingFinished functions were not set!'); + if (options.flash === 'on') { + // Enable torch for video recording + this.setState({ + isRecordingWithFlash: true + }); + } + const nativeOptions = passThruOptions; + if (typeof videoBitRate === 'number') { + // If the user passed an absolute number as a bit-rate, we just use this as a full override. + nativeOptions.videoBitRateOverride = videoBitRate; + } else if (typeof videoBitRate === 'string' && videoBitRate !== 'normal') { + // If the user passed 'low'/'normal'/'high', we need to apply this as a multiplier to the native bitrate instead of absolutely setting it + nativeOptions.videoBitRateMultiplier = this.getBitRateMultiplier(videoBitRate); + } + const onRecordCallback = (video, error) => { + if (this.state.isRecordingWithFlash) { + // disable torch again if it was enabled + this.setState({ + isRecordingWithFlash: false + }); + } + if (error != null) return onRecordingError(error); + if (video != null) return onRecordingFinished(video); + }; + try { + // TODO: Use TurboModules to make this awaitable. + CameraModule.startRecording(this.handle, nativeOptions, onRecordCallback); + } catch (e) { + throw tryParseNativeCameraError(e); + } + } + + /** + * Pauses the current video recording. + * + * @throws {@linkcode CameraCaptureError} When any kind of error occured while pausing the video recording. + * Use the {@linkcode CameraCaptureError.code | code} property to get the actual error + * + * @example + * ```ts + * // Start + * await camera.current.startRecording({ + * onRecordingFinished: (video) => console.log(video), + * onRecordingError: (error) => console.error(error), + * }) + * await timeout(1000) + * // Pause + * await camera.current.pauseRecording() + * await timeout(500) + * // Resume + * await camera.current.resumeRecording() + * await timeout(2000) + * // Stop + * await camera.current.stopRecording() + * ``` + */ + async pauseRecording() { + try { + return await CameraModule.pauseRecording(this.handle); + } catch (e) { + throw tryParseNativeCameraError(e); + } + } + + /** + * Resumes a currently paused video recording. + * + * @throws {@linkcode CameraCaptureError} When any kind of error occured while resuming the video recording. + * Use the {@linkcode CameraCaptureError.code | code} property to get the actual error + * + * @example + * ```ts + * // Start + * await camera.current.startRecording({ + * onRecordingFinished: (video) => console.log(video), + * onRecordingError: (error) => console.error(error), + * }) + * await timeout(1000) + * // Pause + * await camera.current.pauseRecording() + * await timeout(500) + * // Resume + * await camera.current.resumeRecording() + * await timeout(2000) + * // Stop + * await camera.current.stopRecording() + * ``` + */ + async resumeRecording() { + try { + return await CameraModule.resumeRecording(this.handle); + } catch (e) { + throw tryParseNativeCameraError(e); + } + } + + /** + * Stop the current video recording. + * + * @throws {@linkcode CameraCaptureError} When any kind of error occured while stopping the video recording. + * Use the {@linkcode CameraCaptureError.code | code} property to get the actual error + * + * @example + * ```ts + * await camera.current.startRecording({ + * onRecordingFinished: (video) => console.log(video), + * onRecordingError: (error) => console.error(error), + * }) + * setTimeout(async () => { + * await camera.current.stopRecording() + * }, 5000) + * ``` + */ + async stopRecording() { + try { + return await CameraModule.stopRecording(this.handle); + } catch (e) { + throw tryParseNativeCameraError(e); + } + } + + /** + * Cancel the current video recording. The temporary video file will be deleted, + * and the `startRecording`'s `onRecordingError` callback will be invoked with a `capture/recording-canceled` error. + * + * @throws {@linkcode CameraCaptureError} When any kind of error occured while canceling the video recording. + * Use the {@linkcode CameraCaptureError.code | code} property to get the actual error + * + * @example + * ```ts + * await camera.current.startRecording({ + * onRecordingFinished: (video) => console.log(video), + * onRecordingError: (error) => { + * if (error.code === 'capture/recording-canceled') { + * // recording was canceled. + * } else { + * console.error(error) + * } + * }, + * }) + * setTimeout(async () => { + * await camera.current.cancelRecording() + * }, 5000) + * ``` + */ + async cancelRecording() { + try { + return await CameraModule.cancelRecording(this.handle); + } catch (e) { + throw tryParseNativeCameraError(e); + } + } + + /** + * Focus the camera to a specific point in the coordinate system. + * @param {Point} point The point to focus to. This should be relative + * to the Camera view's coordinate system and is expressed in points. + * * `(0, 0)` means **top left**. + * * `(CameraView.width, CameraView.height)` means **bottom right**. + * + * Make sure the value doesn't exceed the CameraView's dimensions. + * + * @throws {@linkcode CameraRuntimeError} When any kind of error occured while focussing. + * Use the {@linkcode CameraRuntimeError.code | code} property to get the actual error + * @example + * ```ts + * await camera.current.focus({ + * x: tapEvent.x, + * y: tapEvent.y + * }) + * ``` + */ + async focus(point) { + try { + return await CameraModule.focus(this.handle, point); + } catch (e) { + throw tryParseNativeCameraError(e); + } + } + //#endregion + + async lockFocusAndExposureToPoint(point) { + try { + return await CameraModule.lockFocusAndExposureToPoint(this.handle, point); + } catch (e) { + throw tryParseNativeCameraError(e); + } + } + async freeFocusAndExposure() { + try { + return await CameraModule.freeFocusAndExposure(this.handle); + } catch (e) { + throw tryParseNativeCameraError(e); + } + } + + //#region Static Functions (NativeModule) + /** + * Get a list of all available camera devices on the current phone. + * + * If you use Hooks, use the `useCameraDevices(..)` hook instead. + * + * * For Camera Devices attached to the phone, it is safe to assume that this will never change. + * * For external Camera Devices (USB cameras, Mac continuity cameras, etc.) the available Camera Devices + * could change over time when the external Camera device gets plugged in or plugged out, so + * use {@link addCameraDevicesChangedListener | addCameraDevicesChangedListener(...)} to listen for such changes. + * + * @example + * ```ts + * const devices = Camera.getAvailableCameraDevices() + * const backCameras = devices.filter((d) => d.position === "back") + * const frontCameras = devices.filter((d) => d.position === "front") + * ``` + */ + static getAvailableCameraDevices() { + return CameraDevices.getAvailableCameraDevices(); + } + /** + * Adds a listener that gets called everytime the Camera Devices change, for example + * when an external Camera Device (USB or continuity Camera) gets plugged in or plugged out. + * + * If you use Hooks, use the `useCameraDevices()` hook instead. + */ + static addCameraDevicesChangedListener(listener) { + return CameraDevices.addCameraDevicesChangedListener(listener); + } + /** + * Gets the current Camera Permission Status. Check this before mounting the Camera to ensure + * the user has permitted the app to use the camera. + * + * To actually prompt the user for camera permission, use {@linkcode Camera.requestCameraPermission | requestCameraPermission()}. + */ + static getCameraPermissionStatus() { + return CameraModule.getCameraPermissionStatus(); + } + /** + * Gets the current Microphone-Recording Permission Status. + * Check this before enabling the `audio={...}` property to make sure the + * user has permitted the app to use the microphone. + * + * To actually prompt the user for microphone permission, use {@linkcode Camera.requestMicrophonePermission | requestMicrophonePermission()}. + */ + static getMicrophonePermissionStatus() { + return CameraModule.getMicrophonePermissionStatus(); + } + /** + * Gets the current Location Permission Status. + * Check this before enabling the `location={...}` property to make sure the + * the user has permitted the app to use the location. + * + * To actually prompt the user for location permission, use {@linkcode Camera.requestLocationPermission | requestLocationPermission()}. + * + * Note: This method will throw a `system/location-not-enabled` error if the Location APIs are not enabled at build-time. + * See [the "GPS Location Tags" documentation](https://react-native-vision-camera.com/docs/guides/location) for more information. + */ + static getLocationPermissionStatus() { + return CameraModule.getLocationPermissionStatus(); + } + /** + * Shows a "request permission" alert to the user, and resolves with the new camera permission status. + * + * If the user has previously blocked the app from using the camera, the alert will not be shown + * and `"denied"` will be returned. + * + * @throws {@linkcode CameraRuntimeError} When any kind of error occured while requesting permission. + * Use the {@linkcode CameraRuntimeError.code | code} property to get the actual error + */ + static async requestCameraPermission() { + try { + return await CameraModule.requestCameraPermission(); + } catch (e) { + throw tryParseNativeCameraError(e); + } + } + /** + * Shows a "request permission" alert to the user, and resolves with the new microphone permission status. + * + * If the user has previously blocked the app from using the microphone, the alert will not be shown + * and `"denied"` will be returned. + * + * @throws {@linkcode CameraRuntimeError} When any kind of error occured while requesting permission. + * Use the {@linkcode CameraRuntimeError.code | code} property to get the actual error + */ + static async requestMicrophonePermission() { + try { + return await CameraModule.requestMicrophonePermission(); + } catch (e) { + throw tryParseNativeCameraError(e); + } + } + /** + * Shows a "request permission" alert to the user, and resolves with the new location permission status. + * + * If the user has previously blocked the app from using the location, the alert will not be shown + * and `"denied"` will be returned. + * + * @throws {@linkcode CameraRuntimeError} When any kind of error occured while requesting permission. + * Use the {@linkcode CameraRuntimeError.code | code} property to get the actual error + */ + static async requestLocationPermission() { + try { + return await CameraModule.requestLocationPermission(); + } catch (e) { + throw tryParseNativeCameraError(e); + } + } + //#endregion + + //#region Events (Wrapped to maintain reference equality) + onError(event) { + const error = event.nativeEvent; + const cause = isErrorWithCause(error.cause) ? error.cause : undefined; + // @ts-expect-error We're casting from unknown bridge types to TS unions, I expect it to hopefully work + const cameraError = new CameraRuntimeError(error.code, error.message, cause); + if (this.props.onError != null) { + this.props.onError(cameraError); + } else { + // User didn't pass an `onError` handler, so just log it to console + console.error(cameraError); + } + } + onInitialized() { + this.props.onInitialized?.(); + } + onStarted() { + this.props.onStarted?.(); + } + onStopped() { + this.props.onStopped?.(); + } + onPreviewStarted() { + this.props.onPreviewStarted?.(); + } + onPreviewStopped() { + this.props.onPreviewStopped?.(); + } + onShutter(event) { + this.props.onShutter?.(event.nativeEvent); + } + onOutputOrientationChanged({ + nativeEvent: { + outputOrientation + } + }) { + this.rotationHelper.outputOrientation = outputOrientation; + this.props.onOutputOrientationChanged?.(outputOrientation); + this.maybeUpdateUIRotation(); + } + onPreviewOrientationChanged({ + nativeEvent: { + previewOrientation + } + }) { + this.rotationHelper.previewOrientation = previewOrientation; + this.props.onPreviewOrientationChanged?.(previewOrientation); + this.maybeUpdateUIRotation(); + if (isSkiaFrameProcessor(this.props.frameProcessor)) { + // If we have a Skia Frame Processor, we need to update it's orientation so it knows how to render. + this.props.frameProcessor.previewOrientation.value = previewOrientation; + } + } + maybeUpdateUIRotation() { + const uiRotation = this.rotationHelper.uiRotation; + if (uiRotation !== this.lastUIRotation) { + this.props.onUIRotationChanged?.(uiRotation); + this.lastUIRotation = uiRotation; + } + } + //#endregion + + onCodeScanned(event) { + const codeScanner = this.props.codeScanner; + if (codeScanner == null) return; + codeScanner.onCodeScanned(event.nativeEvent.codes, event.nativeEvent.frame); + } + + //#region Lifecycle + setFrameProcessor(frameProcessor) { + VisionCameraProxy.setFrameProcessor(this.handle, frameProcessor); + } + unsetFrameProcessor() { + VisionCameraProxy.removeFrameProcessor(this.handle); + } + onViewReady() { + this.isNativeViewMounted = true; + if (this.props.frameProcessor != null) { + // user passed a `frameProcessor` but we didn't set it yet because the native view was not mounted yet. set it now. + this.setFrameProcessor(this.props.frameProcessor.frameProcessor); + this.lastFrameProcessor = this.props.frameProcessor.frameProcessor; + } + } + onAverageFpsChanged({ + nativeEvent: { + averageFps + } + }) { + this.setState(state => { + const averageFpsSamples = [...state.averageFpsSamples, averageFps]; + while (averageFpsSamples.length >= MAX_BARS + 1) { + // we keep a maximum of 30 FPS samples in our history + averageFpsSamples.shift(); + } + return { + ...state, + averageFpsSamples: averageFpsSamples + }; + }); + } + + /** @internal */ + componentDidUpdate() { + if (!this.isNativeViewMounted) return; + const frameProcessor = this.props.frameProcessor; + if (frameProcessor?.frameProcessor !== this.lastFrameProcessor) { + // frameProcessor argument identity changed. Update native to reflect the change. + if (frameProcessor != null) this.setFrameProcessor(frameProcessor.frameProcessor);else this.unsetFrameProcessor(); + this.lastFrameProcessor = frameProcessor?.frameProcessor; + } + } + //#endregion + + /** @internal */ + render() { + // We remove the big `device` object from the props because we only need to pass `cameraId` to native. + const { + device, + frameProcessor, + codeScanner, + enableFpsGraph, + fps, + ...props + } = this.props; + + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (device == null) { + throw new CameraRuntimeError('device/no-device', 'Camera: `device` is null! Select a valid Camera device. See: https://mrousavy.com/react-native-vision-camera/docs/guides/devices'); + } + const shouldEnableBufferCompression = props.video === true && frameProcessor == null; + const torch = this.state.isRecordingWithFlash ? 'on' : props.torch; + const isRenderingWithSkia = isSkiaFrameProcessor(frameProcessor); + const shouldBeMirrored = device.position === 'front'; + + // minFps/maxFps is either the fixed `fps` value, or a value from the [min, max] tuple + const minFps = fps == null ? undefined : typeof fps === 'number' ? fps : fps[0]; + const maxFps = fps == null ? undefined : typeof fps === 'number' ? fps : fps[1]; + return /*#__PURE__*/React.createElement(NativeCameraView, _extends({}, props, { + cameraId: device.id, + ref: this.ref, + torch: torch, + minFps: minFps, + maxFps: maxFps, + isMirrored: props.isMirrored ?? shouldBeMirrored, + onViewReady: this.onViewReady, + onAverageFpsChanged: enableFpsGraph ? this.onAverageFpsChanged : undefined, + onInitialized: this.onInitialized, + onCodeScanned: this.onCodeScanned, + onStarted: this.onStarted, + onStopped: this.onStopped, + onPreviewStarted: this.onPreviewStarted, + onPreviewStopped: this.onPreviewStopped, + onShutter: this.onShutter, + onOutputOrientationChanged: this.onOutputOrientationChanged, + onPreviewOrientationChanged: this.onPreviewOrientationChanged, + onError: this.onError, + codeScannerOptions: codeScanner, + enableFrameProcessor: frameProcessor != null, + enableBufferCompression: props.enableBufferCompression ?? shouldEnableBufferCompression, + preview: isRenderingWithSkia ? false : props.preview ?? true + }), isRenderingWithSkia && /*#__PURE__*/React.createElement(SkiaCameraCanvas, { + style: styles.customPreviewView, + offscreenTextures: frameProcessor.offscreenTextures, + resizeMode: props.resizeMode + }), enableFpsGraph && /*#__PURE__*/React.createElement(FpsGraph, { + style: styles.fpsGraph, + averageFpsSamples: this.state.averageFpsSamples, + targetMaxFps: props.format?.maxFps ?? 60 + })); + } +} +//#endregion + +const styles = StyleSheet.create({ + customPreviewView: { + flex: 1 + }, + fpsGraph: { + elevation: 1, + position: 'absolute', + left: 15, + top: 30 + } +}); +//# sourceMappingURL=Camera.js.map \ No newline at end of file diff --git a/package/lib/module/Camera.js.map b/package/lib/module/Camera.js.map new file mode 100644 index 0000000000..3884e0bef3 --- /dev/null +++ b/package/lib/module/Camera.js.map @@ -0,0 +1 @@ +{"version":3,"names":["React","findNodeHandle","StyleSheet","CameraRuntimeError","tryParseNativeCameraError","isErrorWithCause","CameraModule","VisionCameraProxy","CameraDevices","SkiaCameraCanvas","FpsGraph","MAX_BARS","NativeCameraView","RotationHelper","isSkiaFrameProcessor","frameProcessor","type","Camera","PureComponent","displayName","isNativeViewMounted","lastUIRotation","undefined","rotationHelper","constructor","props","onViewReady","bind","onAverageFpsChanged","onInitialized","onStarted","onStopped","onPreviewStarted","onPreviewStopped","onShutter","onOutputOrientationChanged","onPreviewOrientationChanged","onError","onCodeScanned","ref","createRef","lastFrameProcessor","state","isRecordingWithFlash","averageFpsSamples","handle","nodeHandle","current","takePhoto","options","e","takeSnapshot","getBitRateMultiplier","bitRate","startRecording","onRecordingError","onRecordingFinished","videoBitRate","passThruOptions","flash","setState","nativeOptions","videoBitRateOverride","videoBitRateMultiplier","onRecordCallback","video","error","pauseRecording","resumeRecording","stopRecording","cancelRecording","focus","point","lockFocusAndExposureToPoint","freeFocusAndExposure","getAvailableCameraDevices","addCameraDevicesChangedListener","listener","getCameraPermissionStatus","getMicrophonePermissionStatus","getLocationPermissionStatus","requestCameraPermission","requestMicrophonePermission","requestLocationPermission","event","nativeEvent","cause","cameraError","code","message","console","outputOrientation","maybeUpdateUIRotation","previewOrientation","value","uiRotation","onUIRotationChanged","codeScanner","codes","frame","setFrameProcessor","unsetFrameProcessor","removeFrameProcessor","averageFps","length","shift","componentDidUpdate","render","device","enableFpsGraph","fps","shouldEnableBufferCompression","torch","isRenderingWithSkia","shouldBeMirrored","position","minFps","maxFps","createElement","_extends","cameraId","id","isMirrored","codeScannerOptions","enableFrameProcessor","enableBufferCompression","preview","style","styles","customPreviewView","offscreenTextures","resizeMode","fpsGraph","targetMaxFps","format","create","flex","elevation","left","top"],"sourceRoot":"../../src","sources":["Camera.tsx"],"mappings":"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"} diff --git a/package/lib/module/CameraDevices.js b/package/lib/module/CameraDevices.js new file mode 100644 index 0000000000..18c8361c15 --- /dev/null +++ b/package/lib/module/CameraDevices.js @@ -0,0 +1,18 @@ +import { NativeModules, NativeEventEmitter } from 'react-native'; +const CameraDevicesManager = NativeModules.CameraDevices; +const constants = CameraDevicesManager.getConstants(); +let devices = constants.availableCameraDevices; +const DEVICES_CHANGED_NAME = 'CameraDevicesChanged'; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const eventEmitter = new NativeEventEmitter(CameraDevicesManager); +eventEmitter.addListener(DEVICES_CHANGED_NAME, newDevices => { + devices = newDevices; +}); +export const CameraDevices = { + userPreferredCameraDevice: constants.userPreferredCameraDevice, + getAvailableCameraDevices: () => devices, + addCameraDevicesChangedListener: callback => { + return eventEmitter.addListener(DEVICES_CHANGED_NAME, callback); + } +}; +//# sourceMappingURL=CameraDevices.js.map \ No newline at end of file diff --git a/package/lib/module/CameraDevices.js.map b/package/lib/module/CameraDevices.js.map new file mode 100644 index 0000000000..6e8d793e3e --- /dev/null +++ b/package/lib/module/CameraDevices.js.map @@ -0,0 +1 @@ +{"version":3,"names":["NativeModules","NativeEventEmitter","CameraDevicesManager","CameraDevices","constants","getConstants","devices","availableCameraDevices","DEVICES_CHANGED_NAME","eventEmitter","addListener","newDevices","userPreferredCameraDevice","getAvailableCameraDevices","addCameraDevicesChangedListener","callback"],"sourceRoot":"../../src","sources":["CameraDevices.ts"],"mappings":"AAAA,SAASA,aAAa,EAAEC,kBAAkB,QAAQ,cAAc;AAGhE,MAAMC,oBAAoB,GAAGF,aAAa,CAACG,aAK1C;AAED,MAAMC,SAAS,GAAGF,oBAAoB,CAACG,YAAY,CAAC,CAAC;AACrD,IAAIC,OAAO,GAAGF,SAAS,CAACG,sBAAsB;AAE9C,MAAMC,oBAAoB,GAAG,sBAAsB;AACnD;AACA,MAAMC,YAAY,GAAG,IAAIR,kBAAkB,CAACC,oBAA2B,CAAC;AACxEO,YAAY,CAACC,WAAW,CAACF,oBAAoB,EAAGG,UAA0B,IAAK;EAC7EL,OAAO,GAAGK,UAAU;AACtB,CAAC,CAAC;AAEF,OAAO,MAAMR,aAAa,GAAG;EAC3BS,yBAAyB,EAAER,SAAS,CAACQ,yBAAyB;EAC9DC,yBAAyB,EAAEA,CAAA,KAAMP,OAAO;EACxCQ,+BAA+B,EAAGC,QAA8C,IAAK;IACnF,OAAON,YAAY,CAACC,WAAW,CAACF,oBAAoB,EAAEO,QAAQ,CAAC;EACjE;AACF,CAAC"} diff --git a/package/lib/module/CameraError.js b/package/lib/module/CameraError.js new file mode 100644 index 0000000000..8d776c4dba --- /dev/null +++ b/package/lib/module/CameraError.js @@ -0,0 +1,92 @@ +/** + * Represents a JSON-style error cause. This contains native `NSError`/`Throwable` information, and can have recursive {@linkcode ErrorWithCause.cause | .cause} properties until the ultimate cause has been found. + */ + +/** + * Represents any kind of error that occured in the {@linkcode Camera} View Module. + */ +class CameraError extends Error { + get code() { + return this._code; + } + get message() { + return this._message; + } + get cause() { + const c = this._cause; + if (c == null) return undefined; + return new Error(`[${c.code}]: ${c.message}`); + } + + /** + * @internal + */ + constructor(code, message, cause) { + super(`[${code}]: ${message}${cause != null ? ` (Cause: ${cause.message})` : ''}`); + super.name = code; + super.message = message; + this._code = code; + this._message = message; + this._cause = cause; + } + toString() { + let string = `[${this.code}]: ${this.message}`; + if (this._cause != null) string += ` (caused by ${JSON.stringify(this._cause)})`; + return string; + } +} + +/** + * Represents any kind of error that occured while trying to capture a video or photo. + * + * See the ["Camera Errors" documentation](https://react-native-vision-camera.com/docs/guides/errors) for more information about Camera Errors. + */ +export class CameraCaptureError extends CameraError {} + +/** + * Represents any kind of error that occured in the Camera View Module. + * + * See the ["Camera Errors" documentation](https://react-native-vision-camera.com/docs/guides/errors) for more information about Camera Errors. + */ +export class CameraRuntimeError extends CameraError {} + +/** + * Checks if the given `error` is of type {@linkcode ErrorWithCause} + * @param {unknown} error Any unknown object to validate + * @returns `true` if the given `error` is of type {@linkcode ErrorWithCause} + */ +export const isErrorWithCause = error => typeof error === 'object' && error != null && +// @ts-expect-error error is still unknown +typeof error.message === 'string' && ( +// @ts-expect-error error is still unknown +typeof error.stacktrace === 'string' || error.stacktrace == null) && ( +// @ts-expect-error error is still unknown +isErrorWithCause(error.cause) || error.cause == null); +const isCameraErrorJson = error => typeof error === 'object' && error != null && +// @ts-expect-error error is still unknown +typeof error.code === 'string' && +// @ts-expect-error error is still unknown +typeof error.message === 'string' && ( +// @ts-expect-error error is still unknown +typeof error.cause === 'object' || error.cause == null); + +/** + * Tries to parse an error coming from native to a typed JS camera error. + * @param {CameraError} nativeError The native error instance. This is a JSON in the legacy native module architecture. + * @returns A {@linkcode CameraRuntimeError} or {@linkcode CameraCaptureError}, or the `nativeError` itself if it's not parsable + * @method + */ +export const tryParseNativeCameraError = nativeError => { + if (isCameraErrorJson(nativeError)) { + if (nativeError.code.startsWith('capture')) { + return new CameraCaptureError(nativeError.code, nativeError.message, nativeError.cause); + } else { + return new CameraRuntimeError( + // @ts-expect-error the code is string, we narrow it down to TS union. + nativeError.code, nativeError.message, nativeError.cause); + } + } else { + return nativeError; + } +}; +//# sourceMappingURL=CameraError.js.map \ No newline at end of file diff --git a/package/lib/module/CameraError.js.map b/package/lib/module/CameraError.js.map new file mode 100644 index 0000000000..adc18d2d74 --- /dev/null +++ b/package/lib/module/CameraError.js.map @@ -0,0 +1 @@ +{"version":3,"names":["CameraError","Error","code","_code","message","_message","cause","c","_cause","undefined","constructor","name","toString","string","JSON","stringify","CameraCaptureError","CameraRuntimeError","isErrorWithCause","error","stacktrace","isCameraErrorJson","tryParseNativeCameraError","nativeError","startsWith"],"sourceRoot":"../../src","sources":["CameraError.ts"],"mappings":"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"} diff --git a/package/lib/module/FpsGraph.js b/package/lib/module/FpsGraph.js new file mode 100644 index 0000000000..22eb8b3379 --- /dev/null +++ b/package/lib/module/FpsGraph.js @@ -0,0 +1,68 @@ +function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } +import React, { useMemo } from 'react'; +import { StyleSheet, Text } from 'react-native'; +import { View } from 'react-native'; +export const MAX_BARS = 30; +const WIDTH = 100; +const HEIGHT = 65; +const BAR_WIDTH = WIDTH / MAX_BARS; +export function FpsGraph({ + averageFpsSamples, + targetMaxFps, + style, + ...props +}) { + const maxFps = useMemo(() => { + const currentMaxFps = averageFpsSamples.reduce((prev, curr) => Math.max(prev, curr), 0); + return Math.max(currentMaxFps, targetMaxFps); + }, [averageFpsSamples, targetMaxFps]); + const latestFps = averageFpsSamples[averageFpsSamples.length - 1]; + return /*#__PURE__*/React.createElement(View, _extends({}, props, { + style: [styles.container, style] + }), averageFpsSamples.map((fps, index) => { + let height = fps / maxFps * HEIGHT; + if (Number.isNaN(height) || height < 0) { + // clamp to 0 if needed + height = 0; + } + return /*#__PURE__*/React.createElement(View, { + key: index, + style: [styles.bar, { + height: height + }] + }); + }), latestFps != null && !Number.isNaN(latestFps) && /*#__PURE__*/React.createElement(View, { + style: styles.centerContainer + }, /*#__PURE__*/React.createElement(Text, { + style: styles.text + }, Math.round(latestFps), " FPS"))); +} +const styles = StyleSheet.create({ + container: { + width: WIDTH, + height: HEIGHT, + backgroundColor: 'rgba(0, 0, 0, 0.3)', + flexDirection: 'row', + justifyContent: 'flex-end', + alignItems: 'flex-end', + borderRadius: 5, + overflow: 'hidden' + }, + bar: { + width: BAR_WIDTH, + height: 5, + backgroundColor: 'rgb(243, 74, 77)' + }, + centerContainer: { + ...StyleSheet.absoluteFillObject, + justifyContent: 'center', + alignItems: 'center' + }, + text: { + position: 'absolute', + fontWeight: 'bold', + fontSize: 14, + color: 'rgb(255, 255, 255)' + } +}); +//# sourceMappingURL=FpsGraph.js.map \ No newline at end of file diff --git a/package/lib/module/FpsGraph.js.map b/package/lib/module/FpsGraph.js.map new file mode 100644 index 0000000000..8c2f969d3d --- /dev/null +++ b/package/lib/module/FpsGraph.js.map @@ -0,0 +1 @@ +{"version":3,"names":["React","useMemo","StyleSheet","Text","View","MAX_BARS","WIDTH","HEIGHT","BAR_WIDTH","FpsGraph","averageFpsSamples","targetMaxFps","style","props","maxFps","currentMaxFps","reduce","prev","curr","Math","max","latestFps","length","createElement","_extends","styles","container","map","fps","index","height","Number","isNaN","key","bar","centerContainer","text","round","create","width","backgroundColor","flexDirection","justifyContent","alignItems","borderRadius","overflow","absoluteFillObject","position","fontWeight","fontSize","color"],"sourceRoot":"../../src","sources":["FpsGraph.tsx"],"mappings":";AAAA,OAAOA,KAAK,IAAIC,OAAO,QAAQ,OAAO;AAEtC,SAASC,UAAU,EAAEC,IAAI,QAAQ,cAAc;AAC/C,SAASC,IAAI,QAAQ,cAAc;AAanC,OAAO,MAAMC,QAAQ,GAAG,EAAE;AAE1B,MAAMC,KAAK,GAAG,GAAG;AACjB,MAAMC,MAAM,GAAG,EAAE;AACjB,MAAMC,SAAS,GAAGF,KAAK,GAAGD,QAAQ;AAElC,OAAO,SAASI,QAAQA,CAAC;EAAEC,iBAAiB;EAAEC,YAAY;EAAEC,KAAK;EAAE,GAAGC;AAAa,CAAC,EAAsB;EACxG,MAAMC,MAAM,GAAGb,OAAO,CAAC,MAAM;IAC3B,MAAMc,aAAa,GAAGL,iBAAiB,CAACM,MAAM,CAAC,CAACC,IAAI,EAAEC,IAAI,KAAKC,IAAI,CAACC,GAAG,CAACH,IAAI,EAAEC,IAAI,CAAC,EAAE,CAAC,CAAC;IACvF,OAAOC,IAAI,CAACC,GAAG,CAACL,aAAa,EAAEJ,YAAY,CAAC;EAC9C,CAAC,EAAE,CAACD,iBAAiB,EAAEC,YAAY,CAAC,CAAC;EACrC,MAAMU,SAAS,GAAGX,iBAAiB,CAACA,iBAAiB,CAACY,MAAM,GAAG,CAAC,CAAC;EAEjE,oBACEtB,KAAA,CAAAuB,aAAA,CAACnB,IAAI,EAAAoB,QAAA,KAAKX,KAAK;IAAED,KAAK,EAAE,CAACa,MAAM,CAACC,SAAS,EAAEd,KAAK;EAAE,IAC/CF,iBAAiB,CAACiB,GAAG,CAAC,CAACC,GAAG,EAAEC,KAAK,KAAK;IACrC,IAAIC,MAAM,GAAIF,GAAG,GAAGd,MAAM,GAAIP,MAAM;IACpC,IAAIwB,MAAM,CAACC,KAAK,CAACF,MAAM,CAAC,IAAIA,MAAM,GAAG,CAAC,EAAE;MACtC;MACAA,MAAM,GAAG,CAAC;IACZ;IACA,oBAAO9B,KAAA,CAAAuB,aAAA,CAACnB,IAAI;MAAC6B,GAAG,EAAEJ,KAAM;MAACjB,KAAK,EAAE,CAACa,MAAM,CAACS,GAAG,EAAE;QAAEJ,MAAM,EAAEA;MAAO,CAAC;IAAE,CAAE,CAAC;EACtE,CAAC,CAAC,EACDT,SAAS,IAAI,IAAI,IAAI,CAACU,MAAM,CAACC,KAAK,CAACX,SAAS,CAAC,iBAC5CrB,KAAA,CAAAuB,aAAA,CAACnB,IAAI;IAACQ,KAAK,EAAEa,MAAM,CAACU;EAAgB,gBAClCnC,KAAA,CAAAuB,aAAA,CAACpB,IAAI;IAACS,KAAK,EAAEa,MAAM,CAACW;EAAK,GAAEjB,IAAI,CAACkB,KAAK,CAAChB,SAAS,CAAC,EAAC,MAAU,CACvD,CAEJ,CAAC;AAEX;AAEA,MAAMI,MAAM,GAAGvB,UAAU,CAACoC,MAAM,CAAC;EAC/BZ,SAAS,EAAE;IACTa,KAAK,EAAEjC,KAAK;IACZwB,MAAM,EAAEvB,MAAM;IACdiC,eAAe,EAAE,oBAAoB;IACrCC,aAAa,EAAE,KAAK;IACpBC,cAAc,EAAE,UAAU;IAC1BC,UAAU,EAAE,UAAU;IACtBC,YAAY,EAAE,CAAC;IACfC,QAAQ,EAAE;EACZ,CAAC;EACDX,GAAG,EAAE;IACHK,KAAK,EAAE/B,SAAS;IAChBsB,MAAM,EAAE,CAAC;IACTU,eAAe,EAAE;EACnB,CAAC;EACDL,eAAe,EAAE;IACf,GAAGjC,UAAU,CAAC4C,kBAAkB;IAChCJ,cAAc,EAAE,QAAQ;IACxBC,UAAU,EAAE;EACd,CAAC;EACDP,IAAI,EAAE;IACJW,QAAQ,EAAE,UAAU;IACpBC,UAAU,EAAE,MAAM;IAClBC,QAAQ,EAAE,EAAE;IACZC,KAAK,EAAE;EACT;AACF,CAAC,CAAC"} diff --git a/package/lib/module/JSIHelper.js b/package/lib/module/JSIHelper.js new file mode 100644 index 0000000000..17a1026bb5 --- /dev/null +++ b/package/lib/module/JSIHelper.js @@ -0,0 +1,9 @@ +import { CameraRuntimeError } from './CameraError'; +export function assertJSIAvailable() { + // Check if we are running on-device (JSI) + // @ts-expect-error JSI functions aren't typed + if (global.nativeCallSyncHook == null) { + throw new CameraRuntimeError('system/frame-processors-unavailable', 'Failed to initialize VisionCamera Frame Processors: React Native is not running on-device. Frame Processors can only be used when synchronous method invocations (JSI) are possible. If you are using a remote debugger (e.g. Chrome), switch to an on-device debugger (e.g. Flipper) instead.'); + } +} +//# sourceMappingURL=JSIHelper.js.map \ No newline at end of file diff --git a/package/lib/module/JSIHelper.js.map b/package/lib/module/JSIHelper.js.map new file mode 100644 index 0000000000..8129831a27 --- /dev/null +++ b/package/lib/module/JSIHelper.js.map @@ -0,0 +1 @@ +{"version":3,"names":["CameraRuntimeError","assertJSIAvailable","global","nativeCallSyncHook"],"sourceRoot":"../../src","sources":["JSIHelper.ts"],"mappings":"AAAA,SAASA,kBAAkB,QAAQ,eAAe;AAElD,OAAO,SAASC,kBAAkBA,CAAA,EAAS;EACzC;EACA;EACA,IAAIC,MAAM,CAACC,kBAAkB,IAAI,IAAI,EAAE;IACrC,MAAM,IAAIH,kBAAkB,CAC1B,qCAAqC,EACrC,gSACF,CAAC;EACH;AACF"} diff --git a/package/lib/module/NativeCameraModule.js b/package/lib/module/NativeCameraModule.js new file mode 100644 index 0000000000..9efd839df1 --- /dev/null +++ b/package/lib/module/NativeCameraModule.js @@ -0,0 +1,33 @@ +import { NativeModules, Platform } from 'react-native'; +import { CameraRuntimeError } from './CameraError'; +const supportedPlatforms = ['ios', 'android', 'macos']; + +// NativeModules automatically resolves 'CameraView' to 'CameraViewModule' +// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment +export const CameraModule = NativeModules.CameraView; +if (CameraModule == null) { + if (!supportedPlatforms.includes(Platform.OS)) { + throw new CameraRuntimeError('system/camera-module-not-found', `Failed to initialize VisionCamera: VisionCamera currently does not work on ${Platform.OS}.`); + } + let message = 'Failed to initialize VisionCamera: The native Camera Module (`NativeModules.CameraView`) could not be found.'; + message += '\n* Make sure react-native-vision-camera is correctly autolinked (run `npx react-native config` to verify)'; + if (Platform.OS === 'ios' || Platform.OS === 'macos') message += '\n* Make sure you ran `pod install` in the ios/ directory.'; + if (Platform.OS === 'android') message += '\n* Make sure gradle is synced.'; + + // check if Expo + // @ts-expect-error expo global JSI modules are not typed + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const ExpoConstants = global.expo?.modules?.ExponentConstants; + if (ExpoConstants != null) { + if (ExpoConstants.appOwnership === 'expo') { + // We're running Expo Go + throw new CameraRuntimeError('system/camera-module-not-found', `react-native-vision-camera is not supported in Expo Go! Use EAS/expo prebuild instead (\`expo run:${Platform.OS}\`). For more info, see https://docs.expo.dev/workflow/prebuild/.`); + } else { + // We're running Expo bare / standalone + message += '\n* Make sure you ran `expo prebuild`.'; + } + } + message += '\n* Make sure you rebuilt the app.'; + throw new CameraRuntimeError('system/camera-module-not-found', message); +} +//# sourceMappingURL=NativeCameraModule.js.map \ No newline at end of file diff --git a/package/lib/module/NativeCameraModule.js.map b/package/lib/module/NativeCameraModule.js.map new file mode 100644 index 0000000000..aaf8a0bc11 --- /dev/null +++ b/package/lib/module/NativeCameraModule.js.map @@ -0,0 +1 @@ +{"version":3,"names":["NativeModules","Platform","CameraRuntimeError","supportedPlatforms","CameraModule","CameraView","includes","OS","message","ExpoConstants","global","expo","modules","ExponentConstants","appOwnership"],"sourceRoot":"../../src","sources":["NativeCameraModule.ts"],"mappings":"AAAA,SAASA,aAAa,EAAEC,QAAQ,QAAQ,cAAc;AACtD,SAASC,kBAAkB,QAAQ,eAAe;AAElD,MAAMC,kBAAkB,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,CAAC;;AAEtD;AACA;AACA,OAAO,MAAMC,YAAY,GAAGJ,aAAa,CAACK,UAAU;AACpD,IAAID,YAAY,IAAI,IAAI,EAAE;EACxB,IAAI,CAACD,kBAAkB,CAACG,QAAQ,CAACL,QAAQ,CAACM,EAAE,CAAC,EAAE;IAC7C,MAAM,IAAIL,kBAAkB,CAC1B,gCAAgC,EAC/B,8EAA6ED,QAAQ,CAACM,EAAG,GAC5F,CAAC;EACH;EAEA,IAAIC,OAAO,GAAG,8GAA8G;EAC5HA,OAAO,IAAI,4GAA4G;EACvH,IAAIP,QAAQ,CAACM,EAAE,KAAK,KAAK,IAAIN,QAAQ,CAACM,EAAE,KAAK,OAAO,EAAEC,OAAO,IAAI,4DAA4D;EAE7H,IAAIP,QAAQ,CAACM,EAAE,KAAK,SAAS,EAAEC,OAAO,IAAI,iCAAiC;;EAE3E;EACA;EACA;EACA,MAAMC,aAAa,GAAGC,MAAM,CAACC,IAAI,EAAEC,OAAO,EAAEC,iBAAiB;EAC7D,IAAIJ,aAAa,IAAI,IAAI,EAAE;IACzB,IAAIA,aAAa,CAACK,YAAY,KAAK,MAAM,EAAE;MACzC;MACA,MAAM,IAAIZ,kBAAkB,CAC1B,gCAAgC,EAC/B,qGAAoGD,QAAQ,CAACM,EAAG,mEACnH,CAAC;IACH,CAAC,MAAM;MACL;MACAC,OAAO,IAAI,wCAAwC;IACrD;EACF;EAEAA,OAAO,IAAI,oCAAoC;EAC/C,MAAM,IAAIN,kBAAkB,CAAC,gCAAgC,EAAEM,OAAO,CAAC;AACzE"} diff --git a/package/lib/module/NativeCameraView.js b/package/lib/module/NativeCameraView.js new file mode 100644 index 0000000000..2957dac69d --- /dev/null +++ b/package/lib/module/NativeCameraView.js @@ -0,0 +1,4 @@ +import { requireNativeComponent } from 'react-native'; +// requireNativeComponent automatically resolves 'CameraView' to 'CameraViewManager' +export const NativeCameraView = requireNativeComponent('CameraView'); +//# sourceMappingURL=NativeCameraView.js.map \ No newline at end of file diff --git a/package/lib/module/NativeCameraView.js.map b/package/lib/module/NativeCameraView.js.map new file mode 100644 index 0000000000..d543e4d55c --- /dev/null +++ b/package/lib/module/NativeCameraView.js.map @@ -0,0 +1 @@ +{"version":3,"names":["requireNativeComponent","NativeCameraView"],"sourceRoot":"../../src","sources":["NativeCameraView.ts"],"mappings":"AACA,SAASA,sBAAsB,QAAQ,cAAc;AA0DrD;AACA,OAAO,MAAMC,gBAAgB,GAAGD,sBAAsB,CAAwB,YAAY,CAAC"} diff --git a/package/lib/module/RotationHelper.js b/package/lib/module/RotationHelper.js new file mode 100644 index 0000000000..4639cf3d0e --- /dev/null +++ b/package/lib/module/RotationHelper.js @@ -0,0 +1,43 @@ +function orientationToDegrees(orientation) { + switch (orientation) { + case 'portrait': + return 0; + case 'landscape-right': + return 90; + case 'portrait-upside-down': + return 180; + case 'landscape-left': + return 270; + } +} +export class RotationHelper { + /** + * Gets or sets the current preview orientation. + */ + previewOrientation = 'portrait'; + /** + * Gets or sets the current output orientation. + */ + outputOrientation = 'portrait'; + + /** + * Gets the current target rotation (in degrees) that needs to be applied + * to all UI elements so they appear up-right. + */ + get uiRotation() { + const previewDegrees = orientationToDegrees(this.previewOrientation); + const outputDegrees = orientationToDegrees(this.outputOrientation); + const diffDegrees = (outputDegrees - previewDegrees) % 360; + if (diffDegrees < -180) { + // Changes e.g. -270 to +90, so it is a shorter rotation on UI + return diffDegrees + 360; + } else if (diffDegrees > 180) { + // Changes e.g. +270 to -90, so it is a shorter rotation on UI + return diffDegrees - 360; + } else { + // It is a short rotation already, return it + return diffDegrees; + } + } +} +//# sourceMappingURL=RotationHelper.js.map \ No newline at end of file diff --git a/package/lib/module/RotationHelper.js.map b/package/lib/module/RotationHelper.js.map new file mode 100644 index 0000000000..81342fd591 --- /dev/null +++ b/package/lib/module/RotationHelper.js.map @@ -0,0 +1 @@ +{"version":3,"names":["orientationToDegrees","orientation","RotationHelper","previewOrientation","outputOrientation","uiRotation","previewDegrees","outputDegrees","diffDegrees"],"sourceRoot":"../../src","sources":["RotationHelper.ts"],"mappings":"AAEA,SAASA,oBAAoBA,CAACC,WAAwB,EAAU;EAC9D,QAAQA,WAAW;IACjB,KAAK,UAAU;MACb,OAAO,CAAC;IACV,KAAK,iBAAiB;MACpB,OAAO,EAAE;IACX,KAAK,sBAAsB;MACzB,OAAO,GAAG;IACZ,KAAK,gBAAgB;MACnB,OAAO,GAAG;EACd;AACF;AAEA,OAAO,MAAMC,cAAc,CAAC;EAC1B;AACF;AACA;EACEC,kBAAkB,GAAgB,UAAU;EAC5C;AACF;AACA;EACEC,iBAAiB,GAAgB,UAAU;;EAE3C;AACF;AACA;AACA;EACE,IAAIC,UAAUA,CAAA,EAAW;IACvB,MAAMC,cAAc,GAAGN,oBAAoB,CAAC,IAAI,CAACG,kBAAkB,CAAC;IACpE,MAAMI,aAAa,GAAGP,oBAAoB,CAAC,IAAI,CAACI,iBAAiB,CAAC;IAClE,MAAMI,WAAW,GAAG,CAACD,aAAa,GAAGD,cAAc,IAAI,GAAG;IAE1D,IAAIE,WAAW,GAAG,CAAC,GAAG,EAAE;MACtB;MACA,OAAOA,WAAW,GAAG,GAAG;IAC1B,CAAC,MAAM,IAAIA,WAAW,GAAG,GAAG,EAAE;MAC5B;MACA,OAAOA,WAAW,GAAG,GAAG;IAC1B,CAAC,MAAM;MACL;MACA,OAAOA,WAAW;IACpB;EACF;AACF"} diff --git a/package/lib/module/dependencies/ModuleProxy.js b/package/lib/module/dependencies/ModuleProxy.js new file mode 100644 index 0000000000..3325421a1b --- /dev/null +++ b/package/lib/module/dependencies/ModuleProxy.js @@ -0,0 +1,35 @@ +/** + * Create a lazily-imported module proxy. + * This is useful for lazily requiring optional dependencies. + */ +export const createModuleProxy = getModule => { + const holder = { + module: undefined + }; + const proxy = new Proxy(holder, { + get: (target, property) => { + if (property === '$$typeof') { + // If inlineRequires is enabled, Metro will look up all imports + // with the $$typeof operator. In this case, this will throw the + // `OptionalDependencyNotInstalledError` error because we try to access the module + // even though we are not using it (Metro does it), so instead we return undefined + // to bail out of inlineRequires here. + // See https://github.com/mrousavy/react-native-vision-camera/pull/2953 + return undefined; + } + if (target.module == null) { + // lazy initialize module via require() + // caller needs to make sure the require() call is wrapped in a try/catch + target.module = getModule(); + } + return target.module[property]; + } + }); + return proxy; +}; +export class OptionalDependencyNotInstalledError extends Error { + constructor(name) { + super(`${name} is not installed!`); + } +} +//# sourceMappingURL=ModuleProxy.js.map \ No newline at end of file diff --git a/package/lib/module/dependencies/ModuleProxy.js.map b/package/lib/module/dependencies/ModuleProxy.js.map new file mode 100644 index 0000000000..81c33f7bf8 --- /dev/null +++ b/package/lib/module/dependencies/ModuleProxy.js.map @@ -0,0 +1 @@ +{"version":3,"names":["createModuleProxy","getModule","holder","module","undefined","proxy","Proxy","get","target","property","OptionalDependencyNotInstalledError","Error","constructor","name"],"sourceRoot":"../../../src","sources":["dependencies/ModuleProxy.ts"],"mappings":"AAEA;AACA;AACA;AACA;AACA,OAAO,MAAMA,iBAAiB,GAAaC,SAA2B,IAAc;EAClF,MAAMC,MAAuC,GAAG;IAAEC,MAAM,EAAEC;EAAU,CAAC;EAErE,MAAMC,KAAK,GAAG,IAAIC,KAAK,CAACJ,MAAM,EAAE;IAC9BK,GAAG,EAAEA,CAACC,MAAM,EAAEC,QAAQ,KAAK;MACzB,IAAIA,QAAQ,KAAK,UAAU,EAAE;QAC3B;QACA;QACA;QACA;QACA;QACA;QACA,OAAOL,SAAS;MAClB;MAEA,IAAII,MAAM,CAACL,MAAM,IAAI,IAAI,EAAE;QACzB;QACA;QACAK,MAAM,CAACL,MAAM,GAAGF,SAAS,CAAC,CAAY;MACxC;MACA,OAAOO,MAAM,CAACL,MAAM,CAACM,QAAQ,CAA+B;IAC9D;EACF,CAAC,CAAC;EACF,OAAOJ,KAAK;AACd,CAAC;AAED,OAAO,MAAMK,mCAAmC,SAASC,KAAK,CAAC;EAC7DC,WAAWA,CAACC,IAAY,EAAE;IACxB,KAAK,CAAE,GAAEA,IAAK,oBAAmB,CAAC;EACpC;AACF"} diff --git a/package/lib/module/dependencies/ReanimatedProxy.js b/package/lib/module/dependencies/ReanimatedProxy.js new file mode 100644 index 0000000000..1beb4f1092 --- /dev/null +++ b/package/lib/module/dependencies/ReanimatedProxy.js @@ -0,0 +1,16 @@ +import { createModuleProxy, OptionalDependencyNotInstalledError } from './ModuleProxy'; +/** + * A proxy object that lazy-imports react-native-reanimated as soon as the + * caller tries to access a property on {@linkcode ReanimatedProxy}. + * + * If react-native-reanimated is not installed, accessing anything on + * {@linkcode ReanimatedProxy} will throw. + */ +export const ReanimatedProxy = createModuleProxy(() => { + try { + return require('react-native-reanimated'); + } catch (e) { + throw new OptionalDependencyNotInstalledError('react-native-reanimated'); + } +}); +//# sourceMappingURL=ReanimatedProxy.js.map \ No newline at end of file diff --git a/package/lib/module/dependencies/ReanimatedProxy.js.map b/package/lib/module/dependencies/ReanimatedProxy.js.map new file mode 100644 index 0000000000..a659b27563 --- /dev/null +++ b/package/lib/module/dependencies/ReanimatedProxy.js.map @@ -0,0 +1 @@ +{"version":3,"names":["createModuleProxy","OptionalDependencyNotInstalledError","ReanimatedProxy","require","e"],"sourceRoot":"../../../src","sources":["dependencies/ReanimatedProxy.ts"],"mappings":"AACA,SAASA,iBAAiB,EAAEC,mCAAmC,QAAQ,eAAe;AAItF;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,eAAe,GAAGF,iBAAiB,CAAc,MAAM;EAClE,IAAI;IACF,OAAOG,OAAO,CAAC,yBAAyB,CAAC;EAC3C,CAAC,CAAC,OAAOC,CAAC,EAAE;IACV,MAAM,IAAIH,mCAAmC,CAAC,yBAAyB,CAAC;EAC1E;AACF,CAAC,CAAC"} diff --git a/package/lib/module/dependencies/SkiaProxy.js b/package/lib/module/dependencies/SkiaProxy.js new file mode 100644 index 0000000000..6e439eb558 --- /dev/null +++ b/package/lib/module/dependencies/SkiaProxy.js @@ -0,0 +1,16 @@ +import { createModuleProxy, OptionalDependencyNotInstalledError } from './ModuleProxy'; +/** + * A proxy object that lazy-imports @shopify/react-native-skia as soon as the + * caller tries to access a property on {@linkcode SkiaProxy}. + * + * If @shopify/react-native-skia is not installed, accessing anything on + * {@linkcode SkiaProxy} will throw. + */ +export const SkiaProxy = createModuleProxy(() => { + try { + return require('@shopify/react-native-skia'); + } catch (e) { + throw new OptionalDependencyNotInstalledError('@shopify/react-native-skia'); + } +}); +//# sourceMappingURL=SkiaProxy.js.map \ No newline at end of file diff --git a/package/lib/module/dependencies/SkiaProxy.js.map b/package/lib/module/dependencies/SkiaProxy.js.map new file mode 100644 index 0000000000..8d32847d2a --- /dev/null +++ b/package/lib/module/dependencies/SkiaProxy.js.map @@ -0,0 +1 @@ +{"version":3,"names":["createModuleProxy","OptionalDependencyNotInstalledError","SkiaProxy","require","e"],"sourceRoot":"../../../src","sources":["dependencies/SkiaProxy.ts"],"mappings":"AACA,SAASA,iBAAiB,EAAEC,mCAAmC,QAAQ,eAAe;AAItF;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,SAAS,GAAGF,iBAAiB,CAAQ,MAAM;EACtD,IAAI;IACF,OAAOG,OAAO,CAAC,4BAA4B,CAAC;EAC9C,CAAC,CAAC,OAAOC,CAAC,EAAE;IACV,MAAM,IAAIH,mCAAmC,CAAC,4BAA4B,CAAC;EAC7E;AACF,CAAC,CAAC"} diff --git a/package/lib/module/dependencies/WorkletsProxy.js b/package/lib/module/dependencies/WorkletsProxy.js new file mode 100644 index 0000000000..acc2c91d51 --- /dev/null +++ b/package/lib/module/dependencies/WorkletsProxy.js @@ -0,0 +1,16 @@ +import { createModuleProxy, OptionalDependencyNotInstalledError } from './ModuleProxy'; +/** + * A proxy object that lazy-imports react-native-worklets-core as soon as the + * caller tries to access a property on {@linkcode WorkletsProxy}. + * + * If react-native-worklets-core is not installed, accessing anything on + * {@linkcode WorkletsProxy} will throw. + */ +export const WorkletsProxy = createModuleProxy(() => { + try { + return require('react-native-worklets-core'); + } catch (e) { + throw new OptionalDependencyNotInstalledError('react-native-worklets-core'); + } +}); +//# sourceMappingURL=WorkletsProxy.js.map \ No newline at end of file diff --git a/package/lib/module/dependencies/WorkletsProxy.js.map b/package/lib/module/dependencies/WorkletsProxy.js.map new file mode 100644 index 0000000000..7ae36d5cf5 --- /dev/null +++ b/package/lib/module/dependencies/WorkletsProxy.js.map @@ -0,0 +1 @@ +{"version":3,"names":["createModuleProxy","OptionalDependencyNotInstalledError","WorkletsProxy","require","e"],"sourceRoot":"../../../src","sources":["dependencies/WorkletsProxy.ts"],"mappings":"AACA,SAASA,iBAAiB,EAAEC,mCAAmC,QAAQ,eAAe;AAItF;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,aAAa,GAAGF,iBAAiB,CAAY,MAAM;EAC9D,IAAI;IACF,OAAOG,OAAO,CAAC,4BAA4B,CAAC;EAC9C,CAAC,CAAC,OAAOC,CAAC,EAAE;IACV,MAAM,IAAIH,mCAAmC,CAAC,4BAA4B,CAAC;EAC7E;AACF,CAAC,CAAC"} diff --git a/package/lib/module/devices/Templates.js b/package/lib/module/devices/Templates.js new file mode 100644 index 0000000000..51479b4759 --- /dev/null +++ b/package/lib/module/devices/Templates.js @@ -0,0 +1,100 @@ +import { Dimensions } from 'react-native'; +const SnapchatResolution = { + width: 1920, + height: 1080 +}; +const InstagramResolution = { + width: 3840, + height: 2160 +}; +const ScreenAspectRatio = Dimensions.get('window').height / Dimensions.get('window').width; + +/** + * Predefined templates for use in `useCameraFormat`/`getCameraFormat`. + * @example + * ```ts + * const format = useCameraFormat(device, Templates.Snapchat) + * ``` + */ +export const Templates = { + /** + * Highest resolution video recordings (e.g. 4k) + */ + Video: [{ + videoResolution: 'max' + }], + /** + * High resolution 60 FPS video recordings (e.g. 1080@60 FPS) + */ + Video60Fps: [{ + fps: 60 + }, { + videoResolution: 'max' + }], + /** + * High-FPS video recordings (e.g. 720@240 FPS) + */ + VideoSlowMotion: [{ + fps: 240 + }, { + videoResolution: 'max' + }], + /** + * High resolution video recordings with cinematic video stabilization + */ + VideoStabilized: [{ + videoResolution: 'max' + }, { + videoStabilizationMode: 'cinematic-extended' + }], + /** + * Highest resolution photo capture (e.g. 4k) + */ + Photo: [{ + photoResolution: 'max' + }], + /** + * Highest resolution photo capture with portrait screen aspect ratio (e.g. 4k) + */ + PhotoPortrait: [{ + photoResolution: 'max' + }, { + photoAspectRatio: ScreenAspectRatio + }], + /** + * HD-quality for faster Frame Processing (e.g. 720p) + */ + FrameProcessing: [{ + videoResolution: { + width: 1080, + height: 720 + } + }], + /** + * Snapchat-style video recordings and photo capture + * Targets Full HD-quality for lower file sizes and portrait screen aspect ratio. + */ + Snapchat: [{ + videoAspectRatio: ScreenAspectRatio + }, { + videoResolution: SnapchatResolution + }, { + photoAspectRatio: ScreenAspectRatio + }, { + photoResolution: SnapchatResolution + }], + /** + * Instagram-style video recordings and photo capture. + * Targets 4k-quality and portrait screen aspect ratio. + */ + Instagram: [{ + videoAspectRatio: ScreenAspectRatio + }, { + videoResolution: InstagramResolution + }, { + photoAspectRatio: ScreenAspectRatio + }, { + photoResolution: InstagramResolution + }] +}; +//# sourceMappingURL=Templates.js.map \ No newline at end of file diff --git a/package/lib/module/devices/Templates.js.map b/package/lib/module/devices/Templates.js.map new file mode 100644 index 0000000000..466a53dc42 --- /dev/null +++ b/package/lib/module/devices/Templates.js.map @@ -0,0 +1 @@ +{"version":3,"names":["Dimensions","SnapchatResolution","width","height","InstagramResolution","ScreenAspectRatio","get","Templates","Video","videoResolution","Video60Fps","fps","VideoSlowMotion","VideoStabilized","videoStabilizationMode","Photo","photoResolution","PhotoPortrait","photoAspectRatio","FrameProcessing","Snapchat","videoAspectRatio","Instagram"],"sourceRoot":"../../../src","sources":["devices/Templates.ts"],"mappings":"AAAA,SAASA,UAAU,QAAQ,cAAc;AAczC,MAAMC,kBAAkB,GAAG;EAAEC,KAAK,EAAE,IAAI;EAAEC,MAAM,EAAE;AAAK,CAAC;AACxD,MAAMC,mBAAmB,GAAG;EAAEF,KAAK,EAAE,IAAI;EAAEC,MAAM,EAAE;AAAK,CAAC;AACzD,MAAME,iBAAiB,GAAGL,UAAU,CAACM,GAAG,CAAC,QAAQ,CAAC,CAACH,MAAM,GAAGH,UAAU,CAACM,GAAG,CAAC,QAAQ,CAAC,CAACJ,KAAK;;AAE1F;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMK,SAAsD,GAAG;EACpE;AACF;AACA;EACEC,KAAK,EAAE,CAAC;IAAEC,eAAe,EAAE;EAAM,CAAC,CAAC;EACnC;AACF;AACA;EACEC,UAAU,EAAE,CAAC;IAAEC,GAAG,EAAE;EAAG,CAAC,EAAE;IAAEF,eAAe,EAAE;EAAM,CAAC,CAAC;EACrD;AACF;AACA;EACEG,eAAe,EAAE,CAAC;IAAED,GAAG,EAAE;EAAI,CAAC,EAAE;IAAEF,eAAe,EAAE;EAAM,CAAC,CAAC;EAC3D;AACF;AACA;EACEI,eAAe,EAAE,CAAC;IAAEJ,eAAe,EAAE;EAAM,CAAC,EAAE;IAAEK,sBAAsB,EAAE;EAAqB,CAAC,CAAC;EAC/F;AACF;AACA;EACEC,KAAK,EAAE,CAAC;IAAEC,eAAe,EAAE;EAAM,CAAC,CAAC;EACnC;AACF;AACA;EACEC,aAAa,EAAE,CAAC;IAAED,eAAe,EAAE;EAAM,CAAC,EAAE;IAAEE,gBAAgB,EAAEb;EAAkB,CAAC,CAAC;EACpF;AACF;AACA;EACEc,eAAe,EAAE,CAAC;IAAEV,eAAe,EAAE;MAAEP,KAAK,EAAE,IAAI;MAAEC,MAAM,EAAE;IAAI;EAAE,CAAC,CAAC;EACpE;AACF;AACA;AACA;EACEiB,QAAQ,EAAE,CACR;IAAEC,gBAAgB,EAAEhB;EAAkB,CAAC,EACvC;IAAEI,eAAe,EAAER;EAAmB,CAAC,EACvC;IAAEiB,gBAAgB,EAAEb;EAAkB,CAAC,EACvC;IAAEW,eAAe,EAAEf;EAAmB,CAAC,CACxC;EACD;AACF;AACA;AACA;EACEqB,SAAS,EAAE,CACT;IAAED,gBAAgB,EAAEhB;EAAkB,CAAC,EACvC;IAAEI,eAAe,EAAEL;EAAoB,CAAC,EACxC;IAAEc,gBAAgB,EAAEb;EAAkB,CAAC,EACvC;IAAEW,eAAe,EAAEZ;EAAoB,CAAC;AAE5C,CAAC"} diff --git a/package/lib/module/devices/getCameraDevice.js b/package/lib/module/devices/getCameraDevice.js new file mode 100644 index 0000000000..e6b635ad47 --- /dev/null +++ b/package/lib/module/devices/getCameraDevice.js @@ -0,0 +1,49 @@ +/** + * Get the best matching Camera device that best satisfies your requirements using a sorting filter, or `undefined` if {@linkcode devices} does not contain any devices. + * @param position The position of the Camera device relative to the phone. + * @param filter The filter you want to use. The Camera device that matches your filter the closest will be returned + * @returns The Camera device that matches your filter the closest, or `undefined` if no such Camera Device exists on the given {@linkcode position}. + * @example + * ```ts + * const devices = Camera.getAvailableCameraDevices() + * const device = getCameraDevice(devices, 'back', { + * physicalDevices: ['wide-angle-camera'] + * }) + * ``` + */ +export function getCameraDevice(devices, position, filter = {}) { + const filtered = devices.filter(d => d.position === position); + let bestDevice = filtered[0]; + if (bestDevice == null) return undefined; + + // Compare each device using a point scoring system + for (const device of filtered) { + let leftPoints = 0; + let rightPoints = 0; + + // prefer higher hardware-level + if (bestDevice.hardwareLevel === 'full') leftPoints += 4; + if (device.hardwareLevel === 'full') rightPoints += 4; + if (filter.physicalDevices != null) { + // user did pass a physical device filter, two possible scenarios: + // 1. user wants all cameras ([ultra-wide, wide, tele]) to zoom. prefer those devices that have all 3 cameras. + // 2. user wants only one ([wide]) for faster performance. prefer those devices that only have one camera, if they have more, we rank them lower. + for (const d of bestDevice.physicalDevices) { + if (filter.physicalDevices.includes(d)) leftPoints += 1;else leftPoints -= 1; + } + for (const d of device.physicalDevices) { + if (filter.physicalDevices.includes(d)) rightPoints += 1;else rightPoints -= 1; + } + } else { + // user did not pass a physical device filter. prefer wide-angle-camera as a default + if (bestDevice.physicalDevices.includes('wide-angle-camera')) leftPoints += 2; + if (device.physicalDevices.includes('wide-angle-camera')) rightPoints += 2; + // if we have more than one device, we rank it lower. we only want a simple camera + if (bestDevice.physicalDevices.length > device.physicalDevices.length) leftPoints -= 1; + if (device.physicalDevices.length > bestDevice.physicalDevices.length) rightPoints -= 1; + } + if (rightPoints > leftPoints) bestDevice = device; + } + return bestDevice; +} +//# sourceMappingURL=getCameraDevice.js.map \ No newline at end of file diff --git a/package/lib/module/devices/getCameraDevice.js.map b/package/lib/module/devices/getCameraDevice.js.map new file mode 100644 index 0000000000..33ffb080ce --- /dev/null +++ b/package/lib/module/devices/getCameraDevice.js.map @@ -0,0 +1 @@ +{"version":3,"names":["getCameraDevice","devices","position","filter","filtered","d","bestDevice","undefined","device","leftPoints","rightPoints","hardwareLevel","physicalDevices","includes","length"],"sourceRoot":"../../../src","sources":["devices/getCameraDevice.ts"],"mappings":"AAwBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASA,eAAeA,CAACC,OAAuB,EAAEC,QAAwB,EAAEC,MAAoB,GAAG,CAAC,CAAC,EAA4B;EACtI,MAAMC,QAAQ,GAAGH,OAAO,CAACE,MAAM,CAAEE,CAAC,IAAKA,CAAC,CAACH,QAAQ,KAAKA,QAAQ,CAAC;EAE/D,IAAII,UAAU,GAAGF,QAAQ,CAAC,CAAC,CAAC;EAC5B,IAAIE,UAAU,IAAI,IAAI,EAAE,OAAOC,SAAS;;EAExC;EACA,KAAK,MAAMC,MAAM,IAAIJ,QAAQ,EAAE;IAC7B,IAAIK,UAAU,GAAG,CAAC;IAClB,IAAIC,WAAW,GAAG,CAAC;;IAEnB;IACA,IAAIJ,UAAU,CAACK,aAAa,KAAK,MAAM,EAAEF,UAAU,IAAI,CAAC;IACxD,IAAID,MAAM,CAACG,aAAa,KAAK,MAAM,EAAED,WAAW,IAAI,CAAC;IAErD,IAAIP,MAAM,CAACS,eAAe,IAAI,IAAI,EAAE;MAClC;MACA;MACA;MACA,KAAK,MAAMP,CAAC,IAAIC,UAAU,CAACM,eAAe,EAAE;QAC1C,IAAIT,MAAM,CAACS,eAAe,CAACC,QAAQ,CAACR,CAAC,CAAC,EAAEI,UAAU,IAAI,CAAC,MAClDA,UAAU,IAAI,CAAC;MACtB;MACA,KAAK,MAAMJ,CAAC,IAAIG,MAAM,CAACI,eAAe,EAAE;QACtC,IAAIT,MAAM,CAACS,eAAe,CAACC,QAAQ,CAACR,CAAC,CAAC,EAAEK,WAAW,IAAI,CAAC,MACnDA,WAAW,IAAI,CAAC;MACvB;IACF,CAAC,MAAM;MACL;MACA,IAAIJ,UAAU,CAACM,eAAe,CAACC,QAAQ,CAAC,mBAAmB,CAAC,EAAEJ,UAAU,IAAI,CAAC;MAC7E,IAAID,MAAM,CAACI,eAAe,CAACC,QAAQ,CAAC,mBAAmB,CAAC,EAAEH,WAAW,IAAI,CAAC;MAC1E;MACA,IAAIJ,UAAU,CAACM,eAAe,CAACE,MAAM,GAAGN,MAAM,CAACI,eAAe,CAACE,MAAM,EAAEL,UAAU,IAAI,CAAC;MACtF,IAAID,MAAM,CAACI,eAAe,CAACE,MAAM,GAAGR,UAAU,CAACM,eAAe,CAACE,MAAM,EAAEJ,WAAW,IAAI,CAAC;IACzF;IAEA,IAAIA,WAAW,GAAGD,UAAU,EAAEH,UAAU,GAAGE,MAAM;EACnD;EAEA,OAAOF,UAAU;AACnB"} diff --git a/package/lib/module/devices/getCameraFormat.js b/package/lib/module/devices/getCameraFormat.js new file mode 100644 index 0000000000..d037898c9b --- /dev/null +++ b/package/lib/module/devices/getCameraFormat.js @@ -0,0 +1,154 @@ +import { CameraRuntimeError } from '../CameraError'; +function filtersToFilterMap(filters) { + return filters.reduce((map, curr, index) => { + for (const key in curr) { + // @ts-expect-error keys are untyped + map[key] = { + // @ts-expect-error keys are untyped + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + target: curr[key], + priority: filters.length - index + }; + } + return map; + }, {}); +} + +/** + * Get the best matching Camera format for the given device that satisfies your requirements using a sorting filter. By default, formats are sorted by highest to lowest resolution. + * + * The {@linkcode filters | filters} are ranked by priority, from highest to lowest. + * This means the first item you pass will have a higher priority than the second, and so on. + * + * @param device The Camera Device you're currently using + * @param filters The filters you want to use. The format that matches your filter the closest will be returned + * @returns The format that matches your filter the closest. + * + * @example + * ```ts + * const format = getCameraFormat(device, [ + * { videoResolution: { width: 3048, height: 2160 } }, + * { fps: 60 } + * ]) + * ``` + */ +export function getCameraFormat(device, filters) { + // Combine filters into a single filter map for constant-time lookup + const filter = filtersToFilterMap(filters); + let bestFormat = device.formats[0]; + if (bestFormat == null) throw new CameraRuntimeError('device/invalid-device', `The given Camera Device (${device.id}) does not have any formats!`); + + // Compare each format using a point scoring system + for (const format of device.formats) { + let leftPoints = 0; + let rightPoints = 0; + + // Video Resolution + if (filter.videoResolution != null) { + const leftVideoResolution = bestFormat.videoWidth * bestFormat.videoHeight; + const rightVideoResolution = format.videoWidth * format.videoHeight; + if (filter.videoResolution.target === 'max') { + // We just want the maximum resolution + if (leftVideoResolution > rightVideoResolution) leftPoints += filter.videoResolution.priority; + if (rightVideoResolution > leftVideoResolution) rightPoints += filter.videoResolution.priority; + } else { + // Find video resolution closest to the filter (ignoring orientation) + const targetResolution = filter.videoResolution.target.width * filter.videoResolution.target.height; + const leftDiff = Math.abs(leftVideoResolution - targetResolution); + const rightDiff = Math.abs(rightVideoResolution - targetResolution); + if (leftDiff < rightDiff) leftPoints += filter.videoResolution.priority; + if (rightDiff < leftDiff) rightPoints += filter.videoResolution.priority; + } + } + + // Photo Resolution + if (filter.photoResolution != null) { + const leftPhotoResolution = bestFormat.photoWidth * bestFormat.photoHeight; + const rightPhotoResolution = format.photoWidth * format.photoHeight; + if (filter.photoResolution.target === 'max') { + // We just want the maximum resolution + if (leftPhotoResolution > rightPhotoResolution) leftPoints += filter.photoResolution.priority; + if (rightPhotoResolution > leftPhotoResolution) rightPoints += filter.photoResolution.priority; + } else { + // Find closest photo resolution to the filter (ignoring orientation) + const targetResolution = filter.photoResolution.target.width * filter.photoResolution.target.height; + const leftDiff = Math.abs(leftPhotoResolution - targetResolution); + const rightDiff = Math.abs(rightPhotoResolution - targetResolution); + if (leftDiff < rightDiff) leftPoints += filter.photoResolution.priority; + if (rightDiff < leftDiff) rightPoints += filter.photoResolution.priority; + } + } + + // Find closest aspect ratio (video) + if (filter.videoAspectRatio != null) { + const leftAspect = bestFormat.videoWidth / bestFormat.videoHeight; + const rightAspect = format.videoWidth / format.videoHeight; + const leftDiff = Math.abs(leftAspect - filter.videoAspectRatio.target); + const rightDiff = Math.abs(rightAspect - filter.videoAspectRatio.target); + if (leftDiff < rightDiff) leftPoints += filter.videoAspectRatio.priority; + if (rightDiff < leftDiff) rightPoints += filter.videoAspectRatio.priority; + } + + // Find closest aspect ratio (photo) + if (filter.photoAspectRatio != null) { + const leftAspect = bestFormat.photoWidth / bestFormat.photoHeight; + const rightAspect = format.photoWidth / format.photoHeight; + const leftDiff = Math.abs(leftAspect - filter.photoAspectRatio.target); + const rightDiff = Math.abs(rightAspect - filter.photoAspectRatio.target); + if (leftDiff < rightDiff) leftPoints += filter.photoAspectRatio.priority; + if (rightDiff < leftDiff) rightPoints += filter.photoAspectRatio.priority; + } + + // Find closest max FPS + if (filter.fps != null) { + if (filter.fps.target === 'max') { + if (bestFormat.maxFps > format.maxFps) leftPoints += filter.fps.priority; + if (format.maxFps > bestFormat.maxFps) rightPoints += filter.fps.priority; + } else { + if (bestFormat.maxFps >= filter.fps.target) leftPoints += filter.fps.priority; + if (format.maxFps >= filter.fps.target) rightPoints += filter.fps.priority; + } + } + + // Find closest ISO + if (filter.iso != null) { + if (filter.iso.target === 'max') { + if (bestFormat.maxISO > format.maxISO) leftPoints += filter.iso.priority; + if (format.maxISO > bestFormat.maxISO) rightPoints += filter.iso.priority; + } else if (filter.iso.target === 'min') { + if (bestFormat.minISO < format.minISO) leftPoints += filter.iso.priority; + if (format.minISO < bestFormat.minISO) rightPoints += filter.iso.priority; + } else { + if (filter.iso.target >= bestFormat.minISO && filter.iso.target <= bestFormat.maxISO) leftPoints += filter.iso.priority; + if (filter.iso.target >= format.minISO && filter.iso.target <= format.maxISO) rightPoints += filter.iso.priority; + } + } + + // Find video stabilization mode + if (filter.videoStabilizationMode != null) { + if (bestFormat.videoStabilizationModes.includes(filter.videoStabilizationMode.target)) leftPoints += filter.videoStabilizationMode.priority; + if (format.videoStabilizationModes.includes(filter.videoStabilizationMode.target)) rightPoints += filter.videoStabilizationMode.priority; + } + + // Find Photo HDR formats + if (filter.photoHdr != null) { + if (bestFormat.supportsPhotoHdr === filter.photoHdr.target) leftPoints += filter.photoHdr.priority; + if (format.supportsPhotoHdr === filter.photoHdr.target) rightPoints += filter.photoHdr.priority; + } + + // Find Video HDR formats + if (filter.videoHdr != null) { + if (bestFormat.supportsVideoHdr === filter.videoHdr.target) leftPoints += filter.videoHdr.priority; + if (format.supportsVideoHdr === filter.videoHdr.target) rightPoints += filter.videoHdr.priority; + } + + // Find matching AF system + if (filter.autoFocusSystem != null) { + if (bestFormat.autoFocusSystem === filter.autoFocusSystem.target) leftPoints += filter.autoFocusSystem.priority; + if (format.autoFocusSystem === filter.autoFocusSystem.target) rightPoints += filter.autoFocusSystem.priority; + } + if (rightPoints > leftPoints) bestFormat = format; + } + return bestFormat; +} +//# sourceMappingURL=getCameraFormat.js.map \ No newline at end of file diff --git a/package/lib/module/devices/getCameraFormat.js.map b/package/lib/module/devices/getCameraFormat.js.map new file mode 100644 index 0000000000..df316ca91f --- /dev/null +++ b/package/lib/module/devices/getCameraFormat.js.map @@ -0,0 +1 @@ +{"version":3,"names":["CameraRuntimeError","filtersToFilterMap","filters","reduce","map","curr","index","key","target","priority","length","getCameraFormat","device","filter","bestFormat","formats","id","format","leftPoints","rightPoints","videoResolution","leftVideoResolution","videoWidth","videoHeight","rightVideoResolution","targetResolution","width","height","leftDiff","Math","abs","rightDiff","photoResolution","leftPhotoResolution","photoWidth","photoHeight","rightPhotoResolution","videoAspectRatio","leftAspect","rightAspect","photoAspectRatio","fps","maxFps","iso","maxISO","minISO","videoStabilizationMode","videoStabilizationModes","includes","photoHdr","supportsPhotoHdr","videoHdr","supportsVideoHdr","autoFocusSystem"],"sourceRoot":"../../../src","sources":["devices/getCameraFormat.ts"],"mappings":"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"} diff --git a/package/lib/module/expo-plugin/@types.js b/package/lib/module/expo-plugin/@types.js new file mode 100644 index 0000000000..d980e31f5c --- /dev/null +++ b/package/lib/module/expo-plugin/@types.js @@ -0,0 +1,2 @@ + +//# sourceMappingURL=@types.js.map \ No newline at end of file diff --git a/package/lib/module/expo-plugin/@types.js.map b/package/lib/module/expo-plugin/@types.js.map new file mode 100644 index 0000000000..02dff7e44e --- /dev/null +++ b/package/lib/module/expo-plugin/@types.js.map @@ -0,0 +1 @@ +{"version":3,"names":[],"sourceRoot":"../../../src","sources":["expo-plugin/@types.ts"],"mappings":""} diff --git a/package/lib/module/expo-plugin/withAndroidMLKitVisionModel.js b/package/lib/module/expo-plugin/withAndroidMLKitVisionModel.js new file mode 100644 index 0000000000..8566b37412 --- /dev/null +++ b/package/lib/module/expo-plugin/withAndroidMLKitVisionModel.js @@ -0,0 +1,21 @@ +import { withGradleProperties } from '@expo/config-plugins'; +/** + * Set the `VisionCamera_enableCodeScanner` value in the static `gradle.properties` file. + * This is used to add the full MLKit dependency to the project. + */ +export const withAndroidMLKitVisionModel = c => { + const key = 'VisionCamera_enableCodeScanner'; + return withGradleProperties(c, config => { + config.modResults = config.modResults.filter(item => { + if (item.type === 'property' && item.key === key) return false; + return true; + }); + config.modResults.push({ + type: 'property', + key: key, + value: 'true' + }); + return config; + }); +}; +//# sourceMappingURL=withAndroidMLKitVisionModel.js.map \ No newline at end of file diff --git a/package/lib/module/expo-plugin/withAndroidMLKitVisionModel.js.map b/package/lib/module/expo-plugin/withAndroidMLKitVisionModel.js.map new file mode 100644 index 0000000000..b456bdb3f5 --- /dev/null +++ b/package/lib/module/expo-plugin/withAndroidMLKitVisionModel.js.map @@ -0,0 +1 @@ +{"version":3,"names":["withGradleProperties","withAndroidMLKitVisionModel","c","key","config","modResults","filter","item","type","push","value"],"sourceRoot":"../../../src","sources":["expo-plugin/withAndroidMLKitVisionModel.ts"],"mappings":"AACA,SAASA,oBAAoB,QAAQ,sBAAsB;AAG3D;AACA;AACA;AACA;AACA,OAAO,MAAMC,2BAAsD,GAAIC,CAAC,IAAK;EAC3E,MAAMC,GAAG,GAAG,gCAAgC;EAC5C,OAAOH,oBAAoB,CAACE,CAAC,EAAGE,MAAM,IAAK;IACzCA,MAAM,CAACC,UAAU,GAAGD,MAAM,CAACC,UAAU,CAACC,MAAM,CAAEC,IAAI,IAAK;MACrD,IAAIA,IAAI,CAACC,IAAI,KAAK,UAAU,IAAID,IAAI,CAACJ,GAAG,KAAKA,GAAG,EAAE,OAAO,KAAK;MAC9D,OAAO,IAAI;IACb,CAAC,CAAC;IAEFC,MAAM,CAACC,UAAU,CAACI,IAAI,CAAC;MACrBD,IAAI,EAAE,UAAU;MAChBL,GAAG,EAAEA,GAAG;MACRO,KAAK,EAAE;IACT,CAAC,CAAC;IAEF,OAAON,MAAM;EACf,CAAC,CAAC;AACJ,CAAC"} diff --git a/package/lib/module/expo-plugin/withEnableFrameProcessorsAndroid.js b/package/lib/module/expo-plugin/withEnableFrameProcessorsAndroid.js new file mode 100644 index 0000000000..3ad8d94f85 --- /dev/null +++ b/package/lib/module/expo-plugin/withEnableFrameProcessorsAndroid.js @@ -0,0 +1,22 @@ +import { withGradleProperties } from '@expo/config-plugins'; + +/** + * Set the `VisionCamera_enableFrameProcessors` value in the static `gradle.properties` file. + * This is used to disable frame processors if you don't need it for android. + */ +export const withEnableFrameProcessorsAndroid = (c, enableFrameProcessors) => { + const enableFrameProcessorsKey = 'VisionCamera_enableFrameProcessors'; + return withGradleProperties(c, config => { + config.modResults = config.modResults.filter(item => { + if (item.type === 'property' && item.key === enableFrameProcessorsKey) return false; + return true; + }); + config.modResults.push({ + type: 'property', + key: enableFrameProcessorsKey, + value: String(enableFrameProcessors) + }); + return config; + }); +}; +//# sourceMappingURL=withEnableFrameProcessorsAndroid.js.map \ No newline at end of file diff --git a/package/lib/module/expo-plugin/withEnableFrameProcessorsAndroid.js.map b/package/lib/module/expo-plugin/withEnableFrameProcessorsAndroid.js.map new file mode 100644 index 0000000000..1fb242ef1e --- /dev/null +++ b/package/lib/module/expo-plugin/withEnableFrameProcessorsAndroid.js.map @@ -0,0 +1 @@ +{"version":3,"names":["withGradleProperties","withEnableFrameProcessorsAndroid","c","enableFrameProcessors","enableFrameProcessorsKey","config","modResults","filter","item","type","key","push","value","String"],"sourceRoot":"../../../src","sources":["expo-plugin/withEnableFrameProcessorsAndroid.ts"],"mappings":"AACA,SAASA,oBAAoB,QAAQ,sBAAsB;;AAE3D;AACA;AACA;AACA;AACA,OAAO,MAAMC,gCAAuD,GAAGA,CAACC,CAAC,EAAEC,qBAAqB,KAAK;EACnG,MAAMC,wBAAwB,GAAG,oCAAoC;EACrE,OAAOJ,oBAAoB,CAACE,CAAC,EAAGG,MAAM,IAAK;IACzCA,MAAM,CAACC,UAAU,GAAGD,MAAM,CAACC,UAAU,CAACC,MAAM,CAAEC,IAAI,IAAK;MACrD,IAAIA,IAAI,CAACC,IAAI,KAAK,UAAU,IAAID,IAAI,CAACE,GAAG,KAAKN,wBAAwB,EAAE,OAAO,KAAK;MACnF,OAAO,IAAI;IACb,CAAC,CAAC;IAEFC,MAAM,CAACC,UAAU,CAACK,IAAI,CAAC;MACrBF,IAAI,EAAE,UAAU;MAChBC,GAAG,EAAEN,wBAAwB;MAC7BQ,KAAK,EAAEC,MAAM,CAACV,qBAAqB;IACrC,CAAC,CAAC;IAEF,OAAOE,MAAM;EACf,CAAC,CAAC;AACJ,CAAC"} diff --git a/package/lib/module/expo-plugin/withEnableFrameProcessorsIOS.js b/package/lib/module/expo-plugin/withEnableFrameProcessorsIOS.js new file mode 100644 index 0000000000..9d7e336b0e --- /dev/null +++ b/package/lib/module/expo-plugin/withEnableFrameProcessorsIOS.js @@ -0,0 +1,14 @@ +import { withDangerousMod } from '@expo/config-plugins'; +import { writeToPodfile } from './writeToPodfile'; + +/** + * Set the `enableFrameProcessors` flag inside of the XcodeProject. + * This is used to disable frame processors if you don't need it on iOS. (will save CPU and Memory) + */ +export const withEnableFrameProcessorsIOS = (c, enableFrameProcessors) => { + return withDangerousMod(c, ['ios', config => { + writeToPodfile(config.modRequest.projectRoot, '$VCEnableFrameProcessors', String(enableFrameProcessors)); + return config; + }]); +}; +//# sourceMappingURL=withEnableFrameProcessorsIOS.js.map \ No newline at end of file diff --git a/package/lib/module/expo-plugin/withEnableFrameProcessorsIOS.js.map b/package/lib/module/expo-plugin/withEnableFrameProcessorsIOS.js.map new file mode 100644 index 0000000000..9c5ab87ac2 --- /dev/null +++ b/package/lib/module/expo-plugin/withEnableFrameProcessorsIOS.js.map @@ -0,0 +1 @@ +{"version":3,"names":["withDangerousMod","writeToPodfile","withEnableFrameProcessorsIOS","c","enableFrameProcessors","config","modRequest","projectRoot","String"],"sourceRoot":"../../../src","sources":["expo-plugin/withEnableFrameProcessorsIOS.ts"],"mappings":"AACA,SAASA,gBAAgB,QAAQ,sBAAsB;AACvD,SAASC,cAAc,QAAQ,kBAAkB;;AAEjD;AACA;AACA;AACA;AACA,OAAO,MAAMC,4BAAmD,GAAGA,CAACC,CAAC,EAAEC,qBAAqB,KAAK;EAC/F,OAAOJ,gBAAgB,CAACG,CAAC,EAAE,CACzB,KAAK,EACJE,MAAM,IAAK;IACVJ,cAAc,CAACI,MAAM,CAACC,UAAU,CAACC,WAAW,EAAE,0BAA0B,EAAEC,MAAM,CAACJ,qBAAqB,CAAC,CAAC;IACxG,OAAOC,MAAM;EACf,CAAC,CACF,CAAC;AACJ,CAAC"} diff --git a/package/lib/module/expo-plugin/withEnableLocationIOS.js b/package/lib/module/expo-plugin/withEnableLocationIOS.js new file mode 100644 index 0000000000..5a4eaf7140 --- /dev/null +++ b/package/lib/module/expo-plugin/withEnableLocationIOS.js @@ -0,0 +1,16 @@ +import { withDangerousMod } from '@expo/config-plugins'; +import { writeToPodfile } from './writeToPodfile'; + +/** + * Set the `enableLocation` flag inside of the XcodeProject. + * This is used to enable location APIs. + * If location is disabled, the CLLocation APIs are not used in the codebase. + * This is useful if you don't use Location and apple review is unhappy about CLLocation usage. + */ +export const withEnableLocationIOS = (c, enableLocation) => { + return withDangerousMod(c, ['ios', config => { + writeToPodfile(config.modRequest.projectRoot, '$VCEnableLocation', String(enableLocation)); + return config; + }]); +}; +//# sourceMappingURL=withEnableLocationIOS.js.map \ No newline at end of file diff --git a/package/lib/module/expo-plugin/withEnableLocationIOS.js.map b/package/lib/module/expo-plugin/withEnableLocationIOS.js.map new file mode 100644 index 0000000000..de73f31c0c --- /dev/null +++ b/package/lib/module/expo-plugin/withEnableLocationIOS.js.map @@ -0,0 +1 @@ +{"version":3,"names":["withDangerousMod","writeToPodfile","withEnableLocationIOS","c","enableLocation","config","modRequest","projectRoot","String"],"sourceRoot":"../../../src","sources":["expo-plugin/withEnableLocationIOS.ts"],"mappings":"AACA,SAASA,gBAAgB,QAAQ,sBAAsB;AACvD,SAASC,cAAc,QAAQ,kBAAkB;;AAEjD;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,qBAA4C,GAAGA,CAACC,CAAC,EAAEC,cAAc,KAAK;EACjF,OAAOJ,gBAAgB,CAACG,CAAC,EAAE,CACzB,KAAK,EACJE,MAAM,IAAK;IACVJ,cAAc,CAACI,MAAM,CAACC,UAAU,CAACC,WAAW,EAAE,mBAAmB,EAAEC,MAAM,CAACJ,cAAc,CAAC,CAAC;IAC1F,OAAOC,MAAM;EACf,CAAC,CACF,CAAC;AACJ,CAAC"} diff --git a/package/lib/module/expo-plugin/withVisionCamera.js b/package/lib/module/expo-plugin/withVisionCamera.js new file mode 100644 index 0000000000..405acd1020 --- /dev/null +++ b/package/lib/module/expo-plugin/withVisionCamera.js @@ -0,0 +1,40 @@ +import { withPlugins, AndroidConfig, createRunOncePlugin } from '@expo/config-plugins'; +import { withEnableFrameProcessorsAndroid } from './withEnableFrameProcessorsAndroid'; +import { withEnableFrameProcessorsIOS } from './withEnableFrameProcessorsIOS'; +import { withAndroidMLKitVisionModel } from './withAndroidMLKitVisionModel'; +import { withEnableLocationIOS } from './withEnableLocationIOS'; +// eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-assignment +const pkg = require('../../../package.json'); +const CAMERA_USAGE = 'Allow $(PRODUCT_NAME) to access your camera'; +const MICROPHONE_USAGE = 'Allow $(PRODUCT_NAME) to access your microphone'; +const LOCATION_USAGE = 'Allow $(PRODUCT_NAME) to access your location'; +const withCamera = (config, props = {}) => { + if (config.ios == null) config.ios = {}; + if (config.ios.infoPlist == null) config.ios.infoPlist = {}; + // Camera permission + config.ios.infoPlist.NSCameraUsageDescription = props.cameraPermissionText ?? config.ios.infoPlist.NSCameraUsageDescription ?? CAMERA_USAGE; + if (props.enableMicrophonePermission) { + // Microphone permission + config.ios.infoPlist.NSMicrophoneUsageDescription = props.microphonePermissionText ?? config.ios.infoPlist.NSMicrophoneUsageDescription ?? MICROPHONE_USAGE; + } + if (props.enableLocation) { + // Location permission + config.ios.infoPlist.NSLocationWhenInUseUsageDescription = props.locationPermissionText ?? config.ios.infoPlist.NSLocationWhenInUseUsageDescription ?? LOCATION_USAGE; + } + const androidPermissions = ['android.permission.CAMERA']; + if (props.enableMicrophonePermission) androidPermissions.push('android.permission.RECORD_AUDIO'); + if (props.enableLocation) androidPermissions.push('android.permission.ACCESS_FINE_LOCATION'); + if (props.enableLocation != null) { + // set Podfile property to build location-related stuff + config = withEnableLocationIOS(config, props.enableLocation); + } + if (props.enableFrameProcessors != null) { + // set Podfile property to build frame-processor-related stuff + config = withEnableFrameProcessorsAndroid(config, props.enableFrameProcessors); + config = withEnableFrameProcessorsIOS(config, props.enableFrameProcessors); + } + if (props.enableCodeScanner) config = withAndroidMLKitVisionModel(config, props); + return withPlugins(config, [[AndroidConfig.Permissions.withPermissions, androidPermissions]]); +}; +export default createRunOncePlugin(withCamera, pkg.name, pkg.version); +//# sourceMappingURL=withVisionCamera.js.map \ No newline at end of file diff --git a/package/lib/module/expo-plugin/withVisionCamera.js.map b/package/lib/module/expo-plugin/withVisionCamera.js.map new file mode 100644 index 0000000000..f1da173e93 --- /dev/null +++ b/package/lib/module/expo-plugin/withVisionCamera.js.map @@ -0,0 +1 @@ +{"version":3,"names":["withPlugins","AndroidConfig","createRunOncePlugin","withEnableFrameProcessorsAndroid","withEnableFrameProcessorsIOS","withAndroidMLKitVisionModel","withEnableLocationIOS","pkg","require","CAMERA_USAGE","MICROPHONE_USAGE","LOCATION_USAGE","withCamera","config","props","ios","infoPlist","NSCameraUsageDescription","cameraPermissionText","enableMicrophonePermission","NSMicrophoneUsageDescription","microphonePermissionText","enableLocation","NSLocationWhenInUseUsageDescription","locationPermissionText","androidPermissions","push","enableFrameProcessors","enableCodeScanner","Permissions","withPermissions","name","version"],"sourceRoot":"../../../src","sources":["expo-plugin/withVisionCamera.ts"],"mappings":"AACA,SAASA,WAAW,EAAEC,aAAa,EAAEC,mBAAmB,QAAQ,sBAAsB;AACtF,SAASC,gCAAgC,QAAQ,oCAAoC;AACrF,SAASC,4BAA4B,QAAQ,gCAAgC;AAC7E,SAASC,2BAA2B,QAAQ,+BAA+B;AAE3E,SAASC,qBAAqB,QAAQ,yBAAyB;AAC/D;AACA,MAAMC,GAAG,GAAGC,OAAO,CAAC,uBAAuB,CAAC;AAE5C,MAAMC,YAAY,GAAG,6CAA6C;AAClE,MAAMC,gBAAgB,GAAG,iDAAiD;AAC1E,MAAMC,cAAc,GAAG,+CAA+C;AAEtE,MAAMC,UAAqC,GAAGA,CAACC,MAAM,EAAEC,KAAK,GAAG,CAAC,CAAC,KAAK;EACpE,IAAID,MAAM,CAACE,GAAG,IAAI,IAAI,EAAEF,MAAM,CAACE,GAAG,GAAG,CAAC,CAAC;EACvC,IAAIF,MAAM,CAACE,GAAG,CAACC,SAAS,IAAI,IAAI,EAAEH,MAAM,CAACE,GAAG,CAACC,SAAS,GAAG,CAAC,CAAC;EAC3D;EACAH,MAAM,CAACE,GAAG,CAACC,SAAS,CAACC,wBAAwB,GAC3CH,KAAK,CAACI,oBAAoB,IAAKL,MAAM,CAACE,GAAG,CAACC,SAAS,CAACC,wBAA+C,IAAIR,YAAY;EACrH,IAAIK,KAAK,CAACK,0BAA0B,EAAE;IACpC;IACAN,MAAM,CAACE,GAAG,CAACC,SAAS,CAACI,4BAA4B,GAC/CN,KAAK,CAACO,wBAAwB,IAAKR,MAAM,CAACE,GAAG,CAACC,SAAS,CAACI,4BAAmD,IAAIV,gBAAgB;EACnI;EACA,IAAII,KAAK,CAACQ,cAAc,EAAE;IACxB;IACAT,MAAM,CAACE,GAAG,CAACC,SAAS,CAACO,mCAAmC,GACtDT,KAAK,CAACU,sBAAsB,IAAKX,MAAM,CAACE,GAAG,CAACC,SAAS,CAACO,mCAA0D,IAAIZ,cAAc;EACtI;EACA,MAAMc,kBAAkB,GAAG,CAAC,2BAA2B,CAAC;EACxD,IAAIX,KAAK,CAACK,0BAA0B,EAAEM,kBAAkB,CAACC,IAAI,CAAC,iCAAiC,CAAC;EAChG,IAAIZ,KAAK,CAACQ,cAAc,EAAEG,kBAAkB,CAACC,IAAI,CAAC,yCAAyC,CAAC;EAE5F,IAAIZ,KAAK,CAACQ,cAAc,IAAI,IAAI,EAAE;IAChC;IACAT,MAAM,GAAGP,qBAAqB,CAACO,MAAM,EAAEC,KAAK,CAACQ,cAAc,CAAC;EAC9D;EACA,IAAIR,KAAK,CAACa,qBAAqB,IAAI,IAAI,EAAE;IACvC;IACAd,MAAM,GAAGV,gCAAgC,CAACU,MAAM,EAAEC,KAAK,CAACa,qBAAqB,CAAC;IAC9Ed,MAAM,GAAGT,4BAA4B,CAACS,MAAM,EAAEC,KAAK,CAACa,qBAAqB,CAAC;EAC5E;EAEA,IAAIb,KAAK,CAACc,iBAAiB,EAAEf,MAAM,GAAGR,2BAA2B,CAACQ,MAAM,EAAEC,KAAK,CAAC;EAEhF,OAAOd,WAAW,CAACa,MAAM,EAAE,CAAC,CAACZ,aAAa,CAAC4B,WAAW,CAACC,eAAe,EAAEL,kBAAkB,CAAC,CAAC,CAAC;AAC/F,CAAC;AAED,eAAevB,mBAAmB,CAACU,UAAU,EAAEL,GAAG,CAACwB,IAAI,EAAExB,GAAG,CAACyB,OAAO,CAAC"} diff --git a/package/lib/module/expo-plugin/writeToPodfile.js b/package/lib/module/expo-plugin/writeToPodfile.js new file mode 100644 index 0000000000..cf8380c82e --- /dev/null +++ b/package/lib/module/expo-plugin/writeToPodfile.js @@ -0,0 +1,16 @@ +import fs from 'fs'; +import path from 'path'; +export function writeToPodfile(projectRoot, key, value) { + const podfilePath = path.join(projectRoot, 'ios', 'Podfile'); + // get Podfile content as individual lines + let lines = fs.readFileSync(podfilePath, 'utf8').split('\n'); + // filter out any lines where the given key is already set + lines = lines.filter(l => !l.includes(key)); + // set the key as the first item in the array so its at the top of the file + lines.unshift(`${key}=${value}`); + + // write the file back + const fileContent = lines.join('\n'); + fs.writeFileSync(podfilePath, fileContent, 'utf8'); +} +//# sourceMappingURL=writeToPodfile.js.map \ No newline at end of file diff --git a/package/lib/module/expo-plugin/writeToPodfile.js.map b/package/lib/module/expo-plugin/writeToPodfile.js.map new file mode 100644 index 0000000000..6d788c1f21 --- /dev/null +++ b/package/lib/module/expo-plugin/writeToPodfile.js.map @@ -0,0 +1 @@ +{"version":3,"names":["fs","path","writeToPodfile","projectRoot","key","value","podfilePath","join","lines","readFileSync","split","filter","l","includes","unshift","fileContent","writeFileSync"],"sourceRoot":"../../../src","sources":["expo-plugin/writeToPodfile.ts"],"mappings":"AAAA,OAAOA,EAAE,MAAM,IAAI;AACnB,OAAOC,IAAI,MAAM,MAAM;AAEvB,OAAO,SAASC,cAAcA,CAACC,WAAmB,EAAEC,GAAW,EAAEC,KAAa,EAAQ;EACpF,MAAMC,WAAW,GAAGL,IAAI,CAACM,IAAI,CAACJ,WAAW,EAAE,KAAK,EAAE,SAAS,CAAC;EAC5D;EACA,IAAIK,KAAK,GAAGR,EAAE,CAACS,YAAY,CAACH,WAAW,EAAE,MAAM,CAAC,CAACI,KAAK,CAAC,IAAI,CAAC;EAC5D;EACAF,KAAK,GAAGA,KAAK,CAACG,MAAM,CAAEC,CAAC,IAAK,CAACA,CAAC,CAACC,QAAQ,CAACT,GAAG,CAAC,CAAC;EAC7C;EACAI,KAAK,CAACM,OAAO,CAAE,GAAEV,GAAI,IAAGC,KAAM,EAAC,CAAC;;EAEhC;EACA,MAAMU,WAAW,GAAGP,KAAK,CAACD,IAAI,CAAC,IAAI,CAAC;EACpCP,EAAE,CAACgB,aAAa,CAACV,WAAW,EAAES,WAAW,EAAE,MAAM,CAAC;AACpD"} diff --git a/package/lib/module/frame-processors/FrameProcessorsUnavailableError.js b/package/lib/module/frame-processors/FrameProcessorsUnavailableError.js new file mode 100644 index 0000000000..c2240a09de --- /dev/null +++ b/package/lib/module/frame-processors/FrameProcessorsUnavailableError.js @@ -0,0 +1,7 @@ +import { CameraRuntimeError } from '../CameraError'; +export class FrameProcessorsUnavailableError extends CameraRuntimeError { + constructor(reason) { + super('system/frame-processors-unavailable', 'Frame Processors are not available, react-native-worklets-core is not installed! ' + `Error: ${reason instanceof Error ? reason.message : reason}`); + } +} +//# sourceMappingURL=FrameProcessorsUnavailableError.js.map \ No newline at end of file diff --git a/package/lib/module/frame-processors/FrameProcessorsUnavailableError.js.map b/package/lib/module/frame-processors/FrameProcessorsUnavailableError.js.map new file mode 100644 index 0000000000..c197638b47 --- /dev/null +++ b/package/lib/module/frame-processors/FrameProcessorsUnavailableError.js.map @@ -0,0 +1 @@ +{"version":3,"names":["CameraRuntimeError","FrameProcessorsUnavailableError","constructor","reason","Error","message"],"sourceRoot":"../../../src","sources":["frame-processors/FrameProcessorsUnavailableError.ts"],"mappings":"AAAA,SAASA,kBAAkB,QAAQ,gBAAgB;AAEnD,OAAO,MAAMC,+BAA+B,SAASD,kBAAkB,CAAC;EACtEE,WAAWA,CAACC,MAAe,EAAE;IAC3B,KAAK,CACH,qCAAqC,EACrC,mFAAmF,GAChF,UAASA,MAAM,YAAYC,KAAK,GAAGD,MAAM,CAACE,OAAO,GAAGF,MAAO,EAChE,CAAC;EACH;AACF"} diff --git a/package/lib/module/frame-processors/VisionCameraProxy.js b/package/lib/module/frame-processors/VisionCameraProxy.js new file mode 100644 index 0000000000..a4bafc83e4 --- /dev/null +++ b/package/lib/module/frame-processors/VisionCameraProxy.js @@ -0,0 +1,45 @@ +import { CameraModule } from '../NativeCameraModule'; +import { FrameProcessorsUnavailableError } from './FrameProcessorsUnavailableError'; + +/** + * An initialized native instance of a FrameProcessorPlugin. + * All memory allocated by this plugin will be deleted once this value goes out of scope. + */ + +let proxy; +try { + // 1. Load react-native-worklets-core + require('react-native-worklets-core'); + // 2. If react-native-worklets-core could be loaded, try to install Frame Processor bindings + const result = CameraModule.installFrameProcessorBindings(); + if (result !== true) throw new Error(`Failed to install Frame Processor JSI bindings! installFrameProcessorBindings() returned ${result}`); + + // 3. Get global.VisionCameraProxy which was just installed by installFrameProcessorBindings() + // @ts-expect-error it's a global JSI variable injected by native + const globalProxy = global.VisionCameraProxy; + if (globalProxy == null) throw new Error('global.VisionCameraProxy is not installed! Was installFrameProcessorBindings() called?'); + proxy = globalProxy; +} catch (e) { + // global.VisionCameraProxy is not injected! + // Just use dummy implementations that will throw when the user tries to use Frame Processors. + proxy = { + initFrameProcessorPlugin: () => { + throw new FrameProcessorsUnavailableError(e); + }, + removeFrameProcessor: () => { + throw new FrameProcessorsUnavailableError(e); + }, + setFrameProcessor: () => { + throw new FrameProcessorsUnavailableError(e); + }, + workletContext: undefined + }; +} + +/** + * The JSI Proxy for the Frame Processors Runtime. + * + * This will be replaced with a CxxTurboModule in the future. + */ +export const VisionCameraProxy = proxy; +//# sourceMappingURL=VisionCameraProxy.js.map \ No newline at end of file diff --git a/package/lib/module/frame-processors/VisionCameraProxy.js.map b/package/lib/module/frame-processors/VisionCameraProxy.js.map new file mode 100644 index 0000000000..17af964e34 --- /dev/null +++ b/package/lib/module/frame-processors/VisionCameraProxy.js.map @@ -0,0 +1 @@ +{"version":3,"names":["CameraModule","FrameProcessorsUnavailableError","proxy","require","result","installFrameProcessorBindings","Error","globalProxy","global","VisionCameraProxy","e","initFrameProcessorPlugin","removeFrameProcessor","setFrameProcessor","workletContext","undefined"],"sourceRoot":"../../../src","sources":["frame-processors/VisionCameraProxy.ts"],"mappings":"AACA,SAASA,YAAY,QAAQ,uBAAuB;AAEpD,SAASC,+BAA+B,QAAQ,mCAAmC;;AAKnF;AACA;AACA;AACA;;AA4CA,IAAIC,KAAyB;AAE7B,IAAI;EACF;EACAC,OAAO,CAAC,4BAA4B,CAAC;EACrC;EACA,MAAMC,MAAM,GAAGJ,YAAY,CAACK,6BAA6B,CAAC,CAAY;EACtE,IAAID,MAAM,KAAK,IAAI,EAAE,MAAM,IAAIE,KAAK,CAAE,4FAA2FF,MAAO,EAAC,CAAC;;EAE1I;EACA;EACA,MAAMG,WAAW,GAAGC,MAAM,CAACC,iBAAmD;EAC9E,IAAIF,WAAW,IAAI,IAAI,EAAE,MAAM,IAAID,KAAK,CAAC,wFAAwF,CAAC;EAElIJ,KAAK,GAAGK,WAAW;AACrB,CAAC,CAAC,OAAOG,CAAC,EAAE;EACV;EACA;EACAR,KAAK,GAAG;IACNS,wBAAwB,EAAEA,CAAA,KAAM;MAC9B,MAAM,IAAIV,+BAA+B,CAACS,CAAC,CAAC;IAC9C,CAAC;IACDE,oBAAoB,EAAEA,CAAA,KAAM;MAC1B,MAAM,IAAIX,+BAA+B,CAACS,CAAC,CAAC;IAC9C,CAAC;IACDG,iBAAiB,EAAEA,CAAA,KAAM;MACvB,MAAM,IAAIZ,+BAA+B,CAACS,CAAC,CAAC;IAC9C,CAAC;IACDI,cAAc,EAAEC;EAClB,CAAC;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMN,iBAAiB,GAAGP,KAAK"} diff --git a/package/lib/module/frame-processors/runAsync.js b/package/lib/module/frame-processors/runAsync.js new file mode 100644 index 0000000000..01c67f219e --- /dev/null +++ b/package/lib/module/frame-processors/runAsync.js @@ -0,0 +1,100 @@ +import { WorkletsProxy } from '../dependencies/WorkletsProxy'; +import { FrameProcessorsUnavailableError } from './FrameProcessorsUnavailableError'; +import { throwErrorOnJS } from './throwErrorOnJS'; + +/** + * A synchronized Shared Value to indicate whether the async context is currently executing + */ +let isAsyncContextBusy; +/** + * Runs the given function on the async context, and sets {@linkcode isAsyncContextBusy} to false after it finished executing. + */ +let runOnAsyncContext; +try { + const Worklets = WorkletsProxy.Worklets; + isAsyncContextBusy = Worklets.createSharedValue(false); + const asyncContext = Worklets.createContext('VisionCamera.async'); + runOnAsyncContext = asyncContext.createRunAsync((frame, func) => { + 'worklet'; + + try { + // Call long-running function + func(); + } catch (e) { + // Re-throw error on JS Thread + throwErrorOnJS(e); + } finally { + // Potentially delete Frame if we were the last ref + const internal = frame; + internal.decrementRefCount(); + + // free up async context again, new calls can be made + isAsyncContextBusy.value = false; + } + }); +} catch (e) { + // react-native-worklets-core is not installed! + // Just use dummy implementations that will throw when the user tries to use Frame Processors. + isAsyncContextBusy = { + value: false + }; + runOnAsyncContext = () => { + throw new FrameProcessorsUnavailableError(e); + }; +} + +/** + * Runs the given {@linkcode func} asynchronously on a separate thread, + * allowing the Frame Processor to continue executing without dropping a Frame. + * + * Only one {@linkcode runAsync} call will execute at the same time, + * so {@linkcode runAsync} is **not parallel**, **but asynchronous**. + * + * + * For example, if your Camera is running at 60 FPS (16ms per frame), and a + * heavy ML face detection Frame Processor Plugin takes 500ms to execute, + * you have two options: + * - Run the plugin normally (synchronously in `useFrameProcessor`) + * but drop a lot of Frames, as we can only run at 2 FPS (500ms per frame) + * - Call the plugin inside {@linkcode runAsync} to allow the Camera to still + * run at 60 FPS, but offload the heavy ML face detection plugin to the + * asynchronous context, where it will run at 2 FPS. + * + * @note {@linkcode runAsync} cannot be used to draw to a Frame in a Skia Frame Processor. + * @param frame The current Frame of the Frame Processor. + * @param func The function to execute. + * @worklet + * @example + * + * ```ts + * const frameProcessor = useFrameProcessor((frame) => { + * 'worklet' + * console.log('New Frame arrived!') + * + * runAsync(frame, () => { + * 'worklet' + * const faces = detectFaces(frame) + * const face = [faces0] + * console.log(`Detected a new face: ${face}`) + * }) + * }) + * ``` + */ +export function runAsync(frame, func) { + 'worklet'; + + if (isAsyncContextBusy.value) { + // async context is currently busy, we cannot schedule new work in time. + // drop this frame/runAsync call. + return; + } + + // Increment ref count by one + const internal = frame; + internal.incrementRefCount(); + isAsyncContextBusy.value = true; + + // Call in separate background context + runOnAsyncContext(frame, func); +} +//# sourceMappingURL=runAsync.js.map \ No newline at end of file diff --git a/package/lib/module/frame-processors/runAsync.js.map b/package/lib/module/frame-processors/runAsync.js.map new file mode 100644 index 0000000000..2057a762dd --- /dev/null +++ b/package/lib/module/frame-processors/runAsync.js.map @@ -0,0 +1 @@ +{"version":3,"names":["WorkletsProxy","FrameProcessorsUnavailableError","throwErrorOnJS","isAsyncContextBusy","runOnAsyncContext","Worklets","createSharedValue","asyncContext","createContext","createRunAsync","frame","func","e","internal","decrementRefCount","value","runAsync","incrementRefCount"],"sourceRoot":"../../../src","sources":["frame-processors/runAsync.ts"],"mappings":"AAAA,SAASA,aAAa,QAAQ,+BAA+B;AAE7D,SAASC,+BAA+B,QAAQ,mCAAmC;AACnF,SAASC,cAAc,QAAQ,kBAAkB;;AAEjD;AACA;AACA;AACA,IAAIC,kBAAsC;AAC1C;AACA;AACA;AACA,IAAIC,iBAA2D;AAE/D,IAAI;EACF,MAAMC,QAAQ,GAAGL,aAAa,CAACK,QAAQ;EACvCF,kBAAkB,GAAGE,QAAQ,CAACC,iBAAiB,CAAC,KAAK,CAAC;EAEtD,MAAMC,YAAY,GAAGF,QAAQ,CAACG,aAAa,CAAC,oBAAoB,CAAC;EACjEJ,iBAAiB,GAAGG,YAAY,CAACE,cAAc,CAAC,CAACC,KAAY,EAAEC,IAAgB,KAAK;IAClF,SAAS;;IACT,IAAI;MACF;MACAA,IAAI,CAAC,CAAC;IACR,CAAC,CAAC,OAAOC,CAAC,EAAE;MACV;MACAV,cAAc,CAACU,CAAC,CAAC;IACnB,CAAC,SAAS;MACR;MACA,MAAMC,QAAQ,GAAGH,KAAsB;MACvCG,QAAQ,CAACC,iBAAiB,CAAC,CAAC;;MAE5B;MACAX,kBAAkB,CAACY,KAAK,GAAG,KAAK;IAClC;EACF,CAAC,CAAC;AACJ,CAAC,CAAC,OAAOH,CAAC,EAAE;EACV;EACA;EACAT,kBAAkB,GAAG;IAAEY,KAAK,EAAE;EAAM,CAAC;EACrCX,iBAAiB,GAAGA,CAAA,KAAM;IACxB,MAAM,IAAIH,+BAA+B,CAACW,CAAC,CAAC;EAC9C,CAAC;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASI,QAAQA,CAACN,KAAY,EAAEC,IAAgB,EAAQ;EAC7D,SAAS;;EAET,IAAIR,kBAAkB,CAACY,KAAK,EAAE;IAC5B;IACA;IACA;EACF;;EAEA;EACA,MAAMF,QAAQ,GAAGH,KAAsB;EACvCG,QAAQ,CAACI,iBAAiB,CAAC,CAAC;EAE5Bd,kBAAkB,CAACY,KAAK,GAAG,IAAI;;EAE/B;EACAX,iBAAiB,CAACM,KAAK,EAAEC,IAAI,CAAC;AAChC"} diff --git a/package/lib/module/frame-processors/runAtTargetFps.js b/package/lib/module/frame-processors/runAtTargetFps.js new file mode 100644 index 0000000000..b0ad1f22be --- /dev/null +++ b/package/lib/module/frame-processors/runAtTargetFps.js @@ -0,0 +1,56 @@ +function getLastFrameProcessorCall(frameProcessorFuncId) { + 'worklet'; + + return global.__frameProcessorRunAtTargetFpsMap?.[frameProcessorFuncId] ?? 0; +} +function setLastFrameProcessorCall(frameProcessorFuncId, value) { + 'worklet'; + + if (global.__frameProcessorRunAtTargetFpsMap == null) global.__frameProcessorRunAtTargetFpsMap = {}; + global.__frameProcessorRunAtTargetFpsMap[frameProcessorFuncId] = value; +} + +/** + * Runs the given {@linkcode func} at the given target {@linkcode fps} rate. + * + * {@linkcode runAtTargetFps} still executes the given {@linkcode func} synchronously, + * so this is only useful for throttling calls to a plugin or logger. + * + * For example, if you want to scan faces only once per second to avoid excessive + * CPU usage, use {@linkcode runAtTargetFps runAtTargetFps(1, ...)}. + * + * @param fps The target FPS rate at which the given function should be executed + * @param func The function to execute. + * @returns The result of the function if it was executed, or `undefined` otherwise. + * @worklet + * @example + * + * ```ts + * const frameProcessor = useFrameProcessor((frame) => { + * 'worklet' + * console.log('New Frame') + * runAtTargetFps(5, () => { + * 'worklet' + * const faces = detectFaces(frame) + * console.log(`Detected a new face: ${faces[0]}`) + * }) + * }) + * ``` + */ +export function runAtTargetFps(fps, func) { + 'worklet'; + + // @ts-expect-error + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const funcId = func.__workletHash ?? '1'; + const targetIntervalMs = 1000 / fps; // <-- 60 FPS => 16,6667ms interval + const now = performance.now(); + const diffToLastCall = now - getLastFrameProcessorCall(funcId); + if (diffToLastCall >= targetIntervalMs) { + setLastFrameProcessorCall(funcId, now); + // Last Frame Processor call is already so long ago that we want to make a new call + return func(); + } + return undefined; +} +//# sourceMappingURL=runAtTargetFps.js.map \ No newline at end of file diff --git a/package/lib/module/frame-processors/runAtTargetFps.js.map b/package/lib/module/frame-processors/runAtTargetFps.js.map new file mode 100644 index 0000000000..99dba0dc06 --- /dev/null +++ b/package/lib/module/frame-processors/runAtTargetFps.js.map @@ -0,0 +1 @@ +{"version":3,"names":["getLastFrameProcessorCall","frameProcessorFuncId","global","__frameProcessorRunAtTargetFpsMap","setLastFrameProcessorCall","value","runAtTargetFps","fps","func","funcId","__workletHash","targetIntervalMs","now","performance","diffToLastCall","undefined"],"sourceRoot":"../../../src","sources":["frame-processors/runAtTargetFps.ts"],"mappings":"AAKA,SAASA,yBAAyBA,CAACC,oBAA4B,EAAU;EACvE,SAAS;;EACT,OAAOC,MAAM,CAACC,iCAAiC,GAAGF,oBAAoB,CAAC,IAAI,CAAC;AAC9E;AACA,SAASG,yBAAyBA,CAACH,oBAA4B,EAAEI,KAAa,EAAQ;EACpF,SAAS;;EACT,IAAIH,MAAM,CAACC,iCAAiC,IAAI,IAAI,EAAED,MAAM,CAACC,iCAAiC,GAAG,CAAC,CAAC;EACnGD,MAAM,CAACC,iCAAiC,CAACF,oBAAoB,CAAC,GAAGI,KAAK;AACxE;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,cAAcA,CAAIC,GAAW,EAAEC,IAAa,EAAiB;EAC3E,SAAS;;EACT;EACA;EACA,MAAMC,MAAM,GAAGD,IAAI,CAACE,aAAa,IAAI,GAAG;EAExC,MAAMC,gBAAgB,GAAG,IAAI,GAAGJ,GAAG,EAAC;EACpC,MAAMK,GAAG,GAAGC,WAAW,CAACD,GAAG,CAAC,CAAC;EAC7B,MAAME,cAAc,GAAGF,GAAG,GAAGZ,yBAAyB,CAACS,MAAM,CAAC;EAC9D,IAAIK,cAAc,IAAIH,gBAAgB,EAAE;IACtCP,yBAAyB,CAACK,MAAM,EAAEG,GAAG,CAAC;IACtC;IACA,OAAOJ,IAAI,CAAC,CAAC;EACf;EACA,OAAOO,SAAS;AAClB"} diff --git a/package/lib/module/frame-processors/throwErrorOnJS.js b/package/lib/module/frame-processors/throwErrorOnJS.js new file mode 100644 index 0000000000..660538b8ca --- /dev/null +++ b/package/lib/module/frame-processors/throwErrorOnJS.js @@ -0,0 +1,47 @@ +import { WorkletsProxy } from '../dependencies/WorkletsProxy'; +import { FrameProcessorsUnavailableError } from './FrameProcessorsUnavailableError'; +/** + * Rethrows the given message and stack as a JS Error on the JS Thread. + */ +let rethrowErrorOnJS; +try { + const Worklets = WorkletsProxy.Worklets; + rethrowErrorOnJS = Worklets.createRunOnJS((message, stack) => { + const error = new Error(); + error.message = message; + error.stack = stack; + error.name = 'Frame Processor Error'; + // @ts-expect-error this is react-native specific + error.jsEngine = 'VisionCamera'; + + // From react-native: + // @ts-expect-error it's untyped + const errorUtils = global.ErrorUtils ?? global.__ErrorUtils; + if (errorUtils != null && typeof errorUtils.reportFatalError === 'function') { + // we can use the JS error reporter view from react native + errorUtils.reportFatalError(error); + } else { + // just log it to console.error as a fallback + console.error('Frame Processor Error:', error); + } + }); +} catch (e) { + // react-native-worklets-core is not installed! + // Just use dummy implementations that will throw when the user tries to use Frame Processors. + rethrowErrorOnJS = () => { + throw new FrameProcessorsUnavailableError(e); + }; +} + +/** + * Throws the given Error on the JS Thread using React Native's error reporter. + * @param error An {@linkcode Error}, or an object with a `message` property, otherwise a default messageg will be thrown. + */ +export function throwErrorOnJS(error) { + 'worklet'; + + const safeError = error; + const message = safeError != null && 'message' in safeError ? safeError.message : 'Frame Processor threw an error.'; + rethrowErrorOnJS(message, safeError?.stack); +} +//# sourceMappingURL=throwErrorOnJS.js.map \ No newline at end of file diff --git a/package/lib/module/frame-processors/throwErrorOnJS.js.map b/package/lib/module/frame-processors/throwErrorOnJS.js.map new file mode 100644 index 0000000000..20a45c8755 --- /dev/null +++ b/package/lib/module/frame-processors/throwErrorOnJS.js.map @@ -0,0 +1 @@ +{"version":3,"names":["WorkletsProxy","FrameProcessorsUnavailableError","rethrowErrorOnJS","Worklets","createRunOnJS","message","stack","error","Error","name","jsEngine","errorUtils","global","ErrorUtils","__ErrorUtils","reportFatalError","console","e","throwErrorOnJS","safeError"],"sourceRoot":"../../../src","sources":["frame-processors/throwErrorOnJS.ts"],"mappings":"AAAA,SAASA,aAAa,QAAQ,+BAA+B;AAC7D,SAASC,+BAA+B,QAAQ,mCAAmC;AAMnF;AACA;AACA;AACA,IAAIC,gBAAsE;AAE1E,IAAI;EACF,MAAMC,QAAQ,GAAGH,aAAa,CAACG,QAAQ;EACvCD,gBAAgB,GAAGC,QAAQ,CAACC,aAAa,CAAC,CAACC,OAAe,EAAEC,KAAyB,KAAK;IACxF,MAAMC,KAAK,GAAG,IAAIC,KAAK,CAAC,CAAC;IACzBD,KAAK,CAACF,OAAO,GAAGA,OAAO;IACvBE,KAAK,CAACD,KAAK,GAAGA,KAAK;IACnBC,KAAK,CAACE,IAAI,GAAG,uBAAuB;IACpC;IACAF,KAAK,CAACG,QAAQ,GAAG,cAAc;;IAE/B;IACA;IACA,MAAMC,UAAU,GAAIC,MAAM,CAACC,UAAU,IAAID,MAAM,CAACE,YAAwC;IACxF,IAAIH,UAAU,IAAI,IAAI,IAAI,OAAOA,UAAU,CAACI,gBAAgB,KAAK,UAAU,EAAE;MAC3E;MACAJ,UAAU,CAACI,gBAAgB,CAACR,KAAK,CAAC;IACpC,CAAC,MAAM;MACL;MACAS,OAAO,CAACT,KAAK,CAAC,wBAAwB,EAAEA,KAAK,CAAC;IAChD;EACF,CAAC,CAAC;AACJ,CAAC,CAAC,OAAOU,CAAC,EAAE;EACV;EACA;EACAf,gBAAgB,GAAGA,CAAA,KAAM;IACvB,MAAM,IAAID,+BAA+B,CAACgB,CAAC,CAAC;EAC9C,CAAC;AACH;;AAEA;AACA;AACA;AACA;AACA,OAAO,SAASC,cAAcA,CAACX,KAAc,EAAQ;EACnD,SAAS;;EACT,MAAMY,SAAS,GAAGZ,KAA0B;EAC5C,MAAMF,OAAO,GAAGc,SAAS,IAAI,IAAI,IAAI,SAAS,IAAIA,SAAS,GAAGA,SAAS,CAACd,OAAO,GAAG,iCAAiC;EACnHH,gBAAgB,CAACG,OAAO,EAAEc,SAAS,EAAEb,KAAK,CAAC;AAC7C"} diff --git a/package/lib/module/frame-processors/withFrameRefCounting.js b/package/lib/module/frame-processors/withFrameRefCounting.js new file mode 100644 index 0000000000..668fded9b5 --- /dev/null +++ b/package/lib/module/frame-processors/withFrameRefCounting.js @@ -0,0 +1,27 @@ +import { throwErrorOnJS } from './throwErrorOnJS'; + +/** + * A private API to wrap a Frame Processor with a ref-counting mechanism + * @worklet + * @internal + */ +export function withFrameRefCounting(frameProcessor) { + return frame => { + 'worklet'; + + // Increment ref-count by one + const internal = frame; + internal.incrementRefCount(); + try { + // Call sync frame processor + frameProcessor(frame); + } catch (e) { + // Re-throw error on JS Thread + throwErrorOnJS(e); + } finally { + // Potentially delete Frame if we were the last ref (no runAsync) + internal.decrementRefCount(); + } + }; +} +//# sourceMappingURL=withFrameRefCounting.js.map \ No newline at end of file diff --git a/package/lib/module/frame-processors/withFrameRefCounting.js.map b/package/lib/module/frame-processors/withFrameRefCounting.js.map new file mode 100644 index 0000000000..d09cbfeec9 --- /dev/null +++ b/package/lib/module/frame-processors/withFrameRefCounting.js.map @@ -0,0 +1 @@ +{"version":3,"names":["throwErrorOnJS","withFrameRefCounting","frameProcessor","frame","internal","incrementRefCount","e","decrementRefCount"],"sourceRoot":"../../../src","sources":["frame-processors/withFrameRefCounting.ts"],"mappings":"AACA,SAASA,cAAc,QAAQ,kBAAkB;;AAEjD;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,oBAAoBA,CAACC,cAAsC,EAA0B;EACnG,OAAQC,KAAK,IAAK;IAChB,SAAS;;IACT;IACA,MAAMC,QAAQ,GAAGD,KAAsB;IACvCC,QAAQ,CAACC,iBAAiB,CAAC,CAAC;IAC5B,IAAI;MACF;MACAH,cAAc,CAACC,KAAK,CAAC;IACvB,CAAC,CAAC,OAAOG,CAAC,EAAE;MACV;MACAN,cAAc,CAACM,CAAC,CAAC;IACnB,CAAC,SAAS;MACR;MACAF,QAAQ,CAACG,iBAAiB,CAAC,CAAC;IAC9B;EACF,CAAC;AACH"} diff --git a/package/lib/module/hooks/useCameraDevice.js b/package/lib/module/hooks/useCameraDevice.js new file mode 100644 index 0000000000..181150eb73 --- /dev/null +++ b/package/lib/module/hooks/useCameraDevice.js @@ -0,0 +1,24 @@ +import { useMemo } from 'react'; +import { getCameraDevice } from '../devices/getCameraDevice'; +import { useCameraDevices } from './useCameraDevices'; + +/** + * Get the best matching Camera device that best satisfies your requirements using a sorting filter. + * @param position The position of the Camera device relative to the phone. + * @param filter The filter you want to use. The Camera device that matches your filter the closest will be returned + * @returns The Camera device that matches your filter the closest, or `undefined` if no such Camera Device exists on the given {@linkcode position}. + * @example + * ```ts + * const device = useCameraDevice('back', { + * physicalDevices: ['wide-angle-camera'] + * }) + * ``` + */ +export function useCameraDevice(position, filter) { + const devices = useCameraDevices(); + const device = useMemo(() => getCameraDevice(devices, position, filter), + // eslint-disable-next-line react-hooks/exhaustive-deps + [devices, position, JSON.stringify(filter)]); + return device; +} +//# sourceMappingURL=useCameraDevice.js.map \ No newline at end of file diff --git a/package/lib/module/hooks/useCameraDevice.js.map b/package/lib/module/hooks/useCameraDevice.js.map new file mode 100644 index 0000000000..7562f09d9c --- /dev/null +++ b/package/lib/module/hooks/useCameraDevice.js.map @@ -0,0 +1 @@ +{"version":3,"names":["useMemo","getCameraDevice","useCameraDevices","useCameraDevice","position","filter","devices","device","JSON","stringify"],"sourceRoot":"../../../src","sources":["hooks/useCameraDevice.ts"],"mappings":"AAAA,SAASA,OAAO,QAAQ,OAAO;AAG/B,SAASC,eAAe,QAAQ,4BAA4B;AAC5D,SAASC,gBAAgB,QAAQ,oBAAoB;;AAErD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,eAAeA,CAACC,QAAwB,EAAEC,MAAqB,EAA4B;EACzG,MAAMC,OAAO,GAAGJ,gBAAgB,CAAC,CAAC;EAElC,MAAMK,MAAM,GAAGP,OAAO,CACpB,MAAMC,eAAe,CAACK,OAAO,EAAEF,QAAQ,EAAEC,MAAM,CAAC;EAChD;EACA,CAACC,OAAO,EAAEF,QAAQ,EAAEI,IAAI,CAACC,SAAS,CAACJ,MAAM,CAAC,CAC5C,CAAC;EAED,OAAOE,MAAM;AACf"} diff --git a/package/lib/module/hooks/useCameraDevices.js b/package/lib/module/hooks/useCameraDevices.js new file mode 100644 index 0000000000..47c42b4407 --- /dev/null +++ b/package/lib/module/hooks/useCameraDevices.js @@ -0,0 +1,21 @@ +import { useEffect, useState } from 'react'; +import { CameraDevices } from '../CameraDevices'; + +/** + * Get all available Camera Devices this phone has. + * + * Camera Devices attached to this phone (`back` or `front`) are always available, + * while `external` devices might be plugged in or out at any point, + * so the result of this function might update over time. + */ +export function useCameraDevices() { + const [devices, setDevices] = useState(() => CameraDevices.getAvailableCameraDevices()); + useEffect(() => { + const listener = CameraDevices.addCameraDevicesChangedListener(newDevices => { + setDevices(newDevices); + }); + return () => listener.remove(); + }, []); + return devices; +} +//# sourceMappingURL=useCameraDevices.js.map \ No newline at end of file diff --git a/package/lib/module/hooks/useCameraDevices.js.map b/package/lib/module/hooks/useCameraDevices.js.map new file mode 100644 index 0000000000..f8df00664e --- /dev/null +++ b/package/lib/module/hooks/useCameraDevices.js.map @@ -0,0 +1 @@ +{"version":3,"names":["useEffect","useState","CameraDevices","useCameraDevices","devices","setDevices","getAvailableCameraDevices","listener","addCameraDevicesChangedListener","newDevices","remove"],"sourceRoot":"../../../src","sources":["hooks/useCameraDevices.ts"],"mappings":"AAAA,SAASA,SAAS,EAAEC,QAAQ,QAAQ,OAAO;AAE3C,SAASC,aAAa,QAAQ,kBAAkB;;AAEhD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,gBAAgBA,CAAA,EAAmB;EACjD,MAAM,CAACC,OAAO,EAAEC,UAAU,CAAC,GAAGJ,QAAQ,CAAC,MAAMC,aAAa,CAACI,yBAAyB,CAAC,CAAC,CAAC;EAEvFN,SAAS,CAAC,MAAM;IACd,MAAMO,QAAQ,GAAGL,aAAa,CAACM,+BAA+B,CAAEC,UAAU,IAAK;MAC7EJ,UAAU,CAACI,UAAU,CAAC;IACxB,CAAC,CAAC;IACF,OAAO,MAAMF,QAAQ,CAACG,MAAM,CAAC,CAAC;EAChC,CAAC,EAAE,EAAE,CAAC;EAEN,OAAON,OAAO;AAChB"} diff --git a/package/lib/module/hooks/useCameraFormat.js b/package/lib/module/hooks/useCameraFormat.js new file mode 100644 index 0000000000..f9804fa05d --- /dev/null +++ b/package/lib/module/hooks/useCameraFormat.js @@ -0,0 +1,30 @@ +import { useMemo } from 'react'; +import { getCameraFormat } from '../devices/getCameraFormat'; + +/** + * Get the best matching Camera format for the given device that satisfies your requirements using a sorting filter. By default, formats are sorted by highest to lowest resolution. + * + * The {@linkcode filters | filters} are ranked by priority, from highest to lowest. + * This means the first item you pass will have a higher priority than the second, and so on. + * + * @param device The Camera Device you're currently using + * @param filters The filters you want to use. The format that matches your filter the closest will be returned + * @returns The format that matches your filter the closest. + * @example + * ```ts + * const device = useCameraDevice(...) + * const format = useCameraFormat(device, [ + * { videoResolution: { width: 3048, height: 2160 } }, + * { fps: 60 } + * ]) + * ``` + */ +export function useCameraFormat(device, filters) { + const format = useMemo(() => { + if (device == null) return undefined; + return getCameraFormat(device, filters); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [device, JSON.stringify(filters)]); + return format; +} +//# sourceMappingURL=useCameraFormat.js.map \ No newline at end of file diff --git a/package/lib/module/hooks/useCameraFormat.js.map b/package/lib/module/hooks/useCameraFormat.js.map new file mode 100644 index 0000000000..4cf0003140 --- /dev/null +++ b/package/lib/module/hooks/useCameraFormat.js.map @@ -0,0 +1 @@ +{"version":3,"names":["useMemo","getCameraFormat","useCameraFormat","device","filters","format","undefined","JSON","stringify"],"sourceRoot":"../../../src","sources":["hooks/useCameraFormat.ts"],"mappings":"AAAA,SAASA,OAAO,QAAQ,OAAO;AAG/B,SAASC,eAAe,QAAQ,4BAA4B;;AAE5D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,eAAeA,CAACC,MAAgC,EAAEC,OAAuB,EAAkC;EACzH,MAAMC,MAAM,GAAGL,OAAO,CAAC,MAAM;IAC3B,IAAIG,MAAM,IAAI,IAAI,EAAE,OAAOG,SAAS;IACpC,OAAOL,eAAe,CAACE,MAAM,EAAEC,OAAO,CAAC;IACvC;EACF,CAAC,EAAE,CAACD,MAAM,EAAEI,IAAI,CAACC,SAAS,CAACJ,OAAO,CAAC,CAAC,CAAC;EAErC,OAAOC,MAAM;AACf"} diff --git a/package/lib/module/hooks/useCameraPermission.js b/package/lib/module/hooks/useCameraPermission.js new file mode 100644 index 0000000000..91e2fd4998 --- /dev/null +++ b/package/lib/module/hooks/useCameraPermission.js @@ -0,0 +1,80 @@ +import { useCallback, useEffect, useMemo, useState } from 'react'; +import { Camera } from '../Camera'; +import { AppState } from 'react-native'; +function usePermission(get, request) { + const [hasPermission, setHasPermission] = useState(() => get() === 'granted'); + const requestPermission = useCallback(async () => { + const result = await request(); + const hasPermissionNow = result === 'granted'; + setHasPermission(hasPermissionNow); + return hasPermissionNow; + }, [request]); + useEffect(() => { + // Refresh permission when app state changes, as user might have allowed it in Settings + const listener = AppState.addEventListener('change', () => { + setHasPermission(get() === 'granted'); + }); + return () => listener.remove(); + }, [get]); + return useMemo(() => ({ + hasPermission, + requestPermission + }), [hasPermission, requestPermission]); +} + +/** + * Returns whether the user has granted permission to use the Camera, or not. + * + * If the user doesn't grant Camera Permission, you cannot use the ``. + * + * @example + * ```tsx + * const { hasPermission, requestPermission } = useCameraPermission() + * + * if (!hasPermission) { + * return + * } else { + * return + * } + * ``` + */ +export function useCameraPermission() { + return usePermission(Camera.getCameraPermissionStatus, Camera.requestCameraPermission); +} + +/** + * Returns whether the user has granted permission to use the Microphone, or not. + * + * If the user doesn't grant Audio Permission, you can use the `` but you cannot + * record videos with audio (the `audio={..}` prop). + * + * @example + * ```tsx + * const { hasPermission, requestPermission } = useMicrophonePermission() + * const canRecordAudio = hasPermission + * + * return + * ``` + */ +export function useMicrophonePermission() { + return usePermission(Camera.getMicrophonePermissionStatus, Camera.requestMicrophonePermission); +} + +/** + * Returns whether the user has granted permission to use the Location, or not. + * + * If the user doesn't grant Location Permission, you can use the `` but you cannot + * capture photos or videos with GPS EXIF tags (the `location={..}` prop). + * + * @example + * ```tsx + * const { hasPermission, requestPermission } = useLocationPermission() + * const canCaptureLocation = hasPermission + * + * return + * ``` + */ +export function useLocationPermission() { + return usePermission(Camera.getLocationPermissionStatus, Camera.requestLocationPermission); +} +//# sourceMappingURL=useCameraPermission.js.map \ No newline at end of file diff --git a/package/lib/module/hooks/useCameraPermission.js.map b/package/lib/module/hooks/useCameraPermission.js.map new file mode 100644 index 0000000000..2771f24955 --- /dev/null +++ b/package/lib/module/hooks/useCameraPermission.js.map @@ -0,0 +1 @@ +{"version":3,"names":["useCallback","useEffect","useMemo","useState","Camera","AppState","usePermission","get","request","hasPermission","setHasPermission","requestPermission","result","hasPermissionNow","listener","addEventListener","remove","useCameraPermission","getCameraPermissionStatus","requestCameraPermission","useMicrophonePermission","getMicrophonePermissionStatus","requestMicrophonePermission","useLocationPermission","getLocationPermissionStatus","requestLocationPermission"],"sourceRoot":"../../../src","sources":["hooks/useCameraPermission.ts"],"mappings":"AAAA,SAASA,WAAW,EAAEC,SAAS,EAAEC,OAAO,EAAEC,QAAQ,QAAQ,OAAO;AAEjE,SAASC,MAAM,QAAQ,WAAW;AAClC,SAASC,QAAQ,QAAQ,cAAc;AAevC,SAASC,aAAaA,CAACC,GAAiC,EAAEC,OAAqD,EAAmB;EAChI,MAAM,CAACC,aAAa,EAAEC,gBAAgB,CAAC,GAAGP,QAAQ,CAAC,MAAMI,GAAG,CAAC,CAAC,KAAK,SAAS,CAAC;EAE7E,MAAMI,iBAAiB,GAAGX,WAAW,CAAC,YAAY;IAChD,MAAMY,MAAM,GAAG,MAAMJ,OAAO,CAAC,CAAC;IAC9B,MAAMK,gBAAgB,GAAGD,MAAM,KAAK,SAAS;IAC7CF,gBAAgB,CAACG,gBAAgB,CAAC;IAClC,OAAOA,gBAAgB;EACzB,CAAC,EAAE,CAACL,OAAO,CAAC,CAAC;EAEbP,SAAS,CAAC,MAAM;IACd;IACA,MAAMa,QAAQ,GAAGT,QAAQ,CAACU,gBAAgB,CAAC,QAAQ,EAAE,MAAM;MACzDL,gBAAgB,CAACH,GAAG,CAAC,CAAC,KAAK,SAAS,CAAC;IACvC,CAAC,CAAC;IACF,OAAO,MAAMO,QAAQ,CAACE,MAAM,CAAC,CAAC;EAChC,CAAC,EAAE,CAACT,GAAG,CAAC,CAAC;EAET,OAAOL,OAAO,CACZ,OAAO;IACLO,aAAa;IACbE;EACF,CAAC,CAAC,EACF,CAACF,aAAa,EAAEE,iBAAiB,CACnC,CAAC;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASM,mBAAmBA,CAAA,EAAoB;EACrD,OAAOX,aAAa,CAACF,MAAM,CAACc,yBAAyB,EAAEd,MAAM,CAACe,uBAAuB,CAAC;AACxF;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,uBAAuBA,CAAA,EAAoB;EACzD,OAAOd,aAAa,CAACF,MAAM,CAACiB,6BAA6B,EAAEjB,MAAM,CAACkB,2BAA2B,CAAC;AAChG;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,qBAAqBA,CAAA,EAAoB;EACvD,OAAOjB,aAAa,CAACF,MAAM,CAACoB,2BAA2B,EAAEpB,MAAM,CAACqB,yBAAyB,CAAC;AAC5F"} diff --git a/package/lib/module/hooks/useCodeScanner.js b/package/lib/module/hooks/useCodeScanner.js new file mode 100644 index 0000000000..eb19f0c2d6 --- /dev/null +++ b/package/lib/module/hooks/useCodeScanner.js @@ -0,0 +1,23 @@ +import { useCallback, useMemo, useRef } from 'react'; +export function useCodeScanner(codeScanner) { + const { + onCodeScanned, + ...codeScannerOptions + } = codeScanner; + + // Memoize the function once and use a ref on any identity changes + const ref = useRef(onCodeScanned); + ref.current = onCodeScanned; + const callback = useCallback((codes, frame) => { + ref.current(codes, frame); + }, []); + + // CodeScanner needs to be memoized so it doesn't trigger a Camera Session re-build + return useMemo(() => ({ + ...codeScannerOptions, + onCodeScanned: callback + }), + // eslint-disable-next-line react-hooks/exhaustive-deps + [JSON.stringify(codeScannerOptions), callback]); +} +//# sourceMappingURL=useCodeScanner.js.map \ No newline at end of file diff --git a/package/lib/module/hooks/useCodeScanner.js.map b/package/lib/module/hooks/useCodeScanner.js.map new file mode 100644 index 0000000000..15b096d61d --- /dev/null +++ b/package/lib/module/hooks/useCodeScanner.js.map @@ -0,0 +1 @@ +{"version":3,"names":["useCallback","useMemo","useRef","useCodeScanner","codeScanner","onCodeScanned","codeScannerOptions","ref","current","callback","codes","frame","JSON","stringify"],"sourceRoot":"../../../src","sources":["hooks/useCodeScanner.ts"],"mappings":"AAAA,SAASA,WAAW,EAAEC,OAAO,EAAEC,MAAM,QAAQ,OAAO;AAGpD,OAAO,SAASC,cAAcA,CAACC,WAAwB,EAAe;EACpE,MAAM;IAAEC,aAAa;IAAE,GAAGC;EAAmB,CAAC,GAAGF,WAAW;;EAE5D;EACA,MAAMG,GAAG,GAAGL,MAAM,CAACG,aAAa,CAAC;EACjCE,GAAG,CAACC,OAAO,GAAGH,aAAa;EAC3B,MAAMI,QAAQ,GAAGT,WAAW,CAAC,CAACU,KAAa,EAAEC,KAAuB,KAAK;IACvEJ,GAAG,CAACC,OAAO,CAACE,KAAK,EAAEC,KAAK,CAAC;EAC3B,CAAC,EAAE,EAAE,CAAC;;EAEN;EACA,OAAOV,OAAO,CACZ,OAAO;IACL,GAAGK,kBAAkB;IACrBD,aAAa,EAAEI;EACjB,CAAC,CAAC;EACF;EACA,CAACG,IAAI,CAACC,SAAS,CAACP,kBAAkB,CAAC,EAAEG,QAAQ,CAC/C,CAAC;AACH"} diff --git a/package/lib/module/hooks/useFrameProcessor.js b/package/lib/module/hooks/useFrameProcessor.js new file mode 100644 index 0000000000..ac43715393 --- /dev/null +++ b/package/lib/module/hooks/useFrameProcessor.js @@ -0,0 +1,42 @@ +import { useMemo } from 'react'; +import { withFrameRefCounting } from '../frame-processors/withFrameRefCounting'; +/** + * Create a new Frame Processor function which you can pass to the ``. + * (See ["Frame Processors"](https://react-native-vision-camera.com/docs/guides/frame-processors)) + * + * Make sure to add the `'worklet'` directive to the top of the Frame Processor function, otherwise it will not get compiled into a worklet. + * + * Also make sure to memoize the returned object, so that the Camera doesn't reset the Frame Processor Context each time. + * @worklet + */ +export function createFrameProcessor(frameProcessor) { + return { + frameProcessor: withFrameRefCounting(frameProcessor), + type: 'readonly' + }; +} + +/** + * Returns a memoized Frame Processor function wich you can pass to the ``. + * (See ["Frame Processors"](https://react-native-vision-camera.com/docs/guides/frame-processors)) + * + * Make sure to add the `'worklet'` directive to the top of the Frame Processor function, otherwise it will not get compiled into a worklet. + * + * @worklet + * @param frameProcessor The Frame Processor + * @param dependencies The React dependencies which will be copied into the VisionCamera JS-Runtime. + * @returns The memoized Frame Processor. + * @example + * ```ts + * const frameProcessor = useFrameProcessor((frame) => { + * 'worklet' + * const faces = scanFaces(frame) + * console.log(`Faces: ${faces}`) + * }, []) + * ``` + */ +export function useFrameProcessor(frameProcessor, dependencies) { + // eslint-disable-next-line react-hooks/exhaustive-deps + return useMemo(() => createFrameProcessor(frameProcessor), dependencies); +} +//# sourceMappingURL=useFrameProcessor.js.map \ No newline at end of file diff --git a/package/lib/module/hooks/useFrameProcessor.js.map b/package/lib/module/hooks/useFrameProcessor.js.map new file mode 100644 index 0000000000..a784dd6cc6 --- /dev/null +++ b/package/lib/module/hooks/useFrameProcessor.js.map @@ -0,0 +1 @@ +{"version":3,"names":["useMemo","withFrameRefCounting","createFrameProcessor","frameProcessor","type","useFrameProcessor","dependencies"],"sourceRoot":"../../../src","sources":["hooks/useFrameProcessor.ts"],"mappings":"AACA,SAASA,OAAO,QAAQ,OAAO;AAC/B,SAASC,oBAAoB,QAAQ,0CAA0C;AAI/E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,oBAAoBA,CAACC,cAAsC,EAA0B;EACnG,OAAO;IACLA,cAAc,EAAEF,oBAAoB,CAACE,cAAc,CAAC;IACpDC,IAAI,EAAE;EACR,CAAC;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,iBAAiBA,CAACF,cAAsC,EAAEG,YAA4B,EAA0B;EAC9H;EACA,OAAON,OAAO,CAAC,MAAME,oBAAoB,CAACC,cAAc,CAAC,EAAEG,YAAY,CAAC;AAC1E"} diff --git a/package/lib/module/index.js b/package/lib/module/index.js new file mode 100644 index 0000000000..ded3fac145 --- /dev/null +++ b/package/lib/module/index.js @@ -0,0 +1,39 @@ +// Base Camera Exports +export * from './Camera'; +export * from './CameraError'; + +// Types +export * from './types/CameraDevice'; +export * from './types/CameraProps'; +export * from './types/Frame'; +export * from './types/Orientation'; +export * from './types/OutputOrientation'; +export * from './types/PhotoFile'; +export * from './types/Snapshot'; +export * from './types/PixelFormat'; +export * from './types/Point'; +export * from './types/VideoFile'; +export * from './types/CodeScanner'; + +// Devices API +export * from './devices/getCameraFormat'; +export * from './devices/getCameraDevice'; +export * from './devices/Templates'; + +// Hooks +export * from './hooks/useCameraDevice'; +export * from './hooks/useCameraDevices'; +export * from './hooks/useCameraFormat'; +export * from './hooks/useCameraPermission'; +export * from './hooks/useCodeScanner'; +export * from './hooks/useFrameProcessor'; + +// Frame Processors +export * from './frame-processors/runAsync'; +export * from './frame-processors/runAtTargetFps'; +// DEPRECATED: This will be removed in favour of a CxxTurboModule in the future. +export * from './frame-processors/VisionCameraProxy'; + +// Skia Frame Processors +export * from './skia/useSkiaFrameProcessor'; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/package/lib/module/index.js.map b/package/lib/module/index.js.map new file mode 100644 index 0000000000..9dd47938ec --- /dev/null +++ b/package/lib/module/index.js.map @@ -0,0 +1 @@ +{"version":3,"names":[],"sourceRoot":"../../src","sources":["index.ts"],"mappings":"AAAA;AACA,cAAc,UAAU;AACxB,cAAc,eAAe;;AAE7B;AACA,cAAc,sBAAsB;AACpC,cAAc,qBAAqB;AACnC,cAAc,eAAe;AAC7B,cAAc,qBAAqB;AACnC,cAAc,2BAA2B;AACzC,cAAc,mBAAmB;AACjC,cAAc,kBAAkB;AAChC,cAAc,qBAAqB;AACnC,cAAc,eAAe;AAC7B,cAAc,mBAAmB;AACjC,cAAc,qBAAqB;;AAEnC;AACA,cAAc,2BAA2B;AACzC,cAAc,2BAA2B;AACzC,cAAc,qBAAqB;;AAEnC;AACA,cAAc,yBAAyB;AACvC,cAAc,0BAA0B;AACxC,cAAc,yBAAyB;AACvC,cAAc,6BAA6B;AAC3C,cAAc,wBAAwB;AACtC,cAAc,2BAA2B;;AAEzC;AACA,cAAc,6BAA6B;AAC3C,cAAc,mCAAmC;AACjD;AACA,cAAc,sCAAsC;;AAEpD;AACA,cAAc,8BAA8B"} diff --git a/package/lib/module/skia/SkiaCameraCanvas.js b/package/lib/module/skia/SkiaCameraCanvas.js new file mode 100644 index 0000000000..fe33361ccb --- /dev/null +++ b/package/lib/module/skia/SkiaCameraCanvas.js @@ -0,0 +1,51 @@ +function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } +import React, { useCallback, useState } from 'react'; +import { ReanimatedProxy } from '../dependencies/ReanimatedProxy'; +import { SkiaProxy } from '../dependencies/SkiaProxy'; +function SkiaCameraCanvasImpl({ + offscreenTextures, + resizeMode = 'cover', + children, + ...props +}) { + const texture = ReanimatedProxy.useSharedValue(null); + const [width, setWidth] = useState(0); + const [height, setHeight] = useState(0); + ReanimatedProxy.useFrameCallback(() => { + 'worklet'; + + // 1. atomically pop() the latest rendered frame/texture from our queue + const latestTexture = offscreenTextures.value.pop(); + if (latestTexture == null) { + // we don't have a new Frame from the Camera yet, skip this render. + return; + } + + // 2. dispose the last rendered frame + texture.value?.dispose(); + + // 3. set a new one which will be rendered then + texture.value = latestTexture; + }); + const onLayout = useCallback(({ + nativeEvent: { + layout + } + }) => { + setWidth(Math.round(layout.width)); + setHeight(Math.round(layout.height)); + }, []); + return /*#__PURE__*/React.createElement(SkiaProxy.Canvas, _extends({}, props, { + onLayout: onLayout, + pointerEvents: "none" + }), children, /*#__PURE__*/React.createElement(SkiaProxy.Image, { + x: 0, + y: 0, + width: width, + height: height, + fit: resizeMode, + image: texture + })); +} +export const SkiaCameraCanvas = /*#__PURE__*/React.memo(SkiaCameraCanvasImpl); +//# sourceMappingURL=SkiaCameraCanvas.js.map \ No newline at end of file diff --git a/package/lib/module/skia/SkiaCameraCanvas.js.map b/package/lib/module/skia/SkiaCameraCanvas.js.map new file mode 100644 index 0000000000..a99023f224 --- /dev/null +++ b/package/lib/module/skia/SkiaCameraCanvas.js.map @@ -0,0 +1 @@ +{"version":3,"names":["React","useCallback","useState","ReanimatedProxy","SkiaProxy","SkiaCameraCanvasImpl","offscreenTextures","resizeMode","children","props","texture","useSharedValue","width","setWidth","height","setHeight","useFrameCallback","latestTexture","value","pop","dispose","onLayout","nativeEvent","layout","Math","round","createElement","Canvas","_extends","pointerEvents","Image","x","y","fit","image","SkiaCameraCanvas","memo"],"sourceRoot":"../../../src","sources":["skia/SkiaCameraCanvas.tsx"],"mappings":";AAAA,OAAOA,KAAK,IAAIC,WAAW,EAAEC,QAAQ,QAAQ,OAAO;AAKpD,SAASC,eAAe,QAAQ,iCAAiC;AACjE,SAASC,SAAS,QAAQ,2BAA2B;AAerD,SAASC,oBAAoBA,CAAC;EAAEC,iBAAiB;EAAEC,UAAU,GAAG,OAAO;EAAEC,QAAQ;EAAE,GAAGC;AAA6B,CAAC,EAAsB;EACxI,MAAMC,OAAO,GAAGP,eAAe,CAACQ,cAAc,CAAiB,IAAI,CAAC;EACpE,MAAM,CAACC,KAAK,EAAEC,QAAQ,CAAC,GAAGX,QAAQ,CAAC,CAAC,CAAC;EACrC,MAAM,CAACY,MAAM,EAAEC,SAAS,CAAC,GAAGb,QAAQ,CAAC,CAAC,CAAC;EAEvCC,eAAe,CAACa,gBAAgB,CAAC,MAAM;IACrC,SAAS;;IAET;IACA,MAAMC,aAAa,GAAGX,iBAAiB,CAACY,KAAK,CAACC,GAAG,CAAC,CAAC;IACnD,IAAIF,aAAa,IAAI,IAAI,EAAE;MACzB;MACA;IACF;;IAEA;IACAP,OAAO,CAACQ,KAAK,EAAEE,OAAO,CAAC,CAAC;;IAExB;IACAV,OAAO,CAACQ,KAAK,GAAGD,aAAa;EAC/B,CAAC,CAAC;EAEF,MAAMI,QAAQ,GAAGpB,WAAW,CAAC,CAAC;IAAEqB,WAAW,EAAE;MAAEC;IAAO;EAAqB,CAAC,KAAK;IAC/EV,QAAQ,CAACW,IAAI,CAACC,KAAK,CAACF,MAAM,CAACX,KAAK,CAAC,CAAC;IAClCG,SAAS,CAACS,IAAI,CAACC,KAAK,CAACF,MAAM,CAACT,MAAM,CAAC,CAAC;EACtC,CAAC,EAAE,EAAE,CAAC;EAEN,oBACEd,KAAA,CAAA0B,aAAA,CAACtB,SAAS,CAACuB,MAAM,EAAAC,QAAA,KAAKnB,KAAK;IAAEY,QAAQ,EAAEA,QAAS;IAACQ,aAAa,EAAC;EAAM,IAClErB,QAAQ,eACTR,KAAA,CAAA0B,aAAA,CAACtB,SAAS,CAAC0B,KAAK;IAACC,CAAC,EAAE,CAAE;IAACC,CAAC,EAAE,CAAE;IAACpB,KAAK,EAAEA,KAAM;IAACE,MAAM,EAAEA,MAAO;IAACmB,GAAG,EAAE1B,UAAW;IAAC2B,KAAK,EAAExB;EAAQ,CAAE,CAC7E,CAAC;AAEvB;AAEA,OAAO,MAAMyB,gBAAgB,gBAAGnC,KAAK,CAACoC,IAAI,CAAC/B,oBAAoB,CAAC"} diff --git a/package/lib/module/skia/useSkiaFrameProcessor.js b/package/lib/module/skia/useSkiaFrameProcessor.js new file mode 100644 index 0000000000..44c1a5ec69 --- /dev/null +++ b/package/lib/module/skia/useSkiaFrameProcessor.js @@ -0,0 +1,310 @@ +import { useEffect, useMemo } from 'react'; +import { WorkletsProxy } from '../dependencies/WorkletsProxy'; +import { SkiaProxy } from '../dependencies/SkiaProxy'; +import { withFrameRefCounting } from '../frame-processors/withFrameRefCounting'; +import { VisionCameraProxy } from '../frame-processors/VisionCameraProxy'; + +/** + * Represents a Camera Frame that can be directly drawn to using Skia. + * + * @see {@linkcode useSkiaFrameProcessor} + * @see {@linkcode render} + */ + +function getDegrees(orientation) { + 'worklet'; + + switch (orientation) { + case 'portrait': + return 0; + case 'landscape-left': + return 90; + case 'portrait-upside-down': + return 180; + case 'landscape-right': + return 270; + } +} +function getOrientation(degrees) { + 'worklet'; + + const clamped = (degrees + 360) % 360; + if (clamped >= 315 || clamped <= 45) return 'portrait';else if (clamped >= 45 && clamped <= 135) return 'landscape-left';else if (clamped >= 135 && clamped <= 225) return 'portrait-upside-down';else if (clamped >= 225 && clamped <= 315) return 'landscape-right';else throw new Error(`Invalid degrees! ${degrees}`); +} +function relativeTo(a, b) { + 'worklet'; + + return getOrientation(getDegrees(a) - getDegrees(b)); +} + +/** + * Counter-rotates the {@linkcode canvas} by the {@linkcode frame}'s {@linkcode Frame.orientation orientation} + * to ensure the Frame will be drawn upright. + */ +function withRotatedFrame(frame, canvas, previewOrientation, func) { + 'worklet'; + + // 1. save current translation matrix + canvas.save(); + try { + // 2. properly rotate canvas so Frame is rendered up-right. + const orientation = relativeTo(frame.orientation, previewOrientation); + switch (orientation) { + case 'portrait': + // do nothing + break; + case 'landscape-left': + // rotate two flips on (0,0) origin and move X + Y into view again + canvas.translate(frame.height, frame.width); + canvas.rotate(270, 0, 0); + break; + case 'portrait-upside-down': + // rotate three flips on (0,0) origin and move Y into view again + canvas.translate(frame.width, frame.height); + canvas.rotate(180, 0, 0); + break; + case 'landscape-right': + // rotate one flip on (0,0) origin and move X into view again + canvas.translate(frame.height, 0); + canvas.rotate(90, 0, 0); + break; + default: + throw new Error(`Invalid frame.orientation: ${frame.orientation}!`); + } + + // 3. call actual processing code + func(); + } finally { + // 4. restore matrix again to original base + canvas.restore(); + } +} +/** + * Get the size of the surface that will be used for rendering, which already accounts + * for the Frame's {@linkcode Frame.orientation orientation}. + */ +function getSurfaceSize(frame) { + 'worklet'; + + switch (frame.orientation) { + case 'portrait': + case 'portrait-upside-down': + return { + width: frame.width, + height: frame.height + }; + case 'landscape-left': + case 'landscape-right': + return { + width: frame.height, + height: frame.width + }; + } +} + +/** + * Create a new Frame Processor function which you can pass to the ``. + * (See ["Frame Processors"](https://react-native-vision-camera.com/docs/guides/frame-processors)) + * + * Make sure to add the `'worklet'` directive to the top of the Frame Processor function, otherwise it will not get compiled into a worklet. + * + * Also make sure to memoize the returned object, so that the Camera doesn't reset the Frame Processor Context each time. + * + * @worklet + * @example + * ```ts + * const surfaceHolder = Worklets.createSharedValue({}) + * const offscreenTextures = Worklets.createSharedValue([]) + * const frameProcessor = createSkiaFrameProcessor((frame) => { + * 'worklet' + * const faces = scanFaces(frame) + * + * frame.render() + * for (const face of faces) { + * const rect = Skia.XYWHRect(face.x, face.y, face.width, face.height) + * frame.drawRect(rect) + * } + * }, surfaceHolder, offscreenTextures) + * ``` + */ +export function createSkiaFrameProcessor(frameProcessor, surfaceHolder, offscreenTextures, previewOrientation) { + const Skia = SkiaProxy.Skia; + const Worklets = WorkletsProxy.Worklets; + const getSkiaSurface = frame => { + 'worklet'; + + // 1. The Frame Processor runs on an iOS `DispatchQueue`, which might use + // multiple C++ Threads between runs (it's still serial though - not concurrent!) + // 2. react-native-skia uses `thread_local` Skia Contexts (`GrDirectContext`), + // which means if a new Thread calls a Skia method, it also uses a new + // Skia Context. + // + // This will cause issues if we cache the `SkSurface` between renders, + // as the next render might be on a different C++ Thread. + // When the next render uses a different C++ Thread, it will also use a + // different Skia Context (`GrDirectContext`) for creating the SkImage, + // than the one used for creating the `SkSurface` in the first render. + // This will cause the render to fail, as an SkImage can only be rendered + // to an SkSurface if both were created on the same Skia Context. + // To prevent this, we cache the SkSurface on a per-thread basis, + // so in my tests the DispatchQueue uses up to 10 different Threads, + // causing 10 different Surfaces to exist in memory. + // A true workaround would be to expose Skia Contexts to JS in RN Skia, + // but for now this is fine. + const threadId = Worklets.getCurrentThreadId(); + const size = getSurfaceSize(frame); + if (surfaceHolder.value[threadId] == null || surfaceHolder.value[threadId]?.width !== size.width || surfaceHolder.value[threadId]?.height !== size.height) { + const surface = Skia.Surface.MakeOffscreen(size.width, size.height); + if (surface == null) { + // skia surface couldn't be allocated + throw new Error(`Failed to create ${size.width}x${size.height} Skia Surface!`); + } + surfaceHolder.value[threadId]?.surface.dispose(); + delete surfaceHolder.value[threadId]; + surfaceHolder.value[threadId] = { + surface: surface, + width: size.width, + height: size.height + }; + } + const surface = surfaceHolder.value[threadId]?.surface; + if (surface == null) throw new Error(`Couldn't find Surface in Thread-cache! ID: ${threadId}`); + return surface; + }; + const createDrawableProxy = (frame, canvas) => { + 'worklet'; + + // Convert Frame to SkImage/Texture + const nativeBuffer = frame.getNativeBuffer(); + const image = Skia.Image.MakeImageFromNativeBuffer(nativeBuffer.pointer); + + // Creates a `Proxy` that holds the SkCanvas, but also adds additional methods such as render() and dispose(). + const canvasProxy = new Proxy(canvas, { + get(_, property) { + switch (property) { + case '__skImage': + return image; + case 'render': + return paint => { + 'worklet'; + + if (paint != null) canvas.drawImage(image, 0, 0, paint);else canvas.drawImage(image, 0, 0); + }; + case 'dispose': + return () => { + 'worklet'; + + // dispose the Frame and the SkImage/Texture + image.dispose(); + nativeBuffer.delete(); + }; + } + return canvas[property]; + } + }); + return frame.withBaseClass(canvasProxy); + }; + return { + frameProcessor: withFrameRefCounting(frame => { + 'worklet'; + + // 1. Set up Skia Surface with size of Frame + const surface = getSkiaSurface(frame); + + // 2. Create DrawableFrame proxy which internally creates an SkImage/Texture + const canvas = surface.getCanvas(); + const drawableFrame = createDrawableProxy(frame, canvas); + try { + // 3. Clear the current Canvas + const black = Skia.Color('black'); + canvas.clear(black); + + // 4. rotate the frame properly to make sure it's upright + withRotatedFrame(frame, canvas, previewOrientation.value, () => { + // 5. Run any user drawing operations + frameProcessor(drawableFrame); + }); + + // 6. Flush draw operations and submit to GPU + surface.flush(); + } finally { + // 7. Delete the SkImage/Texture that holds the Frame + drawableFrame.dispose(); + } + + // 8. Capture rendered results as a Texture/SkImage to later render to screen + const snapshot = surface.makeImageSnapshot(); + const snapshotCopy = snapshot.makeNonTextureImage(); + snapshot.dispose(); + offscreenTextures.value.push(snapshotCopy); + + // 9. Close old textures that are still in the queue. + while (offscreenTextures.value.length > 1) { + // shift() atomically removes the first element, and is therefore thread-safe. + const texture = offscreenTextures.value.shift(); + if (texture == null) break; + texture.dispose(); + } + }), + type: 'drawable-skia', + offscreenTextures: offscreenTextures, + previewOrientation: previewOrientation + }; +} + +/** + * Returns a memoized Skia Frame Processor function wich you can pass to the ``. + * + * The Skia Frame Processor alows you to draw ontop of the Frame, and will manage it's internal offscreen Skia Canvas + * and onscreen Skia preview view. + * + * (See ["Frame Processors"](https://react-native-vision-camera.com/docs/guides/frame-processors)) + * + * Make sure to add the `'worklet'` directive to the top of the Frame Processor function, otherwise it will not get compiled into a worklet. + * + * @worklet + * @param frameProcessor The Frame Processor + * @param dependencies The React dependencies which will be copied into the VisionCamera JS-Runtime. + * @returns The memoized Skia Frame Processor. + * @example + * ```ts + * const frameProcessor = useSkiaFrameProcessor((frame) => { + * 'worklet' + * const faces = scanFaces(frame) + * + * frame.render() + * for (const face of faces) { + * const rect = Skia.XYWHRect(face.x, face.y, face.width, face.height) + * frame.drawRect(rect) + * } + * }, []) + * ``` + */ +export function useSkiaFrameProcessor(frameProcessor, dependencies) { + const surface = WorkletsProxy.useSharedValue({}); + const offscreenTextures = WorkletsProxy.useSharedValue([]); + const previewOrientation = WorkletsProxy.useSharedValue('portrait'); + useEffect(() => { + return () => { + // on unmount, we clean up the resources on the Worklet Context. + // this causes it to run _after_ the Frame Processor has finished executing, + // if it is currently executing - so we avoid race conditions here. + VisionCameraProxy.workletContext?.runAsync(() => { + 'worklet'; + + const surfaces = Object.values(surface.value).map(v => v.surface); + surface.value = {}; + surfaces.forEach(s => s.dispose()); + while (offscreenTextures.value.length > 0) { + const texture = offscreenTextures.value.shift(); + if (texture == null) break; + texture.dispose(); + } + }); + }; + }, [offscreenTextures, surface]); + return useMemo(() => createSkiaFrameProcessor(frameProcessor, surface, offscreenTextures, previewOrientation), + // eslint-disable-next-line react-hooks/exhaustive-deps + dependencies); +} +//# sourceMappingURL=useSkiaFrameProcessor.js.map \ No newline at end of file diff --git a/package/lib/module/skia/useSkiaFrameProcessor.js.map b/package/lib/module/skia/useSkiaFrameProcessor.js.map new file mode 100644 index 0000000000..b0455426aa --- /dev/null +++ b/package/lib/module/skia/useSkiaFrameProcessor.js.map @@ -0,0 +1 @@ +{"version":3,"names":["useEffect","useMemo","WorkletsProxy","SkiaProxy","withFrameRefCounting","VisionCameraProxy","getDegrees","orientation","getOrientation","degrees","clamped","Error","relativeTo","a","b","withRotatedFrame","frame","canvas","previewOrientation","func","save","translate","height","width","rotate","restore","getSurfaceSize","createSkiaFrameProcessor","frameProcessor","surfaceHolder","offscreenTextures","Skia","Worklets","getSkiaSurface","threadId","getCurrentThreadId","size","value","surface","Surface","MakeOffscreen","dispose","createDrawableProxy","nativeBuffer","getNativeBuffer","image","Image","MakeImageFromNativeBuffer","pointer","canvasProxy","Proxy","get","_","property","paint","drawImage","delete","withBaseClass","getCanvas","drawableFrame","black","Color","clear","flush","snapshot","makeImageSnapshot","snapshotCopy","makeNonTextureImage","push","length","texture","shift","type","useSkiaFrameProcessor","dependencies","useSharedValue","workletContext","runAsync","surfaces","Object","values","map","v","forEach","s"],"sourceRoot":"../../../src","sources":["skia/useSkiaFrameProcessor.ts"],"mappings":"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"} diff --git a/package/lib/module/types/CameraDevice.js b/package/lib/module/types/CameraDevice.js new file mode 100644 index 0000000000..02069c9065 --- /dev/null +++ b/package/lib/module/types/CameraDevice.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=CameraDevice.js.map \ No newline at end of file diff --git a/package/lib/module/types/CameraDevice.js.map b/package/lib/module/types/CameraDevice.js.map new file mode 100644 index 0000000000..3fe41bde9d --- /dev/null +++ b/package/lib/module/types/CameraDevice.js.map @@ -0,0 +1 @@ +{"version":3,"names":[],"sourceRoot":"../../../src","sources":["types/CameraDevice.ts"],"mappings":""} diff --git a/package/lib/module/types/CameraProps.js b/package/lib/module/types/CameraProps.js new file mode 100644 index 0000000000..0a6c20fc45 --- /dev/null +++ b/package/lib/module/types/CameraProps.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=CameraProps.js.map \ No newline at end of file diff --git a/package/lib/module/types/CameraProps.js.map b/package/lib/module/types/CameraProps.js.map new file mode 100644 index 0000000000..806ac28929 --- /dev/null +++ b/package/lib/module/types/CameraProps.js.map @@ -0,0 +1 @@ +{"version":3,"names":[],"sourceRoot":"../../../src","sources":["types/CameraProps.ts"],"mappings":""} diff --git a/package/lib/module/types/CodeScanner.js b/package/lib/module/types/CodeScanner.js new file mode 100644 index 0000000000..2c9bdeaa2a --- /dev/null +++ b/package/lib/module/types/CodeScanner.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=CodeScanner.js.map \ No newline at end of file diff --git a/package/lib/module/types/CodeScanner.js.map b/package/lib/module/types/CodeScanner.js.map new file mode 100644 index 0000000000..0d8321e0f3 --- /dev/null +++ b/package/lib/module/types/CodeScanner.js.map @@ -0,0 +1 @@ +{"version":3,"names":[],"sourceRoot":"../../../src","sources":["types/CodeScanner.ts"],"mappings":""} diff --git a/package/lib/module/types/Frame.js b/package/lib/module/types/Frame.js new file mode 100644 index 0000000000..cae95851f5 --- /dev/null +++ b/package/lib/module/types/Frame.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=Frame.js.map \ No newline at end of file diff --git a/package/lib/module/types/Frame.js.map b/package/lib/module/types/Frame.js.map new file mode 100644 index 0000000000..ef9b29c008 --- /dev/null +++ b/package/lib/module/types/Frame.js.map @@ -0,0 +1 @@ +{"version":3,"names":[],"sourceRoot":"../../../src","sources":["types/Frame.ts"],"mappings":""} diff --git a/package/lib/module/types/Orientation.js b/package/lib/module/types/Orientation.js new file mode 100644 index 0000000000..c0c25066ce --- /dev/null +++ b/package/lib/module/types/Orientation.js @@ -0,0 +1,2 @@ + +//# sourceMappingURL=Orientation.js.map \ No newline at end of file diff --git a/package/lib/module/types/Orientation.js.map b/package/lib/module/types/Orientation.js.map new file mode 100644 index 0000000000..300dc6eef9 --- /dev/null +++ b/package/lib/module/types/Orientation.js.map @@ -0,0 +1 @@ +{"version":3,"names":[],"sourceRoot":"../../../src","sources":["types/Orientation.ts"],"mappings":""} diff --git a/package/lib/module/types/OutputOrientation.js b/package/lib/module/types/OutputOrientation.js new file mode 100644 index 0000000000..aa14e4e0f9 --- /dev/null +++ b/package/lib/module/types/OutputOrientation.js @@ -0,0 +1,2 @@ + +//# sourceMappingURL=OutputOrientation.js.map \ No newline at end of file diff --git a/package/lib/module/types/OutputOrientation.js.map b/package/lib/module/types/OutputOrientation.js.map new file mode 100644 index 0000000000..65e6a56734 --- /dev/null +++ b/package/lib/module/types/OutputOrientation.js.map @@ -0,0 +1 @@ +{"version":3,"names":[],"sourceRoot":"../../../src","sources":["types/OutputOrientation.ts"],"mappings":""} diff --git a/package/lib/module/types/PhotoFile.js b/package/lib/module/types/PhotoFile.js new file mode 100644 index 0000000000..f43b7c1a9b --- /dev/null +++ b/package/lib/module/types/PhotoFile.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=PhotoFile.js.map \ No newline at end of file diff --git a/package/lib/module/types/PhotoFile.js.map b/package/lib/module/types/PhotoFile.js.map new file mode 100644 index 0000000000..aff0304f5a --- /dev/null +++ b/package/lib/module/types/PhotoFile.js.map @@ -0,0 +1 @@ +{"version":3,"names":[],"sourceRoot":"../../../src","sources":["types/PhotoFile.ts"],"mappings":""} diff --git a/package/lib/module/types/PixelFormat.js b/package/lib/module/types/PixelFormat.js new file mode 100644 index 0000000000..e4b466dcc2 --- /dev/null +++ b/package/lib/module/types/PixelFormat.js @@ -0,0 +1,2 @@ + +//# sourceMappingURL=PixelFormat.js.map \ No newline at end of file diff --git a/package/lib/module/types/PixelFormat.js.map b/package/lib/module/types/PixelFormat.js.map new file mode 100644 index 0000000000..0ce5129416 --- /dev/null +++ b/package/lib/module/types/PixelFormat.js.map @@ -0,0 +1 @@ +{"version":3,"names":[],"sourceRoot":"../../../src","sources":["types/PixelFormat.ts"],"mappings":""} diff --git a/package/lib/module/types/Point.js b/package/lib/module/types/Point.js new file mode 100644 index 0000000000..cedbe97390 --- /dev/null +++ b/package/lib/module/types/Point.js @@ -0,0 +1,2 @@ + +//# sourceMappingURL=Point.js.map \ No newline at end of file diff --git a/package/lib/module/types/Point.js.map b/package/lib/module/types/Point.js.map new file mode 100644 index 0000000000..baa69dec46 --- /dev/null +++ b/package/lib/module/types/Point.js.map @@ -0,0 +1 @@ +{"version":3,"names":[],"sourceRoot":"../../../src","sources":["types/Point.ts"],"mappings":""} diff --git a/package/lib/module/types/Snapshot.js b/package/lib/module/types/Snapshot.js new file mode 100644 index 0000000000..54209cb109 --- /dev/null +++ b/package/lib/module/types/Snapshot.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=Snapshot.js.map \ No newline at end of file diff --git a/package/lib/module/types/Snapshot.js.map b/package/lib/module/types/Snapshot.js.map new file mode 100644 index 0000000000..7c051279f5 --- /dev/null +++ b/package/lib/module/types/Snapshot.js.map @@ -0,0 +1 @@ +{"version":3,"names":[],"sourceRoot":"../../../src","sources":["types/Snapshot.ts"],"mappings":""} diff --git a/package/lib/module/types/TemporaryFile.js b/package/lib/module/types/TemporaryFile.js new file mode 100644 index 0000000000..dc810fe002 --- /dev/null +++ b/package/lib/module/types/TemporaryFile.js @@ -0,0 +1,2 @@ + +//# sourceMappingURL=TemporaryFile.js.map \ No newline at end of file diff --git a/package/lib/module/types/TemporaryFile.js.map b/package/lib/module/types/TemporaryFile.js.map new file mode 100644 index 0000000000..2383b61ab8 --- /dev/null +++ b/package/lib/module/types/TemporaryFile.js.map @@ -0,0 +1 @@ +{"version":3,"names":[],"sourceRoot":"../../../src","sources":["types/TemporaryFile.ts"],"mappings":""} diff --git a/package/lib/module/types/VideoFile.js b/package/lib/module/types/VideoFile.js new file mode 100644 index 0000000000..c4ab5b0d67 --- /dev/null +++ b/package/lib/module/types/VideoFile.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=VideoFile.js.map \ No newline at end of file diff --git a/package/lib/module/types/VideoFile.js.map b/package/lib/module/types/VideoFile.js.map new file mode 100644 index 0000000000..d437623ef9 --- /dev/null +++ b/package/lib/module/types/VideoFile.js.map @@ -0,0 +1 @@ +{"version":3,"names":[],"sourceRoot":"../../../src","sources":["types/VideoFile.ts"],"mappings":""} diff --git a/package/lib/typescript/Camera.d.ts b/package/lib/typescript/Camera.d.ts new file mode 100644 index 0000000000..ea3772baa3 --- /dev/null +++ b/package/lib/typescript/Camera.d.ts @@ -0,0 +1,326 @@ +import React from 'react'; +import type { CameraDevice } from './types/CameraDevice'; +import type { CameraProps } from './types/CameraProps'; +import type { PhotoFile, TakePhotoOptions } from './types/PhotoFile'; +import type { Point } from './types/Point'; +import type { RecordVideoOptions } from './types/VideoFile'; +import type { EmitterSubscription } from 'react-native'; +import type { TakeSnapshotOptions } from './types/Snapshot'; +export type CameraPermissionStatus = 'granted' | 'not-determined' | 'denied' | 'restricted'; +export type CameraPermissionRequestResult = 'granted' | 'denied'; +interface CameraState { + isRecordingWithFlash: boolean; + averageFpsSamples: number[]; +} +/** + * ### A powerful `` component. + * + * Read the [VisionCamera documentation](https://react-native-vision-camera.com/) for more information. + * + * The `` component's most important properties are: + * + * * {@linkcode CameraProps.device | device}: Specifies the {@linkcode CameraDevice} to use. Get a {@linkcode CameraDevice} by using + * the {@linkcode useCameraDevice | useCameraDevice(..)} hook, or manually by using + * the {@linkcode CameraDevices.getAvailableCameraDevices | CameraDevices.getAvailableCameraDevices()} function. + * * {@linkcode CameraProps.isActive | isActive}: A boolean value that specifies whether the Camera should + * actively stream video frames or not. This can be compared to a Video component, where `isActive` specifies whether the video + * is paused or not. If you fully unmount the `` component instead of using `isActive={false}`, the Camera will take a bit longer to start again. + * + * @example + * ```tsx + * function App() { + * const device = useCameraDevice('back') + * + * if (device == null) return + * return ( + * + * ) + * } + * ``` + * + * @component + */ +export declare class Camera extends React.PureComponent { + /** @internal */ + static displayName: string; + /** @internal */ + displayName: string; + private lastFrameProcessor; + private isNativeViewMounted; + private lastUIRotation; + private rotationHelper; + private readonly ref; + /** @internal */ + constructor(props: CameraProps); + private get handle(); + /** + * Take a single photo and write it's content to a temporary file. + * + * @throws {@linkcode CameraCaptureError} When any kind of error occured while capturing the photo. + * Use the {@linkcode CameraCaptureError.code | code} property to get the actual error + * @example + * ```ts + * const photo = await camera.current.takePhoto({ + * flash: 'on', + * enableAutoRedEyeReduction: true + * }) + * ``` + */ + takePhoto(options?: TakePhotoOptions): Promise; + /** + * Captures a snapshot of the Camera view and write it's content to a temporary file. + * + * - On iOS, `takeSnapshot` waits for a Frame from the video pipeline and therefore requires `video` to be enabled. + * - On Android, `takeSnapshot` performs a GPU view screenshot from the preview view. + * + * @throws {@linkcode CameraCaptureError} When any kind of error occured while capturing the photo. + * Use the {@linkcode CameraCaptureError.code | code} property to get the actual error + * @example + * ```ts + * const snapshot = await camera.current.takeSnapshot({ + * quality: 100 + * }) + * ``` + */ + takeSnapshot(options?: TakeSnapshotOptions): Promise; + private getBitRateMultiplier; + /** + * Start a new video recording. + * + * @throws {@linkcode CameraCaptureError} When any kind of error occured while starting the video recording. + * Use the {@linkcode CameraCaptureError.code | code} property to get the actual error + * + * @example + * ```ts + * camera.current.startRecording({ + * onRecordingFinished: (video) => console.log(video), + * onRecordingError: (error) => console.error(error), + * }) + * setTimeout(() => { + * camera.current.stopRecording() + * }, 5000) + * ``` + */ + startRecording(options: RecordVideoOptions): void; + /** + * Pauses the current video recording. + * + * @throws {@linkcode CameraCaptureError} When any kind of error occured while pausing the video recording. + * Use the {@linkcode CameraCaptureError.code | code} property to get the actual error + * + * @example + * ```ts + * // Start + * await camera.current.startRecording({ + * onRecordingFinished: (video) => console.log(video), + * onRecordingError: (error) => console.error(error), + * }) + * await timeout(1000) + * // Pause + * await camera.current.pauseRecording() + * await timeout(500) + * // Resume + * await camera.current.resumeRecording() + * await timeout(2000) + * // Stop + * await camera.current.stopRecording() + * ``` + */ + pauseRecording(): Promise; + /** + * Resumes a currently paused video recording. + * + * @throws {@linkcode CameraCaptureError} When any kind of error occured while resuming the video recording. + * Use the {@linkcode CameraCaptureError.code | code} property to get the actual error + * + * @example + * ```ts + * // Start + * await camera.current.startRecording({ + * onRecordingFinished: (video) => console.log(video), + * onRecordingError: (error) => console.error(error), + * }) + * await timeout(1000) + * // Pause + * await camera.current.pauseRecording() + * await timeout(500) + * // Resume + * await camera.current.resumeRecording() + * await timeout(2000) + * // Stop + * await camera.current.stopRecording() + * ``` + */ + resumeRecording(): Promise; + /** + * Stop the current video recording. + * + * @throws {@linkcode CameraCaptureError} When any kind of error occured while stopping the video recording. + * Use the {@linkcode CameraCaptureError.code | code} property to get the actual error + * + * @example + * ```ts + * await camera.current.startRecording({ + * onRecordingFinished: (video) => console.log(video), + * onRecordingError: (error) => console.error(error), + * }) + * setTimeout(async () => { + * await camera.current.stopRecording() + * }, 5000) + * ``` + */ + stopRecording(): Promise; + /** + * Cancel the current video recording. The temporary video file will be deleted, + * and the `startRecording`'s `onRecordingError` callback will be invoked with a `capture/recording-canceled` error. + * + * @throws {@linkcode CameraCaptureError} When any kind of error occured while canceling the video recording. + * Use the {@linkcode CameraCaptureError.code | code} property to get the actual error + * + * @example + * ```ts + * await camera.current.startRecording({ + * onRecordingFinished: (video) => console.log(video), + * onRecordingError: (error) => { + * if (error.code === 'capture/recording-canceled') { + * // recording was canceled. + * } else { + * console.error(error) + * } + * }, + * }) + * setTimeout(async () => { + * await camera.current.cancelRecording() + * }, 5000) + * ``` + */ + cancelRecording(): Promise; + /** + * Focus the camera to a specific point in the coordinate system. + * @param {Point} point The point to focus to. This should be relative + * to the Camera view's coordinate system and is expressed in points. + * * `(0, 0)` means **top left**. + * * `(CameraView.width, CameraView.height)` means **bottom right**. + * + * Make sure the value doesn't exceed the CameraView's dimensions. + * + * @throws {@linkcode CameraRuntimeError} When any kind of error occured while focussing. + * Use the {@linkcode CameraRuntimeError.code | code} property to get the actual error + * @example + * ```ts + * await camera.current.focus({ + * x: tapEvent.x, + * y: tapEvent.y + * }) + * ``` + */ + focus(point: Point): Promise; + lockFocusAndExposureToPoint(point: Point): Promise; + freeFocusAndExposure(): Promise; + /** + * Get a list of all available camera devices on the current phone. + * + * If you use Hooks, use the `useCameraDevices(..)` hook instead. + * + * * For Camera Devices attached to the phone, it is safe to assume that this will never change. + * * For external Camera Devices (USB cameras, Mac continuity cameras, etc.) the available Camera Devices + * could change over time when the external Camera device gets plugged in or plugged out, so + * use {@link addCameraDevicesChangedListener | addCameraDevicesChangedListener(...)} to listen for such changes. + * + * @example + * ```ts + * const devices = Camera.getAvailableCameraDevices() + * const backCameras = devices.filter((d) => d.position === "back") + * const frontCameras = devices.filter((d) => d.position === "front") + * ``` + */ + static getAvailableCameraDevices(): CameraDevice[]; + /** + * Adds a listener that gets called everytime the Camera Devices change, for example + * when an external Camera Device (USB or continuity Camera) gets plugged in or plugged out. + * + * If you use Hooks, use the `useCameraDevices()` hook instead. + */ + static addCameraDevicesChangedListener(listener: (newDevices: CameraDevice[]) => void): EmitterSubscription; + /** + * Gets the current Camera Permission Status. Check this before mounting the Camera to ensure + * the user has permitted the app to use the camera. + * + * To actually prompt the user for camera permission, use {@linkcode Camera.requestCameraPermission | requestCameraPermission()}. + */ + static getCameraPermissionStatus(): CameraPermissionStatus; + /** + * Gets the current Microphone-Recording Permission Status. + * Check this before enabling the `audio={...}` property to make sure the + * user has permitted the app to use the microphone. + * + * To actually prompt the user for microphone permission, use {@linkcode Camera.requestMicrophonePermission | requestMicrophonePermission()}. + */ + static getMicrophonePermissionStatus(): CameraPermissionStatus; + /** + * Gets the current Location Permission Status. + * Check this before enabling the `location={...}` property to make sure the + * the user has permitted the app to use the location. + * + * To actually prompt the user for location permission, use {@linkcode Camera.requestLocationPermission | requestLocationPermission()}. + * + * Note: This method will throw a `system/location-not-enabled` error if the Location APIs are not enabled at build-time. + * See [the "GPS Location Tags" documentation](https://react-native-vision-camera.com/docs/guides/location) for more information. + */ + static getLocationPermissionStatus(): CameraPermissionStatus; + /** + * Shows a "request permission" alert to the user, and resolves with the new camera permission status. + * + * If the user has previously blocked the app from using the camera, the alert will not be shown + * and `"denied"` will be returned. + * + * @throws {@linkcode CameraRuntimeError} When any kind of error occured while requesting permission. + * Use the {@linkcode CameraRuntimeError.code | code} property to get the actual error + */ + static requestCameraPermission(): Promise; + /** + * Shows a "request permission" alert to the user, and resolves with the new microphone permission status. + * + * If the user has previously blocked the app from using the microphone, the alert will not be shown + * and `"denied"` will be returned. + * + * @throws {@linkcode CameraRuntimeError} When any kind of error occured while requesting permission. + * Use the {@linkcode CameraRuntimeError.code | code} property to get the actual error + */ + static requestMicrophonePermission(): Promise; + /** + * Shows a "request permission" alert to the user, and resolves with the new location permission status. + * + * If the user has previously blocked the app from using the location, the alert will not be shown + * and `"denied"` will be returned. + * + * @throws {@linkcode CameraRuntimeError} When any kind of error occured while requesting permission. + * Use the {@linkcode CameraRuntimeError.code | code} property to get the actual error + */ + static requestLocationPermission(): Promise; + private onError; + private onInitialized; + private onStarted; + private onStopped; + private onPreviewStarted; + private onPreviewStopped; + private onShutter; + private onOutputOrientationChanged; + private onPreviewOrientationChanged; + private maybeUpdateUIRotation; + private onCodeScanned; + private setFrameProcessor; + private unsetFrameProcessor; + private onViewReady; + private onAverageFpsChanged; + /** @internal */ + componentDidUpdate(): void; + /** @internal */ + render(): React.ReactNode; +} +export {}; +//# sourceMappingURL=Camera.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/Camera.d.ts.map b/package/lib/typescript/Camera.d.ts.map new file mode 100644 index 0000000000..c8a1267b62 --- /dev/null +++ b/package/lib/typescript/Camera.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Camera.d.ts","sourceRoot":"","sources":["../../src/Camera.tsx"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/package/lib/typescript/CameraDevices.d.ts b/package/lib/typescript/CameraDevices.d.ts new file mode 100644 index 0000000000..34dd0d79f3 --- /dev/null +++ b/package/lib/typescript/CameraDevices.d.ts @@ -0,0 +1,7 @@ +import type { CameraDevice } from './types/CameraDevice'; +export declare const CameraDevices: { + userPreferredCameraDevice: CameraDevice | undefined; + getAvailableCameraDevices: () => CameraDevice[]; + addCameraDevicesChangedListener: (callback: (newDevices: CameraDevice[]) => void) => import("react-native").EmitterSubscription; +}; +//# sourceMappingURL=CameraDevices.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/CameraDevices.d.ts.map b/package/lib/typescript/CameraDevices.d.ts.map new file mode 100644 index 0000000000..49de6d547a --- /dev/null +++ b/package/lib/typescript/CameraDevices.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"CameraDevices.d.ts","sourceRoot":"","sources":["../../src/CameraDevices.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAmBxD,eAAO,MAAM,aAAa;;;6DAGiC,YAAY,EAAE,KAAK,IAAI;CAGjF,CAAA"} \ No newline at end of file diff --git a/package/lib/typescript/CameraError.d.ts b/package/lib/typescript/CameraError.d.ts new file mode 100644 index 0000000000..d45f329011 --- /dev/null +++ b/package/lib/typescript/CameraError.d.ts @@ -0,0 +1,102 @@ +export type PermissionError = 'permission/microphone-permission-denied' | 'permission/camera-permission-denied'; +export type ParameterError = 'parameter/invalid-parameter' | 'parameter/unsupported-output' | 'parameter/unsupported-input' | 'parameter/invalid-combination'; +export type DeviceError = 'device/configuration-error' | 'device/no-device' | 'device/invalid-device' | 'device/microphone-unavailable' | 'device/pixel-format-not-supported' | 'device/low-light-boost-not-supported' | 'device/focus-not-supported' | 'device/camera-not-available-on-simulator' | 'device/camera-already-in-use'; +export type FormatError = 'format/invalid-fps' | 'format/invalid-video-hdr' | 'format/photo-hdr-and-video-hdr-not-suppoted-simultaneously' | 'format/low-light-boost-not-supported-with-hdr' | 'format/invalid-video-stabilization-mode' | 'format/incompatible-pixel-format-with-hdr-setting' | 'format/invalid-format' | 'format/format-required'; +export type SessionError = 'session/camera-not-ready' | 'session/audio-in-use-by-other-app' | 'session/no-outputs' | 'session/audio-session-failed-to-activate' | 'session/hardware-cost-too-high' | 'session/invalid-output-configuration'; +export type CodeScannerError = 'code-scanner/not-compatible-with-outputs' | 'code-scanner/code-type-not-supported' | 'code-scanner/cannot-load-model'; +export type CaptureError = 'capture/recording-in-progress' | 'capture/recording-canceled' | 'capture/no-recording-in-progress' | 'capture/file-io-error' | 'capture/invalid-path' | 'capture/create-temp-file-error' | 'capture/create-recorder-error' | 'capture/insufficient-storage' | 'capture/video-not-enabled' | 'capture/photo-not-enabled' | 'capture/frame-invalid' | 'capture/no-data' | 'capture/recorder-error' | 'capture/focus-canceled' | 'capture/focus-requires-preview' | 'capture/timed-out' | 'capture/snapshot-failed' | 'capture/snapshot-failed-preview-not-enabled' | 'capture/image-data-access-error' | 'capture/encoder-error' | 'capture/invalid-image-type' | 'capture/failed-writing-metadata' | 'capture/unknown'; +export type SystemError = 'system/camera-module-not-found' | 'system/camera-is-restricted' | 'system/location-not-enabled' | 'system/no-camera-manager' | 'system/frame-processors-unavailable' | 'system/recording-while-frame-processing-unavailable' | 'system/view-not-found' | 'system/max-cameras-in-use' | 'system/do-not-disturb-bug'; +export type UnknownError = 'unknown/unknown'; +/** + * Represents a JSON-style error cause. This contains native `NSError`/`Throwable` information, and can have recursive {@linkcode ErrorWithCause.cause | .cause} properties until the ultimate cause has been found. + */ +export interface ErrorWithCause { + /** + * The native error's code. + * + * * iOS: `NSError.code` + * * Android: N/A + */ + code?: number; + /** + * The native error's domain. + * + * * iOS: `NSError.domain` + * * Android: N/A + */ + domain?: string; + /** + * The native error description + * + * * iOS: `NSError.message` + * * Android: `Throwable.message` + */ + message: string; + /** + * Optional additional details + * + * * iOS: `NSError.userInfo` + * * Android: N/A + */ + details?: Record; + /** + * Optional Java stacktrace + * + * * iOS: N/A + * * Android: `Throwable.stacktrace.toString()` + */ + stacktrace?: string; + /** + * Optional additional cause for nested errors + * + * * iOS: N/A + * * Android: `Throwable.cause` + */ + cause?: ErrorWithCause; +} +type CameraErrorCode = PermissionError | ParameterError | DeviceError | FormatError | SessionError | CaptureError | SystemError | UnknownError; +/** + * Represents any kind of error that occured in the {@linkcode Camera} View Module. + */ +declare class CameraError extends Error { + private readonly _code; + private readonly _message; + private readonly _cause?; + get code(): TCode; + get message(): string; + get cause(): Error | undefined; + /** + * @internal + */ + constructor(code: TCode, message: string, cause?: ErrorWithCause); + toString(): string; +} +/** + * Represents any kind of error that occured while trying to capture a video or photo. + * + * See the ["Camera Errors" documentation](https://react-native-vision-camera.com/docs/guides/errors) for more information about Camera Errors. + */ +export declare class CameraCaptureError extends CameraError { +} +/** + * Represents any kind of error that occured in the Camera View Module. + * + * See the ["Camera Errors" documentation](https://react-native-vision-camera.com/docs/guides/errors) for more information about Camera Errors. + */ +export declare class CameraRuntimeError extends CameraError { +} +/** + * Checks if the given `error` is of type {@linkcode ErrorWithCause} + * @param {unknown} error Any unknown object to validate + * @returns `true` if the given `error` is of type {@linkcode ErrorWithCause} + */ +export declare const isErrorWithCause: (error: unknown) => error is ErrorWithCause; +/** + * Tries to parse an error coming from native to a typed JS camera error. + * @param {CameraError} nativeError The native error instance. This is a JSON in the legacy native module architecture. + * @returns A {@linkcode CameraRuntimeError} or {@linkcode CameraCaptureError}, or the `nativeError` itself if it's not parsable + * @method + */ +export declare const tryParseNativeCameraError: (nativeError: T) => CameraCaptureError | CameraRuntimeError | T; +export {}; +//# sourceMappingURL=CameraError.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/CameraError.d.ts.map b/package/lib/typescript/CameraError.d.ts.map new file mode 100644 index 0000000000..6043ed2af1 --- /dev/null +++ b/package/lib/typescript/CameraError.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"CameraError.d.ts","sourceRoot":"","sources":["../../src/CameraError.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/package/lib/typescript/FpsGraph.d.ts b/package/lib/typescript/FpsGraph.d.ts new file mode 100644 index 0000000000..6941946c94 --- /dev/null +++ b/package/lib/typescript/FpsGraph.d.ts @@ -0,0 +1,16 @@ +import React from 'react'; +import type { ViewProps } from 'react-native'; +interface Props extends ViewProps { + /** + * The current average FPS samples over time. One sample should be 1 second + */ + averageFpsSamples: number[]; + /** + * The target FPS rate + */ + targetMaxFps: number; +} +export declare const MAX_BARS = 30; +export declare function FpsGraph({ averageFpsSamples, targetMaxFps, style, ...props }: Props): React.ReactElement; +export {}; +//# sourceMappingURL=FpsGraph.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/FpsGraph.d.ts.map b/package/lib/typescript/FpsGraph.d.ts.map new file mode 100644 index 0000000000..3604e4bf82 --- /dev/null +++ b/package/lib/typescript/FpsGraph.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"FpsGraph.d.ts","sourceRoot":"","sources":["../../src/FpsGraph.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkB,MAAM,OAAO,CAAA;AACtC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAI7C,UAAU,KAAM,SAAQ,SAAS;IAC/B;;OAEG;IACH,iBAAiB,EAAE,MAAM,EAAE,CAAA;IAC3B;;OAEG;IACH,YAAY,EAAE,MAAM,CAAA;CACrB;AAED,eAAO,MAAM,QAAQ,KAAK,CAAA;AAM1B,wBAAgB,QAAQ,CAAC,EAAE,iBAAiB,EAAE,YAAY,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,GAAG,KAAK,CAAC,YAAY,CAwBxG"} \ No newline at end of file diff --git a/package/lib/typescript/JSIHelper.d.ts b/package/lib/typescript/JSIHelper.d.ts new file mode 100644 index 0000000000..9f94ec192e --- /dev/null +++ b/package/lib/typescript/JSIHelper.d.ts @@ -0,0 +1,2 @@ +export declare function assertJSIAvailable(): void; +//# sourceMappingURL=JSIHelper.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/JSIHelper.d.ts.map b/package/lib/typescript/JSIHelper.d.ts.map new file mode 100644 index 0000000000..58ae6b55b1 --- /dev/null +++ b/package/lib/typescript/JSIHelper.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"JSIHelper.d.ts","sourceRoot":"","sources":["../../src/JSIHelper.ts"],"names":[],"mappings":"AAEA,wBAAgB,kBAAkB,IAAI,IAAI,CASzC"} \ No newline at end of file diff --git a/package/lib/typescript/NativeCameraModule.d.ts b/package/lib/typescript/NativeCameraModule.d.ts new file mode 100644 index 0000000000..929806aa8d --- /dev/null +++ b/package/lib/typescript/NativeCameraModule.d.ts @@ -0,0 +1,2 @@ +export declare const CameraModule: any; +//# sourceMappingURL=NativeCameraModule.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/NativeCameraModule.d.ts.map b/package/lib/typescript/NativeCameraModule.d.ts.map new file mode 100644 index 0000000000..a92c41e8f0 --- /dev/null +++ b/package/lib/typescript/NativeCameraModule.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"NativeCameraModule.d.ts","sourceRoot":"","sources":["../../src/NativeCameraModule.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,YAAY,KAA2B,CAAA"} \ No newline at end of file diff --git a/package/lib/typescript/NativeCameraView.d.ts b/package/lib/typescript/NativeCameraView.d.ts new file mode 100644 index 0000000000..6223494da0 --- /dev/null +++ b/package/lib/typescript/NativeCameraView.d.ts @@ -0,0 +1,44 @@ +import type { NativeSyntheticEvent } from 'react-native'; +import type { ErrorWithCause } from './CameraError'; +import type { CameraProps, OnShutterEvent } from './types/CameraProps'; +import type { Code, CodeScanner, CodeScannerFrame } from './types/CodeScanner'; +import type { Orientation } from './types/Orientation'; +export interface OnCodeScannedEvent { + codes: Code[]; + frame: CodeScannerFrame; +} +export interface OnErrorEvent { + code: string; + message: string; + cause?: ErrorWithCause; +} +export interface AverageFpsChangedEvent { + averageFps: number; +} +export interface OutputOrientationChangedEvent { + outputOrientation: Orientation; +} +export interface PreviewOrientationChangedEvent { + previewOrientation: Orientation; +} +export type NativeCameraViewProps = Omit & { + cameraId: string; + enableFrameProcessor: boolean; + codeScannerOptions?: Omit; + minFps?: number; + maxFps?: number; + onViewReady: (event: NativeSyntheticEvent) => void; + onAverageFpsChanged?: (event: NativeSyntheticEvent) => void; + onInitialized?: (event: NativeSyntheticEvent) => void; + onError?: (event: NativeSyntheticEvent) => void; + onCodeScanned?: (event: NativeSyntheticEvent) => void; + onStarted?: (event: NativeSyntheticEvent) => void; + onStopped?: (event: NativeSyntheticEvent) => void; + onPreviewStarted?: (event: NativeSyntheticEvent) => void; + onPreviewStopped?: (event: NativeSyntheticEvent) => void; + onShutter?: (event: NativeSyntheticEvent) => void; + onOutputOrientationChanged?: (event: NativeSyntheticEvent) => void; + onPreviewOrientationChanged?: (event: NativeSyntheticEvent) => void; +}; +export declare const NativeCameraView: import("react-native").HostComponent; +//# sourceMappingURL=NativeCameraView.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/NativeCameraView.d.ts.map b/package/lib/typescript/NativeCameraView.d.ts.map new file mode 100644 index 0000000000..8d6cf9d218 --- /dev/null +++ b/package/lib/typescript/NativeCameraView.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"NativeCameraView.d.ts","sourceRoot":"","sources":["../../src/NativeCameraView.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AAExD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AACnD,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACtE,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAC9E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAEtD,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,IAAI,EAAE,CAAA;IACb,KAAK,EAAE,gBAAgB,CAAA;CACxB;AACD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,cAAc,CAAA;CACvB;AACD,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,MAAM,CAAA;CACnB;AACD,MAAM,WAAW,6BAA6B;IAC5C,iBAAiB,EAAE,WAAW,CAAA;CAC/B;AACD,MAAM,WAAW,8BAA8B;IAC7C,kBAAkB,EAAE,WAAW,CAAA;CAChC;AACD,MAAM,MAAM,qBAAqB,GAAG,IAAI,CACtC,WAAW,EACT,QAAQ,GACR,eAAe,GACf,SAAS,GACT,WAAW,GACX,4BAA4B,GAC5B,6BAA6B,GAC7B,gBAAgB,GAChB,aAAa,GACb,KAAK,CACR,GAAG;IAEF,QAAQ,EAAE,MAAM,CAAA;IAChB,oBAAoB,EAAE,OAAO,CAAA;IAC7B,kBAAkB,CAAC,EAAE,IAAI,CAAC,WAAW,EAAE,eAAe,CAAC,CAAA;IACvD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IAEf,WAAW,EAAE,CAAC,KAAK,EAAE,oBAAoB,CAAC,IAAI,CAAC,KAAK,IAAI,CAAA;IACxD,mBAAmB,CAAC,EAAE,CAAC,KAAK,EAAE,oBAAoB,CAAC,sBAAsB,CAAC,KAAK,IAAI,CAAA;IAEnF,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,oBAAoB,CAAC,IAAI,CAAC,KAAK,IAAI,CAAA;IAC3D,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,oBAAoB,CAAC,YAAY,CAAC,KAAK,IAAI,CAAA;IAC7D,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,oBAAoB,CAAC,kBAAkB,CAAC,KAAK,IAAI,CAAA;IACzE,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,oBAAoB,CAAC,IAAI,CAAC,KAAK,IAAI,CAAA;IACvD,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,oBAAoB,CAAC,IAAI,CAAC,KAAK,IAAI,CAAA;IACvD,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,oBAAoB,CAAC,IAAI,CAAC,KAAK,IAAI,CAAA;IAC9D,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,oBAAoB,CAAC,IAAI,CAAC,KAAK,IAAI,CAAA;IAC9D,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,oBAAoB,CAAC,cAAc,CAAC,KAAK,IAAI,CAAA;IACjE,0BAA0B,CAAC,EAAE,CAAC,KAAK,EAAE,oBAAoB,CAAC,6BAA6B,CAAC,KAAK,IAAI,CAAA;IACjG,2BAA2B,CAAC,EAAE,CAAC,KAAK,EAAE,oBAAoB,CAAC,8BAA8B,CAAC,KAAK,IAAI,CAAA;CACpG,CAAA;AAGD,eAAO,MAAM,gBAAgB,6DAA8D,CAAA"} \ No newline at end of file diff --git a/package/lib/typescript/RotationHelper.d.ts b/package/lib/typescript/RotationHelper.d.ts new file mode 100644 index 0000000000..f4853c37c5 --- /dev/null +++ b/package/lib/typescript/RotationHelper.d.ts @@ -0,0 +1,17 @@ +import type { Orientation } from './types/Orientation'; +export declare class RotationHelper { + /** + * Gets or sets the current preview orientation. + */ + previewOrientation: Orientation; + /** + * Gets or sets the current output orientation. + */ + outputOrientation: Orientation; + /** + * Gets the current target rotation (in degrees) that needs to be applied + * to all UI elements so they appear up-right. + */ + get uiRotation(): number; +} +//# sourceMappingURL=RotationHelper.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/RotationHelper.d.ts.map b/package/lib/typescript/RotationHelper.d.ts.map new file mode 100644 index 0000000000..90f41ab3a1 --- /dev/null +++ b/package/lib/typescript/RotationHelper.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"RotationHelper.d.ts","sourceRoot":"","sources":["../../src/RotationHelper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAetD,qBAAa,cAAc;IACzB;;OAEG;IACH,kBAAkB,EAAE,WAAW,CAAa;IAC5C;;OAEG;IACH,iBAAiB,EAAE,WAAW,CAAa;IAE3C;;;OAGG;IACH,IAAI,UAAU,IAAI,MAAM,CAevB;CACF"} \ No newline at end of file diff --git a/package/lib/typescript/dependencies/ModuleProxy.d.ts b/package/lib/typescript/dependencies/ModuleProxy.d.ts new file mode 100644 index 0000000000..e976fb885d --- /dev/null +++ b/package/lib/typescript/dependencies/ModuleProxy.d.ts @@ -0,0 +1,13 @@ +/// +/// +type ImportType = ReturnType; +/** + * Create a lazily-imported module proxy. + * This is useful for lazily requiring optional dependencies. + */ +export declare const createModuleProxy: (getModule: () => ImportType) => TModule; +export declare class OptionalDependencyNotInstalledError extends Error { + constructor(name: string); +} +export {}; +//# sourceMappingURL=ModuleProxy.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/dependencies/ModuleProxy.d.ts.map b/package/lib/typescript/dependencies/ModuleProxy.d.ts.map new file mode 100644 index 0000000000..7dfeecb3cc --- /dev/null +++ b/package/lib/typescript/dependencies/ModuleProxy.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"ModuleProxy.d.ts","sourceRoot":"","sources":["../../../src/dependencies/ModuleProxy.ts"],"names":[],"mappings":";;AAAA,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,OAAO,CAAC,CAAA;AAE5C;;;GAGG;AACH,eAAO,MAAM,iBAAiB,uBAAwB,MAAM,UAAU,YAwBrE,CAAA;AAED,qBAAa,mCAAoC,SAAQ,KAAK;gBAChD,IAAI,EAAE,MAAM;CAGzB"} \ No newline at end of file diff --git a/package/lib/typescript/dependencies/ReanimatedProxy.d.ts b/package/lib/typescript/dependencies/ReanimatedProxy.d.ts new file mode 100644 index 0000000000..c74285c9d9 --- /dev/null +++ b/package/lib/typescript/dependencies/ReanimatedProxy.d.ts @@ -0,0 +1,10 @@ +import type * as Reanimated from 'react-native-reanimated'; +/** + * A proxy object that lazy-imports react-native-reanimated as soon as the + * caller tries to access a property on {@linkcode ReanimatedProxy}. + * + * If react-native-reanimated is not installed, accessing anything on + * {@linkcode ReanimatedProxy} will throw. + */ +export declare const ReanimatedProxy: typeof Reanimated; +//# sourceMappingURL=ReanimatedProxy.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/dependencies/ReanimatedProxy.d.ts.map b/package/lib/typescript/dependencies/ReanimatedProxy.d.ts.map new file mode 100644 index 0000000000..71059342f8 --- /dev/null +++ b/package/lib/typescript/dependencies/ReanimatedProxy.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"ReanimatedProxy.d.ts","sourceRoot":"","sources":["../../../src/dependencies/ReanimatedProxy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,UAAU,MAAM,yBAAyB,CAAA;AAK1D;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,mBAM1B,CAAA"} \ No newline at end of file diff --git a/package/lib/typescript/dependencies/SkiaProxy.d.ts b/package/lib/typescript/dependencies/SkiaProxy.d.ts new file mode 100644 index 0000000000..311273e700 --- /dev/null +++ b/package/lib/typescript/dependencies/SkiaProxy.d.ts @@ -0,0 +1,10 @@ +import type * as Skia from '@shopify/react-native-skia'; +/** + * A proxy object that lazy-imports @shopify/react-native-skia as soon as the + * caller tries to access a property on {@linkcode SkiaProxy}. + * + * If @shopify/react-native-skia is not installed, accessing anything on + * {@linkcode SkiaProxy} will throw. + */ +export declare const SkiaProxy: typeof Skia; +//# sourceMappingURL=SkiaProxy.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/dependencies/SkiaProxy.d.ts.map b/package/lib/typescript/dependencies/SkiaProxy.d.ts.map new file mode 100644 index 0000000000..10fef347f9 --- /dev/null +++ b/package/lib/typescript/dependencies/SkiaProxy.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"SkiaProxy.d.ts","sourceRoot":"","sources":["../../../src/dependencies/SkiaProxy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,IAAI,MAAM,4BAA4B,CAAA;AAKvD;;;;;;GAMG;AACH,eAAO,MAAM,SAAS,aAMpB,CAAA"} \ No newline at end of file diff --git a/package/lib/typescript/dependencies/WorkletsProxy.d.ts b/package/lib/typescript/dependencies/WorkletsProxy.d.ts new file mode 100644 index 0000000000..e490ac0e46 --- /dev/null +++ b/package/lib/typescript/dependencies/WorkletsProxy.d.ts @@ -0,0 +1,10 @@ +import type * as Worklets from 'react-native-worklets-core'; +/** + * A proxy object that lazy-imports react-native-worklets-core as soon as the + * caller tries to access a property on {@linkcode WorkletsProxy}. + * + * If react-native-worklets-core is not installed, accessing anything on + * {@linkcode WorkletsProxy} will throw. + */ +export declare const WorkletsProxy: typeof Worklets; +//# sourceMappingURL=WorkletsProxy.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/dependencies/WorkletsProxy.d.ts.map b/package/lib/typescript/dependencies/WorkletsProxy.d.ts.map new file mode 100644 index 0000000000..8f8e22f596 --- /dev/null +++ b/package/lib/typescript/dependencies/WorkletsProxy.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"WorkletsProxy.d.ts","sourceRoot":"","sources":["../../../src/dependencies/WorkletsProxy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,QAAQ,MAAM,4BAA4B,CAAA;AAK3D;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,iBAMxB,CAAA"} \ No newline at end of file diff --git a/package/lib/typescript/devices/Templates.d.ts b/package/lib/typescript/devices/Templates.d.ts new file mode 100644 index 0000000000..ef2576856a --- /dev/null +++ b/package/lib/typescript/devices/Templates.d.ts @@ -0,0 +1,12 @@ +import type { FormatFilter } from './getCameraFormat'; +type PredefinedTemplates = 'Video' | 'Video60Fps' | 'VideoSlowMotion' | 'VideoStabilized' | 'Photo' | 'PhotoPortrait' | 'FrameProcessing' | 'Snapchat' | 'Instagram'; +/** + * Predefined templates for use in `useCameraFormat`/`getCameraFormat`. + * @example + * ```ts + * const format = useCameraFormat(device, Templates.Snapchat) + * ``` + */ +export declare const Templates: Record; +export {}; +//# sourceMappingURL=Templates.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/devices/Templates.d.ts.map b/package/lib/typescript/devices/Templates.d.ts.map new file mode 100644 index 0000000000..f98d8f6ac0 --- /dev/null +++ b/package/lib/typescript/devices/Templates.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Templates.d.ts","sourceRoot":"","sources":["../../../src/devices/Templates.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAErD,KAAK,mBAAmB,GACpB,OAAO,GACP,YAAY,GACZ,iBAAiB,GACjB,iBAAiB,GACjB,OAAO,GACP,eAAe,GACf,iBAAiB,GACjB,UAAU,GACV,WAAW,CAAA;AAMf;;;;;;GAMG;AACH,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,mBAAmB,EAAE,YAAY,EAAE,CAiDjE,CAAA"} \ No newline at end of file diff --git a/package/lib/typescript/devices/getCameraDevice.d.ts b/package/lib/typescript/devices/getCameraDevice.d.ts new file mode 100644 index 0000000000..9eb6e1143a --- /dev/null +++ b/package/lib/typescript/devices/getCameraDevice.d.ts @@ -0,0 +1,37 @@ +import type { CameraDevice, CameraPosition, PhysicalCameraDeviceType } from '../types/CameraDevice'; +export interface DeviceFilter { + /** + * The desired physical devices your camera device should have. + * + * Many modern phones have multiple Camera devices on one side and can combine those physical camera devices to one logical camera device. + * For example, the iPhone 11 has two physical camera devices, the `ultra-wide-angle-camera` ("fish-eye") and the normal `wide-angle-camera`. You can either use one of those devices individually, or use a combined logical camera device which can smoothly switch over between the two physical cameras depending on the current `zoom` level. + * When the user is at 0.5x-1x zoom, the `ultra-wide-angle-camera` can be used to offer a fish-eye zoom-out effect, and anything above 1x will smoothly switch over to the `wide-angle-camera`. + * + * **Note:** Devices with less phyiscal devices (`['wide-angle-camera']`) are usually faster to start-up than more complex + * devices (`['ultra-wide-angle-camera', 'wide-angle-camera', 'telephoto-camera']`), but don't offer zoom switch-over capabilities. + * + * @example + * ```ts + * // This device is simpler, so it starts up faster. + * getCameraDevice({ physicalDevices: ['wide-angle-camera'] }) + * // This device is more complex, so it starts up slower, but you can switch between devices on 0.5x, 1x and 2x zoom. + * getCameraDevice({ physicalDevices: ['ultra-wide-angle-camera', 'wide-angle-camera', 'telephoto-camera'] }) + * ``` + */ + physicalDevices?: PhysicalCameraDeviceType[]; +} +/** + * Get the best matching Camera device that best satisfies your requirements using a sorting filter, or `undefined` if {@linkcode devices} does not contain any devices. + * @param position The position of the Camera device relative to the phone. + * @param filter The filter you want to use. The Camera device that matches your filter the closest will be returned + * @returns The Camera device that matches your filter the closest, or `undefined` if no such Camera Device exists on the given {@linkcode position}. + * @example + * ```ts + * const devices = Camera.getAvailableCameraDevices() + * const device = getCameraDevice(devices, 'back', { + * physicalDevices: ['wide-angle-camera'] + * }) + * ``` + */ +export declare function getCameraDevice(devices: CameraDevice[], position: CameraPosition, filter?: DeviceFilter): CameraDevice | undefined; +//# sourceMappingURL=getCameraDevice.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/devices/getCameraDevice.d.ts.map b/package/lib/typescript/devices/getCameraDevice.d.ts.map new file mode 100644 index 0000000000..f06c3fef50 --- /dev/null +++ b/package/lib/typescript/devices/getCameraDevice.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"getCameraDevice.d.ts","sourceRoot":"","sources":["../../../src/devices/getCameraDevice.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAA;AAEnG,MAAM,WAAW,YAAY;IAC3B;;;;;;;;;;;;;;;;;OAiBG;IACH,eAAe,CAAC,EAAE,wBAAwB,EAAE,CAAA;CAC7C;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,GAAE,YAAiB,GAAG,YAAY,GAAG,SAAS,CAwCtI"} \ No newline at end of file diff --git a/package/lib/typescript/devices/getCameraFormat.d.ts b/package/lib/typescript/devices/getCameraFormat.d.ts new file mode 100644 index 0000000000..21cda79b1e --- /dev/null +++ b/package/lib/typescript/devices/getCameraFormat.d.ts @@ -0,0 +1,95 @@ +import type { AutoFocusSystem, CameraDevice, CameraDeviceFormat, VideoStabilizationMode } from '../types/CameraDevice'; +interface Size { + width: number; + height: number; +} +export interface FormatFilter { + /** + * The target resolution of the video (and frame processor) output pipeline. + * If no format supports the given resolution, the format closest to this value will be used. + */ + videoResolution?: Size | 'max'; + /** + * The target resolution of the photo output pipeline. + * If no format supports the given resolution, the format closest to this value will be used. + */ + photoResolution?: Size | 'max'; + /** + * The target aspect ratio of the video (and preview) output, expressed as a factor: `width / height`. + * (Note: Cameras are in landscape orientation) + * + * In most cases, you want this to be as close to the screen's aspect ratio as possible (usually ~9:16). + * + * @example + * ```ts + * const screen = Dimensions.get('screen') + * targetVideoAspectRatio: screen.height / screen.width + * ``` + */ + videoAspectRatio?: number; + /** + * The target aspect ratio of the photo output, expressed as a factor: `width / height`. + * (Note: Cameras are in landscape orientation) + * + * In most cases, you want this to be the same as `targetVideoAspectRatio`, which you often want + * to be as close to the screen's aspect ratio as possible (usually ~9:16) + * + * @example + * ```ts + * const screen = Dimensions.get('screen') + * targetPhotoAspectRatio: screen.height / screen.width + * ``` + */ + photoAspectRatio?: number; + /** + * The target FPS you want to record video at. + * If the FPS requirements can not be met, the format closest to this value will be used. + */ + fps?: number | 'max'; + /** + * The target video stabilization mode you want to use. + * If no format supports the target video stabilization mode, the best other matching format will be used. + */ + videoStabilizationMode?: VideoStabilizationMode; + /** + * Whether you want to find a format that supports Photo HDR. + */ + photoHdr?: boolean; + /** + * Whether you want to find a format that supports Photo HDR. + */ + videoHdr?: boolean; + /** + * The target ISO value for capturing photos. + * Higher ISO values tend to capture sharper photos, at the cost of reduced capture speed. + * Lower ISO values tend to capture photos quicker. + */ + iso?: number | 'max' | 'min'; + /** + * The target auto-focus system. + * While `phase-detection` is generally the best system available, + * you might want to choose a different auto-focus system. + */ + autoFocusSystem?: AutoFocusSystem; +} +/** + * Get the best matching Camera format for the given device that satisfies your requirements using a sorting filter. By default, formats are sorted by highest to lowest resolution. + * + * The {@linkcode filters | filters} are ranked by priority, from highest to lowest. + * This means the first item you pass will have a higher priority than the second, and so on. + * + * @param device The Camera Device you're currently using + * @param filters The filters you want to use. The format that matches your filter the closest will be returned + * @returns The format that matches your filter the closest. + * + * @example + * ```ts + * const format = getCameraFormat(device, [ + * { videoResolution: { width: 3048, height: 2160 } }, + * { fps: 60 } + * ]) + * ``` + */ +export declare function getCameraFormat(device: CameraDevice, filters: FormatFilter[]): CameraDeviceFormat; +export {}; +//# sourceMappingURL=getCameraFormat.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/devices/getCameraFormat.d.ts.map b/package/lib/typescript/devices/getCameraFormat.d.ts.map new file mode 100644 index 0000000000..5d8fc1d679 --- /dev/null +++ b/package/lib/typescript/devices/getCameraFormat.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"getCameraFormat.d.ts","sourceRoot":"","sources":["../../../src/devices/getCameraFormat.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAA;AAGtH,UAAU,IAAI;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,YAAY;IAC3B;;;OAGG;IACH,eAAe,CAAC,EAAE,IAAI,GAAG,KAAK,CAAA;IAC9B;;;OAGG;IACH,eAAe,CAAC,EAAE,IAAI,GAAG,KAAK,CAAA;IAC9B;;;;;;;;;;;OAWG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;;;;;;;;;;;OAYG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,GAAG,KAAK,CAAA;IACpB;;;OAGG;IACH,sBAAsB,CAAC,EAAE,sBAAsB,CAAA;IAC/C;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,KAAK,CAAA;IAC5B;;;;OAIG;IACH,eAAe,CAAC,EAAE,eAAe,CAAA;CAClC;AAwBD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,kBAAkB,CA4HjG"} \ No newline at end of file diff --git a/package/lib/typescript/expo-plugin/@types.d.ts b/package/lib/typescript/expo-plugin/@types.d.ts new file mode 100644 index 0000000000..f92e5dc978 --- /dev/null +++ b/package/lib/typescript/expo-plugin/@types.d.ts @@ -0,0 +1,51 @@ +export type ConfigProps = { + /** + * The text to show in the native dialog when asking for Camera Permissions. + * @default 'Allow $(PRODUCT_NAME) to access your camera' + */ + cameraPermissionText?: string; + /** + * Whether to add Microphone Permissions to the native manifest or not. + * @default false + */ + enableMicrophonePermission?: boolean; + /** + * Whether to add Location Permissions to the native manifest or not. + * + * On iOS, this also fully removes the location-related APIs (`CLLocationManager`) from the compiled app. + * @default false + */ + enableLocation?: boolean; + /** + * The text to show in the native dialog when asking for Microphone Permissions. + * @default 'Allow $(PRODUCT_NAME) to access your microphone' + */ + microphonePermissionText?: string; + /** + * The text to show in the native dialog when asking for Location Permissions. + * @default 'Allow $(PRODUCT_NAME) to access your location' + */ + locationPermissionText?: string; + /** + * Whether to enable the Frame Processors runtime, or explicitly disable it. + * Disabling Frame Processors will make your app smaller as the C++ files will not be compiled. + * See [Frame Processors](https://react-native-vision-camera.com/docs/guides/frame-processors) + * + * Note: When react-native-worklets-core is not installed, Frame Processors are automatically disabled anyways. + * @default true + */ + enableFrameProcessors?: boolean; + /** + * Whether to enable the QR/Barcode Scanner Model. + * + * - When set to `true`, the MLKit Model will be bundled alongside + * with your app. (~2.4 MB in size). + * - When set to `false`, it can still be downloaded on-the-fly on devices with Google Play Services installed if you are using the `CodeScanner`. + * + * See [QR/Barcode Scanning](https://react-native-vision-camera.com/docs/guides/code-scanning) + * + * @default false + */ + enableCodeScanner?: boolean; +}; +//# sourceMappingURL=@types.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/expo-plugin/@types.d.ts.map b/package/lib/typescript/expo-plugin/@types.d.ts.map new file mode 100644 index 0000000000..e177b8af53 --- /dev/null +++ b/package/lib/typescript/expo-plugin/@types.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"@types.d.ts","sourceRoot":"","sources":["../../../src/expo-plugin/@types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG;IACxB;;;OAGG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B;;;OAGG;IACH,0BAA0B,CAAC,EAAE,OAAO,CAAA;IACpC;;;;;OAKG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;OAGG;IACH,wBAAwB,CAAC,EAAE,MAAM,CAAA;IACjC;;;OAGG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAC/B;;;;;;;OAOG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B;;;;;;;;;;OAUG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAC5B,CAAA"} \ No newline at end of file diff --git a/package/lib/typescript/expo-plugin/withAndroidMLKitVisionModel.d.ts b/package/lib/typescript/expo-plugin/withAndroidMLKitVisionModel.d.ts new file mode 100644 index 0000000000..6d0d8556dd --- /dev/null +++ b/package/lib/typescript/expo-plugin/withAndroidMLKitVisionModel.d.ts @@ -0,0 +1,8 @@ +import type { ConfigPlugin } from '@expo/config-plugins'; +import type { ConfigProps } from './@types'; +/** + * Set the `VisionCamera_enableCodeScanner` value in the static `gradle.properties` file. + * This is used to add the full MLKit dependency to the project. + */ +export declare const withAndroidMLKitVisionModel: ConfigPlugin; +//# sourceMappingURL=withAndroidMLKitVisionModel.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/expo-plugin/withAndroidMLKitVisionModel.d.ts.map b/package/lib/typescript/expo-plugin/withAndroidMLKitVisionModel.d.ts.map new file mode 100644 index 0000000000..f7ab61bd98 --- /dev/null +++ b/package/lib/typescript/expo-plugin/withAndroidMLKitVisionModel.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"withAndroidMLKitVisionModel.d.ts","sourceRoot":"","sources":["../../../src/expo-plugin/withAndroidMLKitVisionModel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAExD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAE3C;;;GAGG;AACH,eAAO,MAAM,2BAA2B,EAAE,YAAY,CAAC,WAAW,CAgBjE,CAAA"} \ No newline at end of file diff --git a/package/lib/typescript/expo-plugin/withEnableFrameProcessorsAndroid.d.ts b/package/lib/typescript/expo-plugin/withEnableFrameProcessorsAndroid.d.ts new file mode 100644 index 0000000000..abee492018 --- /dev/null +++ b/package/lib/typescript/expo-plugin/withEnableFrameProcessorsAndroid.d.ts @@ -0,0 +1,7 @@ +import type { ConfigPlugin } from '@expo/config-plugins'; +/** + * Set the `VisionCamera_enableFrameProcessors` value in the static `gradle.properties` file. + * This is used to disable frame processors if you don't need it for android. + */ +export declare const withEnableFrameProcessorsAndroid: ConfigPlugin; +//# sourceMappingURL=withEnableFrameProcessorsAndroid.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/expo-plugin/withEnableFrameProcessorsAndroid.d.ts.map b/package/lib/typescript/expo-plugin/withEnableFrameProcessorsAndroid.d.ts.map new file mode 100644 index 0000000000..ef0580b774 --- /dev/null +++ b/package/lib/typescript/expo-plugin/withEnableFrameProcessorsAndroid.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"withEnableFrameProcessorsAndroid.d.ts","sourceRoot":"","sources":["../../../src/expo-plugin/withEnableFrameProcessorsAndroid.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAGxD;;;GAGG;AACH,eAAO,MAAM,gCAAgC,EAAE,YAAY,CAAC,OAAO,CAgBlE,CAAA"} \ No newline at end of file diff --git a/package/lib/typescript/expo-plugin/withEnableFrameProcessorsIOS.d.ts b/package/lib/typescript/expo-plugin/withEnableFrameProcessorsIOS.d.ts new file mode 100644 index 0000000000..8c067617b1 --- /dev/null +++ b/package/lib/typescript/expo-plugin/withEnableFrameProcessorsIOS.d.ts @@ -0,0 +1,7 @@ +import type { ConfigPlugin } from '@expo/config-plugins'; +/** + * Set the `enableFrameProcessors` flag inside of the XcodeProject. + * This is used to disable frame processors if you don't need it on iOS. (will save CPU and Memory) + */ +export declare const withEnableFrameProcessorsIOS: ConfigPlugin; +//# sourceMappingURL=withEnableFrameProcessorsIOS.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/expo-plugin/withEnableFrameProcessorsIOS.d.ts.map b/package/lib/typescript/expo-plugin/withEnableFrameProcessorsIOS.d.ts.map new file mode 100644 index 0000000000..f08d4b19f5 --- /dev/null +++ b/package/lib/typescript/expo-plugin/withEnableFrameProcessorsIOS.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"withEnableFrameProcessorsIOS.d.ts","sourceRoot":"","sources":["../../../src/expo-plugin/withEnableFrameProcessorsIOS.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAIxD;;;GAGG;AACH,eAAO,MAAM,4BAA4B,EAAE,YAAY,CAAC,OAAO,CAQ9D,CAAA"} \ No newline at end of file diff --git a/package/lib/typescript/expo-plugin/withEnableLocationIOS.d.ts b/package/lib/typescript/expo-plugin/withEnableLocationIOS.d.ts new file mode 100644 index 0000000000..b1db1d8769 --- /dev/null +++ b/package/lib/typescript/expo-plugin/withEnableLocationIOS.d.ts @@ -0,0 +1,9 @@ +import type { ConfigPlugin } from '@expo/config-plugins'; +/** + * Set the `enableLocation` flag inside of the XcodeProject. + * This is used to enable location APIs. + * If location is disabled, the CLLocation APIs are not used in the codebase. + * This is useful if you don't use Location and apple review is unhappy about CLLocation usage. + */ +export declare const withEnableLocationIOS: ConfigPlugin; +//# sourceMappingURL=withEnableLocationIOS.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/expo-plugin/withEnableLocationIOS.d.ts.map b/package/lib/typescript/expo-plugin/withEnableLocationIOS.d.ts.map new file mode 100644 index 0000000000..49f09b8e80 --- /dev/null +++ b/package/lib/typescript/expo-plugin/withEnableLocationIOS.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"withEnableLocationIOS.d.ts","sourceRoot":"","sources":["../../../src/expo-plugin/withEnableLocationIOS.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAIxD;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,EAAE,YAAY,CAAC,OAAO,CAQvD,CAAA"} \ No newline at end of file diff --git a/package/lib/typescript/expo-plugin/withVisionCamera.d.ts b/package/lib/typescript/expo-plugin/withVisionCamera.d.ts new file mode 100644 index 0000000000..ecb92df12d --- /dev/null +++ b/package/lib/typescript/expo-plugin/withVisionCamera.d.ts @@ -0,0 +1,5 @@ +import type { ConfigPlugin } from '@expo/config-plugins'; +import type { ConfigProps } from './@types'; +declare const _default: ConfigPlugin; +export default _default; +//# sourceMappingURL=withVisionCamera.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/expo-plugin/withVisionCamera.d.ts.map b/package/lib/typescript/expo-plugin/withVisionCamera.d.ts.map new file mode 100644 index 0000000000..9e61689dd6 --- /dev/null +++ b/package/lib/typescript/expo-plugin/withVisionCamera.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"withVisionCamera.d.ts","sourceRoot":"","sources":["../../../src/expo-plugin/withVisionCamera.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAKxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;;AA4C3C,wBAAqE"} \ No newline at end of file diff --git a/package/lib/typescript/expo-plugin/writeToPodfile.d.ts b/package/lib/typescript/expo-plugin/writeToPodfile.d.ts new file mode 100644 index 0000000000..123b9dd91b --- /dev/null +++ b/package/lib/typescript/expo-plugin/writeToPodfile.d.ts @@ -0,0 +1,2 @@ +export declare function writeToPodfile(projectRoot: string, key: string, value: string): void; +//# sourceMappingURL=writeToPodfile.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/expo-plugin/writeToPodfile.d.ts.map b/package/lib/typescript/expo-plugin/writeToPodfile.d.ts.map new file mode 100644 index 0000000000..f092b62709 --- /dev/null +++ b/package/lib/typescript/expo-plugin/writeToPodfile.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"writeToPodfile.d.ts","sourceRoot":"","sources":["../../../src/expo-plugin/writeToPodfile.ts"],"names":[],"mappings":"AAGA,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAYpF"} \ No newline at end of file diff --git a/package/lib/typescript/frame-processors/FrameProcessorsUnavailableError.d.ts b/package/lib/typescript/frame-processors/FrameProcessorsUnavailableError.d.ts new file mode 100644 index 0000000000..e64e15e950 --- /dev/null +++ b/package/lib/typescript/frame-processors/FrameProcessorsUnavailableError.d.ts @@ -0,0 +1,5 @@ +import { CameraRuntimeError } from '../CameraError'; +export declare class FrameProcessorsUnavailableError extends CameraRuntimeError { + constructor(reason: unknown); +} +//# sourceMappingURL=FrameProcessorsUnavailableError.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/frame-processors/FrameProcessorsUnavailableError.d.ts.map b/package/lib/typescript/frame-processors/FrameProcessorsUnavailableError.d.ts.map new file mode 100644 index 0000000000..d76229e13d --- /dev/null +++ b/package/lib/typescript/frame-processors/FrameProcessorsUnavailableError.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"FrameProcessorsUnavailableError.d.ts","sourceRoot":"","sources":["../../../src/frame-processors/FrameProcessorsUnavailableError.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AAEnD,qBAAa,+BAAgC,SAAQ,kBAAkB;gBACzD,MAAM,EAAE,OAAO;CAO5B"} \ No newline at end of file diff --git a/package/lib/typescript/frame-processors/VisionCameraProxy.d.ts b/package/lib/typescript/frame-processors/VisionCameraProxy.d.ts new file mode 100644 index 0000000000..cdaef44130 --- /dev/null +++ b/package/lib/typescript/frame-processors/VisionCameraProxy.d.ts @@ -0,0 +1,57 @@ +import type { IWorkletContext } from 'react-native-worklets-core'; +import type { Frame } from '../types/Frame'; +type BasicParameterType = string | number | boolean | undefined | ArrayBuffer; +type ParameterType = BasicParameterType | BasicParameterType[] | Record; +/** + * An initialized native instance of a FrameProcessorPlugin. + * All memory allocated by this plugin will be deleted once this value goes out of scope. + */ +export interface FrameProcessorPlugin { + /** + * Call the native Frame Processor Plugin with the given Frame and options. + * @param frame The Frame from the Frame Processor. + * @param options (optional) Additional options. Options will be converted to a native dictionary + * @returns (optional) A value returned from the native Frame Processor Plugin (or undefined) + */ + call(frame: Frame, options?: Record): ParameterType; +} +interface TVisionCameraProxy { + /** + * @internal + */ + setFrameProcessor(viewTag: number, frameProcessor: (frame: Frame) => void): void; + /** + * @internal + */ + removeFrameProcessor(viewTag: number): void; + /** + * Creates a new instance of a native Frame Processor Plugin. + * The Plugin has to be registered on the native side, otherwise this returns `undefined`. + * @param name The name of the Frame Processor Plugin. This has to be the same name as on the native side. + * @param options (optional) Options, as a native dictionary, passed to the constructor/init-function of the native plugin. + * @example + * ```ts + * const plugin = VisionCameraProxy.initFrameProcessorPlugin('scanFaces', { model: 'fast' }) + * if (plugin == null) throw new Error("Failed to load scanFaces plugin!") + * ``` + */ + initFrameProcessorPlugin(name: string, options: Record): FrameProcessorPlugin | undefined; + /** + * Get the Frame Processor Runtime Worklet Context. + * + * This is the serial [DispatchQueue](https://developer.apple.com/documentation/dispatch/dispatchqueue) + * / [Executor](https://developer.android.com/reference/java/util/concurrent/Executor) the + * video/frame processor pipeline is running on. + * + * @internal + */ + workletContext: IWorkletContext | undefined; +} +/** + * The JSI Proxy for the Frame Processors Runtime. + * + * This will be replaced with a CxxTurboModule in the future. + */ +export declare const VisionCameraProxy: TVisionCameraProxy; +export {}; +//# sourceMappingURL=VisionCameraProxy.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/frame-processors/VisionCameraProxy.d.ts.map b/package/lib/typescript/frame-processors/VisionCameraProxy.d.ts.map new file mode 100644 index 0000000000..e2d56556f6 --- /dev/null +++ b/package/lib/typescript/frame-processors/VisionCameraProxy.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"VisionCameraProxy.d.ts","sourceRoot":"","sources":["../../../src/frame-processors/VisionCameraProxy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAEjE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AAG3C,KAAK,kBAAkB,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,WAAW,CAAA;AAC7E,KAAK,aAAa,GAAG,kBAAkB,GAAG,kBAAkB,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,kBAAkB,GAAG,SAAS,CAAC,CAAA;AAE/G;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;;OAKG;IACH,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,GAAG,aAAa,CAAA;CAC3E;AAED,UAAU,kBAAkB;IAC1B;;OAEG;IACH,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAAA;IAChF;;OAEG;IACH,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3C;;;;;;;;;;OAUG;IACH,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,GAAG,oBAAoB,GAAG,SAAS,CAAA;IAChH;;;;;;;;OAQG;IACH,cAAc,EAAE,eAAe,GAAG,SAAS,CAAA;CAC5C;AAkCD;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,oBAAQ,CAAA"} \ No newline at end of file diff --git a/package/lib/typescript/frame-processors/runAsync.d.ts b/package/lib/typescript/frame-processors/runAsync.d.ts new file mode 100644 index 0000000000..45e7dfd176 --- /dev/null +++ b/package/lib/typescript/frame-processors/runAsync.d.ts @@ -0,0 +1,40 @@ +import type { Frame } from '../types/Frame'; +/** + * Runs the given {@linkcode func} asynchronously on a separate thread, + * allowing the Frame Processor to continue executing without dropping a Frame. + * + * Only one {@linkcode runAsync} call will execute at the same time, + * so {@linkcode runAsync} is **not parallel**, **but asynchronous**. + * + * + * For example, if your Camera is running at 60 FPS (16ms per frame), and a + * heavy ML face detection Frame Processor Plugin takes 500ms to execute, + * you have two options: + * - Run the plugin normally (synchronously in `useFrameProcessor`) + * but drop a lot of Frames, as we can only run at 2 FPS (500ms per frame) + * - Call the plugin inside {@linkcode runAsync} to allow the Camera to still + * run at 60 FPS, but offload the heavy ML face detection plugin to the + * asynchronous context, where it will run at 2 FPS. + * + * @note {@linkcode runAsync} cannot be used to draw to a Frame in a Skia Frame Processor. + * @param frame The current Frame of the Frame Processor. + * @param func The function to execute. + * @worklet + * @example + * + * ```ts + * const frameProcessor = useFrameProcessor((frame) => { + * 'worklet' + * console.log('New Frame arrived!') + * + * runAsync(frame, () => { + * 'worklet' + * const faces = detectFaces(frame) + * const face = [faces0] + * console.log(`Detected a new face: ${face}`) + * }) + * }) + * ``` + */ +export declare function runAsync(frame: Frame, func: () => void): void; +//# sourceMappingURL=runAsync.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/frame-processors/runAsync.d.ts.map b/package/lib/typescript/frame-processors/runAsync.d.ts.map new file mode 100644 index 0000000000..915e25d0ad --- /dev/null +++ b/package/lib/typescript/frame-processors/runAsync.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"runAsync.d.ts","sourceRoot":"","sources":["../../../src/frame-processors/runAsync.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAiB,MAAM,gBAAgB,CAAA;AA4C1D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,GAAG,IAAI,CAiB7D"} \ No newline at end of file diff --git a/package/lib/typescript/frame-processors/runAtTargetFps.d.ts b/package/lib/typescript/frame-processors/runAtTargetFps.d.ts new file mode 100644 index 0000000000..a1ec993780 --- /dev/null +++ b/package/lib/typescript/frame-processors/runAtTargetFps.d.ts @@ -0,0 +1,32 @@ +declare global { + var __frameProcessorRunAtTargetFpsMap: Record | undefined; +} +/** + * Runs the given {@linkcode func} at the given target {@linkcode fps} rate. + * + * {@linkcode runAtTargetFps} still executes the given {@linkcode func} synchronously, + * so this is only useful for throttling calls to a plugin or logger. + * + * For example, if you want to scan faces only once per second to avoid excessive + * CPU usage, use {@linkcode runAtTargetFps runAtTargetFps(1, ...)}. + * + * @param fps The target FPS rate at which the given function should be executed + * @param func The function to execute. + * @returns The result of the function if it was executed, or `undefined` otherwise. + * @worklet + * @example + * + * ```ts + * const frameProcessor = useFrameProcessor((frame) => { + * 'worklet' + * console.log('New Frame') + * runAtTargetFps(5, () => { + * 'worklet' + * const faces = detectFaces(frame) + * console.log(`Detected a new face: ${faces[0]}`) + * }) + * }) + * ``` + */ +export declare function runAtTargetFps(fps: number, func: () => T): T | undefined; +//# sourceMappingURL=runAtTargetFps.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/frame-processors/runAtTargetFps.d.ts.map b/package/lib/typescript/frame-processors/runAtTargetFps.d.ts.map new file mode 100644 index 0000000000..c78dce527d --- /dev/null +++ b/package/lib/typescript/frame-processors/runAtTargetFps.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"runAtTargetFps.d.ts","sourceRoot":"","sources":["../../../src/frame-processors/runAtTargetFps.ts"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,CAAC;IAEb,IAAI,iCAAiC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,SAAS,CAAA;CACtF;AAYD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,GAAG,SAAS,CAe3E"} \ No newline at end of file diff --git a/package/lib/typescript/frame-processors/throwErrorOnJS.d.ts b/package/lib/typescript/frame-processors/throwErrorOnJS.d.ts new file mode 100644 index 0000000000..388ad6fee8 --- /dev/null +++ b/package/lib/typescript/frame-processors/throwErrorOnJS.d.ts @@ -0,0 +1,6 @@ +/** + * Throws the given Error on the JS Thread using React Native's error reporter. + * @param error An {@linkcode Error}, or an object with a `message` property, otherwise a default messageg will be thrown. + */ +export declare function throwErrorOnJS(error: unknown): void; +//# sourceMappingURL=throwErrorOnJS.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/frame-processors/throwErrorOnJS.d.ts.map b/package/lib/typescript/frame-processors/throwErrorOnJS.d.ts.map new file mode 100644 index 0000000000..0ca143bab5 --- /dev/null +++ b/package/lib/typescript/frame-processors/throwErrorOnJS.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"throwErrorOnJS.d.ts","sourceRoot":"","sources":["../../../src/frame-processors/throwErrorOnJS.ts"],"names":[],"mappings":"AAyCA;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAKnD"} \ No newline at end of file diff --git a/package/lib/typescript/frame-processors/withFrameRefCounting.d.ts b/package/lib/typescript/frame-processors/withFrameRefCounting.d.ts new file mode 100644 index 0000000000..ec6eedb0b0 --- /dev/null +++ b/package/lib/typescript/frame-processors/withFrameRefCounting.d.ts @@ -0,0 +1,8 @@ +import type { Frame } from '../types/Frame'; +/** + * A private API to wrap a Frame Processor with a ref-counting mechanism + * @worklet + * @internal + */ +export declare function withFrameRefCounting(frameProcessor: (frame: Frame) => void): (frame: Frame) => void; +//# sourceMappingURL=withFrameRefCounting.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/frame-processors/withFrameRefCounting.d.ts.map b/package/lib/typescript/frame-processors/withFrameRefCounting.d.ts.map new file mode 100644 index 0000000000..20ffe73b94 --- /dev/null +++ b/package/lib/typescript/frame-processors/withFrameRefCounting.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"withFrameRefCounting.d.ts","sourceRoot":"","sources":["../../../src/frame-processors/withFrameRefCounting.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAiB,MAAM,gBAAgB,CAAA;AAG1D;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,cAAc,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAiBnG"} \ No newline at end of file diff --git a/package/lib/typescript/hooks/useCameraDevice.d.ts b/package/lib/typescript/hooks/useCameraDevice.d.ts new file mode 100644 index 0000000000..1b7b948ad7 --- /dev/null +++ b/package/lib/typescript/hooks/useCameraDevice.d.ts @@ -0,0 +1,16 @@ +import type { CameraDevice, CameraPosition } from '../types/CameraDevice'; +import type { DeviceFilter } from '../devices/getCameraDevice'; +/** + * Get the best matching Camera device that best satisfies your requirements using a sorting filter. + * @param position The position of the Camera device relative to the phone. + * @param filter The filter you want to use. The Camera device that matches your filter the closest will be returned + * @returns The Camera device that matches your filter the closest, or `undefined` if no such Camera Device exists on the given {@linkcode position}. + * @example + * ```ts + * const device = useCameraDevice('back', { + * physicalDevices: ['wide-angle-camera'] + * }) + * ``` + */ +export declare function useCameraDevice(position: CameraPosition, filter?: DeviceFilter): CameraDevice | undefined; +//# sourceMappingURL=useCameraDevice.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/hooks/useCameraDevice.d.ts.map b/package/lib/typescript/hooks/useCameraDevice.d.ts.map new file mode 100644 index 0000000000..a124c29c6c --- /dev/null +++ b/package/lib/typescript/hooks/useCameraDevice.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"useCameraDevice.d.ts","sourceRoot":"","sources":["../../../src/hooks/useCameraDevice.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAI9D;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,cAAc,EAAE,MAAM,CAAC,EAAE,YAAY,GAAG,YAAY,GAAG,SAAS,CAUzG"} \ No newline at end of file diff --git a/package/lib/typescript/hooks/useCameraDevices.d.ts b/package/lib/typescript/hooks/useCameraDevices.d.ts new file mode 100644 index 0000000000..018b0996f3 --- /dev/null +++ b/package/lib/typescript/hooks/useCameraDevices.d.ts @@ -0,0 +1,10 @@ +import type { CameraDevice } from '../types/CameraDevice'; +/** + * Get all available Camera Devices this phone has. + * + * Camera Devices attached to this phone (`back` or `front`) are always available, + * while `external` devices might be plugged in or out at any point, + * so the result of this function might update over time. + */ +export declare function useCameraDevices(): CameraDevice[]; +//# sourceMappingURL=useCameraDevices.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/hooks/useCameraDevices.d.ts.map b/package/lib/typescript/hooks/useCameraDevices.d.ts.map new file mode 100644 index 0000000000..a7a23316ef --- /dev/null +++ b/package/lib/typescript/hooks/useCameraDevices.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"useCameraDevices.d.ts","sourceRoot":"","sources":["../../../src/hooks/useCameraDevices.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAGzD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,IAAI,YAAY,EAAE,CAWjD"} \ No newline at end of file diff --git a/package/lib/typescript/hooks/useCameraFormat.d.ts b/package/lib/typescript/hooks/useCameraFormat.d.ts new file mode 100644 index 0000000000..f1f21bfd06 --- /dev/null +++ b/package/lib/typescript/hooks/useCameraFormat.d.ts @@ -0,0 +1,22 @@ +import type { CameraDevice, CameraDeviceFormat } from '../types/CameraDevice'; +import type { FormatFilter } from '../devices/getCameraFormat'; +/** + * Get the best matching Camera format for the given device that satisfies your requirements using a sorting filter. By default, formats are sorted by highest to lowest resolution. + * + * The {@linkcode filters | filters} are ranked by priority, from highest to lowest. + * This means the first item you pass will have a higher priority than the second, and so on. + * + * @param device The Camera Device you're currently using + * @param filters The filters you want to use. The format that matches your filter the closest will be returned + * @returns The format that matches your filter the closest. + * @example + * ```ts + * const device = useCameraDevice(...) + * const format = useCameraFormat(device, [ + * { videoResolution: { width: 3048, height: 2160 } }, + * { fps: 60 } + * ]) + * ``` + */ +export declare function useCameraFormat(device: CameraDevice | undefined, filters: FormatFilter[]): CameraDeviceFormat | undefined; +//# sourceMappingURL=useCameraFormat.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/hooks/useCameraFormat.d.ts.map b/package/lib/typescript/hooks/useCameraFormat.d.ts.map new file mode 100644 index 0000000000..260e12cd1a --- /dev/null +++ b/package/lib/typescript/hooks/useCameraFormat.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"useCameraFormat.d.ts","sourceRoot":"","sources":["../../../src/hooks/useCameraFormat.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAC7E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAG9D;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,SAAS,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,kBAAkB,GAAG,SAAS,CAQzH"} \ No newline at end of file diff --git a/package/lib/typescript/hooks/useCameraPermission.d.ts b/package/lib/typescript/hooks/useCameraPermission.d.ts new file mode 100644 index 0000000000..32e067e0c1 --- /dev/null +++ b/package/lib/typescript/hooks/useCameraPermission.d.ts @@ -0,0 +1,61 @@ +interface PermissionState { + /** + * Whether the specified permission has explicitly been granted. + * By default, this will be `false`. To request permission, call `requestPermission()`. + */ + hasPermission: boolean; + /** + * Requests the specified permission from the user. + * @returns Whether the specified permission has now been granted, or not. + */ + requestPermission: () => Promise; +} +/** + * Returns whether the user has granted permission to use the Camera, or not. + * + * If the user doesn't grant Camera Permission, you cannot use the ``. + * + * @example + * ```tsx + * const { hasPermission, requestPermission } = useCameraPermission() + * + * if (!hasPermission) { + * return + * } else { + * return + * } + * ``` + */ +export declare function useCameraPermission(): PermissionState; +/** + * Returns whether the user has granted permission to use the Microphone, or not. + * + * If the user doesn't grant Audio Permission, you can use the `` but you cannot + * record videos with audio (the `audio={..}` prop). + * + * @example + * ```tsx + * const { hasPermission, requestPermission } = useMicrophonePermission() + * const canRecordAudio = hasPermission + * + * return + * ``` + */ +export declare function useMicrophonePermission(): PermissionState; +/** + * Returns whether the user has granted permission to use the Location, or not. + * + * If the user doesn't grant Location Permission, you can use the `` but you cannot + * capture photos or videos with GPS EXIF tags (the `location={..}` prop). + * + * @example + * ```tsx + * const { hasPermission, requestPermission } = useLocationPermission() + * const canCaptureLocation = hasPermission + * + * return + * ``` + */ +export declare function useLocationPermission(): PermissionState; +export {}; +//# sourceMappingURL=useCameraPermission.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/hooks/useCameraPermission.d.ts.map b/package/lib/typescript/hooks/useCameraPermission.d.ts.map new file mode 100644 index 0000000000..e9a0b0e3c6 --- /dev/null +++ b/package/lib/typescript/hooks/useCameraPermission.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"useCameraPermission.d.ts","sourceRoot":"","sources":["../../../src/hooks/useCameraPermission.ts"],"names":[],"mappings":"AAKA,UAAU,eAAe;IACvB;;;OAGG;IACH,aAAa,EAAE,OAAO,CAAA;IACtB;;;OAGG;IACH,iBAAiB,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;CAC1C;AA6BD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,mBAAmB,IAAI,eAAe,CAErD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,uBAAuB,IAAI,eAAe,CAEzD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,IAAI,eAAe,CAEvD"} \ No newline at end of file diff --git a/package/lib/typescript/hooks/useCodeScanner.d.ts b/package/lib/typescript/hooks/useCodeScanner.d.ts new file mode 100644 index 0000000000..d26b992660 --- /dev/null +++ b/package/lib/typescript/hooks/useCodeScanner.d.ts @@ -0,0 +1,3 @@ +import type { CodeScanner } from '../types/CodeScanner'; +export declare function useCodeScanner(codeScanner: CodeScanner): CodeScanner; +//# sourceMappingURL=useCodeScanner.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/hooks/useCodeScanner.d.ts.map b/package/lib/typescript/hooks/useCodeScanner.d.ts.map new file mode 100644 index 0000000000..017c4d535f --- /dev/null +++ b/package/lib/typescript/hooks/useCodeScanner.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"useCodeScanner.d.ts","sourceRoot":"","sources":["../../../src/hooks/useCodeScanner.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAQ,WAAW,EAAoB,MAAM,sBAAsB,CAAA;AAE/E,wBAAgB,cAAc,CAAC,WAAW,EAAE,WAAW,GAAG,WAAW,CAmBpE"} \ No newline at end of file diff --git a/package/lib/typescript/hooks/useFrameProcessor.d.ts b/package/lib/typescript/hooks/useFrameProcessor.d.ts new file mode 100644 index 0000000000..376fb39464 --- /dev/null +++ b/package/lib/typescript/hooks/useFrameProcessor.d.ts @@ -0,0 +1,34 @@ +import type { DependencyList } from 'react'; +import type { ReadonlyFrameProcessor } from '../types/CameraProps'; +import type { Frame } from '../types/Frame'; +/** + * Create a new Frame Processor function which you can pass to the ``. + * (See ["Frame Processors"](https://react-native-vision-camera.com/docs/guides/frame-processors)) + * + * Make sure to add the `'worklet'` directive to the top of the Frame Processor function, otherwise it will not get compiled into a worklet. + * + * Also make sure to memoize the returned object, so that the Camera doesn't reset the Frame Processor Context each time. + * @worklet + */ +export declare function createFrameProcessor(frameProcessor: (frame: Frame) => void): ReadonlyFrameProcessor; +/** + * Returns a memoized Frame Processor function wich you can pass to the ``. + * (See ["Frame Processors"](https://react-native-vision-camera.com/docs/guides/frame-processors)) + * + * Make sure to add the `'worklet'` directive to the top of the Frame Processor function, otherwise it will not get compiled into a worklet. + * + * @worklet + * @param frameProcessor The Frame Processor + * @param dependencies The React dependencies which will be copied into the VisionCamera JS-Runtime. + * @returns The memoized Frame Processor. + * @example + * ```ts + * const frameProcessor = useFrameProcessor((frame) => { + * 'worklet' + * const faces = scanFaces(frame) + * console.log(`Faces: ${faces}`) + * }, []) + * ``` + */ +export declare function useFrameProcessor(frameProcessor: (frame: Frame) => void, dependencies: DependencyList): ReadonlyFrameProcessor; +//# sourceMappingURL=useFrameProcessor.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/hooks/useFrameProcessor.d.ts.map b/package/lib/typescript/hooks/useFrameProcessor.d.ts.map new file mode 100644 index 0000000000..a7f27e984d --- /dev/null +++ b/package/lib/typescript/hooks/useFrameProcessor.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"useFrameProcessor.d.ts","sourceRoot":"","sources":["../../../src/hooks/useFrameProcessor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAA;AAG3C,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAA;AAClE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AAE3C;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,cAAc,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,sBAAsB,CAKnG;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,iBAAiB,CAAC,cAAc,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,EAAE,YAAY,EAAE,cAAc,GAAG,sBAAsB,CAG9H"} \ No newline at end of file diff --git a/package/lib/typescript/index.d.ts b/package/lib/typescript/index.d.ts new file mode 100644 index 0000000000..e5d7909f4d --- /dev/null +++ b/package/lib/typescript/index.d.ts @@ -0,0 +1,27 @@ +export * from './Camera'; +export * from './CameraError'; +export * from './types/CameraDevice'; +export * from './types/CameraProps'; +export * from './types/Frame'; +export * from './types/Orientation'; +export * from './types/OutputOrientation'; +export * from './types/PhotoFile'; +export * from './types/Snapshot'; +export * from './types/PixelFormat'; +export * from './types/Point'; +export * from './types/VideoFile'; +export * from './types/CodeScanner'; +export * from './devices/getCameraFormat'; +export * from './devices/getCameraDevice'; +export * from './devices/Templates'; +export * from './hooks/useCameraDevice'; +export * from './hooks/useCameraDevices'; +export * from './hooks/useCameraFormat'; +export * from './hooks/useCameraPermission'; +export * from './hooks/useCodeScanner'; +export * from './hooks/useFrameProcessor'; +export * from './frame-processors/runAsync'; +export * from './frame-processors/runAtTargetFps'; +export * from './frame-processors/VisionCameraProxy'; +export * from './skia/useSkiaFrameProcessor'; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/index.d.ts.map b/package/lib/typescript/index.d.ts.map new file mode 100644 index 0000000000..96ec52f735 --- /dev/null +++ b/package/lib/typescript/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,cAAc,UAAU,CAAA;AACxB,cAAc,eAAe,CAAA;AAG7B,cAAc,sBAAsB,CAAA;AACpC,cAAc,qBAAqB,CAAA;AACnC,cAAc,eAAe,CAAA;AAC7B,cAAc,qBAAqB,CAAA;AACnC,cAAc,2BAA2B,CAAA;AACzC,cAAc,mBAAmB,CAAA;AACjC,cAAc,kBAAkB,CAAA;AAChC,cAAc,qBAAqB,CAAA;AACnC,cAAc,eAAe,CAAA;AAC7B,cAAc,mBAAmB,CAAA;AACjC,cAAc,qBAAqB,CAAA;AAGnC,cAAc,2BAA2B,CAAA;AACzC,cAAc,2BAA2B,CAAA;AACzC,cAAc,qBAAqB,CAAA;AAGnC,cAAc,yBAAyB,CAAA;AACvC,cAAc,0BAA0B,CAAA;AACxC,cAAc,yBAAyB,CAAA;AACvC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,wBAAwB,CAAA;AACtC,cAAc,2BAA2B,CAAA;AAGzC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,mCAAmC,CAAA;AAEjD,cAAc,sCAAsC,CAAA;AAGpD,cAAc,8BAA8B,CAAA"} \ No newline at end of file diff --git a/package/lib/typescript/skia/SkiaCameraCanvas.d.ts b/package/lib/typescript/skia/SkiaCameraCanvas.d.ts new file mode 100644 index 0000000000..a3b1574942 --- /dev/null +++ b/package/lib/typescript/skia/SkiaCameraCanvas.d.ts @@ -0,0 +1,21 @@ +import React from 'react'; +import type { ViewProps } from 'react-native'; +import type { CameraProps } from '../types/CameraProps'; +import type { ISharedValue } from 'react-native-worklets-core'; +import type { SkImage } from '@shopify/react-native-skia'; +interface SkiaCameraCanvasProps extends ViewProps { + /** + * The offscreen textures queue that have been rendered by the Skia Frame Processor. + * + * This view will always pop the latest Texture from this queue and render it. + */ + offscreenTextures: ISharedValue; + /** + * The resize mode to use for displaying the feed + */ + resizeMode: CameraProps['resizeMode']; +} +declare function SkiaCameraCanvasImpl({ offscreenTextures, resizeMode, children, ...props }: SkiaCameraCanvasProps): React.ReactElement; +export declare const SkiaCameraCanvas: React.MemoExoticComponent; +export {}; +//# sourceMappingURL=SkiaCameraCanvas.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/skia/SkiaCameraCanvas.d.ts.map b/package/lib/typescript/skia/SkiaCameraCanvas.d.ts.map new file mode 100644 index 0000000000..59d40d95ba --- /dev/null +++ b/package/lib/typescript/skia/SkiaCameraCanvas.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"SkiaCameraCanvas.d.ts","sourceRoot":"","sources":["../../../src/skia/SkiaCameraCanvas.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAgC,MAAM,OAAO,CAAA;AACpD,OAAO,KAAK,EAAqB,SAAS,EAAE,MAAM,cAAc,CAAA;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAC9D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAA;AAIzD,UAAU,qBAAsB,SAAQ,SAAS;IAC/C;;;;OAIG;IACH,iBAAiB,EAAE,YAAY,CAAC,OAAO,EAAE,CAAC,CAAA;IAC1C;;OAEG;IACH,UAAU,EAAE,WAAW,CAAC,YAAY,CAAC,CAAA;CACtC;AAED,iBAAS,oBAAoB,CAAC,EAAE,iBAAiB,EAAE,UAAoB,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAE,EAAE,qBAAqB,GAAG,KAAK,CAAC,YAAY,CAiCxI;AAED,eAAO,MAAM,gBAAgB,wDAAmC,CAAA"} \ No newline at end of file diff --git a/package/lib/typescript/skia/useSkiaFrameProcessor.d.ts b/package/lib/typescript/skia/useSkiaFrameProcessor.d.ts new file mode 100644 index 0000000000..bbd206917d --- /dev/null +++ b/package/lib/typescript/skia/useSkiaFrameProcessor.d.ts @@ -0,0 +1,92 @@ +import type { Frame } from '../types/Frame'; +import type { DependencyList } from 'react'; +import type { DrawableFrameProcessor } from '../types/CameraProps'; +import type { ISharedValue, IWorkletNativeApi } from 'react-native-worklets-core'; +import type { SkCanvas, SkPaint, SkImage, SkSurface } from '@shopify/react-native-skia'; +import type { Orientation } from '../types/Orientation'; +/** + * Represents a Camera Frame that can be directly drawn to using Skia. + * + * @see {@linkcode useSkiaFrameProcessor} + * @see {@linkcode render} + */ +export interface DrawableFrame extends Frame, SkCanvas { + /** + * Renders the Camera Frame to the Canvas. + * @param paint An optional Paint object, for example for applying filters/shaders to the Camera Frame. + */ + render(paint?: SkPaint): void; + /** + * A private property that holds the SkImage. + * @internal + */ + readonly __skImage: SkImage; + /** + * A private method to dispose the internally created Texture after rendering has completed. + * @internal + */ + dispose(): void; +} +type ThreadID = ReturnType; +type SurfaceCache = Record; +/** + * Create a new Frame Processor function which you can pass to the ``. + * (See ["Frame Processors"](https://react-native-vision-camera.com/docs/guides/frame-processors)) + * + * Make sure to add the `'worklet'` directive to the top of the Frame Processor function, otherwise it will not get compiled into a worklet. + * + * Also make sure to memoize the returned object, so that the Camera doesn't reset the Frame Processor Context each time. + * + * @worklet + * @example + * ```ts + * const surfaceHolder = Worklets.createSharedValue({}) + * const offscreenTextures = Worklets.createSharedValue([]) + * const frameProcessor = createSkiaFrameProcessor((frame) => { + * 'worklet' + * const faces = scanFaces(frame) + * + * frame.render() + * for (const face of faces) { + * const rect = Skia.XYWHRect(face.x, face.y, face.width, face.height) + * frame.drawRect(rect) + * } + * }, surfaceHolder, offscreenTextures) + * ``` + */ +export declare function createSkiaFrameProcessor(frameProcessor: (frame: DrawableFrame) => void, surfaceHolder: ISharedValue, offscreenTextures: ISharedValue, previewOrientation: ISharedValue): DrawableFrameProcessor; +/** + * Returns a memoized Skia Frame Processor function wich you can pass to the ``. + * + * The Skia Frame Processor alows you to draw ontop of the Frame, and will manage it's internal offscreen Skia Canvas + * and onscreen Skia preview view. + * + * (See ["Frame Processors"](https://react-native-vision-camera.com/docs/guides/frame-processors)) + * + * Make sure to add the `'worklet'` directive to the top of the Frame Processor function, otherwise it will not get compiled into a worklet. + * + * @worklet + * @param frameProcessor The Frame Processor + * @param dependencies The React dependencies which will be copied into the VisionCamera JS-Runtime. + * @returns The memoized Skia Frame Processor. + * @example + * ```ts + * const frameProcessor = useSkiaFrameProcessor((frame) => { + * 'worklet' + * const faces = scanFaces(frame) + * + * frame.render() + * for (const face of faces) { + * const rect = Skia.XYWHRect(face.x, face.y, face.width, face.height) + * frame.drawRect(rect) + * } + * }, []) + * ``` + */ +export declare function useSkiaFrameProcessor(frameProcessor: (frame: DrawableFrame) => void, dependencies: DependencyList): DrawableFrameProcessor; +export {}; +//# sourceMappingURL=useSkiaFrameProcessor.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/skia/useSkiaFrameProcessor.d.ts.map b/package/lib/typescript/skia/useSkiaFrameProcessor.d.ts.map new file mode 100644 index 0000000000..8655f8d822 --- /dev/null +++ b/package/lib/typescript/skia/useSkiaFrameProcessor.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"useSkiaFrameProcessor.d.ts","sourceRoot":"","sources":["../../../src/skia/useSkiaFrameProcessor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAiB,MAAM,gBAAgB,CAAA;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAA;AAE3C,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAA;AAClE,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAA;AACjF,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAA;AAKvF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAEvD;;;;;GAKG;AACH,MAAM,WAAW,aAAc,SAAQ,KAAK,EAAE,QAAQ;IACpD;;;OAGG;IACH,MAAM,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,IAAI,CAAA;IAC7B;;;OAGG;IACH,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;IAC3B;;;OAGG;IACH,OAAO,IAAI,IAAI,CAAA;CAChB;AAKD,KAAK,QAAQ,GAAG,UAAU,CAAC,iBAAiB,CAAC,oBAAoB,CAAC,CAAC,CAAA;AACnE,KAAK,YAAY,GAAG,MAAM,CACxB,QAAQ,EACR;IACE,OAAO,EAAE,SAAS,CAAA;IAClB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf,CACF,CAAA;AAgGD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,wBAAwB,CACtC,cAAc,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,EAC9C,aAAa,EAAE,YAAY,CAAC,YAAY,CAAC,EACzC,iBAAiB,EAAE,YAAY,CAAC,OAAO,EAAE,CAAC,EAC1C,kBAAkB,EAAE,YAAY,CAAC,WAAW,CAAC,GAC5C,sBAAsB,CA+HxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,qBAAqB,CACnC,cAAc,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,EAC9C,YAAY,EAAE,cAAc,GAC3B,sBAAsB,CA6BxB"} \ No newline at end of file diff --git a/package/lib/typescript/types/CameraDevice.d.ts b/package/lib/typescript/types/CameraDevice.d.ts new file mode 100644 index 0000000000..5a98a79fca --- /dev/null +++ b/package/lib/typescript/types/CameraDevice.d.ts @@ -0,0 +1,232 @@ +import type { Orientation } from './Orientation'; +/** + * Represents the camera device position. + * + * * `"back"`: Indicates that the device is physically located on the back of the phone + * * `"front"`: Indicates that the device is physically located on the front of the phone + * * `"external"`: The camera device is an external camera, and has no fixed facing relative to the phone. (e.g. USB or Continuity Cameras) + */ +export type CameraPosition = 'front' | 'back' | 'external'; +/** + * Indentifiers for a physical camera (one that actually exists on the back/front of the device) + * + * * `"ultra-wide-angle-camera"`: A built-in camera with a shorter focal length than that of a wide-angle camera. (FOV of 94° or higher) + * * `"wide-angle-camera"`: A built-in wide-angle camera. (FOV between 60° and 94°) + * * `"telephoto-camera"`: A built-in camera device with a longer focal length than a wide-angle camera. (FOV of 60° or lower) + * + * Some Camera devices consist of multiple physical devices. They can be interpreted as _logical devices_, for example: + * + * * `"ultra-wide-angle-camera"` + `"wide-angle-camera"` = **dual wide-angle camera**. + * * `"wide-angle-camera"` + `"telephoto-camera"` = **dual camera**. + * * `"ultra-wide-angle-camera"` + `"wide-angle-camera"` + `"telephoto-camera"` = **triple camera**. + */ +export type PhysicalCameraDeviceType = 'ultra-wide-angle-camera' | 'wide-angle-camera' | 'telephoto-camera'; +/** + * Indicates a format's autofocus system. + * + * * `"none"`: Indicates that autofocus is not available + * * `"contrast-detection"`: Indicates that autofocus is achieved by contrast detection. Contrast detection performs a focus scan to find the optimal position + * * `"phase-detection"`: Indicates that autofocus is achieved by phase detection. Phase detection has the ability to achieve focus in many cases without a focus scan. Phase detection autofocus is typically less visually intrusive than contrast detection autofocus + */ +export type AutoFocusSystem = 'contrast-detection' | 'phase-detection' | 'none'; +/** + * Indicates a format's supported video stabilization mode. Enabling video stabilization may introduce additional latency into the video capture pipeline. + * + * * `"off"`: No video stabilization. Indicates that video should not be stabilized + * * `"standard"`: Standard software-based video stabilization. Standard video stabilization reduces the field of view by about 10%. + * * `"cinematic"`: Advanced software-based video stabilization. This applies more aggressive cropping or transformations than standard. + * * `"cinematic-extended"`: Extended software- and hardware-based stabilization that aggressively crops and transforms the video to apply a smooth cinematic stabilization. + * * `"auto"`: Indicates that the most appropriate video stabilization mode for the device and format should be chosen automatically + */ +export type VideoStabilizationMode = 'off' | 'standard' | 'cinematic' | 'cinematic-extended' | 'auto'; +/** + * A Camera Device's stream-configuration format. + * + * A format specifies: + * - Video Resolution (`videoWidth`/`videoHeight`) + * - Photo Resolution (`photoWidth`/`photoHeight`) + * - Possible FPS ranges (`fps`) + * - Video Stabilization Modes (`videoStabilizationModes`) + */ +export interface CameraDeviceFormat { + /** + * The height of the highest resolution a still image (photo) can be produced in + */ + photoHeight: number; + /** + * The width of the highest resolution a still image (photo) can be produced in + */ + photoWidth: number; + /** + * The video resolutions's height + */ + videoHeight: number; + /** + * The video resolution's width + */ + videoWidth: number; + /** + * Maximum supported ISO value + */ + maxISO: number; + /** + * Minimum supported ISO value + */ + minISO: number; + /** + * The video field of view in degrees + */ + fieldOfView: number; + /** + * Specifies whether this format supports HDR mode for video capture + */ + supportsVideoHdr: boolean; + /** + * Specifies whether this format supports HDR mode for photo capture + */ + supportsPhotoHdr: boolean; + /** + * Specifies whether this format supports delivering depth data for photo or video capture. + */ + supportsDepthCapture: boolean; + /** + * The minum frame rate this Format needs to run at. High resolution formats often run at lower frame rates. + */ + minFps: number; + /** + * The maximum frame rate this Format is able to run at. High resolution formats often run at lower frame rates. + */ + maxFps: number; + /** + * Specifies this format's auto focus system. + */ + autoFocusSystem: AutoFocusSystem; + /** + * All supported video stabilization modes + */ + videoStabilizationModes: VideoStabilizationMode[]; +} +/** + * Represents a camera device discovered by the {@linkcode Camera.getAvailableCameraDevices | Camera.getAvailableCameraDevices()} function + */ +export interface CameraDevice { + /** + * The native ID of the camera device instance. + */ + id: string; + /** + * The physical devices this `CameraDevice` consists of. + * + * * If this camera device is a **logical camera** (combination of multiple physical cameras, e.g. "Triple Camera"), there are multiple cameras in this array. + * * If this camera device is a **physical camera** (e.g. "wide-angle-camera"), there is only a single element in this array. + * + * You can check if the camera is a logical multi-camera by using the `isMultiCam` property. + */ + physicalDevices: PhysicalCameraDeviceType[]; + /** + * Specifies the physical position of this camera. + * - `back`: The Camera Device is located on the back of the phone. These devices can be used for capturing what's in front of the user. + * - `front`: The Camera Device is located on the front of the phone. These devices can be used for selfies or FaceTime. + * - `external`: The Camera Device is an external device. These devices can be either: + * - USB Camera Devices (if they support the [USB Video Class (UVC) Specification](https://en.wikipedia.org/wiki/List_of_USB_video_class_devices)) + * - [Continuity Camera Devices](https://support.apple.com/en-us/HT213244) (e.g. your iPhone's or Mac's Camera connected through WiFi/Continuity) + * - Bluetooth/WiFi Camera Devices (if they are supported in the platform-native Camera APIs; Camera2 and AVFoundation) + */ + position: CameraPosition; + /** + * A friendly localized name describing the camera. + */ + name: string; + /** + * Specifies whether this camera supports enabling flash for photo capture. + */ + hasFlash: boolean; + /** + * Specifies whether this camera supports continuously enabling the flash to act like a torch (flash with video capture) + */ + hasTorch: boolean; + /** + * The minimum distance this device can properly focus to (in centimeters/cm) or `0` if unknown. + */ + minFocusDistance: number; + /** + * A property indicating whether the device is a virtual multi-camera consisting of multiple combined physical cameras. + * + * Examples: + * * The Dual Camera, which supports seamlessly switching between a wide and telephoto camera while zooming and generating depth data from the disparities between the different points of view of the physical cameras. + * * The TrueDepth Camera, which generates depth data from disparities between a YUV camera and an Infrared camera pointed in the same direction. + */ + isMultiCam: boolean; + /** + * Minimum available zoom factor (e.g. `1`) + */ + minZoom: number; + /** + * Maximum available zoom factor (e.g. `128`) + */ + maxZoom: number; + /** + * The zoom factor where the camera is "neutral". + * + * * For single-physical cameras this property is always `1.0`. + * * For multi cameras this property is a value between `minZoom` and `maxZoom`, where the camera is in _wide-angle_ mode and hasn't switched to the _ultra-wide-angle_ ("fish-eye") or telephoto camera yet. + * + * Use this value as an initial value for the zoom property if you implement custom zoom. (e.g. reanimated shared value should be initially set to this value) + * @example + * const device = ... + * + * const zoom = useSharedValue(device.neutralZoom) // <-- initial value so it doesn't start at ultra-wide + * const cameraProps = useAnimatedProps(() => ({ + * zoom: zoom.value + * })) + */ + neutralZoom: number; + /** + * The minimum Exposure-Bias value this format supports. When setting the `exposure` to this value, the image is almost completely dark (under-exposed). + */ + minExposure: number; + /** + * The maximum Exposure-Bias value this format supports. When setting the `exposure` to this value, the image is almost completely bright (over-exposed). + */ + maxExposure: number; + /** + * All available formats for this camera device. Use this to find the best format for your use case and set it to the Camera's {@linkcode CameraProps.format | Camera's .format} property. + * + * See [the Camera Formats documentation](https://react-native-vision-camera.com/docs/guides/formats) for more information about Camera Formats. + */ + formats: CameraDeviceFormat[]; + /** + * Whether this camera device supports low light boost. + */ + supportsLowLightBoost: boolean; + /** + * Whether this camera supports taking photos in RAW format + * + * **! Work in Progress !** + */ + supportsRawCapture: boolean; + /** + * Specifies whether this device supports focusing ({@linkcode Camera.focus | Camera.focus(...)}) + */ + supportsFocus: boolean; + /** + * The hardware level of the Camera. + * - On Android, some older devices are running at a `legacy` or `limited` level which means they are running in a backwards compatible mode. + * - On iOS, all devices are `full`. + */ + hardwareLevel: 'legacy' | 'limited' | 'full'; + /** + * Represents the sensor's orientation relative to the phone. + * For most phones this will be landscape, as Camera sensors are usually always rotated by 90 degrees (i.e. width and height are flipped). + * + * All Camera streams will stream in this orientation. To properly rotate the buffers "up-right", + * frames will need to be counter-rotated by this orientation here. + * - For photo and video capture this is handled using EXIF flags. + * - For preview this is handled using view transforms (rotate + translate matrix). + * - For frame processors this needs to be handled manually by the user (see `Frame.orientation`) + * + * @see See ["Orientation"](https://react-native-vision-camera.com/docs/guides/orientation) + */ + sensorOrientation: Orientation; +} +//# sourceMappingURL=CameraDevice.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/types/CameraDevice.d.ts.map b/package/lib/typescript/types/CameraDevice.d.ts.map new file mode 100644 index 0000000000..2a92ee2c72 --- /dev/null +++ b/package/lib/typescript/types/CameraDevice.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"CameraDevice.d.ts","sourceRoot":"","sources":["../../../src/types/CameraDevice.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAEhD;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,MAAM,GAAG,UAAU,CAAA;AAE1D;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,wBAAwB,GAAG,yBAAyB,GAAG,mBAAmB,GAAG,kBAAkB,CAAA;AAE3G;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG,oBAAoB,GAAG,iBAAiB,GAAG,MAAM,CAAA;AAE/E;;;;;;;;GAQG;AACH,MAAM,MAAM,sBAAsB,GAAG,KAAK,GAAG,UAAU,GAAG,WAAW,GAAG,oBAAoB,GAAG,MAAM,CAAA;AAErG;;;;;;;;GAQG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,WAAW,EAAE,MAAM,CAAA;IACnB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAA;IAClB;;OAEG;IACH,WAAW,EAAE,MAAM,CAAA;IACnB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAA;IAClB;;OAEG;IACH,MAAM,EAAE,MAAM,CAAA;IACd;;OAEG;IACH,MAAM,EAAE,MAAM,CAAA;IACd;;OAEG;IACH,WAAW,EAAE,MAAM,CAAA;IACnB;;OAEG;IACH,gBAAgB,EAAE,OAAO,CAAA;IACzB;;OAEG;IACH,gBAAgB,EAAE,OAAO,CAAA;IACzB;;OAEG;IACH,oBAAoB,EAAE,OAAO,CAAA;IAC7B;;OAEG;IACH,MAAM,EAAE,MAAM,CAAA;IACd;;OAEG;IACH,MAAM,EAAE,MAAM,CAAA;IACd;;OAEG;IACH,eAAe,EAAE,eAAe,CAAA;IAChC;;OAEG;IACH,uBAAuB,EAAE,sBAAsB,EAAE,CAAA;CAClD;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;OAEG;IACH,EAAE,EAAE,MAAM,CAAA;IACV;;;;;;;OAOG;IACH,eAAe,EAAE,wBAAwB,EAAE,CAAA;IAC3C;;;;;;;;OAQG;IACH,QAAQ,EAAE,cAAc,CAAA;IACxB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ;;OAEG;IACH,QAAQ,EAAE,OAAO,CAAA;IACjB;;OAEG;IACH,QAAQ,EAAE,OAAO,CAAA;IACjB;;OAEG;IACH,gBAAgB,EAAE,MAAM,CAAA;IACxB;;;;;;OAMG;IACH,UAAU,EAAE,OAAO,CAAA;IACnB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAA;IACf;;OAEG;IACH,OAAO,EAAE,MAAM,CAAA;IACf;;;;;;;;;;;;;;OAcG;IACH,WAAW,EAAE,MAAM,CAAA;IACnB;;OAEG;IACH,WAAW,EAAE,MAAM,CAAA;IACnB;;OAEG;IACH,WAAW,EAAE,MAAM,CAAA;IACnB;;;;OAIG;IACH,OAAO,EAAE,kBAAkB,EAAE,CAAA;IAC7B;;OAEG;IACH,qBAAqB,EAAE,OAAO,CAAA;IAC9B;;;;OAIG;IACH,kBAAkB,EAAE,OAAO,CAAA;IAC3B;;OAEG;IACH,aAAa,EAAE,OAAO,CAAA;IACtB;;;;OAIG;IACH,aAAa,EAAE,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAA;IAC5C;;;;;;;;;;;OAWG;IACH,iBAAiB,EAAE,WAAW,CAAA;CAC/B"} \ No newline at end of file diff --git a/package/lib/typescript/types/CameraProps.d.ts b/package/lib/typescript/types/CameraProps.d.ts new file mode 100644 index 0000000000..80912413c9 --- /dev/null +++ b/package/lib/typescript/types/CameraProps.d.ts @@ -0,0 +1,389 @@ +import type { ViewProps } from 'react-native'; +import type { CameraDevice, CameraDeviceFormat, VideoStabilizationMode } from './CameraDevice'; +import type { CameraRuntimeError } from '../CameraError'; +import type { CodeScanner } from './CodeScanner'; +import type { Frame } from './Frame'; +import type { ISharedValue } from 'react-native-worklets-core'; +import type { SkImage } from '@shopify/react-native-skia'; +import type { OutputOrientation } from './OutputOrientation'; +import type { Orientation } from './Orientation'; +export interface ReadonlyFrameProcessor { + frameProcessor: (frame: Frame) => void; + type: 'readonly'; +} +export interface DrawableFrameProcessor { + frameProcessor: (frame: Frame) => void; + type: 'drawable-skia'; + offscreenTextures: ISharedValue; + previewOrientation: ISharedValue; +} +export interface OnShutterEvent { + /** + * The type of the media that was captured in this `onShutter` event. + */ + type: 'photo' | 'snapshot'; +} +export interface CameraProps extends ViewProps { + /** + * The Camera Device to use. + * + * See the [Camera Devices](https://react-native-vision-camera.com/docs/guides/devices) section in the documentation for more information about Camera Devices. + * + * @example + * ```tsx + * const device = useCameraDevice('back') + * + * if (device == null) return + * return ( + * + * ) + * ``` + */ + device: CameraDevice; + /** + * Whether the Camera should actively stream video frames, or not. See the [documentation about the `isActive` prop](https://react-native-vision-camera.com/docs/guides/lifecycle#the-isactive-prop) for more information. + * + * This can be compared to a Video component, where `isActive` specifies whether the video is paused or not. + * + * @note If you fully unmount the `` component instead of using `isActive={false}`, the Camera will take a bit longer to start again. In return, it will use less resources since the Camera will be completely destroyed when unmounted. + */ + isActive: boolean; + /** + * Enables **preview** streaming. + * + * Preview is enabled by default, and disabled when using a Skia Frame Processor as + * Skia will use the video stream as it's preview. + * @default true + */ + preview?: boolean; + /** + * Enables **photo capture** with the `takePhoto` function (see ["Taking Photos"](https://react-native-vision-camera.com/docs/guides/taking-photos)) + */ + photo?: boolean; + /** + * Enables **video capture** with the `startRecording` function (see ["Recording Videos"](https://react-native-vision-camera.com/docs/guides/recording-videos)) + */ + video?: boolean; + /** + * Enables **audio capture** for video recordings (see ["Recording Videos"](https://react-native-vision-camera.com/docs/guides/recording-videos)) + * + * Note: Requires audio permission. + */ + audio?: boolean; + /** + * Specifies the pixel format of Frames streamed from a [Frame Processor](https://react-native-vision-camera.com/docs/guides/frame-processors). + * + * While `'yuv'` is the most efficient format, some ML models (such as TensorFlow Face Detection Models) require input Frames to be in RGB colorspace, otherwise they just output nonsense. + * + * The following values are supported: + * + * - `yuv`: The YUV (Y'CbCr 4:2:0 or NV21, 8-bit) format, either video- or full-range, depending on hardware capabilities. This is the most efficient format. + * - `rgb`: The RGB (RGBA or BGRA, 8-bit) format. This is less efficient format and sometimes requires explicit conversion. + * + * @default 'yuv' + */ + pixelFormat?: 'yuv' | 'rgb'; + /** + * Enables location streaming to add GPS EXIF tags to captured photos and videos. + * + * Note: Requires location permission. + * + * Note: This property will throw a `system/location-not-enabled` error if the Location APIs are not enabled at build-time. + * See [the "GPS Location Tags" documentation](https://react-native-vision-camera.com/docs/guides/location) for more information. + */ + enableLocation?: boolean; + /** + * Set the current torch mode. + * + * Make sure the given {@linkcode device} has a torch (see {@linkcode CameraDevice.hasTorch device.hasTorch}). + * + * @default "off" + */ + torch?: 'off' | 'on'; + /** + * Specifies the zoom factor of the current camera, in "factor"/scale. + * + * This value ranges from `minZoom` (e.g. `1`) to `maxZoom` (e.g. `128`). It is recommended to set this value + * to the CameraDevice's `neutralZoom` per default and let the user zoom out to the fish-eye (ultra-wide) camera + * on demand (if available) + * + * **Note:** Linearly increasing this value always appears logarithmic to the user. + * + * @default 1.0 + */ + zoom?: number; + /** + * Enables or disables the native pinch to zoom gesture. + * + * If you want to implement a custom zoom gesture, see [the Zooming with Reanimated documentation](https://react-native-vision-camera.com/docs/guides/zooming). + * + * @default false + */ + enableZoomGesture?: boolean; + /** + * Specifies the Exposure bias of the current camera. A lower value means darker images, a higher value means brighter images. + * + * The Camera will still continue to auto-adjust exposure and focus, but will premultiply the exposure setting with the provided value here. + * + * This values ranges from {@linkcode CameraDevice.minExposure device.minExposure} to {@linkcode CameraDevice.maxExposure device.maxExposure}. + * + * The value between min- and max supported exposure is considered the default, neutral value. + */ + exposure?: number; + /** + * Selects a given format. By default, the best matching format is chosen. See {@linkcode CameraDeviceFormat} + * + * The format defines the possible values for properties like: + * - {@linkcode fps}: `format.minFps`...`format.maxFps` + * - {@linkcode videoHdr}: `format.supportsVideoHdr` + * - {@linkcode photoHdr}: `format.supportsPhotoHdr` + * - {@linkcode enableDepthData}: `format.supportsDepthCapture` + * - {@linkcode videoStabilizationMode}: `format.videoStabilizationModes` + * + * In other words; {@linkcode enableDepthData} can only be set to true if {@linkcode CameraDeviceFormat.supportsDepthCapture format.supportsDepthCapture} is true. + */ + format?: CameraDeviceFormat; + /** + * Specifies the Preview's resize mode. + * - `"cover"`: Keep aspect ratio and fill entire parent view (centered). + * - `"contain"`: Keep aspect ratio and make sure the entire content is visible inside the parent view, even if it introduces additional blank areas (centered). + * + * @default "cover" + */ + resizeMode?: 'cover' | 'contain'; + /** + * Specifies the implementation mode for the Preview View on Android. + * - `"surface-view"`: Uses a [`SurfaceView`](https://developer.android.com/reference/android/view/SurfaceView) for rendering. + * This is more efficient and supports HDR rendering, but doesn't support masks, transparency, rotations or clipping. + * - `"texture-view"`: Uses a [`TextureView`](https://developer.android.com/reference/android/view/TextureView) for rendering. + * This is less efficient and doesn't support HDR rendering, but supports masks, transparency, rotations and clipping. + * + * @default 'surface-view' + */ + androidPreviewViewType?: 'surface-view' | 'texture-view'; + /** + * Specify a the number of frames per second this camera should stream frames at. + * + * - If `fps` is a single number, the Camera will be streaming at a fixed FPS value. + * - If `fps` is a tuple/array, the Camera will be free to choose a FPS value between `minFps` and `maxFps`, + * depending on current lighting conditions. Allowing a lower `minFps` value can result in better photos + * and videos, as the Camera can take more time to properly receive light for frames. + * + * Make sure the given {@linkcode format} can stream at the target {@linkcode fps} value (see {@linkcode CameraDeviceFormat.minFps format.minFps} and {@linkcode CameraDeviceFormat.maxFps format.maxFps}). + */ + fps?: number | [minFps: number, maxFps: number]; + /** + * Enables or disables HDR Video Streaming for Preview, Video and Frame Processor via a 10-bit wide-color pixel format. + * + * Make sure the given {@linkcode format} supports HDR (see {@linkcode CameraDeviceFormat.supportsVideoHdr format.supportsVideoHdr}). + */ + videoHdr?: boolean; + /** + * Enables or disables HDR Photo Capture via a double capture routine that combines low- and high exposure photos. + * + * On Android, {@linkcode photoHdr} uses a vendor-specific "HDR" extension which is not compatible with {@linkcode videoHdr}, + * so only one of video- or photo-HDR can be enabled at a time. + * + * Make sure the given {@linkcode format} supports HDR (see {@linkcode CameraDeviceFormat.supportsPhotoHdr format.supportsPhotoHdr}). + */ + photoHdr?: boolean; + /** + * Configures the photo pipeline for a specific quality balance prioritization. + * - `'speed'`: Prioritizes fast capture speed over quality (faster edge-detection, distortion correction, AF/AE/AWB times, etc.) + * - `'balanced'`: A balanced set of prioritization configurations + * - `'quality'`: Prioritizes high quality capture over speed (higher accuracy edge-detection, distortion correction, AF/AE/AWB times, etc.) + * + * @default 'balanced' + */ + photoQualityBalance?: 'speed' | 'balanced' | 'quality'; + /** + * LightOS: Configures the compression quality of saved images. + * Accepts values of 0-100 + * See docs: + * https://developer.android.com/reference/androidx/camera/core/ImageCapture.Builder#setJpegQuality(int) + * @default 100 + */ + jpegCompressionQuality?: number; + /** + * Enables or disables lossy buffer compression for the video stream. + * If you only use {@linkcode video} or a {@linkcode frameProcessor}, this + * can increase the efficiency and lower memory usage of the Camera. + * + * If buffer compression is enabled, the video pipeline will try to use a + * lossy-compressed pixel format instead of the normal one. + * + * If you use a {@linkcode frameProcessor}, you might need to change how pixels + * are read inside your native frame processor function as this is different + * from the usual `yuv` or `rgb` layout. + * + * If buffer compression is not available but this property is enabled, the normal + * pixel formats will be used and no error will be thrown. + * + * @platform iOS + * @default + * - true // if frameProcessor={undefined} + * - false // otherwise + */ + enableBufferCompression?: boolean; + /** + * Enables or disables low-light boost on this camera device. + * + * Enabling low light boost allows the FPS rate to be throttled to up to half of what it is set to to allow for more + * exposure in low light conditions. + * + * On Android, {@linkcode lowLightBoost} might even use a vendor-specific "night-mode" extension to allow for even more visibility in low-light conditions. + * + * Make sure the given {@linkcode device} supports low-light-boost (see {@linkcode CameraDevice.supportsLowLightBoost device.supportsLowLightBoost}). + */ + lowLightBoost?: boolean; + /** + * Specifies the video stabilization mode to use. + * + * Make sure the given {@linkcode format} supports the given {@linkcode videoStabilizationMode}. + */ + videoStabilizationMode?: VideoStabilizationMode; + /** + * Enables or disables depth data delivery for photo capture. + * + * Make sure the given {@linkcode format} supports depth data (see {@linkcode CameraDeviceFormat.supportsDepthCapture format.supportsDepthCapture}). + * + * @default false + */ + enableDepthData?: boolean; + /** + * A boolean specifying whether the photo render pipeline is prepared for portrait effects matte delivery. + * + * When enabling this, you must also set `enableDepthData` to `true`. + * + * @platform iOS 12.0+ + * @default false + */ + enablePortraitEffectsMatteDelivery?: boolean; + /** + * If `true`, show a debug view to display the FPS of the Video Pipeline (Frame Processor). + * This is useful for debugging your Frame Processor's speed. + * + * @default false + */ + enableFpsGraph?: boolean; + /** + * Sets the orientation of all Camera Outputs (Photo, Snapshot and Video). + * + * - `'preview'`: Use the same orientation as the preview view. If the device rotation is locked, the user cannot take photos or videos in different orientations. + * - `'device'`: Use whatever orientation the device is held in, even if the preview view is not rotated to that orientation. If the device rotation is locked, the user can still rotate his phone to take photos or videos in different orientations than the preview view. + * + * @note Preview orientation will not be affected by this property, as it is always dependant on screen orientation + * @note Frame Processors will not be affected by this property, as their buffer size (respective to {@linkcode Frame.orientation}) is always the same + * @see See [the Orientation documentation](https://react-native-vision-camera.com/docs/guides/orientation) for more information + * @default 'device' + */ + outputOrientation?: OutputOrientation; + /** + * Enables or disables mirroring of outputs alongside the vertical axis. + * + * Mirroring only affects the photo-, video-, or snapshot-output, but not preview. + * The Preview is always mirrored for front cameras, and not mirrored for back cameras. + * + * @default false (back camera), true (front camera) + */ + isMirrored?: boolean; + /** + * Called when any kind of runtime error occured. + */ + onError?: (error: CameraRuntimeError) => void; + /** + * Called when the camera session was successfully initialized and is ready for capture. + * + * At this point, the Camera `ref` can be used and methods like `takePhoto(..)` can be called. + * + * This is called everytime the {@linkcode device} or one of the outputs changes. + */ + onInitialized?: () => void; + /** + * Called when the camera started the session. (`isActive={true}`) + * + * At this point, outputs can start receiving frames from the Camera, but might not have received any yet. + */ + onStarted?: () => void; + /** + * Called when the camera stopped the session. (`isActive={false}`) + * + * At this point, outputs will stop receiving frames from the Camera. + */ + onStopped?: () => void; + /** + * Called when the Preview View has received it's first frame and is now started. + * + * @note This will only be called if {@linkcode preview} is true, and no Skia Frame Processor is used + */ + onPreviewStarted?: () => void; + /** + * Called when the Preview View has stoppped streaming frames and is now stopped. + * + * @note This will only be called if {@linkcode preview} is true, and no Skia Frame Processor is used + */ + onPreviewStopped?: () => void; + /** + * Called just before a photo or snapshot is captured. + * + * Inside this callback you can play a custom shutter sound or show visual feedback to the user. + */ + onShutter?: (event: OnShutterEvent) => void; + /** + * Called whenever the output orientation changed. + * This might happen even if the screen/interface rotation is locked. + * + * @see See ["Orientation"](https://react-native-vision-camera.com/docs/guides/orientation) + */ + onOutputOrientationChanged?: (outputOrientation: Orientation) => void; + /** + * Called whenever the preview orientation changed. + * This will happen whenever the screen/interface rotates. + * + * @see See ["Orientation"](https://react-native-vision-camera.com/docs/guides/orientation) + */ + onPreviewOrientationChanged?: (previewOrientation: Orientation) => void; + /** + * Called whenever the target UI rotation/orientation changes. + * @param uiRotation The degrees that UI elements need to be rotated by to appear up-right. + */ + onUIRotationChanged?: (uiRotation: number) => void; + /** + * A worklet which will be called for every frame the Camera "sees". + * + * @see See [the Frame Processors documentation](https://react-native-vision-camera.com/docs/guides/frame-processors) for more information + * @example + * ```tsx + * const frameProcessor = useFrameProcessor((frame) => { + * 'worklet' + * const faces = scanFaces(frame) + * console.log(`Faces: ${faces}`) + * }, []) + * + * return + * ``` + */ + frameProcessor?: ReadonlyFrameProcessor | DrawableFrameProcessor; + /** + * A CodeScanner that can detect QR-Codes or Barcodes using platform-native APIs. + * + * @see See [the Code Scanner documentation](https://react-native-vision-camera.com/docs/guides/code-scanning) for more information + * @example + * ```tsx + * const codeScanner = useCodeScanner({ + * codeTypes: ['qr', 'ean-13'], + * onCodeScanned: (codes) => { + * console.log(`Scanned ${codes.length} codes!`) + * } + * }) + * + * return + * ``` + */ + codeScanner?: CodeScanner; +} +//# sourceMappingURL=CameraProps.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/types/CameraProps.d.ts.map b/package/lib/typescript/types/CameraProps.d.ts.map new file mode 100644 index 0000000000..73189c63dd --- /dev/null +++ b/package/lib/typescript/types/CameraProps.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"CameraProps.d.ts","sourceRoot":"","sources":["../../../src/types/CameraProps.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/package/lib/typescript/types/CodeScanner.d.ts b/package/lib/typescript/types/CodeScanner.d.ts new file mode 100644 index 0000000000..cbc6ccae91 --- /dev/null +++ b/package/lib/typescript/types/CodeScanner.d.ts @@ -0,0 +1,71 @@ +import type { Point } from './Point'; +/** + * The type of the code to scan. + */ +export type CodeType = 'code-128' | 'code-39' | 'code-93' | 'codabar' | 'ean-13' | 'ean-8' | 'itf' | 'upc-e' | 'upc-a' | 'qr' | 'pdf-417' | 'aztec' | 'data-matrix'; +/** + * The full area that is used for code scanning. In most cases, this is 1280x720 or 1920x1080. + */ +export interface CodeScannerFrame { + /** + * The width of the frame + */ + width: number; + /** + * The height of the frame + */ + height: number; +} +/** + * A scanned code. + */ +export interface Code { + /** + * The type of the code that was scanned. + */ + type: CodeType | 'unknown'; + /** + * The string value, or null if it cannot be decoded. + */ + value?: string; + /** + * The location of the code relative to the Camera Preview (in dp). + */ + frame?: { + x: number; + y: number; + width: number; + height: number; + }; + /** + * The location of each corner relative to the Camera Preview (in dp). + */ + corners?: Point[]; +} +/** + * A scanner for detecting codes in a Camera Stream. + */ +export interface CodeScanner { + /** + * The types of codes to configure the code scanner for. + */ + codeTypes: CodeType[]; + /** + * A callback to call whenever the scanned codes change. + * @param codes The scanned codes, or an empty array if none. + * @param frame The full area that is used for scanning. Code bounds and corners are relative to this frame. + */ + onCodeScanned: (codes: Code[], frame: CodeScannerFrame) => void; + /** + * Crops the scanner's view area to the specific region of interest. + * + * @platform iOS + */ + regionOfInterest?: { + x: number; + y: number; + width: number; + height: number; + }; +} +//# sourceMappingURL=CodeScanner.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/types/CodeScanner.d.ts.map b/package/lib/typescript/types/CodeScanner.d.ts.map new file mode 100644 index 0000000000..cd93ce056d --- /dev/null +++ b/package/lib/typescript/types/CodeScanner.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"CodeScanner.d.ts","sourceRoot":"","sources":["../../../src/types/CodeScanner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAEpC;;GAEG;AACH,MAAM,MAAM,QAAQ,GAChB,UAAU,GACV,SAAS,GACT,SAAS,GACT,SAAS,GACT,QAAQ,GACR,OAAO,GACP,KAAK,GACL,OAAO,GACP,OAAO,GACP,IAAI,GACJ,SAAS,GACT,OAAO,GACP,aAAa,CAAA;AAEjB;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,KAAK,EAAE,MAAM,CAAA;IACb;;OAEG;IACH,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;GAEG;AACH,MAAM,WAAW,IAAI;IACnB;;OAEG;IACH,IAAI,EAAE,QAAQ,GAAG,SAAS,CAAA;IAC1B;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;OAEG;IACH,KAAK,CAAC,EAAE;QACN,CAAC,EAAE,MAAM,CAAA;QACT,CAAC,EAAE,MAAM,CAAA;QACT,KAAK,EAAE,MAAM,CAAA;QACb,MAAM,EAAE,MAAM,CAAA;KACf,CAAA;IACD;;OAEG;IACH,OAAO,CAAC,EAAE,KAAK,EAAE,CAAA;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B;;OAEG;IACH,SAAS,EAAE,QAAQ,EAAE,CAAA;IACrB;;;;OAIG;IACH,aAAa,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAA;IAC/D;;;;OAIG;IACH,gBAAgB,CAAC,EAAE;QACjB,CAAC,EAAE,MAAM,CAAA;QACT,CAAC,EAAE,MAAM,CAAA;QACT,KAAK,EAAE,MAAM,CAAA;QACb,MAAM,EAAE,MAAM,CAAA;KACf,CAAA;CACF"} \ No newline at end of file diff --git a/package/lib/typescript/types/Frame.d.ts b/package/lib/typescript/types/Frame.d.ts new file mode 100644 index 0000000000..0a00e27924 --- /dev/null +++ b/package/lib/typescript/types/Frame.d.ts @@ -0,0 +1,160 @@ +import type { Orientation } from './Orientation'; +import type { PixelFormat } from './PixelFormat'; +/** + * A single frame, as seen by the camera. This is backed by a C++ HostObject wrapping the native GPU buffer. + * At a 4k resolution, a raw Frame can be 12MB in size. + * + * @example + * ```ts + * const frameProcessor = useFrameProcessor((frame) => { + * 'worklet' + * console.log(`Frame: ${frame.width}x${frame.height} (${frame.pixelFormat})`) + * }, []) + * ``` + */ +export interface Frame { + /** + * Whether the underlying buffer is still valid or not. + * A Frame is valid as long as your Frame Processor (or a `runAsync(..)` operation) is still running + */ + readonly isValid: boolean; + /** + * Returns the width of the frame, in pixels. + */ + readonly width: number; + /** + * Returns the height of the frame, in pixels. + */ + readonly height: number; + /** + * Returns the amount of bytes per row. + */ + readonly bytesPerRow: number; + /** + * Returns the number of planes this frame contains. + */ + readonly planesCount: number; + /** + * Returns whether the Frame is mirrored (selfie camera) or not. + */ + readonly isMirrored: boolean; + /** + * Returns the timestamp of the Frame relative to the host sytem's clock. + */ + readonly timestamp: number; + /** + * Represents the orientation of the Frame, relative of what the desired output orientation is. + * + * For example, if the phone is held in `'portrait'` mode and the Frame's {@linkcode orientation} + * is `'landscape-left'`, it is 90° rotated relative to the phone's rotation. + * + * To make the frame appear up-right, one would need to counter-rotate it by 90°. + * Such counter-rotations should not actually rotate pixels in the buffers, + * but instead be handled via flags or transforms to avoid any performance overheads. + * + * For example in MLKit, the caller just needs to pass the Frame's {@linkcode orientation} + * to it's `detect(...)` function and it will interpret buffers in that target orientation. + * + * @see See ["Orientation"](https://react-native-vision-camera.com/docs/guides/orientation) + */ + readonly orientation: Orientation; + /** + * Represents the pixel-format of the Frame. + */ + readonly pixelFormat: PixelFormat; + /** + * Get the underlying data of the Frame as a uint8 array buffer. + * + * The format of the buffer depends on the Frame's {@linkcode pixelFormat}. + * + * Note that Frames are allocated on the GPU, so calling `toArrayBuffer()` will copy from the GPU to the CPU. + * + * @example + * ```ts + * const frameProcessor = useFrameProcessor((frame) => { + * 'worklet' + * + * if (frame.pixelFormat === 'rgb') { + * const buffer = frame.toArrayBuffer() + * const data = new Uint8Array(buffer) + * console.log(`Pixel at 0,0: RGB(${data[0]}, ${data[1]}, ${data[2]})`) + * } + * }, []) + * ``` + */ + toArrayBuffer(): ArrayBuffer; + /** + * Returns a string representation of the frame. + * @example + * ```ts + * console.log(frame.toString()) // -> "3840 x 2160 Frame" + * ``` + */ + toString(): string; + /** + * Get the native platform buffer of the Frame. + * - On Android, this is a `AHardwareBuffer*` + * - On iOS, this is a `CVPixelBufferRef` + * + * The native buffer needs to be manually deleted using + * {@linkcode NativeBuffer.delete | NativeBuffer.delete()}, and this {@linkcode Frame} + * needs to be kept alive as long as-, or longer than + * the {@linkcode NativeBuffer}. + */ + getNativeBuffer(): NativeBuffer; +} +/** + * A managed memory pointer to a native platform buffer + */ +export interface NativeBuffer { + /** + * A uint64_t/uintptr_t to the native platform buffer. + * - On iOS; this points to a `CVPixelBufferRef` + * - On Android; this points to a `AHardwareBuffer*` + */ + pointer: bigint; + /** + * Delete this reference to the platform buffer again. + * There might still be other references, so it does not guarantee buffer deletion. + * + * This must always be called, otherwise the pipeline will stall. + */ + delete(): void; +} +/** @internal */ +export interface FrameInternal extends Frame { + /** + * Increment the Frame Buffer ref-count by one. + * + * This is a private API, do not use this. + * @internal + */ + incrementRefCount(): void; + /** + * Increment the Frame Buffer ref-count by one. + * + * This is a private API, do not use this. + * @internal + */ + decrementRefCount(): void; + /** + * Assign a new base instance to this Frame, and have all properties and methods of + * {@linkcode baseInstance} also be a part of this Frame. + * + * This is useful if you need to pass this {@linkcode Frame} to another consumer + * (e.g. a native Frame Processor Plugin) and still need it to be a `jsi::HostObject` of + * type `FrameHostObject` while containing properties of another instance ({@linkcode baseInstance}) + * @param baseInstance The base instance to use. + * @internal + * @example + * ```ts + * const canvas = skSurface.getCanvas() + * const drawableFrame = frame.withBaseClass(canvas) + * // now `drawableFrame` has all methods from `canvas`, as well as `frame`. + * // it's actual type is still `FrameHostObject`, no `Proxy`, no `Object`, no `Canvas`. + * drawableFrame.drawRect(...) + * ``` + */ + withBaseClass(baseInstance: T): T & Frame; +} +//# sourceMappingURL=Frame.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/types/Frame.d.ts.map b/package/lib/typescript/types/Frame.d.ts.map new file mode 100644 index 0000000000..41d6ffd71e --- /dev/null +++ b/package/lib/typescript/types/Frame.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Frame.d.ts","sourceRoot":"","sources":["../../../src/types/Frame.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAEhD;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,KAAK;IACpB;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB;;OAEG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B;;OAEG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B;;OAEG;IACH,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAA;IAC5B;;OAEG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC;;OAEG;IACH,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IAEjC;;;;;;;;;;;;;;;;;;;OAmBG;IACH,aAAa,IAAI,WAAW,CAAA;IAC5B;;;;;;OAMG;IACH,QAAQ,IAAI,MAAM,CAAA;IAClB;;;;;;;;;OASG;IACH,eAAe,IAAI,YAAY,CAAA;CAChC;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;OAIG;IACH,OAAO,EAAE,MAAM,CAAA;IACf;;;;;OAKG;IACH,MAAM,IAAI,IAAI,CAAA;CACf;AAED,gBAAgB;AAChB,MAAM,WAAW,aAAc,SAAQ,KAAK;IAC1C;;;;;OAKG;IACH,iBAAiB,IAAI,IAAI,CAAA;IACzB;;;;;OAKG;IACH,iBAAiB,IAAI,IAAI,CAAA;IACzB;;;;;;;;;;;;;;;;;OAiBG;IACH,aAAa,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;CAC7C"} \ No newline at end of file diff --git a/package/lib/typescript/types/Orientation.d.ts b/package/lib/typescript/types/Orientation.d.ts new file mode 100644 index 0000000000..333cce635a --- /dev/null +++ b/package/lib/typescript/types/Orientation.d.ts @@ -0,0 +1,11 @@ +/** + * Represents Orientation. Depending on the context, this might be a sensor + * orientation (relative to the phone's orentation), or view orientation. + * + * - `portrait`: **0°** (home-button at the bottom) + * - `landscape-left`: **90°** (home-button on the left) + * - `portrait-upside-down`: **180°** (home-button at the top) + * - `landscape-right`: **270°** (home-button on the right) + */ +export type Orientation = 'portrait' | 'portrait-upside-down' | 'landscape-left' | 'landscape-right'; +//# sourceMappingURL=Orientation.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/types/Orientation.d.ts.map b/package/lib/typescript/types/Orientation.d.ts.map new file mode 100644 index 0000000000..cac87c9162 --- /dev/null +++ b/package/lib/typescript/types/Orientation.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Orientation.d.ts","sourceRoot":"","sources":["../../../src/types/Orientation.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,sBAAsB,GAAG,gBAAgB,GAAG,iBAAiB,CAAA"} \ No newline at end of file diff --git a/package/lib/typescript/types/OutputOrientation.d.ts b/package/lib/typescript/types/OutputOrientation.d.ts new file mode 100644 index 0000000000..bfbd572faa --- /dev/null +++ b/package/lib/typescript/types/OutputOrientation.d.ts @@ -0,0 +1,8 @@ +/** + * Represents the orientation of the camera outputs. + * + * Output orientation can either be fixed to whatever the Preview View's orientation is (`'preview'`), + * or rotate alongside the device even if the Preview View is locked (`'device'`). + */ +export type OutputOrientation = 'device' | 'preview'; +//# sourceMappingURL=OutputOrientation.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/types/OutputOrientation.d.ts.map b/package/lib/typescript/types/OutputOrientation.d.ts.map new file mode 100644 index 0000000000..bfc9cec7e2 --- /dev/null +++ b/package/lib/typescript/types/OutputOrientation.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"OutputOrientation.d.ts","sourceRoot":"","sources":["../../../src/types/OutputOrientation.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,SAAS,CAAA"} \ No newline at end of file diff --git a/package/lib/typescript/types/PhotoFile.d.ts b/package/lib/typescript/types/PhotoFile.d.ts new file mode 100644 index 0000000000..db45dacfce --- /dev/null +++ b/package/lib/typescript/types/PhotoFile.d.ts @@ -0,0 +1,163 @@ +import type { Orientation } from './Orientation'; +import type { TemporaryFile } from './TemporaryFile'; +export interface TakePhotoOptions { + /** + * Whether the Flash should be enabled or disabled + * + * @default "off" + */ + flash?: 'on' | 'off' | 'auto'; + /** + * A custom `path` where the photo will be saved to. + * + * This must be a directory, as VisionCamera will generate a unique filename itself. + * If the given directory does not exist, this method will throw an error. + * + * By default, VisionCamera will use the device's temporary directory. + */ + path?: string; + /** + * Specifies whether red-eye reduction should be applied automatically on flash captures. + * + * @platform iOS + * @default false + */ + enableAutoRedEyeReduction?: boolean; + /** + * Specifies whether the photo output should use content aware distortion correction on this photo request. + * For example, the algorithm may not apply correction to faces in the center of a photo, but may apply it to faces near the photo’s edges. + * + * @platform iOS + * @default false + */ + enableAutoDistortionCorrection?: boolean; + /** + * Whether to play the default shutter "click" sound when taking a picture or not. + * + * @default true + */ + enableShutterSound?: boolean; + /** + * For LP3, this option should reduce shutter speed and prevent much refocusing when taking a photo in locked focus mode + */ + useFastMode?: boolean; + /** + * For LP3, this option will resolve the promise on the onCaptureStart callback instead of when the photo finishes processing + * + * @default false + */ + resolveOnCaptureStarted?: boolean; +} +/** + * Represents a Photo taken by the Camera written to the local filesystem. + * + * See {@linkcode Camera.takePhoto | Camera.takePhoto()} + */ +export interface PhotoFile extends TemporaryFile { + /** + * The width of the photo, in pixels. + */ + width: number; + /** + * The height of the photo, in pixels. + */ + height: number; + /** + * Whether this photo is in RAW format or not. + */ + isRawPhoto: boolean; + /** + * Display orientation of the photo, relative to the Camera's sensor orientation. + * + * Note that Camera sensors are landscape, so e.g. "portrait" photos will have a value of "landscape-left", etc. + */ + orientation: Orientation; + /** + * Whether this photo is mirrored (selfies) or not. + */ + isMirrored: boolean; + thumbnail?: Record; + /** + * Metadata information describing the captured image. (iOS only) + * + * @see [AVCapturePhoto.metadata](https://developer.apple.com/documentation/avfoundation/avcapturephoto/2873982-metadata) + * + * @platform iOS + */ + metadata?: { + /** + * Orientation of the EXIF Image. + * + * * 1 = 0 degrees: the correct orientation, no adjustment is required. + * * 2 = 0 degrees, mirrored: image has been flipped back-to-front. + * * 3 = 180 degrees: image is upside down. + * * 4 = 180 degrees, mirrored: image has been flipped back-to-front and is upside down. + * * 5 = 90 degrees: image has been flipped back-to-front and is on its side. + * * 6 = 90 degrees, mirrored: image is on its side. + * * 7 = 270 degrees: image has been flipped back-to-front and is on its far side. + * * 8 = 270 degrees, mirrored: image is on its far side. + */ + Orientation: number; + /** + * @platform iOS + */ + DPIHeight: number; + /** + * @platform iOS + */ + DPIWidth: number; + /** + * Represents any data Apple cameras write to the metadata + * + * @platform iOS + */ + '{MakerApple}'?: Record; + '{TIFF}': { + ResolutionUnit: number; + Software: string; + Make: string; + DateTime: string; + XResolution: number; + /** + * @platform iOS + */ + HostComputer?: string; + Model: string; + YResolution: number; + }; + '{Exif}': { + DateTimeOriginal: string; + ExposureTime: number; + FNumber: number; + LensSpecification: number[]; + ExposureBiasValue: number; + ColorSpace: number; + FocalLenIn35mmFilm: number; + BrightnessValue: number; + ExposureMode: number; + LensModel: string; + SceneType: number; + PixelXDimension: number; + ShutterSpeedValue: number; + SensingMethod: number; + SubjectArea: number[]; + ApertureValue: number; + SubsecTimeDigitized: string; + FocalLength: number; + LensMake: string; + SubsecTimeOriginal: string; + OffsetTimeDigitized: string; + PixelYDimension: number; + ISOSpeedRatings: number[]; + WhiteBalance: number; + DateTimeDigitized: string; + OffsetTimeOriginal: string; + ExifVersion: string; + OffsetTime: string; + Flash: number; + ExposureProgram: number; + MeteringMode: number; + }; + }; +} +//# sourceMappingURL=PhotoFile.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/types/PhotoFile.d.ts.map b/package/lib/typescript/types/PhotoFile.d.ts.map new file mode 100644 index 0000000000..d8a98bff19 --- /dev/null +++ b/package/lib/typescript/types/PhotoFile.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"PhotoFile.d.ts","sourceRoot":"","sources":["../../../src/types/PhotoFile.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/package/lib/typescript/types/PixelFormat.d.ts b/package/lib/typescript/types/PixelFormat.d.ts new file mode 100644 index 0000000000..6026819aae --- /dev/null +++ b/package/lib/typescript/types/PixelFormat.d.ts @@ -0,0 +1,14 @@ +/** + * Represents the pixel format of a `Frame`. + * + * If you intend to read Pixels from this Frame or use an ML model for processing, make sure that you are + * using the expected `PixelFormat`, otherwise the plugin might not be able to properly understand the Frame's content. + * + * Most ML models operate in either `yuv` (recommended) or `rgb`. + * + * - `yuv`: Frame is in YUV pixel-format (Y'CbCr 4:2:0 or NV21, 8-bit) + * - `rgb`: Frame is in RGB pixel-format (RGBA or BGRA, 8-bit) + * - `unknown`: Frame has unknown/unsupported pixel-format. + */ +export type PixelFormat = 'yuv' | 'rgb' | 'unknown'; +//# sourceMappingURL=PixelFormat.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/types/PixelFormat.d.ts.map b/package/lib/typescript/types/PixelFormat.d.ts.map new file mode 100644 index 0000000000..b94db1abff --- /dev/null +++ b/package/lib/typescript/types/PixelFormat.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"PixelFormat.d.ts","sourceRoot":"","sources":["../../../src/types/PixelFormat.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,KAAK,GAAG,SAAS,CAAA"} \ No newline at end of file diff --git a/package/lib/typescript/types/Point.d.ts b/package/lib/typescript/types/Point.d.ts new file mode 100644 index 0000000000..34591392c5 --- /dev/null +++ b/package/lib/typescript/types/Point.d.ts @@ -0,0 +1,14 @@ +/** + * Represents a Point in a 2 dimensional coordinate system. + */ +export interface Point { + /** + * The X coordinate of this Point. (double) + */ + x: number; + /** + * The Y coordinate of this Point. (double) + */ + y: number; +} +//# sourceMappingURL=Point.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/types/Point.d.ts.map b/package/lib/typescript/types/Point.d.ts.map new file mode 100644 index 0000000000..94b331c749 --- /dev/null +++ b/package/lib/typescript/types/Point.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Point.d.ts","sourceRoot":"","sources":["../../../src/types/Point.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,KAAK;IACpB;;OAEG;IACH,CAAC,EAAE,MAAM,CAAA;IACT;;OAEG;IACH,CAAC,EAAE,MAAM,CAAA;CACV"} \ No newline at end of file diff --git a/package/lib/typescript/types/Snapshot.d.ts b/package/lib/typescript/types/Snapshot.d.ts new file mode 100644 index 0000000000..c02c3f07dc --- /dev/null +++ b/package/lib/typescript/types/Snapshot.d.ts @@ -0,0 +1,19 @@ +import type { PhotoFile } from './PhotoFile'; +export interface TakeSnapshotOptions { + /** + * Specify a quality for the JPEG encoding of the snapshot. + * @default 100 + */ + quality?: number; + /** + * A custom `path` where the snapshot will be saved to. + * + * This must be a directory, as VisionCamera will generate a unique filename itself. + * If the given directory does not exist, this method will throw an error. + * + * By default, VisionCamera will use the device's temporary directory. + */ + path?: string; +} +export type SnapshotFile = Pick; +//# sourceMappingURL=Snapshot.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/types/Snapshot.d.ts.map b/package/lib/typescript/types/Snapshot.d.ts.map new file mode 100644 index 0000000000..a24daadd69 --- /dev/null +++ b/package/lib/typescript/types/Snapshot.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Snapshot.d.ts","sourceRoot":"","sources":["../../../src/types/Snapshot.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAE5C,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,MAAM,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,aAAa,GAAG,YAAY,CAAC,CAAA"} \ No newline at end of file diff --git a/package/lib/typescript/types/TemporaryFile.d.ts b/package/lib/typescript/types/TemporaryFile.d.ts new file mode 100644 index 0000000000..9e5d9c4354 --- /dev/null +++ b/package/lib/typescript/types/TemporaryFile.d.ts @@ -0,0 +1,14 @@ +/** + * Represents a temporary file in the local filesystem. + */ +export interface TemporaryFile { + /** + * The path of the file. + * + * * **Note:** If you want to consume this file (e.g. for displaying it in an `` component), you might have to add the `file://` prefix. + * + * * **Note:** This file might get deleted once the app closes because it lives in the temp directory. + */ + path: string; +} +//# sourceMappingURL=TemporaryFile.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/types/TemporaryFile.d.ts.map b/package/lib/typescript/types/TemporaryFile.d.ts.map new file mode 100644 index 0000000000..fc2001aa04 --- /dev/null +++ b/package/lib/typescript/types/TemporaryFile.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"TemporaryFile.d.ts","sourceRoot":"","sources":["../../../src/types/TemporaryFile.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;;OAMG;IACH,IAAI,EAAE,MAAM,CAAA;CACb"} \ No newline at end of file diff --git a/package/lib/typescript/types/VideoFile.d.ts b/package/lib/typescript/types/VideoFile.d.ts new file mode 100644 index 0000000000..e93b4878f2 --- /dev/null +++ b/package/lib/typescript/types/VideoFile.d.ts @@ -0,0 +1,72 @@ +import type { CameraCaptureError } from '../CameraError'; +import type { TemporaryFile } from './TemporaryFile'; +export interface RecordVideoOptions { + /** + * Set the video flash mode. Natively, this just enables the torch while recording. + */ + flash?: 'on' | 'off'; + /** + * Specifies the output file type to record videos into. + */ + fileType?: 'mov' | 'mp4'; + /** + * A custom `path` where the video will be saved to. + * + * This must be a directory, as VisionCamera will generate a unique filename itself. + * If the given directory does not exist, this method will throw an error. + * + * By default, VisionCamera will use the device's temporary directory. + */ + path?: string; + /** + * Called when there was an unexpected runtime error while recording the video. + */ + onRecordingError: (error: CameraCaptureError) => void; + /** + * Called when the recording has been successfully saved to file. + */ + onRecordingFinished: (video: VideoFile) => void; + /** + * The Video Codec to record in. + * - `h264`: Widely supported, but might be less efficient, especially with larger sizes or framerates. + * - `h265`: The HEVC (High-Efficient-Video-Codec) for higher efficient video recordings. Results in up to 50% smaller file-sizes. + */ + videoCodec?: 'h264' | 'h265'; + /** + * The bit-rate for encoding the video into a file, in Mbps (Megabits per second). + * + * Bit-rate is dependant on various factors such as resolution, FPS, pixel format (whether it's 10 bit HDR or not), and video codec. + * + * By default, it will be calculated by the hardware encoder, which takes all those factors into account. + * + * * `extra-low`: 40% lower than whatever the hardware encoder recommends. + * * `low`: 20% lower than whatever the hardware encoder recommends. + * * `normal`: The recommended value by the hardware encoder. + * * `high`: 20% higher than whatever the hardware encoder recommends. + * * `extra-high`: 40% higher than whatever the hardware encoder recommends. + * * `number`: Any custom number for the bit-rate, in Mbps. + * + * @default 'normal' + */ + videoBitRate?: 'extra-low' | 'low' | 'normal' | 'high' | 'extra-high' | number; +} +/** + * Represents a Video taken by the Camera written to the local filesystem. + * + * Related: {@linkcode Camera.startRecording | Camera.startRecording()}, {@linkcode Camera.stopRecording | Camera.stopRecording()} + */ +export interface VideoFile extends TemporaryFile { + /** + * Represents the duration of the video, in seconds. + */ + duration: number; + /** + * The width of the video, in pixels. + */ + width: number; + /** + * The height of the video, in pixels. + */ + height: number; +} +//# sourceMappingURL=VideoFile.d.ts.map \ No newline at end of file diff --git a/package/lib/typescript/types/VideoFile.d.ts.map b/package/lib/typescript/types/VideoFile.d.ts.map new file mode 100644 index 0000000000..8186fcd097 --- /dev/null +++ b/package/lib/typescript/types/VideoFile.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"VideoFile.d.ts","sourceRoot":"","sources":["../../../src/types/VideoFile.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AACxD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAEpD,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,KAAK,CAAC,EAAE,IAAI,GAAG,KAAK,CAAA;IACpB;;OAEG;IACH,QAAQ,CAAC,EAAE,KAAK,GAAG,KAAK,CAAA;IACxB;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;OAEG;IACH,gBAAgB,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAA;IACrD;;OAEG;IACH,mBAAmB,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAA;IAC/C;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IAC5B;;;;;;;;;;;;;;;OAeG;IACH,YAAY,CAAC,EAAE,WAAW,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,YAAY,GAAG,MAAM,CAAA;CAC/E;AAED;;;;GAIG;AACH,MAAM,WAAW,SAAU,SAAQ,aAAa;IAC9C;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAA;IACb;;OAEG;IACH,MAAM,EAAE,MAAM,CAAA;CACf"} \ No newline at end of file diff --git a/package/package.json b/package/package.json index ced762c701..7c2c57381e 100644 --- a/package/package.json +++ b/package/package.json @@ -1,6 +1,6 @@ { "name": "react-native-vision-camera", - "version": "4.5.3", + "version": "4.6.17", "description": "A powerful, high-performance React Native Camera library.", "main": "lib/commonjs/index", "module": "lib/module/index", @@ -72,7 +72,7 @@ "processing", "realtime" ], - "repository": "https://github.com/mrousavy/react-native-vision-camera", + "repository": "https://github.com/sanctuarycomputer/react-native-vision-camera", "author": "Marc Rousavy (https://github.com/mrousavy)", "license": "MIT", "bugs": { @@ -127,7 +127,7 @@ "tagName": "v${version}" }, "npm": { - "publish": true + "publish": false }, "github": { "release": true diff --git a/package/src/Camera.tsx b/package/src/Camera.tsx index c896e1542b..ece4b985ee 100644 --- a/package/src/Camera.tsx +++ b/package/src/Camera.tsx @@ -392,6 +392,23 @@ export class Camera extends React.PureComponent { } //#endregion + + public async lockFocusAndExposureToPoint(point: Point): Promise { + try { + return await CameraModule.lockFocusAndExposureToPoint(this.handle, point) + } catch (e) { + throw tryParseNativeCameraError(e); + } + } + + public async freeFocusAndExposure(): Promise { + try { + return await CameraModule.freeFocusAndExposure(this.handle) + } catch (e) { + throw tryParseNativeCameraError(e); + } + } + //#region Static Functions (NativeModule) /** * Get a list of all available camera devices on the current phone. diff --git a/package/src/types/CameraProps.ts b/package/src/types/CameraProps.ts index 8056d35c95..4a6ca18054 100644 --- a/package/src/types/CameraProps.ts +++ b/package/src/types/CameraProps.ts @@ -218,6 +218,14 @@ export interface CameraProps extends ViewProps { * @default 'balanced' */ photoQualityBalance?: 'speed' | 'balanced' | 'quality' + /** + * LightOS: Configures the compression quality of saved images. + * Accepts values of 0-100 + * See docs: + * https://developer.android.com/reference/androidx/camera/core/ImageCapture.Builder#setJpegQuality(int) + * @default 100 + */ + jpegCompressionQuality?: number /** * Enables or disables lossy buffer compression for the video stream. * If you only use {@linkcode video} or a {@linkcode frameProcessor}, this diff --git a/package/src/types/PhotoFile.ts b/package/src/types/PhotoFile.ts index 85098d6898..f17d7a57f0 100644 --- a/package/src/types/PhotoFile.ts +++ b/package/src/types/PhotoFile.ts @@ -38,6 +38,18 @@ export interface TakePhotoOptions { * @default true */ enableShutterSound?: boolean + + /** + * For LP3, this option should reduce shutter speed and prevent much refocusing when taking a photo in locked focus mode + */ + useFastMode?: boolean + + /** + * For LP3, this option will resolve the promise on the onCaptureStart callback instead of when the photo finishes processing + * + * @default false + */ + resolveOnCaptureStarted?: boolean } /**