--- a/android/src/main/java/app/capgo/capacitor/camera/preview/CameraXView.java +++ b/android/src/main/java/app/capgo/capacitor/camera/preview/CameraXView.java @@ -389,0 +390,4 @@ + public Bitmap getPreviewBitmap() { + return previewView == null ? null : previewView.getBitmap(); + } + @@ -1095 +1099 @@ - .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY) + .setCaptureMode(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY) @@ -2054,2 +2058,3 @@ - // Set rotation from accelerometer for device orientation regardless of lock - int rotation = getRotationFromAccelerometer(); + // Match the visible finder, including rotation lock. + int rotation = previewView != null && previewView.getDisplay() != null + ? previewView.getDisplay().getRotation() : android.view.Surface.ROTATION_0; --- a/android/src/main/java/app/capgo/capacitor/camera/preview/CameraPreview.java +++ b/android/src/main/java/app/capgo/capacitor/camera/preview/CameraPreview.java @@ -521,0 +522,32 @@ + } + + @PluginMethod + public void capturePreview(PluginCall call) { + getActivity().runOnUiThread(() -> { + try { + if (cameraXView == null || !cameraXView.isRunning()) { + call.reject("Camera is not running"); + return; + } + final android.graphics.Bitmap bitmap = cameraXView.getPreviewBitmap(); + if (bitmap == null) { call.reject("Preview is not ready"); return; } + new Thread(() -> { + android.graphics.Bitmap small = null; + try { + float scale = Math.min(1f, 640f / Math.max(bitmap.getWidth(), bitmap.getHeight())); + small = android.graphics.Bitmap.createScaledBitmap(bitmap, + Math.max(1, Math.round(bitmap.getWidth() * scale)), + Math.max(1, Math.round(bitmap.getHeight() * scale)), true); + java.io.ByteArrayOutputStream bytes = new java.io.ByteArrayOutputStream(); + small.compress(android.graphics.Bitmap.CompressFormat.JPEG, 72, bytes); + JSObject result = new JSObject(); + result.put("value", android.util.Base64.encodeToString(bytes.toByteArray(), android.util.Base64.NO_WRAP)); + call.resolve(result); + } catch (Exception e) { call.reject("Preview snapshot failed", e); } + finally { + if (small != null && small != bitmap) small.recycle(); + bitmap.recycle(); + } + }, "preview-backdrop").start(); + } catch (Exception e) { call.reject("Preview snapshot failed", e); } + }); --- a/ios/Sources/CapgoCameraPreviewPlugin/CameraController.swift +++ b/ios/Sources/CapgoCameraPreviewPlugin/CameraController.swift @@ -630,0 +631 @@ + self.photoOutput?.maxPhotoQualityPrioritization = .quality @@ -1343 +1344 @@ - let captureOrientation = self.getPhysicalOrientation() + let captureOrientation = self.getVideoOrientation() // Match the visible finder, including rotation lock. --- a/ios/Sources/CapgoCameraPreviewPlugin/Plugin.swift +++ b/ios/Sources/CapgoCameraPreviewPlugin/Plugin.swift @@ -45,0 +46 @@ + CAPPluginMethod(name: "capturePreview", returnType: CAPPluginReturnPromise), @@ -1533,0 +1535,18 @@ + @objc func capturePreview(_ call: CAPPluginCall) { + self.cameraController.captureSample { image, error in + guard let image = image else { call.reject("Preview is not ready"); return } + let scale = min(1, 640 / max(image.size.width, image.size.height)) + let size = CGSize(width: max(1, image.size.width * scale), height: max(1, image.size.height * scale)) + let format = UIGraphicsImageRendererFormat() + format.scale = 1 + format.opaque = true + let preview = UIGraphicsImageRenderer(size: size, format: format).image { _ in + image.draw(in: CGRect(origin: .zero, size: size)) + } + guard let data = preview.jpegData(compressionQuality: 0.72) else { + call.reject("Preview snapshot failed"); return + } + call.resolve(["value": data.base64EncodedString()]) + } + } +