capacitor-camera-module 0.0.32 → 0.0.34
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.
|
@@ -15,7 +15,6 @@ import com.getcapacitor.annotation.PermissionCallback;
|
|
|
15
15
|
|
|
16
16
|
import android.view.ViewGroup;
|
|
17
17
|
import android.widget.FrameLayout;
|
|
18
|
-
import androidx.appcompat.app.AppCompatActivity;
|
|
19
18
|
import androidx.core.content.ContextCompat;
|
|
20
19
|
import androidx.camera.core.CameraSelector;
|
|
21
20
|
import androidx.camera.core.Preview;
|
|
@@ -67,7 +66,11 @@ import com.google.mlkit.vision.barcode.common.Barcode;
|
|
|
67
66
|
import com.google.mlkit.vision.barcode.BarcodeScanner;
|
|
68
67
|
import com.google.mlkit.vision.barcode.BarcodeScanning;
|
|
69
68
|
|
|
69
|
+
import android.graphics.YuvImage;
|
|
70
|
+
import android.graphics.Rect;
|
|
71
|
+
import java.util.concurrent.Executors;
|
|
70
72
|
|
|
73
|
+
import java.util.concurrent.ExecutorService;
|
|
71
74
|
|
|
72
75
|
|
|
73
76
|
@CapacitorPlugin(
|
|
@@ -92,7 +95,6 @@ public class CameraModulePlugin extends Plugin {
|
|
|
92
95
|
|
|
93
96
|
private PreviewView previewView;
|
|
94
97
|
private ProcessCameraProvider cameraProvider;
|
|
95
|
-
private CameraSelector cameraSelector;
|
|
96
98
|
|
|
97
99
|
private Camera camera;
|
|
98
100
|
|
|
@@ -101,12 +103,17 @@ public class CameraModulePlugin extends Plugin {
|
|
|
101
103
|
|
|
102
104
|
private ImageCapture imageCapture;
|
|
103
105
|
|
|
104
|
-
private PluginCall pendingCaptureCall;
|
|
105
|
-
|
|
106
106
|
private ImageAnalysis imageAnalysis;
|
|
107
107
|
private boolean isScanning = false;
|
|
108
108
|
private PluginCall scanCall;
|
|
109
109
|
|
|
110
|
+
private CameraSelector cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA;
|
|
111
|
+
|
|
112
|
+
private BarcodeScanner barcodeScanner;
|
|
113
|
+
|
|
114
|
+
private final ExecutorService barcodeExecutor = Executors.newSingleThreadExecutor();
|
|
115
|
+
|
|
116
|
+
|
|
110
117
|
|
|
111
118
|
@Override
|
|
112
119
|
public void load() {
|
|
@@ -236,6 +243,12 @@ public class CameraModulePlugin extends Plugin {
|
|
|
236
243
|
@PluginMethod
|
|
237
244
|
public void startPreview(PluginCall call) {
|
|
238
245
|
getActivity().runOnUiThread(() -> {
|
|
246
|
+
|
|
247
|
+
if (previewView != null) {
|
|
248
|
+
call.resolve();
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
|
|
239
252
|
previewView = new PreviewView(getContext());
|
|
240
253
|
previewView.setLayoutParams(
|
|
241
254
|
new FrameLayout.LayoutParams(
|
|
@@ -269,7 +282,7 @@ public class CameraModulePlugin extends Plugin {
|
|
|
269
282
|
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
|
|
270
283
|
.build();
|
|
271
284
|
|
|
272
|
-
|
|
285
|
+
|
|
273
286
|
|
|
274
287
|
cameraProvider.unbindAll();
|
|
275
288
|
|
|
@@ -306,6 +319,11 @@ public class CameraModulePlugin extends Plugin {
|
|
|
306
319
|
previewView = null;
|
|
307
320
|
}
|
|
308
321
|
|
|
322
|
+
if (barcodeScanner != null) {
|
|
323
|
+
barcodeScanner.close();
|
|
324
|
+
barcodeScanner = null;
|
|
325
|
+
}
|
|
326
|
+
|
|
309
327
|
call.resolve();
|
|
310
328
|
});
|
|
311
329
|
}
|
|
@@ -355,6 +373,10 @@ public class CameraModulePlugin extends Plugin {
|
|
|
355
373
|
return;
|
|
356
374
|
}
|
|
357
375
|
|
|
376
|
+
if (savedCall != null) {
|
|
377
|
+
call.reject("Gallery already open");
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
358
380
|
savedCall = call;
|
|
359
381
|
|
|
360
382
|
Intent intent = new Intent(
|
|
@@ -404,11 +426,19 @@ public class CameraModulePlugin extends Plugin {
|
|
|
404
426
|
float ratio = (float) width / height;
|
|
405
427
|
|
|
406
428
|
if (width > height) {
|
|
407
|
-
if (width <= maxSize)
|
|
429
|
+
if (width <= maxSize && height <= maxSize) {
|
|
430
|
+
Bitmap.Config config =
|
|
431
|
+
bitmap.getConfig() != null ? bitmap.getConfig() : Bitmap.Config.ARGB_8888;
|
|
432
|
+
return bitmap.copy(config, false);
|
|
433
|
+
}
|
|
408
434
|
width = maxSize;
|
|
409
435
|
height = Math.round(width / ratio);
|
|
410
436
|
} else {
|
|
411
|
-
if (height <= maxSize)
|
|
437
|
+
if (height <= maxSize && width <= maxSize) {
|
|
438
|
+
Bitmap.Config config =
|
|
439
|
+
bitmap.getConfig() != null ? bitmap.getConfig() : Bitmap.Config.ARGB_8888;
|
|
440
|
+
return bitmap.copy(config, false);
|
|
441
|
+
}
|
|
412
442
|
height = maxSize;
|
|
413
443
|
width = Math.round(height * ratio);
|
|
414
444
|
}
|
|
@@ -558,6 +588,11 @@ public class CameraModulePlugin extends Plugin {
|
|
|
558
588
|
) {
|
|
559
589
|
try {
|
|
560
590
|
Bitmap bitmap = imageProxyToBitmap(image);
|
|
591
|
+
if (bitmap == null) {
|
|
592
|
+
image.close();
|
|
593
|
+
call.reject("Failed to convert image");
|
|
594
|
+
return;
|
|
595
|
+
}
|
|
561
596
|
int rotation = image.getImageInfo().getRotationDegrees();
|
|
562
597
|
bitmap = rotateBitmap(bitmap, rotation);
|
|
563
598
|
image.close();
|
|
@@ -600,15 +635,45 @@ public class CameraModulePlugin extends Plugin {
|
|
|
600
635
|
}
|
|
601
636
|
|
|
602
637
|
private Bitmap imageProxyToBitmap(ImageProxy image) {
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
638
|
+
Image mediaImage = image.getImage();
|
|
639
|
+
if (mediaImage == null) return null;
|
|
640
|
+
|
|
641
|
+
ByteBuffer yBuffer = image.getPlanes()[0].getBuffer();
|
|
642
|
+
ByteBuffer uBuffer = image.getPlanes()[1].getBuffer();
|
|
643
|
+
ByteBuffer vBuffer = image.getPlanes()[2].getBuffer();
|
|
644
|
+
|
|
645
|
+
int ySize = yBuffer.remaining();
|
|
646
|
+
int uSize = uBuffer.remaining();
|
|
647
|
+
int vSize = vBuffer.remaining();
|
|
648
|
+
|
|
649
|
+
byte[] nv21 = new byte[ySize + uSize + vSize];
|
|
650
|
+
|
|
651
|
+
yBuffer.get(nv21, 0, ySize);
|
|
652
|
+
vBuffer.get(nv21, ySize, vSize);
|
|
653
|
+
uBuffer.get(nv21, ySize + vSize, uSize);
|
|
654
|
+
|
|
655
|
+
YuvImage yuvImage =
|
|
656
|
+
new YuvImage(
|
|
657
|
+
nv21,
|
|
658
|
+
ImageFormat.NV21,
|
|
659
|
+
image.getWidth(),
|
|
660
|
+
image.getHeight(),
|
|
661
|
+
null
|
|
662
|
+
);
|
|
607
663
|
|
|
608
|
-
|
|
664
|
+
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
|
665
|
+
yuvImage.compressToJpeg(
|
|
666
|
+
new Rect(0, 0, image.getWidth(), image.getHeight()),
|
|
667
|
+
100,
|
|
668
|
+
out
|
|
669
|
+
);
|
|
670
|
+
|
|
671
|
+
byte[] jpegBytes = out.toByteArray();
|
|
672
|
+
return BitmapFactory.decodeByteArray(jpegBytes, 0, jpegBytes.length);
|
|
609
673
|
}
|
|
610
674
|
|
|
611
675
|
|
|
676
|
+
|
|
612
677
|
private Bitmap rotateBitmap(Bitmap bitmap, int rotationDegrees) {
|
|
613
678
|
if (rotationDegrees == 0) return bitmap;
|
|
614
679
|
|
|
@@ -627,32 +692,19 @@ public class CameraModulePlugin extends Plugin {
|
|
|
627
692
|
}
|
|
628
693
|
|
|
629
694
|
|
|
630
|
-
|
|
631
|
-
private Bitmap mirrorBitmap(Bitmap bitmap) {
|
|
632
|
-
Matrix matrix = new Matrix();
|
|
633
|
-
matrix.preScale(-1, 1);
|
|
634
|
-
|
|
635
|
-
return Bitmap.createBitmap(
|
|
636
|
-
bitmap,
|
|
637
|
-
0,
|
|
638
|
-
0,
|
|
639
|
-
bitmap.getWidth(),
|
|
640
|
-
bitmap.getHeight(),
|
|
641
|
-
matrix,
|
|
642
|
-
true
|
|
643
|
-
);
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
private String bitmapToBase64(Bitmap bitmap) {
|
|
647
|
-
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
|
648
|
-
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, outputStream);
|
|
649
|
-
byte[] bytes = outputStream.toByteArray();
|
|
650
|
-
return Base64.encodeToString(bytes, Base64.NO_WRAP);
|
|
651
|
-
}
|
|
652
|
-
|
|
653
695
|
@PluginMethod
|
|
654
696
|
public void startBarcodeScan(PluginCall call) {
|
|
655
697
|
|
|
698
|
+
if (previewView == null) {
|
|
699
|
+
call.reject("Preview not started");
|
|
700
|
+
return;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
if (getPermissionState("camera") != PermissionState.GRANTED) {
|
|
704
|
+
call.reject("Camera permission not granted");
|
|
705
|
+
return;
|
|
706
|
+
}
|
|
707
|
+
|
|
656
708
|
if (cameraProvider == null) {
|
|
657
709
|
call.reject("Camera not initialized");
|
|
658
710
|
return;
|
|
@@ -663,6 +715,10 @@ public class CameraModulePlugin extends Plugin {
|
|
|
663
715
|
return;
|
|
664
716
|
}
|
|
665
717
|
|
|
718
|
+
barcodeScanner = BarcodeScanning.getClient();
|
|
719
|
+
|
|
720
|
+
call.setKeepAlive(true);
|
|
721
|
+
|
|
666
722
|
scanCall = call;
|
|
667
723
|
isScanning = true;
|
|
668
724
|
|
|
@@ -674,8 +730,8 @@ public class CameraModulePlugin extends Plugin {
|
|
|
674
730
|
.build();
|
|
675
731
|
|
|
676
732
|
imageAnalysis.setAnalyzer(
|
|
677
|
-
|
|
678
|
-
|
|
733
|
+
barcodeExecutor,
|
|
734
|
+
this::processBarcode
|
|
679
735
|
);
|
|
680
736
|
|
|
681
737
|
cameraProvider.unbindAll();
|
|
@@ -688,6 +744,10 @@ public class CameraModulePlugin extends Plugin {
|
|
|
688
744
|
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
|
|
689
745
|
.build();
|
|
690
746
|
|
|
747
|
+
if (cameraSelector == null) {
|
|
748
|
+
cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA;
|
|
749
|
+
}
|
|
750
|
+
|
|
691
751
|
camera = cameraProvider.bindToLifecycle(
|
|
692
752
|
getActivity(),
|
|
693
753
|
cameraSelector,
|
|
@@ -695,9 +755,13 @@ public class CameraModulePlugin extends Plugin {
|
|
|
695
755
|
imageCapture,
|
|
696
756
|
imageAnalysis
|
|
697
757
|
);
|
|
758
|
+
|
|
759
|
+
call.resolve();
|
|
760
|
+
|
|
698
761
|
}
|
|
699
762
|
|
|
700
763
|
private void processBarcode(ImageProxy imageProxy) {
|
|
764
|
+
|
|
701
765
|
if (!isScanning) {
|
|
702
766
|
imageProxy.close();
|
|
703
767
|
return;
|
|
@@ -709,19 +773,26 @@ public class CameraModulePlugin extends Plugin {
|
|
|
709
773
|
return;
|
|
710
774
|
}
|
|
711
775
|
|
|
712
|
-
InputImage image =
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
);
|
|
717
|
-
|
|
718
|
-
BarcodeScanner scanner =
|
|
719
|
-
BarcodeScanning.getClient();
|
|
776
|
+
InputImage image = InputImage.fromMediaImage(
|
|
777
|
+
mediaImage,
|
|
778
|
+
imageProxy.getImageInfo().getRotationDegrees()
|
|
779
|
+
);
|
|
720
780
|
|
|
721
|
-
|
|
781
|
+
if (barcodeScanner == null) {
|
|
782
|
+
imageProxy.close();
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
785
|
+
barcodeScanner.process(image)
|
|
722
786
|
.addOnSuccessListener(barcodes -> {
|
|
723
|
-
if (!barcodes.isEmpty() && isScanning) {
|
|
724
787
|
|
|
788
|
+
if (!isScanning) {
|
|
789
|
+
imageProxy.close();
|
|
790
|
+
return;
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
if (!barcodes.isEmpty()) {
|
|
794
|
+
|
|
795
|
+
isScanning = false;
|
|
725
796
|
vibrateOnce();
|
|
726
797
|
|
|
727
798
|
Barcode barcode = barcodes.get(0);
|
|
@@ -730,36 +801,63 @@ public class CameraModulePlugin extends Plugin {
|
|
|
730
801
|
ret.put("rawValue", barcode.getRawValue());
|
|
731
802
|
ret.put("format", barcode.getFormat());
|
|
732
803
|
|
|
733
|
-
|
|
734
|
-
|
|
804
|
+
if (scanCall != null) {
|
|
805
|
+
scanCall.resolve(ret);
|
|
806
|
+
scanCall.setKeepAlive(false);
|
|
807
|
+
scanCall = null;
|
|
808
|
+
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
if (barcodeScanner != null) {
|
|
812
|
+
barcodeScanner.close();
|
|
813
|
+
barcodeScanner = null;
|
|
814
|
+
}
|
|
735
815
|
|
|
736
|
-
scanCall.resolve(ret);
|
|
737
|
-
scanCall = null;
|
|
738
816
|
|
|
739
817
|
stopBarcodeScanInternal();
|
|
740
|
-
} else {
|
|
741
|
-
imageProxy.close();
|
|
742
818
|
}
|
|
819
|
+
|
|
820
|
+
imageProxy.close();
|
|
743
821
|
})
|
|
744
822
|
.addOnFailureListener(e -> {
|
|
745
823
|
imageProxy.close();
|
|
746
824
|
});
|
|
747
825
|
}
|
|
748
826
|
|
|
827
|
+
|
|
749
828
|
private void stopBarcodeScanInternal() {
|
|
750
|
-
|
|
751
|
-
cameraProvider
|
|
752
|
-
|
|
753
|
-
|
|
829
|
+
getActivity().runOnUiThread(() -> {
|
|
830
|
+
if (cameraProvider != null) {
|
|
831
|
+
cameraProvider.unbindAll();
|
|
832
|
+
startCamera();
|
|
833
|
+
}
|
|
834
|
+
});
|
|
754
835
|
}
|
|
755
836
|
|
|
837
|
+
|
|
838
|
+
|
|
756
839
|
@PluginMethod
|
|
757
840
|
public void stopBarcodeScan(PluginCall call) {
|
|
758
841
|
isScanning = false;
|
|
842
|
+
imageAnalysis = null;
|
|
843
|
+
|
|
844
|
+
if (scanCall != null) {
|
|
845
|
+
scanCall.setKeepAlive(false);
|
|
846
|
+
scanCall = null;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
if (barcodeScanner != null) {
|
|
850
|
+
barcodeScanner.close();
|
|
851
|
+
barcodeScanner = null;
|
|
852
|
+
}
|
|
853
|
+
|
|
759
854
|
stopBarcodeScanInternal();
|
|
855
|
+
|
|
760
856
|
call.resolve();
|
|
761
857
|
}
|
|
762
858
|
|
|
859
|
+
|
|
860
|
+
|
|
763
861
|
private void vibrateOnce() {
|
|
764
862
|
Vibrator vibrator =
|
|
765
863
|
(Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
|