这里有一些代码可以做到这一点。一方面,我还无法在多监视器系统上进行测试,但另一方面,编写代码时没有对使用哪种显示器或其位置进行任何假设。所以,它应该起作用。
CGDirectDisplayID displays[32];
uint32_t count;
if (CGGetActiveDisplayList(sizeof(displays)/sizeof(displays[0]), displays, &count) != kCGErrorSuccess)
{
NSLog(@"failed to get display list");
exit(EXIT_FAILURE);
}
CGRect rect = CGRectNull;
CGRect primaryDisplayRect = CGRectZero;
for (uint32_t i = 0; i < count; i++)
{
// if display is secondary mirror of another display, skip it
if (CGDisplayMirrorsDisplay(displays[i]) != kCGNullDirectDisplay)
continue;
CGRect displayRect = CGDisplayBounds(displays[i]);
if (i == 0)
primaryDisplayRect = displayRect;
displayRect.origin.y = CGRectGetMaxY(primaryDisplayRect) - CGRectGetMaxY(displayRect);
rect = CGRectUnion(rect, displayRect);
}
NSBitmapImageRep* imageRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
pixelsWide:CGRectGetWidth(rect)
pixelsHigh:CGRectGetHeight(rect)
bitsPerSample:8
samplesPerPixel:4
hasAlpha:YES
isPlanar:NO
colorSpaceName:NSCalibratedRGBColorSpace
bitmapFormat:0
bytesPerRow:0
bitsPerPixel:32];
if (!imageRep)
{
NSLog(@"failed to create bitmap image rep");
exit(EXIT_FAILURE);
}
NSGraphicsContext* context = [NSGraphicsContext graphicsContextWithBitmapImageRep:imageRep];
if (!context)
{
NSLog(@"failed to create graphics context");
exit(EXIT_FAILURE);
}
[NSGraphicsContext saveGraphicsState];
{
[NSGraphicsContext setCurrentContext:context];
CGContextRef cgcontext = [context graphicsPort];
CGContextClearRect(cgcontext, CGRectMake(0, 0, CGRectGetWidth(rect), CGRectGetHeight(rect)));
for (uint32_t i = 0; i < count; i++)
{
// if display is secondary mirror of another display, skip it
if (CGDisplayMirrorsDisplay(displays[i]) != kCGNullDirectDisplay)
continue;
CGRect displayRect = CGDisplayBounds(displays[i]);
displayRect.origin.y = CGRectGetMaxY(primaryDisplayRect) - CGRectGetMaxY(displayRect);
CGImageRef image = CGDisplayCreateImage(displays[i]);
if (!image)
continue;
CGRect dest = CGRectMake(displayRect.origin.x - rect.origin.x,
displayRect.origin.y - rect.origin.y,
displayRect.size.width,
displayRect.size.height);
CGContextDrawImage(cgcontext, dest, image);
CGImageRelease(image);
}
[[NSGraphicsContext currentContext] flushGraphics];
}
[NSGraphicsContext restoreGraphicsState];
NSData* data = [imageRep representationUsingType:NSPNGFileType properties:@{ }];
[data writeToFile:@"/tmp/screenshot.png" atomically:YES];
主要可能的失败点是为足够大的矩形分配位图图像上下文以包含所有显示。注意,所有显示的总矩形可以比任何一个显示的矩形大得多。例如,如果两个显示器的排列方式使它们几乎不接触角落,那么围绕它们的矩形将几乎与2x2排列方式中的四个显示器一样大。对于三个显示器,它可以在3x3的排列中多达9个显示器。等
这里有一个不使用Cocoa的实现,只使用Core Graphics:
CGDirectDisplayID displays[32];
uint32_t count;
if (CGGetActiveDisplayList(sizeof(displays)/sizeof(displays[0]), displays, &count) != kCGErrorSuccess)
{
NSLog(@"failed to get display list");
exit(EXIT_FAILURE);
}
CGRect rect = CGRectNull;
for (uint32_t i = 0; i < count; i++)
{
// if display is secondary mirror of another display, skip it
if (CGDisplayMirrorsDisplay(displays[i]) != kCGNullDirectDisplay)
continue;
rect = CGRectUnion(rect, CGDisplayBounds(displays[i]));
}
CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
if (!colorspace)
{
NSLog(@"failed to create colorspace");
exit(EXIT_FAILURE);
}
CGContextRef cgcontext = CGBitmapContextCreate(NULL, CGRectGetWidth(rect), CGRectGetHeight(rect), 8, 0, colorspace, (CGBitmapInfo)kCGImageAlphaPremultipliedFirst);
CGColorSpaceRelease(colorspace);
if (!cgcontext)
{
NSLog(@"failed to create bitmap context");
exit(EXIT_FAILURE);
}
CGContextClearRect(cgcontext, CGRectMake(0, 0, CGRectGetWidth(rect), CGRectGetHeight(rect)));
for (uint32_t i = 0; i < count; i++)
{
// if display is secondary mirror of another display, skip it
if (CGDisplayMirrorsDisplay(displays[i]) != kCGNullDirectDisplay)
continue;
CGRect displayRect = CGDisplayBounds(displays[i]);
CGImageRef image = CGDisplayCreateImage(displays[i]);
if (!image)
continue;
CGRect dest = CGRectMake(displayRect.origin.x - rect.origin.x,
displayRect.origin.y - rect.origin.y,
displayRect.size.width,
displayRect.size.height);
CGContextDrawImage(cgcontext, dest, image);
CGImageRelease(image);
}
CGImageRef image = CGBitmapContextCreateImage(cgcontext);
CGContextRelease(cgcontext);
if (!image)
{
NSLog(@"failed to create image from bitmap context");
exit(EXIT_FAILURE);
}
CFURLRef url = CFURLCreateWithFileSystemPath(NULL, CFSTR("/tmp/screenshot.png"), kCFURLPOSIXPathStyle, NO);
if (!url)
{
NSLog(@"failed to create URL");
exit(EXIT_FAILURE);
}
CGImageDestinationRef dest = CGImageDestinationCreateWithURL(url, kUTTypePNG, 1, NULL);
CFRelease(url);
if (!dest)
{
NSLog(@"failed to create image destination");
exit(EXIT_FAILURE);
}
CGImageDestinationAddImage(dest, image, NULL);
CGImageRelease(image);
if (!CGImageDestinationFinalize(dest))
{
NSLog(@"failed to finalize image destination");
exit(EXIT_FAILURE);
}
CFRelease(dest);