@capgo/camera-preview 7.4.0-beta.13 → 7.4.0-beta.16

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.
@@ -84,7 +84,6 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelega
84
84
  var toBack: Bool?
85
85
  var storeToFile: Bool?
86
86
  var enableZoom: Bool?
87
- var highResolutionOutput: Bool = false
88
87
  var disableAudio: Bool = false
89
88
  var locationManager: CLLocationManager?
90
89
  var currentLocation: CLLocation?
@@ -138,26 +137,8 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelega
138
137
  let height = heightValue - paddingBottom
139
138
 
140
139
  // Handle auto-centering during rotation
141
- if posX == -1 || posY == -1 {
142
- // Trigger full recalculation for auto-centered views
143
- self.updateCameraFrame()
144
- } else {
145
- // Manual positioning - use original rotation logic with no animation
146
- CATransaction.begin()
147
- CATransaction.setDisableActions(true)
148
-
149
- if UIWindow.isLandscape {
150
- previewView.frame = CGRect(x: posY, y: posX, width: max(height, width), height: min(height, width))
151
- self.cameraController.previewLayer?.frame = previewView.bounds
152
- }
153
-
154
- if UIWindow.isPortrait {
155
- previewView.frame = CGRect(x: posX, y: posY, width: min(height, width), height: max(height, width))
156
- self.cameraController.previewLayer?.frame = previewView.bounds
157
- }
158
-
159
- CATransaction.commit()
160
- }
140
+ // Always use the factorized method for consistent positioning
141
+ self.updateCameraFrame()
161
142
 
162
143
  if let connection = self.cameraController.fileVideoOutput?.connection(with: .video) {
163
144
  switch UIDevice.current.orientation {
@@ -206,48 +187,51 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelega
206
187
  self.aspectRatio = newAspectRatio
207
188
 
208
189
  DispatchQueue.main.async {
209
- // When aspect ratio changes, calculate maximum size possible from current position
210
- if let posX = self.posX, let posY = self.posY {
211
- let webViewWidth = self.webView?.frame.width ?? UIScreen.main.bounds.width
212
- let webViewHeight = self.webView?.frame.height ?? UIScreen.main.bounds.height
213
- let paddingBottom = self.paddingBottom ?? 0
214
-
215
- // Calculate available space from current position
216
- let availableWidth: CGFloat
217
- let availableHeight: CGFloat
218
-
219
- if posX == -1 || posY == -1 {
220
- // Auto-centering mode - use full dimensions
221
- availableWidth = webViewWidth
222
- availableHeight = webViewHeight - paddingBottom
223
- } else {
224
- // Manual positioning - calculate remaining space
225
- availableWidth = webViewWidth - posX
226
- availableHeight = webViewHeight - posY - paddingBottom
227
- }
228
-
229
- // Parse aspect ratio - convert to portrait orientation for camera use
230
- let ratioParts = newAspectRatio.split(separator: ":").map { Double($0) ?? 1.0 }
231
- // For camera, we want portrait orientation: 4:3 becomes 3:4, 16:9 becomes 9:16
232
- let ratio = ratioParts[1] / ratioParts[0]
190
+ // When aspect ratio changes, always auto-center the view
191
+ // This ensures consistent behavior where changing aspect ratio recenters the view
192
+ self.posX = -1
193
+ self.posY = -1
194
+
195
+ // Calculate maximum size based on aspect ratio
196
+ let webViewWidth = self.webView?.frame.width ?? UIScreen.main.bounds.width
197
+ let webViewHeight = self.webView?.frame.height ?? UIScreen.main.bounds.height
198
+ let paddingBottom = self.paddingBottom ?? 0
199
+
200
+ // Calculate available space
201
+ let availableWidth: CGFloat
202
+ let availableHeight: CGFloat
203
+
204
+ if self.posX == -1 || self.posY == -1 {
205
+ // Auto-centering mode - use full dimensions
206
+ availableWidth = webViewWidth
207
+ availableHeight = webViewHeight - paddingBottom
208
+ } else {
209
+ // Manual positioning - calculate remaining space
210
+ availableWidth = webViewWidth - self.posX!
211
+ availableHeight = webViewHeight - self.posY! - paddingBottom
212
+ }
233
213
 
234
- // Calculate maximum size that fits the aspect ratio in available space
235
- let maxWidthByHeight = availableHeight * CGFloat(ratio)
236
- let maxHeightByWidth = availableWidth / CGFloat(ratio)
214
+ // Parse aspect ratio - convert to portrait orientation for camera use
215
+ let ratioParts = newAspectRatio.split(separator: ":").map { Double($0) ?? 1.0 }
216
+ // For camera, we want portrait orientation: 4:3 becomes 3:4, 16:9 becomes 9:16
217
+ let ratio = ratioParts[1] / ratioParts[0]
237
218
 
238
- if maxWidthByHeight <= availableWidth {
239
- // Height is the limiting factor
240
- self.width = maxWidthByHeight
241
- self.height = availableHeight
242
- } else {
243
- // Width is the limiting factor
244
- self.width = availableWidth
245
- self.height = maxHeightByWidth
246
- }
219
+ // Calculate maximum size that fits the aspect ratio in available space
220
+ let maxWidthByHeight = availableHeight * CGFloat(ratio)
221
+ let maxHeightByWidth = availableWidth / CGFloat(ratio)
247
222
 
248
- print("[CameraPreview] Aspect ratio changed to \(newAspectRatio), new size: \(self.width!)x\(self.height!)")
223
+ if maxWidthByHeight <= availableWidth {
224
+ // Height is the limiting factor
225
+ self.width = maxWidthByHeight
226
+ self.height = availableHeight
227
+ } else {
228
+ // Width is the limiting factor
229
+ self.width = availableWidth
230
+ self.height = maxHeightByWidth
249
231
  }
250
232
 
233
+ print("[CameraPreview] Aspect ratio changed to \(newAspectRatio), new size: \(self.width!)x\(self.height!)")
234
+
251
235
  self.updateCameraFrame()
252
236
 
253
237
  // Return the actual preview bounds
@@ -412,8 +396,6 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelega
412
396
  self.cameraPosition = call.getString("position") ?? "rear"
413
397
  let deviceId = call.getString("deviceId")
414
398
  let cameraMode = call.getBool("cameraMode") ?? false
415
- self.highResolutionOutput = call.getBool("enableHighResolution") ?? false
416
- self.cameraController.highResolutionOutput = self.highResolutionOutput
417
399
 
418
400
  // Set width - use screen width if not provided or if 0
419
401
  if let width = call.getInt("width"), width > 0 {
@@ -453,6 +435,7 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelega
453
435
  self.disableAudio = call.getBool("disableAudio") ?? true
454
436
  self.aspectRatio = call.getString("aspectRatio")
455
437
  self.gridMode = call.getString("gridMode") ?? "none"
438
+ let initialZoomLevel = call.getFloat("initialZoomLevel") ?? 1.0
456
439
  if self.aspectRatio != nil && (call.getInt("width") != nil || call.getInt("height") != nil) {
457
440
  call.reject("Cannot set both aspectRatio and size (width/height). Use setPreviewSize after start.")
458
441
  return
@@ -471,12 +454,7 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelega
471
454
  if self.cameraController.captureSession?.isRunning ?? false {
472
455
  call.reject("camera already started")
473
456
  } else {
474
- // Pre-initialize session if not already done
475
- if self.cameraController.captureSession == nil {
476
- self.cameraController.prepareFullSession()
477
- }
478
-
479
- self.cameraController.prepare(cameraPosition: self.cameraPosition, deviceId: deviceId, disableAudio: self.disableAudio, cameraMode: cameraMode, aspectRatio: self.aspectRatio) {error in
457
+ self.cameraController.prepare(cameraPosition: self.cameraPosition, deviceId: deviceId, disableAudio: self.disableAudio, cameraMode: cameraMode, aspectRatio: self.aspectRatio, initialZoomLevel: Float(initialZoomLevel)) {error in
480
458
  if let error = error {
481
459
  print(error)
482
460
  call.reject(error.localizedDescription)
@@ -506,8 +484,7 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelega
506
484
  // Display the camera preview on the configured view
507
485
  try? self.cameraController.displayPreview(on: self.previewView)
508
486
 
509
- let frontView = self.toBack! ? self.webView : self.previewView
510
- self.cameraController.setupGestures(target: frontView ?? self.previewView, enableZoom: self.enableZoom!)
487
+ self.cameraController.setupGestures(target: self.previewView, enableZoom: self.enableZoom!)
511
488
 
512
489
  // Add grid overlay if enabled
513
490
  if self.gridMode != "none" {
@@ -686,11 +663,19 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelega
686
663
  let withExifLocation = call.getBool("withExifLocation", false)
687
664
  let width = call.getInt("width")
688
665
  let height = call.getInt("height")
666
+ let aspectRatio = call.getString("aspectRatio")
689
667
 
690
- print("[CameraPreview] Capture params - quality: \(quality), saveToGallery: \(saveToGallery), withExifLocation: \(withExifLocation), width: \(width ?? -1), height: \(height ?? -1)")
668
+ // Check for conflicting parameters
669
+ if aspectRatio != nil && (width != nil || height != nil) {
670
+ print("[CameraPreview] Error: Cannot set both aspectRatio and size (width/height)")
671
+ call.reject("Cannot set both aspectRatio and size (width/height). Use setPreviewSize after start.")
672
+ return
673
+ }
674
+
675
+ print("[CameraPreview] Capture params - quality: \(quality), saveToGallery: \(saveToGallery), withExifLocation: \(withExifLocation), width: \(width ?? -1), height: \(height ?? -1), aspectRatio: \(aspectRatio ?? "nil")")
691
676
  print("[CameraPreview] Current location: \(self.currentLocation?.description ?? "nil")")
692
677
 
693
- self.cameraController.captureImage(width: width, height: height, quality: quality, gpsLocation: self.currentLocation) { (image, error) in
678
+ self.cameraController.captureImage(width: width, height: height, aspectRatio: aspectRatio, quality: quality, gpsLocation: self.currentLocation) { (image, error) in
694
679
  print("[CameraPreview] captureImage callback received")
695
680
  DispatchQueue.main.async {
696
681
  print("[CameraPreview] Processing capture on main thread")
@@ -700,7 +685,13 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelega
700
685
  return
701
686
  }
702
687
 
703
- guard let imageDataWithExif = self.createImageDataWithExif(from: image!, quality: Int(quality), location: withExifLocation ? self.currentLocation : nil) else {
688
+ guard let image = image,
689
+ let imageDataWithExif = self.createImageDataWithExif(
690
+ from: image,
691
+ quality: Int(quality),
692
+ location: withExifLocation ? self.currentLocation : nil
693
+ )
694
+ else {
704
695
  print("[CameraPreview] Failed to create image data with EXIF")
705
696
  call.reject("Failed to create image data with EXIF")
706
697
  return
@@ -1060,9 +1051,10 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelega
1060
1051
  }
1061
1052
 
1062
1053
  let ramp = call.getBool("ramp") ?? true
1054
+ let autoFocus = call.getBool("autoFocus") ?? true
1063
1055
 
1064
1056
  do {
1065
- try self.cameraController.setZoom(level: CGFloat(level), ramp: ramp)
1057
+ try self.cameraController.setZoom(level: CGFloat(level), ramp: ramp, autoFocus: autoFocus)
1066
1058
  call.resolve()
1067
1059
  } catch {
1068
1060
  call.reject("Failed to set zoom: \(error.localizedDescription)")
@@ -1304,54 +1296,79 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelega
1304
1296
  }
1305
1297
  }
1306
1298
 
1307
- private func updateCameraFrame() {
1308
- guard let width = self.width, var height = self.height, let posX = self.posX, let posY = self.posY else {
1309
- return
1310
- }
1311
-
1312
- // Ensure UI operations happen on main thread
1313
- guard Thread.isMainThread else {
1314
- DispatchQueue.main.async {
1315
- self.updateCameraFrame()
1316
- }
1317
- return
1318
- }
1299
+ private func calculateCameraFrame(x: CGFloat? = nil, y: CGFloat? = nil, width: CGFloat? = nil, height: CGFloat? = nil, aspectRatio: String? = nil) -> CGRect {
1300
+ // Use provided values or existing ones
1301
+ let currentWidth = width ?? self.width ?? UIScreen.main.bounds.size.width
1302
+ let currentHeight = height ?? self.height ?? UIScreen.main.bounds.size.height
1303
+ let currentX = x ?? self.posX ?? -1
1304
+ let currentY = y ?? self.posY ?? -1
1305
+ let currentAspectRatio = aspectRatio ?? self.aspectRatio
1319
1306
 
1320
1307
  let paddingBottom = self.paddingBottom ?? 0
1321
- height -= paddingBottom
1308
+ let adjustedHeight = currentHeight - CGFloat(paddingBottom)
1322
1309
 
1323
1310
  // Cache webView dimensions for performance
1324
1311
  let webViewWidth = self.webView?.frame.width ?? UIScreen.main.bounds.width
1325
1312
  let webViewHeight = self.webView?.frame.height ?? UIScreen.main.bounds.height
1326
1313
 
1327
- var finalX = posX
1328
- var finalY = posY
1329
- var finalWidth = width
1330
- var finalHeight = height
1314
+ var finalX = currentX
1315
+ var finalY = currentY
1316
+ var finalWidth = currentWidth
1317
+ var finalHeight = adjustedHeight
1331
1318
 
1332
1319
  // Handle auto-centering when position is -1
1333
- if posX == -1 || posY == -1 {
1334
- finalWidth = webViewWidth
1335
-
1336
- // Calculate height based on aspect ratio or use provided height
1337
- if let aspectRatio = self.aspectRatio {
1338
- let ratioParts = aspectRatio.split(separator: ":").compactMap { Double($0) }
1320
+ if currentX == -1 || currentY == -1 {
1321
+ // Only override dimensions if aspect ratio is provided and no explicit dimensions given
1322
+ if let ratio = currentAspectRatio,
1323
+ currentWidth == UIScreen.main.bounds.size.width &&
1324
+ currentHeight == UIScreen.main.bounds.size.height {
1325
+ finalWidth = webViewWidth
1326
+
1327
+ // Calculate height based on aspect ratio
1328
+ let ratioParts = ratio.split(separator: ":").compactMap { Double($0) }
1339
1329
  if ratioParts.count == 2 {
1340
1330
  // For camera, use portrait orientation: 4:3 becomes 3:4, 16:9 becomes 9:16
1341
- let ratio = ratioParts[1] / ratioParts[0]
1342
- finalHeight = finalWidth / CGFloat(ratio)
1331
+ let ratioValue = ratioParts[1] / ratioParts[0]
1332
+ finalHeight = finalWidth / CGFloat(ratioValue)
1343
1333
  }
1344
1334
  }
1345
1335
 
1346
- finalX = posX == -1 ? 0 : posX
1336
+ // Center horizontally if x is -1
1337
+ if currentX == -1 {
1338
+ finalX = (webViewWidth - finalWidth) / 2
1339
+ } else {
1340
+ finalX = currentX
1341
+ }
1347
1342
 
1348
- if posY == -1 {
1349
- let availableHeight = webViewHeight - paddingBottom
1350
- finalY = finalHeight < availableHeight ? (availableHeight - finalHeight) / 2 : 0
1343
+ // Center vertically if y is -1
1344
+ if currentY == -1 {
1345
+ // Use full screen height for centering
1346
+ let screenHeight = UIScreen.main.bounds.size.height
1347
+ finalY = (screenHeight - finalHeight) / 2
1348
+ print("[CameraPreview] Centering vertically: screenHeight=\(screenHeight), finalHeight=\(finalHeight), finalY=\(finalY)")
1349
+ } else {
1350
+ finalY = currentY
1351
1351
  }
1352
1352
  }
1353
1353
 
1354
- var frame = CGRect(x: finalX, y: finalY, width: finalWidth, height: finalHeight)
1354
+ return CGRect(x: finalX, y: finalY, width: finalWidth, height: finalHeight)
1355
+ }
1356
+
1357
+ private func updateCameraFrame() {
1358
+ guard let width = self.width, let height = self.height, let posX = self.posX, let posY = self.posY else {
1359
+ return
1360
+ }
1361
+
1362
+ // Ensure UI operations happen on main thread
1363
+ guard Thread.isMainThread else {
1364
+ DispatchQueue.main.async {
1365
+ self.updateCameraFrame()
1366
+ }
1367
+ return
1368
+ }
1369
+
1370
+ // Calculate the base frame using the factorized method
1371
+ var frame = calculateCameraFrame()
1355
1372
 
1356
1373
  // Apply aspect ratio adjustments only if not auto-centering
1357
1374
  if posX != -1 && posY != -1, let aspectRatio = self.aspectRatio {
@@ -1359,15 +1376,15 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelega
1359
1376
  if ratioParts.count == 2 {
1360
1377
  // For camera, use portrait orientation: 4:3 becomes 3:4, 16:9 becomes 9:16
1361
1378
  let ratio = ratioParts[1] / ratioParts[0]
1362
- let currentRatio = Double(finalWidth) / Double(finalHeight)
1379
+ let currentRatio = Double(frame.width) / Double(frame.height)
1363
1380
 
1364
1381
  if currentRatio > ratio {
1365
- let newWidth = Double(finalHeight) * ratio
1366
- frame.origin.x = finalX + (Double(finalWidth) - newWidth) / 2
1382
+ let newWidth = Double(frame.height) * ratio
1383
+ frame.origin.x = frame.origin.x + (frame.width - CGFloat(newWidth)) / 2
1367
1384
  frame.size.width = CGFloat(newWidth)
1368
1385
  } else {
1369
- let newHeight = Double(finalWidth) / ratio
1370
- frame.origin.y = finalY + (Double(finalHeight) - newHeight) / 2
1386
+ let newHeight = Double(frame.width) / ratio
1387
+ frame.origin.y = frame.origin.y + (frame.height - CGFloat(newHeight)) / 2
1371
1388
  frame.size.height = CGFloat(newHeight)
1372
1389
  }
1373
1390
  }
@@ -1420,13 +1437,19 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelega
1420
1437
  return
1421
1438
  }
1422
1439
 
1423
- // Only update position if explicitly provided, otherwise keep auto-centering
1440
+ // Always set to -1 for auto-centering if not explicitly provided
1424
1441
  if let x = call.getInt("x") {
1425
1442
  self.posX = CGFloat(x)
1443
+ } else {
1444
+ self.posX = -1 // Auto-center if X not provided
1426
1445
  }
1446
+
1427
1447
  if let y = call.getInt("y") {
1428
1448
  self.posY = CGFloat(y)
1449
+ } else {
1450
+ self.posY = -1 // Auto-center if Y not provided
1429
1451
  }
1452
+
1430
1453
  if let width = call.getInt("width") { self.width = CGFloat(width) }
1431
1454
  if let height = call.getInt("height") { self.height = CGFloat(height) }
1432
1455
 
@@ -1456,15 +1479,17 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelega
1456
1479
  return
1457
1480
  }
1458
1481
 
1459
- // Ensure values are between 0 and 1
1460
- let normalizedX = max(0, min(1, x))
1461
- let normalizedY = max(0, min(1, y))
1482
+ // Reject if values are outside 0-1 range
1483
+ if x < 0 || x > 1 || y < 0 || y > 1 {
1484
+ call.reject("Focus coordinates must be between 0 and 1")
1485
+ return
1486
+ }
1462
1487
 
1463
1488
  DispatchQueue.main.async {
1464
1489
  do {
1465
1490
  // Convert normalized coordinates to view coordinates
1466
- let viewX = CGFloat(normalizedX) * self.previewView.bounds.width
1467
- let viewY = CGFloat(normalizedY) * self.previewView.bounds.height
1491
+ let viewX = CGFloat(x) * self.previewView.bounds.width
1492
+ let viewY = CGFloat(y) * self.previewView.bounds.height
1468
1493
  let focusPoint = CGPoint(x: viewX, y: viewY)
1469
1494
 
1470
1495
  // Convert view coordinates to device coordinates
@@ -1474,7 +1499,7 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelega
1474
1499
  }
1475
1500
  let devicePoint = previewLayer.captureDevicePointConverted(fromLayerPoint: focusPoint)
1476
1501
 
1477
- try self.cameraController.setFocus(at: devicePoint)
1502
+ try self.cameraController.setFocus(at: devicePoint, showIndicator: true, in: self.previewView)
1478
1503
  call.resolve()
1479
1504
  } catch {
1480
1505
  call.reject("Failed to set focus: \(error.localizedDescription)")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/camera-preview",
3
- "version": "7.4.0-beta.13",
3
+ "version": "7.4.0-beta.16",
4
4
  "description": "Camera preview",
5
5
  "license": "MIT",
6
6
  "repository": {