Programmatically Screenshot | Swift 3, macOS
Yes its possible. This function takes all connected monitors screenshots and writes to specified path as jpg file. Generates file name as unix time stamp.
func TakeScreensShots(folderName: String){
var displayCount: UInt32 = 0;
var result = CGGetActiveDisplayList(0, nil, &displayCount)
if (result != CGError.success) {
print("error: \(result)")
return
}
let allocated = Int(displayCount)
let activeDisplays = UnsafeMutablePointer<CGDirectDisplayID>.allocate(capacity: allocated)
result = CGGetActiveDisplayList(displayCount, activeDisplays, &displayCount)
if (result != CGError.success) {
print("error: \(result)")
return
}
for i in 1...displayCount {
let unixTimestamp = CreateTimeStamp()
let fileUrl = URL(fileURLWithPath: folderName + "\(unixTimestamp)" + "_" + "\(i)" + ".jpg", isDirectory: true)
let screenShot:CGImage = CGDisplayCreateImage(activeDisplays[Int(i-1)])!
let bitmapRep = NSBitmapImageRep(cgImage: screenShot)
let jpegData = bitmapRep.representation(using: NSBitmapImageRep.FileType.jpeg, properties: [:])!
do {
try jpegData.write(to: fileUrl, options: .atomic)
}
catch {print("error: \(error)")}
}
}
func CreateTimeStamp() -> Int32
{
return Int32(Date().timeIntervalSince1970)
}
How can I programmatically display a window on a specific screen (i.e., main display as opposed to external displays) in Swift 5? [MacOS; Xcode 15]
Thanks to the question asked by @Willeke, I was able to use the following code to display the window on the main screen (as opposed to external displays). I just needed to use DispatchQueue.main.async {}
.
override func viewDidLoad() {
super.viewDidLoad()
DispatchQueue.main.async {
//set up the main display as the display where window shows up
let screens = NSScreen.screens
var pos = NSPoint()
pos.x = screens[0].visibleFrame.midX
pos.y = screens[0].visibleFrame.midY
self.view.window?.setFrameOrigin(pos)
}
}
Swift open new window programmatically in macOS
The following demo creates a second window called by a method in a custom class. It may be run in Xcode by adding a 'swift.main' file and replacing AppDelegate with the following code:
import Cocoa
class Abc : NSObject {
var panel: NSPanel!
func buildWnd2() {
let _panelW : CGFloat = 200
let _panelH : CGFloat = 200
panel = NSPanel(contentRect:NSMakeRect(9300, 1300, _panelW, _panelH), styleMask:[.titled, .closable, .utilityWindow],
backing:.buffered, defer: false)
panel.isFloatingPanel = true
panel.title = "NSPanel"
panel.orderFront(nil)
}
}
let abc = Abc()
class AppDelegate: NSObject, NSApplicationDelegate {
var window:NSWindow!
@objc func myBtnAction(_ sender:AnyObject ) {
abc.buildWnd2()
}
func buildMenu() {
let mainMenu = NSMenu()
NSApp.mainMenu = mainMenu
// **** App menu **** //
let appMenuItem = NSMenuItem()
mainMenu.addItem(appMenuItem)
let appMenu = NSMenu()
appMenuItem.submenu = appMenu
appMenu.addItem(withTitle: "Quit", action:#selector(NSApplication.terminate), keyEquivalent: "q")
}
func buildWnd() {
let _wndW : CGFloat = 400
let _wndH : CGFloat = 300
window = NSWindow(contentRect:NSMakeRect(0,0,_wndW,_wndH),styleMask:[.titled, .closable, .miniaturizable, .resizable], backing:.buffered, defer:false)
window.center()
window.title = "Swift Test Window"
window.makeKeyAndOrderFront(window)
// **** Button **** //
let myBtn = NSButton (frame:NSMakeRect( 100, 100, 175, 30 ))
myBtn.bezelStyle = .rounded
myBtn.autoresizingMask = [.maxXMargin,.minYMargin]
myBtn.title = "Build Second Window"
myBtn.action = #selector(self.myBtnAction(_:))
window.contentView!.addSubview (myBtn)
// **** Quit btn **** //
let quitBtn = NSButton (frame:NSMakeRect( _wndW - 50, 10, 40, 40 ))
quitBtn.bezelStyle = .circular
quitBtn.autoresizingMask = [.minXMargin,.maxYMargin]
quitBtn.title = "Q"
quitBtn.action = #selector(NSApplication.terminate)
window.contentView!.addSubview(quitBtn)
}
func applicationDidFinishLaunching(_ notification: Notification) {
buildMenu()
buildWnd()
}
func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
return true
}
}
let appDelegate = AppDelegate()
// **** main.swift **** //
let app = NSApplication.shared
app.delegate = appDelegate
app.setActivationPolicy(.regular)
app.activate(ignoringOtherApps:true)
app.run()
How to take a screenshot of your entire screen
The error has to do with saving the file. You are constructing the URL badly.
First, expanding ~
to the home directory is generally a shell feature, not an OS feature. The underlying file path APIs (e.g. open()
) just treat that as a normal character in a path. Foundation does support expanding ~
in path strings (not URLs), but you have to specifically request it with expandingTildeInPath
. It's never automatic and it's never meaningful in URLs.
Next, I suspect you were trying to build a URL to a file within the Documents directory. However, you did not put a path separator (/
) between the name of the directory and the name of the file. In other words, you constructed ~/Documents10989439875_1.jpg
, not ~/Documents/10989439875_1.jpg
.
You should use FileManager().urls(for:.downloadsDirectory, in:.userDomainMask)[0]
to get the URL to the Downloads folder and then append a path component to that using appendingPathComponent(_:isDirectory:)
.
Swift 3/macOS: Open window on certain screen
Each screen from NSScreen.screens()
has a visibleFrame
property that tells you the global frame rectangle.
You can then set your window origin to fit inside the frame rect coordinates of whatever screen you want. Objective-C answers can be seen here and here.
This does mean you have to write some code to specify the preferred window. In my own app, I take the global frame rectangles for each screen and then scale them way down into a NSView to display something that looks like the Monitors pane from System Preferences:
Mac - How to programmatically hide NSApplicationActivationPolicyAccessory or LSUIElement application?
Use NSApplication.sharedApplication().hide(nil)
. One would normally address the application object (instance of NSApplication
) rather than an instance of NSRunningApplication
to operate on the current app.
Related Topics
Whats the Swift Animate Withduration Syntax
What Is the Reduce() Function Doing, in Swift
How to Load an Image from Documents Directory on MACos Swift
Convert Between Decimal, Binary and Hexadecimal in Swift
How to Draw Text in PDF Context in Swift
Stop a Dispatchqueue That Is Running on the Main Thread
Iboutlet of Another View Controller Is Nil
Safariviewcontroller: How to Grab Oauth Token from Url
Add @Published Behaviour for Computed Property
Can You Override Between Extensions in Swift or Not? (Compiler Seems Confused!)
Finish Asynchronous Task in Firebase With Swift
Compiler Error When Comparing Values of Enum Type with Associated Values
How to Get Directory Size with Swift on Os X
Why Does Filter(_:)'s Predicate Get Called So Many Times When Evaluating It Lazily
Returning a Value from a Function with Alamofire and Swiftyjson
Distinction in Swift Between Uppercase "Self" and Lowercase "Self"