@capacitor-community/camera-preview 2.1.0 → 3.1.1
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/README.md +14 -3
- package/android/build.gradle +15 -10
- package/android/src/androidTest/java/com/getcapacitor/android/ExampleInstrumentedTest.java +3 -3
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CameraActivity.java +835 -799
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CameraPreview.java +184 -173
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CustomSurfaceView.java +12 -14
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CustomTextureView.java +16 -18
- package/android/src/main/java/com/ahm/capacitor/camera/preview/Preview.java +327 -323
- package/android/src/main/java/com/ahm/capacitor/camera/preview/TapGestureDetector.java +15 -14
- package/android/src/test/java/com/getcapacitor/ExampleUnitTest.java +4 -3
- package/dist/esm/definitions.d.ts +10 -8
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/web.d.ts +3 -3
- package/dist/esm/web.js +36 -25
- package/dist/esm/web.js.map +1 -1
- package/ios/Plugin/CameraController.swift +107 -129
- package/ios/Plugin/Plugin.swift +76 -90
- package/ios/PluginTests/PluginTests.swift +8 -8
- package/package.json +27 -2
|
@@ -11,20 +11,20 @@ import UIKit
|
|
|
11
11
|
|
|
12
12
|
class CameraController: NSObject {
|
|
13
13
|
var captureSession: AVCaptureSession?
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
var currentCameraPosition: CameraPosition?
|
|
16
|
-
|
|
16
|
+
|
|
17
17
|
var frontCamera: AVCaptureDevice?
|
|
18
18
|
var frontCameraInput: AVCaptureDeviceInput?
|
|
19
|
-
|
|
19
|
+
|
|
20
20
|
var dataOutput: AVCaptureVideoDataOutput?
|
|
21
21
|
var photoOutput: AVCapturePhotoOutput?
|
|
22
|
-
|
|
22
|
+
|
|
23
23
|
var rearCamera: AVCaptureDevice?
|
|
24
24
|
var rearCameraInput: AVCaptureDeviceInput?
|
|
25
|
-
|
|
25
|
+
|
|
26
26
|
var previewLayer: AVCaptureVideoPreviewLayer?
|
|
27
|
-
|
|
27
|
+
|
|
28
28
|
var flashMode = AVCaptureDevice.FlashMode.off
|
|
29
29
|
var photoCaptureCompletionBlock: ((UIImage?, Error?) -> Void)?
|
|
30
30
|
|
|
@@ -34,12 +34,12 @@ class CameraController: NSObject {
|
|
|
34
34
|
|
|
35
35
|
var audioDevice: AVCaptureDevice?
|
|
36
36
|
var audioInput: AVCaptureDeviceInput?
|
|
37
|
-
|
|
37
|
+
|
|
38
38
|
var zoomFactor: CGFloat = 1.0
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
extension CameraController {
|
|
42
|
-
func prepare(cameraPosition: String, completionHandler: @escaping (Error?) -> Void) {
|
|
42
|
+
func prepare(cameraPosition: String, disableAudio: Bool, completionHandler: @escaping (Error?) -> Void) {
|
|
43
43
|
func createCaptureSession() {
|
|
44
44
|
self.captureSession = AVCaptureSession()
|
|
45
45
|
}
|
|
@@ -64,7 +64,9 @@ extension CameraController {
|
|
|
64
64
|
camera.unlockForConfiguration()
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
|
-
|
|
67
|
+
if disableAudio == false {
|
|
68
|
+
self.audioDevice = AVCaptureDevice.default(for: AVMediaType.audio)
|
|
69
|
+
}
|
|
68
70
|
}
|
|
69
71
|
|
|
70
72
|
func configureDeviceInputs() throws {
|
|
@@ -82,20 +84,21 @@ extension CameraController {
|
|
|
82
84
|
if let frontCamera = self.frontCamera {
|
|
83
85
|
self.frontCameraInput = try AVCaptureDeviceInput(device: frontCamera)
|
|
84
86
|
|
|
85
|
-
if captureSession.canAddInput(self.frontCameraInput!) { captureSession.addInput(self.frontCameraInput!) }
|
|
86
|
-
else { throw CameraControllerError.inputsAreInvalid }
|
|
87
|
+
if captureSession.canAddInput(self.frontCameraInput!) { captureSession.addInput(self.frontCameraInput!) } else { throw CameraControllerError.inputsAreInvalid }
|
|
87
88
|
|
|
88
89
|
self.currentCameraPosition = .front
|
|
89
90
|
}
|
|
90
91
|
} else { throw CameraControllerError.noCamerasAvailable }
|
|
91
92
|
|
|
92
93
|
// Add audio input
|
|
93
|
-
if
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
captureSession.
|
|
97
|
-
|
|
98
|
-
|
|
94
|
+
if disableAudio == false {
|
|
95
|
+
if let audioDevice = self.audioDevice {
|
|
96
|
+
self.audioInput = try AVCaptureDeviceInput(device: audioDevice)
|
|
97
|
+
if captureSession.canAddInput(self.audioInput!) {
|
|
98
|
+
captureSession.addInput(self.audioInput!)
|
|
99
|
+
} else {
|
|
100
|
+
throw CameraControllerError.inputsAreInvalid
|
|
101
|
+
}
|
|
99
102
|
}
|
|
100
103
|
}
|
|
101
104
|
}
|
|
@@ -104,7 +107,7 @@ extension CameraController {
|
|
|
104
107
|
guard let captureSession = self.captureSession else { throw CameraControllerError.captureSessionIsMissing }
|
|
105
108
|
|
|
106
109
|
self.photoOutput = AVCapturePhotoOutput()
|
|
107
|
-
self.photoOutput!.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format: [AVVideoCodecKey
|
|
110
|
+
self.photoOutput!.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.jpeg])], completionHandler: nil)
|
|
108
111
|
self.photoOutput?.isHighResolutionCaptureEnabled = self.highResolutionOutput
|
|
109
112
|
if captureSession.canAddOutput(self.photoOutput!) { captureSession.addOutput(self.photoOutput!) }
|
|
110
113
|
captureSession.startRunning()
|
|
@@ -135,10 +138,8 @@ extension CameraController {
|
|
|
135
138
|
try configureDeviceInputs()
|
|
136
139
|
try configurePhotoOutput()
|
|
137
140
|
try configureDataOutput()
|
|
138
|
-
//try configureVideoOutput()
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
catch {
|
|
141
|
+
// try configureVideoOutput()
|
|
142
|
+
} catch {
|
|
142
143
|
DispatchQueue.main.async {
|
|
143
144
|
completionHandler(error)
|
|
144
145
|
}
|
|
@@ -147,8 +148,6 @@ extension CameraController {
|
|
|
147
148
|
}
|
|
148
149
|
|
|
149
150
|
DispatchQueue.main.async {
|
|
150
|
-
self.updateVideoOrientation()
|
|
151
|
-
|
|
152
151
|
completionHandler(nil)
|
|
153
152
|
}
|
|
154
153
|
}
|
|
@@ -162,21 +161,23 @@ extension CameraController {
|
|
|
162
161
|
|
|
163
162
|
view.layer.insertSublayer(self.previewLayer!, at: 0)
|
|
164
163
|
self.previewLayer?.frame = view.frame
|
|
164
|
+
|
|
165
|
+
updateVideoOrientation()
|
|
165
166
|
}
|
|
166
167
|
|
|
167
168
|
func setupGestures(target: UIView, enableZoom: Bool) {
|
|
168
169
|
setupTapGesture(target: target, selector: #selector(handleTap(_:)), delegate: self)
|
|
169
|
-
if
|
|
170
|
+
if enableZoom {
|
|
170
171
|
setupPinchGesture(target: target, selector: #selector(handlePinch(_:)), delegate: self)
|
|
171
172
|
}
|
|
172
173
|
}
|
|
173
|
-
|
|
174
|
+
|
|
174
175
|
func setupTapGesture(target: UIView, selector: Selector, delegate: UIGestureRecognizerDelegate?) {
|
|
175
176
|
let tapGesture = UITapGestureRecognizer(target: self, action: selector)
|
|
176
177
|
tapGesture.delegate = delegate
|
|
177
178
|
target.addGestureRecognizer(tapGesture)
|
|
178
179
|
}
|
|
179
|
-
|
|
180
|
+
|
|
180
181
|
func setupPinchGesture(target: UIView, selector: Selector, delegate: UIGestureRecognizerDelegate?) {
|
|
181
182
|
let pinchGesture = UIPinchGestureRecognizer(target: self, action: selector)
|
|
182
183
|
pinchGesture.delegate = delegate
|
|
@@ -187,36 +188,24 @@ extension CameraController {
|
|
|
187
188
|
assert(Thread.isMainThread) // UIApplication.statusBarOrientation requires the main thread.
|
|
188
189
|
|
|
189
190
|
let videoOrientation: AVCaptureVideoOrientation
|
|
190
|
-
switch
|
|
191
|
+
switch UIApplication.shared.statusBarOrientation {
|
|
191
192
|
case .portrait:
|
|
192
193
|
videoOrientation = .portrait
|
|
193
194
|
case .landscapeLeft:
|
|
194
|
-
videoOrientation = .landscapeRight
|
|
195
|
-
case .landscapeRight:
|
|
196
195
|
videoOrientation = .landscapeLeft
|
|
196
|
+
case .landscapeRight:
|
|
197
|
+
videoOrientation = .landscapeRight
|
|
197
198
|
case .portraitUpsideDown:
|
|
198
199
|
videoOrientation = .portraitUpsideDown
|
|
199
|
-
case .
|
|
200
|
+
case .unknown:
|
|
200
201
|
fallthrough
|
|
201
202
|
@unknown default:
|
|
202
|
-
|
|
203
|
-
case .portrait:
|
|
204
|
-
videoOrientation = .portrait
|
|
205
|
-
case .landscapeLeft:
|
|
206
|
-
videoOrientation = .landscapeLeft
|
|
207
|
-
case .landscapeRight:
|
|
208
|
-
videoOrientation = .landscapeRight
|
|
209
|
-
case .portraitUpsideDown:
|
|
210
|
-
videoOrientation = .portraitUpsideDown
|
|
211
|
-
case .unknown:
|
|
212
|
-
fallthrough
|
|
213
|
-
@unknown default:
|
|
214
|
-
videoOrientation = .portrait
|
|
215
|
-
}
|
|
203
|
+
videoOrientation = .portrait
|
|
216
204
|
}
|
|
217
205
|
|
|
218
206
|
previewLayer?.connection?.videoOrientation = videoOrientation
|
|
219
207
|
dataOutput?.connections.forEach { $0.videoOrientation = videoOrientation }
|
|
208
|
+
photoOutput?.connections.forEach { $0.videoOrientation = videoOrientation }
|
|
220
209
|
}
|
|
221
210
|
|
|
222
211
|
func switchCameras() throws {
|
|
@@ -227,7 +216,7 @@ extension CameraController {
|
|
|
227
216
|
func switchToFrontCamera() throws {
|
|
228
217
|
|
|
229
218
|
guard let rearCameraInput = self.rearCameraInput, captureSession.inputs.contains(rearCameraInput),
|
|
230
|
-
|
|
219
|
+
let frontCamera = self.frontCamera else { throw CameraControllerError.invalidOperation }
|
|
231
220
|
|
|
232
221
|
self.frontCameraInput = try AVCaptureDeviceInput(device: frontCamera)
|
|
233
222
|
|
|
@@ -237,9 +226,7 @@ extension CameraController {
|
|
|
237
226
|
captureSession.addInput(self.frontCameraInput!)
|
|
238
227
|
|
|
239
228
|
self.currentCameraPosition = .front
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
else {
|
|
229
|
+
} else {
|
|
243
230
|
throw CameraControllerError.invalidOperation
|
|
244
231
|
}
|
|
245
232
|
}
|
|
@@ -247,7 +234,7 @@ extension CameraController {
|
|
|
247
234
|
func switchToRearCamera() throws {
|
|
248
235
|
|
|
249
236
|
guard let frontCameraInput = self.frontCameraInput, captureSession.inputs.contains(frontCameraInput),
|
|
250
|
-
|
|
237
|
+
let rearCamera = self.rearCamera else { throw CameraControllerError.invalidOperation }
|
|
251
238
|
|
|
252
239
|
self.rearCameraInput = try AVCaptureDeviceInput(device: rearCamera)
|
|
253
240
|
|
|
@@ -257,9 +244,7 @@ extension CameraController {
|
|
|
257
244
|
captureSession.addInput(self.rearCameraInput!)
|
|
258
245
|
|
|
259
246
|
self.currentCameraPosition = .rear
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
else { throw CameraControllerError.invalidOperation }
|
|
247
|
+
} else { throw CameraControllerError.invalidOperation }
|
|
263
248
|
}
|
|
264
249
|
|
|
265
250
|
switch currentCameraPosition {
|
|
@@ -278,7 +263,7 @@ extension CameraController {
|
|
|
278
263
|
let settings = AVCapturePhotoSettings()
|
|
279
264
|
|
|
280
265
|
settings.flashMode = self.flashMode
|
|
281
|
-
settings.isHighResolutionPhotoEnabled = self.highResolutionOutput
|
|
266
|
+
settings.isHighResolutionPhotoEnabled = self.highResolutionOutput
|
|
282
267
|
|
|
283
268
|
self.photoOutput?.capturePhoto(with: settings, delegate: self)
|
|
284
269
|
self.photoCaptureCompletionBlock = completion
|
|
@@ -293,23 +278,23 @@ extension CameraController {
|
|
|
293
278
|
|
|
294
279
|
self.sampleBufferCaptureCompletionBlock = completion
|
|
295
280
|
}
|
|
296
|
-
|
|
281
|
+
|
|
297
282
|
func getSupportedFlashModes() throws -> [String] {
|
|
298
283
|
var currentCamera: AVCaptureDevice?
|
|
299
284
|
switch currentCameraPosition {
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
285
|
+
case .front:
|
|
286
|
+
currentCamera = self.frontCamera!
|
|
287
|
+
case .rear:
|
|
288
|
+
currentCamera = self.rearCamera!
|
|
289
|
+
default: break
|
|
305
290
|
}
|
|
306
|
-
|
|
291
|
+
|
|
307
292
|
guard
|
|
308
293
|
let device = currentCamera
|
|
309
294
|
else {
|
|
310
295
|
throw CameraControllerError.noCamerasAvailable
|
|
311
296
|
}
|
|
312
|
-
|
|
297
|
+
|
|
313
298
|
var supportedFlashModesAsStrings: [String] = []
|
|
314
299
|
if device.hasFlash {
|
|
315
300
|
guard let supportedFlashModes: [AVCaptureDevice.FlashMode] = self.photoOutput?.supportedFlashModes else {
|
|
@@ -319,13 +304,13 @@ extension CameraController {
|
|
|
319
304
|
for flashMode in supportedFlashModes {
|
|
320
305
|
var flashModeValue: String?
|
|
321
306
|
switch flashMode {
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
307
|
+
case AVCaptureDevice.FlashMode.off:
|
|
308
|
+
flashModeValue = "off"
|
|
309
|
+
case AVCaptureDevice.FlashMode.on:
|
|
310
|
+
flashModeValue = "on"
|
|
311
|
+
case AVCaptureDevice.FlashMode.auto:
|
|
312
|
+
flashModeValue = "auto"
|
|
313
|
+
default: break
|
|
329
314
|
}
|
|
330
315
|
if flashModeValue != nil {
|
|
331
316
|
supportedFlashModesAsStrings.append(flashModeValue!)
|
|
@@ -336,38 +321,38 @@ extension CameraController {
|
|
|
336
321
|
supportedFlashModesAsStrings.append("torch")
|
|
337
322
|
}
|
|
338
323
|
return supportedFlashModesAsStrings
|
|
339
|
-
|
|
324
|
+
|
|
340
325
|
}
|
|
341
|
-
|
|
326
|
+
|
|
342
327
|
func setFlashMode(flashMode: AVCaptureDevice.FlashMode) throws {
|
|
343
328
|
var currentCamera: AVCaptureDevice?
|
|
344
329
|
switch currentCameraPosition {
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
330
|
+
case .front:
|
|
331
|
+
currentCamera = self.frontCamera!
|
|
332
|
+
case .rear:
|
|
333
|
+
currentCamera = self.rearCamera!
|
|
334
|
+
default: break
|
|
350
335
|
}
|
|
351
|
-
|
|
336
|
+
|
|
352
337
|
guard let device = currentCamera else {
|
|
353
338
|
throw CameraControllerError.noCamerasAvailable
|
|
354
339
|
}
|
|
355
|
-
|
|
340
|
+
|
|
356
341
|
guard let supportedFlashModes: [AVCaptureDevice.FlashMode] = self.photoOutput?.supportedFlashModes else {
|
|
357
342
|
throw CameraControllerError.invalidOperation
|
|
358
343
|
}
|
|
359
344
|
if supportedFlashModes.contains(flashMode) {
|
|
360
345
|
do {
|
|
361
346
|
try device.lockForConfiguration()
|
|
362
|
-
|
|
363
|
-
if
|
|
347
|
+
|
|
348
|
+
if device.hasTorch && device.isTorchAvailable && device.torchMode == AVCaptureDevice.TorchMode.on {
|
|
364
349
|
device.torchMode = AVCaptureDevice.TorchMode.off
|
|
365
350
|
}
|
|
366
351
|
self.flashMode = flashMode
|
|
367
352
|
let photoSettings = AVCapturePhotoSettings()
|
|
368
353
|
photoSettings.flashMode = flashMode
|
|
369
354
|
self.photoOutput?.photoSettingsForSceneMonitoring = photoSettings
|
|
370
|
-
|
|
355
|
+
|
|
371
356
|
device.unlockForConfiguration()
|
|
372
357
|
} catch {
|
|
373
358
|
throw CameraControllerError.invalidOperation
|
|
@@ -376,17 +361,17 @@ extension CameraController {
|
|
|
376
361
|
throw CameraControllerError.invalidOperation
|
|
377
362
|
}
|
|
378
363
|
}
|
|
379
|
-
|
|
364
|
+
|
|
380
365
|
func setTorchMode() throws {
|
|
381
366
|
var currentCamera: AVCaptureDevice?
|
|
382
367
|
switch currentCameraPosition {
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
368
|
+
case .front:
|
|
369
|
+
currentCamera = self.frontCamera!
|
|
370
|
+
case .rear:
|
|
371
|
+
currentCamera = self.rearCamera!
|
|
372
|
+
default: break
|
|
388
373
|
}
|
|
389
|
-
|
|
374
|
+
|
|
390
375
|
guard
|
|
391
376
|
let device = currentCamera,
|
|
392
377
|
device.hasTorch,
|
|
@@ -397,9 +382,9 @@ extension CameraController {
|
|
|
397
382
|
|
|
398
383
|
do {
|
|
399
384
|
try device.lockForConfiguration()
|
|
400
|
-
if
|
|
385
|
+
if device.isTorchModeSupported(AVCaptureDevice.TorchMode.on) {
|
|
401
386
|
device.torchMode = AVCaptureDevice.TorchMode.on
|
|
402
|
-
} else if
|
|
387
|
+
} else if device.isTorchModeSupported(AVCaptureDevice.TorchMode.auto) {
|
|
403
388
|
device.torchMode = AVCaptureDevice.TorchMode.auto
|
|
404
389
|
} else {
|
|
405
390
|
device.torchMode = AVCaptureDevice.TorchMode.off
|
|
@@ -408,7 +393,7 @@ extension CameraController {
|
|
|
408
393
|
} catch {
|
|
409
394
|
throw CameraControllerError.invalidOperation
|
|
410
395
|
}
|
|
411
|
-
|
|
396
|
+
|
|
412
397
|
}
|
|
413
398
|
|
|
414
399
|
func captureVideo(completion: @escaping (URL?, Error?) -> Void) {
|
|
@@ -422,10 +407,10 @@ extension CameraController {
|
|
|
422
407
|
let finalIdentifier = String(randomIdentifier.prefix(8))
|
|
423
408
|
let fileName="cpcp_video_"+finalIdentifier+".mp4"
|
|
424
409
|
|
|
425
|
-
|
|
410
|
+
let fileUrl = path.appendingPathComponent(fileName)
|
|
426
411
|
try? FileManager.default.removeItem(at: fileUrl)
|
|
427
412
|
/*videoOutput!.startRecording(to: fileUrl, recordingDelegate: self)
|
|
428
|
-
|
|
413
|
+
self.videoRecordCompletionBlock = completion*/
|
|
429
414
|
}
|
|
430
415
|
|
|
431
416
|
func stopRecording(completion: @escaping (Error?) -> Void) {
|
|
@@ -433,32 +418,32 @@ extension CameraController {
|
|
|
433
418
|
completion(CameraControllerError.captureSessionIsMissing)
|
|
434
419
|
return
|
|
435
420
|
}
|
|
436
|
-
//self.videoOutput?.stopRecording()
|
|
421
|
+
// self.videoOutput?.stopRecording()
|
|
437
422
|
}
|
|
438
423
|
}
|
|
439
424
|
|
|
440
425
|
extension CameraController: UIGestureRecognizerDelegate {
|
|
441
426
|
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
|
|
442
|
-
return true
|
|
427
|
+
return true
|
|
443
428
|
}
|
|
444
|
-
|
|
429
|
+
|
|
445
430
|
@objc
|
|
446
431
|
func handleTap(_ tap: UITapGestureRecognizer) {
|
|
447
432
|
guard let device = self.currentCameraPosition == .rear ? rearCamera : frontCamera else { return }
|
|
448
|
-
|
|
433
|
+
|
|
449
434
|
let point = tap.location(in: tap.view)
|
|
450
435
|
let devicePoint = self.previewLayer?.captureDevicePointConverted(fromLayerPoint: point)
|
|
451
|
-
|
|
436
|
+
|
|
452
437
|
do {
|
|
453
438
|
try device.lockForConfiguration()
|
|
454
439
|
defer { device.unlockForConfiguration() }
|
|
455
|
-
|
|
440
|
+
|
|
456
441
|
let focusMode = AVCaptureDevice.FocusMode.autoFocus
|
|
457
442
|
if device.isFocusPointOfInterestSupported && device.isFocusModeSupported(focusMode) {
|
|
458
443
|
device.focusPointOfInterest = CGPoint(x: CGFloat(devicePoint?.x ?? 0), y: CGFloat(devicePoint?.y ?? 0))
|
|
459
444
|
device.focusMode = focusMode
|
|
460
445
|
}
|
|
461
|
-
|
|
446
|
+
|
|
462
447
|
let exposureMode = AVCaptureDevice.ExposureMode.autoExpose
|
|
463
448
|
if device.isExposurePointOfInterestSupported && device.isExposureModeSupported(exposureMode) {
|
|
464
449
|
device.exposurePointOfInterest = CGPoint(x: CGFloat(devicePoint?.x ?? 0), y: CGFloat(devicePoint?.y ?? 0))
|
|
@@ -468,24 +453,24 @@ extension CameraController: UIGestureRecognizerDelegate {
|
|
|
468
453
|
debugPrint(error)
|
|
469
454
|
}
|
|
470
455
|
}
|
|
471
|
-
|
|
456
|
+
|
|
472
457
|
@objc
|
|
473
458
|
private func handlePinch(_ pinch: UIPinchGestureRecognizer) {
|
|
474
459
|
guard let device = self.currentCameraPosition == .rear ? rearCamera : frontCamera else { return }
|
|
475
|
-
|
|
460
|
+
|
|
476
461
|
func minMaxZoom(_ factor: CGFloat) -> CGFloat { return max(1.0, min(factor, device.activeFormat.videoMaxZoomFactor)) }
|
|
477
|
-
|
|
462
|
+
|
|
478
463
|
func update(scale factor: CGFloat) {
|
|
479
464
|
do {
|
|
480
465
|
try device.lockForConfiguration()
|
|
481
466
|
defer { device.unlockForConfiguration() }
|
|
482
|
-
|
|
467
|
+
|
|
483
468
|
device.videoZoomFactor = factor
|
|
484
469
|
} catch {
|
|
485
470
|
debugPrint(error)
|
|
486
471
|
}
|
|
487
472
|
}
|
|
488
|
-
|
|
473
|
+
|
|
489
474
|
switch pinch.state {
|
|
490
475
|
case .began: fallthrough
|
|
491
476
|
case .changed:
|
|
@@ -501,14 +486,10 @@ extension CameraController: UIGestureRecognizerDelegate {
|
|
|
501
486
|
extension CameraController: AVCapturePhotoCaptureDelegate {
|
|
502
487
|
public func photoOutput(_ captureOutput: AVCapturePhotoOutput, didFinishProcessingPhoto photoSampleBuffer: CMSampleBuffer?, previewPhoto previewPhotoSampleBuffer: CMSampleBuffer?,
|
|
503
488
|
resolvedSettings: AVCaptureResolvedPhotoSettings, bracketSettings: AVCaptureBracketedStillImageSettings?, error: Swift.Error?) {
|
|
504
|
-
if let error = error { self.photoCaptureCompletionBlock?(nil, error) }
|
|
505
|
-
|
|
506
|
-
else if let buffer = photoSampleBuffer, let data = AVCapturePhotoOutput.jpegPhotoDataRepresentation(forJPEGSampleBuffer: buffer, previewPhotoSampleBuffer: nil),
|
|
507
|
-
let image = UIImage(data: data) {
|
|
489
|
+
if let error = error { self.photoCaptureCompletionBlock?(nil, error) } else if let buffer = photoSampleBuffer, let data = AVCapturePhotoOutput.jpegPhotoDataRepresentation(forJPEGSampleBuffer: buffer, previewPhotoSampleBuffer: nil),
|
|
490
|
+
let image = UIImage(data: data) {
|
|
508
491
|
self.photoCaptureCompletionBlock?(image.fixedOrientation(), nil)
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
else {
|
|
492
|
+
} else {
|
|
512
493
|
self.photoCaptureCompletionBlock?(nil, CameraControllerError.unknown)
|
|
513
494
|
}
|
|
514
495
|
}
|
|
@@ -556,9 +537,6 @@ extension CameraController: AVCaptureVideoDataOutputSampleBufferDelegate {
|
|
|
556
537
|
}
|
|
557
538
|
}
|
|
558
539
|
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
540
|
enum CameraControllerError: Swift.Error {
|
|
563
541
|
case captureSessionAlreadyRunning
|
|
564
542
|
case captureSessionIsMissing
|
|
@@ -596,21 +574,21 @@ extension CameraControllerError: LocalizedError {
|
|
|
596
574
|
extension UIImage {
|
|
597
575
|
|
|
598
576
|
func fixedOrientation() -> UIImage? {
|
|
599
|
-
|
|
577
|
+
|
|
600
578
|
guard imageOrientation != UIImage.Orientation.up else {
|
|
601
|
-
//This is default orientation, don't need to do anything
|
|
579
|
+
// This is default orientation, don't need to do anything
|
|
602
580
|
return self.copy() as? UIImage
|
|
603
581
|
}
|
|
604
|
-
|
|
582
|
+
|
|
605
583
|
guard let cgImage = self.cgImage else {
|
|
606
|
-
//CGImage is not available
|
|
584
|
+
// CGImage is not available
|
|
607
585
|
return nil
|
|
608
586
|
}
|
|
609
587
|
|
|
610
588
|
guard let colorSpace = cgImage.colorSpace, let ctx = CGContext(data: nil, width: Int(size.width), height: Int(size.height), bitsPerComponent: cgImage.bitsPerComponent, bytesPerRow: 0, space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) else {
|
|
611
|
-
return nil //Not able to create CGContext
|
|
589
|
+
return nil // Not able to create CGContext
|
|
612
590
|
}
|
|
613
|
-
|
|
591
|
+
|
|
614
592
|
var transform: CGAffineTransform = CGAffineTransform.identity
|
|
615
593
|
switch imageOrientation {
|
|
616
594
|
case .down, .downMirrored:
|
|
@@ -631,8 +609,8 @@ extension UIImage {
|
|
|
631
609
|
case .up, .upMirrored:
|
|
632
610
|
break
|
|
633
611
|
}
|
|
634
|
-
|
|
635
|
-
//Flip image one more time if needed to, this is to prevent flipped image
|
|
612
|
+
|
|
613
|
+
// Flip image one more time if needed to, this is to prevent flipped image
|
|
636
614
|
switch imageOrientation {
|
|
637
615
|
case .upMirrored, .downMirrored:
|
|
638
616
|
transform.translatedBy(x: size.width, y: 0)
|
|
@@ -644,9 +622,9 @@ extension UIImage {
|
|
|
644
622
|
case .up, .down, .left, .right:
|
|
645
623
|
break
|
|
646
624
|
}
|
|
647
|
-
|
|
625
|
+
|
|
648
626
|
ctx.concatenate(transform)
|
|
649
|
-
|
|
627
|
+
|
|
650
628
|
switch imageOrientation {
|
|
651
629
|
case .left, .leftMirrored, .right, .rightMirrored:
|
|
652
630
|
ctx.draw(self.cgImage!, in: CGRect(x: 0, y: 0, width: size.height, height: size.width))
|
|
@@ -662,9 +640,9 @@ extension UIImage {
|
|
|
662
640
|
extension CameraController: AVCaptureFileOutputRecordingDelegate {
|
|
663
641
|
func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) {
|
|
664
642
|
/*if error == nil {
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
643
|
+
self.videoRecordCompletionBlock?(outputFileURL, nil)
|
|
644
|
+
} else {
|
|
645
|
+
self.videoRecordCompletionBlock?(nil, error)
|
|
646
|
+
}*/
|
|
669
647
|
}
|
|
670
648
|
}
|