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
- cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA;
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) return bitmap;
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) return bitmap;
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
- ImageProxy.PlaneProxy[] planes = image.getPlanes();
604
- ByteBuffer buffer = planes[0].getBuffer();
605
- byte[] bytes = new byte[buffer.remaining()];
606
- buffer.get(bytes);
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
- return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
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
- ContextCompat.getMainExecutor(getContext()),
678
- image -> processBarcode(image)
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
- InputImage.fromMediaImage(
714
- mediaImage,
715
- imageProxy.getImageInfo().getRotationDegrees()
716
- );
717
-
718
- BarcodeScanner scanner =
719
- BarcodeScanning.getClient();
776
+ InputImage image = InputImage.fromMediaImage(
777
+ mediaImage,
778
+ imageProxy.getImageInfo().getRotationDegrees()
779
+ );
720
780
 
721
- scanner.process(image)
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
- isScanning = false;
734
- imageProxy.close();
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
- if (imageAnalysis != null) {
751
- cameraProvider.unbind(imageAnalysis);
752
- imageAnalysis = null;
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);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "capacitor-camera-module",
3
- "version": "0.0.32",
3
+ "version": "0.0.34",
4
4
  "description": "Plugin to request permissiones view camera take phots",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",