capacitor-camera-module 0.0.33 → 0.0.35

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
  }
@@ -548,107 +578,63 @@ public class CameraModulePlugin extends Plugin {
548
578
  return;
549
579
  }
550
580
 
551
- imageCapture.takePicture(
552
- ContextCompat.getMainExecutor(getContext()),
553
- new ImageCapture.OnImageCapturedCallback() {
554
-
555
- @Override
556
- public void onCaptureSuccess(
557
- @NonNull ImageProxy image
558
- ) {
559
- try {
560
- Bitmap bitmap = imageProxyToBitmap(image);
561
- int rotation = image.getImageInfo().getRotationDegrees();
562
- bitmap = rotateBitmap(bitmap, rotation);
563
- image.close();
564
-
565
- Bitmap resized = resizeBitmap(bitmap, 1024);
566
-
567
- ByteArrayOutputStream outputStream =
568
- new ByteArrayOutputStream();
569
- resized.compress(
570
- Bitmap.CompressFormat.JPEG,
571
- 80,
572
- outputStream
573
- );
574
-
575
- byte[] bytes = outputStream.toByteArray();
576
- String base64 =
577
- Base64.encodeToString(bytes, Base64.NO_WRAP);
578
-
579
- bitmap.recycle();
580
- resized.recycle();
581
-
582
- JSObject ret = new JSObject();
583
- ret.put("base64", base64);
584
- ret.put("mimeType", "image/jpeg");
585
- call.resolve(ret);
586
-
587
- } catch (Exception e) {
588
- call.reject("Error capturing image", e);
581
+ try {
582
+ File photoFile = File.createTempFile(
583
+ "photo_",
584
+ ".jpg",
585
+ getContext().getCacheDir()
586
+ );
587
+
588
+ ImageCapture.OutputFileOptions options =
589
+ new ImageCapture.OutputFileOptions.Builder(photoFile).build();
590
+
591
+ imageCapture.takePicture(
592
+ options,
593
+ ContextCompat.getMainExecutor(getContext()),
594
+ new ImageCapture.OnImageSavedCallback() {
595
+
596
+ @Override
597
+ public void onImageSaved(
598
+ @NonNull ImageCapture.OutputFileResults output
599
+ ) {
600
+ try {
601
+ Bitmap bitmap = BitmapFactory.decodeFile(photoFile.getAbsolutePath());
602
+ Bitmap resized = resizeBitmap(bitmap, 1024);
603
+
604
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
605
+ resized.compress(Bitmap.CompressFormat.JPEG, 80, out);
606
+
607
+ String base64 = Base64.encodeToString(
608
+ out.toByteArray(),
609
+ Base64.NO_WRAP
610
+ );
611
+
612
+ bitmap.recycle();
613
+ resized.recycle();
614
+ photoFile.delete();
615
+
616
+ JSObject ret = new JSObject();
617
+ ret.put("base64", base64);
618
+ ret.put("mimeType", "image/jpeg");
619
+ call.resolve(ret);
620
+
621
+ } catch (Exception e) {
622
+ call.reject("Error processing image", e);
623
+ }
589
624
  }
590
- }
591
625
 
592
- @Override
593
- public void onError(
594
- @NonNull ImageCaptureException exception
595
- ) {
596
- call.reject("Capture failed", exception);
626
+ @Override
627
+ public void onError(@NonNull ImageCaptureException exception) {
628
+ call.reject("Capture failed", exception);
629
+ }
597
630
  }
598
- }
599
- );
600
- }
601
-
602
- 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);
607
-
608
- return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
609
- }
610
-
611
-
612
- private Bitmap rotateBitmap(Bitmap bitmap, int rotationDegrees) {
613
- if (rotationDegrees == 0) return bitmap;
614
-
615
- Matrix matrix = new Matrix();
616
- matrix.postRotate(rotationDegrees);
617
-
618
- return Bitmap.createBitmap(
619
- bitmap,
620
- 0,
621
- 0,
622
- bitmap.getWidth(),
623
- bitmap.getHeight(),
624
- matrix,
625
- true
626
- );
627
- }
628
-
629
-
630
-
631
- private Bitmap mirrorBitmap(Bitmap bitmap) {
632
- Matrix matrix = new Matrix();
633
- matrix.preScale(-1, 1);
631
+ );
634
632
 
635
- return Bitmap.createBitmap(
636
- bitmap,
637
- 0,
638
- 0,
639
- bitmap.getWidth(),
640
- bitmap.getHeight(),
641
- matrix,
642
- true
643
- );
633
+ } catch (Exception e) {
634
+ call.reject("Error creating file", e);
635
+ }
644
636
  }
645
637
 
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
638
 
653
639
  @PluginMethod
654
640
  public void startBarcodeScan(PluginCall call) {
@@ -673,6 +659,10 @@ public class CameraModulePlugin extends Plugin {
673
659
  return;
674
660
  }
675
661
 
662
+ barcodeScanner = BarcodeScanning.getClient();
663
+
664
+ call.setKeepAlive(true);
665
+
676
666
  scanCall = call;
677
667
  isScanning = true;
678
668
 
@@ -684,7 +674,7 @@ public class CameraModulePlugin extends Plugin {
684
674
  .build();
685
675
 
686
676
  imageAnalysis.setAnalyzer(
687
- ContextCompat.getMainExecutor(getContext()),
677
+ barcodeExecutor,
688
678
  this::processBarcode
689
679
  );
690
680
 
@@ -698,6 +688,10 @@ public class CameraModulePlugin extends Plugin {
698
688
  .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
699
689
  .build();
700
690
 
691
+ if (cameraSelector == null) {
692
+ cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA;
693
+ }
694
+
701
695
  camera = cameraProvider.bindToLifecycle(
702
696
  getActivity(),
703
697
  cameraSelector,
@@ -705,9 +699,13 @@ public class CameraModulePlugin extends Plugin {
705
699
  imageCapture,
706
700
  imageAnalysis
707
701
  );
702
+
703
+ call.resolve();
704
+
708
705
  }
709
706
 
710
707
  private void processBarcode(ImageProxy imageProxy) {
708
+
711
709
  if (!isScanning) {
712
710
  imageProxy.close();
713
711
  return;
@@ -719,19 +717,26 @@ public class CameraModulePlugin extends Plugin {
719
717
  return;
720
718
  }
721
719
 
722
- InputImage image =
723
- InputImage.fromMediaImage(
724
- mediaImage,
725
- imageProxy.getImageInfo().getRotationDegrees()
726
- );
727
-
728
- BarcodeScanner scanner =
729
- BarcodeScanning.getClient();
720
+ InputImage image = InputImage.fromMediaImage(
721
+ mediaImage,
722
+ imageProxy.getImageInfo().getRotationDegrees()
723
+ );
730
724
 
731
- scanner.process(image)
725
+ if (barcodeScanner == null) {
726
+ imageProxy.close();
727
+ return;
728
+ }
729
+ barcodeScanner.process(image)
732
730
  .addOnSuccessListener(barcodes -> {
733
- if (!barcodes.isEmpty() && isScanning) {
734
731
 
732
+ if (!isScanning) {
733
+ imageProxy.close();
734
+ return;
735
+ }
736
+
737
+ if (!barcodes.isEmpty()) {
738
+
739
+ isScanning = false;
735
740
  vibrateOnce();
736
741
 
737
742
  Barcode barcode = barcodes.get(0);
@@ -740,36 +745,63 @@ public class CameraModulePlugin extends Plugin {
740
745
  ret.put("rawValue", barcode.getRawValue());
741
746
  ret.put("format", barcode.getFormat());
742
747
 
743
- isScanning = false;
744
- imageProxy.close();
748
+ if (scanCall != null) {
749
+ scanCall.resolve(ret);
750
+ scanCall.setKeepAlive(false);
751
+ scanCall = null;
752
+
753
+ }
754
+
755
+ if (barcodeScanner != null) {
756
+ barcodeScanner.close();
757
+ barcodeScanner = null;
758
+ }
745
759
 
746
- scanCall.resolve(ret);
747
- scanCall = null;
748
760
 
749
761
  stopBarcodeScanInternal();
750
- } else {
751
- imageProxy.close();
752
762
  }
763
+
764
+ imageProxy.close();
753
765
  })
754
766
  .addOnFailureListener(e -> {
755
767
  imageProxy.close();
756
768
  });
757
769
  }
758
770
 
771
+
759
772
  private void stopBarcodeScanInternal() {
760
- if (imageAnalysis != null) {
761
- cameraProvider.unbind(imageAnalysis);
762
- imageAnalysis = null;
763
- }
773
+ getActivity().runOnUiThread(() -> {
774
+ if (cameraProvider != null) {
775
+ cameraProvider.unbindAll();
776
+ startCamera();
777
+ }
778
+ });
764
779
  }
765
780
 
781
+
782
+
766
783
  @PluginMethod
767
784
  public void stopBarcodeScan(PluginCall call) {
768
785
  isScanning = false;
786
+ imageAnalysis = null;
787
+
788
+ if (scanCall != null) {
789
+ scanCall.setKeepAlive(false);
790
+ scanCall = null;
791
+ }
792
+
793
+ if (barcodeScanner != null) {
794
+ barcodeScanner.close();
795
+ barcodeScanner = null;
796
+ }
797
+
769
798
  stopBarcodeScanInternal();
799
+
770
800
  call.resolve();
771
801
  }
772
802
 
803
+
804
+
773
805
  private void vibrateOnce() {
774
806
  Vibrator vibrator =
775
807
  (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
@@ -788,5 +820,28 @@ public class CameraModulePlugin extends Plugin {
788
820
  }
789
821
  }
790
822
 
823
+ private void restartNormalPreview() {
824
+ if (cameraProvider == null) return;
825
+
826
+ cameraProvider.unbindAll();
827
+
828
+ Preview preview = new Preview.Builder().build();
829
+ preview.setSurfaceProvider(previewView.getSurfaceProvider());
830
+
831
+ imageCapture = new ImageCapture.Builder()
832
+ .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
833
+ .build();
834
+
835
+ CameraSelector cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA;
836
+
837
+ cameraProvider.bindToLifecycle(
838
+ getActivity(),
839
+ cameraSelector,
840
+ preview,
841
+ imageCapture
842
+ );
843
+ }
844
+
845
+
791
846
 
792
847
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "capacitor-camera-module",
3
- "version": "0.0.33",
3
+ "version": "0.0.35",
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",