capacitor-plugin-camera-forked 3.0.95 → 3.0.97

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.
@@ -542,7 +542,7 @@ public class CameraPreviewPlugin extends Plugin {
542
542
 
543
543
  } catch (Exception e) {
544
544
  e.printStackTrace();
545
- call.reject(e.getMessage());
545
+ call.resolve();
546
546
  }
547
547
  }
548
548
  call.resolve();
@@ -550,22 +550,34 @@ public class CameraPreviewPlugin extends Plugin {
550
550
 
551
551
  @PluginMethod
552
552
  public void setFocus(PluginCall call) {
553
+
554
+ JSObject response = new JSObject();
553
555
  if (!call.hasOption("x") || !call.hasOption("y")) {
554
- call.reject("Invalid focus coordinates - x and y are required");
556
+ response.put("success", false);
557
+ call.resolve(response);
555
558
  return;
556
559
  }
557
560
 
558
561
  Float x = call.getFloat("x");
559
562
  Float y = call.getFloat("y");
560
563
 
564
+ // Check for null values
565
+ if (x == null || y == null) {
566
+ response.put("success", false);
567
+ call.resolve(response);
568
+ return;
569
+ }
570
+
561
571
  // Validate coordinate ranges (should be 0-1 for normalized coordinates)
562
572
  if (x < 0.0f || x > 1.0f || y < 0.0f || y > 1.0f) {
563
- call.reject("Focus coordinates must be normalized values between 0.0 and 1.0");
573
+ response.put("success", false);
574
+ call.resolve(response);
564
575
  return;
565
576
  }
566
577
 
567
578
  if (previewView == null || camera == null) {
568
- call.reject("Camera preview is not initialized");
579
+ response.put("success", false);
580
+ call.resolve(response);
569
581
  return;
570
582
  }
571
583
 
@@ -634,7 +646,9 @@ public class CameraPreviewPlugin extends Plugin {
634
646
 
635
647
  } catch (Exception e) {
636
648
  Log.e("Camera", "Error setting focus", e);
637
- call.reject("Error setting focus: " + e.getMessage());
649
+ response.put("success", false);
650
+ response.put("error", e.getMessage());
651
+ call.resolve(response);
638
652
  }
639
653
  }
640
654
  });
@@ -33,9 +33,6 @@ public class CameraPreviewPlugin: CAPPlugin, AVCaptureVideoDataOutputSampleBuffe
33
33
  private let focusThrottleInterval: TimeInterval = 0.5
34
34
  var currentCameraDevice: AVCaptureDevice?
35
35
 
36
- // Simple focus management with fixed delay
37
- var continuousFocusReturnTimer: Timer?
38
-
39
36
  // Store the desired JPEG quality, set during initialization
40
37
  var desiredJpegQuality: CGFloat = 0.95 // Default to high quality (0.0-1.0)
41
38
 
@@ -379,21 +376,26 @@ public class CameraPreviewPlugin: CAPPlugin, AVCaptureVideoDataOutputSampleBuffe
379
376
 
380
377
  device.unlockForConfiguration()
381
378
 
379
+ if device.isAdjustingFocus {
382
380
  // Wait longer for focus to settle, especially for close objects
383
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
384
- self.photoOutput.capturePhoto(with: photoSettings, delegate: self)
385
-
386
- // Restore previous settings after capture
387
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.8) {
388
- do {
389
- try device.lockForConfiguration()
390
- device.focusMode = previousFocusMode
391
- device.exposureMode = previousExposureMode
392
- device.unlockForConfiguration()
393
- } catch {
394
- print("Could not restore camera settings: \(error)")
381
+ DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
382
+ self.photoOutput.capturePhoto(with: photoSettings, delegate: self)
383
+
384
+ // Restore previous settings after capture
385
+ DispatchQueue.main.asyncAfter(deadline: .now() + 0.8) {
386
+ do {
387
+ try device.lockForConfiguration()
388
+ device.focusMode = previousFocusMode
389
+ device.exposureMode = previousExposureMode
390
+ device.unlockForConfiguration()
391
+ } catch {
392
+ print("Could not restore camera settings: \(error)")
393
+ }
395
394
  }
396
395
  }
396
+ } else {
397
+ self.photoOutput.capturePhoto(with: photoSettings, delegate: self)
398
+
397
399
  }
398
400
  } catch {
399
401
  // If focus configuration fails, capture anyway
@@ -877,17 +879,51 @@ public class CameraPreviewPlugin: CAPPlugin, AVCaptureVideoDataOutputSampleBuffe
877
879
  x >= 0.0 && x <= 1.0, y >= 0.0 && y <= 1.0 {
878
880
  let point = CGPoint(x: CGFloat(x), y: CGFloat(y))
879
881
 
880
- // Simplified focus without complex throttling or maintenance
882
+ // Check if focus is currently animating and reset if stuck
883
+ if isFocusAnimating {
884
+ resetFocusIfStuck()
885
+ }
886
+
881
887
  focusWithPoint(point: point)
882
888
 
889
+ // Calculate the point in the preview layer's coordinate space
890
+ //let previewPoint = CGPoint(x: point.x * previewView.bounds.width,
891
+ // y: point.y * previewView.bounds.height)
892
+ // showFocusView(at: previewPoint)
883
893
  call.resolve()
884
894
  } else {
885
895
  call.reject("Invalid coordinates. Provide normalized x,y values (0.0-1.0)")
886
896
  }
887
897
  }
888
898
 
899
+ private func resetFocusIfStuck() {
900
+ DispatchQueue.main.async { [weak self] in
901
+ guard let self = self else { return }
902
+
903
+ // Remove any existing focus indicator
904
+ self.focusView?.removeFromSuperview()
905
+ self.focusCompletionTimer?.invalidate()
906
+ self.isFocusAnimating = false
907
+
908
+ // Reset focus to continuous mode
909
+ guard let videoInput = self.videoInput else { return }
910
+ let device = videoInput.device
911
+ do {
912
+ try device.lockForConfiguration()
913
+ if device.isFocusModeSupported(.continuousAutoFocus) {
914
+ device.focusMode = .continuousAutoFocus
915
+ }
916
+ device.unlockForConfiguration()
917
+ } catch {
918
+ print("Could not reset focus: \(error)")
919
+ }
920
+ }
921
+ }
922
+
889
923
  @objc func resetFocus(_ call: CAPPluginCall) {
890
- // Simple reset to center focus
924
+ resetFocusIfStuck()
925
+
926
+ // Reset to center focus
891
927
  let centerPoint = CGPoint(x: 0.5, y: 0.5)
892
928
  focusWithPoint(point: centerPoint)
893
929
 
@@ -899,57 +935,99 @@ public class CameraPreviewPlugin: CAPPlugin, AVCaptureVideoDataOutputSampleBuffe
899
935
  let convertedPoint = self.previewView.videoPreviewLayer.captureDevicePointConverted(fromLayerPoint: location)
900
936
 
901
937
  focusWithPoint(point: convertedPoint)
938
+ // showFocusView(at: location)
902
939
  }
903
940
 
904
941
  func focusWithPoint(point: CGPoint) {
905
942
  guard let videoInput = self.videoInput else { return }
906
943
  let device = videoInput.device
907
944
 
945
+ let now = Date()
946
+ if now.timeIntervalSince(lastFocusTime) < focusThrottleInterval {
947
+ return
948
+ }
949
+ lastFocusTime = now
950
+
908
951
  do {
909
952
  try device.lockForConfiguration()
910
953
 
911
- // Cancel any existing focus/exposure operations
912
- if device.isFocusModeSupported(.autoFocus) && device.isFocusPointOfInterestSupported {
954
+ focusCompletionTimer?.invalidate()
955
+
956
+ if device.isFocusPointOfInterestSupported {
913
957
  device.focusPointOfInterest = point
914
- device.focusMode = .autoFocus
958
+
959
+ // Use autoFocus for more aggressive focusing on specific points
960
+ if device.isFocusModeSupported(.autoFocus) {
961
+ device.focusMode = .autoFocus
962
+
963
+ // Set up observer for focus completion
964
+ NotificationCenter.default.addObserver(
965
+ self,
966
+ selector: #selector(subjectAreaDidChange),
967
+ name: .AVCaptureDeviceSubjectAreaDidChange,
968
+ object: device
969
+ )
970
+ } else if device.isFocusModeSupported(.continuousAutoFocus) {
971
+ device.focusMode = .continuousAutoFocus
972
+ }
915
973
  }
916
974
 
917
- if device.isExposureModeSupported(.autoExpose) && device.isExposurePointOfInterestSupported {
975
+ if device.isExposurePointOfInterestSupported {
918
976
  device.exposurePointOfInterest = point
919
- device.exposureMode = .autoExpose
977
+
978
+ // Use autoExpose for specific point exposure
979
+ if device.isExposureModeSupported(.autoExpose) {
980
+ device.exposureMode = .autoExpose
981
+ } else if device.isExposureModeSupported(.continuousAutoExposure) {
982
+ device.exposureMode = .continuousAutoExposure
983
+ }
920
984
  }
921
985
 
922
- // Ensure full focus range is available
986
+ // Ensure full focus range is available for close objects
923
987
  if device.isAutoFocusRangeRestrictionSupported {
924
988
  device.autoFocusRangeRestriction = .none
925
989
  }
926
990
 
927
- device.unlockForConfiguration()
991
+ device.isSubjectAreaChangeMonitoringEnabled = true
928
992
 
929
- // Cancel any existing timer
930
- continuousFocusReturnTimer?.invalidate()
993
+ device.unlockForConfiguration()
931
994
 
932
- // Return to continuous focus after fixed delay
933
- // This provides predictable behavior - user has 2 seconds to take photo after tap-to-focus
934
- continuousFocusReturnTimer = Timer.scheduledTimer(withTimeInterval: 2.0, repeats: false) { [weak self] _ in
995
+ // Switch back to continuous focus after a delay to maintain automatic focus
996
+ DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in
935
997
  self?.returnToContinuousFocus()
936
998
  }
937
999
 
1000
+ // focusCompletionTimer = Timer.scheduledTimer(withTimeInterval: 2.0, repeats: false) { [weak self] _ in
1001
+ // DispatchQueue.main.async {
1002
+ // self?.hideFocusIndicatorWithCompletion()
1003
+ // }
1004
+ // }
1005
+
938
1006
  } catch {
939
1007
  print("Could not focus: \(error.localizedDescription)")
940
1008
  }
941
1009
  }
942
1010
 
1011
+ // @objc private func subjectAreaDidChange(notification: NSNotification) {
1012
+ // DispatchQueue.main.async { [weak self] in
1013
+ // self?.hideFocusIndicatorWithCompletion()
1014
+ // }
1015
+
1016
+ // NotificationCenter.default.removeObserver(self, name: .AVCaptureDeviceSubjectAreaDidChange, object: notification.object)
1017
+ // }
1018
+
943
1019
  private func returnToContinuousFocus() {
944
1020
  guard let videoInput = self.videoInput else { return }
945
1021
  let device = videoInput.device
946
1022
  do {
947
1023
  try device.lockForConfiguration()
948
1024
 
1025
+ // Return to continuous auto focus for automatic operation
949
1026
  if device.isFocusModeSupported(.continuousAutoFocus) {
950
1027
  device.focusMode = .continuousAutoFocus
951
1028
  }
952
1029
 
1030
+ // Return to continuous auto exposure
953
1031
  if device.isExposureModeSupported(.continuousAutoExposure) {
954
1032
  device.exposureMode = .continuousAutoExposure
955
1033
  }
@@ -960,6 +1038,22 @@ public class CameraPreviewPlugin: CAPPlugin, AVCaptureVideoDataOutputSampleBuffe
960
1038
  }
961
1039
  }
962
1040
 
1041
+
1042
+
1043
+ // private func hideFocusIndicatorWithCompletion() {
1044
+ // DispatchQueue.main.async { [weak self] in
1045
+ // guard let self = self, let focusView = self.focusView else { return }
1046
+
1047
+ // UIView.animate(withDuration: 0.2, animations: {
1048
+ // focusView.alpha = 0.0
1049
+ // focusView.transform = CGAffineTransform(scaleX: 0.8, y: 0.8)
1050
+ // }) { _ in
1051
+ // focusView.removeFromSuperview()
1052
+ // focusView.transform = CGAffineTransform.identity
1053
+ // self.isFocusAnimating = false
1054
+ // }
1055
+ // }
1056
+ // }
963
1057
  @objc func requestCameraPermission(_ call: CAPPluginCall) {
964
1058
  AVCaptureDevice.requestAccess(for: .video) { granted in
965
1059
  DispatchQueue.main.async {
@@ -1075,59 +1169,14 @@ public class CameraPreviewPlugin: CAPPlugin, AVCaptureVideoDataOutputSampleBuffe
1075
1169
  }
1076
1170
 
1077
1171
  @objc func takePhoto(_ call: CAPPluginCall) {
1172
+ call.keepAlive = true
1078
1173
  takePhotoCall = call
1079
-
1080
- // Configure photo settings
1081
- let photoSettings = AVCapturePhotoSettings()
1082
- photoSettings.isHighResolutionPhotoEnabled = true
1083
-
1084
- // Use JPEG format with quality setting
1085
- if #available(iOS 11.0, *) {
1086
- photoSettings.photoQualityPrioritization = .quality
1087
- }
1088
-
1089
- // Configure for optimal photo capture without complex focus management
1090
- guard let device = videoInput?.device else {
1091
- self.photoOutput.capturePhoto(with: photoSettings, delegate: self)
1092
- return
1093
- }
1094
-
1095
- if device.isFocusModeSupported(.autoFocus) {
1096
- do {
1097
- try device.lockForConfiguration()
1098
-
1099
- // Set to auto focus for capture
1100
- device.focusMode = .autoFocus
1101
-
1102
- // Ensure full focus range
1103
- if device.isAutoFocusRangeRestrictionSupported {
1104
- device.autoFocusRangeRestriction = .none
1105
- }
1106
-
1107
- // Set exposure for photo
1108
- if device.isExposureModeSupported(.autoExpose) {
1109
- device.exposureMode = .autoExpose
1110
- }
1111
-
1112
- device.unlockForConfiguration()
1113
-
1114
- // Wait briefly for focus, then capture
1115
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
1116
- self.photoOutput.capturePhoto(with: photoSettings, delegate: self)
1117
- }
1118
- } catch {
1119
- print("Could not configure focus for capture: \(error)")
1120
- self.photoOutput.capturePhoto(with: photoSettings, delegate: self)
1121
- }
1122
- } else {
1123
- // Capture immediately if auto focus isn't supported
1124
- self.photoOutput.capturePhoto(with: photoSettings, delegate: self)
1125
- }
1174
+ takePhotoWithAVFoundation()
1126
1175
  }
1127
1176
 
1128
1177
  deinit {
1178
+ NotificationCenter.default.removeObserver(self)
1129
1179
  focusCompletionTimer?.invalidate()
1130
- continuousFocusReturnTimer?.invalidate()
1131
1180
  }
1132
1181
 
1133
1182
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "capacitor-plugin-camera-forked",
3
- "version": "3.0.95",
3
+ "version": "3.0.97",
4
4
  "description": "A capacitor camera plugin - A custom Capacitor camera plugin with additional features.",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",