From ef2c66a16b2e2b50bcee99f57cd6f47def408f76 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sun, 15 Feb 2026 20:33:14 +0000 Subject: [PATCH] refactor(camera): centralize JPEG transcode cap --- .../ios/Sources/Camera/CameraController.swift | 18 +++++-------- .../OpenClaw/CameraCaptureService.swift | 26 ++++++++++--------- .../Sources/OpenClawKit/PhotoCapture.swift | 19 ++++++++++++++ 3 files changed, 40 insertions(+), 23 deletions(-) create mode 100644 apps/shared/OpenClawKit/Sources/OpenClawKit/PhotoCapture.swift diff --git a/apps/ios/Sources/Camera/CameraController.swift b/apps/ios/Sources/Camera/CameraController.swift index e76dbeeabb..1e9c10bc44 100644 --- a/apps/ios/Sources/Camera/CameraController.swift +++ b/apps/ios/Sources/Camera/CameraController.swift @@ -93,14 +93,10 @@ actor CameraController { } withExtendedLifetime(delegate) {} - let maxPayloadBytes = 5 * 1024 * 1024 - // Base64 inflates payloads by ~4/3; cap encoded bytes so the payload stays under 5MB (API limit). - let maxEncodedBytes = (maxPayloadBytes / 4) * 3 - let res = try JPEGTranscoder.transcodeToJPEG( - imageData: rawData, + let res = try PhotoCapture.transcodeJPEGForGateway( + rawData: rawData, maxWidthPx: maxWidth, - quality: quality, - maxBytes: maxEncodedBytes) + quality: quality) return ( format: format.rawValue, @@ -335,8 +331,8 @@ private final class PhotoCaptureDelegate: NSObject, AVCapturePhotoCaptureDelegat func photoOutput( _ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, - error: Error?) - { + error: Error? + ) { guard !self.didResume else { return } self.didResume = true @@ -364,8 +360,8 @@ private final class PhotoCaptureDelegate: NSObject, AVCapturePhotoCaptureDelegat func photoOutput( _ output: AVCapturePhotoOutput, didFinishCaptureFor resolvedSettings: AVCaptureResolvedPhotoSettings, - error: Error?) - { + error: Error? + ) { guard let error else { return } guard !self.didResume else { return } self.didResume = true diff --git a/apps/macos/Sources/OpenClaw/CameraCaptureService.swift b/apps/macos/Sources/OpenClaw/CameraCaptureService.swift index cfc8c2cde5..24717ec553 100644 --- a/apps/macos/Sources/OpenClaw/CameraCaptureService.swift +++ b/apps/macos/Sources/OpenClaw/CameraCaptureService.swift @@ -106,14 +106,16 @@ actor CameraCaptureService { } withExtendedLifetime(delegate) {} - let maxPayloadBytes = 5 * 1024 * 1024 - // Base64 inflates payloads by ~4/3; cap encoded bytes so the payload stays under 5MB (API limit). - let maxEncodedBytes = (maxPayloadBytes / 4) * 3 - let res = try JPEGTranscoder.transcodeToJPEG( - imageData: rawData, - maxWidthPx: maxWidth, - quality: quality, - maxBytes: maxEncodedBytes) + let res: (data: Data, widthPx: Int, heightPx: Int) + do { + res = try PhotoCapture.transcodeJPEGForGateway( + rawData: rawData, + maxWidthPx: maxWidth, + quality: quality) + } catch { + throw CameraError.captureFailed(error.localizedDescription) + } + return (data: res.data, size: CGSize(width: res.widthPx, height: res.heightPx)) } @@ -355,8 +357,8 @@ private final class PhotoCaptureDelegate: NSObject, AVCapturePhotoCaptureDelegat func photoOutput( _ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, - error: Error?) - { + error: Error? + ) { guard !self.didResume, let cont else { return } self.didResume = true self.cont = nil @@ -378,8 +380,8 @@ private final class PhotoCaptureDelegate: NSObject, AVCapturePhotoCaptureDelegat func photoOutput( _ output: AVCapturePhotoOutput, didFinishCaptureFor resolvedSettings: AVCaptureResolvedPhotoSettings, - error: Error?) - { + error: Error? + ) { guard let error else { return } guard !self.didResume, let cont else { return } self.didResume = true diff --git a/apps/shared/OpenClawKit/Sources/OpenClawKit/PhotoCapture.swift b/apps/shared/OpenClawKit/Sources/OpenClawKit/PhotoCapture.swift new file mode 100644 index 0000000000..b5f00d3475 --- /dev/null +++ b/apps/shared/OpenClawKit/Sources/OpenClawKit/PhotoCapture.swift @@ -0,0 +1,19 @@ +import Foundation + +public enum PhotoCapture { + public static func transcodeJPEGForGateway( + rawData: Data, + maxWidthPx: Int, + quality: Double, + maxPayloadBytes: Int = 5 * 1024 * 1024 + ) throws -> (data: Data, widthPx: Int, heightPx: Int) { + // Base64 inflates payloads by ~4/3; cap encoded bytes so the payload stays under maxPayloadBytes (API limit). + let maxEncodedBytes = (maxPayloadBytes / 4) * 3 + return try JPEGTranscoder.transcodeToJPEG( + imageData: rawData, + maxWidthPx: maxWidthPx, + quality: quality, + maxBytes: maxEncodedBytes) + } +} +