☰
【2014-07-08】cocos2dx学习笔记:CCImage及获取特定点的颜色值
2026/9/27 18:27:15 网站建设 项目流程

[历史归档]本文原发布于 cstriker1407.info 个人博客,内容为历史存档,仅供参考。
发布时间:2014-07-08| 标题:cocos2dx学习笔记:CCImage及获取特定点的颜色值|分类:编程 / C && C++ / cocos2dx |标签:cocos2dx·CCImage


cocos2dx学习笔记:CCImage及获取特定点的颜色值

    • CCImage简单分析:
    • 获取特定点颜色的方法:
    • 备注:

在进行cocos2dx游戏开发时,我们有时候需要知道特定点的颜色,这里笔记下如何使用CCImage读取png文件来实现。

CCImage简单分析:

这里我们先简单的分析下CCImage的实现。
首先看下【CCImage::initWithImageFile】的实现,在文件【\cocos2d-x-2.2.3\cocos2dx\platform\CCImageCommon_cpp.h】中:

boolCCImage::initWithImageFile(constchar*strPath,EImageFormat eImgFmt/* = eFmtPng*/){boolbRet=false;#ifdefEMSCRIPTEN。。。。。。 。。。。。。#elseunsignedlongnSize=0;std::string fullPath=CCFileUtils::sharedFileUtils()->fullPathForFilename(strPath);//获取了传入文件的绝对路径//读文件,pBuffer为文件内容,nSize为内容长度unsignedchar*pBuffer=CCFileUtils::sharedFileUtils()->getFileData(fullPath.c_str(),"rb",&nSize);if(pBuffer!=NULL&&nSize>0){//进入函数进行处理,这里假设我们传入的eImgFmt为png类型的。bRet=initWithImageData(pBuffer,nSize,eImgFmt);}CC_SAFE_DELETE_ARRAY(pBuffer);#endif// EMSCRIPTENreturnbRet;}boolCCImage::initWithImageData(void*pData,intnDataLen,EImageFormat eFmt/* = eSrcFmtPng*/,intnWidth/* = 0*/,intnHeight/* = 0*/,intnBitsPerComponent/* = 8*/){boolbRet=false;do{CC_BREAK_IF(!pData||nDataLen<=0);if(kFmtPng==eFmt){bRet=_initWithPngData(pData,nDataLen);break;}//这里我们仅仅分析png格式的读取,其他的先略掉。。。。。。 。。。。。。}while(0);returnbRet;}//cocos2dx使用libpng来读取png图片,具体的使用方法这里不再展开笔记,只笔记下整体的流程boolCCImage::_initWithPngData(void*pData,intnDatalen){// length of bytes to check if it is a valid png file#definePNGSIGSIZE8boolbRet=false;//先声明libpng需要的结构体png_byte header[PNGSIGSIZE]={0};png_structp png_ptr=0;png_infop info_ptr=0;do{//各种校验// png header len is 8 bytesCC_BREAK_IF(nDatalen<PNGSIGSIZE);// check the data is png or notmemcpy(header,pData,PNGSIGSIZE);CC_BREAK_IF(png_sig_cmp(header,0,PNGSIGSIZE));// init png_struct//初始化结构体png_ptr=png_create_read_struct(PNG_LIBPNG_VER_STRING,0,0,0);CC_BREAK_IF(!png_ptr);//初始化结构体// init png_infoinfo_ptr=png_create_info_struct(png_ptr);CC_BREAK_IF(!info_ptr);#if(CC_TARGET_PLATFORM!=CC_PLATFORM_BADA&&CC_TARGET_PLATFORM!=CC_PLATFORM_NACL)CC_BREAK_IF(setjmp(png_jmpbuf(png_ptr)));#endif// set the read call back functiontImageSource imageSource;imageSource.data=(unsignedchar*)pData;imageSource.size=nDatalen;imageSource.offset=0;//设定了读取的回调函数png_set_read_fn(png_ptr,&imageSource,pngReadCallback);// read png header info//读取png文件信息// read png file infopng_read_info(png_ptr,info_ptr);//获取了文件的宽,高等信息m_nWidth=png_get_image_width(png_ptr,info_ptr);m_nHeight=png_get_image_height(png_ptr,info_ptr);m_nBitsPerComponent=png_get_bit_depth(png_ptr,info_ptr);png_uint_32 color_type=png_get_color_type(png_ptr,info_ptr);//CCLOG("color type %u", color_type);//将不同的png设置为RGB8888的格式。// force palette images to be expanded to 24-bit RGB// it may include alpha channelif(color_type==PNG_COLOR_TYPE_PALETTE){png_set_palette_to_rgb(png_ptr);}// low-bit-depth grayscale images are to be expanded to 8 bitsif(color_type==PNG_COLOR_TYPE_GRAY&&m_nBitsPerComponent<8){png_set_expand_gray_1_2_4_to_8(png_ptr);}// expand any tRNS chunk data into a full alpha channelif(png_get_valid(png_ptr,info_ptr,PNG_INFO_tRNS)){png_set_tRNS_to_alpha(png_ptr);}// reduce images with 16-bit samples to 8 bitsif(m_nBitsPerComponent==16){png_set_strip_16(png_ptr);}// expand grayscale images to RGBif(color_type==PNG_COLOR_TYPE_GRAY||color_type==PNG_COLOR_TYPE_GRAY_ALPHA){png_set_gray_to_rgb(png_ptr);}// read png data// m_nBitsPerComponent will always be 8m_nBitsPerComponent=8;png_uint_32 rowbytes;//根据高度申请行数组,每个元素代表一行,每个元素的类型为png_bytep,即unsigned char*png_bytep*row_pointers=(png_bytep*)malloc(sizeof(png_bytep)*m_nHeight);png_read_update_info(png_ptr,info_ptr);//获取存储单行的像素的数据的大小(字节),也就是宽*4(RGBA,每个占一字节)rowbytes=png_get_rowbytes(png_ptr,info_ptr);//根据行数(高)和单行的数据大小申请存储空间,每个元素类型为unsigned char*//用来存储rgba中的一个。即每4个元素构成一个完整的像素m_pData=newunsignedchar;CC_BREAK_IF(!m_pData);//更新下行数组的节点,将每行的起始位置赋值到行数组的节点for(unsignedshorti=0;i<m_nHeight;++i){row_pointers=m_pData+i*rowbytes;}//按行读取数据png_read_image(png_ptr,row_pointers);//读取结束png_read_end(png_ptr,NULL);//获取单个像素点占用的字节。png_uint_32 channel=rowbytes/m_nWidth;if(channel==4)//这里必须为4,RGBA{m_bHasAlpha=true;//用unsigned int 类型来处理m_pData,这样一次++就可以转到下一个像素点。unsignedint*tmp=(unsignedint*)m_pData;for(unsignedshorti=0;i<m_nHeight;i++){for(unsignedintj=0;j<rowbytes;j+=4){//将RGBA转换下重新放到原位置,宏定义在下面//这里需要注意的是tmp的位置和row_pointers其实是一样的。//只不过是类型不同,tmp类型为unsigned int,++一次移动4个字节,即一个像素。//row_pointers为png_bytep(unsigned char *)型,++一次移动1个字节。因此row_pointers//为row_pointers向后移动一个字节。这里每4个字节构成一个完整的像素点。*tmp++=CC_RGB_PREMULTIPLY_ALPHA(row_pointers,row_pointers,row_pointers,row_pointers);}}m_bPreMulti=true;}CC_SAFE_FREE(row_pointers);bRet=true;}while(0);if(png_ptr){png_destroy_read_struct(&png_ptr,(info_ptr)?&info_ptr:0,0);}returnbRet;}//非常重要的一个宏,通过这个宏我们可以知道rgba在内存中的分布。// premultiply alpha, or the effect will wrong when want to use other pixel format in CCTexture2D,// such as RGB888, RGB5A1#defineCC_RGB_PREMULTIPLY_ALPHA(vr,vg,vb,va)\(unsigned)(((unsigned)((unsignedchar)(vr)*((unsignedchar)(va)+1))>>8)|\((unsigned)((unsignedchar)(vg)*((unsignedchar)(va)+1)>>8)<<8)|\((unsigned)((unsignedchar)(vb)*((unsignedchar)(va)+1)>>8)<<16)|\((unsigned)(unsignedchar)(va)<<24))// on ios, we should use platform/ios/CCImage_ios.mm instead

因此,根据最后的这个宏CC_RGB_PREMULTIPLY_ALPHA,我们就可以得到如下的函数,用来获取指定点的颜色:

获取特定点颜色的方法:

cocos2d::ccColor4BgetImageColorOfPos(cocos2d::CCImage*pImage,cocos2d::CCPoint&pt){ccColor4B c={0,0,0,0};//cocos2dx使用的是openGL坐标系,y坐标是从下到上递增的。//libpng读取png图片时是从上到下逐行读取的,因此这里的纵坐标需要处理下。unsignedintx=pt.x,y=pImage->getHeight()-pt.y;intwidth=pImage->getWidth();unsignedchar*data_=pImage->getData();unsignedint*pixel=(unsignedint*)data_;//以unsigned int来处理pixel=pixel+(y*width)+x;//跳到指定的像素点。c.a=(*pixel>>24)&0xff;floatscale=(c.a+1.0f)/256;c.r=*pixel&0xff;c.r=c.r/scale;c.g=(*pixel>>8)&0xff;c.g=c.g/scale;c.b=(*pixel>>16)&0xff;c.b=c.b/scale;returnc;}//代码示例:CCImage*pImage=newCCImage();pImage->initWithImageFile("images.png",CCImage::kFmtPng);ccColor4B colorOfPos=getImageColorOfPos(pImage,ccp(0,0));pImage->release();

备注:

由于获取颜色的代码中有很多数学运算,比较复杂,这里可以简化一下,如果png上所有像素的透明度全部为255,那么根据**(255 + 1)>>8 = 1**可以得出:

c.r=*pixel&0xff;c.g=(*pixel>>8)&0xff;c.b=(*pixel>>16)&0xff;c.a=(*pixel>>24)&0xff;

这样可以简化掉相当多的运算。

后续参考加深资料:

【 http://www.cnblogs.com/xiaoxiaoboke/archive/2012/02/13/2349765.html 】
【 http://blog.csdn.net/honghaier/article/details/8032434 】

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询