我尝试将与我的MAC连接的所有显示器的屏幕截图设置为一张图片。我知道,如果每个显示器的截图都会保存到不同的图片中,我怎么能这样做,但这不是我想要的。我发现函数 CGGetDisplaysWithRect ,但我的解决方案不起作用,因为输出图片为空。我希望,函数CGDisplayCreateImageForRect(*显示,rect)的问题,因为第一个参数必须是CGDirectDisplayID类型,而不是CGDirectDisplayID *。但我找不到函数,它可以用一些CGDirectDisplayID对象创建一张图片 请帮帮我!!!
#include <stdio.h>
#include <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
CGDisplayCount displayCount;
CGDirectDisplayID displays[32];
memset(&displays, 0, 32);
CGImageRef image[32];
CGRect rect = CGRectNull;
//grab the active displays
if (CGGetActiveDisplayList(32, displays, &displayCount) != kCGErrorSuccess)
{
printf("Error occured: %s\n", strerror(errno));
}
//go through the list
for (int i = 0; i < displayCount; i++)
{
if (CGDisplayMirrorsDisplay(displays[i]) != kCGNullDirectDisplay)
{
continue;
}
//return the smallest rectangle wich contain the two source rectangles
rect = CGRectUnion(rect, CGDisplayBounds(displays[i]));
if (CGRectIsNull(rect))
{
printf("Error: %s", strerror(errno));
}
}
CGFloat whitePoint[3];
CGFloat blackPoint[3];
CGFloat gamma[3];
CGFloat matrix[9];
CGColorSpaceRef colorSpace = CGColorSpaceCreateCalibratedRGB (&whitePoint[3], &blackPoint[3], &gamma[3], &matrix[9] );
if(colorSpace == NULL)
{
printf("Error: %s", strerror(errno));
}
//CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
//Create bmp context for image
CGContextRef context = CGBitmapContextCreate(NULL, //data
CGRectGetWidth(rect), //width
CGRectGetHeight(rect), //height
8, //bitPerComponent, for RGB must be 8
0, //if data == NULL, it must be 0
colorSpace, //colorspace device independent
kCGBitmapByteOrderDefault ); //bitmap info
if(context == NULL)
{
printf("Error: %s", strerror(errno));
}
//Create a snapshot image
for (int i = 0; i < displayCount; i++)
{
image[i] = CGBitmapContextCreateImage(context);
if(image == NULL)
{
//printf("Error: %s", strerror(errno));
}
}
//Create destination to image
CFURLRef url = CFURLCreateWithString ( kCFAllocatorDefault, CFSTR("out.bmp"), NULL);
if(url == NULL)
{
printf("Error: %s", strerror(errno));
}
CFErrorRef *error = NULL;
CFURLRef urlToFile = CFURLCreateFilePathURL ( kCFAllocatorDefault, url, error );
if(urlToFile == NULL)
{
//printf("Error: %s", error);
}
CGImageDestinationRef imageDestination = CGImageDestinationCreateWithURL(urlToFile, kUTTypeBMP, displayCount, NULL);
if(imageDestination == NULL)
{
printf("Error: %s", strerror(errno));
}
//CGImageDestinationAddImage(imageDestination, image, NULL);
CGImageDestinationFinalize(imageDestination);
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
CFRelease(imageDestination);
return 0;
}
APDATE:我试过smth,我在下面说过,但现在我收到了错误:
错误:CGBitmapContextCreate:不支持的参数组合:8个整数位/组件; 24位/像素; 3组分色彩空间; kCGImageAlphaNone; 3456字节/行。
答案 0 :(得分:3)
这是应该做的一些代码。一方面,我还无法在多监视器系统上进行测试,但另一方面,编写的代码没有任何关于使用哪个显示器或它所处位置的假设。所以,它应该有用。
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);