2013-05-09 5 views
6

Ich möchte einen Screenshot von einem Hintergrunddienst erfassen. Private API ist in Ordnung, da ich nicht im App Store einreichen muss. Ich habe bereits versucht UIGetScreenImage und es funktioniert nicht von Hintergrund App.IOSurface - IOS Private API - Screenshot im Hintergrund erfassen

Ich benutze folgenden Code, den ich von SO bekommen habe. IOSurfaceCreate gibt für mich null zurück. Jede Hilfe wird geschätzt.

CFMutableDictionaryRef dict; 
     IOSurfaceRef screenSurface = NULL; 

     char pixelFormat[4] = {'A','R','G','B'}; 
     dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 

     uint32_t width ; 
     uint32_t height; 
     void *pitch; 
     void *bPE; 
     void *size; 
     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); 
     uint32_t aseed; 
     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]; 
     UIImageWriteToSavedPhotosAlbum(image, self_object, nil, nil); 
     CGImageRelease(cgImage); 
     CFRelease(destSurf); 

Antwort

8

Nach der Kombination von Code aus 2 Orten konnte ich Foto zu Fotoalbum speichern

IOSurfaces - Artefacts in video and unable to grab video surfaces

https://github.com/tomcool420/SMFramework/blob/master/SMFScreenCapture.m

Bitte versuchen Sie es aus und lassen Sie mich wissen, ob es für Sie arbeitet.

-(void)SavePhoto 
{ 
    IOMobileFramebufferConnection connect; 
    kern_return_t result; 
    IOSurfaceRef screenSurface = NULL; 

    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); 
    //int m_width = 320; 
    //int m_height = 480; 
    CFMutableDictionaryRef dict; 
    int pitch = width*4, size = width*height*4; 
    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); 

    void* outAcc; 
    IOSurfaceAcceleratorCreate(NULL, 0, &outAcc); 

    IOSurfaceAcceleratorTransferSurface(outAcc, screenSurface, destSurf, dict, NULL); 

    IOSurfaceUnlock(screenSurface, kIOSurfaceLockReadOnly, &aseed); 
    CFRelease(outAcc); 

    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 *img = [UIImage imageWithCGImage:cgImage]; 
    UIImageWriteToSavedPhotosAlbum(img, self, nil, nil); 

    // MOST RELEVANT PART OF CODE 

    //CVPixelBufferCreateWithBytes(NULL, width, height, kCVPixelFormatType_32BGRA, IOSurfaceGetBaseAddress(destSurf), IOSurfaceGetBytesPerRow(destSurf), NULL, NULL, NULL, &sampleBuffer); 
} 
+0

Haben Sie das auf iOS 7 funktioniert? Ich erhalte einen Linker-Fehler bei IOMobileFramebufferOpen. Könnten Sie bitte teilen, welche Frameworks/Lib genau verlinken und wo Sie die Header haben? – Frank

+0

mit dem Hinzufügen dieses Terminals Cmd, um Fehler zu löschen kommen von iOSurface > CD/Anwendungen/Xcode.app/Inhalte/Entwickler/Plattformen/iPhoneOS.platform/Entwickler/SDKs/iPhoneOS7.0.sdk/System/Library/Frameworks/IOKit. Framework > sudo ln -s Versionen/A/IOKit – HDNZ

+0

Hat jemand ein funktionierendes Demo-Projekt für iOS 8? Oder können Sie mir sagen, wie Sie dieses Framework verwenden/die Header bekommen? – Max