@capgo/camera-preview 7.4.0-beta.3 → 7.4.0-beta.4
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 +66 -23
- package/android/.gradle/8.14.2/checksums/checksums.lock +0 -0
- package/android/.gradle/8.14.2/checksums/md5-checksums.bin +0 -0
- package/android/.gradle/8.14.2/checksums/sha1-checksums.bin +0 -0
- package/android/.gradle/8.14.2/executionHistory/executionHistory.bin +0 -0
- package/android/.gradle/8.14.2/executionHistory/executionHistory.lock +0 -0
- package/android/.gradle/8.14.2/fileHashes/fileHashes.bin +0 -0
- package/android/.gradle/8.14.2/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/8.14.2/fileHashes/resourceHashesCache.bin +0 -0
- package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
- package/android/.gradle/file-system.probe +0 -0
- package/android/src/main/AndroidManifest.xml +1 -1
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CameraPreview.java +54 -27
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CameraXView.java +132 -19
- package/android/src/main/java/com/ahm/capacitor/camera/preview/GridOverlayView.java +80 -0
- package/android/src/main/java/com/ahm/capacitor/camera/preview/model/CameraSessionConfiguration.java +19 -5
- package/dist/docs.json +100 -3
- package/dist/esm/definitions.d.ts +44 -2
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.d.ts +16 -2
- package/dist/esm/web.js +177 -78
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +177 -78
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +177 -78
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/CapgoCameraPreview/CameraController.swift +78 -20
- package/ios/Sources/CapgoCameraPreview/GridOverlayView.swift +65 -0
- package/ios/Sources/CapgoCameraPreview/Plugin.swift +155 -37
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -220,6 +220,8 @@ Documentation for the [uploader](https://github.com/Cap-go/capacitor-uploader)
|
|
|
220
220
|
* [`capture(...)`](#capture)
|
|
221
221
|
* [`captureSample(...)`](#capturesample)
|
|
222
222
|
* [`getSupportedFlashModes()`](#getsupportedflashmodes)
|
|
223
|
+
* [`setAspectRatio(...)`](#setaspectratio)
|
|
224
|
+
* [`getAspectRatio()`](#getaspectratio)
|
|
223
225
|
* [`getHorizontalFov()`](#gethorizontalfov)
|
|
224
226
|
* [`getSupportedPictureSizes()`](#getsupportedpicturesizes)
|
|
225
227
|
* [`setFlashMode(...)`](#setflashmode)
|
|
@@ -249,7 +251,7 @@ The main interface for the CameraPreview plugin.
|
|
|
249
251
|
### start(...)
|
|
250
252
|
|
|
251
253
|
```typescript
|
|
252
|
-
start(options: CameraPreviewOptions) => Promise<
|
|
254
|
+
start(options: CameraPreviewOptions) => Promise<{ width: number; height: number; x: number; y: number; }>
|
|
253
255
|
```
|
|
254
256
|
|
|
255
257
|
Starts the camera preview.
|
|
@@ -258,6 +260,8 @@ Starts the camera preview.
|
|
|
258
260
|
| ------------- | --------------------------------------------------------------------- | ------------------------------------------- |
|
|
259
261
|
| **`options`** | <code><a href="#camerapreviewoptions">CameraPreviewOptions</a></code> | - The configuration for the camera preview. |
|
|
260
262
|
|
|
263
|
+
**Returns:** <code>Promise<{ width: number; height: number; x: number; y: number; }></code>
|
|
264
|
+
|
|
261
265
|
**Since:** 0.0.1
|
|
262
266
|
|
|
263
267
|
--------------------
|
|
@@ -329,6 +333,38 @@ Gets the flash modes supported by the active camera.
|
|
|
329
333
|
--------------------
|
|
330
334
|
|
|
331
335
|
|
|
336
|
+
### setAspectRatio(...)
|
|
337
|
+
|
|
338
|
+
```typescript
|
|
339
|
+
setAspectRatio(options: { aspectRatio: '4:3' | '16:9' | 'fill'; }) => Promise<void>
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
Set the aspect ratio of the camera preview.
|
|
343
|
+
|
|
344
|
+
| Param | Type | Description |
|
|
345
|
+
| ------------- | -------------------------------------------------------- | --------------------------- |
|
|
346
|
+
| **`options`** | <code>{ aspectRatio: '4:3' \| '16:9' \| 'fill'; }</code> | - The desired aspect ratio. |
|
|
347
|
+
|
|
348
|
+
**Since:** 7.4.0
|
|
349
|
+
|
|
350
|
+
--------------------
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
### getAspectRatio()
|
|
354
|
+
|
|
355
|
+
```typescript
|
|
356
|
+
getAspectRatio() => Promise<{ aspectRatio: '4:3' | '16:9' | 'fill'; }>
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
Gets the current aspect ratio of the camera preview.
|
|
360
|
+
|
|
361
|
+
**Returns:** <code>Promise<{ aspectRatio: '4:3' | '16:9' | 'fill'; }></code>
|
|
362
|
+
|
|
363
|
+
**Since:** 7.4.0
|
|
364
|
+
|
|
365
|
+
--------------------
|
|
366
|
+
|
|
367
|
+
|
|
332
368
|
### getHorizontalFov()
|
|
333
369
|
|
|
334
370
|
```typescript
|
|
@@ -568,28 +604,30 @@ Gets the ID of the currently active camera device.
|
|
|
568
604
|
|
|
569
605
|
Defines the configuration options for starting the camera preview.
|
|
570
606
|
|
|
571
|
-
| Prop | Type
|
|
572
|
-
| ---------------------------------- |
|
|
573
|
-
| **`parent`** | <code>string</code>
|
|
574
|
-
| **`className`** | <code>string</code>
|
|
575
|
-
| **`width`** | <code>number</code>
|
|
576
|
-
| **`height`** | <code>number</code>
|
|
577
|
-
| **`x`** | <code>number</code>
|
|
578
|
-
| **`y`** | <code>number</code>
|
|
579
|
-
| **`
|
|
580
|
-
| **`
|
|
581
|
-
| **`
|
|
582
|
-
| **`
|
|
583
|
-
| **`
|
|
584
|
-
| **`
|
|
585
|
-
| **`
|
|
586
|
-
| **`
|
|
587
|
-
| **`
|
|
588
|
-
| **`
|
|
589
|
-
| **`
|
|
590
|
-
| **`
|
|
591
|
-
| **`
|
|
592
|
-
| **`
|
|
607
|
+
| Prop | Type | Description | Default | Since |
|
|
608
|
+
| ---------------------------------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | ------------------- | ----- |
|
|
609
|
+
| **`parent`** | <code>string</code> | The parent element to attach the video preview to. | | |
|
|
610
|
+
| **`className`** | <code>string</code> | A CSS class name to add to the preview element. | | |
|
|
611
|
+
| **`width`** | <code>number</code> | The width of the preview in pixels. Defaults to the screen width. | | |
|
|
612
|
+
| **`height`** | <code>number</code> | The height of the preview in pixels. Defaults to the screen height. | | |
|
|
613
|
+
| **`x`** | <code>number</code> | The horizontal origin of the preview, in pixels. | | |
|
|
614
|
+
| **`y`** | <code>number</code> | The vertical origin of the preview, in pixels. | | |
|
|
615
|
+
| **`aspectRatio`** | <code>'4:3' \| '16:9' \| 'fill'</code> | The aspect ratio of the camera preview, '4:3' or '16:9'. If not set, the camera will use the default aspect ratio. | | 2.0.0 |
|
|
616
|
+
| **`gridMode`** | <code><a href="#gridmode">GridMode</a></code> | The grid overlay to display on the camera preview. | <code>"none"</code> | 2.1.0 |
|
|
617
|
+
| **`includeSafeAreaInsets`** | <code>boolean</code> | Adjusts the y-position to account for safe areas (e.g., notches). | <code>false</code> | |
|
|
618
|
+
| **`toBack`** | <code>boolean</code> | If true, places the preview behind the webview. | <code>true</code> | |
|
|
619
|
+
| **`paddingBottom`** | <code>number</code> | Bottom padding for the preview, in pixels. | | |
|
|
620
|
+
| **`rotateWhenOrientationChanged`** | <code>boolean</code> | Whether to rotate the preview when the device orientation changes. | <code>true</code> | |
|
|
621
|
+
| **`position`** | <code>string</code> | The camera to use. | <code>"rear"</code> | |
|
|
622
|
+
| **`storeToFile`** | <code>boolean</code> | If true, saves the captured image to a file and returns the file path. If false, returns a base64 encoded string. | <code>false</code> | |
|
|
623
|
+
| **`disableExifHeaderStripping`** | <code>boolean</code> | If true, prevents the plugin from rotating the image based on EXIF data. | <code>false</code> | |
|
|
624
|
+
| **`enableHighResolution`** | <code>boolean</code> | If true, enables high-resolution image capture. | <code>false</code> | |
|
|
625
|
+
| **`disableAudio`** | <code>boolean</code> | If true, disables the audio stream, preventing audio permission requests. | <code>true</code> | |
|
|
626
|
+
| **`lockAndroidOrientation`** | <code>boolean</code> | If true, locks the device orientation while the camera is active. | <code>false</code> | |
|
|
627
|
+
| **`enableOpacity`** | <code>boolean</code> | If true, allows the camera preview's opacity to be changed. | <code>false</code> | |
|
|
628
|
+
| **`enableZoom`** | <code>boolean</code> | If true, enables pinch-to-zoom functionality on the preview. | <code>false</code> | |
|
|
629
|
+
| **`enableVideoMode`** | <code>boolean</code> | If true, uses the video-optimized preset for the camera session. | <code>false</code> | |
|
|
630
|
+
| **`deviceId`** | <code>string</code> | The `deviceId` of the camera to use. If provided, `position` is ignored. | | |
|
|
593
631
|
|
|
594
632
|
|
|
595
633
|
#### ExifData
|
|
@@ -693,6 +731,11 @@ Represents the detailed information of the currently active lens.
|
|
|
693
731
|
### Type Aliases
|
|
694
732
|
|
|
695
733
|
|
|
734
|
+
#### GridMode
|
|
735
|
+
|
|
736
|
+
<code>"none" | "3x3" | "4x4"</code>
|
|
737
|
+
|
|
738
|
+
|
|
696
739
|
#### CameraPosition
|
|
697
740
|
|
|
698
741
|
<code>"rear" | "front"</code>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
3
3
|
<uses-permission android:name="android.permission.CAMERA" />
|
|
4
|
+
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
|
4
5
|
<uses-feature android:name="android.hardware.camera" />
|
|
5
6
|
<uses-feature android:name="android.hardware.camera.autofocus" />
|
|
6
7
|
</manifest>
|
|
7
|
-
|
|
@@ -30,6 +30,14 @@ import org.json.JSONObject;
|
|
|
30
30
|
import android.location.Location;
|
|
31
31
|
import com.getcapacitor.Logger;
|
|
32
32
|
|
|
33
|
+
interface CameraPreviewListener {
|
|
34
|
+
void onPictureTaken(String base64, JSONObject exif);
|
|
35
|
+
void onPictureTakenError(String message);
|
|
36
|
+
void onCameraStarted(int width, int height, int x, int y);
|
|
37
|
+
void onCameraStopped();
|
|
38
|
+
void onCaptureStarted();
|
|
39
|
+
}
|
|
40
|
+
|
|
33
41
|
@CapacitorPlugin(
|
|
34
42
|
name = "CameraPreview",
|
|
35
43
|
permissions = {
|
|
@@ -49,7 +57,7 @@ import com.getcapacitor.Logger;
|
|
|
49
57
|
)
|
|
50
58
|
public class CameraPreview
|
|
51
59
|
extends Plugin
|
|
52
|
-
implements
|
|
60
|
+
implements CameraPreviewListener {
|
|
53
61
|
|
|
54
62
|
static final String CAMERA_WITH_AUDIO_PERMISSION_ALIAS = "cameraWithAudio";
|
|
55
63
|
static final String CAMERA_ONLY_PERMISSION_ALIAS = "cameraOnly";
|
|
@@ -146,7 +154,7 @@ public class CameraPreview
|
|
|
146
154
|
final boolean saveToGallery = call.getBoolean("saveToGallery", false);
|
|
147
155
|
Integer width = call.getInt("width");
|
|
148
156
|
Integer height = call.getInt("height");
|
|
149
|
-
|
|
157
|
+
|
|
150
158
|
cameraXView.capturePhoto(quality, saveToGallery, width, height, location);
|
|
151
159
|
}
|
|
152
160
|
|
|
@@ -291,7 +299,7 @@ public class CameraPreview
|
|
|
291
299
|
}
|
|
292
300
|
rear.put("supportedPictureSizes", rearSizesJs);
|
|
293
301
|
supportedPictureSizesResult.put(rear);
|
|
294
|
-
|
|
302
|
+
|
|
295
303
|
List<Size> frontSizes = CameraXView.getSupportedPictureSizes("front");
|
|
296
304
|
JSObject front = new JSObject();
|
|
297
305
|
front.put("facing", "front");
|
|
@@ -304,7 +312,7 @@ public class CameraPreview
|
|
|
304
312
|
}
|
|
305
313
|
front.put("supportedPictureSizes", frontSizesJs);
|
|
306
314
|
supportedPictureSizesResult.put(front);
|
|
307
|
-
|
|
315
|
+
|
|
308
316
|
JSObject ret = new JSObject();
|
|
309
317
|
ret.put("supportedPictureSizes", supportedPictureSizesResult);
|
|
310
318
|
call.resolve(ret);
|
|
@@ -389,7 +397,9 @@ public class CameraPreview
|
|
|
389
397
|
final boolean disableExifHeaderStripping = Boolean.TRUE.equals(call.getBoolean("disableExifHeaderStripping", false));
|
|
390
398
|
final boolean lockOrientation = Boolean.TRUE.equals(call.getBoolean("lockAndroidOrientation", false));
|
|
391
399
|
final boolean disableAudio = Boolean.TRUE.equals(call.getBoolean("disableAudio", true));
|
|
392
|
-
|
|
400
|
+
final String aspectRatio = call.getString("aspectRatio", "fill");
|
|
401
|
+
final String gridMode = call.getString("gridMode", "none");
|
|
402
|
+
|
|
393
403
|
float targetZoom = 1.0f;
|
|
394
404
|
// Check if the selected device is a physical ultra-wide
|
|
395
405
|
if (originalDeviceId != null) {
|
|
@@ -401,7 +411,7 @@ public class CameraPreview
|
|
|
401
411
|
Log.d("CameraPreview", "Ultra-wide lens selected. Targeting 0.5x zoom on logical camera.");
|
|
402
412
|
targetZoom = 0.5f;
|
|
403
413
|
// Force the use of the logical camera by clearing the specific deviceId
|
|
404
|
-
deviceId = null;
|
|
414
|
+
deviceId = null;
|
|
405
415
|
break;
|
|
406
416
|
}
|
|
407
417
|
}
|
|
@@ -412,7 +422,7 @@ public class CameraPreview
|
|
|
412
422
|
|
|
413
423
|
previousOrientationRequest = getBridge().getActivity().getRequestedOrientation();
|
|
414
424
|
cameraXView = new CameraXView(getContext(), getBridge().getWebView());
|
|
415
|
-
cameraXView.setListener(this);
|
|
425
|
+
cameraXView.setListener((CameraXView.CameraXViewListener) this);
|
|
416
426
|
|
|
417
427
|
String finalDeviceId = deviceId;
|
|
418
428
|
float finalTargetZoom = targetZoom;
|
|
@@ -427,9 +437,9 @@ public class CameraPreview
|
|
|
427
437
|
int computedHeight = height != 0 ? (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, height, metrics) : getBridge().getWebView().getHeight();
|
|
428
438
|
computedHeight -= (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, paddingBottom, metrics);
|
|
429
439
|
|
|
430
|
-
CameraSessionConfiguration config = new CameraSessionConfiguration(finalDeviceId, position, computedX, computedY, computedWidth, computedHeight, paddingBottom, toBack, storeToFile, enableOpacity, enableZoom, disableExifHeaderStripping, disableAudio, 1.0f);
|
|
440
|
+
CameraSessionConfiguration config = new CameraSessionConfiguration(finalDeviceId, position, computedX, computedY, computedWidth, computedHeight, paddingBottom, toBack, storeToFile, enableOpacity, enableZoom, disableExifHeaderStripping, disableAudio, 1.0f, aspectRatio, gridMode);
|
|
431
441
|
config.setTargetZoom(finalTargetZoom);
|
|
432
|
-
|
|
442
|
+
|
|
433
443
|
bridge.saveCall(call);
|
|
434
444
|
cameraStartCallbackId = call.getCallbackId();
|
|
435
445
|
cameraXView.startSession(config);
|
|
@@ -463,33 +473,50 @@ public class CameraPreview
|
|
|
463
473
|
}
|
|
464
474
|
|
|
465
475
|
@Override
|
|
466
|
-
public void
|
|
467
|
-
|
|
468
|
-
jsObject.put("value", result);
|
|
469
|
-
bridge.getSavedCall(snapshotCallbackId).resolve(jsObject);
|
|
476
|
+
public void onCaptureStarted() {
|
|
477
|
+
Log.i("CameraPreview", "Capture started");
|
|
470
478
|
}
|
|
471
479
|
|
|
472
480
|
@Override
|
|
473
|
-
public void
|
|
474
|
-
bridge.getSavedCall(
|
|
481
|
+
public void onCameraStarted(int width, int height, int x, int y) {
|
|
482
|
+
PluginCall call = bridge.getSavedCall(cameraStartCallbackId);
|
|
483
|
+
if (call != null) {
|
|
484
|
+
JSObject result = new JSObject();
|
|
485
|
+
result.put("width", width);
|
|
486
|
+
result.put("height", height);
|
|
487
|
+
result.put("x", x);
|
|
488
|
+
result.put("y", y);
|
|
489
|
+
call.resolve(result);
|
|
490
|
+
bridge.releaseCall(call);
|
|
491
|
+
cameraStartCallbackId = null; // Prevent re-use
|
|
492
|
+
}
|
|
475
493
|
}
|
|
476
494
|
|
|
477
495
|
@Override
|
|
478
|
-
public void
|
|
479
|
-
|
|
480
|
-
if (pluginCall != null) {
|
|
481
|
-
pluginCall.resolve();
|
|
482
|
-
bridge.releaseCall(pluginCall);
|
|
483
|
-
}
|
|
496
|
+
public void onCameraStopped() {
|
|
497
|
+
// This method is no longer needed as onCameraStarted handles the promise resolution.
|
|
484
498
|
}
|
|
485
499
|
|
|
486
|
-
@
|
|
487
|
-
public void
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
bridge.releaseCall(pluginCall);
|
|
500
|
+
@PluginMethod
|
|
501
|
+
public void setAspectRatio(PluginCall call) {
|
|
502
|
+
if (cameraXView == null || !cameraXView.isRunning()) {
|
|
503
|
+
call.reject("Camera is not running");
|
|
504
|
+
return;
|
|
492
505
|
}
|
|
506
|
+
String aspectRatio = call.getString("aspectRatio", "fill");
|
|
507
|
+
cameraXView.setAspectRatio(aspectRatio);
|
|
508
|
+
call.resolve();
|
|
493
509
|
}
|
|
494
510
|
|
|
511
|
+
@PluginMethod
|
|
512
|
+
public void getAspectRatio(PluginCall call) {
|
|
513
|
+
if (cameraXView == null || !cameraXView.isRunning()) {
|
|
514
|
+
call.reject("Camera is not running");
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
String aspectRatio = cameraXView.getAspectRatio();
|
|
518
|
+
JSObject ret = new JSObject();
|
|
519
|
+
ret.put("aspectRatio", aspectRatio);
|
|
520
|
+
call.resolve(ret);
|
|
521
|
+
}
|
|
495
522
|
}
|
|
@@ -18,6 +18,8 @@ import androidx.camera.core.ImageCapture;
|
|
|
18
18
|
import androidx.camera.core.ImageCaptureException;
|
|
19
19
|
import androidx.camera.core.ImageProxy;
|
|
20
20
|
import androidx.camera.core.Preview;
|
|
21
|
+
import androidx.camera.core.AspectRatio;
|
|
22
|
+
import androidx.camera.core.resolutionselector.AspectRatioStrategy;
|
|
21
23
|
import androidx.camera.core.resolutionselector.ResolutionSelector;
|
|
22
24
|
import androidx.camera.core.resolutionselector.ResolutionStrategy;
|
|
23
25
|
import androidx.camera.lifecycle.ProcessCameraProvider;
|
|
@@ -27,6 +29,7 @@ import androidx.lifecycle.Lifecycle;
|
|
|
27
29
|
import androidx.lifecycle.LifecycleOwner;
|
|
28
30
|
import androidx.lifecycle.LifecycleRegistry;
|
|
29
31
|
import com.ahm.capacitor.camera.preview.model.CameraSessionConfiguration;
|
|
32
|
+
import android.widget.FrameLayout;
|
|
30
33
|
import com.ahm.capacitor.camera.preview.model.LensInfo;
|
|
31
34
|
import com.ahm.capacitor.camera.preview.model.ZoomFactors;
|
|
32
35
|
import com.google.common.util.concurrent.ListenableFuture;
|
|
@@ -61,8 +64,12 @@ import android.graphics.Bitmap;
|
|
|
61
64
|
import android.graphics.Matrix;
|
|
62
65
|
import java.io.ByteArrayOutputStream;
|
|
63
66
|
import android.location.Location;
|
|
67
|
+
import android.widget.FrameLayout;
|
|
68
|
+
import androidx.lifecycle.LifecycleObserver;
|
|
69
|
+
import androidx.lifecycle.OnLifecycleEvent;
|
|
70
|
+
import android.util.Rational;
|
|
64
71
|
|
|
65
|
-
public class CameraXView implements LifecycleOwner {
|
|
72
|
+
public class CameraXView implements LifecycleOwner, LifecycleObserver {
|
|
66
73
|
private static final String TAG = "CameraPreview CameraXView";
|
|
67
74
|
|
|
68
75
|
public interface CameraXViewListener {
|
|
@@ -79,6 +86,8 @@ public class CameraXView implements LifecycleOwner {
|
|
|
79
86
|
private ImageCapture imageCapture;
|
|
80
87
|
private ImageCapture sampleImageCapture;
|
|
81
88
|
private PreviewView previewView;
|
|
89
|
+
private GridOverlayView gridOverlayView;
|
|
90
|
+
private FrameLayout previewContainer;
|
|
82
91
|
private CameraSelector currentCameraSelector;
|
|
83
92
|
private String currentDeviceId;
|
|
84
93
|
private int currentFlashMode = ImageCapture.FLASH_MODE_OFF;
|
|
@@ -179,23 +188,47 @@ public class CameraXView implements LifecycleOwner {
|
|
|
179
188
|
if (sessionConfig.isToBack()) {
|
|
180
189
|
webView.setBackgroundColor(android.graphics.Color.TRANSPARENT);
|
|
181
190
|
}
|
|
191
|
+
|
|
192
|
+
// Create a container to hold both the preview and grid overlay
|
|
193
|
+
previewContainer = new FrameLayout(context);
|
|
194
|
+
|
|
195
|
+
// Create and setup the preview view
|
|
182
196
|
previewView = new PreviewView(context);
|
|
183
197
|
previewView.setScaleType(PreviewView.ScaleType.FILL_CENTER);
|
|
198
|
+
previewContainer.addView(previewView, new FrameLayout.LayoutParams(
|
|
199
|
+
FrameLayout.LayoutParams.MATCH_PARENT,
|
|
200
|
+
FrameLayout.LayoutParams.MATCH_PARENT
|
|
201
|
+
));
|
|
202
|
+
|
|
203
|
+
// Create and setup the grid overlay
|
|
204
|
+
gridOverlayView = new GridOverlayView(context);
|
|
205
|
+
gridOverlayView.setGridMode(sessionConfig.getGridMode());
|
|
206
|
+
previewContainer.addView(gridOverlayView, new FrameLayout.LayoutParams(
|
|
207
|
+
FrameLayout.LayoutParams.MATCH_PARENT,
|
|
208
|
+
FrameLayout.LayoutParams.MATCH_PARENT
|
|
209
|
+
));
|
|
210
|
+
|
|
184
211
|
ViewGroup parent = (ViewGroup) webView.getParent();
|
|
185
212
|
if (parent != null) {
|
|
186
|
-
parent.addView(
|
|
213
|
+
parent.addView(previewContainer, new ViewGroup.LayoutParams(sessionConfig.getWidth(), sessionConfig.getHeight()));
|
|
187
214
|
if(sessionConfig.isToBack()) webView.bringToFront();
|
|
188
215
|
}
|
|
189
216
|
}
|
|
190
217
|
|
|
191
218
|
private void removePreviewView() {
|
|
192
|
-
if (
|
|
193
|
-
ViewGroup parent = (ViewGroup)
|
|
219
|
+
if (previewContainer != null) {
|
|
220
|
+
ViewGroup parent = (ViewGroup) previewContainer.getParent();
|
|
194
221
|
if (parent != null) {
|
|
195
|
-
parent.removeView(
|
|
222
|
+
parent.removeView(previewContainer);
|
|
196
223
|
}
|
|
224
|
+
previewContainer = null;
|
|
225
|
+
}
|
|
226
|
+
if (previewView != null) {
|
|
197
227
|
previewView = null;
|
|
198
228
|
}
|
|
229
|
+
if (gridOverlayView != null) {
|
|
230
|
+
gridOverlayView = null;
|
|
231
|
+
}
|
|
199
232
|
webView.setBackgroundColor(android.graphics.Color.WHITE);
|
|
200
233
|
}
|
|
201
234
|
|
|
@@ -206,9 +239,22 @@ public class CameraXView implements LifecycleOwner {
|
|
|
206
239
|
try {
|
|
207
240
|
Log.d(TAG, "Building camera selector with deviceId: " + sessionConfig.getDeviceId() + " and position: " + sessionConfig.getPosition());
|
|
208
241
|
currentCameraSelector = buildCameraSelector();
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
.
|
|
242
|
+
|
|
243
|
+
ResolutionSelector.Builder resolutionSelectorBuilder = new ResolutionSelector.Builder()
|
|
244
|
+
.setResolutionStrategy(ResolutionStrategy.HIGHEST_AVAILABLE_STRATEGY);
|
|
245
|
+
|
|
246
|
+
if (sessionConfig.getAspectRatio() != null) {
|
|
247
|
+
int aspectRatio;
|
|
248
|
+
if ("16:9".equals(sessionConfig.getAspectRatio())) {
|
|
249
|
+
aspectRatio = AspectRatio.RATIO_16_9;
|
|
250
|
+
} else { // "4:3"
|
|
251
|
+
aspectRatio = AspectRatio.RATIO_4_3;
|
|
252
|
+
}
|
|
253
|
+
resolutionSelectorBuilder.setAspectRatioStrategy(new AspectRatioStrategy(aspectRatio, AspectRatioStrategy.FALLBACK_RULE_AUTO));
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
ResolutionSelector resolutionSelector = resolutionSelectorBuilder.build();
|
|
257
|
+
|
|
212
258
|
Preview preview = new Preview.Builder().setResolutionSelector(resolutionSelector).build();
|
|
213
259
|
imageCapture = new ImageCapture.Builder().setResolutionSelector(resolutionSelector).setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY).setFlashMode(currentFlashMode).build();
|
|
214
260
|
sampleImageCapture = imageCapture;
|
|
@@ -347,13 +393,18 @@ public class CameraXView implements LifecycleOwner {
|
|
|
347
393
|
@Override
|
|
348
394
|
public void onImageSaved(@NonNull ImageCapture.OutputFileResults output) {
|
|
349
395
|
try {
|
|
350
|
-
|
|
351
|
-
|
|
396
|
+
// Read file using FileInputStream for compatibility
|
|
397
|
+
byte[] bytes = new byte[(int) tempFile.length()];
|
|
398
|
+
java.io.FileInputStream fis = new java.io.FileInputStream(tempFile);
|
|
399
|
+
fis.read(bytes);
|
|
400
|
+
fis.close();
|
|
352
401
|
|
|
402
|
+
ExifInterface exifInterface = new ExifInterface(tempFile.getAbsolutePath());
|
|
403
|
+
|
|
353
404
|
if (location != null) {
|
|
354
405
|
exifInterface.setGpsInfo(location);
|
|
355
406
|
}
|
|
356
|
-
|
|
407
|
+
|
|
357
408
|
JSONObject exifData = getExifData(exifInterface);
|
|
358
409
|
|
|
359
410
|
if (width != null && height != null) {
|
|
@@ -363,13 +414,13 @@ public class CameraXView implements LifecycleOwner {
|
|
|
363
414
|
resizedBitmap.compress(Bitmap.CompressFormat.JPEG, quality, stream);
|
|
364
415
|
bytes = stream.toByteArray();
|
|
365
416
|
}
|
|
366
|
-
|
|
417
|
+
|
|
367
418
|
if (saveToGallery) {
|
|
368
419
|
saveImageToGallery(bytes);
|
|
369
420
|
}
|
|
370
421
|
|
|
371
422
|
String base64 = Base64.encodeToString(bytes, Base64.NO_WRAP);
|
|
372
|
-
|
|
423
|
+
|
|
373
424
|
tempFile.delete();
|
|
374
425
|
|
|
375
426
|
if (listener != null) {
|
|
@@ -389,7 +440,7 @@ public class CameraXView implements LifecycleOwner {
|
|
|
389
440
|
private Bitmap resizeBitmap(Bitmap bitmap, int width, int height) {
|
|
390
441
|
return Bitmap.createScaledBitmap(bitmap, width, height, true);
|
|
391
442
|
}
|
|
392
|
-
|
|
443
|
+
|
|
393
444
|
private JSONObject getExifData(ExifInterface exifInterface) {
|
|
394
445
|
JSONObject exifData = new JSONObject();
|
|
395
446
|
try {
|
|
@@ -615,7 +666,7 @@ public class CameraXView implements LifecycleOwner {
|
|
|
615
666
|
for (CameraInfo cameraInfo : cameraProvider.getAvailableCameraInfos()) {
|
|
616
667
|
String logicalCameraId = Camera2CameraInfo.from(cameraInfo).getCameraId();
|
|
617
668
|
String position = isBackCamera(cameraInfo) ? "rear" : "front";
|
|
618
|
-
|
|
669
|
+
|
|
619
670
|
// Add logical camera
|
|
620
671
|
float minZoom = Objects.requireNonNull(cameraInfo.getZoomState().getValue()).getMinZoomRatio();
|
|
621
672
|
float maxZoom = cameraInfo.getZoomState().getValue().getMaxZoomRatio();
|
|
@@ -651,7 +702,7 @@ public class CameraXView implements LifecycleOwner {
|
|
|
651
702
|
if (focalLengths[0] < 3.0f) deviceType = "ultraWide";
|
|
652
703
|
else if (focalLengths[0] > 5.0f) deviceType = "telephoto";
|
|
653
704
|
}
|
|
654
|
-
|
|
705
|
+
|
|
655
706
|
float physicalMinZoom = 1.0f;
|
|
656
707
|
float physicalMaxZoom = 1.0f;
|
|
657
708
|
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
|
|
@@ -661,11 +712,11 @@ public class CameraXView implements LifecycleOwner {
|
|
|
661
712
|
physicalMaxZoom = zoomRange.getUpper();
|
|
662
713
|
}
|
|
663
714
|
}
|
|
664
|
-
|
|
715
|
+
|
|
665
716
|
String label = "Physical " + deviceType + " (" + position + ")";
|
|
666
717
|
List<LensInfo> physicalLenses = new ArrayList<>();
|
|
667
718
|
physicalLenses.add(new LensInfo(focalLengths != null ? focalLengths[0] : 4.25f, deviceType, 1.0f, physicalMaxZoom));
|
|
668
|
-
|
|
719
|
+
|
|
669
720
|
devices.add(new com.ahm.capacitor.camera.preview.model.CameraDevice(
|
|
670
721
|
physicalId, label, position, physicalLenses, physicalMinZoom, physicalMaxZoom, false
|
|
671
722
|
));
|
|
@@ -969,7 +1020,9 @@ public class CameraXView implements LifecycleOwner {
|
|
|
969
1020
|
sessionConfig.isEnableZoom(), // enableZoom
|
|
970
1021
|
sessionConfig.isDisableExifHeaderStripping(), // disableExifHeaderStripping
|
|
971
1022
|
sessionConfig.isDisableAudio(), // disableAudio
|
|
972
|
-
sessionConfig.getZoomFactor() // zoomFactor
|
|
1023
|
+
sessionConfig.getZoomFactor(), // zoomFactor
|
|
1024
|
+
sessionConfig.getAspectRatio(), // aspectRatio
|
|
1025
|
+
sessionConfig.getGridMode() // gridMode
|
|
973
1026
|
);
|
|
974
1027
|
|
|
975
1028
|
// Clear current device ID to force position-based selection
|
|
@@ -987,4 +1040,64 @@ public class CameraXView implements LifecycleOwner {
|
|
|
987
1040
|
previewView.setAlpha(opacity);
|
|
988
1041
|
}
|
|
989
1042
|
}
|
|
1043
|
+
|
|
1044
|
+
private void updateLayoutParams() {
|
|
1045
|
+
if (sessionConfig == null) return;
|
|
1046
|
+
|
|
1047
|
+
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
|
|
1048
|
+
sessionConfig.getWidth(),
|
|
1049
|
+
sessionConfig.getHeight()
|
|
1050
|
+
);
|
|
1051
|
+
layoutParams.leftMargin = sessionConfig.getX();
|
|
1052
|
+
layoutParams.topMargin = sessionConfig.getY();
|
|
1053
|
+
|
|
1054
|
+
if (sessionConfig.getAspectRatio() != null && !sessionConfig.getAspectRatio().equals("fill")) {
|
|
1055
|
+
String[] ratios = sessionConfig.getAspectRatio().split(":");
|
|
1056
|
+
float ratio = Float.parseFloat(ratios[0]) / Float.parseFloat(ratios[1]);
|
|
1057
|
+
if (sessionConfig.getWidth() > 0) {
|
|
1058
|
+
layoutParams.height = (int) (sessionConfig.getWidth() / ratio);
|
|
1059
|
+
} else if (sessionConfig.getHeight() > 0) {
|
|
1060
|
+
layoutParams.width = (int) (sessionConfig.getHeight() * ratio);
|
|
1061
|
+
}
|
|
1062
|
+
} else {
|
|
1063
|
+
previewView.setScaleType(PreviewView.ScaleType.FILL_CENTER);
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
previewView.setLayoutParams(layoutParams);
|
|
1067
|
+
|
|
1068
|
+
if (listener != null) {
|
|
1069
|
+
listener.onCameraStarted();
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
public String getAspectRatio() {
|
|
1074
|
+
if (sessionConfig != null) {
|
|
1075
|
+
return sessionConfig.getAspectRatio();
|
|
1076
|
+
}
|
|
1077
|
+
return "fill";
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
public void setAspectRatio(String aspectRatio) {
|
|
1081
|
+
if (sessionConfig != null) {
|
|
1082
|
+
sessionConfig = new CameraSessionConfiguration(
|
|
1083
|
+
sessionConfig.getDeviceId(),
|
|
1084
|
+
sessionConfig.getPosition(),
|
|
1085
|
+
sessionConfig.getX(),
|
|
1086
|
+
sessionConfig.getY(),
|
|
1087
|
+
sessionConfig.getWidth(),
|
|
1088
|
+
sessionConfig.getHeight(),
|
|
1089
|
+
sessionConfig.getPaddingBottom(),
|
|
1090
|
+
sessionConfig.getToBack(),
|
|
1091
|
+
sessionConfig.getStoreToFile(),
|
|
1092
|
+
sessionConfig.getEnableOpacity(),
|
|
1093
|
+
sessionConfig.getEnableZoom(),
|
|
1094
|
+
sessionConfig.getDisableExifHeaderStripping(),
|
|
1095
|
+
sessionConfig.getDisableAudio(),
|
|
1096
|
+
sessionConfig.getZoomFactor(),
|
|
1097
|
+
aspectRatio,
|
|
1098
|
+
sessionConfig.getGridMode()
|
|
1099
|
+
);
|
|
1100
|
+
updateLayoutParams();
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
990
1103
|
}
|