capacitor-community-multilens-camerapreview 7.1.1 → 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 +70 -85
- 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)
|
|
@@ -287,103 +293,82 @@ extension CameraController {
|
|
|
287
293
|
|
|
288
294
|
// Restart the capture session
|
|
289
295
|
captureSession.startRunning()
|
|
296
|
+
|
|
297
|
+
updateVideoOrientation()
|
|
290
298
|
}
|
|
291
|
-
func
|
|
292
|
-
print(lens)
|
|
299
|
+
func setCameraLens(lens: String) throws {
|
|
293
300
|
guard let captureSession = self.captureSession, captureSession.isRunning else {
|
|
294
301
|
throw CameraControllerError.captureSessionIsMissing
|
|
295
302
|
}
|
|
296
|
-
|
|
297
|
-
|
|
303
|
+
|
|
304
|
+
guard self.currentCameraPosition == .rear else {
|
|
305
|
+
throw CameraControllerError.invalidOperation // Only allow lens switching for rear camera
|
|
306
|
+
}
|
|
307
|
+
|
|
298
308
|
captureSession.stopRunning()
|
|
299
|
-
|
|
300
309
|
captureSession.beginConfiguration()
|
|
301
310
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
311
|
+
// Remove existing rear camera input
|
|
312
|
+
if let currentRearInput = self.rearCameraInput {
|
|
313
|
+
captureSession.removeInput(currentRearInput)
|
|
314
|
+
self.rearCameraInput = nil
|
|
305
315
|
}
|
|
306
316
|
|
|
307
|
-
var
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
position: .unspecified
|
|
318
|
-
)
|
|
319
|
-
} else if lens == "wide" {
|
|
320
|
-
session = AVCaptureDevice.DiscoverySession(
|
|
321
|
-
deviceTypes: [.builtInWideAngleCamera],
|
|
322
|
-
mediaType: AVMediaType.video,
|
|
323
|
-
position: .unspecified
|
|
324
|
-
)
|
|
325
|
-
} else if lens == "tele" {
|
|
326
|
-
session = AVCaptureDevice.DiscoverySession(
|
|
327
|
-
deviceTypes: [.builtInWideAngleCamera, .builtInTelephotoCamera],
|
|
328
|
-
mediaType: AVMediaType.video,
|
|
329
|
-
position: .unspecified
|
|
330
|
-
)
|
|
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
|
|
331
327
|
}
|
|
332
|
-
|
|
333
|
-
let
|
|
334
|
-
|
|
335
|
-
captureSession.startRunning() // Restart before throwing
|
|
328
|
+
|
|
329
|
+
guard let camera = newRearCamera else {
|
|
330
|
+
captureSession.startRunning()
|
|
336
331
|
throw CameraControllerError.noCamerasAvailable
|
|
337
332
|
}
|
|
338
333
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
self.rearCamera = camera
|
|
346
|
-
|
|
347
|
-
try camera.lockForConfiguration()
|
|
348
|
-
if camera.isFocusModeSupported(.continuousAutoFocus) {
|
|
349
|
-
camera.focusMode = .continuousAutoFocus
|
|
350
|
-
}
|
|
351
|
-
camera.unlockForConfiguration()
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
if let inputs = captureSession.inputs as? [AVCaptureDeviceInput] {
|
|
356
|
-
for input in inputs {
|
|
357
|
-
captureSession.removeInput(input)
|
|
358
|
-
}
|
|
334
|
+
self.rearCameraInput = try AVCaptureDeviceInput(device: camera)
|
|
335
|
+
if captureSession.canAddInput(self.rearCameraInput!) {
|
|
336
|
+
captureSession.addInput(self.rearCameraInput!)
|
|
337
|
+
} else {
|
|
338
|
+
captureSession.startRunning()
|
|
339
|
+
throw CameraControllerError.inputsAreInvalid
|
|
359
340
|
}
|
|
341
|
+
|
|
360
342
|
captureSession.commitConfiguration()
|
|
343
|
+
captureSession.startRunning()
|
|
361
344
|
|
|
362
|
-
|
|
345
|
+
updateVideoOrientation()
|
|
346
|
+
}
|
|
363
347
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
348
|
+
func setZoom(zoomFactor: CGFloat) throws {
|
|
349
|
+
guard let captureSession = self.captureSession, captureSession.isRunning else {
|
|
350
|
+
throw CameraControllerError.captureSessionIsMissing
|
|
367
351
|
}
|
|
368
352
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
return
|
|
373
|
-
}
|
|
353
|
+
guard let device = self.currentCameraPosition == .rear ? rearCameraInput?.device : frontCameraInput?.device else {
|
|
354
|
+
throw CameraControllerError.noCamerasAvailable
|
|
355
|
+
}
|
|
374
356
|
|
|
357
|
+
do {
|
|
375
358
|
try device.lockForConfiguration()
|
|
376
359
|
defer { device.unlockForConfiguration() }
|
|
377
|
-
|
|
378
|
-
device.videoZoomFactor = 1.0
|
|
379
|
-
zoomFactor = device.videoZoomFactor
|
|
380
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
|
|
381
366
|
} catch {
|
|
382
367
|
debugPrint(error)
|
|
368
|
+
throw CameraControllerError.invalidOperation
|
|
383
369
|
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
captureSession.startRunning()
|
|
370
|
+
|
|
371
|
+
updateVideoOrientation()
|
|
387
372
|
}
|
|
388
373
|
|
|
389
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