15

Is it possible to take a screenshot programmatically of the desktop on mac using Swift 3? I can't find a single thread or forum post about the topic, not even in apple's official documentation.

I have found this so far but it doesn't seem to help: one two

Cœur
  • 37,241
  • 25
  • 195
  • 267
user6879072
  • 441
  • 1
  • 7
  • 17
  • for security and privacy reason it is highly considerable from both developers and users' perspectives. – holex Sep 25 '16 at 20:26
  • Yes I understand but I have no intentions of releasing this software it is rather for learning and in-house deploent purposes and I would be fine if a little "accept screenshot" window would appear. – user6879072 Sep 25 '16 at 20:29
  • 1
    `NSTask` - `screencapture` – vadian Sep 25 '16 at 20:44
  • @vadian Can you point me to a sample code or documentation or some other useful source regarding "NSTask - screen capture" – user6879072 Sep 25 '16 at 21:02
  • 4
    `NSTask` is the Cocoa class to run command line interfaces - `screencapture` is the command line interface to make screenshots – vadian Sep 25 '16 at 21:04

2 Answers2

28

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)
}
imike
  • 5,515
  • 2
  • 37
  • 44
B.Tekkan
  • 570
  • 4
  • 7
  • I didn't check your code yet but it looks like quality, unlike the way I solved it using scripts and terminal. I didn't expect any answers after so long. – user6879072 Nov 29 '16 at 19:03
  • 1
    It works, it's a really nice implementation handles multiple displays. – Magrafear Nov 30 '16 at 06:50
  • @B.Tekkan @Magrafear I get an error CreateTimeStamp(): `let unixTimestamp = CreateTimeStamp()` "use of unresolved identifier 'CreateTimeSpan'" – user6879072 Dec 12 '16 at 21:02
  • Just create a function for CreateTimeStamp() that returns Date() or NSDate() as a string formatted how you need. – Magrafear Dec 13 '16 at 07:27
  • CreateTimeStamp() method just creates a uniq name for the file. I add the method for you. – B.Tekkan Dec 13 '16 at 12:50
14
let displayID = CGMainDisplayID()
let imageRef = CGDisplayCreateImage(displayID)
Magrafear
  • 573
  • 4
  • 17