@capgo/camera-preview 8.3.6 → 8.3.8-beta.pr356.31.1
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 +188 -36
- package/android/build.gradle +1 -0
- package/android/src/main/AndroidManifest.xml +5 -0
- package/android/src/main/java/app/capgo/capacitor/camera/preview/CameraPreview.java +337 -9
- package/android/src/main/java/app/capgo/capacitor/camera/preview/CameraXView.java +280 -0
- package/dist/docs.json +345 -11
- package/dist/esm/definitions.d.ts +83 -7
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.d.ts +13 -3
- package/dist/esm/web.js +169 -9
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +169 -9
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +169 -9
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/CapgoCameraPreviewPlugin/CameraController.swift +167 -1
- package/ios/Sources/CapgoCameraPreviewPlugin/Plugin.swift +72 -3
- package/package.json +7 -3
package/dist/plugin.js
CHANGED
|
@@ -54,6 +54,10 @@ var capacitorCapacitorCameraView = (function (exports, core) {
|
|
|
54
54
|
this.orientationListenerBound = false;
|
|
55
55
|
this.mediaRecorder = null;
|
|
56
56
|
this.recordedChunks = [];
|
|
57
|
+
this.currentAspectRatio = '4:3';
|
|
58
|
+
this.barcodeDetector = null;
|
|
59
|
+
this.barcodeScannerTimer = null;
|
|
60
|
+
this.barcodeScannerBusy = false;
|
|
57
61
|
}
|
|
58
62
|
async checkPermissions(options) {
|
|
59
63
|
const result = {
|
|
@@ -241,6 +245,7 @@ var capacitorCapacitorCameraView = (function (exports, core) {
|
|
|
241
245
|
// Default to 4:3 if no aspect ratio or size specified
|
|
242
246
|
const useDefaultAspectRatio = !options.aspectRatio && !options.width && !options.height;
|
|
243
247
|
const effectiveAspectRatio = options.aspectRatio || (useDefaultAspectRatio ? '4:3' : null);
|
|
248
|
+
this.currentAspectRatio = effectiveAspectRatio || '4:3';
|
|
244
249
|
if (options.width) {
|
|
245
250
|
this.videoElement.width = options.width;
|
|
246
251
|
this.videoElement.style.width = `${options.width}px`;
|
|
@@ -392,16 +397,24 @@ var capacitorCapacitorCameraView = (function (exports, core) {
|
|
|
392
397
|
}
|
|
393
398
|
else if (effectiveAspectRatio) {
|
|
394
399
|
// Aspect ratio specified but no size
|
|
395
|
-
const [widthRatio, heightRatio] = effectiveAspectRatio.split(':').map(Number);
|
|
396
|
-
const targetRatio = widthRatio / heightRatio;
|
|
397
400
|
const viewportWidth = window.innerWidth;
|
|
398
401
|
const viewportHeight = window.innerHeight;
|
|
399
|
-
let targetWidth
|
|
400
|
-
let targetHeight
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
targetHeight =
|
|
404
|
-
|
|
402
|
+
let targetWidth;
|
|
403
|
+
let targetHeight;
|
|
404
|
+
if (effectiveAspectRatio === 'fill') {
|
|
405
|
+
targetWidth = containerWidth;
|
|
406
|
+
targetHeight = containerHeight;
|
|
407
|
+
}
|
|
408
|
+
else {
|
|
409
|
+
const [widthRatio, heightRatio] = effectiveAspectRatio.split(':').map(Number);
|
|
410
|
+
const targetRatio = widthRatio / heightRatio;
|
|
411
|
+
targetWidth = viewportWidth;
|
|
412
|
+
targetHeight = targetWidth / targetRatio;
|
|
413
|
+
// If height exceeds viewport, fit to height instead
|
|
414
|
+
if (targetHeight > viewportHeight) {
|
|
415
|
+
targetHeight = viewportHeight;
|
|
416
|
+
targetWidth = targetHeight * targetRatio;
|
|
417
|
+
}
|
|
405
418
|
}
|
|
406
419
|
this.videoElement.width = targetWidth;
|
|
407
420
|
this.videoElement.height = targetHeight;
|
|
@@ -529,12 +542,23 @@ var capacitorCapacitorCameraView = (function (exports, core) {
|
|
|
529
542
|
height: computedStyle.height,
|
|
530
543
|
},
|
|
531
544
|
});
|
|
532
|
-
|
|
545
|
+
const result = {
|
|
533
546
|
width: Math.round(rect.width),
|
|
534
547
|
height: Math.round(rect.height),
|
|
535
548
|
x: Math.round(rect.x),
|
|
536
549
|
y: Math.round(rect.y),
|
|
537
550
|
};
|
|
551
|
+
const barcodeScannerOptions = this.getStartBarcodeScannerOptions(options);
|
|
552
|
+
if (barcodeScannerOptions) {
|
|
553
|
+
try {
|
|
554
|
+
await this.startBarcodeScanner(barcodeScannerOptions);
|
|
555
|
+
}
|
|
556
|
+
catch (error) {
|
|
557
|
+
await this.stop({ force: true });
|
|
558
|
+
throw error;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
return result;
|
|
538
562
|
}
|
|
539
563
|
stopStream(stream) {
|
|
540
564
|
if (stream) {
|
|
@@ -544,6 +568,7 @@ var capacitorCapacitorCameraView = (function (exports, core) {
|
|
|
544
568
|
}
|
|
545
569
|
}
|
|
546
570
|
async stop(_options) {
|
|
571
|
+
await this.stopBarcodeScanner();
|
|
547
572
|
const video = document.getElementById(DEFAULT_VIDEO_ID);
|
|
548
573
|
if (video) {
|
|
549
574
|
video.pause();
|
|
@@ -631,6 +656,116 @@ var capacitorCapacitorCameraView = (function (exports, core) {
|
|
|
631
656
|
async captureSample(_options) {
|
|
632
657
|
return this.capture(_options);
|
|
633
658
|
}
|
|
659
|
+
async startBarcodeScanner(options) {
|
|
660
|
+
var _a, _b;
|
|
661
|
+
if (!this.isStarted || !((_a = this.videoElement) === null || _a === void 0 ? void 0 : _a.srcObject)) {
|
|
662
|
+
throw new Error('camera is not running');
|
|
663
|
+
}
|
|
664
|
+
const Detector = window.BarcodeDetector;
|
|
665
|
+
if (!Detector) {
|
|
666
|
+
throw new Error('BarcodeDetector API is not available in this browser');
|
|
667
|
+
}
|
|
668
|
+
await this.stopBarcodeScanner();
|
|
669
|
+
const formats = ((options === null || options === void 0 ? void 0 : options.formats) || [])
|
|
670
|
+
.map((format) => this.toWebBarcodeFormat(format))
|
|
671
|
+
.filter((format) => !!format);
|
|
672
|
+
this.barcodeDetector = new Detector(formats.length > 0 ? { formats } : undefined);
|
|
673
|
+
const detectionInterval = Math.max(100, (_b = options === null || options === void 0 ? void 0 : options.detectionInterval) !== null && _b !== void 0 ? _b : 500);
|
|
674
|
+
const detect = async () => {
|
|
675
|
+
var _a;
|
|
676
|
+
if (this.barcodeScannerBusy || !this.barcodeDetector || !((_a = this.videoElement) === null || _a === void 0 ? void 0 : _a.srcObject)) {
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
679
|
+
this.barcodeScannerBusy = true;
|
|
680
|
+
try {
|
|
681
|
+
const results = (await this.barcodeDetector.detect(this.videoElement));
|
|
682
|
+
const barcodes = results
|
|
683
|
+
.map((result) => this.toBarcodeScanResult(result))
|
|
684
|
+
.filter((barcode) => !!barcode);
|
|
685
|
+
if (barcodes.length > 0) {
|
|
686
|
+
this.notifyListeners('barcodeScanned', { barcodes });
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
catch (error) {
|
|
690
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
691
|
+
console.error('Barcode detection failed:', error);
|
|
692
|
+
this.notifyListeners('barcodeScanError', { message });
|
|
693
|
+
}
|
|
694
|
+
finally {
|
|
695
|
+
this.barcodeScannerBusy = false;
|
|
696
|
+
}
|
|
697
|
+
};
|
|
698
|
+
this.barcodeScannerTimer = window.setInterval(() => {
|
|
699
|
+
void detect();
|
|
700
|
+
}, detectionInterval);
|
|
701
|
+
void detect();
|
|
702
|
+
}
|
|
703
|
+
async stopBarcodeScanner() {
|
|
704
|
+
if (this.barcodeScannerTimer !== null) {
|
|
705
|
+
window.clearInterval(this.barcodeScannerTimer);
|
|
706
|
+
this.barcodeScannerTimer = null;
|
|
707
|
+
}
|
|
708
|
+
this.barcodeDetector = null;
|
|
709
|
+
this.barcodeScannerBusy = false;
|
|
710
|
+
}
|
|
711
|
+
getStartBarcodeScannerOptions(options) {
|
|
712
|
+
if (options.barcodeScanner === true) {
|
|
713
|
+
return {};
|
|
714
|
+
}
|
|
715
|
+
if (options.barcodeScanner && typeof options.barcodeScanner === 'object') {
|
|
716
|
+
return options.barcodeScanner;
|
|
717
|
+
}
|
|
718
|
+
return null;
|
|
719
|
+
}
|
|
720
|
+
toWebBarcodeFormat(format) {
|
|
721
|
+
switch (format) {
|
|
722
|
+
case 'aztec':
|
|
723
|
+
case 'codabar':
|
|
724
|
+
case 'code_39':
|
|
725
|
+
case 'code_93':
|
|
726
|
+
case 'code_128':
|
|
727
|
+
case 'data_matrix':
|
|
728
|
+
case 'ean_8':
|
|
729
|
+
case 'ean_13':
|
|
730
|
+
case 'itf':
|
|
731
|
+
case 'pdf417':
|
|
732
|
+
case 'qr_code':
|
|
733
|
+
case 'upc_a':
|
|
734
|
+
case 'upc_e':
|
|
735
|
+
return format;
|
|
736
|
+
default:
|
|
737
|
+
return null;
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
toBarcodeScanResult(result) {
|
|
741
|
+
if (!result.rawValue) {
|
|
742
|
+
return null;
|
|
743
|
+
}
|
|
744
|
+
return {
|
|
745
|
+
value: result.rawValue,
|
|
746
|
+
format: this.fromWebBarcodeFormat(result.format),
|
|
747
|
+
};
|
|
748
|
+
}
|
|
749
|
+
fromWebBarcodeFormat(format) {
|
|
750
|
+
switch (format) {
|
|
751
|
+
case 'aztec':
|
|
752
|
+
case 'codabar':
|
|
753
|
+
case 'code_39':
|
|
754
|
+
case 'code_93':
|
|
755
|
+
case 'code_128':
|
|
756
|
+
case 'data_matrix':
|
|
757
|
+
case 'ean_8':
|
|
758
|
+
case 'ean_13':
|
|
759
|
+
case 'itf':
|
|
760
|
+
case 'pdf417':
|
|
761
|
+
case 'qr_code':
|
|
762
|
+
case 'upc_a':
|
|
763
|
+
case 'upc_e':
|
|
764
|
+
return format;
|
|
765
|
+
default:
|
|
766
|
+
return 'unknown';
|
|
767
|
+
}
|
|
768
|
+
}
|
|
634
769
|
async stopRecordVideo() {
|
|
635
770
|
if (!this.mediaRecorder) {
|
|
636
771
|
throw new Error('video recording is not running');
|
|
@@ -948,6 +1083,9 @@ var capacitorCapacitorCameraView = (function (exports, core) {
|
|
|
948
1083
|
if (!video) {
|
|
949
1084
|
throw new Error('camera is not running');
|
|
950
1085
|
}
|
|
1086
|
+
if (this.currentAspectRatio === 'fill') {
|
|
1087
|
+
return { aspectRatio: 'fill' };
|
|
1088
|
+
}
|
|
951
1089
|
const width = video.offsetWidth;
|
|
952
1090
|
const height = video.offsetHeight;
|
|
953
1091
|
if (width && height) {
|
|
@@ -964,10 +1102,32 @@ var capacitorCapacitorCameraView = (function (exports, core) {
|
|
|
964
1102
|
return { aspectRatio: '4:3' };
|
|
965
1103
|
}
|
|
966
1104
|
async setAspectRatio(options) {
|
|
1105
|
+
var _a, _b;
|
|
967
1106
|
const video = document.getElementById(DEFAULT_VIDEO_ID);
|
|
968
1107
|
if (!video) {
|
|
969
1108
|
throw new Error('camera is not running');
|
|
970
1109
|
}
|
|
1110
|
+
this.currentAspectRatio = options.aspectRatio;
|
|
1111
|
+
if (options.aspectRatio === 'fill') {
|
|
1112
|
+
const parent = video.parentElement || document.body;
|
|
1113
|
+
const targetWidth = parent.clientWidth || window.innerWidth;
|
|
1114
|
+
const targetHeight = parent.clientHeight || window.innerHeight;
|
|
1115
|
+
const x = (_a = options.x) !== null && _a !== void 0 ? _a : 0;
|
|
1116
|
+
const y = (_b = options.y) !== null && _b !== void 0 ? _b : 0;
|
|
1117
|
+
video.style.width = `${targetWidth}px`;
|
|
1118
|
+
video.style.height = `${targetHeight}px`;
|
|
1119
|
+
video.style.left = `${x}px`;
|
|
1120
|
+
video.style.top = `${y}px`;
|
|
1121
|
+
video.style.position = 'absolute';
|
|
1122
|
+
const offsetX = targetWidth / 8;
|
|
1123
|
+
const offsetY = targetHeight / 8;
|
|
1124
|
+
return {
|
|
1125
|
+
width: Math.round(targetWidth),
|
|
1126
|
+
height: Math.round(targetHeight),
|
|
1127
|
+
x: Math.round(x + offsetX),
|
|
1128
|
+
y: Math.round(y + offsetY),
|
|
1129
|
+
};
|
|
1130
|
+
}
|
|
971
1131
|
if (options.aspectRatio) {
|
|
972
1132
|
const [widthRatio, heightRatio] = options.aspectRatio.split(':').map(Number);
|
|
973
1133
|
// For camera, use portrait orientation: 4:3 becomes 3:4, 16:9 becomes 9:16
|