| 
									
										
										
										
											2021-02-19 20:41:49 +01:00
										 |  |  | package com.mrousavy.camera | 
					
						
							| 
									
										
										
										
											2021-02-19 16:28:14 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | import android.annotation.SuppressLint | 
					
						
							|  |  |  | import android.hardware.camera2.* | 
					
						
							|  |  |  | import android.util.Log | 
					
						
							|  |  |  | import androidx.camera.camera2.interop.Camera2CameraInfo | 
					
						
							|  |  |  | import androidx.camera.core.ImageCapture | 
					
						
							|  |  |  | import androidx.camera.core.ImageProxy | 
					
						
							|  |  |  | import androidx.exifinterface.media.ExifInterface | 
					
						
							|  |  |  | import com.facebook.react.bridge.Arguments | 
					
						
							|  |  |  | import com.facebook.react.bridge.ReadableMap | 
					
						
							|  |  |  | import com.facebook.react.bridge.WritableMap | 
					
						
							| 
									
										
										
										
											2021-02-26 10:56:20 +01:00
										 |  |  | import com.mrousavy.camera.utils.* | 
					
						
							| 
									
										
										
										
											2021-02-19 16:28:14 +01:00
										 |  |  | import kotlinx.coroutines.* | 
					
						
							|  |  |  | import java.io.File | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private const val TAG = "CameraView.performance" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @SuppressLint("UnsafeExperimentalUsageError") | 
					
						
							|  |  |  | suspend fun CameraView.takePhoto(options: ReadableMap): WritableMap = coroutineScope { | 
					
						
							| 
									
										
										
										
											2021-02-26 10:56:20 +01:00
										 |  |  |   val startFunc = System.nanoTime() | 
					
						
							|  |  |  |   Log.d(CameraView.REACT_CLASS, "takePhoto() called") | 
					
						
							|  |  |  |   val imageCapture = imageCapture ?: throw CameraNotReadyError() | 
					
						
							| 
									
										
										
										
											2021-02-19 16:28:14 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-26 10:56:20 +01:00
										 |  |  |   if (options.hasKey("flash")) { | 
					
						
							|  |  |  |     val flashMode = options.getString("flash") | 
					
						
							|  |  |  |     imageCapture.flashMode = when (flashMode) { | 
					
						
							|  |  |  |       "on" -> ImageCapture.FLASH_MODE_ON | 
					
						
							|  |  |  |       "off" -> ImageCapture.FLASH_MODE_OFF | 
					
						
							|  |  |  |       "auto" -> ImageCapture.FLASH_MODE_AUTO | 
					
						
							|  |  |  |       else -> throw InvalidTypeScriptUnionError("flash", flashMode ?: "(null)") | 
					
						
							| 
									
										
										
										
											2021-02-19 16:28:14 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-02-26 10:56:20 +01:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2021-03-17 19:29:03 +01:00
										 |  |  |   // All those options are not yet implemented - see https://github.com/cuvent/react-native-vision-camera/issues/75
 | 
					
						
							|  |  |  |   if (options.hasKey("photoCodec")) { | 
					
						
							|  |  |  |     // TODO photoCodec
 | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (options.hasKey("qualityPrioritization")) { | 
					
						
							|  |  |  |     // TODO qualityPrioritization
 | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2021-02-26 10:56:20 +01:00
										 |  |  |   if (options.hasKey("enableAutoRedEyeReduction")) { | 
					
						
							|  |  |  |     // TODO enableAutoRedEyeReduction
 | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (options.hasKey("enableDualCameraFusion")) { | 
					
						
							|  |  |  |     // TODO enableDualCameraFusion
 | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (options.hasKey("enableVirtualDeviceFusion")) { | 
					
						
							|  |  |  |     // TODO enableVirtualDeviceFusion
 | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (options.hasKey("enableAutoStabilization")) { | 
					
						
							|  |  |  |     // TODO enableAutoStabilization
 | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (options.hasKey("enableAutoDistortionCorrection")) { | 
					
						
							|  |  |  |     // TODO enableAutoDistortionCorrection
 | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   val skipMetadata = if (options.hasKey("skipMetadata")) options.getBoolean("skipMetadata") else false | 
					
						
							| 
									
										
										
										
											2021-02-19 16:28:14 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-26 10:56:20 +01:00
										 |  |  |   val camera2Info = Camera2CameraInfo.from(camera!!.cameraInfo) | 
					
						
							|  |  |  |   val lensFacing = camera2Info.getCameraCharacteristic(CameraCharacteristics.LENS_FACING) | 
					
						
							| 
									
										
										
										
											2021-03-17 19:29:03 +01:00
										 |  |  |   // TODO: Flip image if lens is front side - see https://github.com/cuvent/react-native-vision-camera/issues/74
 | 
					
						
							| 
									
										
										
										
											2021-02-19 16:28:14 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-26 10:56:20 +01:00
										 |  |  |   val results = awaitAll( | 
					
						
							|  |  |  |     async(coroutineContext) { | 
					
						
							|  |  |  |       Log.d(CameraView.REACT_CLASS, "Taking picture...") | 
					
						
							|  |  |  |       val startCapture = System.nanoTime() | 
					
						
							|  |  |  |       val pic = imageCapture.takePicture(takePhotoExecutor) | 
					
						
							|  |  |  |       val endCapture = System.nanoTime() | 
					
						
							|  |  |  |       Log.d(TAG, "Finished image capture in ${(endCapture - startCapture) / 1_000_000}ms") | 
					
						
							|  |  |  |       pic | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     async(Dispatchers.IO) { | 
					
						
							|  |  |  |       Log.d(CameraView.REACT_CLASS, "Creating temp file...") | 
					
						
							|  |  |  |       File.createTempFile("mrousavy", ".jpg", context.cacheDir).apply { deleteOnExit() } | 
					
						
							| 
									
										
										
										
											2021-02-19 16:28:14 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-02-26 10:56:20 +01:00
										 |  |  |   ) | 
					
						
							|  |  |  |   val photo = results.first { it is ImageProxy } as ImageProxy | 
					
						
							|  |  |  |   val file = results.first { it is File } as File | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   val exif: ExifInterface? | 
					
						
							|  |  |  |   @Suppress("BlockingMethodInNonBlockingContext") | 
					
						
							|  |  |  |   withContext(Dispatchers.IO) { | 
					
						
							|  |  |  |     Log.d(CameraView.REACT_CLASS, "Saving picture to ${file.absolutePath}...") | 
					
						
							|  |  |  |     val startSave = System.nanoTime() | 
					
						
							|  |  |  |     photo.save(file, lensFacing == CameraCharacteristics.LENS_FACING_FRONT) | 
					
						
							|  |  |  |     val endSave = System.nanoTime() | 
					
						
							|  |  |  |     Log.d(TAG, "Finished image saving in ${(endSave - startSave) / 1_000_000}ms") | 
					
						
							|  |  |  |     // TODO: Read Exif from existing in-memory photo buffer instead of file?
 | 
					
						
							|  |  |  |     exif = if (skipMetadata) null else ExifInterface(file) | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2021-02-19 16:28:14 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-26 10:56:20 +01:00
										 |  |  |   val map = Arguments.createMap() | 
					
						
							|  |  |  |   map.putString("path", file.absolutePath) | 
					
						
							|  |  |  |   map.putInt("width", photo.width) | 
					
						
							|  |  |  |   map.putInt("height", photo.height) | 
					
						
							|  |  |  |   map.putBoolean("isRawPhoto", photo.isRaw) | 
					
						
							| 
									
										
										
										
											2021-02-19 16:28:14 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-26 10:56:20 +01:00
										 |  |  |   val metadata = exif?.buildMetadataMap() | 
					
						
							|  |  |  |   map.putMap("metadata", metadata) | 
					
						
							| 
									
										
										
										
											2021-02-19 16:28:14 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-26 10:56:20 +01:00
										 |  |  |   photo.close() | 
					
						
							| 
									
										
										
										
											2021-02-19 16:28:14 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-26 10:56:20 +01:00
										 |  |  |   Log.d(CameraView.REACT_CLASS, "Finished taking photo!") | 
					
						
							| 
									
										
										
										
											2021-02-19 16:28:14 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-26 10:56:20 +01:00
										 |  |  |   val endFunc = System.nanoTime() | 
					
						
							|  |  |  |   Log.d(TAG, "Finished function execution in ${(endFunc - startFunc) / 1_000_000}ms") | 
					
						
							|  |  |  |   return@coroutineScope map | 
					
						
							| 
									
										
										
										
											2021-02-19 16:28:14 +01:00
										 |  |  | } |