@capgo/camera-preview 7.4.0-beta.20 → 7.4.0-beta.22
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 +30 -24
- 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/java/com/ahm/capacitor/camera/preview/CameraPreview.java +161 -55
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CameraXView.java +79 -38
- package/android/src/main/java/com/ahm/capacitor/camera/preview/GridOverlayView.java +8 -1
- package/dist/docs.json +43 -2
- package/dist/esm/definitions.d.ts +8 -0
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.js +50 -7
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +50 -7
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +50 -7
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/CapgoCameraPreview/CameraController.swift +70 -59
- package/ios/Sources/CapgoCameraPreview/Plugin.swift +36 -17
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -690,30 +690,31 @@ Sets the camera focus to a specific point in the preview.
|
|
|
690
690
|
|
|
691
691
|
Defines the configuration options for starting the camera preview.
|
|
692
692
|
|
|
693
|
-
| Prop | Type
|
|
694
|
-
| ---------------------------------- |
|
|
695
|
-
| **`parent`** | <code>string</code>
|
|
696
|
-
| **`className`** | <code>string</code>
|
|
697
|
-
| **`width`** | <code>number</code>
|
|
698
|
-
| **`height`** | <code>number</code>
|
|
699
|
-
| **`x`** | <code>number</code>
|
|
700
|
-
| **`y`** | <code>number</code>
|
|
701
|
-
| **`aspectRatio`** | <code>'4:3' \| '16:9'</code>
|
|
702
|
-
| **`gridMode`** | <code><a href="#gridmode">GridMode</a></code>
|
|
703
|
-
| **`includeSafeAreaInsets`** | <code>boolean</code>
|
|
704
|
-
| **`toBack`** | <code>boolean</code>
|
|
705
|
-
| **`paddingBottom`** | <code>number</code>
|
|
706
|
-
| **`rotateWhenOrientationChanged`** | <code>boolean</code>
|
|
707
|
-
| **`position`** | <code>string</code>
|
|
708
|
-
| **`storeToFile`** | <code>boolean</code>
|
|
709
|
-
| **`disableExifHeaderStripping`** | <code>boolean</code>
|
|
710
|
-
| **`disableAudio`** | <code>boolean</code>
|
|
711
|
-
| **`lockAndroidOrientation`** | <code>boolean</code>
|
|
712
|
-
| **`enableOpacity`** | <code>boolean</code>
|
|
713
|
-
| **`enableZoom`** | <code>boolean</code>
|
|
714
|
-
| **`enableVideoMode`** | <code>boolean</code>
|
|
715
|
-
| **`deviceId`** | <code>string</code>
|
|
716
|
-
| **`initialZoomLevel`** | <code>number</code>
|
|
693
|
+
| Prop | Type | Description | Default | Since |
|
|
694
|
+
| ---------------------------------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- | ----- |
|
|
695
|
+
| **`parent`** | <code>string</code> | The parent element to attach the video preview to. | | |
|
|
696
|
+
| **`className`** | <code>string</code> | A CSS class name to add to the preview element. | | |
|
|
697
|
+
| **`width`** | <code>number</code> | The width of the preview in pixels. Defaults to the screen width. | | |
|
|
698
|
+
| **`height`** | <code>number</code> | The height of the preview in pixels. Defaults to the screen height. | | |
|
|
699
|
+
| **`x`** | <code>number</code> | The horizontal origin of the preview, in pixels. | | |
|
|
700
|
+
| **`y`** | <code>number</code> | The vertical origin of the preview, in pixels. | | |
|
|
701
|
+
| **`aspectRatio`** | <code>'4:3' \| '16:9'</code> | The aspect ratio of the camera preview, '4:3' or '16:9' or 'fill'. Cannot be set if width or height is provided, otherwise the call will be rejected. Use setPreviewSize to adjust size after starting. | | 2.0.0 |
|
|
702
|
+
| **`gridMode`** | <code><a href="#gridmode">GridMode</a></code> | The grid overlay to display on the camera preview. | <code>"none"</code> | 2.1.0 |
|
|
703
|
+
| **`includeSafeAreaInsets`** | <code>boolean</code> | Adjusts the y-position to account for safe areas (e.g., notches). | <code>false</code> | |
|
|
704
|
+
| **`toBack`** | <code>boolean</code> | If true, places the preview behind the webview. | <code>true</code> | |
|
|
705
|
+
| **`paddingBottom`** | <code>number</code> | Bottom padding for the preview, in pixels. | | |
|
|
706
|
+
| **`rotateWhenOrientationChanged`** | <code>boolean</code> | Whether to rotate the preview when the device orientation changes. | <code>true</code> | |
|
|
707
|
+
| **`position`** | <code>string</code> | The camera to use. | <code>"rear"</code> | |
|
|
708
|
+
| **`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> | |
|
|
709
|
+
| **`disableExifHeaderStripping`** | <code>boolean</code> | If true, prevents the plugin from rotating the image based on EXIF data. | <code>false</code> | |
|
|
710
|
+
| **`disableAudio`** | <code>boolean</code> | If true, disables the audio stream, preventing audio permission requests. | <code>true</code> | |
|
|
711
|
+
| **`lockAndroidOrientation`** | <code>boolean</code> | If true, locks the device orientation while the camera is active. | <code>false</code> | |
|
|
712
|
+
| **`enableOpacity`** | <code>boolean</code> | If true, allows the camera preview's opacity to be changed. | <code>false</code> | |
|
|
713
|
+
| **`enableZoom`** | <code>boolean</code> | If true, enables pinch-to-zoom functionality on the preview. | <code>false</code> | |
|
|
714
|
+
| **`enableVideoMode`** | <code>boolean</code> | If true, uses the video-optimized preset for the camera session. | <code>false</code> | |
|
|
715
|
+
| **`deviceId`** | <code>string</code> | The `deviceId` of the camera to use. If provided, `position` is ignored. | | |
|
|
716
|
+
| **`initialZoomLevel`** | <code>number</code> | The initial zoom level when starting the camera preview. If the requested zoom level is not available, the native plugin will reject. | <code>1.0</code> | 2.2.0 |
|
|
717
|
+
| **`positioning`** | <code><a href="#camerapositioning">CameraPositioning</a></code> | The vertical positioning of the camera preview. | <code>"center"</code> | 2.3.0 |
|
|
717
718
|
|
|
718
719
|
|
|
719
720
|
#### ExifData
|
|
@@ -828,6 +829,11 @@ Represents the detailed information of the currently active lens.
|
|
|
828
829
|
<code>"rear" | "front"</code>
|
|
829
830
|
|
|
830
831
|
|
|
832
|
+
#### CameraPositioning
|
|
833
|
+
|
|
834
|
+
<code>"center" | "top" | "bottom"</code>
|
|
835
|
+
|
|
836
|
+
|
|
831
837
|
#### PictureFormat
|
|
832
838
|
|
|
833
839
|
<code>"jpeg" | "png"</code>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -174,7 +174,14 @@ public class CameraPreview
|
|
|
174
174
|
Integer height = call.getInt("height");
|
|
175
175
|
String aspectRatio = call.getString("aspectRatio");
|
|
176
176
|
|
|
177
|
-
cameraXView.capturePhoto(
|
|
177
|
+
cameraXView.capturePhoto(
|
|
178
|
+
quality,
|
|
179
|
+
saveToGallery,
|
|
180
|
+
width,
|
|
181
|
+
height,
|
|
182
|
+
aspectRatio,
|
|
183
|
+
location
|
|
184
|
+
);
|
|
178
185
|
}
|
|
179
186
|
|
|
180
187
|
@PluginMethod
|
|
@@ -493,6 +500,7 @@ public class CameraPreview
|
|
|
493
500
|
);
|
|
494
501
|
final String aspectRatio = call.getString("aspectRatio", "4:3");
|
|
495
502
|
final String gridMode = call.getString("gridMode", "none");
|
|
503
|
+
final String positioning = call.getString("positioning", "top");
|
|
496
504
|
final float initialZoomLevel = call.getFloat("initialZoomLevel", 1.0f);
|
|
497
505
|
|
|
498
506
|
// Check for conflict between aspectRatio and size
|
|
@@ -576,39 +584,82 @@ public class CameraPreview
|
|
|
576
584
|
|
|
577
585
|
// Calculate pixel ratio
|
|
578
586
|
float pixelRatio = metrics.density;
|
|
579
|
-
|
|
587
|
+
|
|
580
588
|
// The key insight: JavaScript coordinates are relative to the WebView's viewport
|
|
581
|
-
// If the WebView is positioned below the status bar (webViewLocationOnScreen[1] > 0),
|
|
589
|
+
// If the WebView is positioned below the status bar (webViewLocationOnScreen[1] > 0),
|
|
582
590
|
// we need to add that offset when placing native views
|
|
583
591
|
int webViewTopInset = webViewLocationOnScreen[1];
|
|
584
592
|
boolean isEdgeToEdgeActive = webViewLocationOnScreen[1] > 0;
|
|
585
|
-
|
|
593
|
+
|
|
586
594
|
// Log all the positioning information for debugging
|
|
587
595
|
Log.d("CameraPreview", "WebView Position Debug:");
|
|
588
596
|
Log.d("CameraPreview", " - webView.getTop(): " + webViewTop);
|
|
589
597
|
Log.d("CameraPreview", " - webView.getLeft(): " + webViewLeft);
|
|
590
|
-
Log.d(
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
598
|
+
Log.d(
|
|
599
|
+
"CameraPreview",
|
|
600
|
+
" - webView locationInWindow: (" +
|
|
601
|
+
webViewLocationInWindow[0] +
|
|
602
|
+
", " +
|
|
603
|
+
webViewLocationInWindow[1] +
|
|
604
|
+
")"
|
|
605
|
+
);
|
|
606
|
+
Log.d(
|
|
607
|
+
"CameraPreview",
|
|
608
|
+
" - webView locationOnScreen: (" +
|
|
609
|
+
webViewLocationOnScreen[0] +
|
|
610
|
+
", " +
|
|
611
|
+
webViewLocationOnScreen[1] +
|
|
612
|
+
")"
|
|
613
|
+
);
|
|
614
|
+
Log.d(
|
|
615
|
+
"CameraPreview",
|
|
616
|
+
" - parent locationInWindow: (" +
|
|
617
|
+
parentLocationInWindow[0] +
|
|
618
|
+
", " +
|
|
619
|
+
parentLocationInWindow[1] +
|
|
620
|
+
")"
|
|
621
|
+
);
|
|
622
|
+
Log.d(
|
|
623
|
+
"CameraPreview",
|
|
624
|
+
" - parent locationOnScreen: (" +
|
|
625
|
+
parentLocationOnScreen[0] +
|
|
626
|
+
", " +
|
|
627
|
+
parentLocationOnScreen[1] +
|
|
628
|
+
")"
|
|
629
|
+
);
|
|
630
|
+
|
|
595
631
|
// Check if WebView has margins
|
|
596
632
|
View webView = getBridge().getWebView();
|
|
597
633
|
ViewGroup.LayoutParams webViewLayoutParams = webView.getLayoutParams();
|
|
598
634
|
if (webViewLayoutParams instanceof ViewGroup.MarginLayoutParams) {
|
|
599
|
-
ViewGroup.MarginLayoutParams marginParams =
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
635
|
+
ViewGroup.MarginLayoutParams marginParams =
|
|
636
|
+
(ViewGroup.MarginLayoutParams) webViewLayoutParams;
|
|
637
|
+
Log.d(
|
|
638
|
+
"CameraPreview",
|
|
639
|
+
" - webView margins: left=" +
|
|
640
|
+
marginParams.leftMargin +
|
|
641
|
+
", top=" +
|
|
642
|
+
marginParams.topMargin +
|
|
643
|
+
", right=" +
|
|
644
|
+
marginParams.rightMargin +
|
|
645
|
+
", bottom=" +
|
|
646
|
+
marginParams.bottomMargin
|
|
647
|
+
);
|
|
604
648
|
}
|
|
605
|
-
|
|
649
|
+
|
|
606
650
|
// Check WebView padding
|
|
607
|
-
Log.d(
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
651
|
+
Log.d(
|
|
652
|
+
"CameraPreview",
|
|
653
|
+
" - webView padding: left=" +
|
|
654
|
+
webView.getPaddingLeft() +
|
|
655
|
+
", top=" +
|
|
656
|
+
webView.getPaddingTop() +
|
|
657
|
+
", right=" +
|
|
658
|
+
webView.getPaddingRight() +
|
|
659
|
+
", bottom=" +
|
|
660
|
+
webView.getPaddingBottom()
|
|
661
|
+
);
|
|
662
|
+
|
|
612
663
|
Log.d("CameraPreview", " - Using webViewTopInset: " + webViewTopInset);
|
|
613
664
|
Log.d("CameraPreview", " - isEdgeToEdgeActive: " + isEdgeToEdgeActive);
|
|
614
665
|
|
|
@@ -627,11 +678,39 @@ public class CameraPreview
|
|
|
627
678
|
|
|
628
679
|
Log.d("CameraPreview", "========================");
|
|
629
680
|
Log.d("CameraPreview", "POSITIONING CALCULATIONS:");
|
|
630
|
-
Log.d(
|
|
681
|
+
Log.d(
|
|
682
|
+
"CameraPreview",
|
|
683
|
+
"1. INPUT - x: " +
|
|
684
|
+
x +
|
|
685
|
+
", y: " +
|
|
686
|
+
y +
|
|
687
|
+
", width: " +
|
|
688
|
+
width +
|
|
689
|
+
", height: " +
|
|
690
|
+
height
|
|
691
|
+
);
|
|
631
692
|
Log.d("CameraPreview", "2. PIXEL RATIO: " + pixelRatio);
|
|
632
|
-
Log.d(
|
|
633
|
-
|
|
634
|
-
|
|
693
|
+
Log.d(
|
|
694
|
+
"CameraPreview",
|
|
695
|
+
"3. SCREEN - width: " +
|
|
696
|
+
metrics.widthPixels +
|
|
697
|
+
", height: " +
|
|
698
|
+
metrics.heightPixels
|
|
699
|
+
);
|
|
700
|
+
Log.d(
|
|
701
|
+
"CameraPreview",
|
|
702
|
+
"4. WEBVIEW - width: " +
|
|
703
|
+
getBridge().getWebView().getWidth() +
|
|
704
|
+
", height: " +
|
|
705
|
+
getBridge().getWebView().getHeight()
|
|
706
|
+
);
|
|
707
|
+
Log.d(
|
|
708
|
+
"CameraPreview",
|
|
709
|
+
"5. COMPUTED DIMENSIONS - width: " +
|
|
710
|
+
computedWidth +
|
|
711
|
+
", height: " +
|
|
712
|
+
computedHeight
|
|
713
|
+
);
|
|
635
714
|
|
|
636
715
|
if (x == -1) {
|
|
637
716
|
// Center horizontally
|
|
@@ -660,34 +739,58 @@ public class CameraPreview
|
|
|
660
739
|
}
|
|
661
740
|
|
|
662
741
|
if (y == -1) {
|
|
663
|
-
//
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
"CameraPreview",
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
742
|
+
// Position vertically based on positioning parameter
|
|
743
|
+
int screenHeight = metrics.heightPixels;
|
|
744
|
+
|
|
745
|
+
switch (positioning) {
|
|
746
|
+
case "top":
|
|
747
|
+
computedY = 0;
|
|
748
|
+
Log.d("CameraPreview", "Positioning at top: computedY=0");
|
|
749
|
+
break;
|
|
750
|
+
case "bottom":
|
|
751
|
+
computedY = screenHeight - computedHeight;
|
|
752
|
+
Log.d(
|
|
753
|
+
"CameraPreview",
|
|
754
|
+
"Positioning at bottom: screenHeight=" +
|
|
755
|
+
screenHeight +
|
|
756
|
+
", computedHeight=" +
|
|
757
|
+
computedHeight +
|
|
758
|
+
", computedY=" +
|
|
759
|
+
computedY
|
|
760
|
+
);
|
|
761
|
+
break;
|
|
762
|
+
case "center":
|
|
763
|
+
default:
|
|
764
|
+
// Center vertically
|
|
765
|
+
if (isEdgeToEdgeActive) {
|
|
766
|
+
// When WebView is offset from top, center within the available space
|
|
767
|
+
// The camera should be centered in the full screen, not just the WebView area
|
|
768
|
+
computedY = (screenHeight - computedHeight) / 2;
|
|
769
|
+
Log.d(
|
|
770
|
+
"CameraPreview",
|
|
771
|
+
"Centering vertically with WebView offset: screenHeight=" +
|
|
772
|
+
screenHeight +
|
|
773
|
+
", webViewTop=" +
|
|
774
|
+
webViewTopInset +
|
|
775
|
+
", computedHeight=" +
|
|
776
|
+
computedHeight +
|
|
777
|
+
", computedY=" +
|
|
778
|
+
computedY
|
|
779
|
+
);
|
|
780
|
+
} else {
|
|
781
|
+
// Normal mode - use full screen height
|
|
782
|
+
computedY = (screenHeight - computedHeight) / 2;
|
|
783
|
+
Log.d(
|
|
784
|
+
"CameraPreview",
|
|
785
|
+
"Centering vertically (normal): screenHeight=" +
|
|
786
|
+
screenHeight +
|
|
787
|
+
", computedHeight=" +
|
|
788
|
+
computedHeight +
|
|
789
|
+
", computedY=" +
|
|
790
|
+
computedY
|
|
791
|
+
);
|
|
792
|
+
}
|
|
793
|
+
break;
|
|
691
794
|
}
|
|
692
795
|
} else {
|
|
693
796
|
computedY = (int) (y * pixelRatio);
|
|
@@ -698,7 +801,7 @@ public class CameraPreview
|
|
|
698
801
|
Log.d(
|
|
699
802
|
"CameraPreview",
|
|
700
803
|
"Edge-to-edge adjustment: Y position " +
|
|
701
|
-
(int)(y * pixelRatio) +
|
|
804
|
+
(int) (y * pixelRatio) +
|
|
702
805
|
" + inset " +
|
|
703
806
|
webViewTopInset +
|
|
704
807
|
" = " +
|
|
@@ -719,7 +822,10 @@ public class CameraPreview
|
|
|
719
822
|
|
|
720
823
|
Log.d(
|
|
721
824
|
"CameraPreview",
|
|
722
|
-
"2b. EDGE-TO-EDGE - " +
|
|
825
|
+
"2b. EDGE-TO-EDGE - " +
|
|
826
|
+
(isEdgeToEdgeActive
|
|
827
|
+
? "ACTIVE (inset=" + webViewTopInset + ")"
|
|
828
|
+
: "INACTIVE")
|
|
723
829
|
);
|
|
724
830
|
Log.d(
|
|
725
831
|
"CameraPreview",
|
|
@@ -1062,7 +1168,7 @@ public class CameraPreview
|
|
|
1062
1168
|
|
|
1063
1169
|
int x = (xParam != null && xParam > 0) ? (int) (xParam * pixelRatio) : 0;
|
|
1064
1170
|
int y = (yParam != null && yParam > 0) ? (int) (yParam * pixelRatio) : 0;
|
|
1065
|
-
|
|
1171
|
+
|
|
1066
1172
|
// Add edge-to-edge inset to Y if active
|
|
1067
1173
|
if (isEdgeToEdgeActive && y > 0) {
|
|
1068
1174
|
y += webViewTopInset;
|
|
@@ -360,14 +360,21 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
|
|
|
360
360
|
Log.d(TAG, "setupPreviewView: Setting grid mode to: " + currentGridMode);
|
|
361
361
|
gridOverlayView.setGridMode(currentGridMode);
|
|
362
362
|
});
|
|
363
|
-
|
|
363
|
+
|
|
364
364
|
// Add a layout listener to update grid bounds when preview view changes size
|
|
365
|
-
previewView.addOnLayoutChangeListener(
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
365
|
+
previewView.addOnLayoutChangeListener(
|
|
366
|
+
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
|
|
367
|
+
if (
|
|
368
|
+
left != oldLeft ||
|
|
369
|
+
top != oldTop ||
|
|
370
|
+
right != oldRight ||
|
|
371
|
+
bottom != oldBottom
|
|
372
|
+
) {
|
|
373
|
+
Log.d(TAG, "PreviewView layout changed, updating grid bounds");
|
|
374
|
+
updateGridOverlayBounds();
|
|
375
|
+
}
|
|
369
376
|
}
|
|
370
|
-
|
|
377
|
+
);
|
|
371
378
|
|
|
372
379
|
ViewGroup parent = (ViewGroup) webView.getParent();
|
|
373
380
|
if (parent != null) {
|
|
@@ -838,12 +845,24 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
|
|
|
838
845
|
String aspectRatio,
|
|
839
846
|
Location location
|
|
840
847
|
) {
|
|
841
|
-
Log.d(
|
|
848
|
+
Log.d(
|
|
849
|
+
TAG,
|
|
850
|
+
"capturePhoto: Starting photo capture with quality: " +
|
|
851
|
+
quality +
|
|
852
|
+
", width: " +
|
|
853
|
+
width +
|
|
854
|
+
", height: " +
|
|
855
|
+
height +
|
|
856
|
+
", aspectRatio: " +
|
|
857
|
+
aspectRatio
|
|
858
|
+
);
|
|
842
859
|
|
|
843
860
|
// Check for conflicting parameters
|
|
844
861
|
if (aspectRatio != null && (width != null || height != null)) {
|
|
845
862
|
if (listener != null) {
|
|
846
|
-
listener.onPictureTakenError(
|
|
863
|
+
listener.onPictureTakenError(
|
|
864
|
+
"Cannot set both aspectRatio and size (width/height). Use setPreviewSize after start."
|
|
865
|
+
);
|
|
847
866
|
}
|
|
848
867
|
return;
|
|
849
868
|
}
|
|
@@ -896,36 +915,56 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
|
|
|
896
915
|
|
|
897
916
|
// Use the stored aspectRatio if none is provided and no width/height is specified
|
|
898
917
|
String captureAspectRatio = aspectRatio;
|
|
899
|
-
if (
|
|
918
|
+
if (
|
|
919
|
+
width == null &&
|
|
920
|
+
height == null &&
|
|
921
|
+
aspectRatio == null &&
|
|
922
|
+
sessionConfig != null
|
|
923
|
+
) {
|
|
900
924
|
captureAspectRatio = sessionConfig.getAspectRatio();
|
|
901
925
|
// Default to "4:3" if no aspect ratio was set at all
|
|
902
926
|
if (captureAspectRatio == null) {
|
|
903
927
|
captureAspectRatio = "4:3";
|
|
904
928
|
}
|
|
905
|
-
Log.d(
|
|
929
|
+
Log.d(
|
|
930
|
+
TAG,
|
|
931
|
+
"capturePhoto: Using stored aspectRatio: " + captureAspectRatio
|
|
932
|
+
);
|
|
906
933
|
}
|
|
907
|
-
|
|
934
|
+
|
|
908
935
|
// Handle aspect ratio if no width/height specified
|
|
909
|
-
if (
|
|
936
|
+
if (
|
|
937
|
+
width == null &&
|
|
938
|
+
height == null &&
|
|
939
|
+
captureAspectRatio != null &&
|
|
940
|
+
!captureAspectRatio.isEmpty()
|
|
941
|
+
) {
|
|
910
942
|
// Get the original image dimensions
|
|
911
|
-
Bitmap originalBitmap = BitmapFactory.decodeByteArray(
|
|
943
|
+
Bitmap originalBitmap = BitmapFactory.decodeByteArray(
|
|
944
|
+
bytes,
|
|
945
|
+
0,
|
|
946
|
+
bytes.length
|
|
947
|
+
);
|
|
912
948
|
int originalWidth = originalBitmap.getWidth();
|
|
913
949
|
int originalHeight = originalBitmap.getHeight();
|
|
914
|
-
|
|
950
|
+
|
|
915
951
|
// Parse aspect ratio
|
|
916
952
|
String[] ratios = captureAspectRatio.split(":");
|
|
917
953
|
if (ratios.length == 2) {
|
|
918
954
|
try {
|
|
919
955
|
float widthRatio = Float.parseFloat(ratios[0]);
|
|
920
956
|
float heightRatio = Float.parseFloat(ratios[1]);
|
|
921
|
-
|
|
957
|
+
|
|
922
958
|
// For capture in portrait orientation, swap the aspect ratio (16:9 becomes 9:16)
|
|
923
959
|
boolean isPortrait = originalHeight > originalWidth;
|
|
924
|
-
float targetAspectRatio = isPortrait
|
|
925
|
-
|
|
926
|
-
|
|
960
|
+
float targetAspectRatio = isPortrait
|
|
961
|
+
? heightRatio / widthRatio
|
|
962
|
+
: widthRatio / heightRatio;
|
|
963
|
+
float originalAspectRatio =
|
|
964
|
+
(float) originalWidth / originalHeight;
|
|
965
|
+
|
|
927
966
|
int targetWidth, targetHeight;
|
|
928
|
-
|
|
967
|
+
|
|
929
968
|
if (originalAspectRatio > targetAspectRatio) {
|
|
930
969
|
// Original is wider than target - fit by height
|
|
931
970
|
targetHeight = originalHeight;
|
|
@@ -935,11 +974,11 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
|
|
|
935
974
|
targetWidth = originalWidth;
|
|
936
975
|
targetHeight = (int) (targetWidth / targetAspectRatio);
|
|
937
976
|
}
|
|
938
|
-
|
|
977
|
+
|
|
939
978
|
// Center crop the image
|
|
940
979
|
int xOffset = (originalWidth - targetWidth) / 2;
|
|
941
980
|
int yOffset = (originalHeight - targetHeight) / 2;
|
|
942
|
-
|
|
981
|
+
|
|
943
982
|
Bitmap croppedBitmap = Bitmap.createBitmap(
|
|
944
983
|
originalBitmap,
|
|
945
984
|
xOffset,
|
|
@@ -947,18 +986,26 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
|
|
|
947
986
|
targetWidth,
|
|
948
987
|
targetHeight
|
|
949
988
|
);
|
|
950
|
-
|
|
989
|
+
|
|
951
990
|
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
|
952
|
-
croppedBitmap.compress(
|
|
991
|
+
croppedBitmap.compress(
|
|
992
|
+
Bitmap.CompressFormat.JPEG,
|
|
993
|
+
quality,
|
|
994
|
+
stream
|
|
995
|
+
);
|
|
953
996
|
bytes = stream.toByteArray();
|
|
954
|
-
|
|
997
|
+
|
|
955
998
|
// Write EXIF data back to cropped image
|
|
956
999
|
bytes = writeExifToImageBytes(bytes, exifInterface);
|
|
957
|
-
|
|
1000
|
+
|
|
958
1001
|
originalBitmap.recycle();
|
|
959
1002
|
croppedBitmap.recycle();
|
|
960
1003
|
} catch (NumberFormatException e) {
|
|
961
|
-
Log.e(
|
|
1004
|
+
Log.e(
|
|
1005
|
+
TAG,
|
|
1006
|
+
"Invalid aspect ratio format: " + captureAspectRatio,
|
|
1007
|
+
e
|
|
1008
|
+
);
|
|
962
1009
|
}
|
|
963
1010
|
}
|
|
964
1011
|
} else if (width != null && height != null) {
|
|
@@ -1616,7 +1663,7 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
|
|
|
1616
1663
|
|
|
1617
1664
|
int viewWidth = previewView.getWidth();
|
|
1618
1665
|
int viewHeight = previewView.getHeight();
|
|
1619
|
-
|
|
1666
|
+
|
|
1620
1667
|
if (viewWidth <= 0 || viewHeight <= 0) {
|
|
1621
1668
|
throw new Exception(
|
|
1622
1669
|
"Preview view has invalid dimensions: " + viewWidth + "x" + viewHeight
|
|
@@ -2804,7 +2851,7 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
|
|
|
2804
2851
|
finalY +
|
|
2805
2852
|
")"
|
|
2806
2853
|
);
|
|
2807
|
-
|
|
2854
|
+
|
|
2808
2855
|
// Update grid overlay bounds after aspect ratio change
|
|
2809
2856
|
previewContainer.post(() -> updateGridOverlayBounds());
|
|
2810
2857
|
}
|
|
@@ -2863,14 +2910,8 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
|
|
|
2863
2910
|
int webViewTopInset = getWebViewTopInset();
|
|
2864
2911
|
int webViewLeftInset = getWebViewLeftInset();
|
|
2865
2912
|
|
|
2866
|
-
int x = Math.max(
|
|
2867
|
-
|
|
2868
|
-
(int) ((actualX - webViewLeftInset) / pixelRatio)
|
|
2869
|
-
);
|
|
2870
|
-
int y = Math.max(
|
|
2871
|
-
0,
|
|
2872
|
-
(int) ((actualY - webViewTopInset) / pixelRatio)
|
|
2873
|
-
);
|
|
2913
|
+
int x = Math.max(0, (int) ((actualX - webViewLeftInset) / pixelRatio));
|
|
2914
|
+
int y = Math.max(0, (int) ((actualY - webViewTopInset) / pixelRatio));
|
|
2874
2915
|
int width = (int) (actualWidth / pixelRatio);
|
|
2875
2916
|
int height = (int) (actualHeight / pixelRatio);
|
|
2876
2917
|
|
|
@@ -2881,10 +2922,10 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
|
|
|
2881
2922
|
if (gridOverlayView != null && previewView != null) {
|
|
2882
2923
|
// Get the actual camera bounds
|
|
2883
2924
|
Rect cameraBounds = getActualCameraBounds();
|
|
2884
|
-
|
|
2925
|
+
|
|
2885
2926
|
// Update the grid overlay with the camera bounds
|
|
2886
2927
|
gridOverlayView.setCameraBounds(cameraBounds);
|
|
2887
|
-
|
|
2928
|
+
|
|
2888
2929
|
Log.d(
|
|
2889
2930
|
TAG,
|
|
2890
2931
|
"updateGridOverlayBounds: Updated grid bounds to " +
|
|
@@ -93,7 +93,14 @@ public class GridOverlayView extends View {
|
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
private void drawGrid(
|
|
96
|
+
private void drawGrid(
|
|
97
|
+
Canvas canvas,
|
|
98
|
+
int left,
|
|
99
|
+
int top,
|
|
100
|
+
int width,
|
|
101
|
+
int height,
|
|
102
|
+
int divisions
|
|
103
|
+
) {
|
|
97
104
|
float stepX = (float) width / divisions;
|
|
98
105
|
float stepY = (float) height / divisions;
|
|
99
106
|
|