你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> iOS應用截屏

iOS應用截屏

編輯:IOS開發綜合

iPhone自從推出後就自帶了截屏功能,簡單而易用,所以應用就沒什麼截屏的需求了,不過有些時候我們還是會遇到這個需求。比如,我們開發了一個播放器,用openGL進行video render,此時直接截屏有可能有OSD疊加內容,所以希望能截完全是視頻的幀,這時就需要應用自己來實現了。

從應用角度看,雖說都是截屏,但用不用openGL是不同的,因為openGL是直接寫GPU frame buffer的,如果我們是直接用UIController來用做的界面:

- (void)snapshotScreen
{
    // check the retina screen
    if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]){
        UIGraphicsBeginImageContextWithOptions(self.view.window.bounds.size, NO, [UIScreen mainScreen].scale);
    } else {
        UIGraphicsBeginImageContext(self.view.window.bounds.size);
    }

    [self.view.window.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    NSData * data = UIImagePNGRepresentation(image);
    
    NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *filename = [[path objectAtIndex:0] stringByAppendingPathComponent:@"foo.png"];
    [data writeToFile:filename atomically:YES];
}

這個代碼前面部分是檢查是否是retina屏幕的,因為iPhone都是retina的屏幕,但iPod有非retina的屏幕;最後一部分是把image存到應用的document目錄下。


如果要截openGL的內容,那麼上面的代碼就不能用了,思路是用openGL的API,glReadPixels去讀出內容來。代碼如下:

- (void)getGLScreenShot {
    int       w = self.bounds.size.width;
    int       h = self.bounds.size.height;
    NSInteger myDataLength = w * h * 4;
    
    // allocate array and read pixels into it.
    GLubyte *buffer = (GLubyte *) malloc(myDataLength);
    glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
    
    // gl renders "upside down" so swap top to bottom into new array.
    // there's gotta be a better way, but this works.
    GLubyte *buffer2 = (GLubyte *) malloc(myDataLength);
    for(int y = 0; y < h; y++) {
        for(int x = 0; x       這段代碼是抓下了openGL渲染的一個GLView的所有內容,因為openGL讀出的內容是顛倒的,所以習慣上需要顛倒一下,中間的兩層for循環就是這個用途,當然,這個寫法效率不高,不過一時也沒找到什麼高效的方法,就先用一下。

這段代碼裡面釋放了buffer的內存,但沒有釋放buffer2的內存。因為圖片的存儲是異步的,所以是在存完圖片之後,調用@selector(GLImage:didFinishSavingWithError:contextInfo:)這個方法進行清理,通過這個回調,在UI上也可以做一些限制,防止用戶連續快速的截屏導致系統負載過重。

順便說一下,這裡把存下的圖片按照習慣放到了圖片庫之中。


在iOS7之後,UIView有了UISnapshotting的category,這個真是大大的方便了我們截屏的實現,因為它既可以截屏普通的UIController,也可以截屏openGL的內容,

// only support iOS7 or Above
- (void)snapshotScreenWithGL
{
    CGSize size = videoView.bounds.size; 
    
    UIGraphicsBeginImageContextWithOptions(size, NO, [UIScreen mainScreen].scale);
    
    CGRect rec = CGRectMake(videoView.frame.origin.x, videoView.frame.origin.y, videoView.bounds.size.width, videoView.bounds.size.height);
    [self.view drawViewHierarchyInRect:rec afterScreenUpdates:YES];
    
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    NSData * data = UIImagePNGRepresentation(image);
    
    NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *filename = [[path objectAtIndex:0] stringByAppendingPathComponent:@"foo.png"];
    [data writeToFile:filename atomically:YES];
}

綜合起來看,iOS7之後,蘋果考慮到了用戶這方面的需求,提供了API,可以比較方便的實現功能。iOS7之前,需要自己手動實現,根據是否使用了openGL代碼有所不同。

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved