diff --git a/README.md b/README.md index 6e4b9c66..2aabf3ca 100644 --- a/README.md +++ b/README.md @@ -168,6 +168,7 @@ Documentation for the [uploader](https://github.com/Cap-go/capacitor-uploader) * [`captureSample(...)`](#capturesample) * [`getSupportedFlashModes()`](#getsupportedflashmodes) * [`getHorizontalFov()`](#gethorizontalfov) +* [`getSupportedPictureSizes()`](#getsupportedpicturesizes) * [`setFlashMode(...)`](#setflashmode) * [`flip()`](#flip) * [`setOpacity(...)`](#setopacity) @@ -279,6 +280,19 @@ Get horizontal field of view. -------------------- +### getSupportedPictureSizes() + +```typescript +getSupportedPictureSizes() => Promise<{ supportedPictureSizes: { facing: string; supportedPictureSizes: { width: number; height: number; }[]; }[]; }> +``` + +Gets the supported picture sizes for a given device. + +**Returns:** Promise<{ supportedPictureSizes: { facing: string; supportedPictureSizes: { width: number; height: number; }[]; }[]; }> + +-------------------- + + ### setFlashMode(...) ```typescript diff --git a/android/src/main/java/com/ahm/capacitor/camera/preview/CameraPreview.java b/android/src/main/java/com/ahm/capacitor/camera/preview/CameraPreview.java index 482b9f7d..cadeec95 100644 --- a/android/src/main/java/com/ahm/capacitor/camera/preview/CameraPreview.java +++ b/android/src/main/java/com/ahm/capacitor/camera/preview/CameraPreview.java @@ -5,11 +5,18 @@ import android.app.FragmentManager; import android.app.FragmentTransaction; +import android.content.Context; import android.content.pm.ActivityInfo; import android.graphics.Color; +import android.graphics.ImageFormat; import android.graphics.Point; import android.hardware.Camera; +import android.hardware.camera2.CameraAccessException; +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CameraManager; +import android.hardware.camera2.params.StreamConfigurationMap; import android.util.DisplayMetrics; +import android.util.Size; import android.util.TypedValue; import android.view.Display; import android.view.MotionEvent; @@ -17,6 +24,7 @@ import android.view.ViewGroup; import android.widget.FrameLayout; import androidx.annotation.NonNull; +import com.getcapacitor.JSArray; import com.getcapacitor.JSObject; import com.getcapacitor.Logger; import com.getcapacitor.PermissionState; @@ -27,6 +35,7 @@ import com.getcapacitor.annotation.Permission; import com.getcapacitor.annotation.PermissionCallback; import java.io.File; +import java.util.ArrayList; import java.util.List; import java.util.Objects; import org.json.JSONArray; @@ -130,6 +139,70 @@ public void captureSample(PluginCall call) { fragment.takeSnapshot(quality); } + @PluginMethod + public void getSupportedPictureSizes(final PluginCall call) { + CameraManager cameraManager = (CameraManager) this.getContext() + .getSystemService(Context.CAMERA_SERVICE); + + JSArray ret = new JSArray(); + try { + String[] cameraIdList = cameraManager.getCameraIdList(); + for (String cameraId : cameraIdList) { + CameraCharacteristics characteristics = + cameraManager.getCameraCharacteristics(cameraId); + + // Determine the facing of the camera + Integer lensFacing = characteristics.get( + CameraCharacteristics.LENS_FACING + ); + String facing = "Unknown"; + if (lensFacing != null) { + switch (lensFacing) { + case CameraCharacteristics.LENS_FACING_FRONT: + facing = "Front"; + break; + case CameraCharacteristics.LENS_FACING_BACK: + facing = "Back"; + break; + case CameraCharacteristics.LENS_FACING_EXTERNAL: + facing = "External"; + break; + } + } + + StreamConfigurationMap map = characteristics.get( + CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP + ); + if (map == null) { + continue; + } + + Size[] jpegSizes = map.getOutputSizes(ImageFormat.JPEG); + JSObject camera = new JSObject(); + camera.put("facing", facing); + JSArray supportedPictureSizes = new JSArray(); + if (jpegSizes != null) { + for (Size size : jpegSizes) { + JSObject sizeJson = new JSObject(); + sizeJson.put("width", size.getWidth()); + sizeJson.put("height", size.getHeight()); + supportedPictureSizes.put(sizeJson); + } + camera.put("supportedPictureSizes", supportedPictureSizes); + ret.put(camera); + } + } + JSObject finalRet = new JSObject(); + finalRet.put("supportedPictureSizes", ret); + call.resolve(finalRet); + } catch (CameraAccessException ex) { + Logger.error(getLogTag(), "Cannot call getSupportedPictureSizes", ex); + call.reject( + String.format("Cannot call getSupportedPictureSizes. Error: %s", ex) + ); + } + } + @PluginMethod public void stop(final PluginCall call) { bridge diff --git a/ios/Plugin/Plugin.m b/ios/Plugin/Plugin.m index b8fb86ce..787ae813 100644 --- a/ios/Plugin/Plugin.m +++ b/ios/Plugin/Plugin.m @@ -14,4 +14,5 @@ CAP_PLUGIN_METHOD(setFlashMode, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(startRecordVideo, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(stopRecordVideo, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(getSupportedPictureSizes, CAPPluginReturnPromise); ) diff --git a/ios/Plugin/Plugin.swift b/ios/Plugin/Plugin.swift index 295969d7..0a33aa92 100644 --- a/ios/Plugin/Plugin.swift +++ b/ios/Plugin/Plugin.swift @@ -81,6 +81,85 @@ public class CameraPreview: CAPPlugin { cameraController.updateVideoOrientation() } + + struct CameraInfo { + let deviceID: String + let position: String + let pictureSizes: [CGSize] + } + + func getSupportedPictureSizes() -> [CameraInfo] { + var cameraInfos = [CameraInfo]() + + // Discover all available cameras + let deviceTypes: [AVCaptureDevice.DeviceType] = [ + .builtInWideAngleCamera, + .builtInTelephotoCamera, + .builtInUltraWideCamera, + .builtInTrueDepthCamera + ] + + let session = AVCaptureDevice.DiscoverySession( + deviceTypes: deviceTypes, + mediaType: .video, + position: .unspecified + ) + + let devices = session.devices + + for device in devices { + // Determine the position of the camera + var position = "Unknown" + switch device.position { + case .front: + position = "Front" + case .back: + position = "Back" + case .unspecified: + position = "Unspecified" + @unknown default: + position = "Unknown" + } + + var pictureSizes = [CGSize]() + + // Get supported formats + for format in device.formats { + let description = format.formatDescription + let dimensions = CMVideoFormatDescriptionGetDimensions(description) + let size = CGSize(width: CGFloat(dimensions.width), height: CGFloat(dimensions.height)) + if !pictureSizes.contains(size) { + pictureSizes.append(size) + } + } + + // Sort sizes in descending order (largest to smallest) + pictureSizes.sort { $0.width * $0.height > $1.width * $1.height } + + let cameraInfo = CameraInfo(deviceID: device.uniqueID, position: position, pictureSizes: pictureSizes) + cameraInfos.append(cameraInfo) + } + + return cameraInfos + } + + + @objc func getSupportedPictureSizes(_ call: CAPPluginCall) { + let cameraInfos = getSupportedPictureSizes() + call.resolve([ + "supportedPictureSizes": cameraInfos.map { + return [ + "facing": $0.position, + "supportedPictureSizes": $0.pictureSizes.map { size in + return [ + "width": String(describing: size.width), + "height": String(describing: size.height), + ] + } + ] + } + ]) + } @objc func start(_ call: CAPPluginCall) { self.cameraPosition = call.getString("position") ?? "rear" diff --git a/src/definitions.ts b/src/definitions.ts index 2bc5cfd2..432e9c99 100644 --- a/src/definitions.ts +++ b/src/definitions.ts @@ -120,6 +120,17 @@ export interface CameraPreviewPlugin { getHorizontalFov(): Promise<{ result: any; }>; + /** + * Gets the supported picture sizes for a given device. + * @returns {Promise} an Promise that resolves with the supported picture sizes for a given device + * @throws An error if the something goes wrong + */ + getSupportedPictureSizes(): Promise<{ + supportedPictureSizes: { + facing: string; + supportedPictureSizes: { width: number; height: number }[]; + }[]; + }>; /** * Set flash mode. * @param options the options to set the flash mode with