From 374af50accb9312c0dc5667fce1cf4b78603e709 Mon Sep 17 00:00:00 2001 From: TZGyn Date: Wed, 12 Aug 2026 16:14:39 +0800 Subject: [PATCH] Capture at full retina resolution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ScreenCaptureKit stream was sized in points at 1x scale, so retina displays produced half-resolution captures that appeared pixelated. Request backingScale x pixels and derive the crop scale from the actual captured image dimensions. 💘 Generated with Crush Assisted-by: Crush:deepseek-v4-flash-0731 --- Sources/Kapture/CaptureController.swift | 15 +++++++++++---- build-app.sh | 4 ++-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/Sources/Kapture/CaptureController.swift b/Sources/Kapture/CaptureController.swift index 0dd2182..08e3f79 100644 --- a/Sources/Kapture/CaptureController.swift +++ b/Sources/Kapture/CaptureController.swift @@ -86,8 +86,10 @@ final class ScreenCapture { @available(macOS 14.0, *) private func crop(_ image: CGImage, to rect: NSRect, display: SCDisplay) -> CGImage? { - let scaleX = CGFloat(display.width) / display.frame.width - let scaleY = CGFloat(display.height) / display.frame.height + // Scale from the actual captured image dimensions, which reflect the + // stream's pixel output (retina => 2x, non-retina => 1x). + let scaleX = CGFloat(image.width) / display.frame.width + let scaleY = CGFloat(image.height) / display.frame.height let cgRect = CGRect( x: rect.minX, y: rect.minY, @@ -133,8 +135,13 @@ final class ScreenCapture { let excluded = content.windows.filter { excludedSet.contains($0.windowID) } let filter = SCContentFilter(display: display, excludingWindows: excluded) let config = SCStreamConfiguration() - config.width = Int(display.width) - config.height = Int(display.height) + // width/height are in points. Use the display's backing scale so + // retina captures come out at full pixel resolution. + let backingScale = NSScreen.screens.first(where: { $0.frame.contains( + NSPoint(x: rect.midX, y: rect.midY) + ) })?.backingScaleFactor ?? 2 + config.width = Int(display.frame.width * backingScale) + config.height = Int(display.frame.height * backingScale) config.showsCursor = true guard let image = try? await SCScreenshotManager.captureImage(contentFilter: filter, configuration: config) else { diff --git a/build-app.sh b/build-app.sh index eb09d74..879951f 100755 --- a/build-app.sh +++ b/build-app.sh @@ -108,9 +108,9 @@ cat > "$APP/Contents/Info.plist" <<'PLIST' CFBundleIconFile Icon CFBundleShortVersionString - 1.1.1 + 1.1.2 CFBundleVersion - 11 + 12 LSUIElement NSHighResolutionCapable