Create an image from ios surface and save it


I am trying to get the surface associated with the main screen of an ios device, create an image from it and save it. This is relevant to this issue - Taking screenshots from an iOS application - Display emulation (request for the inside) .
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 an empty image saved in a folder with photos. Please help in which part I am mistaken. Thanks.

0
source share
2 answers

I remember I saw something on this subject (taking screenshots in the background) a while ago. I could not find the exact location and code that I saw. The only note I left for myself was using createScreenIOSurface

I looked a little and found a couple of references:

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

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

http://pastie.org/pastes/3734430

As I recall, the code was more compact than what you showed.

+1
source

The specified code works if you run it in the background. This takes a screenshot from the topmost surface on the display of the iOS device.
The problem was that a screenshot of an empty view created for the application was taken inside the application.
However, you must take screenshots at minimum intervals of 2 seconds, otherwise the OS will pause your application. Any suggestions for improving this would be helpful.

+1
source

All Articles