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.
- package/ios/Plugin/CameraController.swift +98 -62
- package/ios/Plugin/Plugin.swift +19 -14
- package/package.json +1 -1
|
@@ -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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
84
|
-
self.rearCameraInput = try AVCaptureDeviceInput(device:
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
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
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
}
|
|
304
|
+
guard self.currentCameraPosition == .rear else {
|
|
305
|
+
throw CameraControllerError.invalidOperation // Only allow lens switching for rear camera
|
|
306
|
+
}
|
|
296
307
|
|
|
297
|
-
|
|
298
|
-
|
|
308
|
+
captureSession.stopRunning()
|
|
309
|
+
captureSession.beginConfiguration()
|
|
299
310
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
337
|
+
} else {
|
|
338
|
+
captureSession.startRunning()
|
|
339
|
+
throw CameraControllerError.inputsAreInvalid
|
|
322
340
|
}
|
|
323
341
|
|
|
324
|
-
|
|
325
|
-
|
|
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) {
|
package/ios/Plugin/Plugin.swift
CHANGED
|
@@ -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
|
-
|
|
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,
|
|
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
|
|
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
|
|
203
|
+
imageData = flippedImage.jpegData(compressionQuality: CGFloat(quality/100))
|
|
197
204
|
} else {
|
|
198
|
-
imageData = image.jpegData(compressionQuality: CGFloat(quality
|
|
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
|
|
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
|
|
238
|
+
imageData = flippedImage.jpegData(compressionQuality: CGFloat(quality/100))
|
|
232
239
|
} else {
|
|
233
|
-
imageData = image.jpegData(compressionQuality: CGFloat(quality
|
|
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
|
-
|
|
276
|
+
let zoom = call.getDouble("zoomFactor") ?? 1.0
|
|
270
277
|
do {
|
|
271
|
-
try self.cameraController.setZoom(
|
|
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