capacitor-camera-module 0.0.65 → 0.0.68
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.
|
@@ -5,26 +5,29 @@ import UIKit
|
|
|
5
5
|
import Photos
|
|
6
6
|
|
|
7
7
|
@objc(CameraModule)
|
|
8
|
-
public class CameraModulePlugin: CAPPlugin,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
8
|
+
public class CameraModulePlugin: CAPPlugin,CAPBridgedPlugin,AVCaptureVideoDataOutputSampleBufferDelegate {
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
public let identifier = "CameraModule"
|
|
12
|
+
public let jsName = "CameraModule"
|
|
13
|
+
public let pluginMethods: [CAPPluginMethod] = [
|
|
14
|
+
CAPPluginMethod(name: "checkPermission", returnType: CAPPluginReturnPromise),
|
|
15
|
+
CAPPluginMethod(name: "requestPermission", returnType: CAPPluginReturnPromise),
|
|
16
|
+
CAPPluginMethod(name: "checkGalleryPermission", returnType: CAPPluginReturnPromise),
|
|
17
|
+
CAPPluginMethod(name: "requestGalleryPermission", returnType: CAPPluginReturnPromise),
|
|
18
|
+
CAPPluginMethod(name: "checkAndRequestGalleryPermission", returnType: CAPPluginReturnPromise),
|
|
19
|
+
CAPPluginMethod(name: "pickImageBase64", returnType: CAPPluginReturnPromise),
|
|
20
|
+
CAPPluginMethod(name: "startPreview", returnType: CAPPluginReturnPromise),
|
|
21
|
+
CAPPluginMethod(name: "stopPreview", returnType: CAPPluginReturnPromise),
|
|
22
|
+
CAPPluginMethod(name: "toggleFlash", returnType: CAPPluginReturnPromise),
|
|
23
|
+
CAPPluginMethod(name: "hasFlash", returnType: CAPPluginReturnPromise),
|
|
24
|
+
CAPPluginMethod(name: "takePhotoBase64", returnType: CAPPluginReturnPromise),
|
|
25
|
+
CAPPluginMethod(name: "startBarcodeScan", returnType: CAPPluginReturnPromise),
|
|
26
|
+
CAPPluginMethod(name: "stopBarcodeScan", returnType: CAPPluginReturnPromise),
|
|
27
|
+
CAPPluginMethod(name: "getLastGalleryImage", returnType: CAPPluginReturnPromise)
|
|
28
|
+
|
|
29
|
+
]
|
|
30
|
+
|
|
28
31
|
|
|
29
32
|
private var previewView: UIView?
|
|
30
33
|
private var captureSession: AVCaptureSession?
|
|
@@ -33,6 +36,7 @@ public class CameraModulePlugin: CAPPlugin, CAPBridgedPlugin, AVCaptureVideoData
|
|
|
33
36
|
private var photoDelegate: PhotoDelegate?
|
|
34
37
|
|
|
35
38
|
// MARK: - Barcode
|
|
39
|
+
|
|
36
40
|
private var isScanning = false
|
|
37
41
|
private var scanCall: CAPPluginCall?
|
|
38
42
|
private var barcodeRequest: VNDetectBarcodesRequest?
|
|
@@ -42,14 +46,20 @@ public class CameraModulePlugin: CAPPlugin, CAPBridgedPlugin, AVCaptureVideoData
|
|
|
42
46
|
private let scanDebounceInterval: TimeInterval = 0.5
|
|
43
47
|
|
|
44
48
|
// MARK: - Gallery
|
|
49
|
+
|
|
45
50
|
private var galleryCall: CAPPluginCall?
|
|
46
51
|
|
|
47
52
|
// MARK: - Lifecycle
|
|
48
53
|
public override func load() {
|
|
54
|
+
// Este método ya no fuerza el color negro
|
|
55
|
+
// El webView será configurado dinámicamente en startPreview/stopPreview
|
|
49
56
|
print("📱 CameraModulePlugin cargado")
|
|
50
57
|
}
|
|
51
58
|
|
|
59
|
+
|
|
60
|
+
|
|
52
61
|
// MARK: - Camera Permission
|
|
62
|
+
|
|
53
63
|
@objc func checkPermission(_ call: CAPPluginCall) {
|
|
54
64
|
let status = AVCaptureDevice.authorizationStatus(for: .video)
|
|
55
65
|
call.resolve([
|
|
@@ -70,8 +80,10 @@ public class CameraModulePlugin: CAPPlugin, CAPBridgedPlugin, AVCaptureVideoData
|
|
|
70
80
|
}
|
|
71
81
|
|
|
72
82
|
// MARK: - Gallery Permission
|
|
83
|
+
|
|
73
84
|
@objc func checkGalleryPermission(_ call: CAPPluginCall) {
|
|
74
85
|
let status = PHPhotoLibrary.authorizationStatus(for: .readWrite)
|
|
86
|
+
|
|
75
87
|
switch status {
|
|
76
88
|
case .authorized, .limited:
|
|
77
89
|
call.resolve(["granted": true, "status": "granted"])
|
|
@@ -104,6 +116,7 @@ public class CameraModulePlugin: CAPPlugin, CAPBridgedPlugin, AVCaptureVideoData
|
|
|
104
116
|
}
|
|
105
117
|
|
|
106
118
|
// MARK: - Pick Image
|
|
119
|
+
|
|
107
120
|
@objc func pickImageBase64(_ call: CAPPluginCall) {
|
|
108
121
|
let status = PHPhotoLibrary.authorizationStatus(for: .readWrite)
|
|
109
122
|
guard status == .authorized || status == .limited else {
|
|
@@ -128,116 +141,139 @@ public class CameraModulePlugin: CAPPlugin, CAPBridgedPlugin, AVCaptureVideoData
|
|
|
128
141
|
}
|
|
129
142
|
|
|
130
143
|
// MARK: - Camera Preview
|
|
131
|
-
@objc func startPreview(_ call: CAPPluginCall) {
|
|
132
|
-
DispatchQueue.main.async {
|
|
133
|
-
if self.previewView != nil {
|
|
134
|
-
call.resolve()
|
|
135
|
-
return
|
|
136
|
-
}
|
|
137
144
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
145
|
+
@objc func startPreview(_ call: CAPPluginCall) {
|
|
146
|
+
DispatchQueue.main.async {
|
|
147
|
+
if self.previewView != nil {
|
|
148
|
+
call.resolve()
|
|
149
|
+
return
|
|
150
|
+
}
|
|
142
151
|
|
|
143
|
-
|
|
152
|
+
guard AVCaptureDevice.authorizationStatus(for: .video) == .authorized else {
|
|
153
|
+
call.reject("Camera permission not granted")
|
|
154
|
+
return
|
|
155
|
+
}
|
|
144
156
|
|
|
145
|
-
|
|
146
|
-
let input = try? AVCaptureDeviceInput(device: device) else {
|
|
147
|
-
call.reject("Camera not available")
|
|
148
|
-
return
|
|
149
|
-
}
|
|
157
|
+
let session = AVCaptureSession()
|
|
150
158
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
159
|
+
guard let device = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back),
|
|
160
|
+
let input = try? AVCaptureDeviceInput(device: device) else {
|
|
161
|
+
call.reject("Camera not available")
|
|
162
|
+
return
|
|
163
|
+
}
|
|
154
164
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
165
|
+
if session.canAddInput(input) {
|
|
166
|
+
session.addInput(input)
|
|
167
|
+
}
|
|
158
168
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
}
|
|
169
|
+
if session.canAddOutput(self.photoOutput) {
|
|
170
|
+
session.addOutput(self.photoOutput)
|
|
171
|
+
}
|
|
163
172
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
173
|
+
guard let container = self.bridge?.viewController?.view else {
|
|
174
|
+
call.reject("No container view")
|
|
175
|
+
return
|
|
176
|
+
}
|
|
168
177
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
webView.scrollView.isOpaque = false
|
|
174
|
-
|
|
175
|
-
// Crear previewView
|
|
176
|
-
let previewView = UIView()
|
|
177
|
-
previewView.translatesAutoresizingMaskIntoConstraints = false
|
|
178
|
-
previewView.backgroundColor = .clear
|
|
179
|
-
previewView.isUserInteractionEnabled = false
|
|
180
|
-
|
|
181
|
-
// Insertar previewView DETRÁS de todo
|
|
182
|
-
container.insertSubview(previewView, at: 0)
|
|
183
|
-
|
|
184
|
-
// Configurar constraints para toda la pantalla
|
|
185
|
-
NSLayoutConstraint.activate([
|
|
186
|
-
previewView.topAnchor.constraint(equalTo: container.topAnchor),
|
|
187
|
-
previewView.bottomAnchor.constraint(equalTo: container.bottomAnchor),
|
|
188
|
-
previewView.leadingAnchor.constraint(equalTo: container.leadingAnchor),
|
|
189
|
-
previewView.trailingAnchor.constraint(equalTo: container.trailingAnchor)
|
|
190
|
-
])
|
|
178
|
+
guard let webView = self.bridge?.webView as? WKWebView else {
|
|
179
|
+
call.reject("No webView")
|
|
180
|
+
return
|
|
181
|
+
}
|
|
191
182
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
183
|
+
// 1. Hacer el webView transparente
|
|
184
|
+
webView.isOpaque = false
|
|
185
|
+
webView.backgroundColor = .clear
|
|
186
|
+
webView.scrollView.backgroundColor = .clear
|
|
187
|
+
webView.scrollView.isOpaque = false
|
|
188
|
+
|
|
189
|
+
// 2. Crear previewView
|
|
190
|
+
let previewView = UIView()
|
|
191
|
+
previewView.translatesAutoresizingMaskIntoConstraints = false
|
|
192
|
+
previewView.backgroundColor = .clear // Transparente desde el inicio
|
|
193
|
+
previewView.isUserInteractionEnabled = false // No intercepta toques
|
|
194
|
+
|
|
195
|
+
// 3. Insertar previewView DETRÁS de todo
|
|
196
|
+
container.insertSubview(previewView, at: 0)
|
|
197
|
+
|
|
198
|
+
// 4. Configurar constraints para toda la pantalla
|
|
199
|
+
NSLayoutConstraint.activate([
|
|
200
|
+
previewView.topAnchor.constraint(equalTo: container.topAnchor),
|
|
201
|
+
previewView.bottomAnchor.constraint(equalTo: container.bottomAnchor),
|
|
202
|
+
previewView.leadingAnchor.constraint(equalTo: container.leadingAnchor),
|
|
203
|
+
previewView.trailingAnchor.constraint(equalTo: container.trailingAnchor)
|
|
204
|
+
])
|
|
195
205
|
|
|
196
|
-
|
|
197
|
-
|
|
206
|
+
// 5. Asegurar orden de capas
|
|
207
|
+
previewView.layer.zPosition = -1 // Detrás de todo
|
|
208
|
+
webView.layer.zPosition = 0 // Normal
|
|
198
209
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
previewLayer.videoGravity = .resizeAspectFill
|
|
202
|
-
previewLayer.frame = previewView.bounds
|
|
203
|
-
previewLayer.masksToBounds = true
|
|
210
|
+
// 6. Forzar layout
|
|
211
|
+
container.layoutIfNeeded()
|
|
204
212
|
|
|
205
|
-
|
|
213
|
+
// 7. Crear previewLayer
|
|
214
|
+
let previewLayer = AVCaptureVideoPreviewLayer(session: session)
|
|
215
|
+
previewLayer.videoGravity = .resizeAspectFill
|
|
216
|
+
previewLayer.frame = previewView.bounds
|
|
217
|
+
previewLayer.masksToBounds = true
|
|
206
218
|
|
|
207
|
-
|
|
208
|
-
self.previewView = previewView
|
|
209
|
-
self.videoPreviewLayer = previewLayer
|
|
210
|
-
self.captureSession = session
|
|
219
|
+
previewView.layer.insertSublayer(previewLayer, at: 0)
|
|
211
220
|
|
|
212
|
-
|
|
213
|
-
|
|
221
|
+
// 8. Guardar referencias
|
|
222
|
+
self.previewView = previewView
|
|
223
|
+
self.videoPreviewLayer = previewLayer
|
|
224
|
+
self.captureSession = session
|
|
214
225
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
session.startRunning()
|
|
218
|
-
}
|
|
226
|
+
// 9. Configurar sesión
|
|
227
|
+
session.sessionPreset = .photo
|
|
219
228
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
229
|
+
// 10. Iniciar sesión en background
|
|
230
|
+
DispatchQueue.global(qos: .userInitiated).async {
|
|
231
|
+
session.startRunning()
|
|
232
|
+
|
|
233
|
+
DispatchQueue.main.async {
|
|
234
|
+
print("Cámara iniciada correctamente")
|
|
235
|
+
print("Preview visible: \(previewView.window != nil ? "SÍ" : "NO")")
|
|
236
|
+
}
|
|
224
237
|
}
|
|
238
|
+
|
|
239
|
+
call.resolve([
|
|
240
|
+
"success": true,
|
|
241
|
+
"message": "Preview de cámara iniciado"
|
|
242
|
+
])
|
|
225
243
|
}
|
|
244
|
+
}
|
|
245
|
+
|
|
226
246
|
|
|
227
247
|
@objc func stopPreview(_ call: CAPPluginCall) {
|
|
228
248
|
DispatchQueue.main.async {
|
|
229
|
-
|
|
249
|
+
|
|
250
|
+
if self.isScanning {
|
|
251
|
+
self.isScanning = false
|
|
252
|
+
self.scanCall?.keepAlive = false
|
|
253
|
+
self.scanCall = nil
|
|
254
|
+
self.barcodeRequest = nil
|
|
255
|
+
self.lastScannedValue = nil
|
|
256
|
+
self.lastScanTime = nil
|
|
257
|
+
|
|
258
|
+
if let output = self.videoDataOutput,
|
|
259
|
+
let session = self.captureSession {
|
|
260
|
+
session.removeOutput(output)
|
|
261
|
+
}
|
|
262
|
+
self.videoDataOutput = nil
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// 🛑 Detener cámara
|
|
230
266
|
self.captureSession?.stopRunning()
|
|
231
267
|
self.captureSession = nil
|
|
232
268
|
|
|
233
|
-
//
|
|
269
|
+
// 🧹 Limpiar preview
|
|
234
270
|
self.videoPreviewLayer?.removeFromSuperlayer()
|
|
235
271
|
self.previewView?.removeFromSuperview()
|
|
236
272
|
self.videoPreviewLayer?.session = nil
|
|
237
273
|
self.videoPreviewLayer = nil
|
|
238
274
|
self.previewView = nil
|
|
239
275
|
|
|
240
|
-
// Restaurar
|
|
276
|
+
// 🔁 Restaurar WebView
|
|
241
277
|
if let webView = self.bridge?.webView as? WKWebView {
|
|
242
278
|
webView.isOpaque = true
|
|
243
279
|
webView.backgroundColor = .white
|
|
@@ -245,11 +281,16 @@ public class CameraModulePlugin: CAPPlugin, CAPBridgedPlugin, AVCaptureVideoData
|
|
|
245
281
|
webView.scrollView.isOpaque = true
|
|
246
282
|
}
|
|
247
283
|
|
|
284
|
+
print("Preview y escaneo detenidos correctamente")
|
|
248
285
|
call.resolve()
|
|
249
286
|
}
|
|
250
287
|
}
|
|
251
288
|
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
|
|
252
292
|
// MARK: - Flash
|
|
293
|
+
|
|
253
294
|
@objc func toggleFlash(_ call: CAPPluginCall) {
|
|
254
295
|
guard let enable = call.getBool("enable"),
|
|
255
296
|
let device = AVCaptureDevice.default(for: .video),
|
|
@@ -275,50 +316,53 @@ public class CameraModulePlugin: CAPPlugin, CAPBridgedPlugin, AVCaptureVideoData
|
|
|
275
316
|
}
|
|
276
317
|
|
|
277
318
|
@objc func getLastGalleryImage(_ call: CAPPluginCall) {
|
|
278
|
-
let status = PHPhotoLibrary.authorizationStatus(for: .readWrite)
|
|
279
319
|
|
|
280
|
-
|
|
281
|
-
call.reject("Gallery permission not granted")
|
|
282
|
-
return
|
|
283
|
-
}
|
|
320
|
+
let status = PHPhotoLibrary.authorizationStatus(for: .readWrite)
|
|
284
321
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
fetchOptions.fetchLimit = 1
|
|
322
|
+
guard status == .authorized || status == .limited else {
|
|
323
|
+
call.reject("Gallery permission not granted")
|
|
324
|
+
return
|
|
325
|
+
}
|
|
290
326
|
|
|
291
|
-
|
|
327
|
+
let fetchOptions = PHFetchOptions()
|
|
328
|
+
fetchOptions.sortDescriptors = [
|
|
329
|
+
NSSortDescriptor(key: "creationDate", ascending: false)
|
|
330
|
+
]
|
|
331
|
+
fetchOptions.fetchLimit = 1
|
|
292
332
|
|
|
293
|
-
|
|
294
|
-
call.reject("No images found")
|
|
295
|
-
return
|
|
296
|
-
}
|
|
333
|
+
let assets = PHAsset.fetchAssets(with: .image, options: fetchOptions)
|
|
297
334
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
options.isSynchronous = true
|
|
301
|
-
options.deliveryMode = .highQualityFormat
|
|
302
|
-
options.resizeMode = .none
|
|
303
|
-
|
|
304
|
-
imageManager.requestImageDataAndOrientation(
|
|
305
|
-
for: asset,
|
|
306
|
-
options: options
|
|
307
|
-
) { data, _, _, _ in
|
|
308
|
-
guard let imageData = data else {
|
|
309
|
-
call.reject("Error fetching last image")
|
|
335
|
+
guard let asset = assets.firstObject else {
|
|
336
|
+
call.reject("No images found")
|
|
310
337
|
return
|
|
311
338
|
}
|
|
312
339
|
|
|
313
|
-
let
|
|
340
|
+
let imageManager = PHImageManager.default()
|
|
341
|
+
let options = PHImageRequestOptions()
|
|
342
|
+
options.isSynchronous = true
|
|
343
|
+
options.deliveryMode = .highQualityFormat
|
|
344
|
+
options.resizeMode = .none
|
|
345
|
+
|
|
346
|
+
imageManager.requestImageDataAndOrientation(
|
|
347
|
+
for: asset,
|
|
348
|
+
options: options
|
|
349
|
+
) { data, _, _, _ in
|
|
314
350
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
351
|
+
guard let imageData = data else {
|
|
352
|
+
call.reject("Error fetching last image")
|
|
353
|
+
return
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
let base64 = imageData.base64EncodedString()
|
|
357
|
+
|
|
358
|
+
var ret = JSObject()
|
|
359
|
+
ret["base64"] = base64
|
|
360
|
+
call.resolve(ret)
|
|
361
|
+
}
|
|
318
362
|
}
|
|
319
|
-
}
|
|
320
363
|
|
|
321
364
|
// MARK: - Photo Capture
|
|
365
|
+
|
|
322
366
|
@objc func takePhotoBase64(_ call: CAPPluginCall) {
|
|
323
367
|
guard captureSession?.isRunning == true else {
|
|
324
368
|
call.reject("Camera not started")
|
|
@@ -340,6 +384,7 @@ public class CameraModulePlugin: CAPPlugin, CAPBridgedPlugin, AVCaptureVideoData
|
|
|
340
384
|
}
|
|
341
385
|
|
|
342
386
|
// MARK: - Barcode Scan
|
|
387
|
+
|
|
343
388
|
@objc func startBarcodeScan(_ call: CAPPluginCall) {
|
|
344
389
|
guard let session = captureSession else {
|
|
345
390
|
call.reject("Preview not started")
|
|
@@ -370,12 +415,19 @@ public class CameraModulePlugin: CAPPlugin, CAPBridgedPlugin, AVCaptureVideoData
|
|
|
370
415
|
self.lastScanTime = now
|
|
371
416
|
self.isScanning = false
|
|
372
417
|
|
|
418
|
+
if let output = self.videoDataOutput,
|
|
419
|
+
let session = self.captureSession {
|
|
420
|
+
session.removeOutput(output)
|
|
421
|
+
}
|
|
422
|
+
self.videoDataOutput = nil
|
|
423
|
+
|
|
373
424
|
self.scanCall?.resolve([
|
|
374
425
|
"rawValue": value,
|
|
375
426
|
"format": barcode.symbology.rawValue
|
|
376
427
|
])
|
|
377
428
|
self.scanCall?.keepAlive = false
|
|
378
429
|
self.scanCall = nil
|
|
430
|
+
|
|
379
431
|
}
|
|
380
432
|
|
|
381
433
|
if videoDataOutput == nil {
|
|
@@ -410,25 +462,30 @@ public class CameraModulePlugin: CAPPlugin, CAPBridgedPlugin, AVCaptureVideoData
|
|
|
410
462
|
public func captureOutput(_ output: AVCaptureOutput,
|
|
411
463
|
didOutput sampleBuffer: CMSampleBuffer,
|
|
412
464
|
from connection: AVCaptureConnection) {
|
|
465
|
+
|
|
413
466
|
guard isScanning,
|
|
467
|
+
captureSession?.isRunning == true,
|
|
414
468
|
let request = barcodeRequest,
|
|
415
|
-
let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)
|
|
469
|
+
let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)
|
|
470
|
+
else { return }
|
|
416
471
|
|
|
417
472
|
let handler = VNImageRequestHandler(
|
|
418
473
|
cvPixelBuffer: pixelBuffer,
|
|
419
|
-
orientation:
|
|
474
|
+
orientation: .right,
|
|
420
475
|
options: [:]
|
|
421
476
|
)
|
|
422
477
|
|
|
423
478
|
try? handler.perform([request])
|
|
424
479
|
}
|
|
425
|
-
|
|
480
|
+
|
|
426
481
|
|
|
427
482
|
// MARK: - UIImagePicker Delegate
|
|
483
|
+
|
|
428
484
|
extension CameraModulePlugin: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
|
|
429
485
|
|
|
430
486
|
public func imagePickerController(_ picker: UIImagePickerController,
|
|
431
487
|
didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
|
|
488
|
+
|
|
432
489
|
picker.dismiss(animated: true)
|
|
433
490
|
|
|
434
491
|
guard let image = info[.originalImage] as? UIImage,
|
|
@@ -454,6 +511,7 @@ extension CameraModulePlugin: UIImagePickerControllerDelegate, UINavigationContr
|
|
|
454
511
|
}
|
|
455
512
|
|
|
456
513
|
// MARK: - UIImage Resize
|
|
514
|
+
|
|
457
515
|
extension UIImage {
|
|
458
516
|
func resized(maxSize: CGFloat) -> UIImage? {
|
|
459
517
|
let maxSide = max(size.width, size.height)
|
|
@@ -468,23 +526,6 @@ extension UIImage {
|
|
|
468
526
|
UIGraphicsEndImageContext()
|
|
469
527
|
return img
|
|
470
528
|
}
|
|
471
|
-
}
|
|
472
529
|
|
|
473
|
-
// MARK: - Photo Delegate (si necesitas esta clase)
|
|
474
|
-
class PhotoDelegate: NSObject, AVCapturePhotoCaptureDelegate {
|
|
475
|
-
private let completion: (String) -> Void
|
|
476
530
|
|
|
477
|
-
|
|
478
|
-
self.completion = completion
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
func photoOutput(_ output: AVCapturePhotoOutput,
|
|
482
|
-
didFinishProcessingPhoto photo: AVCapturePhoto,
|
|
483
|
-
error: Error?) {
|
|
484
|
-
guard let data = photo.fileDataRepresentation(),
|
|
485
|
-
let base64 = data.base64EncodedString() else {
|
|
486
|
-
return
|
|
487
|
-
}
|
|
488
|
-
completion(base64)
|
|
489
|
-
}
|
|
490
|
-
}
|
|
531
|
+
}
|