• 第一种方法:用RenderTexture实现截图功能

在cocos2dx 3.2之前,引擎没有提供截图功能,我们可以用RenderTexture来实现截图功能,这个方法在cocos2dx 3.2之后也是可以用的。

--lua 脚本实现截图功能的函数:
function Resources.getScreenShot(node)if node == nil or tolua.isnull(node) thencclog("getScreenShot node == nil")return nilendlocal size = node:getContentSize()if size.width <= 0 or size.height <= 0 thensize = cc.Director:getInstance():getWinSize()endlocal screen = cc.RenderTexture:create(size.width, size.height, cc.TEXTURE2_D_PIXEL_FORMAT_RGB_A8888, 0x88F0)screen:begin()node:visit()screen:endToLua()local uroot = cc.FileUtils:getInstance():getWritablePath()local filePath = string.format("ss_%d.png",os.time)screen:saveToFile(filePath, kCCImageFormatPNG)return uroot..filePath
end

创建RenderTexture时需要四个参数(宽,高,渲染纹理格式,深度),渲染纹理格式参数为空时,默认渲染纹理格式为RGBA8888,深度参数为空时,默认深度为0。

用RenderTexture实现截图功能的原理是:先创建一个指定的渲染纹理并开始记录,然后通过访问指定节点并递归的绘制所有子节点,当所有子节点都绘制完成之后,渲染纹理停止记录并且将渲染纹理保存成图片。简单的说就是创建一个画布,将需要的节点的内容画在画布上,然后将画布保存起来。

用RenderTexture实现截图功能的优点:1、对内存消耗比较小,在真机上测试时体现为截图快,耗时少;2、能够指定截图的大小和内容;

用RenderTexture实现截图功能的缺点:如果使用RenderTexture实现截图时,指定的截图根节点下包含Sprite3D,则得到的截图并不包含Sprite3D(这个缺点是我在使用过程中遇到的,具体原因还没深究,欢迎指点)

第二种方法:用utils:captureScreen的方法截图

在cocos2dx 3.2版本,utils:captureScreen()方法被加入用于保存屏幕截图

//captureScreen接口源码
static EventListenerCustom* s_captureScreenListener;
static CustomCommand s_captureScreenCommand;
void captureScreen(const std::function<void(bool, const std::string&)>& afterCaptured, const std::string& filename)
{if (s_captureScreenListener){CCLOG("Warning: CaptureScreen has been called already, don't call more than once in one frame.");return;}s_captureScreenCommand.init(std::numeric_limits<float>::max());s_captureScreenCommand.func = std::bind(onCaptureScreen, afterCaptured, filename);s_captureScreenListener = Director::getInstance()->getEventDispatcher()->addCustomEventListener(Director::EVENT_AFTER_DRAW, [](EventCustom* /*event*/) {auto director = Director::getInstance();director->getEventDispatcher()->removeEventListener((EventListener*)(s_captureScreenListener));s_captureScreenListener = nullptr;director->getRenderer()->addCommand(&s_captureScreenCommand);director->getRenderer()->render();});
}
//captureScreen实现的源码
/**
* Capture screen implementation, don't use it directly.
*/
void onCaptureScreen(const std::function<void(bool, const std::string&)>& afterCaptured, const std::string& filename)
{static bool startedCapture = false;if (startedCapture){CCLOG("Screen capture is already working");if (afterCaptured){afterCaptured(false, filename);}return;}else{startedCapture = true;}auto glView = Director::getInstance()->getOpenGLView();auto frameSize = glView->getFrameSize();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_MAC) || (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) || (CC_TARGET_PLATFORM == CC_PLATFORM_LINUX)frameSize = frameSize * glView->getFrameZoomFactor() * glView->getRetinaFactor();
#endifint width = static_cast<int>(frameSize.width);int height = static_cast<int>(frameSize.height);bool succeed = false;std::string outputFile = "";do{std::shared_ptr<GLubyte> buffer(new GLubyte[width * height * 4], [](GLubyte* p){ CC_SAFE_DELETE_ARRAY(p); });if (!buffer){break;}glPixelStorei(GL_PACK_ALIGNMENT, 1);glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer.get());std::shared_ptr<GLubyte> flippedBuffer(new GLubyte[width * height * 4], [](GLubyte* p) { CC_SAFE_DELETE_ARRAY(p); });if (!flippedBuffer){break;}for (int row = 0; row < height; ++row){memcpy(flippedBuffer.get() + (height - row - 1) * width * 4, buffer.get() + row * width * 4, width * 4);}Image* image = new (std::nothrow) Image;if (image){image->initWithRawData(flippedBuffer.get(), width * height * 4, width, height, 8);if (FileUtils::getInstance()->isAbsolutePath(filename)){outputFile = filename;}else{CCASSERT(filename.find("/") == std::string::npos, "The existence of a relative path is not guaranteed!");outputFile = FileUtils::getInstance()->getWritablePath() + filename;}// Save image in AsyncTaskPool::TaskType::TASK_IO thread, and call afterCaptured in mainThreadstatic bool succeedSaveToFile = false;std::function<void(void*)> mainThread = [afterCaptured, outputFile](void* /*param*/){if (afterCaptured){afterCaptured(succeedSaveToFile, outputFile);}startedCapture = false;};AsyncTaskPool::getInstance()->enqueue(AsyncTaskPool::TaskType::TASK_IO, std::move(mainThread), nullptr, [image, outputFile](){succeedSaveToFile = image->saveToFile(outputFile);delete image;});}else{CCLOG("Malloc Image memory failed!");if (afterCaptured){afterCaptured(succeed, outputFile);}startedCapture = false;}} while (0);
}
--lua脚本调用captureScreen
function Resources.getNewScreenShot( imgName, callBack )local function defaultCallBack( ... )-- cclog("test getNewScreenShot()")endlocal afterCaptured = callBack or defaultCallBacklocal uroot = cc.FileUtils:getInstance():getWritablePath()local filePath = imgName or string.format("ss_%d.png",os.time())cc.utils:captureScreen(afterCaptured, filePath)return uroot..filePath
end

调用captureScreen需要两个参数:截图保存的文件名以及截图完成后的回调

通过源码分析,captureScreen截图是通过glReadPixels()把已经绘制好的像素(它可能已经被保存到显卡的显存中)读取到内存,然后再将这部分数据复制一份出来,然后新建一个Image,用这份数据初始化Image,然后另外开启一个线程完成将Image保存到指定路径、执行完成截图后的回调、删除Image对象的工作。

调用captureScreen截图的优点:captureScreen截图就像是手机截图,能够将手机屏幕显示的所有像素保存在截图内,即使面对Sprite3D,也能完成截图。

调用captureScreen截图的缺点:1、无法指定截图大小,截图内容;2、对内存消耗比较大,在真机上测试时体现为截图较慢,耗时较长

cocos2dx 3.x 屏幕截图的两种方法及其优缺点相关推荐

  1. cocos2dx 3.x(屏幕截图的两种方法)

    [RenderTexture] RenderTexture这个动态纹理类,顾名思义就是可以动态创建纹理图片. 屏幕截图主要步骤: > 开始截图:render->begin(); >  ...

  2. 系统制作U盘两种方法及优缺点-UltraISO和Win32DiskImager,制作后怎么清空U盘恢复正常使用

    1.下面介绍制作U盘启动的两种工具 1.1下面是UltraISO工具和Win32DiskImager工具下载地址 链接:https://pan.baidu.com/s/1Qjtm2uC6zAQYLT_ ...

  3. Cocos2d-x 处理双击事件的两种方法

    在cocos2d-x的开发过程中有些时候也是需要用到双击的事件处理,那么由于在cocos2d-x中没有实现对双击的事件的处理,那么我们就需要自己用代码实现. 下面介绍两种方式实现双击事件的处理. (一 ...

  4. C++ 区分中文,非中文,截取含有中文的string字符串的两种方法

    C++ 区分中文,非中文,截取含有中文的string字符串的两种方法 方法一 根据中文在ASCII中的范围判断 方法二 把string转成wstring 转自: http://blog.51cto.c ...

  5. SQL Server中灾难时备份结尾日志(Tail of log)的两种方法

    简介 在数据库数据文件因各种原因发生损坏时,如果日志文件没有损坏.可以通过备份结尾日志(Tail of log)使得数据库可以恢复到灾难发生时的状态. 例如: 上图中.在DB_1中做了完整备份,在Lo ...

  6. C++/C++11中用于定义类型别名的两种方法:typedef和using

    类型别名(type alias)是一个名字,它是某种类型的同义词.使用类型别名有很多好处,它让复杂的类型名字变得简单明了.易于理解和使用,还有助于程序员清楚地知道使用该类型的真实目的.在C++中,任何 ...

  7. jquery-12 折叠面板如何实现(两种方法)

    jquery-12 折叠面板如何实现(两种方法) 一.总结 一句话总结:1.根据点击次数来判断显示还是隐藏,用data方法保证每个元素一个点击次数:2.找到元素的下一个,然后toggle实现显示隐藏. ...

  8. java 匿名list,java创造匿名对象的两种方法

    在java中有时候需要一些匿名对象的使用.可能有些小伙伴拿还不会创造,其实我们在学习一些方法时都或多或少的接触过.本篇所要讲到的创造匿名对象总结了两种方法,分别是静态工具方法和Lambda表达式,我们 ...

  9. Android Studio导入Eclipse项目的两种方法

    Android Studio导入Eclipse项目有两种方法,一种是直接把Eclipse项目导入Android Studio,另一种是在Eclipse项目里面进行转换,然后再导入Android Stu ...

最新文章

  1. JAVA图片处理--缩放,切割,类型转换
  2. 使用密钥验证方式登录linux系统
  3. Power of Two
  4. Excel,Python,SQL?数据分析师的技能树要怎么点?
  5. Redis:12---有序集合对象
  6. 【剑指offer】面试题25:合并两个排序的链表(Java 实现)
  7. Linux 学习笔记_12_Windows与Linux文件共享服务_1.1_--Samba(下)Samba经典应用案例
  8. n卡eth挖矿设置_ETH2.0要来了,要不要布局显卡挖矿?
  9. 抢购活动的粗略设计和实现
  10. python:将数据写入csv文件
  11. Oracle | oracle11g安装环境变量配置
  12. 易语言高级表格写入MYSQL_易语言高级表格读写EXCEL源码
  13. Wind的实时行情API使用
  14. python基础ppt_Python入门之你必须了解的基础知识
  15. 内存不能为“read” “written”的解决方法
  16. 软件工程毕业设计课题(34)基于JAVA毕业设计JAVA医院预约挂号系统毕设作品项目
  17. 冒险岛启动游戏提示计算机丢失,各种无法登陆情况解决建议汇总
  18. 今日头条广告投放技巧干货:落地页分析工具
  19. mysql 内联函数_内联函数 - freeboy小亮 - 博客园
  20. 职业连连看模型,助你找到理想职业

热门文章

  1. 操作系统 实验一 进程管理与进程同步
  2. 好用的验证码短信API推荐
  3. python如何读取word中超链接的文本_如何使用python从docx文件中提取超链接中的url...
  4. 动态规划经典题目-数据压缩之图像压缩
  5. 数据结构考研复习知识点梳理(自用非408)第一章
  6. html怎么在序列表中加竖线,Chorme浏览器渲染MathJax时出现竖线的解决方法
  7. RNA-seq FPKMRPKMTPM的介绍区别
  8. 迷你php搭建,laravel 30分站搭建迷你博客
  9. Java笔试题(牢固基础成绩雄壮伟业)
  10. 炫界 (302) -(查动简)_小米有品又玩极简石英表?这块表确实不一样