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 <w * 4; x++) {
- buffer2[(h -1 - y) * w * 4 + x] = buffer[y * 44 * w + x];
- }
- }
- // make data provider with data.
- CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer2, myDataLength, NULL);
- // prep the ingredients
- int bitsPerComponent = 8;
- int bitsPerPixel = 32;
- int bytesPerRow = 44 * w;
- CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
- CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
- CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
- // make the cgimage
- CGImageRef imageRef = CGImageCreate(w, h, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);
- // then make the uiimage from that
- UIImage *myImage = [UIImage imageWithCGImage:imageRef];
- UIImageWriteToSavedPhotosAlbum(myImage, self, @selector(GLImage:didFinishSavingWithError:contextInfo:), buffer2);
- CGImageRelease(imageRef);
- CGDataProviderRelease(provider);
- CGColorSpaceRelease(colorSpaceRef);
- free(buffer);
- }
这段代码是抓下了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代码有所不同。
iOS应用截屏的更多相关文章
- IOS上架截屏 屏幕快照
IOS上架截屏,屏幕快照,4种屏幕尺寸,每种尺寸5张软件功能截图. 大小等于对应设备的屏幕的像素大小.使用模拟器,command +s截图就可以了虚拟机里的手机截屏就保存在mac 桌面上了.jpg,p ...
- iOS 模拟器截屏快捷键
iOS 模拟器截屏快捷键: cmd+S
- IOS中截屏的实现,很简易的方法
// 添加QuartzCore.framework库 #import <QuartzCore/QuartzCore.h> -(void) screenShot { // 截屏 UIGrap ...
- iOS手机截屏使用
.截屏 保存 .data //登录成功进行截屏 //截取屏幕大小 UIGraphicsBeginImageContext([[UIScreen mainScreen]bounds].size); [s ...
- iOS实现截屏 并合适保存
本文转载至:http://blog.csdn.net/zeng11088/article/details/8664510 分类: UIImageView2013-03-12 16:42 122人阅读 ...
- iOS 手机截屏
百度地图自带截图功能,可以截取路线列表,保存到本地.可是对比发现截下来的图片并不是app中看到的那样,截图中头部加入了搜索的起点和终点,每段路程的详细站点都已展开,而且图片会根据路线的长短自动判断图片 ...
- iOS屏幕截屏
#import "ViewController.h" @interface ViewController () @end @implementation ViewControlle ...
- ios 代码截屏模糊问题解决办法
我们常用的截图方法如下所示: //尺寸是按照 UIGraphicsBeginImageContext(CGSizeMake(, )); //currentView 当前的view 创建一个基于位图的图 ...
- ios实现截屏(转)
-(UIImage*) makeImage { UIGraphicsBeginImageContext(self.view.bounds.size); [self.view.layer rende ...
随机推荐
- UIAutomation学习入门
一.界面的自动化操作 .Ui自动化测试 .软件外挂 二.Win32基础知识 a.Win32中一切元素皆窗口,窗口之间有父子关系.整个桌面是一个“根窗口”. b.进程: 根据进程id拿到进程对象Proc ...
- Pandas教程目录
Pandas数据结构 Pandas系列 Pandas数据帧(DataFrame) Pandas面板(Panel) Pandas基本功能 Pandas描述性统计 Pandas函数应用 Pandas重建索 ...
- JSP 国际化
在开始前,需要解释几个重要的概念: 国际化(i18n):表明一个页面根据访问者的语言或国家来呈现不同的翻译版本. 本地化(l10n):向网站添加资源,以使它适应不同的地区和文化.比如网站的印度语版本. ...
- 设计模式--适配器模式C++实现
适配器模式C++实现 1定义Adapter 将一个类的接口变成客户端所需要的另外一种借口,从而使远不因为接口不匹配而无法合作的两个雷能够一起工作 又叫变压器模式,包装模式Wrapper 2类图 角色分 ...
- 搞懂分布式技术10:LVS实现负载均衡的原理与实践
搞懂分布式技术10:LVS实现负载均衡的原理与实践 浅析负载均衡及LVS实现 原创: fireflyc 写程序的康德 2017-09-19 负载均衡 负载均衡(Load Balance,缩写LB)是一 ...
- VMware虚拟机安装linux7并设置网络
1.下载VMware虚拟机 https://www.vmware.com/cn/products/workstation/workstation-evaluation.html 永久激活12位序列号: ...
- linux 常用一些指令
1.后台执行 nohup /bin/bash import.sh 1>&2 2>log & 2.生成脚本 for i in `ls` ; do echo "mys ...
- HP数组转JSON函数json_encode和JSON转数组json_decode函数的使用方法
这两个函数比较简单,我这里直接写例子,但是有一点一定要注意,json数据只支持utf-8格式,GBK格式的数据转换为json会报错! json_encode()用法: <?php$data =a ...
- TP5 volist
VOLIST标签 volist标签通常用于查询数据集(select方法)的结果输出,通常模型的select方法返回的结果是一个二维数组,可以直接使用volist标签进行输出. 在控制器中首先对模版赋值 ...
- oracle的JOB
前文再续,上面说的oracle的JOB,近期有些体会,记录一下: 零.创建JOB 创建JOB 1)创建一个存储过程.逻辑处理都在这个存储过程里面. 2)创建一个JOB运行此存储过程 -- 创建tabl ...