2013-05-09 81 views
6

我想捕獲後臺服務的屏幕截圖。私有API正好,因爲我不需要提交給應用商店。我已經嘗試過UIGetScreenImage,它不能從後臺應用程序工作。IOSurface - IOS私有API - 在後臺捕獲屏幕截圖

我正在使用下面的代碼,我從SO那裏得到。 IOSurfaceCreate對我返回null。任何幫助讚賞。

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

回答

8

將2個地方的代碼合併後,我就可以將照片保存到相冊(我的應用程序在後臺)。

IOSurfaces - Artefacts in video and unable to grab video surfaces

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

請嘗試,讓我知道它是否適合你。

-(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

您是否在iOS 7上正常工作?我在IOMobileFramebufferOpen上收到鏈接器錯誤。你能不能分享哪些框架/ lib完全鏈接,你在哪裏獲取頭文件? – Frank 2013-12-17 21:41:25

+0

添加此終端cmd刪除錯誤來自iOSurface > cd/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.0.sdk/System/Library/Frameworks/IOKit。框架 > sudo ln -s版本/ A/IOKit – HDNZ 2014-10-15 11:22:36

+0

有沒有人有iOS 8的工作演示項目?或者可以告訴我如何使用這個框架/獲取標題? – Max 2014-11-24 17:36:32