57 lines
2.3 KiB
Swift
57 lines
2.3 KiB
Swift
// ScreenGeometry.swift
|
|
// GreenshotMac
|
|
//
|
|
// Conversions between AppKit's bottom-left global space and CoreGraphics'
|
|
// top-left global space, plus display lookups.
|
|
|
|
import AppKit
|
|
|
|
enum ScreenGeometry {
|
|
|
|
/// Height of the primary display, the anchor for both coordinate systems.
|
|
static var primaryHeight: CGFloat {
|
|
NSScreen.screens.first(where: { $0.frame.origin == .zero })?.frame.height
|
|
?? NSScreen.screens.first?.frame.height
|
|
?? 0
|
|
}
|
|
|
|
/// AppKit global rect (bottom-left origin) to CoreGraphics global rect (top-left origin).
|
|
static func cgRect(fromAppKit rect: CGRect) -> CGRect {
|
|
CGRect(x: rect.origin.x,
|
|
y: primaryHeight - rect.origin.y - rect.height,
|
|
width: rect.width,
|
|
height: rect.height)
|
|
}
|
|
|
|
/// CoreGraphics global rect (top-left origin) to AppKit global rect (bottom-left origin).
|
|
static func appKitRect(fromCG rect: CGRect) -> CGRect {
|
|
CGRect(x: rect.origin.x,
|
|
y: primaryHeight - rect.origin.y - rect.height,
|
|
width: rect.width,
|
|
height: rect.height)
|
|
}
|
|
|
|
static func displayID(for screen: NSScreen) -> CGDirectDisplayID? {
|
|
screen.deviceDescription[NSDeviceDescriptionKey("NSScreenNumber")] as? CGDirectDisplayID
|
|
}
|
|
|
|
static func screen(for displayID: CGDirectDisplayID) -> NSScreen? {
|
|
NSScreen.screens.first { ScreenGeometry.displayID(for: $0) == displayID }
|
|
}
|
|
|
|
static func screen(containing point: CGPoint) -> NSScreen? {
|
|
NSScreen.screens.first { $0.frame.contains(point) } ?? NSScreen.main
|
|
}
|
|
|
|
/// Crops a CGImage using a rect expressed in points relative to the image's top-left corner.
|
|
static func crop(_ image: CGImage, toPointRect rect: CGRect, scale: CGFloat) -> CGImage? {
|
|
let pixelRect = CGRect(x: (rect.origin.x * scale).rounded(.down),
|
|
y: (rect.origin.y * scale).rounded(.down),
|
|
width: (rect.width * scale).rounded(),
|
|
height: (rect.height * scale).rounded())
|
|
.intersection(CGRect(x: 0, y: 0, width: CGFloat(image.width), height: CGFloat(image.height)))
|
|
guard pixelRect.width >= 1, pixelRect.height >= 1 else { return nil }
|
|
return image.cropping(to: pixelRect)
|
|
}
|
|
}
|