手遊控制安裝包的大小是很是重要的,這裏介紹一種方法。將帶Alpha通道的PNG圖片分拆成RGB和Alpha分別保存,其中保存RGB的這張圖把它轉換成JPG格式的文件,保存Alpha圖片的就用PNG格式的。原理是JPG格式的壓縮率比較的高能夠減少圖片的大小,可是它沒有Alpha,而Alpha數據單獨拎出來通常比較小,因此直接用PNG格式來保存。問題是怎樣分拆PNG圖片,又怎樣在程序中怎樣將兩張圖片的數據合併起來以達到和直接用一張帶Alpha的PNG圖渲染出來是同樣的效果。這裏提供我本身的方法,給你們參考下,有錯誤的地方但願你們指出來,謝謝!shell
1. 將PNG圖片分拆,也就是將一張PNG圖片生成出一張帶RGB的JPG+一張帶Alpha的PNG,我使用的工具是imagemagick。這裏以bg.png爲例:工具
首先ImageMagick工具提取出Alpha通道,(命令: convert bg.png -channel A -alpha extract bgAlpha.png)spa
而後在將bg.png轉成JPG格式 輸出爲bg.jpg。jpg格式已經不包含Alpha通道,並且jpg的壓縮率比較高(這是採用這種方法能夠減少圖片大小的根本所在)。(convert bg.png bg.jpg)code
這樣就獲得了bg.jpg 和bgAlpha.png,這兩張圖片就是咱們須要的資源。這樣轉換以後bg.jpg+bgAlpha.png的大小大概比bg.png的 小2~3倍對象
2. 在程序中合成blog
因爲在win,Android平臺採用的JPG和PNG解析庫和IOS上的不一樣,因此在程序中要分別處理,這裏介紹下在IOS上的方法(win和Android平臺解析參照CCImage的_initWithJpgData和_initWithPngData 方法,合併和IOS的平臺相似,不一樣地方文中會指出), 這個方法添加在CCImage.mm 文件中便可使用(cocos2dx版本是2.2.2)。圖片
bool CCImage::initWithRgbAndAlpha(const char * jpgFilePath, const char * pngFilePath) { bool bRet = false; do { // 得到JPG文件的數據
unsigned long nSizeJpg = 0; unsigned char* pBufferJpg = CCFileUtils::sharedFileUtils()->getFileData( CCFileUtils::sharedFileUtils()->fullPathForFilename(jpgFilePath).c_str(), "rb", &nSizeJpg); // 保證JPG文件數據必須是存在的
if (pBufferJpg == NULL && nSizeJpg <= 0) {return true;} // 得到Alpha文件的數據
unsigned long nSizePng = 0; unsigned char* pBufferPng = CCFileUtils::sharedFileUtils()->getFileData( CCFileUtils::sharedFileUtils()->fullPathForFilename(pngFilePath).c_str(), "rb", &nSizePng); tImageInfo jpgInfo = {0}; jpgInfo.hasShadow = false; jpgInfo.hasStroke = false; // 利用CCImage原有的方法解析JPG
bRet = _initWithData(pBufferJpg, nSizeJpg, &jpgInfo); unsigned char* jpgData = jpgInfo.data; if (!bRet) {return false;} tImageInfo pngInfo = {0}; pngInfo.hasShadow = false; pngInfo.hasStroke = false; //利用CCImage原有的方法解析Alpha文件
bRet = _initWithData(pBufferPng, nSizePng, &pngInfo); unsigned char* pngData = pngInfo.data; if (!bRet) {return false;} unsigned short jpgHeight = (short)jpgInfo.height; unsigned short jpgWidth = (short)jpgInfo.width; int jpgDataLen = jpgHeight * jpgWidth; int pngIndex = 0; int jpgIndex = 0; m_pData = new unsigned char[jpgHeight * jpgWidth * 4]; unsigned int *tmpData = (unsigned int *)m_pData; // 合併兩個文件的數據
for(int i = 0; i < jpgDataLen; i++) { // 這個宏和CC_RGB_PREMULTIPLY_ALPHA是同樣的,做用是將R,G,B 三個顏色值分別乘Alpha值獲得合併的R,G,B值,
*tmpData++ = CC_RGB_PREMULTIPLY_ALPHA_IOS( jpgData[jpgIndex], // R
jpgData[jpgIndex + 1], // G
jpgData[jpgIndex + 2], // B
pngData[pngIndex]); //A // 兩張圖片在解析以後都爲32位了,因此+4 (Android或者win上 不帶Alpha通道的png文件和jpg文件解析以後是24位的,這是主要區別的地方)
jpgIndex += 4; pngIndex += 4; } m_nHeight = (short)jpgInfo.height; m_nWidth = (short)jpgInfo.width; m_nBitsPerComponent = jpgInfo.bitsPerComponent; m_bPreMulti = true; m_bHasAlpha = true; CC_SAFE_DELETE_ARRAY(pBufferPng); CC_SAFE_DELETE_ARRAY(pBufferJpg); CC_SAFE_DELETE_ARRAY(jpgData); CC_SAFE_DELETE_ARRAY(pngData); bRet = true; } while (0); return bRet; }
這個方法執行以後bg.jpg和bgAlpha.png合併完成,當前的CCImage對象生成的紋理就和直接用bg.png初始化後生成的紋理效果是同樣的了。資源
另外附上一個將png圖片分拆成Jpg和Alpha的shell腳本(shell不太熟,將就着用^_^),使用這個腳本的前提是你已經安裝了imagemagick,這個腳本運行以後會遍歷當前目錄下的全部png文件,而後分拆這些文件,而且會刪除原png文件。(若是不想刪除原png文件,把`rm $src`去掉便可)get
#!/bin/sh convert_img(){ for file in `ls -a $1` do
if [ x"$file" != x"." -a x"$file" != x".." ];then str="$1/$file" length=${#str} sufLength=$(($length - 4)) strSuf=${str:$sufLength:$length} if [ x"$strSuf" = x".png" ];then src=${str:2:$length} dst=${str:2:$dstLength} dstLength=$(($length - 6)) dstSuf="mask" dstJpg=".jpg" convert $src -channel A -alpha extract $dst$dstSuf convert $src $dst$dstJpg `rm $src` echo $src elif [ -d "$1/$file" ];then convert_img "$1/$file" fi fi done } convert_img .