diff --git a/Sources/Kapture/CaptureController.swift b/Sources/Kapture/CaptureController.swift
index 32f2ea1..95e0691 100644
--- a/Sources/Kapture/CaptureController.swift
+++ b/Sources/Kapture/CaptureController.swift
@@ -301,8 +301,11 @@ final class CaptureController: NSObject {
}
return event
}
- // Drag: grow the marquee
+ // Drag: grow the marquee — but only after real movement, so a
+ // click's micro-jitter keeps the hovered window eligible.
guard let start = marqueeStart else { return nil }
+ let distance = hypot(appKitPoint.x - start.x, appKitPoint.y - start.y)
+ guard distance >= 4 else { return nil }
let rect = NSRect(
x: min(start.x, appKitPoint.x),
y: min(start.y, appKitPoint.y),
@@ -443,28 +446,43 @@ final class ScreenCapture {
let detected = Self.detectCornerRadius(of: result)
let radius = min(max((detected.map { $0 * 1.23 + 2.6 }) ?? (10 * scaleX), 4), 40)
CaptureController.log("corners: detected=\(detected.map { String(format: "%.1f", $0) } ?? "nil") using=\(Int(radius))px")
+ // Anti-aliased gray mask: supersample 3x, downsample, then draw
+ // the image through it ONCE at 1x (no content resampling blur).
let ss = 3
let W = result.width * ss, H = result.height * ss
- guard let hiCtx = CGContext(
+ guard let hiMask = CGContext(
data: nil, width: W, height: H,
bitsPerComponent: 8, bytesPerRow: 0,
- space: CGColorSpaceCreateDeviceRGB(),
- bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue
+ space: CGColorSpaceCreateDeviceGray(),
+ bitmapInfo: CGImageAlphaInfo.none.rawValue
) else { return result }
- hiCtx.addPath(CGPath(roundedRect: CGRect(x: 0, y: 0, width: W, height: H), cornerWidth: radius * CGFloat(ss), cornerHeight: radius * CGFloat(ss), transform: nil))
- hiCtx.clip()
- hiCtx.interpolationQuality = .high
- hiCtx.draw(result, in: CGRect(x: 0, y: 0, width: W, height: H))
- guard let hi = hiCtx.makeImage(),
- let downCtx = CGContext(
+ hiMask.setFillColor(CGColor(gray: 1, alpha: 1))
+ hiMask.fill(CGRect(x: 0, y: 0, width: W, height: H))
+ hiMask.setFillColor(CGColor(gray: 0, alpha: 1))
+ let cornerPath = CGMutablePath()
+ cornerPath.addRect(CGRect(x: 0, y: 0, width: W, height: H))
+ cornerPath.addRoundedRect(in: CGRect(x: 0, y: 0, width: W, height: H), cornerWidth: radius * CGFloat(ss), cornerHeight: radius * CGFloat(ss), transform: .identity)
+ hiMask.addPath(cornerPath)
+ hiMask.fillPath(using: .evenOdd)
+ guard let hiMaskImg = hiMask.makeImage(),
+ let downMask = CGContext(
+ data: nil, width: result.width, height: result.height,
+ bitsPerComponent: 8, bytesPerRow: 0,
+ space: CGColorSpaceCreateDeviceGray(),
+ bitmapInfo: CGImageAlphaInfo.none.rawValue
+ ) else { return result }
+ downMask.interpolationQuality = .high
+ downMask.draw(hiMaskImg, in: CGRect(x: 0, y: 0, width: result.width, height: result.height))
+ guard let mask1x = downMask.makeImage(),
+ let ctx = CGContext(
data: nil, width: result.width, height: result.height,
bitsPerComponent: 8, bytesPerRow: 0,
space: CGColorSpaceCreateDeviceRGB(),
bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue
) else { return result }
- downCtx.interpolationQuality = .high
- downCtx.draw(hi, in: CGRect(x: 0, y: 0, width: result.width, height: result.height))
- if let masked = downCtx.makeImage() {
+ ctx.clip(to: CGRect(x: 0, y: 0, width: result.width, height: result.height), mask: mask1x)
+ ctx.draw(result, in: CGRect(x: 0, y: 0, width: result.width, height: result.height))
+ if let masked = ctx.makeImage() {
result = masked
}
}
diff --git a/build-app.sh b/build-app.sh
index 3676233..04ab41e 100755
--- a/build-app.sh
+++ b/build-app.sh
@@ -108,9 +108,9 @@ cat > "$APP/Contents/Info.plist" <<'PLIST'
CFBundleIconFile
Icon
CFBundleShortVersionString
- 1.8.5
+ 1.8.6
CFBundleVersion
- 85
+ 86
LSUIElement
NSHighResolutionCapable