Creating an image out of the ios surface and savin

2019-01-18 17:21发布


I am trying to acquire the surface associated with the main screen of the ios device, create an image out of it and save it. This is in relevance to this question - Taking Screenshots from iOS app - emulating Display recorder (query on the internals).
The code is as follows:

    IOMobileFramebufferConnection connect;
    kern_return_t result;

    io_service_t framebufferService = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleH1CLCD"));
    if(!framebufferService)
        framebufferService = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleM2CLCD"));
    if(!framebufferService)
        framebufferService = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleCLCD"));

    result = IOMobileFramebufferOpen(framebufferService, mach_task_self(), 0, &connect);

    result = IOMobileFramebufferGetLayerDefaultSurface(connect, 0, &screenSurface);

    uint32_t aseed;
    IOSurfaceLock(screenSurface, kIOSurfaceLockReadOnly, &aseed);
    uint32_t width = IOSurfaceGetWidth(screenSurface);
    uint32_t height = IOSurfaceGetHeight(screenSurface);

    CFMutableDictionaryRef dict;
    int pitch = width*4, size = 4*width*height;
    int bPE=4;
    char pixelFormat[4] = {'A','R','G','B'};
    dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
    CFDictionarySetValue(dict, kIOSurfaceIsGlobal, kCFBooleanTrue);
    CFDictionarySetValue(dict, kIOSurfaceBytesPerRow, CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &pitch));
    CFDictionarySetValue(dict, kIOSurfaceBytesPerElement, CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &bPE));
    CFDictionarySetValue(dict, kIOSurfaceWidth, CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &width));
    CFDictionarySetValue(dict, kIOSurfaceHeight, CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &height));
    CFDictionarySetValue(dict, kIOSurfacePixelFormat, CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, pixelFormat));
    CFDictionarySetValue(dict, kIOSurfaceAllocSize, CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &size));

    IOSurfaceRef destSurf = IOSurfaceCreate(dict);
    IOSurfaceAcceleratorRef outAcc;
    IOSurfaceAcceleratorCreate(NULL, 0, &outAcc);

    CFDictionaryRef ed = (__bridge CFDictionaryRef)[NSDictionary dictionaryWithObjectsAndKeys: nil];
    IOSurfaceAcceleratorTransferSurface(outAcc, screenSurface, destSurf, ed, NULL);

    IOSurfaceUnlock(screenSurface, kIOSurfaceLockReadOnly, &aseed);

    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, IOSurfaceGetBaseAddress(destSurf), (width*height*4), NULL);
    CGImageRef cgImage=CGImageCreate(width, height, 8, 8*4, IOSurfaceGetBytesPerRow(destSurf), CGColorSpaceCreateDeviceRGB(), kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little, provider, NULL, YES, kCGRenderingIntentDefault);
    UIImage *image = [UIImage imageWithCGImage: cgImage];
    CGImageRelease(cgImage);
    UIImageWriteToSavedPhotosAlbum(image, self, nil, nil);


But all I get is a blank image saved in my photos folder. Please help on what part am I going wrong. Thanks.

2条回答
干净又极端
2楼-- · 2019-01-18 17:49

The specified code works if you run it in the background. It does take screenshot of the topmost surface on the display of iOS device.
The problem faced was due to the fact that inside the app, it was taking screenshot of the blank view created for the app.
However, you have to take the screenshots at minimum intervals of 2 sec otherwise the OS suspends your app. Any suggestions on how to improve that will be helpful.

查看更多
甜甜的少女心
3楼-- · 2019-01-18 17:56

I remember I saw something on this subject (taking screenshots in the background) some time ago. I wasn't able find exact place and code which I saw. The only note which I left for myself was usage of createScreenIOSurface

I googled a little bit and found couple of mentions:

Get a screenshot while App is in background? (Private APIs allowed)

https://github.com/rpetrich/FastBlurredNotificationCenter/blob/master/Tweak.x

http://pastie.org/pastes/3734430

As I remember the code was way more compact then what you showed.

查看更多
登录 后发表回答