capacitor-community-multilens-camerapreview 7.1.0 → 7.1.2

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.
@@ -23,6 +23,10 @@ class CameraController: NSObject {
23
23
  var rearCamera: AVCaptureDevice?
24
24
  var rearCameraInput: AVCaptureDeviceInput?
25
25
 
26
+ var ultraWideCamera: AVCaptureDevice?
27
+ var wideAngleCamera: AVCaptureDevice?
28
+ var telephotoCamera: AVCaptureDevice?
29
+
26
30
  var previewLayer: AVCaptureVideoPreviewLayer?
27
31
 
28
32
  var flashMode = AVCaptureDevice.FlashMode.off
@@ -38,21 +42,14 @@ class CameraController: NSObject {
38
42
  var zoomFactor: CGFloat = 1.0
39
43
  }
40
44
  extension CameraController {
41
- func prepare(cameraPosition: String, zoomFactor: String, disableAudio: Bool, completionHandler: @escaping (Error?) -> Void) {
45
+ func prepare(cameraPosition: String, disableAudio: Bool, completionHandler: @escaping (Error?) -> Void) {
42
46
 
43
47
  func createCaptureSession() {
44
48
  self.captureSession = AVCaptureSession()
45
49
  }
46
50
 
47
51
  func configureCaptureDevices() throws {
48
- var session = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera,.builtInUltraWideCamera,.builtInTelephotoCamera], mediaType: AVMediaType.video, position: .unspecified)
49
- if(zoomFactor == "ultra"){
50
- session = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera,.builtInUltraWideCamera], mediaType: AVMediaType.video, position: .unspecified)
51
- } else if(zoomFactor == "wide"){
52
- session = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaType.video, position: .unspecified)
53
- } else if(zoomFactor == "tele"){
54
- session = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera,.builtInTelephotoCamera], mediaType: AVMediaType.video, position: .unspecified)
55
- }
52
+ let session = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera, .builtInUltraWideCamera, .builtInTelephotoCamera], mediaType: AVMediaType.video, position: .unspecified)
56
53
  let cameras = session.devices.compactMap { $0 }
57
54
  guard !cameras.isEmpty else { throw CameraControllerError.noCamerasAvailable }
58
55
 
@@ -62,11 +59,21 @@ extension CameraController {
62
59
  }
63
60
 
64
61
  if camera.position == .back {
65
- self.rearCamera = camera
62
+ switch camera.deviceType {
63
+ case .builtInWideAngleCamera:
64
+ self.wideAngleCamera = camera
65
+ case .builtInUltraWideCamera:
66
+ self.ultraWideCamera = camera
67
+ case .builtInTelephotoCamera:
68
+ self.telephotoCamera = camera
69
+ default:
70
+ break
71
+ }
72
+ self.rearCamera = camera // Keep a general rear camera reference
66
73
 
67
74
  try camera.lockForConfiguration()
68
75
  if camera.isFocusModeSupported(.continuousAutoFocus){
69
- camera.focusMode = .continuousAutoFocus
76
+ camera.focusMode = .continuousAutoFocus
70
77
  }
71
78
  camera.unlockForConfiguration()
72
79
  }
@@ -80,8 +87,8 @@ extension CameraController {
80
87
  guard let captureSession = self.captureSession else { throw CameraControllerError.captureSessionIsMissing }
81
88
 
82
89
  if cameraPosition == "rear" {
83
- if let rearCamera = self.rearCamera {
84
- self.rearCameraInput = try AVCaptureDeviceInput(device: rearCamera)
90
+ if let wideAngleCamera = self.wideAngleCamera {
91
+ self.rearCameraInput = try AVCaptureDeviceInput(device: wideAngleCamera)
85
92
 
86
93
  if captureSession.canAddInput(self.rearCameraInput!) { captureSession.addInput(self.rearCameraInput!) }
87
94
 
@@ -145,7 +152,6 @@ extension CameraController {
145
152
  try configureDeviceInputs()
146
153
  try configurePhotoOutput()
147
154
  try configureDataOutput()
148
- // try configureVideoOutput()
149
155
  } catch {
150
156
  DispatchQueue.main.async {
151
157
  completionHandler(error)
@@ -222,14 +228,22 @@ extension CameraController {
222
228
  }
223
229
 
224
230
  func switchCameras() throws {
225
- guard let currentCameraPosition = currentCameraPosition, let captureSession = self.captureSession, captureSession.isRunning else { throw CameraControllerError.captureSessionIsMissing }
231
+ guard let currentCameraPosition = currentCameraPosition, let captureSession = self.captureSession, captureSession.isRunning else {
232
+ throw CameraControllerError.captureSessionIsMissing
233
+ }
234
+
235
+ // Stop the capture session
236
+ captureSession.stopRunning()
226
237
 
227
238
  captureSession.beginConfiguration()
228
239
 
229
240
  func switchToFrontCamera() throws {
230
241
 
231
242
  guard let rearCameraInput = self.rearCameraInput, captureSession.inputs.contains(rearCameraInput),
232
- let frontCamera = self.frontCamera else { throw CameraControllerError.invalidOperation }
243
+ let frontCamera = self.frontCamera else {
244
+ captureSession.startRunning() // Restart before throwing
245
+ throw CameraControllerError.invalidOperation
246
+ }
233
247
 
234
248
  self.frontCameraInput = try AVCaptureDeviceInput(device: frontCamera)
235
249
 
@@ -240,6 +254,7 @@ extension CameraController {
240
254
 
241
255
  self.currentCameraPosition = .front
242
256
  } else {
257
+ captureSession.startRunning() // Restart before throwing
243
258
  throw CameraControllerError.invalidOperation
244
259
  }
245
260
  }
@@ -247,7 +262,10 @@ extension CameraController {
247
262
  func switchToRearCamera() throws {
248
263
 
249
264
  guard let frontCameraInput = self.frontCameraInput, captureSession.inputs.contains(frontCameraInput),
250
- let rearCamera = self.rearCamera else { throw CameraControllerError.invalidOperation }
265
+ let rearCamera = self.rearCamera else {
266
+ captureSession.startRunning() // Restart before throwing
267
+ throw CameraControllerError.invalidOperation
268
+ }
251
269
 
252
270
  self.rearCameraInput = try AVCaptureDeviceInput(device: rearCamera)
253
271
 
@@ -257,7 +275,10 @@ extension CameraController {
257
275
  captureSession.addInput(self.rearCameraInput!)
258
276
 
259
277
  self.currentCameraPosition = .rear
260
- } else { throw CameraControllerError.invalidOperation }
278
+ } else {
279
+ captureSession.startRunning() // Restart before throwing
280
+ throw CameraControllerError.invalidOperation
281
+ }
261
282
  }
262
283
 
263
284
  switch currentCameraPosition {
@@ -269,70 +290,85 @@ extension CameraController {
269
290
  }
270
291
 
271
292
  captureSession.commitConfiguration()
272
- }
273
- func setZoom(lens: String) throws {
274
- print(lens)
275
- guard let captureSession = self.captureSession, captureSession.isRunning else { throw CameraControllerError.captureSessionIsMissing }
276
293
 
277
- captureSession.beginConfiguration()
278
-
279
- guard let rearCameraInput = self.rearCameraInput, captureSession.inputs.contains(rearCameraInput) else { throw CameraControllerError.invalidOperation }
294
+ // Restart the capture session
295
+ captureSession.startRunning()
280
296
 
281
- var session = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera,.builtInUltraWideCamera,.builtInTelephotoCamera], mediaType: AVMediaType.video, position: .unspecified)
282
- if(lens == "ultra"){
283
- session = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera,.builtInUltraWideCamera], mediaType: AVMediaType.video, position: .unspecified)
284
- } else if(lens == "wide"){
285
- session = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaType.video, position: .unspecified)
286
- } else if(lens == "tele"){
287
- session = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera,.builtInTelephotoCamera], mediaType: AVMediaType.video, position: .unspecified)
288
- }
289
- let cameras = session.devices.compactMap { $0 }
290
- guard !cameras.isEmpty else { throw CameraControllerError.noCamerasAvailable }
297
+ updateVideoOrientation()
298
+ }
299
+ func setCameraLens(lens: String) throws {
300
+ guard let captureSession = self.captureSession, captureSession.isRunning else {
301
+ throw CameraControllerError.captureSessionIsMissing
302
+ }
291
303
 
292
- for camera in cameras {
293
- if camera.position == .front {
294
- self.frontCamera = camera
295
- }
304
+ guard self.currentCameraPosition == .rear else {
305
+ throw CameraControllerError.invalidOperation // Only allow lens switching for rear camera
306
+ }
296
307
 
297
- if camera.position == .back {
298
- self.rearCamera = camera
308
+ captureSession.stopRunning()
309
+ captureSession.beginConfiguration()
299
310
 
300
- try camera.lockForConfiguration()
301
- if camera.isFocusModeSupported(.continuousAutoFocus){
302
- camera.focusMode = .continuousAutoFocus
303
- }
304
- camera.unlockForConfiguration()
305
- }
306
- }
307
-
308
- if let inputs = captureSession.inputs as? [AVCaptureDeviceInput] {
309
- for input in inputs {
310
- captureSession.removeInput(input)
311
- }
311
+ // Remove existing rear camera input
312
+ if let currentRearInput = self.rearCameraInput {
313
+ captureSession.removeInput(currentRearInput)
314
+ self.rearCameraInput = nil
312
315
  }
313
- captureSession.commitConfiguration()
314
316
 
315
- self.rearCameraInput = try AVCaptureDeviceInput(device: rearCamera!)
317
+ var newRearCamera: AVCaptureDevice?
318
+ switch lens {
319
+ case "ultra":
320
+ newRearCamera = self.ultraWideCamera
321
+ case "wide":
322
+ newRearCamera = self.wideAngleCamera
323
+ case "tele":
324
+ newRearCamera = self.telephotoCamera
325
+ default:
326
+ newRearCamera = self.wideAngleCamera // Default to wide if unknown lens
327
+ }
316
328
 
317
- //captureSession.removeInput(frontCameraInput)
329
+ guard let camera = newRearCamera else {
330
+ captureSession.startRunning()
331
+ throw CameraControllerError.noCamerasAvailable
332
+ }
318
333
 
334
+ self.rearCameraInput = try AVCaptureDeviceInput(device: camera)
319
335
  if captureSession.canAddInput(self.rearCameraInput!) {
320
336
  captureSession.addInput(self.rearCameraInput!)
321
- self.currentCameraPosition = .rear
337
+ } else {
338
+ captureSession.startRunning()
339
+ throw CameraControllerError.inputsAreInvalid
322
340
  }
323
341
 
324
- do {
325
- guard let device = self.currentCameraPosition == .rear ? rearCamera : frontCamera else { return }
342
+ captureSession.commitConfiguration()
343
+ captureSession.startRunning()
344
+
345
+ updateVideoOrientation()
346
+ }
347
+
348
+ func setZoom(zoomFactor: CGFloat) throws {
349
+ guard let captureSession = self.captureSession, captureSession.isRunning else {
350
+ throw CameraControllerError.captureSessionIsMissing
351
+ }
352
+
353
+ guard let device = self.currentCameraPosition == .rear ? rearCameraInput?.device : frontCameraInput?.device else {
354
+ throw CameraControllerError.noCamerasAvailable
355
+ }
326
356
 
357
+ do {
327
358
  try device.lockForConfiguration()
328
359
  defer { device.unlockForConfiguration() }
329
-
330
- device.videoZoomFactor = 1.0
331
- zoomFactor = device.videoZoomFactor
332
360
 
361
+ let minZoomFactor: CGFloat = 1.0
362
+ let maxZoomFactor = device.activeFormat.videoMaxZoomFactor
363
+
364
+ device.videoZoomFactor = max(minZoomFactor, min(zoomFactor, maxZoomFactor))
365
+ self.zoomFactor = device.videoZoomFactor
333
366
  } catch {
334
367
  debugPrint(error)
368
+ throw CameraControllerError.invalidOperation
335
369
  }
370
+
371
+ updateVideoOrientation()
336
372
  }
337
373
 
338
374
  func captureImage(completion: @escaping (UIImage?, Error?) -> Void) {
@@ -22,7 +22,6 @@ public class CameraPreviewMultiLens: CAPPlugin {
22
22
  var enableZoom: Bool?
23
23
  var highResolutionOutput: Bool = false
24
24
  var disableAudio: Bool = false
25
- var zoomFactor = String()
26
25
 
27
26
  private func currentInterfaceOrientation() -> UIInterfaceOrientation? {
28
27
  if let window = self.webView?.window ?? self.bridge?.viewController?.view.window {
@@ -69,7 +68,7 @@ public class CameraPreviewMultiLens: CAPPlugin {
69
68
 
70
69
  @objc func start(_ call: CAPPluginCall) {
71
70
  self.cameraPosition = call.getString("position") ?? "rear"
72
- self.zoomFactor = call.getString("zoomFactor") ?? "wide"
71
+ let zoomFactor = call.getString("zoomFactor") ?? "wide"
73
72
  self.highResolutionOutput = call.getBool("enableHighResolution") ?? false
74
73
  self.cameraController.highResolutionOutput = self.highResolutionOutput
75
74
 
@@ -105,13 +104,21 @@ public class CameraPreviewMultiLens: CAPPlugin {
105
104
  if self.cameraController.captureSession?.isRunning ?? false {
106
105
  call.reject("camera already started")
107
106
  } else {
108
- self.cameraController.prepare(cameraPosition: self.cameraPosition, zoomFactor: self.zoomFactor, disableAudio: self.disableAudio){error in
107
+ self.cameraController.prepare(cameraPosition: self.cameraPosition, disableAudio: self.disableAudio, completionHandler: {error in
109
108
  if let error = error {
110
109
  print(error)
111
110
  call.reject(error.localizedDescription)
112
111
  return
113
112
  }
114
113
  let height = self.paddingBottom != nil ? self.height! - self.paddingBottom!: self.height!
114
+
115
+ // Set lens after camera is prepared
116
+ do {
117
+ try self.cameraController.setCameraLens(lens: zoomFactor)
118
+ } catch {
119
+ print("Failed to set initial lens: \(error)")
120
+ }
121
+
115
122
  self.previewView = UIView(frame: CGRect(x: self.x ?? 0, y: self.y ?? 0, width: self.width!, height: height))
116
123
  self.webView?.isOpaque = false
117
124
  self.webView?.backgroundColor = UIColor.clear
@@ -135,7 +142,7 @@ public class CameraPreviewMultiLens: CAPPlugin {
135
142
 
136
143
  call.resolve()
137
144
 
138
- }
145
+ })
139
146
  }
140
147
  }
141
148
  })
@@ -177,7 +184,7 @@ public class CameraPreviewMultiLens: CAPPlugin {
177
184
  @objc func capture(_ call: CAPPluginCall) {
178
185
  DispatchQueue.main.async {
179
186
 
180
- let quality: Int? = call.getInt("quality", 85)
187
+ let quality: Int = call.getInt("quality") ?? 85
181
188
 
182
189
  self.cameraController.captureImage { (image, error) in
183
190
 
@@ -193,9 +200,9 @@ public class CameraPreviewMultiLens: CAPPlugin {
193
200
  let imageData: Data?
194
201
  if self.cameraController.currentCameraPosition == .front {
195
202
  let flippedImage = image.withHorizontallyFlippedOrientation()
196
- imageData = flippedImage.jpegData(compressionQuality: CGFloat(quality!/100))
203
+ imageData = flippedImage.jpegData(compressionQuality: CGFloat(quality/100))
197
204
  } else {
198
- imageData = image.jpegData(compressionQuality: CGFloat(quality!/100))
205
+ imageData = image.jpegData(compressionQuality: CGFloat(quality/100))
199
206
  }
200
207
 
201
208
  if self.storeToFile == false {
@@ -216,7 +223,7 @@ public class CameraPreviewMultiLens: CAPPlugin {
216
223
 
217
224
  @objc func captureSample(_ call: CAPPluginCall) {
218
225
  DispatchQueue.main.async {
219
- let quality: Int? = call.getInt("quality", 85)
226
+ let quality: Int = call.getInt("quality") ?? 85
220
227
 
221
228
  self.cameraController.captureSample { image, error in
222
229
  guard let image = image else {
@@ -228,9 +235,9 @@ public class CameraPreviewMultiLens: CAPPlugin {
228
235
  let imageData: Data?
229
236
  if self.cameraController.currentCameraPosition == .front {
230
237
  let flippedImage = image.withHorizontallyFlippedOrientation()
231
- imageData = flippedImage.jpegData(compressionQuality: CGFloat(quality!/100))
238
+ imageData = flippedImage.jpegData(compressionQuality: CGFloat(quality/100))
232
239
  } else {
233
- imageData = image.jpegData(compressionQuality: CGFloat(quality!/100))
240
+ imageData = image.jpegData(compressionQuality: CGFloat(quality/100))
234
241
  }
235
242
 
236
243
  if self.storeToFile == false {
@@ -266,9 +273,9 @@ public class CameraPreviewMultiLens: CAPPlugin {
266
273
  }
267
274
  }
268
275
  @objc func setZoom(_ call: CAPPluginCall) {
269
- self.zoomFactor = call.getString("zoomFactor") ?? "wide"
276
+ let zoom = call.getDouble("zoomFactor") ?? 1.0
270
277
  do {
271
- try self.cameraController.setZoom(lens: self.zoomFactor)
278
+ try self.cameraController.setZoom(zoomFactor: CGFloat(zoom))
272
279
  call.resolve()
273
280
  } catch {
274
281
  call.reject("failed to set zoom")
@@ -307,8 +314,6 @@ public class CameraPreviewMultiLens: CAPPlugin {
307
314
  @objc func startRecordVideo(_ call: CAPPluginCall) {
308
315
  DispatchQueue.main.async {
309
316
 
310
- let _ = call.getInt("quality", 85)
311
-
312
317
  self.cameraController.captureVideo { (image, error) in
313
318
 
314
319
  guard let image = image else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "capacitor-community-multilens-camerapreview",
3
- "version": "7.1.0",
3
+ "version": "7.1.2",
4
4
  "description": "fork of capacitor community camera preview with support for switchting lenses",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",