@capgo/camera-preview 7.4.0-beta.7 → 7.4.0-beta.8
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 +62 -28
- package/android/.gradle/8.14.2/checksums/checksums.lock +0 -0
- package/android/.gradle/8.14.2/checksums/md5-checksums.bin +0 -0
- package/android/.gradle/8.14.2/checksums/sha1-checksums.bin +0 -0
- package/android/.gradle/8.14.2/executionHistory/executionHistory.bin +0 -0
- package/android/.gradle/8.14.2/executionHistory/executionHistory.lock +0 -0
- package/android/.gradle/8.14.2/fileHashes/fileHashes.bin +0 -0
- package/android/.gradle/8.14.2/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/8.14.2/fileHashes/resourceHashesCache.bin +0 -0
- package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
- package/android/.gradle/buildOutputCleanup/cache.properties +1 -1
- package/android/.gradle/buildOutputCleanup/outputFiles.bin +0 -0
- package/android/.gradle/file-system.probe +0 -0
- package/android/build.gradle +1 -0
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CameraPreview.java +127 -14
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CameraXView.java +479 -29
- package/android/src/main/java/com/ahm/capacitor/camera/preview/GridOverlayView.java +2 -0
- package/dist/docs.json +46 -7
- package/dist/esm/definitions.d.ts +42 -5
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.d.ts +25 -1
- package/dist/esm/web.js +81 -9
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +81 -9
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +81 -9
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/CapgoCameraPreview/CameraController.swift +95 -18
- package/ios/Sources/CapgoCameraPreview/Plugin.swift +271 -91
- package/package.json +1 -1
- package/android/.gradle/config.properties +0 -2
- package/android/.idea/AndroidProjectSystem.xml +0 -6
- package/android/.idea/caches/deviceStreaming.xml +0 -811
- package/android/.idea/compiler.xml +0 -6
- package/android/.idea/gradle.xml +0 -18
- package/android/.idea/migrations.xml +0 -10
- package/android/.idea/misc.xml +0 -10
- package/android/.idea/runConfigurations.xml +0 -17
- package/android/.idea/vcs.xml +0 -6
- package/android/.idea/workspace.xml +0 -55
- package/android/local.properties +0 -8
|
@@ -5,6 +5,7 @@ import android.hardware.camera2.CameraAccessException;
|
|
|
5
5
|
import android.hardware.camera2.CameraManager;
|
|
6
6
|
import android.os.Build;
|
|
7
7
|
import android.util.Base64;
|
|
8
|
+
import android.util.DisplayMetrics;
|
|
8
9
|
import android.util.Log;
|
|
9
10
|
import android.util.Size;
|
|
10
11
|
import android.view.ViewGroup;
|
|
@@ -68,6 +69,7 @@ import android.widget.FrameLayout;
|
|
|
68
69
|
import androidx.lifecycle.LifecycleObserver;
|
|
69
70
|
import androidx.lifecycle.OnLifecycleEvent;
|
|
70
71
|
import android.util.Rational;
|
|
72
|
+
import android.view.ViewGroup;
|
|
71
73
|
|
|
72
74
|
public class CameraXView implements LifecycleOwner, LifecycleObserver {
|
|
73
75
|
private static final String TAG = "CameraPreview CameraXView";
|
|
@@ -202,19 +204,86 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
|
|
|
202
204
|
|
|
203
205
|
// Create and setup the grid overlay
|
|
204
206
|
gridOverlayView = new GridOverlayView(context);
|
|
205
|
-
gridOverlayView.setGridMode(sessionConfig.getGridMode());
|
|
206
207
|
previewContainer.addView(gridOverlayView, new FrameLayout.LayoutParams(
|
|
207
208
|
FrameLayout.LayoutParams.MATCH_PARENT,
|
|
208
209
|
FrameLayout.LayoutParams.MATCH_PARENT
|
|
209
210
|
));
|
|
211
|
+
// Set grid mode after adding to container to ensure proper layout
|
|
212
|
+
gridOverlayView.post(() -> {
|
|
213
|
+
String currentGridMode = sessionConfig.getGridMode();
|
|
214
|
+
Log.d(TAG, "setupPreviewView: Setting grid mode to: " + currentGridMode);
|
|
215
|
+
gridOverlayView.setGridMode(currentGridMode);
|
|
216
|
+
});
|
|
210
217
|
|
|
211
218
|
ViewGroup parent = (ViewGroup) webView.getParent();
|
|
212
219
|
if (parent != null) {
|
|
213
|
-
|
|
220
|
+
FrameLayout.LayoutParams layoutParams = calculatePreviewLayoutParams();
|
|
221
|
+
parent.addView(previewContainer, layoutParams);
|
|
214
222
|
if(sessionConfig.isToBack()) webView.bringToFront();
|
|
215
223
|
}
|
|
216
224
|
}
|
|
217
225
|
|
|
226
|
+
private FrameLayout.LayoutParams calculatePreviewLayoutParams() {
|
|
227
|
+
// sessionConfig already contains pixel-converted coordinates with webview offsets applied
|
|
228
|
+
int x = sessionConfig.getX();
|
|
229
|
+
int y = sessionConfig.getY();
|
|
230
|
+
int width = sessionConfig.getWidth();
|
|
231
|
+
int height = sessionConfig.getHeight();
|
|
232
|
+
String aspectRatio = sessionConfig.getAspectRatio();
|
|
233
|
+
|
|
234
|
+
Log.d(TAG, "calculatePreviewLayoutParams: Using sessionConfig values - x:" + x + " y:" + y + " width:" + width + " height:" + height + " aspectRatio:" + aspectRatio);
|
|
235
|
+
|
|
236
|
+
// Apply aspect ratio if specified and no explicit size was given
|
|
237
|
+
if (aspectRatio != null && !aspectRatio.isEmpty()) {
|
|
238
|
+
String[] ratios = aspectRatio.split(":");
|
|
239
|
+
if (ratios.length == 2) {
|
|
240
|
+
try {
|
|
241
|
+
// For camera, use portrait orientation: 4:3 becomes 3:4, 16:9 becomes 9:16
|
|
242
|
+
float ratio = Float.parseFloat(ratios[1]) / Float.parseFloat(ratios[0]);
|
|
243
|
+
|
|
244
|
+
// Calculate optimal size while maintaining aspect ratio
|
|
245
|
+
int optimalWidth = width;
|
|
246
|
+
int optimalHeight = (int) (width / ratio);
|
|
247
|
+
|
|
248
|
+
if (optimalHeight > height) {
|
|
249
|
+
// Height constraint is tighter, fit by height
|
|
250
|
+
optimalHeight = height;
|
|
251
|
+
optimalWidth = (int) (height * ratio);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
width = optimalWidth;
|
|
255
|
+
height = optimalHeight;
|
|
256
|
+
Log.d(TAG, "calculatePreviewLayoutParams: Applied aspect ratio " + aspectRatio + " - new size: " + width + "x" + height);
|
|
257
|
+
} catch (NumberFormatException e) {
|
|
258
|
+
Log.e(TAG, "Invalid aspect ratio format: " + aspectRatio, e);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(width, height);
|
|
264
|
+
|
|
265
|
+
// Only add insets for positioning coordinates, not for full-screen sizes
|
|
266
|
+
int webViewTopInset = getWebViewTopInset();
|
|
267
|
+
int webViewLeftInset = getWebViewLeftInset();
|
|
268
|
+
|
|
269
|
+
// Don't add insets if this looks like a calculated full-screen coordinate (x=0, y=0)
|
|
270
|
+
if (x == 0 && y == 0) {
|
|
271
|
+
layoutParams.leftMargin = x;
|
|
272
|
+
layoutParams.topMargin = y;
|
|
273
|
+
Log.d(TAG, "calculatePreviewLayoutParams: Full-screen mode - keeping position (0,0) without insets");
|
|
274
|
+
} else {
|
|
275
|
+
layoutParams.leftMargin = x + webViewLeftInset;
|
|
276
|
+
layoutParams.topMargin = y + webViewTopInset;
|
|
277
|
+
Log.d(TAG, "calculatePreviewLayoutParams: Positioned mode - applying insets");
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
Log.d(TAG, "calculatePreviewLayoutParams: Applied insets - x:" + x + "+" + webViewLeftInset + "=" + layoutParams.leftMargin +
|
|
281
|
+
", y:" + y + "+" + webViewTopInset + "=" + layoutParams.topMargin);
|
|
282
|
+
|
|
283
|
+
Log.d(TAG, "calculatePreviewLayoutParams: Final layout - x:" + x + " y:" + y + " width:" + width + " height:" + height);
|
|
284
|
+
return layoutParams;
|
|
285
|
+
}
|
|
286
|
+
|
|
218
287
|
private void removePreviewView() {
|
|
219
288
|
if (previewContainer != null) {
|
|
220
289
|
ViewGroup parent = (ViewGroup) previewContainer.getParent();
|
|
@@ -305,12 +374,17 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
|
|
|
305
374
|
|
|
306
375
|
isRunning = true;
|
|
307
376
|
Log.d(TAG, "bindCameraUseCases: Camera bound successfully");
|
|
308
|
-
if (listener != null)
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
377
|
+
if (listener != null) {
|
|
378
|
+
// Post the callback to ensure layout is complete
|
|
379
|
+
previewContainer.post(() -> {
|
|
380
|
+
// Return actual preview container dimensions instead of requested dimensions
|
|
381
|
+
int actualWidth = previewContainer != null ? previewContainer.getWidth() : sessionConfig.getWidth();
|
|
382
|
+
int actualHeight = previewContainer != null ? previewContainer.getHeight() : sessionConfig.getHeight();
|
|
383
|
+
int actualX = previewContainer != null ? previewContainer.getLeft() : sessionConfig.getX();
|
|
384
|
+
int actualY = previewContainer != null ? previewContainer.getTop() : sessionConfig.getY();
|
|
385
|
+
listener.onCameraStarted(actualWidth, actualHeight, actualX, actualY);
|
|
386
|
+
});
|
|
387
|
+
}
|
|
314
388
|
} catch (Exception e) {
|
|
315
389
|
if (listener != null) listener.onCameraStartError("Error binding camera: " + e.getMessage());
|
|
316
390
|
}
|
|
@@ -1058,7 +1132,8 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
|
|
|
1058
1132
|
|
|
1059
1133
|
if (sessionConfig.getAspectRatio() != null) {
|
|
1060
1134
|
String[] ratios = sessionConfig.getAspectRatio().split(":");
|
|
1061
|
-
|
|
1135
|
+
// For camera, use portrait orientation: 4:3 becomes 3:4, 16:9 becomes 9:16
|
|
1136
|
+
float ratio = Float.parseFloat(ratios[1]) / Float.parseFloat(ratios[0]);
|
|
1062
1137
|
if (sessionConfig.getWidth() > 0) {
|
|
1063
1138
|
layoutParams.height = (int) (sessionConfig.getWidth() / ratio);
|
|
1064
1139
|
} else if (sessionConfig.getHeight() > 0) {
|
|
@@ -1093,31 +1168,88 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
|
|
|
1093
1168
|
}
|
|
1094
1169
|
|
|
1095
1170
|
public void setAspectRatio(String aspectRatio) {
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
);
|
|
1115
|
-
|
|
1171
|
+
setAspectRatio(aspectRatio, null, null);
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
public void setAspectRatio(String aspectRatio, Float x, Float y) {
|
|
1175
|
+
setAspectRatio(aspectRatio, x, y, null);
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
public void setAspectRatio(String aspectRatio, Float x, Float y, Runnable callback) {
|
|
1179
|
+
if (sessionConfig == null) {
|
|
1180
|
+
if (callback != null) callback.run();
|
|
1181
|
+
return;
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
String currentAspectRatio = sessionConfig.getAspectRatio();
|
|
1185
|
+
|
|
1186
|
+
// Don't restart camera if aspect ratio hasn't changed and no position specified
|
|
1187
|
+
if (aspectRatio != null && aspectRatio.equals(currentAspectRatio) && x == null && y == null) {
|
|
1188
|
+
Log.d(TAG, "setAspectRatio: Aspect ratio " + aspectRatio + " is already set and no position specified, skipping");
|
|
1189
|
+
if (callback != null) callback.run();
|
|
1190
|
+
return;
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
String currentGridMode = sessionConfig.getGridMode();
|
|
1194
|
+
Log.d(TAG, "setAspectRatio: Changing from " + currentAspectRatio + " to " + aspectRatio +
|
|
1195
|
+
(x != null && y != null ? " at position (" + x + ", " + y + ")" : " with auto-centering") +
|
|
1196
|
+
", preserving grid mode: " + currentGridMode);
|
|
1197
|
+
|
|
1198
|
+
sessionConfig = new CameraSessionConfiguration(
|
|
1199
|
+
sessionConfig.getDeviceId(),
|
|
1200
|
+
sessionConfig.getPosition(),
|
|
1201
|
+
sessionConfig.getX(),
|
|
1202
|
+
sessionConfig.getY(),
|
|
1203
|
+
sessionConfig.getWidth(),
|
|
1204
|
+
sessionConfig.getHeight(),
|
|
1205
|
+
sessionConfig.getPaddingBottom(),
|
|
1206
|
+
sessionConfig.getToBack(),
|
|
1207
|
+
sessionConfig.getStoreToFile(),
|
|
1208
|
+
sessionConfig.getEnableOpacity(),
|
|
1209
|
+
sessionConfig.getEnableZoom(),
|
|
1210
|
+
sessionConfig.getDisableExifHeaderStripping(),
|
|
1211
|
+
sessionConfig.getDisableAudio(),
|
|
1212
|
+
sessionConfig.getZoomFactor(),
|
|
1213
|
+
aspectRatio,
|
|
1214
|
+
currentGridMode
|
|
1215
|
+
);
|
|
1216
|
+
|
|
1217
|
+
// Update layout and rebind camera with new aspect ratio
|
|
1218
|
+
if (isRunning && previewContainer != null) {
|
|
1219
|
+
mainExecutor.execute(() -> {
|
|
1220
|
+
// First update the UI layout
|
|
1221
|
+
updatePreviewLayoutForAspectRatio(aspectRatio, x, y);
|
|
1222
|
+
|
|
1223
|
+
// Then rebind the camera with new aspect ratio configuration
|
|
1224
|
+
Log.d(TAG, "setAspectRatio: Rebinding camera with new aspect ratio: " + aspectRatio);
|
|
1225
|
+
bindCameraUseCases();
|
|
1226
|
+
|
|
1227
|
+
// Preserve grid mode and wait for completion
|
|
1228
|
+
if (gridOverlayView != null) {
|
|
1229
|
+
gridOverlayView.post(() -> {
|
|
1230
|
+
Log.d(TAG, "setAspectRatio: Re-applying grid mode: " + currentGridMode);
|
|
1231
|
+
gridOverlayView.setGridMode(currentGridMode);
|
|
1232
|
+
|
|
1233
|
+
// Wait one more frame for grid to be applied, then call callback
|
|
1234
|
+
if (callback != null) {
|
|
1235
|
+
gridOverlayView.post(callback);
|
|
1236
|
+
}
|
|
1237
|
+
});
|
|
1238
|
+
} else {
|
|
1239
|
+
// No grid overlay, wait one frame for layout completion then call callback
|
|
1240
|
+
if (callback != null) {
|
|
1241
|
+
previewContainer.post(callback);
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
});
|
|
1245
|
+
} else {
|
|
1246
|
+
if (callback != null) callback.run();
|
|
1116
1247
|
}
|
|
1117
1248
|
}
|
|
1118
1249
|
|
|
1119
1250
|
public void setGridMode(String gridMode) {
|
|
1120
1251
|
if (sessionConfig != null) {
|
|
1252
|
+
Log.d(TAG, "setGridMode: Changing grid mode to: " + gridMode);
|
|
1121
1253
|
sessionConfig = new CameraSessionConfiguration(
|
|
1122
1254
|
sessionConfig.getDeviceId(),
|
|
1123
1255
|
sessionConfig.getPosition(),
|
|
@@ -1140,9 +1272,327 @@ public class CameraXView implements LifecycleOwner, LifecycleObserver {
|
|
|
1140
1272
|
// Update the grid overlay immediately
|
|
1141
1273
|
if (gridOverlayView != null) {
|
|
1142
1274
|
gridOverlayView.post(() -> {
|
|
1275
|
+
Log.d(TAG, "setGridMode: Applying grid mode to overlay: " + gridMode);
|
|
1143
1276
|
gridOverlayView.setGridMode(gridMode);
|
|
1144
1277
|
});
|
|
1145
1278
|
}
|
|
1146
1279
|
}
|
|
1147
1280
|
}
|
|
1281
|
+
|
|
1282
|
+
public int getPreviewX() {
|
|
1283
|
+
if (previewContainer == null) return 0;
|
|
1284
|
+
ViewGroup.LayoutParams layoutParams = previewContainer.getLayoutParams();
|
|
1285
|
+
if (layoutParams instanceof ViewGroup.MarginLayoutParams) {
|
|
1286
|
+
// Return position relative to WebView content (subtract insets)
|
|
1287
|
+
int margin = ((ViewGroup.MarginLayoutParams) layoutParams).leftMargin;
|
|
1288
|
+
int leftInset = getWebViewLeftInset();
|
|
1289
|
+
int result = margin - leftInset;
|
|
1290
|
+
Log.d(TAG, "getPreviewX: leftMargin=" + margin + ", leftInset=" + leftInset + ", result=" + result);
|
|
1291
|
+
return result;
|
|
1292
|
+
}
|
|
1293
|
+
return previewContainer.getLeft();
|
|
1294
|
+
}
|
|
1295
|
+
public int getPreviewY() {
|
|
1296
|
+
if (previewContainer == null) return 0;
|
|
1297
|
+
ViewGroup.LayoutParams layoutParams = previewContainer.getLayoutParams();
|
|
1298
|
+
if (layoutParams instanceof ViewGroup.MarginLayoutParams) {
|
|
1299
|
+
// Return position relative to WebView content (subtract insets)
|
|
1300
|
+
int margin = ((ViewGroup.MarginLayoutParams) layoutParams).topMargin;
|
|
1301
|
+
int topInset = getWebViewTopInset();
|
|
1302
|
+
int result = margin - topInset;
|
|
1303
|
+
Log.d(TAG, "getPreviewY: topMargin=" + margin + ", topInset=" + topInset + ", result=" + result);
|
|
1304
|
+
return result;
|
|
1305
|
+
}
|
|
1306
|
+
return previewContainer.getTop();
|
|
1307
|
+
}
|
|
1308
|
+
public int getPreviewWidth() {
|
|
1309
|
+
return previewContainer != null ? previewContainer.getWidth() : 0;
|
|
1310
|
+
}
|
|
1311
|
+
public int getPreviewHeight() {
|
|
1312
|
+
return previewContainer != null ? previewContainer.getHeight() : 0;
|
|
1313
|
+
}
|
|
1314
|
+
public void setPreviewSize(int x, int y, int width, int height) {
|
|
1315
|
+
setPreviewSize(x, y, width, height, null);
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
public void setPreviewSize(int x, int y, int width, int height, Runnable callback) {
|
|
1319
|
+
if (previewContainer == null) {
|
|
1320
|
+
if (callback != null) callback.run();
|
|
1321
|
+
return;
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
// Ensure this runs on the main UI thread
|
|
1325
|
+
mainExecutor.execute(() -> {
|
|
1326
|
+
ViewGroup.LayoutParams layoutParams = previewContainer.getLayoutParams();
|
|
1327
|
+
if (layoutParams instanceof ViewGroup.MarginLayoutParams) {
|
|
1328
|
+
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) layoutParams;
|
|
1329
|
+
|
|
1330
|
+
// Only add insets for positioning coordinates, not for full-screen sizes
|
|
1331
|
+
int webViewTopInset = getWebViewTopInset();
|
|
1332
|
+
int webViewLeftInset = getWebViewLeftInset();
|
|
1333
|
+
|
|
1334
|
+
// Handle positioning - preserve current values if new values are not specified (negative)
|
|
1335
|
+
if (x >= 0) {
|
|
1336
|
+
// Don't add insets if this looks like a calculated full-screen coordinate (x=0, y=0)
|
|
1337
|
+
if (x == 0 && y == 0) {
|
|
1338
|
+
params.leftMargin = x;
|
|
1339
|
+
Log.d(TAG, "setPreviewSize: Full-screen mode - keeping x=0 without insets");
|
|
1340
|
+
} else {
|
|
1341
|
+
params.leftMargin = x + webViewLeftInset;
|
|
1342
|
+
Log.d(TAG, "setPreviewSize: Positioned mode - x=" + x + " + inset=" + webViewLeftInset + " = " + (x + webViewLeftInset));
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
if (y >= 0) {
|
|
1346
|
+
// Don't add insets if this looks like a calculated full-screen coordinate (x=0, y=0)
|
|
1347
|
+
if (x == 0 && y == 0) {
|
|
1348
|
+
params.topMargin = y;
|
|
1349
|
+
Log.d(TAG, "setPreviewSize: Full-screen mode - keeping y=0 without insets");
|
|
1350
|
+
} else {
|
|
1351
|
+
params.topMargin = y + webViewTopInset;
|
|
1352
|
+
Log.d(TAG, "setPreviewSize: Positioned mode - y=" + y + " + inset=" + webViewTopInset + " = " + (y + webViewTopInset));
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
if (width > 0) params.width = width;
|
|
1356
|
+
if (height > 0) params.height = height;
|
|
1357
|
+
|
|
1358
|
+
previewContainer.setLayoutParams(params);
|
|
1359
|
+
previewContainer.requestLayout();
|
|
1360
|
+
|
|
1361
|
+
Log.d(TAG, "setPreviewSize: Updated to " + params.width + "x" + params.height + " at (" + params.leftMargin + "," + params.topMargin + ")");
|
|
1362
|
+
|
|
1363
|
+
// Update session config to reflect actual layout
|
|
1364
|
+
if (sessionConfig != null) {
|
|
1365
|
+
String currentAspectRatio = sessionConfig.getAspectRatio();
|
|
1366
|
+
|
|
1367
|
+
// Calculate aspect ratio from actual dimensions if both width and height are provided
|
|
1368
|
+
String calculatedAspectRatio = currentAspectRatio;
|
|
1369
|
+
if (params.width > 0 && params.height > 0) {
|
|
1370
|
+
// Always use larger dimension / smaller dimension for consistent comparison
|
|
1371
|
+
float ratio = Math.max(params.width, params.height) / (float) Math.min(params.width, params.height);
|
|
1372
|
+
// Standard ratios: 16:9 ≈ 1.778, 4:3 ≈ 1.333
|
|
1373
|
+
float ratio16_9 = 16f / 9f; // 1.778
|
|
1374
|
+
float ratio4_3 = 4f / 3f; // 1.333
|
|
1375
|
+
|
|
1376
|
+
// Determine closest standard aspect ratio
|
|
1377
|
+
if (Math.abs(ratio - ratio16_9) < Math.abs(ratio - ratio4_3)) {
|
|
1378
|
+
calculatedAspectRatio = "16:9";
|
|
1379
|
+
} else {
|
|
1380
|
+
calculatedAspectRatio = "4:3";
|
|
1381
|
+
}
|
|
1382
|
+
Log.d(TAG, "setPreviewSize: Calculated aspect ratio from " + params.width + "x" + params.height + " = " + calculatedAspectRatio + " (normalized ratio=" + ratio + ")");
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
sessionConfig = new CameraSessionConfiguration(
|
|
1386
|
+
sessionConfig.getDeviceId(),
|
|
1387
|
+
sessionConfig.getPosition(),
|
|
1388
|
+
params.leftMargin,
|
|
1389
|
+
params.topMargin,
|
|
1390
|
+
params.width,
|
|
1391
|
+
params.height,
|
|
1392
|
+
sessionConfig.getPaddingBottom(),
|
|
1393
|
+
sessionConfig.getToBack(),
|
|
1394
|
+
sessionConfig.getStoreToFile(),
|
|
1395
|
+
sessionConfig.getEnableOpacity(),
|
|
1396
|
+
sessionConfig.getEnableZoom(),
|
|
1397
|
+
sessionConfig.getDisableExifHeaderStripping(),
|
|
1398
|
+
sessionConfig.getDisableAudio(),
|
|
1399
|
+
sessionConfig.getZoomFactor(),
|
|
1400
|
+
calculatedAspectRatio,
|
|
1401
|
+
sessionConfig.getGridMode()
|
|
1402
|
+
);
|
|
1403
|
+
|
|
1404
|
+
// If aspect ratio changed due to size update, rebind camera
|
|
1405
|
+
if (isRunning && !Objects.equals(currentAspectRatio, calculatedAspectRatio)) {
|
|
1406
|
+
Log.d(TAG, "setPreviewSize: Aspect ratio changed from " + currentAspectRatio + " to " + calculatedAspectRatio + ", rebinding camera");
|
|
1407
|
+
bindCameraUseCases();
|
|
1408
|
+
|
|
1409
|
+
// Wait for camera rebinding to complete, then call callback
|
|
1410
|
+
if (callback != null) {
|
|
1411
|
+
previewContainer.post(() -> previewContainer.post(callback));
|
|
1412
|
+
}
|
|
1413
|
+
} else {
|
|
1414
|
+
// No camera rebinding needed, wait for layout to complete then call callback
|
|
1415
|
+
if (callback != null) {
|
|
1416
|
+
previewContainer.post(callback);
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
} else {
|
|
1420
|
+
// No sessionConfig, just wait for layout then call callback
|
|
1421
|
+
if (callback != null) {
|
|
1422
|
+
previewContainer.post(callback);
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
} else {
|
|
1426
|
+
Log.w(TAG, "setPreviewSize: Cannot set margins on layout params of type " + layoutParams.getClass().getSimpleName());
|
|
1427
|
+
// Fallback: just set width and height if specified
|
|
1428
|
+
if (width > 0) layoutParams.width = width;
|
|
1429
|
+
if (height > 0) layoutParams.height = height;
|
|
1430
|
+
previewContainer.setLayoutParams(layoutParams);
|
|
1431
|
+
previewContainer.requestLayout();
|
|
1432
|
+
|
|
1433
|
+
// Wait for layout then call callback
|
|
1434
|
+
if (callback != null) {
|
|
1435
|
+
previewContainer.post(callback);
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
});
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
private void updatePreviewLayoutForAspectRatio(String aspectRatio) {
|
|
1442
|
+
updatePreviewLayoutForAspectRatio(aspectRatio, null, null);
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
private void updatePreviewLayoutForAspectRatio(String aspectRatio, Float x, Float y) {
|
|
1446
|
+
if (previewContainer == null || aspectRatio == null) return;
|
|
1447
|
+
|
|
1448
|
+
// Parse aspect ratio
|
|
1449
|
+
String[] ratios = aspectRatio.split(":");
|
|
1450
|
+
if (ratios.length != 2) return;
|
|
1451
|
+
|
|
1452
|
+
try {
|
|
1453
|
+
// For camera, use portrait orientation: 4:3 becomes 3:4, 16:9 becomes 9:16
|
|
1454
|
+
float ratio = Float.parseFloat(ratios[1]) / Float.parseFloat(ratios[0]);
|
|
1455
|
+
|
|
1456
|
+
// Get available space from webview dimensions
|
|
1457
|
+
int availableWidth = webView.getWidth();
|
|
1458
|
+
int availableHeight = webView.getHeight();
|
|
1459
|
+
|
|
1460
|
+
// Calculate position and size
|
|
1461
|
+
int finalX, finalY, finalWidth, finalHeight;
|
|
1462
|
+
|
|
1463
|
+
if (x != null && y != null) {
|
|
1464
|
+
// Account for WebView insets from edge-to-edge support
|
|
1465
|
+
int webViewTopInset = getWebViewTopInset();
|
|
1466
|
+
int webViewLeftInset = getWebViewLeftInset();
|
|
1467
|
+
|
|
1468
|
+
// Use provided coordinates with boundary checking, adjusted for insets
|
|
1469
|
+
finalX = Math.max(0, Math.min(x.intValue() + webViewLeftInset, availableWidth));
|
|
1470
|
+
finalY = Math.max(0, Math.min(y.intValue() + webViewTopInset, availableHeight));
|
|
1471
|
+
|
|
1472
|
+
// Calculate maximum available space from the given position
|
|
1473
|
+
int maxWidth = availableWidth - finalX;
|
|
1474
|
+
int maxHeight = availableHeight - finalY;
|
|
1475
|
+
|
|
1476
|
+
// Calculate optimal size while maintaining aspect ratio within available space
|
|
1477
|
+
finalWidth = maxWidth;
|
|
1478
|
+
finalHeight = (int) (maxWidth / ratio);
|
|
1479
|
+
|
|
1480
|
+
if (finalHeight > maxHeight) {
|
|
1481
|
+
// Height constraint is tighter, fit by height
|
|
1482
|
+
finalHeight = maxHeight;
|
|
1483
|
+
finalWidth = (int) (maxHeight * ratio);
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1486
|
+
// Ensure final position stays within bounds
|
|
1487
|
+
finalX = Math.max(0, Math.min(finalX, availableWidth - finalWidth));
|
|
1488
|
+
finalY = Math.max(0, Math.min(finalY, availableHeight - finalHeight));
|
|
1489
|
+
} else {
|
|
1490
|
+
// Auto-center the view
|
|
1491
|
+
// Calculate size based on aspect ratio, using a reasonable base size
|
|
1492
|
+
// Use 80% of available space to ensure aspect ratio differences are visible
|
|
1493
|
+
int maxAvailableWidth = (int) (availableWidth * 0.8);
|
|
1494
|
+
int maxAvailableHeight = (int) (availableHeight * 0.8);
|
|
1495
|
+
|
|
1496
|
+
// Start with width-based calculation
|
|
1497
|
+
finalWidth = maxAvailableWidth;
|
|
1498
|
+
finalHeight = (int) (finalWidth / ratio);
|
|
1499
|
+
|
|
1500
|
+
// If height exceeds available space, use height-based calculation
|
|
1501
|
+
if (finalHeight > maxAvailableHeight) {
|
|
1502
|
+
finalHeight = maxAvailableHeight;
|
|
1503
|
+
finalWidth = (int) (finalHeight * ratio);
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
// Center the view
|
|
1507
|
+
finalX = (availableWidth - finalWidth) / 2;
|
|
1508
|
+
finalY = (availableHeight - finalHeight) / 2;
|
|
1509
|
+
|
|
1510
|
+
Log.d(TAG, "updatePreviewLayoutForAspectRatio: Auto-center mode - ratio=" + ratio +
|
|
1511
|
+
", calculated size=" + finalWidth + "x" + finalHeight +
|
|
1512
|
+
", available=" + availableWidth + "x" + availableHeight);
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1515
|
+
// Update layout params
|
|
1516
|
+
ViewGroup.LayoutParams currentParams = previewContainer.getLayoutParams();
|
|
1517
|
+
if (currentParams instanceof ViewGroup.MarginLayoutParams) {
|
|
1518
|
+
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) currentParams;
|
|
1519
|
+
params.width = finalWidth;
|
|
1520
|
+
params.height = finalHeight;
|
|
1521
|
+
params.leftMargin = finalX;
|
|
1522
|
+
params.topMargin = finalY;
|
|
1523
|
+
previewContainer.setLayoutParams(params);
|
|
1524
|
+
previewContainer.requestLayout();
|
|
1525
|
+
Log.d(TAG, "updatePreviewLayoutForAspectRatio: Updated to " + finalWidth + "x" + finalHeight + " at (" + finalX + "," + finalY + ")");
|
|
1526
|
+
}
|
|
1527
|
+
} catch (NumberFormatException e) {
|
|
1528
|
+
Log.e(TAG, "Invalid aspect ratio format: " + aspectRatio, e);
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
|
|
1532
|
+
private void updatePreviewLayout() {
|
|
1533
|
+
if (previewContainer == null || sessionConfig == null) return;
|
|
1534
|
+
|
|
1535
|
+
String aspectRatio = sessionConfig.getAspectRatio();
|
|
1536
|
+
if (aspectRatio == null) return;
|
|
1537
|
+
|
|
1538
|
+
updatePreviewLayoutForAspectRatio(aspectRatio);
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
private int getWebViewTopInset() {
|
|
1542
|
+
try {
|
|
1543
|
+
if (webView != null) {
|
|
1544
|
+
ViewGroup.LayoutParams layoutParams = webView.getLayoutParams();
|
|
1545
|
+
if (layoutParams instanceof ViewGroup.MarginLayoutParams) {
|
|
1546
|
+
return ((ViewGroup.MarginLayoutParams) layoutParams).topMargin;
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
} catch (Exception e) {
|
|
1550
|
+
Log.w(TAG, "Failed to get WebView top inset", e);
|
|
1551
|
+
}
|
|
1552
|
+
return 0;
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
private int getWebViewLeftInset() {
|
|
1556
|
+
try {
|
|
1557
|
+
if (webView != null) {
|
|
1558
|
+
ViewGroup.LayoutParams layoutParams = webView.getLayoutParams();
|
|
1559
|
+
if (layoutParams instanceof ViewGroup.MarginLayoutParams) {
|
|
1560
|
+
return ((ViewGroup.MarginLayoutParams) layoutParams).leftMargin;
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1563
|
+
} catch (Exception e) {
|
|
1564
|
+
Log.w(TAG, "Failed to get WebView left inset", e);
|
|
1565
|
+
}
|
|
1566
|
+
return 0;
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1569
|
+
/**
|
|
1570
|
+
* Get the current preview position and size in DP units (without insets)
|
|
1571
|
+
*/
|
|
1572
|
+
public int[] getCurrentPreviewBounds() {
|
|
1573
|
+
if (previewContainer == null) {
|
|
1574
|
+
return new int[]{0, 0, 0, 0}; // x, y, width, height
|
|
1575
|
+
}
|
|
1576
|
+
|
|
1577
|
+
ViewGroup.LayoutParams layoutParams = previewContainer.getLayoutParams();
|
|
1578
|
+
int x = 0, y = 0, width = 0, height = 0;
|
|
1579
|
+
|
|
1580
|
+
if (layoutParams instanceof ViewGroup.MarginLayoutParams) {
|
|
1581
|
+
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) layoutParams;
|
|
1582
|
+
|
|
1583
|
+
// Remove insets to get original coordinates in DP
|
|
1584
|
+
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
|
|
1585
|
+
float pixelRatio = metrics.density;
|
|
1586
|
+
|
|
1587
|
+
int webViewTopInset = getWebViewTopInset();
|
|
1588
|
+
int webViewLeftInset = getWebViewLeftInset();
|
|
1589
|
+
|
|
1590
|
+
x = Math.max(0, (int) ((params.leftMargin - webViewLeftInset) / pixelRatio));
|
|
1591
|
+
y = Math.max(0, (int) ((params.topMargin - webViewTopInset) / pixelRatio));
|
|
1592
|
+
width = (int) (params.width / pixelRatio);
|
|
1593
|
+
height = (int) (params.height / pixelRatio);
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
return new int[]{x, y, width, height};
|
|
1597
|
+
}
|
|
1148
1598
|
}
|
|
@@ -34,8 +34,10 @@ public class GridOverlayView extends View {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
public void setGridMode(String mode) {
|
|
37
|
+
String previousMode = this.gridMode;
|
|
37
38
|
this.gridMode = mode != null ? mode : "none";
|
|
38
39
|
setVisibility("none".equals(this.gridMode) ? View.GONE : View.VISIBLE);
|
|
40
|
+
android.util.Log.d("GridOverlayView", "setGridMode: Changed from '" + previousMode + "' to '" + this.gridMode + "', visibility: " + ("none".equals(this.gridMode) ? "GONE" : "VISIBLE"));
|
|
39
41
|
invalidate();
|
|
40
42
|
}
|
|
41
43
|
|
package/dist/docs.json
CHANGED
|
@@ -141,23 +141,23 @@
|
|
|
141
141
|
},
|
|
142
142
|
{
|
|
143
143
|
"name": "setAspectRatio",
|
|
144
|
-
"signature": "(options: { aspectRatio: '4:3' | '16:9'; }) => Promise<
|
|
144
|
+
"signature": "(options: { aspectRatio: '4:3' | '16:9'; x?: number; y?: number; }) => Promise<{ width: number; height: number; x: number; y: number; }>",
|
|
145
145
|
"parameters": [
|
|
146
146
|
{
|
|
147
147
|
"name": "options",
|
|
148
|
-
"docs": "- The desired aspect ratio.",
|
|
149
|
-
"type": "{ aspectRatio: '4:3' | '16:9'; }"
|
|
148
|
+
"docs": "- The desired aspect ratio and optional position.\n- aspectRatio: The desired aspect ratio ('4:3' or '16:9')\n- x: Optional x coordinate for positioning. If not provided, view will be auto-centered horizontally.\n- y: Optional y coordinate for positioning. If not provided, view will be auto-centered vertically.",
|
|
149
|
+
"type": "{ aspectRatio: '4:3' | '16:9'; x?: number | undefined; y?: number | undefined; }"
|
|
150
150
|
}
|
|
151
151
|
],
|
|
152
|
-
"returns": "Promise<
|
|
152
|
+
"returns": "Promise<{ width: number; height: number; x: number; y: number; }>",
|
|
153
153
|
"tags": [
|
|
154
154
|
{
|
|
155
155
|
"name": "param",
|
|
156
|
-
"text": "options - The desired aspect ratio."
|
|
156
|
+
"text": "options - The desired aspect ratio and optional position.\n- aspectRatio: The desired aspect ratio ('4:3' or '16:9')\n- x: Optional x coordinate for positioning. If not provided, view will be auto-centered horizontally.\n- y: Optional y coordinate for positioning. If not provided, view will be auto-centered vertically."
|
|
157
157
|
},
|
|
158
158
|
{
|
|
159
159
|
"name": "returns",
|
|
160
|
-
"text": "A promise that resolves
|
|
160
|
+
"text": "A promise that resolves with the actual preview dimensions and position."
|
|
161
161
|
},
|
|
162
162
|
{
|
|
163
163
|
"name": "since",
|
|
@@ -583,6 +583,45 @@
|
|
|
583
583
|
"docs": "Gets the ID of the currently active camera device.",
|
|
584
584
|
"complexTypes": [],
|
|
585
585
|
"slug": "getdeviceid"
|
|
586
|
+
},
|
|
587
|
+
{
|
|
588
|
+
"name": "getPreviewSize",
|
|
589
|
+
"signature": "() => Promise<{ x: number; y: number; width: number; height: number; }>",
|
|
590
|
+
"parameters": [],
|
|
591
|
+
"returns": "Promise<{ x: number; y: number; width: number; height: number; }>",
|
|
592
|
+
"tags": [
|
|
593
|
+
{
|
|
594
|
+
"name": "returns"
|
|
595
|
+
}
|
|
596
|
+
],
|
|
597
|
+
"docs": "Gets the current preview size and position.",
|
|
598
|
+
"complexTypes": [],
|
|
599
|
+
"slug": "getpreviewsize"
|
|
600
|
+
},
|
|
601
|
+
{
|
|
602
|
+
"name": "setPreviewSize",
|
|
603
|
+
"signature": "(options: { x: number; y: number; width: number; height: number; }) => Promise<{ width: number; height: number; x: number; y: number; }>",
|
|
604
|
+
"parameters": [
|
|
605
|
+
{
|
|
606
|
+
"name": "options",
|
|
607
|
+
"docs": "The new position and dimensions.",
|
|
608
|
+
"type": "{ x: number; y: number; width: number; height: number; }"
|
|
609
|
+
}
|
|
610
|
+
],
|
|
611
|
+
"returns": "Promise<{ width: number; height: number; x: number; y: number; }>",
|
|
612
|
+
"tags": [
|
|
613
|
+
{
|
|
614
|
+
"name": "param",
|
|
615
|
+
"text": "options The new position and dimensions."
|
|
616
|
+
},
|
|
617
|
+
{
|
|
618
|
+
"name": "returns",
|
|
619
|
+
"text": "A promise that resolves with the actual preview dimensions and position."
|
|
620
|
+
}
|
|
621
|
+
],
|
|
622
|
+
"docs": "Sets the preview size and position.",
|
|
623
|
+
"complexTypes": [],
|
|
624
|
+
"slug": "setpreviewsize"
|
|
586
625
|
}
|
|
587
626
|
],
|
|
588
627
|
"properties": []
|
|
@@ -675,7 +714,7 @@
|
|
|
675
714
|
"name": "since"
|
|
676
715
|
}
|
|
677
716
|
],
|
|
678
|
-
"docs": "The aspect ratio of the camera preview, '4:3' or '16:9'.\
|
|
717
|
+
"docs": "The aspect ratio of the camera preview, '4:3' or '16:9' or 'fill'.\nCannot be set if width or height is provided, otherwise the call will be rejected.\nUse setPreviewSize to adjust size after starting.",
|
|
679
718
|
"complexTypes": [],
|
|
680
719
|
"type": "'4:3' | '16:9' | 'fill' | undefined"
|
|
681
720
|
},
|