Debashis
Debashis

Reputation: 199

How do I take a "screenshot" of an NSView?

I need to take the contents of an NSView and put them in an NSImage, for an experimental project. Is this possible? I did some Googling, tried two methods that I found - but they didn't really work. Any suggestions?

Upvotes: 18

Views: 11038

Answers (4)

Noah Nuebling
Noah Nuebling

Reputation: 309

NSView.bitmapImageRepForCachingDisplay() (mentioned in this answer) doesn't render the colors correctly on some views.

CGWindowListCreateImage() works perfectly for me.

Here's my implementation:

extension NSView {
    @objc func takeScreenshot() -> NSImage? {
        
        let screenRect = self.rectInQuartzScreenCoordinates()
        guard let window = self.window else { 
            assert(false); return nil 
        }
        let windowID = CGWindowID(window.windowNumber)
        guard let screenshot = CGWindowListCreateImage(screenRect, .optionIncludingWindow, windowID, []) else { 
            assert(false); return nil 
        }
        
        return NSImage(cgImage: screenshot, size: self.frame.size)
    }
}

This code uses a method NSView.rectInQuartzScreenCoordinates(). To implement it you'll first have to convert the bounds of your view to screenCoordinates using NSView and NSWindow methods and then you need to flip the coordinates like this.

Upvotes: -1

Klaas
Klaas

Reputation: 22763

From WWDC 2012 Session 245 (translated to Swift):

let viewToCapture = self.window!.contentView!
let rep = viewToCapture.bitmapImageRepForCachingDisplay(in: viewToCapture.bounds)!
viewToCapture.cacheDisplay(in: viewToCapture.bounds, to: rep)

let img = NSImage(size: viewToCapture.bounds.size)
img.addRepresentation(rep)

Upvotes: 34

Zelko
Zelko

Reputation: 3961

let dataOfView = view.dataWithPDFInsideRect(view.bounds)
let imageOfView = NSImage(data: dataOfView)

Upvotes: 6

Chuck
Chuck

Reputation: 237010

[[NSImage alloc] initWithData:[view dataWithPDFInsideRect:[view bounds]]];

Upvotes: 23

Related Questions