NSWindow view capture to image

2019-02-28 19:58发布

Update: Nov.6

Thanks to pointum I revised my question.

On 10.13, I'm trying to write a view snapshot function as general purpose NSView or window extension. Here's my take as a window delegate:

var snapshot : NSImage? {
    get {
        guard let window = self.window, let view = self.window!.contentView else { return nil }

        var rect = view.bounds
        rect = view.convert(rect, to: nil)
        rect = window.convertToScreen(rect)

        //  Adjust for titlebar; kTitleUtility = 16, kTitleNormal = 22
        let delta : CGFloat = CGFloat((window.styleMask.contains(.utilityWindow) ? kTitleUtility : kTitleNormal))
        rect.origin.y += delta
        rect.size.height += delta*2

        Swift.print("rect: \(rect)")

        let cgImage = CGWindowListCreateImage(rect, .optionIncludingWindow,
                                              CGWindowID(window.windowNumber), .bestResolution)
        let image = NSImage(cgImage: cgImage!, size: rect.size)

        return image
    }
}

to derive a 'flattened' snapshot of the window is what I'm after. Initially I'm using this image in a document icon drag.

It acts bizarrely. It seems to work initially - window in center, but subsequently the resulting image is different - smaller, especially when window is moved up or down in screen.

I think the rect capture is wrong ?

标签: macos swift3
2条回答
孤傲高冷的网名
2楼-- · 2019-02-28 20:35

Adding to pointum's answer I came up with this:

var snapshot : NSImage? {
    get {
        guard let window = self.window, let view = self.window!.contentView else { return nil }

        let inf = CGFloat(FP_INFINITE)
        let null = CGRect(x: inf, y: inf, width: 0, height: 0)

        let cgImage = CGWindowListCreateImage(null, .optionIncludingWindow,
                                              CGWindowID(window.windowNumber), .bestResolution)
        let image = NSImage(cgImage: cgImage!, size: view.bounds.size)

        return image
    }
}

As I only want / need a single window, specifying 'null' does the trick. Well all else fails, the docs, if you know where to look :o.

查看更多
迷人小祖宗
3楼-- · 2019-02-28 20:41

Use CGWindowListCreateImage:

let rect = /* view bounds converted to screen coordinates */
let image = CGWindowListCreateImage(rect, .optionIncludingWindow,
    CGWindowID(window.windowNumber), .bestResolution)

To save the image use something like this:

let dest = CGImageDestinationCreateWithURL(url, "public.jpeg", 1, nil)
CGImageDestinationAddImage(destination, image, nil)
CGImageDestinationFinalize(destination)

Note that screen coordinates are flipped. From the docs:

The coordinates of the rectangle must be specified in screen coordinates, where the screen origin is in the upper-left corner of the main display and y-axis values increase downward

查看更多
登录 后发表回答