上节讲到了cocos2d-x在iOS上解压绝大数的图片格式为CCImage,然后再转化为纹理格式。其中有一个列外就是Webp格式。今天我们来看看Windows上面的情况,Android上的情况和Windows是类似的,都是使用第三方库来解码图片。按照道理来讲,Android上是可以采用类似iOS的技术,使用Android的系统库来解码图片,而且Android在4.0版本上已经开始原生支持Webp格式了。但是Android的系统库是Java的,如果要传到cocos2d-x中需要通过Jni调用,也就增加了不必要的麻烦。在早期cocos2d-x读取assets资源有严重的性能问题,本人采用了这个方法获得了巨大的性能提升。新的cocos2d-x读取assets的资源利用了缓存加速,性能和这种迂回的方式相差不多了。

好我们来看看windows平台下的CCImage文件,如果你是Mac系统,在xcode工程中是看不到这个文件的,但是你可以使用Sublime打开源码目录下面的文件自行查看。在Windows下面,CCImage的文件组织有点特别。除了platform下面的CCImage.h的头文件,和win32下面的CCImage.cpp文件以外,在platform下面还有两个额外的文件也就是CCImageCommon_cpp.h和CCImageCommonWebp.cpp文件。第一个文件也是源文件,命名为.h是可以通过条件编译导入到CCImage.cpp文件中,至于Webp文件要单独列出来,是因为iOS上也要用到这个文件。因为其他格式的图片解码和Webp的流程差不多,我们使用Webp作为讲解。还记得那个判断函数吗?在Windows下面他变成了这个样子:

bool CCImage::initWithImageData(void * pData,   int nDataLen,                                 EImageFormat eFmt/* = eSrcFmtPng*/,                                 int nWidth/* = 0*/,                                int nHeight/* = 0*/,                                int nBitsPerComponent/* = 8*/){  bool bRet = false;  do   {    CC_BREAK_IF(! pData || nDataLen <= 0);     if (kFmtPng == eFmt)    {      bRet = _initWithPngData(pData, nDataLen);      break;    }    else if (kFmtJpg == eFmt)    {      bRet = _initWithJpgData(pData, nDataLen);      break;    }    else if (kFmtTiff == eFmt)    {      bRet = _initWithTiffData(pData, nDataLen);      break;    }#if (CC_TARGET_PLATFORM != CC_PLATFORM_WINRT) && (CC_TARGET_PLATFORM != CC_PLATFORM_WP8)    else if (kFmtWebp == eFmt)    {      bRet = _initWithWebpData(pData, nDataLen);      break;    }#endif    else if (kFmtRawData == eFmt)    {      bRet = _initWithRawData(pData, nDataLen, nWidth, nHeight, nBitsPerComponent, false);      break;    }    else    {          // if it is a png file buffer.      if (nDataLen > 8)      {        unsigned char* pHead = (unsigned char*)pData;        if (   pHead[0] == 0x89          && pHead[1] == 0x50          && pHead[2] == 0x4E          && pHead[3] == 0x47          && pHead[4] == 0x0D          && pHead[5] == 0x0A          && pHead[6] == 0x1A          && pHead[7] == 0x0A)        {          bRet = _initWithPngData(pData, nDataLen);          break;        }      }           // if it is a tiff file buffer.      if (nDataLen > 2)      {        unsigned char* pHead = (unsigned char*)pData;        if (  (pHead[0] == 0x49 && pHead[1] == 0x49)          || (pHead[0] == 0x4d && pHead[1] == 0x4d)          )        {          bRet = _initWithTiffData(pData, nDataLen);          break;        }      }           // if it is a jpeg file buffer.      if (nDataLen > 2)      {        unsigned char* pHead = (unsigned char*)pData;        if (   pHead[0] == 0xff          && pHead[1] == 0xd8)        {          bRet = _initWithJpgData(pData, nDataLen);          break;        }      }    }  } while (0);  return bRet;}


如果是Webp格式的文件就采用下面这个函数初始化了:

bool CCImage::_initWithWebpData(void*pData,intnDataLen){  bool bRet = false;  do  {    WebPDecoderConfig config;    if(WebPInitDecoderConfig(&config)==0)break;    if(WebPGetFeatures((uint8_t*)pData,nDataLen,&config.input)!=VP8_STATUS_OK)break;    if(config.input.width==0||config.input.height==0)break;     config.output.colorspace=MODE_RGBA;    m_nBitsPerComponent=8;    m_nWidth    = config.input.width;    m_nHeight  = config.input.height;    m_bHasAlpha = true;     int bufferSize = m_nWidth * m_nHeight * 4;    m_pData = new unsigned char[bufferSize];     config.output.u.RGBA.rgba=(uint8_t*)m_pData;    config.output.u.RGBA.stride=m_nWidth*4;    config.output.u.RGBA.size=bufferSize;    config.output.is_external_memory=1;     if(WebPDecode((uint8_t*)pData,nDataLen,&config)!=VP8_STATUS_OK)    {      delete[]m_pData;      m_pData=NULL;      break;    }     bRet=true;  }while(0);  return bRet;}


这个方式很简单,采用Google提供的Webp库解码图片。当然也要包含其头文件和lib。

#if defined(__native_client__) || defined(EMSCRIPTEN)// TODO(sbc): I'm pretty sure all platforms should be including// webph headers in this way.#include "webp/decode.h"#else#include "decode.h"#endif


其他格式由其第三方库的使用方法不同而不同,就不再多说了。相对而已Webp是很简洁的。这便是cocos2d-x中解码图片所采用的方法。还有一点值得注意的是,CCImage将其拷贝构造函数声明为了私有方法,也就是说你不能利用CCImage来赋值,毕竟里面是一大块内存,使用赋值或者添加到容器中都是很愚蠢的行为。

CCImage还有几个比较有趣的功能,他提供了一个saveToFile的函数。我们知道CCImage可以从相当多的格式初始化,那个这个saveToFile就可以作为一个转化函数来使用了。它能将图片保存为png或者jpg的格式,注意这个函数默认是不保存透明的,如果需要可以将其第二个参数设置为true。你可以采用压缩的图片格式打包,然后在游戏第一次运行的时候将其保存为易于解码的格式,来达到游戏发布体积和加载速度上的平衡。CCImage就能简单的完成这个操作。

CCImage还有一个功能就是,它能从一个string初始化一个图片。另外IOS和Android还提供了一个initWithStringShadowStroke的功能。如果你要显示很有艺术感的字体,不妨用用这个函数。字体的渲染向来都是很恶心的内容,在Windows和Android上cocos2d-x采用了一个叫做BitmapDC的概念,再调用各自的平台特性来完成这个工作。在Android上是采用jni的方式调用系统的函数实现的。在iOS上直接采用了系统函数,没有借用BitmapDC这个概念。有一个问题就是,如果你在Android上开启了Debug模式,那么会输出相当多的JVM释放资源的信息,这是因为每一次信息改动都生成了一张显示图片,造成JVM频繁回收。这极大的影响了游戏性能。所以TTF文件使用在Android上是极其低效的,如果你要做聊天,这方面有很大的优化余地。

更多相关文章

  1. 浅谈如何在Eclipse下的Android工程配置Git的.gitignore文件
  2. Android遍历本地视频文件加过滤
  3. Android生成pdf文件之PdfDocument及踩过的坑
  4. Android(Java):jni写文件打印调试信息
  5. Android配置----DDMS 连接真机(己ROOT),用file explore看不到data/
  6. 浅析Android下的Android.mk文件
  7. 在Android下创建文件夹
  8. Android Launcher开发(一)LiveFolder(实时文件夹) 完全解析

随机推荐

  1. Android之ViewTreeObserver
  2. MVP在Android中的初学之路
  3. Android(安卓)Studio下NDK开发之"No such
  4. Android编译环境的搭建(一)
  5. Android基于TCP和URL协议的网络编程示例
  6. 2012年移动互联网数据报告探讨
  7. 浅谈短、信彩信的拦截
  8. 使用Gitlab搭建Android和iOS的持续集成和
  9. 如何实现在 Android(安卓)Studio 上开发
  10. Android(安卓)XML文件链接错误