@capgo/camera-preview 8.0.14 → 8.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1097,6 +1097,7 @@ Defines the configuration options for starting the camera preview.
1097
1097
  | **`positioning`** | <code><a href="#camerapositioning">CameraPositioning</a></code> | The vertical positioning of the camera preview. | <code>"center"</code> | 2.3.0 |
1098
1098
  | **`enableVideoMode`** | <code>boolean</code> | If true, enables video capture capabilities when the camera starts. | <code>false</code> | 7.11.0 |
1099
1099
  | **`force`** | <code>boolean</code> | If true, forces the camera to start/restart even if it's already running or busy. This will kill the current camera session and start a new one, ignoring all state checks. | <code>false</code> | |
1100
+ | **`videoQuality`** | <code>'low' \| 'medium' \| 'high'</code> | Sets the quality of video for recording. Options: 'low', 'medium', 'high' | <code>"high"</code> | |
1100
1101
 
1101
1102
 
1102
1103
  #### ExifData
@@ -79,6 +79,16 @@ public class CameraPreview extends Plugin implements CameraXView.CameraXViewList
79
79
  protected void handleOnResume() {
80
80
  super.handleOnResume();
81
81
  if (lastSessionConfig != null) {
82
+ // Set to black to avoid flicker, transparent set later
83
+ if (lastSessionConfig.isToBack()) {
84
+ try {
85
+ getBridge()
86
+ .getActivity()
87
+ .getWindow()
88
+ .setBackgroundDrawable(new android.graphics.drawable.ColorDrawable(android.graphics.Color.BLACK));
89
+ getBridge().getWebView().setBackgroundColor(android.graphics.Color.BLACK);
90
+ } catch (Exception ignored) {}
91
+ }
82
92
  // Recreate camera with last known configuration
83
93
  if (cameraXView == null) {
84
94
  cameraXView = new CameraXView(getContext(), getBridge().getWebView());
@@ -894,6 +904,7 @@ public class CameraPreview extends Plugin implements CameraXView.CameraXViewList
894
904
  //noinspection DataFlowIssue
895
905
  final boolean disableFocusIndicator = call.getBoolean("disableFocusIndicator", false);
896
906
  final boolean enableVideoMode = Boolean.TRUE.equals(call.getBoolean("enableVideoMode", false));
907
+ final String videoQuality = call.getString("videoQuality", "high");
897
908
 
898
909
  // Check for conflict between aspectRatio and size
899
910
  if (call.getData().has("aspectRatio") && (call.getData().has("width") || call.getData().has("height"))) {
@@ -1193,7 +1204,8 @@ public class CameraPreview extends Plugin implements CameraXView.CameraXViewList
1193
1204
  aspectRatio,
1194
1205
  gridMode,
1195
1206
  disableFocusIndicator,
1196
- enableVideoMode
1207
+ enableVideoMode,
1208
+ videoQuality
1197
1209
  );
1198
1210
  config.setTargetZoom(finalTargetZoom);
1199
1211
  config.setCentered(isCentered);
@@ -856,10 +856,36 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
856
856
 
857
857
  // Only setup VideoCapture if enableVideoMode is true
858
858
  if (sessionConfig.isVideoModeEnabled()) {
859
- QualitySelector qualitySelector = QualitySelector.fromOrderedList(
860
- Arrays.asList(Quality.FHD, Quality.HD, Quality.SD),
861
- FallbackStrategy.higherQualityOrLowerThan(Quality.FHD)
862
- );
859
+ QualitySelector qualitySelector;
860
+
861
+ // Get quality from sessionConfig default to high if null
862
+ String videoQuality = sessionConfig.getVideoQuality() != null ? sessionConfig.getVideoQuality() : "high";
863
+
864
+ switch (videoQuality.toLowerCase()) {
865
+ case "low":
866
+ // Target SD, allow falling back to lower if needed
867
+ qualitySelector = QualitySelector.fromOrderedList(
868
+ Arrays.asList(Quality.SD, Quality.LOWEST),
869
+ FallbackStrategy.lowerQualityOrHigherThan(Quality.SD)
870
+ );
871
+ break;
872
+ case "medium":
873
+ // Target HD, allow falling back to SD
874
+ qualitySelector = QualitySelector.fromOrderedList(
875
+ Arrays.asList(Quality.HD, Quality.SD),
876
+ FallbackStrategy.lowerQualityOrHigherThan(Quality.HD)
877
+ );
878
+ break;
879
+ case "high":
880
+ default:
881
+ // Target FHD allow falling back SD
882
+ qualitySelector = QualitySelector.fromOrderedList(
883
+ Arrays.asList(Quality.FHD, Quality.HD, Quality.SD),
884
+ FallbackStrategy.higherQualityOrLowerThan(Quality.FHD)
885
+ );
886
+ break;
887
+ }
888
+
863
889
  Recorder recorder = new Recorder.Builder().setQualitySelector(qualitySelector).build();
864
890
  videoCapture = VideoCapture.withOutput(recorder);
865
891
  }
@@ -2736,7 +2762,8 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
2736
2762
  sessionConfig.getAspectRatio(),
2737
2763
  sessionConfig.getGridMode(),
2738
2764
  sessionConfig.getDisableFocusIndicator(),
2739
- sessionConfig.isVideoModeEnabled()
2765
+ sessionConfig.isVideoModeEnabled(),
2766
+ sessionConfig.getVideoQuality()
2740
2767
  );
2741
2768
 
2742
2769
  sessionConfig.setCentered(wasCentered);
@@ -2780,7 +2807,8 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
2780
2807
  sessionConfig.getAspectRatio(), // aspectRatio
2781
2808
  sessionConfig.getGridMode(), // gridMode
2782
2809
  sessionConfig.getDisableFocusIndicator(), // disableFocusIndicator
2783
- sessionConfig.isVideoModeEnabled() // enableVideoMode
2810
+ sessionConfig.isVideoModeEnabled(), // enableVideoMode
2811
+ sessionConfig.getVideoQuality() // videoQuality
2784
2812
  );
2785
2813
 
2786
2814
  sessionConfig.setCentered(wasCentered);
@@ -2898,7 +2926,8 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
2898
2926
  aspectRatio,
2899
2927
  currentGridMode,
2900
2928
  sessionConfig.getDisableFocusIndicator(),
2901
- sessionConfig.isVideoModeEnabled()
2929
+ sessionConfig.isVideoModeEnabled(),
2930
+ sessionConfig.getVideoQuality()
2902
2931
  );
2903
2932
  sessionConfig.setCentered(true);
2904
2933
 
@@ -2972,7 +3001,8 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
2972
3001
  aspectRatio,
2973
3002
  currentGridMode,
2974
3003
  sessionConfig.getDisableFocusIndicator(),
2975
- sessionConfig.isVideoModeEnabled()
3004
+ sessionConfig.isVideoModeEnabled(),
3005
+ sessionConfig.getVideoQuality()
2976
3006
  );
2977
3007
  sessionConfig.setCentered(true);
2978
3008
 
@@ -3033,7 +3063,8 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
3033
3063
  sessionConfig.getAspectRatio(),
3034
3064
  gridMode,
3035
3065
  sessionConfig.getDisableFocusIndicator(),
3036
- sessionConfig.isVideoModeEnabled()
3066
+ sessionConfig.isVideoModeEnabled(),
3067
+ sessionConfig.getVideoQuality()
3037
3068
  );
3038
3069
 
3039
3070
  // Update the grid overlay immediately
@@ -3371,7 +3402,8 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
3371
3402
  calculatedAspectRatio,
3372
3403
  sessionConfig.getGridMode(),
3373
3404
  sessionConfig.getDisableFocusIndicator(),
3374
- sessionConfig.isVideoModeEnabled()
3405
+ sessionConfig.isVideoModeEnabled(),
3406
+ sessionConfig.getVideoQuality()
3375
3407
  );
3376
3408
 
3377
3409
  // If aspect ratio changed due to size update, rebind camera
@@ -24,6 +24,7 @@ public class CameraSessionConfiguration {
24
24
  private final boolean enableVideoMode;
25
25
  private float targetZoom = 1.0f;
26
26
  private boolean isCentered = false;
27
+ private final String videoQuality;
27
28
 
28
29
  public CameraSessionConfiguration(
29
30
  String deviceId,
@@ -42,7 +43,8 @@ public class CameraSessionConfiguration {
42
43
  String aspectRatio,
43
44
  String gridMode,
44
45
  boolean disableFocusIndicator,
45
- boolean enableVideoMode
46
+ boolean enableVideoMode,
47
+ String videoQuality
46
48
  ) {
47
49
  this.deviceId = deviceId;
48
50
  this.position = position;
@@ -61,6 +63,7 @@ public class CameraSessionConfiguration {
61
63
  this.gridMode = gridMode != null ? gridMode : "none";
62
64
  this.disableFocusIndicator = disableFocusIndicator;
63
65
  this.enableVideoMode = enableVideoMode;
66
+ this.videoQuality = videoQuality != null ? videoQuality : "high";
64
67
  }
65
68
 
66
69
  public void setTargetZoom(float zoom) {
@@ -131,6 +134,10 @@ public class CameraSessionConfiguration {
131
134
  return gridMode;
132
135
  }
133
136
 
137
+ public String getVideoQuality() {
138
+ return videoQuality;
139
+ }
140
+
134
141
  // Additional getters with "get" prefix for compatibility
135
142
  public boolean getToBack() {
136
143
  return toBack;
package/dist/docs.json CHANGED
@@ -1449,6 +1449,30 @@
1449
1449
  "docs": "If true, forces the camera to start/restart even if it's already running or busy.\nThis will kill the current camera session and start a new one, ignoring all state checks.",
1450
1450
  "complexTypes": [],
1451
1451
  "type": "boolean | undefined"
1452
+ },
1453
+ {
1454
+ "name": "videoQuality",
1455
+ "tags": [
1456
+ {
1457
+ "text": "On Android requires 'enableVideoMode' to be true",
1458
+ "name": "note"
1459
+ },
1460
+ {
1461
+ "text": "Will affect the entire preview stream for iOS",
1462
+ "name": "note"
1463
+ },
1464
+ {
1465
+ "text": "ios, android",
1466
+ "name": "platform"
1467
+ },
1468
+ {
1469
+ "text": "\"high\"",
1470
+ "name": "default"
1471
+ }
1472
+ ],
1473
+ "docs": "Sets the quality of video for recording.\nOptions: 'low', 'medium', 'high'",
1474
+ "complexTypes": [],
1475
+ "type": "'low' | 'medium' | 'high' | undefined"
1452
1476
  }
1453
1477
  ]
1454
1478
  },
@@ -218,6 +218,15 @@ export interface CameraPreviewOptions {
218
218
  * @platform android, ios, web
219
219
  */
220
220
  force?: boolean;
221
+ /**
222
+ * Sets the quality of video for recording.
223
+ * Options: 'low', 'medium', 'high'
224
+ * @note On Android requires 'enableVideoMode' to be true
225
+ * @note Will affect the entire preview stream for iOS
226
+ * @platform ios, android
227
+ * @default "high"
228
+ */
229
+ videoQuality?: 'low' | 'medium' | 'high';
221
230
  }
222
231
  /**
223
232
  * Defines the options for capturing a picture.
@@ -1 +1 @@
1
- {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"AAwBA,MAAM,CAAN,IAAY,UAQX;AARD,WAAY,UAAU;IACpB,sCAAwB,CAAA;IACxB,sCAAwB,CAAA;IACxB,qCAAuB,CAAA;IACvB,sCAAwB,CAAA;IACxB,2BAAa,CAAA;IACb,oCAAsB,CAAA;IACtB,+BAAiB,CAAA;AACnB,CAAC,EARW,UAAU,KAAV,UAAU,QAQrB","sourcesContent":["import type { PermissionState, PluginListenerHandle } from '@capacitor/core';\n\nexport type CameraPosition = 'rear' | 'front';\n\nexport type FlashMode = CameraPreviewFlashMode;\n\nexport type GridMode = 'none' | '3x3' | '4x4';\n\nexport type CameraPositioning = 'center' | 'top' | 'bottom';\n\nexport interface CameraPermissionStatus {\n camera: PermissionState;\n microphone?: PermissionState;\n}\n\nexport interface PermissionRequestOptions {\n disableAudio?: boolean;\n showSettingsAlert?: boolean;\n title?: string;\n message?: string;\n openSettingsButtonTitle?: string;\n cancelButtonTitle?: string;\n}\n\nexport enum DeviceType {\n ULTRA_WIDE = 'ultraWide',\n WIDE_ANGLE = 'wideAngle',\n TELEPHOTO = 'telephoto',\n TRUE_DEPTH = 'trueDepth',\n DUAL = 'dual',\n DUAL_WIDE = 'dualWide',\n TRIPLE = 'triple',\n}\n\n/**\n * Represents a single camera lens on a device. A {@link CameraDevice} can have multiple lenses.\n */\nexport interface CameraLens {\n /** A human-readable name for the lens, e.g., \"Ultra-Wide\". */\n label: string;\n /** The type of the camera lens. */\n deviceType: DeviceType;\n /** The focal length of the lens in millimeters. */\n focalLength: number;\n /** The base zoom factor for this lens (e.g., 0.5 for ultra-wide, 1.0 for wide). */\n baseZoomRatio: number;\n /** The minimum zoom factor supported by this specific lens. */\n minZoom: number;\n /** The maximum zoom factor supported by this specific lens. */\n maxZoom: number;\n}\n\n/**\n * Represents a physical camera on the device (e.g., the front-facing camera).\n */\nexport interface CameraDevice {\n /** A unique identifier for the camera device. */\n deviceId: string;\n /** A human-readable name for the camera device. */\n label: string;\n /** The physical position of the camera on the device. */\n position: CameraPosition;\n /** A list of all available lenses for this camera device. */\n lenses: CameraLens[];\n /** The overall minimum zoom factor available across all lenses on this device. */\n minZoom: number;\n /** The overall maximum zoom factor available across all lenses on this device. */\n maxZoom: number;\n /** Identifies whether the device is a logical camera (composed of multiple physical lenses). */\n isLogical: boolean;\n}\n\n/**\n * Represents the detailed information of the currently active lens.\n */\nexport interface LensInfo {\n /** The focal length of the active lens in millimeters. */\n focalLength: number;\n /** The device type of the active lens. */\n deviceType: DeviceType;\n /** The base zoom ratio of the active lens (e.g., 0.5x, 1.0x). */\n baseZoomRatio: number;\n /** The current digital zoom factor applied on top of the base zoom. */\n digitalZoom: number;\n}\n\n/**\n * Defines the configuration options for starting the camera preview.\n */\nexport interface CameraPreviewOptions {\n /**\n * The parent element to attach the video preview to.\n * @platform web\n */\n parent?: string;\n /**\n * A CSS class name to add to the preview element.\n * @platform web\n */\n className?: string;\n /**\n * The width of the preview in pixels. Defaults to the screen width.\n * @platform android, ios, web\n */\n width?: number;\n /**\n * The height of the preview in pixels. Defaults to the screen height.\n * @platform android, ios, web\n */\n height?: number;\n /**\n * The horizontal origin of the preview, in pixels.\n * @platform android, ios\n */\n x?: number;\n /**\n * The vertical origin of the preview, in pixels.\n * @platform android, ios\n */\n y?: number;\n /**\n * The aspect ratio of the camera preview, '4:3' or '16:9' or 'fill'.\n * Cannot be set if width or height is provided, otherwise the call will be rejected.\n * Use setPreviewSize to adjust size after starting.\n *\n * @since 2.0.0\n */\n aspectRatio?: '4:3' | '16:9';\n /**\n * The grid overlay to display on the camera preview.\n * @default \"none\"\n * @since 2.1.0\n */\n gridMode?: GridMode;\n /**\n * Adjusts the y-position to account for safe areas (e.g., notches).\n * @platform ios\n * @default false\n */\n includeSafeAreaInsets?: boolean;\n /**\n * If true, places the preview behind the webview.\n * @platform android\n * @default true\n */\n toBack?: boolean;\n /**\n * Bottom padding for the preview, in pixels.\n * @platform android, ios\n */\n paddingBottom?: number;\n /**\n * Whether to rotate the preview when the device orientation changes.\n * @platform ios\n * @default true\n */\n rotateWhenOrientationChanged?: boolean;\n /**\n * The camera to use.\n * @default \"rear\"\n */\n position?: CameraPosition | string;\n /**\n * If true, saves the captured image to a file and returns the file path.\n * If false, returns a base64 encoded string.\n * @default false\n */\n storeToFile?: boolean;\n /**\n * If true, prevents the plugin from rotating the image based on EXIF data.\n * @platform android\n * @default false\n */\n disableExifHeaderStripping?: boolean;\n /**\n * If true, disables the audio stream, preventing audio permission requests.\n * @default true\n */\n disableAudio?: boolean;\n /**\n * If true, locks the device orientation while the camera is active.\n * @platform android\n * @default false\n */\n lockAndroidOrientation?: boolean;\n /**\n * If true, allows the camera preview's opacity to be changed.\n * @platform android, web\n * @default false\n */\n enableOpacity?: boolean;\n\n /**\n * If true, disables the visual focus indicator when tapping to focus.\n * @platform android, ios\n * @default false\n */\n disableFocusIndicator?: boolean;\n /**\n * The `deviceId` of the camera to use. If provided, `position` is ignored.\n * @platform ios\n */\n deviceId?: string;\n /**\n * The initial zoom level when starting the camera preview.\n * If the requested zoom level is not available, the native plugin will reject.\n * @default 1.0\n * @platform android, ios\n * @since 2.2.0\n */\n initialZoomLevel?: number;\n /**\n * The vertical positioning of the camera preview.\n * @default \"center\"\n * @platform android, ios, web\n * @since 2.3.0\n */\n positioning?: CameraPositioning;\n /**\n * If true, enables video capture capabilities when the camera starts.\n * @default false\n * @platform android\n * @since 7.11.0\n */\n enableVideoMode?: boolean;\n /**\n * If true, forces the camera to start/restart even if it's already running or busy.\n * This will kill the current camera session and start a new one, ignoring all state checks.\n * @default false\n * @platform android, ios, web\n */\n force?: boolean;\n}\n\n/**\n * Defines the options for capturing a picture.\n */\nexport interface CameraPreviewPictureOptions {\n /**\n * The maximum height of the picture in pixels. The image will be resized to fit within this height while maintaining aspect ratio.\n * If not specified the captured image will match the preview's visible area.\n */\n height?: number;\n /**\n * The maximum width of the picture in pixels. The image will be resized to fit within this width while maintaining aspect ratio.\n * If not specified the captured image will match the preview's visible area.\n */\n width?: number;\n /**\n * The quality of the captured image, from 0 to 100.\n * Does not apply to `png` format.\n * @default 85\n */\n quality?: number;\n /**\n * The format of the captured image.\n * @default \"jpeg\"\n */\n format?: PictureFormat;\n /**\n * If true, the captured image will be saved to the user's gallery.\n * @default false\n * @since 7.5.0\n */\n saveToGallery?: boolean;\n /**\n * If true, the plugin will attempt to add GPS location data to the image's EXIF metadata.\n * This may prompt the user for location permissions.\n * @default false\n * @since 7.6.0\n */\n withExifLocation?: boolean;\n /**\n * If true, the plugin will embed a timestamp in the top-right corner of the image.\n * @default false\n * @since 7.17.0\n */\n embedTimestamp?: boolean;\n /**\n * If true, the plugin will embed the current location in the top-right corner of the image.\n * Requires `withExifLocation` to be enabled.\n * @default false\n * @since 7.18.0\n */\n embedLocation?: boolean;\n /**\n * Sets the priority for photo quality vs. capture speed.\n * - \"speed\": Prioritizes faster capture times, may reduce image quality.\n * - \"balanced\": Aims for a balance between quality and speed.\n * - \"quality\": Prioritizes image quality, may reduce capture speed.\n * See https://developer.apple.com/documentation/avfoundation/avcapturephotosettings/photoqualityprioritization for details.\n *\n * @since 7.21.0\n * @platform ios\n * @default \"speed\"\n */\n photoQualityPrioritization?: 'speed' | 'balanced' | 'quality';\n}\n\n/** Represents EXIF data extracted from an image. */\nexport interface ExifData {\n [key: string]: any;\n}\n\nexport type PictureFormat = 'jpeg' | 'png';\n\n/** Defines a standard picture size with width and height. */\nexport interface PictureSize {\n /** The width of the picture in pixels. */\n width: number;\n /** The height of the picture in pixels. */\n height: number;\n}\n\n/** Represents the supported picture sizes for a camera facing a certain direction. */\nexport interface SupportedPictureSizes {\n /** The camera direction (\"front\" or \"rear\"). */\n facing: string;\n /** A list of supported picture sizes for this camera. */\n supportedPictureSizes: PictureSize[];\n}\n\n/**\n * Defines the options for capturing a sample frame from the camera preview.\n */\nexport interface CameraSampleOptions {\n /**\n * The quality of the captured sample, from 0 to 100.\n * @default 85\n */\n quality?: number;\n}\n\n/**\n * The available flash modes for the camera.\n * 'torch' is a continuous light mode.\n */\nexport type CameraPreviewFlashMode = 'off' | 'on' | 'auto' | 'torch';\n\n/** Reusable exposure mode type for cross-platform support. */\nexport type ExposureMode = 'AUTO' | 'LOCK' | 'CONTINUOUS' | 'CUSTOM';\n\n/**\n * Defines the options for setting the camera preview's opacity.\n */\nexport interface CameraOpacityOptions {\n /**\n * The opacity percentage, from 0.0 (fully transparent) to 1.0 (fully opaque).\n * @default 1.0\n */\n opacity?: number;\n}\n\n/**\n * Represents safe area insets for devices.\n * Android: Values are expressed in logical pixels (dp) to match JS layout units.\n * iOS: Values are expressed in physical pixels and exclude status bar.\n */\nexport interface SafeAreaInsets {\n /** Current device orientation (1 = portrait, 2 = landscape, 0 = unknown). */\n orientation: number;\n /**\n * Orientation-aware notch/camera cutout inset (excluding status bar).\n * In portrait mode: returns top inset (notch at top).\n * In landscape mode: returns left inset (notch at side).\n * Android: Value in dp, iOS: Value in pixels (status bar excluded).\n */\n top: number;\n}\n\n/**\n * Canonical device orientation values across platforms.\n */\nexport type DeviceOrientation = 'portrait' | 'landscape-left' | 'landscape-right' | 'portrait-upside-down' | 'unknown';\n\n/**\n * The main interface for the CameraPreview plugin.\n */\nexport interface CameraPreviewPlugin {\n /**\n * Starts the camera preview.\n *\n * @param {CameraPreviewOptions} options - The configuration for the camera preview.\n * @returns {Promise<{ width: number; height: number; x: number; y: number }>} A promise that resolves with the preview dimensions.\n * @since 0.0.1\n */\n start(options: CameraPreviewOptions): Promise<{\n /** The width of the preview in pixels. */\n width: number;\n /** The height of the preview in pixels. */\n height: number;\n /** The horizontal origin of the preview, in pixels. */\n x: number;\n /** The vertical origin of the preview, in pixels. */\n y: number;\n }>;\n\n /**\n * Stops the camera preview.\n *\n * @param {object} options - Optional configuration for stopping the camera.\n * @param {boolean} options.force - If true, forces the camera to stop even if busy or capturing. Default: false.\n * @returns {Promise<void>} A promise that resolves when the camera preview is stopped.\n * @since 0.0.1\n */\n stop(options?: { force?: boolean }): Promise<void>;\n\n /**\n * Captures a picture from the camera.\n *\n * If `storeToFile` was set to `true` when starting the preview, the returned\n * `value` will be an absolute file path on the device instead of a base64 string. Use getBase64FromFilePath to get the base64 string from the file path.\n *\n * @param {CameraPreviewPictureOptions} options - The options for capturing the picture.\n * @returns {Promise<{ value: string; exif: ExifData }>} Resolves with:\n * - `value`: base64 string, or file path if `storeToFile` is true\n * - `exif`: extracted EXIF metadata when available\n * @since 0.0.1\n */\n capture(options: CameraPreviewPictureOptions): Promise<{ value: string; exif: ExifData }>;\n\n /**\n * Captures a single frame from the camera preview stream.\n *\n * @param {CameraSampleOptions} options - The options for capturing the sample.\n * @returns {Promise<{ value: string }>} A promise that resolves with the sample image as a base64 encoded string.\n * @since 0.0.1\n */\n captureSample(options: CameraSampleOptions): Promise<{ value: string }>;\n\n /**\n * Gets the flash modes supported by the active camera.\n *\n * @returns {Promise<{ result: CameraPreviewFlashMode[] }>} A promise that resolves with an array of supported flash modes.\n * @since 0.0.1\n */\n getSupportedFlashModes(): Promise<{\n result: CameraPreviewFlashMode[];\n }>;\n\n /**\n * Set the aspect ratio of the camera preview.\n *\n * @param {{ aspectRatio: '4:3' | '16:9'; x?: number; y?: number }} options - The desired aspect ratio and optional position.\n * - aspectRatio: The desired aspect ratio ('4:3' or '16:9')\n * - x: Optional x coordinate for positioning. If not provided, view will be auto-centered horizontally.\n * - y: Optional y coordinate for positioning. If not provided, view will be auto-centered vertically.\n * @returns {Promise<{ width: number; height: number; x: number; y: number }>} A promise that resolves with the actual preview dimensions and position.\n * @since 7.5.0\n * @platform android, ios\n */\n setAspectRatio(options: { aspectRatio: '4:3' | '16:9'; x?: number; y?: number }): Promise<{\n width: number;\n height: number;\n x: number;\n y: number;\n }>;\n\n /**\n * Gets the current aspect ratio of the camera preview.\n *\n * @returns {Promise<{ aspectRatio: '4:3' | '16:9' }>} A promise that resolves with the current aspect ratio.\n * @since 7.5.0\n * @platform android, ios\n */\n getAspectRatio(): Promise<{ aspectRatio: '4:3' | '16:9' }>;\n\n /**\n * Sets the grid mode of the camera preview overlay.\n *\n * @param {{ gridMode: GridMode }} options - The desired grid mode ('none', '3x3', or '4x4').\n * @returns {Promise<void>} A promise that resolves when the grid mode is set.\n * @since 8.0.0\n */\n setGridMode(options: { gridMode: GridMode }): Promise<void>;\n\n /**\n * Gets the current grid mode of the camera preview overlay.\n *\n * @returns {Promise<{ gridMode: GridMode }>} A promise that resolves with the current grid mode.\n * @since 8.0.0\n */\n getGridMode(): Promise<{ gridMode: GridMode }>;\n\n /**\n * Checks the current camera (and optionally microphone) permission status without prompting the system dialog.\n *\n * @param options Set `disableAudio` to `false` to also include microphone status (defaults to `true`).\n * @returns {Promise<CameraPermissionStatus>} A promise resolving to the current authorization states.\n * @since 8.7.0\n */\n checkPermissions(options?: Pick<PermissionRequestOptions, 'disableAudio'>): Promise<CameraPermissionStatus>;\n\n /**\n * Requests camera (and optional microphone) permissions. If permissions are already granted or denied,\n * the current status is returned without prompting. When `showSettingsAlert` is true and permissions are denied,\n * a platform specific alert guiding the user to the app settings will be presented.\n *\n * @param {PermissionRequestOptions} options - Configuration for the permission request behaviour.\n * @returns {Promise<CameraPermissionStatus>} A promise resolving to the final authorization states.\n * @since 8.7.0\n */\n requestPermissions(options?: PermissionRequestOptions): Promise<CameraPermissionStatus>;\n\n /**\n * Gets the horizontal field of view (FoV) for the active camera.\n * Note: This can be an estimate on some devices.\n *\n * @returns {Promise<{ result: number }>} A promise that resolves with the horizontal field of view in degrees.\n * @since 0.0.1\n */\n getHorizontalFov(): Promise<{\n result: number;\n }>;\n\n /**\n * Gets the supported picture sizes for all cameras.\n *\n * @returns {Promise<{ supportedPictureSizes: SupportedPictureSizes[] }>} A promise that resolves with the list of supported sizes.\n * @since 7.4.0\n */\n getSupportedPictureSizes(): Promise<{\n supportedPictureSizes: SupportedPictureSizes[];\n }>;\n\n /**\n * Sets the flash mode for the active camera.\n *\n * @param {{ flashMode: CameraPreviewFlashMode | string }} options - The desired flash mode.\n * @returns {Promise<void>} A promise that resolves when the flash mode is set.\n * @since 0.0.1\n */\n setFlashMode(options: { flashMode: CameraPreviewFlashMode | string }): Promise<void>;\n\n /**\n * Toggles between the front and rear cameras.\n *\n * @returns {Promise<void>} A promise that resolves when the camera is flipped.\n * @since 0.0.1\n */\n flip(): Promise<void>;\n\n /**\n * Sets the opacity of the camera preview.\n *\n * @param {CameraOpacityOptions} options - The opacity options.\n * @returns {Promise<void>} A promise that resolves when the opacity is set.\n * @since 0.0.1\n */\n setOpacity(options: CameraOpacityOptions): Promise<void>;\n\n /**\n * Stops an ongoing video recording.\n *\n * @returns {Promise<{ videoFilePath: string }>} A promise that resolves with the path to the recorded video file.\n * @since 0.0.1\n */\n stopRecordVideo(): Promise<{ videoFilePath: string }>;\n\n /**\n * Starts recording a video.\n *\n * @param {CameraPreviewOptions} options - The options for video recording. Only iOS.\n * @returns {Promise<void>} A promise that resolves when video recording starts.\n * @since 0.0.1\n */\n startRecordVideo(options: CameraPreviewOptions): Promise<void>;\n\n /**\n * Checks if the camera preview is currently running.\n *\n * @returns {Promise<{ isRunning: boolean }>} A promise that resolves with the running state.\n * @since 7.5.0\n * @platform android, ios\n */\n isRunning(): Promise<{ isRunning: boolean }>;\n\n /**\n * Gets all available camera devices.\n *\n * @returns {Promise<{ devices: CameraDevice[] }>} A promise that resolves with the list of available camera devices.\n * @since 7.5.0\n * @platform android, ios\n */\n getAvailableDevices(): Promise<{ devices: CameraDevice[] }>;\n\n /**\n * Gets the current zoom state, including min/max and current lens info.\n *\n * @returns {Promise<{ min: number; max: number; current: number; lens: LensInfo }>} A promise that resolves with the zoom state.\n * @since 7.5.0\n * @platform android, ios\n */\n getZoom(): Promise<{\n min: number;\n max: number;\n current: number;\n lens: LensInfo;\n }>;\n\n /**\n * Returns zoom button values for quick switching.\n * - iOS/Android: includes 0.5 if ultra-wide available; 1 and 2 if wide available; 3 if telephoto available\n * - Web: unsupported\n * @since 7.5.0\n * @platform android, ios\n */\n getZoomButtonValues(): Promise<{ values: number[] }>;\n\n /**\n * Sets the zoom level of the camera.\n *\n * @param {{ level: number; ramp?: boolean; autoFocus?: boolean }} options - The desired zoom level. `ramp` is currently unused. `autoFocus` defaults to true.\n * @returns {Promise<void>} A promise that resolves when the zoom level is set.\n * @since 7.5.0\n * @platform android, ios\n */\n setZoom(options: { level: number; ramp?: boolean; autoFocus?: boolean }): Promise<void>;\n\n /**\n * Gets the current flash mode.\n *\n * @returns {Promise<{ flashMode: FlashMode }>} A promise that resolves with the current flash mode.\n * @since 7.5.0\n * @platform android, ios\n */\n getFlashMode(): Promise<{ flashMode: FlashMode }>;\n\n /**\n * Removes all registered listeners.\n *\n * @since 7.5.0\n * @platform android, ios\n */\n removeAllListeners(): Promise<void>;\n\n /**\n * Switches the active camera to the one with the specified `deviceId`.\n *\n * @param {{ deviceId: string }} options - The ID of the device to switch to.\n * @returns {Promise<void>} A promise that resolves when the camera is switched.\n * @since 7.5.0\n * @platform android, ios\n */\n setDeviceId(options: { deviceId: string }): Promise<void>;\n\n /**\n * Gets the ID of the currently active camera device.\n *\n * @returns {Promise<{ deviceId: string }>} A promise that resolves with the current device ID.\n * @since 7.5.0\n * @platform android, ios\n */\n getDeviceId(): Promise<{ deviceId: string }>;\n\n /**\n * Gets the current preview size and position.\n * @returns {Promise<{x: number, y: number, width: number, height: number}>}\n * @since 7.5.0\n * @platform android, ios\n */\n getPreviewSize(): Promise<{\n x: number;\n y: number;\n width: number;\n height: number;\n }>;\n /**\n * Sets the preview size and position.\n * @param options The new position and dimensions.\n * @returns {Promise<{ width: number; height: number; x: number; y: number }>} A promise that resolves with the actual preview dimensions and position.\n * @since 7.5.0\n * @platform android, ios\n */\n setPreviewSize(options: { x?: number; y?: number; width: number; height: number }): Promise<{\n width: number;\n height: number;\n x: number;\n y: number;\n }>;\n\n /**\n * Sets the camera focus to a specific point in the preview.\n *\n * Note: The plugin does not attach any native tap-to-focus gesture handlers. Handle taps in\n * your HTML/JS (e.g., on the overlaying UI), then pass normalized coordinates here.\n *\n * @param {Object} options - The focus options.\n * @param {number} options.x - The x coordinate in the preview view to focus on (0-1 normalized).\n * @param {number} options.y - The y coordinate in the preview view to focus on (0-1 normalized).\n * @returns {Promise<void>} A promise that resolves when the focus is set.\n * @since 7.5.0\n * @platform android, ios\n */\n setFocus(options: { x: number; y: number }): Promise<void>;\n\n /**\n * Adds a listener for screen resize events.\n * @param {string} eventName - The event name to listen for.\n * @param {Function} listenerFunc - The function to call when the event is triggered.\n * @returns {Promise<PluginListenerHandle>} A promise that resolves with a handle to the listener.\n * @since 7.5.0\n * @platform android, ios\n */\n addListener(\n eventName: 'screenResize',\n listenerFunc: (data: { width: number; height: number; x: number; y: number }) => void,\n ): Promise<PluginListenerHandle>;\n\n /**\n * Adds a listener for orientation change events.\n * @param {string} eventName - The event name to listen for.\n * @param {Function} listenerFunc - The function to call when the event is triggered.\n * @returns {Promise<PluginListenerHandle>} A promise that resolves with a handle to the listener.\n * @since 7.5.0\n * @platform android, ios\n */\n addListener(\n eventName: 'orientationChange',\n listenerFunc: (data: { orientation: DeviceOrientation }) => void,\n ): Promise<PluginListenerHandle>;\n /**\n * Deletes a file at the given absolute path on the device.\n * Use this to quickly clean up temporary images created with `storeToFile`.\n * On web, this is not supported and will throw.\n * @since 7.5.0\n * @platform android, ios\n */\n deleteFile(options: { path: string }): Promise<{ success: boolean }>;\n\n /**\n * Gets the safe area insets for devices.\n * Returns the orientation-aware notch/camera cutout inset and the current orientation.\n * In portrait mode: returns top inset (notch at top).\n * In landscape mode: returns left inset (notch moved to side).\n * This specifically targets the cutout area (notch, punch hole, etc.) that all modern phones have.\n *\n * Android: Values returned in dp (logical pixels).\n * iOS: Values returned in physical pixels, excluding status bar (only pure notch/cutout size).\n *\n * @platform android, ios\n */\n getSafeAreaInsets(): Promise<SafeAreaInsets>;\n\n /**\n * Gets the current device orientation in a cross-platform format.\n * @since 7.5.0\n * @platform android, ios\n */\n getOrientation(): Promise<{ orientation: DeviceOrientation }>;\n\n /**\n * Returns the exposure modes supported by the active camera.\n * Modes can include: 'locked', 'auto', 'continuous', 'custom'.\n * @platform android, ios\n */\n getExposureModes(): Promise<{ modes: ExposureMode[] }>;\n\n /**\n * Returns the current exposure mode.\n * @platform android, ios\n */\n getExposureMode(): Promise<{ mode: ExposureMode }>;\n\n /**\n * Sets the exposure mode.\n * @platform android, ios\n */\n setExposureMode(options: { mode: ExposureMode }): Promise<void>;\n\n /**\n * Returns the exposure compensation (EV bias) supported range.\n * @platform ios, android\n */\n getExposureCompensationRange(): Promise<{\n min: number;\n max: number;\n step: number;\n }>;\n\n /**\n * Returns the current exposure compensation (EV bias).\n * @platform ios, android\n */\n getExposureCompensation(): Promise<{ value: number }>;\n\n /**\n * Sets the exposure compensation (EV bias). Value will be clamped to range.\n * @platform ios, android\n */\n setExposureCompensation(options: { value: number }): Promise<void>;\n\n /**\n * Get the native Capacitor plugin version\n *\n * @returns {Promise<{ id: string }>} an Promise with version for this device\n * @throws An error if the something went wrong\n */\n getPluginVersion(): Promise<{ version: string }>;\n}\n"]}
1
+ {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"AAwBA,MAAM,CAAN,IAAY,UAQX;AARD,WAAY,UAAU;IACpB,sCAAwB,CAAA;IACxB,sCAAwB,CAAA;IACxB,qCAAuB,CAAA;IACvB,sCAAwB,CAAA;IACxB,2BAAa,CAAA;IACb,oCAAsB,CAAA;IACtB,+BAAiB,CAAA;AACnB,CAAC,EARW,UAAU,KAAV,UAAU,QAQrB","sourcesContent":["import type { PermissionState, PluginListenerHandle } from '@capacitor/core';\n\nexport type CameraPosition = 'rear' | 'front';\n\nexport type FlashMode = CameraPreviewFlashMode;\n\nexport type GridMode = 'none' | '3x3' | '4x4';\n\nexport type CameraPositioning = 'center' | 'top' | 'bottom';\n\nexport interface CameraPermissionStatus {\n camera: PermissionState;\n microphone?: PermissionState;\n}\n\nexport interface PermissionRequestOptions {\n disableAudio?: boolean;\n showSettingsAlert?: boolean;\n title?: string;\n message?: string;\n openSettingsButtonTitle?: string;\n cancelButtonTitle?: string;\n}\n\nexport enum DeviceType {\n ULTRA_WIDE = 'ultraWide',\n WIDE_ANGLE = 'wideAngle',\n TELEPHOTO = 'telephoto',\n TRUE_DEPTH = 'trueDepth',\n DUAL = 'dual',\n DUAL_WIDE = 'dualWide',\n TRIPLE = 'triple',\n}\n\n/**\n * Represents a single camera lens on a device. A {@link CameraDevice} can have multiple lenses.\n */\nexport interface CameraLens {\n /** A human-readable name for the lens, e.g., \"Ultra-Wide\". */\n label: string;\n /** The type of the camera lens. */\n deviceType: DeviceType;\n /** The focal length of the lens in millimeters. */\n focalLength: number;\n /** The base zoom factor for this lens (e.g., 0.5 for ultra-wide, 1.0 for wide). */\n baseZoomRatio: number;\n /** The minimum zoom factor supported by this specific lens. */\n minZoom: number;\n /** The maximum zoom factor supported by this specific lens. */\n maxZoom: number;\n}\n\n/**\n * Represents a physical camera on the device (e.g., the front-facing camera).\n */\nexport interface CameraDevice {\n /** A unique identifier for the camera device. */\n deviceId: string;\n /** A human-readable name for the camera device. */\n label: string;\n /** The physical position of the camera on the device. */\n position: CameraPosition;\n /** A list of all available lenses for this camera device. */\n lenses: CameraLens[];\n /** The overall minimum zoom factor available across all lenses on this device. */\n minZoom: number;\n /** The overall maximum zoom factor available across all lenses on this device. */\n maxZoom: number;\n /** Identifies whether the device is a logical camera (composed of multiple physical lenses). */\n isLogical: boolean;\n}\n\n/**\n * Represents the detailed information of the currently active lens.\n */\nexport interface LensInfo {\n /** The focal length of the active lens in millimeters. */\n focalLength: number;\n /** The device type of the active lens. */\n deviceType: DeviceType;\n /** The base zoom ratio of the active lens (e.g., 0.5x, 1.0x). */\n baseZoomRatio: number;\n /** The current digital zoom factor applied on top of the base zoom. */\n digitalZoom: number;\n}\n\n/**\n * Defines the configuration options for starting the camera preview.\n */\nexport interface CameraPreviewOptions {\n /**\n * The parent element to attach the video preview to.\n * @platform web\n */\n parent?: string;\n /**\n * A CSS class name to add to the preview element.\n * @platform web\n */\n className?: string;\n /**\n * The width of the preview in pixels. Defaults to the screen width.\n * @platform android, ios, web\n */\n width?: number;\n /**\n * The height of the preview in pixels. Defaults to the screen height.\n * @platform android, ios, web\n */\n height?: number;\n /**\n * The horizontal origin of the preview, in pixels.\n * @platform android, ios\n */\n x?: number;\n /**\n * The vertical origin of the preview, in pixels.\n * @platform android, ios\n */\n y?: number;\n /**\n * The aspect ratio of the camera preview, '4:3' or '16:9' or 'fill'.\n * Cannot be set if width or height is provided, otherwise the call will be rejected.\n * Use setPreviewSize to adjust size after starting.\n *\n * @since 2.0.0\n */\n aspectRatio?: '4:3' | '16:9';\n /**\n * The grid overlay to display on the camera preview.\n * @default \"none\"\n * @since 2.1.0\n */\n gridMode?: GridMode;\n /**\n * Adjusts the y-position to account for safe areas (e.g., notches).\n * @platform ios\n * @default false\n */\n includeSafeAreaInsets?: boolean;\n /**\n * If true, places the preview behind the webview.\n * @platform android\n * @default true\n */\n toBack?: boolean;\n /**\n * Bottom padding for the preview, in pixels.\n * @platform android, ios\n */\n paddingBottom?: number;\n /**\n * Whether to rotate the preview when the device orientation changes.\n * @platform ios\n * @default true\n */\n rotateWhenOrientationChanged?: boolean;\n /**\n * The camera to use.\n * @default \"rear\"\n */\n position?: CameraPosition | string;\n /**\n * If true, saves the captured image to a file and returns the file path.\n * If false, returns a base64 encoded string.\n * @default false\n */\n storeToFile?: boolean;\n /**\n * If true, prevents the plugin from rotating the image based on EXIF data.\n * @platform android\n * @default false\n */\n disableExifHeaderStripping?: boolean;\n /**\n * If true, disables the audio stream, preventing audio permission requests.\n * @default true\n */\n disableAudio?: boolean;\n /**\n * If true, locks the device orientation while the camera is active.\n * @platform android\n * @default false\n */\n lockAndroidOrientation?: boolean;\n /**\n * If true, allows the camera preview's opacity to be changed.\n * @platform android, web\n * @default false\n */\n enableOpacity?: boolean;\n\n /**\n * If true, disables the visual focus indicator when tapping to focus.\n * @platform android, ios\n * @default false\n */\n disableFocusIndicator?: boolean;\n /**\n * The `deviceId` of the camera to use. If provided, `position` is ignored.\n * @platform ios\n */\n deviceId?: string;\n /**\n * The initial zoom level when starting the camera preview.\n * If the requested zoom level is not available, the native plugin will reject.\n * @default 1.0\n * @platform android, ios\n * @since 2.2.0\n */\n initialZoomLevel?: number;\n /**\n * The vertical positioning of the camera preview.\n * @default \"center\"\n * @platform android, ios, web\n * @since 2.3.0\n */\n positioning?: CameraPositioning;\n /**\n * If true, enables video capture capabilities when the camera starts.\n * @default false\n * @platform android\n * @since 7.11.0\n */\n enableVideoMode?: boolean;\n /**\n * If true, forces the camera to start/restart even if it's already running or busy.\n * This will kill the current camera session and start a new one, ignoring all state checks.\n * @default false\n * @platform android, ios, web\n */\n force?: boolean;\n /**\n * Sets the quality of video for recording.\n * Options: 'low', 'medium', 'high'\n * @note On Android requires 'enableVideoMode' to be true\n * @note Will affect the entire preview stream for iOS\n * @platform ios, android\n * @default \"high\"\n */\n videoQuality?: 'low' | 'medium' | 'high';\n}\n\n/**\n * Defines the options for capturing a picture.\n */\nexport interface CameraPreviewPictureOptions {\n /**\n * The maximum height of the picture in pixels. The image will be resized to fit within this height while maintaining aspect ratio.\n * If not specified the captured image will match the preview's visible area.\n */\n height?: number;\n /**\n * The maximum width of the picture in pixels. The image will be resized to fit within this width while maintaining aspect ratio.\n * If not specified the captured image will match the preview's visible area.\n */\n width?: number;\n /**\n * The quality of the captured image, from 0 to 100.\n * Does not apply to `png` format.\n * @default 85\n */\n quality?: number;\n /**\n * The format of the captured image.\n * @default \"jpeg\"\n */\n format?: PictureFormat;\n /**\n * If true, the captured image will be saved to the user's gallery.\n * @default false\n * @since 7.5.0\n */\n saveToGallery?: boolean;\n /**\n * If true, the plugin will attempt to add GPS location data to the image's EXIF metadata.\n * This may prompt the user for location permissions.\n * @default false\n * @since 7.6.0\n */\n withExifLocation?: boolean;\n /**\n * If true, the plugin will embed a timestamp in the top-right corner of the image.\n * @default false\n * @since 7.17.0\n */\n embedTimestamp?: boolean;\n /**\n * If true, the plugin will embed the current location in the top-right corner of the image.\n * Requires `withExifLocation` to be enabled.\n * @default false\n * @since 7.18.0\n */\n embedLocation?: boolean;\n /**\n * Sets the priority for photo quality vs. capture speed.\n * - \"speed\": Prioritizes faster capture times, may reduce image quality.\n * - \"balanced\": Aims for a balance between quality and speed.\n * - \"quality\": Prioritizes image quality, may reduce capture speed.\n * See https://developer.apple.com/documentation/avfoundation/avcapturephotosettings/photoqualityprioritization for details.\n *\n * @since 7.21.0\n * @platform ios\n * @default \"speed\"\n */\n photoQualityPrioritization?: 'speed' | 'balanced' | 'quality';\n}\n\n/** Represents EXIF data extracted from an image. */\nexport interface ExifData {\n [key: string]: any;\n}\n\nexport type PictureFormat = 'jpeg' | 'png';\n\n/** Defines a standard picture size with width and height. */\nexport interface PictureSize {\n /** The width of the picture in pixels. */\n width: number;\n /** The height of the picture in pixels. */\n height: number;\n}\n\n/** Represents the supported picture sizes for a camera facing a certain direction. */\nexport interface SupportedPictureSizes {\n /** The camera direction (\"front\" or \"rear\"). */\n facing: string;\n /** A list of supported picture sizes for this camera. */\n supportedPictureSizes: PictureSize[];\n}\n\n/**\n * Defines the options for capturing a sample frame from the camera preview.\n */\nexport interface CameraSampleOptions {\n /**\n * The quality of the captured sample, from 0 to 100.\n * @default 85\n */\n quality?: number;\n}\n\n/**\n * The available flash modes for the camera.\n * 'torch' is a continuous light mode.\n */\nexport type CameraPreviewFlashMode = 'off' | 'on' | 'auto' | 'torch';\n\n/** Reusable exposure mode type for cross-platform support. */\nexport type ExposureMode = 'AUTO' | 'LOCK' | 'CONTINUOUS' | 'CUSTOM';\n\n/**\n * Defines the options for setting the camera preview's opacity.\n */\nexport interface CameraOpacityOptions {\n /**\n * The opacity percentage, from 0.0 (fully transparent) to 1.0 (fully opaque).\n * @default 1.0\n */\n opacity?: number;\n}\n\n/**\n * Represents safe area insets for devices.\n * Android: Values are expressed in logical pixels (dp) to match JS layout units.\n * iOS: Values are expressed in physical pixels and exclude status bar.\n */\nexport interface SafeAreaInsets {\n /** Current device orientation (1 = portrait, 2 = landscape, 0 = unknown). */\n orientation: number;\n /**\n * Orientation-aware notch/camera cutout inset (excluding status bar).\n * In portrait mode: returns top inset (notch at top).\n * In landscape mode: returns left inset (notch at side).\n * Android: Value in dp, iOS: Value in pixels (status bar excluded).\n */\n top: number;\n}\n\n/**\n * Canonical device orientation values across platforms.\n */\nexport type DeviceOrientation = 'portrait' | 'landscape-left' | 'landscape-right' | 'portrait-upside-down' | 'unknown';\n\n/**\n * The main interface for the CameraPreview plugin.\n */\nexport interface CameraPreviewPlugin {\n /**\n * Starts the camera preview.\n *\n * @param {CameraPreviewOptions} options - The configuration for the camera preview.\n * @returns {Promise<{ width: number; height: number; x: number; y: number }>} A promise that resolves with the preview dimensions.\n * @since 0.0.1\n */\n start(options: CameraPreviewOptions): Promise<{\n /** The width of the preview in pixels. */\n width: number;\n /** The height of the preview in pixels. */\n height: number;\n /** The horizontal origin of the preview, in pixels. */\n x: number;\n /** The vertical origin of the preview, in pixels. */\n y: number;\n }>;\n\n /**\n * Stops the camera preview.\n *\n * @param {object} options - Optional configuration for stopping the camera.\n * @param {boolean} options.force - If true, forces the camera to stop even if busy or capturing. Default: false.\n * @returns {Promise<void>} A promise that resolves when the camera preview is stopped.\n * @since 0.0.1\n */\n stop(options?: { force?: boolean }): Promise<void>;\n\n /**\n * Captures a picture from the camera.\n *\n * If `storeToFile` was set to `true` when starting the preview, the returned\n * `value` will be an absolute file path on the device instead of a base64 string. Use getBase64FromFilePath to get the base64 string from the file path.\n *\n * @param {CameraPreviewPictureOptions} options - The options for capturing the picture.\n * @returns {Promise<{ value: string; exif: ExifData }>} Resolves with:\n * - `value`: base64 string, or file path if `storeToFile` is true\n * - `exif`: extracted EXIF metadata when available\n * @since 0.0.1\n */\n capture(options: CameraPreviewPictureOptions): Promise<{ value: string; exif: ExifData }>;\n\n /**\n * Captures a single frame from the camera preview stream.\n *\n * @param {CameraSampleOptions} options - The options for capturing the sample.\n * @returns {Promise<{ value: string }>} A promise that resolves with the sample image as a base64 encoded string.\n * @since 0.0.1\n */\n captureSample(options: CameraSampleOptions): Promise<{ value: string }>;\n\n /**\n * Gets the flash modes supported by the active camera.\n *\n * @returns {Promise<{ result: CameraPreviewFlashMode[] }>} A promise that resolves with an array of supported flash modes.\n * @since 0.0.1\n */\n getSupportedFlashModes(): Promise<{\n result: CameraPreviewFlashMode[];\n }>;\n\n /**\n * Set the aspect ratio of the camera preview.\n *\n * @param {{ aspectRatio: '4:3' | '16:9'; x?: number; y?: number }} options - The desired aspect ratio and optional position.\n * - aspectRatio: The desired aspect ratio ('4:3' or '16:9')\n * - x: Optional x coordinate for positioning. If not provided, view will be auto-centered horizontally.\n * - y: Optional y coordinate for positioning. If not provided, view will be auto-centered vertically.\n * @returns {Promise<{ width: number; height: number; x: number; y: number }>} A promise that resolves with the actual preview dimensions and position.\n * @since 7.5.0\n * @platform android, ios\n */\n setAspectRatio(options: { aspectRatio: '4:3' | '16:9'; x?: number; y?: number }): Promise<{\n width: number;\n height: number;\n x: number;\n y: number;\n }>;\n\n /**\n * Gets the current aspect ratio of the camera preview.\n *\n * @returns {Promise<{ aspectRatio: '4:3' | '16:9' }>} A promise that resolves with the current aspect ratio.\n * @since 7.5.0\n * @platform android, ios\n */\n getAspectRatio(): Promise<{ aspectRatio: '4:3' | '16:9' }>;\n\n /**\n * Sets the grid mode of the camera preview overlay.\n *\n * @param {{ gridMode: GridMode }} options - The desired grid mode ('none', '3x3', or '4x4').\n * @returns {Promise<void>} A promise that resolves when the grid mode is set.\n * @since 8.0.0\n */\n setGridMode(options: { gridMode: GridMode }): Promise<void>;\n\n /**\n * Gets the current grid mode of the camera preview overlay.\n *\n * @returns {Promise<{ gridMode: GridMode }>} A promise that resolves with the current grid mode.\n * @since 8.0.0\n */\n getGridMode(): Promise<{ gridMode: GridMode }>;\n\n /**\n * Checks the current camera (and optionally microphone) permission status without prompting the system dialog.\n *\n * @param options Set `disableAudio` to `false` to also include microphone status (defaults to `true`).\n * @returns {Promise<CameraPermissionStatus>} A promise resolving to the current authorization states.\n * @since 8.7.0\n */\n checkPermissions(options?: Pick<PermissionRequestOptions, 'disableAudio'>): Promise<CameraPermissionStatus>;\n\n /**\n * Requests camera (and optional microphone) permissions. If permissions are already granted or denied,\n * the current status is returned without prompting. When `showSettingsAlert` is true and permissions are denied,\n * a platform specific alert guiding the user to the app settings will be presented.\n *\n * @param {PermissionRequestOptions} options - Configuration for the permission request behaviour.\n * @returns {Promise<CameraPermissionStatus>} A promise resolving to the final authorization states.\n * @since 8.7.0\n */\n requestPermissions(options?: PermissionRequestOptions): Promise<CameraPermissionStatus>;\n\n /**\n * Gets the horizontal field of view (FoV) for the active camera.\n * Note: This can be an estimate on some devices.\n *\n * @returns {Promise<{ result: number }>} A promise that resolves with the horizontal field of view in degrees.\n * @since 0.0.1\n */\n getHorizontalFov(): Promise<{\n result: number;\n }>;\n\n /**\n * Gets the supported picture sizes for all cameras.\n *\n * @returns {Promise<{ supportedPictureSizes: SupportedPictureSizes[] }>} A promise that resolves with the list of supported sizes.\n * @since 7.4.0\n */\n getSupportedPictureSizes(): Promise<{\n supportedPictureSizes: SupportedPictureSizes[];\n }>;\n\n /**\n * Sets the flash mode for the active camera.\n *\n * @param {{ flashMode: CameraPreviewFlashMode | string }} options - The desired flash mode.\n * @returns {Promise<void>} A promise that resolves when the flash mode is set.\n * @since 0.0.1\n */\n setFlashMode(options: { flashMode: CameraPreviewFlashMode | string }): Promise<void>;\n\n /**\n * Toggles between the front and rear cameras.\n *\n * @returns {Promise<void>} A promise that resolves when the camera is flipped.\n * @since 0.0.1\n */\n flip(): Promise<void>;\n\n /**\n * Sets the opacity of the camera preview.\n *\n * @param {CameraOpacityOptions} options - The opacity options.\n * @returns {Promise<void>} A promise that resolves when the opacity is set.\n * @since 0.0.1\n */\n setOpacity(options: CameraOpacityOptions): Promise<void>;\n\n /**\n * Stops an ongoing video recording.\n *\n * @returns {Promise<{ videoFilePath: string }>} A promise that resolves with the path to the recorded video file.\n * @since 0.0.1\n */\n stopRecordVideo(): Promise<{ videoFilePath: string }>;\n\n /**\n * Starts recording a video.\n *\n * @param {CameraPreviewOptions} options - The options for video recording. Only iOS.\n * @returns {Promise<void>} A promise that resolves when video recording starts.\n * @since 0.0.1\n */\n startRecordVideo(options: CameraPreviewOptions): Promise<void>;\n\n /**\n * Checks if the camera preview is currently running.\n *\n * @returns {Promise<{ isRunning: boolean }>} A promise that resolves with the running state.\n * @since 7.5.0\n * @platform android, ios\n */\n isRunning(): Promise<{ isRunning: boolean }>;\n\n /**\n * Gets all available camera devices.\n *\n * @returns {Promise<{ devices: CameraDevice[] }>} A promise that resolves with the list of available camera devices.\n * @since 7.5.0\n * @platform android, ios\n */\n getAvailableDevices(): Promise<{ devices: CameraDevice[] }>;\n\n /**\n * Gets the current zoom state, including min/max and current lens info.\n *\n * @returns {Promise<{ min: number; max: number; current: number; lens: LensInfo }>} A promise that resolves with the zoom state.\n * @since 7.5.0\n * @platform android, ios\n */\n getZoom(): Promise<{\n min: number;\n max: number;\n current: number;\n lens: LensInfo;\n }>;\n\n /**\n * Returns zoom button values for quick switching.\n * - iOS/Android: includes 0.5 if ultra-wide available; 1 and 2 if wide available; 3 if telephoto available\n * - Web: unsupported\n * @since 7.5.0\n * @platform android, ios\n */\n getZoomButtonValues(): Promise<{ values: number[] }>;\n\n /**\n * Sets the zoom level of the camera.\n *\n * @param {{ level: number; ramp?: boolean; autoFocus?: boolean }} options - The desired zoom level. `ramp` is currently unused. `autoFocus` defaults to true.\n * @returns {Promise<void>} A promise that resolves when the zoom level is set.\n * @since 7.5.0\n * @platform android, ios\n */\n setZoom(options: { level: number; ramp?: boolean; autoFocus?: boolean }): Promise<void>;\n\n /**\n * Gets the current flash mode.\n *\n * @returns {Promise<{ flashMode: FlashMode }>} A promise that resolves with the current flash mode.\n * @since 7.5.0\n * @platform android, ios\n */\n getFlashMode(): Promise<{ flashMode: FlashMode }>;\n\n /**\n * Removes all registered listeners.\n *\n * @since 7.5.0\n * @platform android, ios\n */\n removeAllListeners(): Promise<void>;\n\n /**\n * Switches the active camera to the one with the specified `deviceId`.\n *\n * @param {{ deviceId: string }} options - The ID of the device to switch to.\n * @returns {Promise<void>} A promise that resolves when the camera is switched.\n * @since 7.5.0\n * @platform android, ios\n */\n setDeviceId(options: { deviceId: string }): Promise<void>;\n\n /**\n * Gets the ID of the currently active camera device.\n *\n * @returns {Promise<{ deviceId: string }>} A promise that resolves with the current device ID.\n * @since 7.5.0\n * @platform android, ios\n */\n getDeviceId(): Promise<{ deviceId: string }>;\n\n /**\n * Gets the current preview size and position.\n * @returns {Promise<{x: number, y: number, width: number, height: number}>}\n * @since 7.5.0\n * @platform android, ios\n */\n getPreviewSize(): Promise<{\n x: number;\n y: number;\n width: number;\n height: number;\n }>;\n /**\n * Sets the preview size and position.\n * @param options The new position and dimensions.\n * @returns {Promise<{ width: number; height: number; x: number; y: number }>} A promise that resolves with the actual preview dimensions and position.\n * @since 7.5.0\n * @platform android, ios\n */\n setPreviewSize(options: { x?: number; y?: number; width: number; height: number }): Promise<{\n width: number;\n height: number;\n x: number;\n y: number;\n }>;\n\n /**\n * Sets the camera focus to a specific point in the preview.\n *\n * Note: The plugin does not attach any native tap-to-focus gesture handlers. Handle taps in\n * your HTML/JS (e.g., on the overlaying UI), then pass normalized coordinates here.\n *\n * @param {Object} options - The focus options.\n * @param {number} options.x - The x coordinate in the preview view to focus on (0-1 normalized).\n * @param {number} options.y - The y coordinate in the preview view to focus on (0-1 normalized).\n * @returns {Promise<void>} A promise that resolves when the focus is set.\n * @since 7.5.0\n * @platform android, ios\n */\n setFocus(options: { x: number; y: number }): Promise<void>;\n\n /**\n * Adds a listener for screen resize events.\n * @param {string} eventName - The event name to listen for.\n * @param {Function} listenerFunc - The function to call when the event is triggered.\n * @returns {Promise<PluginListenerHandle>} A promise that resolves with a handle to the listener.\n * @since 7.5.0\n * @platform android, ios\n */\n addListener(\n eventName: 'screenResize',\n listenerFunc: (data: { width: number; height: number; x: number; y: number }) => void,\n ): Promise<PluginListenerHandle>;\n\n /**\n * Adds a listener for orientation change events.\n * @param {string} eventName - The event name to listen for.\n * @param {Function} listenerFunc - The function to call when the event is triggered.\n * @returns {Promise<PluginListenerHandle>} A promise that resolves with a handle to the listener.\n * @since 7.5.0\n * @platform android, ios\n */\n addListener(\n eventName: 'orientationChange',\n listenerFunc: (data: { orientation: DeviceOrientation }) => void,\n ): Promise<PluginListenerHandle>;\n /**\n * Deletes a file at the given absolute path on the device.\n * Use this to quickly clean up temporary images created with `storeToFile`.\n * On web, this is not supported and will throw.\n * @since 7.5.0\n * @platform android, ios\n */\n deleteFile(options: { path: string }): Promise<{ success: boolean }>;\n\n /**\n * Gets the safe area insets for devices.\n * Returns the orientation-aware notch/camera cutout inset and the current orientation.\n * In portrait mode: returns top inset (notch at top).\n * In landscape mode: returns left inset (notch moved to side).\n * This specifically targets the cutout area (notch, punch hole, etc.) that all modern phones have.\n *\n * Android: Values returned in dp (logical pixels).\n * iOS: Values returned in physical pixels, excluding status bar (only pure notch/cutout size).\n *\n * @platform android, ios\n */\n getSafeAreaInsets(): Promise<SafeAreaInsets>;\n\n /**\n * Gets the current device orientation in a cross-platform format.\n * @since 7.5.0\n * @platform android, ios\n */\n getOrientation(): Promise<{ orientation: DeviceOrientation }>;\n\n /**\n * Returns the exposure modes supported by the active camera.\n * Modes can include: 'locked', 'auto', 'continuous', 'custom'.\n * @platform android, ios\n */\n getExposureModes(): Promise<{ modes: ExposureMode[] }>;\n\n /**\n * Returns the current exposure mode.\n * @platform android, ios\n */\n getExposureMode(): Promise<{ mode: ExposureMode }>;\n\n /**\n * Sets the exposure mode.\n * @platform android, ios\n */\n setExposureMode(options: { mode: ExposureMode }): Promise<void>;\n\n /**\n * Returns the exposure compensation (EV bias) supported range.\n * @platform ios, android\n */\n getExposureCompensationRange(): Promise<{\n min: number;\n max: number;\n step: number;\n }>;\n\n /**\n * Returns the current exposure compensation (EV bias).\n * @platform ios, android\n */\n getExposureCompensation(): Promise<{ value: number }>;\n\n /**\n * Sets the exposure compensation (EV bias). Value will be clamped to range.\n * @platform ios, android\n */\n setExposureCompensation(options: { value: number }): Promise<void>;\n\n /**\n * Get the native Capacitor plugin version\n *\n * @returns {Promise<{ id: string }>} an Promise with version for this device\n * @throws An error if the something went wrong\n */\n getPluginVersion(): Promise<{ version: string }>;\n}\n"]}
@@ -99,6 +99,8 @@ class CameraController: NSObject {
99
99
  var videoFileURL: URL?
100
100
  private let saneMaxZoomFactor: CGFloat = 25.5
101
101
 
102
+ var videoQuality: String = "high"
103
+
102
104
  // Track output preparation status
103
105
  private var outputsPrepared: Bool = false
104
106
 
@@ -348,7 +350,7 @@ extension CameraController {
348
350
  self.outputsPrepared = true
349
351
  }
350
352
 
351
- func prepare(cameraPosition: String, deviceId: String? = nil, disableAudio: Bool, cameraMode: Bool, aspectRatio: String? = nil, initialZoomLevel: Float?, disableFocusIndicator: Bool = false, completionHandler: @escaping (Error?) -> Void) {
353
+ func prepare(cameraPosition: String, deviceId: String? = nil, disableAudio: Bool, cameraMode: Bool, aspectRatio: String? = nil, initialZoomLevel: Float?, disableFocusIndicator: Bool = false, videoQuality: String = "high", completionHandler: @escaping (Error?) -> Void) {
352
354
  print("[CameraPreview] 🎬 Starting prepare - position: \(cameraPosition), deviceId: \(deviceId ?? "nil"), disableAudio: \(disableAudio), cameraMode: \(cameraMode), aspectRatio: \(aspectRatio ?? "nil"), zoom: \(initialZoomLevel ?? 1)")
353
355
 
354
356
  DispatchQueue.global(qos: .userInitiated).async { [weak self] in
@@ -379,6 +381,9 @@ extension CameraController {
379
381
  throw CameraControllerError.captureSessionIsMissing
380
382
  }
381
383
 
384
+ // Set quality of video
385
+ self.videoQuality = videoQuality
386
+
382
387
  // Prepare outputs early
383
388
  self.prepareOutputs()
384
389
 
@@ -471,35 +476,62 @@ extension CameraController {
471
476
  guard let captureSession = self.captureSession else { return }
472
477
 
473
478
  var targetPreset: AVCaptureSession.Preset = .photo
474
- if let aspectRatio = aspectRatio {
475
- switch aspectRatio {
476
- case "16:9":
477
- // Start with 1080p for faster initialization, 4K only when explicitly needed
478
- // This maintains capture quality while optimizing preview performance
479
- if captureSession.canSetSessionPreset(.hd1920x1080) {
480
- targetPreset = .hd1920x1080
481
- } else if captureSession.canSetSessionPreset(.hd4K3840x2160) {
482
- targetPreset = .hd4K3840x2160
483
- }
484
- case "4:3":
485
- if captureSession.canSetSessionPreset(.photo) {
486
- targetPreset = .photo
487
- } else if captureSession.canSetSessionPreset(.high) {
488
- targetPreset = .high
489
- } else {
490
- targetPreset = captureSession.sessionPreset
491
- }
492
- default:
493
- if captureSession.canSetSessionPreset(.photo) {
494
- targetPreset = .photo
495
- } else if captureSession.canSetSessionPreset(.high) {
496
- targetPreset = .high
497
- } else {
498
- targetPreset = captureSession.sessionPreset
479
+
480
+ // Prioritize video quality setting
481
+ switch self.videoQuality.lowercased() {
482
+ case "low":
483
+ // Match Android "Low" (SD/480p)
484
+ if captureSession.canSetSessionPreset(.vga640x480) {
485
+ targetPreset = .vga640x480
486
+ } else {
487
+ targetPreset = .low
488
+ }
489
+ case "medium":
490
+ // Match Android "Medium" (HD/720p)
491
+ if captureSession.canSetSessionPreset(.hd1280x720) {
492
+ targetPreset = .hd1280x720
493
+ } else {
494
+ targetPreset = .medium
495
+ }
496
+ case "high":
497
+ // Exisiting logic for High Quality (4K/1080p based on Asepct Ratio)
498
+
499
+ if let aspectRatio = aspectRatio {
500
+ switch aspectRatio {
501
+ case "16:9":
502
+ // Start with 1080p for faster initialization, 4K only when explicitly needed
503
+ // This maintains capture quality while optimizing preview performance
504
+ if captureSession.canSetSessionPreset(.hd1920x1080) {
505
+ targetPreset = .hd1920x1080
506
+ } else if captureSession.canSetSessionPreset(.hd4K3840x2160) {
507
+ targetPreset = .hd4K3840x2160
508
+ }
509
+ case "4:3":
510
+ if captureSession.canSetSessionPreset(.photo) {
511
+ targetPreset = .photo
512
+ } else if captureSession.canSetSessionPreset(.high) {
513
+ targetPreset = .high
514
+ } else {
515
+ targetPreset = captureSession.sessionPreset
516
+ }
517
+ default:
518
+ if captureSession.canSetSessionPreset(.photo) {
519
+ targetPreset = .photo
520
+ } else if captureSession.canSetSessionPreset(.high) {
521
+ targetPreset = .high
522
+ } else {
523
+ targetPreset = captureSession.sessionPreset
524
+ }
499
525
  }
500
526
  }
527
+ // Handle unexpected values
528
+ default:
529
+ if captureSession.canSetSessionPreset(.photo) {
530
+ targetPreset = .photo
531
+ } else {
532
+ targetPreset = .high
533
+ }
501
534
  }
502
-
503
535
  if captureSession.canSetSessionPreset(targetPreset) {
504
536
  captureSession.sessionPreset = targetPreset
505
537
  }
@@ -802,7 +834,21 @@ extension CameraController {
802
834
  }
803
835
 
804
836
  // Helper: pick the best preset the TARGET device supports for a given aspect ratio
805
- private func bestPreset(for aspectRatio: String?, on device: AVCaptureDevice) -> AVCaptureSession.Preset {
837
+ private func bestPreset(for aspectRatio: String?, quality: String, on device: AVCaptureDevice) -> AVCaptureSession.Preset {
838
+
839
+ // Handle specific quality overrides first
840
+ switch quality.lowercased() {
841
+ case "low":
842
+ if device.supportsSessionPreset(.vga640x480) { return .vga640x480 }
843
+ return .low
844
+ case "medium":
845
+ if device.supportsSessionPreset(.hd1280x720) { return .hd1280x720 }
846
+ return .medium
847
+ case "high":
848
+ break // Exit and go off code below
849
+ default:
850
+ break // Exit and go off code below
851
+ }
806
852
  // Preference order depends on aspect ratio
807
853
  if aspectRatio == "16:9" {
808
854
  // Prefer 4K → 1080p → 720p → high → photo → vga
@@ -840,7 +886,7 @@ extension CameraController {
840
886
  }
841
887
 
842
888
  // Compute the desired preset for the TARGET device up front
843
- let desiredPreset = bestPreset(for: self.requestedAspectRatio, on: targetDevice)
889
+ let desiredPreset = bestPreset(for: self.requestedAspectRatio, quality: self.videoQuality, on: targetDevice)
844
890
 
845
891
  // Keep the preview layer visually stable during the swap
846
892
  let savedPreviewFrame = self.previewLayer?.frame
@@ -34,7 +34,7 @@ extension UIWindow {
34
34
  */
35
35
  @objc(CameraPreview)
36
36
  public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelegate {
37
- private let pluginVersion: String = "8.0.14"
37
+ private let pluginVersion: String = "8.0.15"
38
38
  public let identifier = "CameraPreviewPlugin"
39
39
  public let jsName = "CameraPreview"
40
40
  public let pluginMethods: [CAPPluginMethod] = [
@@ -655,6 +655,7 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelega
655
655
  print(" - initialZoomLevel: \(call.getFloat("initialZoomLevel") ?? 1.0)")
656
656
  print(" - disableFocusIndicator: \(call.getBool("disableFocusIndicator") ?? false)")
657
657
  print(" - force: \(call.getBool("force") ?? false)")
658
+ print(" - videoQuality: \(call.getString("videoQuality") ?? "high")")
658
659
 
659
660
  let force = call.getBool("force") ?? false
660
661
 
@@ -752,6 +753,9 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelega
752
753
  self.positioning = call.getString("positioning") ?? "top"
753
754
  self.disableFocusIndicator = call.getBool("disableFocusIndicator") ?? false
754
755
 
756
+ // Default to high if not provided
757
+ let videoQuality = call.getString("videoQuality") ?? "high"
758
+
755
759
  let initialZoomLevel = call.getFloat("initialZoomLevel")
756
760
 
757
761
  // Check for conflict between aspectRatio and size (width/height)
@@ -772,7 +776,7 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelega
772
776
  return
773
777
  }
774
778
 
775
- self.cameraController.prepare(cameraPosition: self.cameraPosition, deviceId: deviceId, disableAudio: self.disableAudio, cameraMode: cameraMode, aspectRatio: self.aspectRatio, initialZoomLevel: initialZoomLevel, disableFocusIndicator: self.disableFocusIndicator) { error in
779
+ self.cameraController.prepare(cameraPosition: self.cameraPosition, deviceId: deviceId, disableAudio: self.disableAudio, cameraMode: cameraMode, aspectRatio: self.aspectRatio, initialZoomLevel: initialZoomLevel, disableFocusIndicator: self.disableFocusIndicator, videoQuality: videoQuality) { error in
776
780
  if let error = error {
777
781
  print(error)
778
782
  DispatchQueue.main.async {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/camera-preview",
3
- "version": "8.0.14",
3
+ "version": "8.0.15",
4
4
  "description": "Camera preview",
5
5
  "license": "MPL-2.0",
6
6
  "repository": {