13
votes

I'm attempting to create an image "loupe" for my application that can be used to inspect images at different magnification levels, and I have run into a bit of a road bump. I'm using Quartz to create a CGImageRef snapshot of a selected portion of the display my app's window is on. The problem is, the nomenclature used by all of the different OS X technologies has me really confused.

The function I'm using is CGDisplayCreateImageForRect(CGDirectDisplayID display, CGRect rect). The documentation states the CGRect rect parameter is the "rectangle, specified in display space, for the portion of the display being copied into the image." The problem is, the output I'm getting in my console isn't what I was expecting. I've tried so many different conversions, transformations, coord flips, etc., that I'm 100% confused now.

So, I guess my question boils down to this: Does screen space == device space == display space, and how does one properly convert his or her view's frame (which happens to be a custom borderless window) coordinates (bottom-left origin) to match the display's coordinates (top-left origin)?

If someone could set me straight, or point me in the right direction, I'd be forever appreciative. Thanks!

1

1 Answers

21
votes

Quartz uses a coordinate space where the origin (0, 0) is at the top-left of the primary display. Increasing y goes down.

Cocoa uses a coordinate space where the origin (0, 0) is the bottom-left of the primary display and increasing y goes up.

You can convert a window's frame from Cocoa to Quartz like so:

NSRect frame = window.frame;
frame.origin.y = NSMaxY(NSScreen.screens[0].frame) - NSMaxY(frame);
CGRect quartzRect = NSRectToCGRect(frame);

Note: you don't use the window's -screen, you always use the primary screen.

This is for a rect in window coordinates. For a rect in a view, first convert from view coordinates to window coordinates using -[NSView convertRect:toView:] with nil as the destination view signifying the window. This would do the right thing for someView.bounds but not for someView.frame, since a view's frame is in the superview's coordinate system.