diff --git a/apps/simple-camera/__tests__/visioncamera.photo.harness.ts b/apps/simple-camera/__tests__/visioncamera.photo.harness.ts index a296dd01d0..079cbf6a5d 100644 --- a/apps/simple-camera/__tests__/visioncamera.photo.harness.ts +++ b/apps/simple-camera/__tests__/visioncamera.photo.harness.ts @@ -1001,6 +1001,51 @@ describe('VisionCamera - Photo', () => { await session.stop() }) + it('returns captured Photo metadata from capturePhotoToFile', async () => { + const session = await VisionCamera.createCameraSession(false) + const photoOutput = VisionCamera.createPhotoOutput({ + targetResolution: CommonResolutions.HD_4_3, + containerFormat: 'jpeg', + quality: 0.8, + qualityPrioritization: 'balanced', + }) + await session.configure([ + { + input: backDevice, + outputs: [{ output: photoOutput, mirrorMode: 'on' }], + constraints: [], + }, + ]) + await session.start() + + try { + photoOutput.outputOrientation = 'left' + const inMemoryPhoto = await photoOutput.capturePhoto( + { flashMode: 'off', enableShutterSound: false }, + {}, + ) + try { + const photoFile = await photoOutput.capturePhotoToFile( + { flashMode: 'off', enableShutterSound: false }, + {}, + ) + + expect(photoFile.filePath).toMatch(/^\/.*\.(jpeg|jpg)$/) + expect(photoFile.width).toBe(inMemoryPhoto.width) + expect(photoFile.height).toBe(inMemoryPhoto.height) + expect(photoFile.orientation).toBe(inMemoryPhoto.orientation) + expect(photoFile.isMirrored).toBe(inMemoryPhoto.isMirrored) + expect(photoFile.timestamp).toBeGreaterThan(0) + expect(photoFile.isRawPhoto).toBe(inMemoryPhoto.isRawPhoto) + expect(photoFile.containerFormat).toBe(inMemoryPhoto.containerFormat) + } finally { + inMemoryPhoto.dispose() + } + } finally { + await session.stop() + } + }) + it('reports supportsDepthDataDelivery on a depth-capable device', async (context) => { // `supportsDepthDataDelivery` is a per-output property that flips to `true` // once the photo output is bound to a device that can produce depth data. diff --git a/packages/react-native-vision-camera/android/src/main/java/com/margelo/nitro/camera/extensions/converters/PhotoFile+fromFile.kt b/packages/react-native-vision-camera/android/src/main/java/com/margelo/nitro/camera/extensions/converters/PhotoFile+fromFile.kt new file mode 100644 index 0000000000..367876ba9a --- /dev/null +++ b/packages/react-native-vision-camera/android/src/main/java/com/margelo/nitro/camera/extensions/converters/PhotoFile+fromFile.kt @@ -0,0 +1,30 @@ +package com.margelo.nitro.camera.extensions.converters + +import android.annotation.SuppressLint +import androidx.camera.core.impl.utils.Exif +import com.margelo.nitro.camera.CameraOrientation +import com.margelo.nitro.camera.PhotoContainerFormat +import com.margelo.nitro.camera.PhotoFile +import com.margelo.nitro.camera.extensions.fromDegrees +import java.io.File + +@SuppressLint("RestrictedApi") +fun PhotoFile.Companion.fromFile( + file: File, + imageFormat: Int, + timestamp: Double, + isMirrored: Boolean, +): PhotoFile { + val exif = Exif.createFromFile(file) + val containerFormat = PhotoContainerFormat.fromImageFormat(imageFormat) + return PhotoFile( + filePath = file.absolutePath, + width = exif.width.toDouble(), + height = exif.height.toDouble(), + orientation = CameraOrientation.fromDegrees(exif.rotation), + isMirrored = isMirrored, + timestamp = timestamp, + isRawPhoto = containerFormat == PhotoContainerFormat.DNG, + containerFormat = containerFormat, + ) +} diff --git a/packages/react-native-vision-camera/android/src/main/java/com/margelo/nitro/camera/hybrids/outputs/HybridPhotoOutput.kt b/packages/react-native-vision-camera/android/src/main/java/com/margelo/nitro/camera/hybrids/outputs/HybridPhotoOutput.kt index f3bdfe38c3..a384e82526 100644 --- a/packages/react-native-vision-camera/android/src/main/java/com/margelo/nitro/camera/hybrids/outputs/HybridPhotoOutput.kt +++ b/packages/react-native-vision-camera/android/src/main/java/com/margelo/nitro/camera/hybrids/outputs/HybridPhotoOutput.kt @@ -1,6 +1,7 @@ package com.margelo.nitro.camera.hybrids.outputs import android.media.MediaActionSound +import android.os.SystemClock import android.util.Log import androidx.camera.core.CameraInfo import androidx.camera.core.CameraSelector @@ -18,6 +19,7 @@ import com.margelo.nitro.camera.PhotoFile import com.margelo.nitro.camera.PhotoOutputOptions import com.margelo.nitro.camera.QualityPrioritization import com.margelo.nitro.camera.Size +import com.margelo.nitro.camera.extensions.converters.fromFile import com.margelo.nitro.camera.extensions.converters.toCaptureMode import com.margelo.nitro.camera.extensions.converters.toFlashMode import com.margelo.nitro.camera.extensions.converters.toOutputFormat @@ -256,30 +258,33 @@ class HybridPhotoOutput( // 2. Perform Capture var didFireOnDidCapturePhoto = false - imageCapture.takePicture( - outputFileOptions, - { - callbacks.onWillBeginCapture?.invoke() - if (enableShutterSound) { - shutterSound.play(MediaActionSound.SHUTTER_CLICK) - } - callbacks.onWillCapturePhoto?.invoke() - }, - { progress -> - if (progress == 100) { - // Capture is complete! Saving... - callbacks.onDidCapturePhoto?.invoke() - didFireOnDidCapturePhoto = true - } - }, - { bitmap -> - // Preview Image delivered! - callbacks.onPreviewImageAvailable?.let { onPreviewImageAvailable -> - val image = HybridImage(bitmap) - onPreviewImageAvailable(image) - } - }, - ) + var timestamp: Double? = null + val result = + imageCapture.takePicture( + outputFileOptions, + { + timestamp = SystemClock.elapsedRealtimeNanos().toDouble() / 1_000_000_000.0 + callbacks.onWillBeginCapture?.invoke() + if (enableShutterSound) { + shutterSound.play(MediaActionSound.SHUTTER_CLICK) + } + callbacks.onWillCapturePhoto?.invoke() + }, + { progress -> + if (progress == 100) { + // Capture is complete! Saving... + callbacks.onDidCapturePhoto?.invoke() + didFireOnDidCapturePhoto = true + } + }, + { bitmap -> + // Preview Image delivered! + callbacks.onPreviewImageAvailable?.let { onPreviewImageAvailable -> + val image = HybridImage(bitmap) + onPreviewImageAvailable(image) + } + }, + ) if (!didFireOnDidCapturePhoto) { // Not every device supports progress callbacks, so we just fire it later here @@ -287,7 +292,14 @@ class HybridPhotoOutput( } // 3. Return - return@async PhotoFile(file.absolutePath) + val captureTimestamp = + timestamp ?: throw Error("Photo capture did not report when exposure started!") + return@async PhotoFile.fromFile( + file = file, + imageFormat = result.imageFormat, + timestamp = captureTimestamp, + isMirrored = isMirrored, + ) } } diff --git a/packages/react-native-vision-camera/ios/Hybrid Objects/Outputs/HybridCameraPhotoOutput.swift b/packages/react-native-vision-camera/ios/Hybrid Objects/Outputs/HybridCameraPhotoOutput.swift index e5249f21be..f5b5c367fc 100644 --- a/packages/react-native-vision-camera/ios/Hybrid Objects/Outputs/HybridCameraPhotoOutput.swift +++ b/packages/react-native-vision-camera/ios/Hybrid Objects/Outputs/HybridCameraPhotoOutput.swift @@ -180,7 +180,15 @@ final class HybridCameraPhotoOutput: HybridCameraPhotoOutputSpec, NativeCameraOu .await() let filePath = try await photo.saveToTemporaryFileAsync() .await() - return PhotoFile(filePath: filePath) + return PhotoFile( + filePath: filePath, + width: photo.width, + height: photo.height, + orientation: photo.orientation, + isMirrored: photo.isMirrored, + timestamp: photo.timestamp, + isRawPhoto: photo.isRawPhoto, + containerFormat: photo.containerFormat) } } diff --git a/packages/react-native-vision-camera/nitrogen/generated/android/c++/JHybridCameraPhotoOutputSpec.cpp b/packages/react-native-vision-camera/nitrogen/generated/android/c++/JHybridCameraPhotoOutputSpec.cpp index c036a55577..9bc658ffac 100644 --- a/packages/react-native-vision-camera/nitrogen/generated/android/c++/JHybridCameraPhotoOutputSpec.cpp +++ b/packages/react-native-vision-camera/nitrogen/generated/android/c++/JHybridCameraPhotoOutputSpec.cpp @@ -11,6 +11,10 @@ namespace margelo::nitro::camera { class HybridPhotoSpec; } // Forward declaration of `PhotoFile` to properly resolve imports. namespace margelo::nitro::camera { struct PhotoFile; } +// Forward declaration of `CameraOrientation` to properly resolve imports. +namespace margelo::nitro::camera { enum class CameraOrientation; } +// Forward declaration of `PhotoContainerFormat` to properly resolve imports. +namespace margelo::nitro::camera { enum class PhotoContainerFormat; } // Forward declaration of `CapturePhotoSettings` to properly resolve imports. namespace margelo::nitro::camera { struct CapturePhotoSettings; } // Forward declaration of `FlashMode` to properly resolve imports. @@ -23,8 +27,6 @@ namespace margelo::nitro::camera { struct CapturePhotoCallbacks; } namespace margelo::nitro::image { class HybridImageSpec; } // Forward declaration of `MediaType` to properly resolve imports. namespace margelo::nitro::camera { enum class MediaType; } -// Forward declaration of `CameraOrientation` to properly resolve imports. -namespace margelo::nitro::camera { enum class CameraOrientation; } // Forward declaration of `Size` to properly resolve imports. namespace margelo::nitro::camera { struct Size; } @@ -36,6 +38,10 @@ namespace margelo::nitro::camera { struct Size; } #include "PhotoFile.hpp" #include "JPhotoFile.hpp" #include +#include "CameraOrientation.hpp" +#include "JCameraOrientation.hpp" +#include "PhotoContainerFormat.hpp" +#include "JPhotoContainerFormat.hpp" #include #include "CapturePhotoSettings.hpp" #include "JCapturePhotoSettings.hpp" @@ -55,8 +61,6 @@ namespace margelo::nitro::camera { struct Size; } #include #include "MediaType.hpp" #include "JMediaType.hpp" -#include "CameraOrientation.hpp" -#include "JCameraOrientation.hpp" #include "Size.hpp" #include "JSize.hpp" diff --git a/packages/react-native-vision-camera/nitrogen/generated/android/c++/JPhotoFile.hpp b/packages/react-native-vision-camera/nitrogen/generated/android/c++/JPhotoFile.hpp index d6abad68c0..08208f6a8b 100644 --- a/packages/react-native-vision-camera/nitrogen/generated/android/c++/JPhotoFile.hpp +++ b/packages/react-native-vision-camera/nitrogen/generated/android/c++/JPhotoFile.hpp @@ -10,6 +10,10 @@ #include #include "PhotoFile.hpp" +#include "CameraOrientation.hpp" +#include "JCameraOrientation.hpp" +#include "JPhotoContainerFormat.hpp" +#include "PhotoContainerFormat.hpp" #include namespace margelo::nitro::camera { @@ -33,8 +37,29 @@ namespace margelo::nitro::camera { static const auto clazz = javaClassStatic(); static const auto fieldFilePath = clazz->getField("filePath"); jni::local_ref filePath = this->getFieldValue(fieldFilePath); + static const auto fieldWidth = clazz->getField("width"); + double width = this->getFieldValue(fieldWidth); + static const auto fieldHeight = clazz->getField("height"); + double height = this->getFieldValue(fieldHeight); + static const auto fieldOrientation = clazz->getField("orientation"); + jni::local_ref orientation = this->getFieldValue(fieldOrientation); + static const auto fieldIsMirrored = clazz->getField("isMirrored"); + jboolean isMirrored = this->getFieldValue(fieldIsMirrored); + static const auto fieldTimestamp = clazz->getField("timestamp"); + double timestamp = this->getFieldValue(fieldTimestamp); + static const auto fieldIsRawPhoto = clazz->getField("isRawPhoto"); + jboolean isRawPhoto = this->getFieldValue(fieldIsRawPhoto); + static const auto fieldContainerFormat = clazz->getField("containerFormat"); + jni::local_ref containerFormat = this->getFieldValue(fieldContainerFormat); return PhotoFile( - filePath->toStdString() + filePath->toStdString(), + width, + height, + orientation->toCpp(), + static_cast(isMirrored), + timestamp, + static_cast(isRawPhoto), + containerFormat->toCpp() ); } @@ -44,12 +69,19 @@ namespace margelo::nitro::camera { */ [[maybe_unused]] static jni::local_ref fromCpp(const PhotoFile& value) { - using JSignature = JPhotoFile(jni::alias_ref); + using JSignature = JPhotoFile(jni::alias_ref, double, double, jni::alias_ref, jboolean, double, jboolean, jni::alias_ref); static const auto clazz = javaClassStatic(); static const auto create = clazz->getStaticMethod("fromCpp"); return create( clazz, - jni::make_jstring(value.filePath) + jni::make_jstring(value.filePath), + value.width, + value.height, + JCameraOrientation::fromCpp(value.orientation), + value.isMirrored, + value.timestamp, + value.isRawPhoto, + JPhotoContainerFormat::fromCpp(value.containerFormat) ); } }; diff --git a/packages/react-native-vision-camera/nitrogen/generated/android/kotlin/com/margelo/nitro/camera/PhotoFile.kt b/packages/react-native-vision-camera/nitrogen/generated/android/kotlin/com/margelo/nitro/camera/PhotoFile.kt index e305fc0ca7..eabdd4de84 100644 --- a/packages/react-native-vision-camera/nitrogen/generated/android/kotlin/com/margelo/nitro/camera/PhotoFile.kt +++ b/packages/react-native-vision-camera/nitrogen/generated/android/kotlin/com/margelo/nitro/camera/PhotoFile.kt @@ -20,7 +20,28 @@ import java.util.Objects data class PhotoFile( @DoNotStrip @Keep - val filePath: String + val filePath: String, + @DoNotStrip + @Keep + val width: Double, + @DoNotStrip + @Keep + val height: Double, + @DoNotStrip + @Keep + val orientation: CameraOrientation, + @DoNotStrip + @Keep + val isMirrored: Boolean, + @DoNotStrip + @Keep + val timestamp: Double, + @DoNotStrip + @Keep + val isRawPhoto: Boolean, + @DoNotStrip + @Keep + val containerFormat: PhotoContainerFormat ) { /* primary constructor */ @@ -28,11 +49,25 @@ data class PhotoFile( if (this === other) return true if (other !is PhotoFile) return false return Objects.deepEquals(this.filePath, other.filePath) + && Objects.deepEquals(this.width, other.width) + && Objects.deepEquals(this.height, other.height) + && Objects.deepEquals(this.orientation, other.orientation) + && Objects.deepEquals(this.isMirrored, other.isMirrored) + && Objects.deepEquals(this.timestamp, other.timestamp) + && Objects.deepEquals(this.isRawPhoto, other.isRawPhoto) + && Objects.deepEquals(this.containerFormat, other.containerFormat) } override fun hashCode(): Int { return arrayOf( - filePath + filePath, + width, + height, + orientation, + isMirrored, + timestamp, + isRawPhoto, + containerFormat ).contentDeepHashCode() } @@ -44,8 +79,8 @@ data class PhotoFile( @Keep @Suppress("unused") @JvmStatic - private fun fromCpp(filePath: String): PhotoFile { - return PhotoFile(filePath) + private fun fromCpp(filePath: String, width: Double, height: Double, orientation: CameraOrientation, isMirrored: Boolean, timestamp: Double, isRawPhoto: Boolean, containerFormat: PhotoContainerFormat): PhotoFile { + return PhotoFile(filePath, width, height, orientation, isMirrored, timestamp, isRawPhoto, containerFormat) } } } diff --git a/packages/react-native-vision-camera/nitrogen/generated/ios/VisionCamera-Swift-Cxx-Bridge.hpp b/packages/react-native-vision-camera/nitrogen/generated/ios/VisionCamera-Swift-Cxx-Bridge.hpp index 9cbee63205..90598bf6f0 100644 --- a/packages/react-native-vision-camera/nitrogen/generated/ios/VisionCamera-Swift-Cxx-Bridge.hpp +++ b/packages/react-native-vision-camera/nitrogen/generated/ios/VisionCamera-Swift-Cxx-Bridge.hpp @@ -126,6 +126,8 @@ namespace margelo::nitro::camera { enum class MeteringMode; } namespace margelo::nitro::camera { enum class MirrorMode; } // Forward declaration of `NativeBuffer` to properly resolve imports. namespace margelo::nitro::camera { struct NativeBuffer; } +// Forward declaration of `PhotoContainerFormat` to properly resolve imports. +namespace margelo::nitro::camera { enum class PhotoContainerFormat; } // Forward declaration of `PhotoFile` to properly resolve imports. namespace margelo::nitro::camera { struct PhotoFile; } // Forward declaration of `PhotoHDRConstraint` to properly resolve imports. @@ -311,6 +313,7 @@ namespace VisionCamera { class HybridZoomGestureControllerSpec_cxx; } #include "MeteringMode.hpp" #include "MirrorMode.hpp" #include "NativeBuffer.hpp" +#include "PhotoContainerFormat.hpp" #include "PhotoFile.hpp" #include "PhotoHDRConstraint.hpp" #include "PixelFormat.hpp" diff --git a/packages/react-native-vision-camera/nitrogen/generated/ios/c++/HybridCameraPhotoOutputSpecSwift.hpp b/packages/react-native-vision-camera/nitrogen/generated/ios/c++/HybridCameraPhotoOutputSpecSwift.hpp index bb3ed93f04..21dbc99d42 100644 --- a/packages/react-native-vision-camera/nitrogen/generated/ios/c++/HybridCameraPhotoOutputSpecSwift.hpp +++ b/packages/react-native-vision-camera/nitrogen/generated/ios/c++/HybridCameraPhotoOutputSpecSwift.hpp @@ -26,6 +26,10 @@ namespace margelo::nitro::camera { struct CapturePhotoCallbacks; } namespace margelo::nitro::image { class HybridImageSpec; } // Forward declaration of `PhotoFile` to properly resolve imports. namespace margelo::nitro::camera { struct PhotoFile; } +// Forward declaration of `CameraOrientation` to properly resolve imports. +namespace margelo::nitro::camera { enum class CameraOrientation; } +// Forward declaration of `PhotoContainerFormat` to properly resolve imports. +namespace margelo::nitro::camera { enum class PhotoContainerFormat; } // Forward declaration of `HybridCameraOutputSpecSwift` to properly resolve imports. namespace margelo::nitro::camera { class HybridCameraOutputSpecSwift; } @@ -41,6 +45,8 @@ namespace margelo::nitro::camera { class HybridCameraOutputSpecSwift; } #include #include "PhotoFile.hpp" #include +#include "CameraOrientation.hpp" +#include "PhotoContainerFormat.hpp" #include #include "HybridCameraOutputSpecSwift.hpp" diff --git a/packages/react-native-vision-camera/nitrogen/generated/ios/swift/PhotoFile.swift b/packages/react-native-vision-camera/nitrogen/generated/ios/swift/PhotoFile.swift index a89b7679f0..c23a22e63d 100644 --- a/packages/react-native-vision-camera/nitrogen/generated/ios/swift/PhotoFile.swift +++ b/packages/react-native-vision-camera/nitrogen/generated/ios/swift/PhotoFile.swift @@ -18,12 +18,47 @@ public extension PhotoFile { /** * Create a new instance of `PhotoFile`. */ - init(filePath: String) { - self.init(std.string(filePath)) + init(filePath: String, width: Double, height: Double, orientation: CameraOrientation, isMirrored: Bool, timestamp: Double, isRawPhoto: Bool, containerFormat: PhotoContainerFormat) { + self.init(std.string(filePath), width, height, orientation, isMirrored, timestamp, isRawPhoto, containerFormat) } @inline(__always) var filePath: String { return String(self.__filePath) } + + @inline(__always) + var width: Double { + return self.__width + } + + @inline(__always) + var height: Double { + return self.__height + } + + @inline(__always) + var orientation: CameraOrientation { + return self.__orientation + } + + @inline(__always) + var isMirrored: Bool { + return self.__isMirrored + } + + @inline(__always) + var timestamp: Double { + return self.__timestamp + } + + @inline(__always) + var isRawPhoto: Bool { + return self.__isRawPhoto + } + + @inline(__always) + var containerFormat: PhotoContainerFormat { + return self.__containerFormat + } } diff --git a/packages/react-native-vision-camera/nitrogen/generated/shared/c++/PhotoFile.hpp b/packages/react-native-vision-camera/nitrogen/generated/shared/c++/PhotoFile.hpp index d502bdd515..989b279c93 100644 --- a/packages/react-native-vision-camera/nitrogen/generated/shared/c++/PhotoFile.hpp +++ b/packages/react-native-vision-camera/nitrogen/generated/shared/c++/PhotoFile.hpp @@ -28,9 +28,14 @@ #error NitroModules cannot be found! Are you sure you installed NitroModules properly? #endif - +// Forward declaration of `CameraOrientation` to properly resolve imports. +namespace margelo::nitro::camera { enum class CameraOrientation; } +// Forward declaration of `PhotoContainerFormat` to properly resolve imports. +namespace margelo::nitro::camera { enum class PhotoContainerFormat; } #include +#include "CameraOrientation.hpp" +#include "PhotoContainerFormat.hpp" namespace margelo::nitro::camera { @@ -40,10 +45,17 @@ namespace margelo::nitro::camera { struct PhotoFile final { public: std::string filePath SWIFT_PRIVATE; + double width SWIFT_PRIVATE; + double height SWIFT_PRIVATE; + CameraOrientation orientation SWIFT_PRIVATE; + bool isMirrored SWIFT_PRIVATE; + double timestamp SWIFT_PRIVATE; + bool isRawPhoto SWIFT_PRIVATE; + PhotoContainerFormat containerFormat SWIFT_PRIVATE; public: PhotoFile() = default; - explicit PhotoFile(std::string filePath): filePath(filePath) {} + explicit PhotoFile(std::string filePath, double width, double height, CameraOrientation orientation, bool isMirrored, double timestamp, bool isRawPhoto, PhotoContainerFormat containerFormat): filePath(filePath), width(width), height(height), orientation(orientation), isMirrored(isMirrored), timestamp(timestamp), isRawPhoto(isRawPhoto), containerFormat(containerFormat) {} public: friend bool operator==(const PhotoFile& lhs, const PhotoFile& rhs) = default; @@ -59,12 +71,26 @@ namespace margelo::nitro { static inline margelo::nitro::camera::PhotoFile fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) { jsi::Object obj = arg.asObject(runtime); return margelo::nitro::camera::PhotoFile( - JSIConverter::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "filePath"))) + JSIConverter::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "filePath"))), + JSIConverter::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "width"))), + JSIConverter::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "height"))), + JSIConverter::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "orientation"))), + JSIConverter::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "isMirrored"))), + JSIConverter::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "timestamp"))), + JSIConverter::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "isRawPhoto"))), + JSIConverter::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "containerFormat"))) ); } static inline jsi::Value toJSI(jsi::Runtime& runtime, const margelo::nitro::camera::PhotoFile& arg) { jsi::Object obj(runtime); obj.setProperty(runtime, PropNameIDCache::get(runtime, "filePath"), JSIConverter::toJSI(runtime, arg.filePath)); + obj.setProperty(runtime, PropNameIDCache::get(runtime, "width"), JSIConverter::toJSI(runtime, arg.width)); + obj.setProperty(runtime, PropNameIDCache::get(runtime, "height"), JSIConverter::toJSI(runtime, arg.height)); + obj.setProperty(runtime, PropNameIDCache::get(runtime, "orientation"), JSIConverter::toJSI(runtime, arg.orientation)); + obj.setProperty(runtime, PropNameIDCache::get(runtime, "isMirrored"), JSIConverter::toJSI(runtime, arg.isMirrored)); + obj.setProperty(runtime, PropNameIDCache::get(runtime, "timestamp"), JSIConverter::toJSI(runtime, arg.timestamp)); + obj.setProperty(runtime, PropNameIDCache::get(runtime, "isRawPhoto"), JSIConverter::toJSI(runtime, arg.isRawPhoto)); + obj.setProperty(runtime, PropNameIDCache::get(runtime, "containerFormat"), JSIConverter::toJSI(runtime, arg.containerFormat)); return obj; } static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) { @@ -76,6 +102,13 @@ namespace margelo::nitro { return false; } if (!JSIConverter::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "filePath")))) return false; + if (!JSIConverter::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "width")))) return false; + if (!JSIConverter::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "height")))) return false; + if (!JSIConverter::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "orientation")))) return false; + if (!JSIConverter::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "isMirrored")))) return false; + if (!JSIConverter::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "timestamp")))) return false; + if (!JSIConverter::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "isRawPhoto")))) return false; + if (!JSIConverter::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "containerFormat")))) return false; return true; } }; diff --git a/packages/react-native-vision-camera/src/specs/outputs/CameraPhotoOutput.nitro.ts b/packages/react-native-vision-camera/src/specs/outputs/CameraPhotoOutput.nitro.ts index 07297a68e3..7a6c262c84 100644 --- a/packages/react-native-vision-camera/src/specs/outputs/CameraPhotoOutput.nitro.ts +++ b/packages/react-native-vision-camera/src/specs/outputs/CameraPhotoOutput.nitro.ts @@ -1,6 +1,10 @@ import type { Image } from 'react-native-nitro-image' import type { usePhotoOutput } from '../../hooks/usePhotoOutput' -import type { TargetPhotoContainerFormat } from '../common-types/PhotoContainerFormat' +import type { CameraOrientation } from '../common-types/CameraOrientation' +import type { + PhotoContainerFormat, + TargetPhotoContainerFormat, +} from '../common-types/PhotoContainerFormat' import type { QualityPrioritization } from '../common-types/QualityPrioritization' import type { Size } from '../common-types/Size' import type { CameraDevice } from '../inputs/CameraDevice.nitro' @@ -225,7 +229,9 @@ export interface CapturePhotoSettings { } /** - * Represents a Photo written to a File. + * Represents a Photo captured by + * {@linkcode CameraPhotoOutput.capturePhotoToFile | capturePhotoToFile(...)} + * and written to a File. */ export interface PhotoFile { /** @@ -233,6 +239,37 @@ export interface PhotoFile { * This is a filesystem path, not a `file://` URL. */ filePath: string + /** + * The width of the captured Photo, in pixels. + */ + width: number + /** + * The height of the captured Photo, in pixels. + */ + height: number + /** + * The {@linkcode CameraOrientation} the Photo was captured in. + * + * The orientation is applied lazily through the file's EXIF metadata. + */ + orientation: CameraOrientation + /** + * Whether the captured Photo is mirrored along its vertical axis. + */ + isMirrored: boolean + /** + * The timestamp at which the Photo was captured, using the system's + * host clock, in seconds. + */ + timestamp: number + /** + * Whether the captured Photo is a RAW photo. + */ + isRawPhoto: boolean + /** + * The {@linkcode PhotoContainerFormat} of the captured Photo. + */ + containerFormat: PhotoContainerFormat } /**