如何从MAC上的所有显示器获取屏幕截图? [英] How can I get screenshot from all displays on MAC?

查看:216
本文介绍了如何从MAC上的所有显示器获取屏幕截图?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试将所有与我的MAC连接的监视器的屏幕截图获取到一张图片.我知道,如果每个监视器的屏幕截图都将保存到不同的图片中,该怎么办,但这不是我想要的.我发现函数 CGGetDisplaysWithRect ,但是我的解决方案不起作用,因为输出图片为空.我希望功能CGDisplayCreateImageForRect(* displays,rect)有此问题,因为第一个参数必须是CGDirectDisplayID类型,而不是CGDirectDisplayID *.但是我找不到函数,该函数可以使用某些CGDirectDisplayID对象创建一张图片.
请帮帮我!

I try to get the screenshot from all monitors connected with my MAC to one picture. I know, how I can do this if every monitor's screenshot will saved to different pictures, but it is not what I want. I found function CGGetDisplaysWithRect, but my solution don't work, because output picture is empty. I expect, that problem with function CGDisplayCreateImageForRect (*displays, rect), because first parameter must be CGDirectDisplayID type, but not CGDirectDisplayID*. But I can't find function, which can create one picture with some CGDirectDisplayID objects.
Help me please!!!

#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:我尝试了以下告诉我的内容,但现在出现错误:

APDATE: I tried smth that me told below, but now I get error:

错误:CGBitmapContextCreate:不支持的参数组合:8个整数位/组件; 24位/像素; 3分量色彩空间; kCGImageAlphaNone; 3456字节/行.

推荐答案

下面是一些应做的代码.一方面,我还不能在多显示器系统上进行测试,但是,另一方面,在编写代码时没有任何关于要使用哪个显示器或显示器位置的假设.因此,它应该可以工作.

Here's some code that should do it. On the one hand, I wasn't able to test on a multi-monitor system yet, but, on the other, the code was written without any assumptions about which display to use or where it is positioned. So, it should work.

    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];

主要的失败点是为一个足以容纳所有显示的矩形分配位图图像上下文.请注意,所有显示器的总rect可能比任何一个显示器的rect大得多.例如,如果安排两个监视器以使其几乎不接触一个角,则包围它们的矩形将几乎与2x2排列中的四个监视器一样大.对于三台显示器,在3x3的排列中,它可以和9台显示器一样大.等等.

The main possible point of failure is in allocating a bitmap image context for a rectangle large enough to encompass all displays. Note that the total rect for all displays can be much larger than the rect for any one. For example, if two monitors are arranged so that they barely touch at a corner, the rectangle encompassing them would be nearly as big as four monitors in a 2x2 arrangement. For three monitors, it can be as big as 9 monitors in a 3x3 arrangement. Etc.

这是一个不使用Cocoa的实现,仅使用Core Graphics:

Here's an implementation that doesn't use Cocoa, just 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);

这篇关于如何从MAC上的所有显示器获取屏幕截图?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆