Cocos2dx在IOS平台中将截屏保存到到手机相册

来源:互联网 发布:网络棋牌游戏 编辑:程序博客网 时间:2024/04/29 06:18

最近使用Cocos2dx 2.2.3进行IOS游戏开发,碰到了关于截屏路径的一个问题,cocos2dx本身自带了截屏的功能,代码如下:

    CCSize size = CCDirector::sharedDirector()->getWinSize();    CCRenderTexture* renderTexture = CCRenderTexture::create(size.width, size.height);    CCScene* curScene = CCDirector::sharedDirector()->getRunningScene();    renderTexture->begin();    curScene->visit();    renderTexture->end();    renderTexture->saveToFile("curScene.png", kCCImageFormatPNG);

但是saveToFile()函数在IOS下面默认保存的路径是应用程序的Document目录,用户无法在自己的相册中进行查看,并且IOS下的权限控制很严格,想要访问相册的目录估计是无法在游戏内部进行了,于是在上网搜索半天无果之后,只好通过C++和OC混合编译,调用IOS的API来进行。苦于没有IOS开发基础,上网搜索了一段OC代码:

-(UIImage *) glToUIImage {    NSInteger myDataLength = 1024 * 768 * 4;        // allocate array and read pixels into it.    GLubyte *buffer = (GLubyte *) malloc(myDataLength);    glReadPixels(0, 0, 1024, 768, 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 <768; y++)    {        for(int x = 0; x <1024 * 4; x++)        {            buffer2[(767 - y) * 1024 * 4 + x] = buffer[y * 4 * 1024 + x];        }    }        // make data provider with data.    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer2, myDataLength, NULL);        // prep the ingredients    int bitsPerComponent = 8;    int bitsPerPixel = 32;    int bytesPerRow = 4 * 1024;    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();    CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;    CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;        // make the cgimage    CGImageRef imageRef = CGImageCreate(1024, 768, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);        // then make the uiimage from that    UIImage *myImage = [UIImage imageWithCGImage:imageRef];    return myImage;    UIImageWriteToSavedPhotosAlbum(myImage, self, nil, nil);}

这段代码通过glReadPixels来读取屏幕的像素值,然后转换为UIImage对象,最后通过UIImageWriteToSavedPhotosAlbum()保存到相册中间,只需要稍稍修改一下屏幕的尺寸能使用。在OC和C++混编的时候还有一些小问题要注意,就是在C++中包含OC头文件的时候不能直接包含:

#include "ScreenShot.h"


这样会报错,必须加上预编译的处理:

#ifdef __OBJC__#include "ScreenShot.h"#endif


然后将要混编的文件改为.mm文件,然后就能很方便的在C++中调用OC的代码了:

#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)    [ScreenShot saveImage];#else


到了这里我以为大功告成了,但是试验之后发现在模拟器中完美截屏,真机测试的时候却发现截图全是黑的,所有像素都是0。谷歌一番之后,找到了问题所在,stackoverflow上的原问题,glReadPixels读取的是缓冲区中的内容,而在ios6.0之后,系统会将已经显示过的内容从缓冲区中清空,而在游戏中调用glReadPixels时屏幕的内容可能已经显示过了,这是Cocos2dx内部的机制,我们无法更改,导致无法正确截图。

仔细思考一下,其实我们调用OC代码的部分也只有保存到相册的那一部分而已,至于截图,完全可以用Cocos2dx自带的功能,所以只要能获取renderTexture的像素信息,再在OC部分中转换为UIImage保存即可,由此诞生了最终版本:

//C++部分的代码    CCSize size = CCDirector::sharedDirector()->getWinSize();    CCRenderTexture* renderTexture = CCRenderTexture::create(size.width, size.height);    CCScene* curScene = CCDirector::sharedDirector()->getRunningScene();    renderTexture->begin();    curScene->visit();    renderTexture->end();    CCImage* image = renderTexture->newCCImage();#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)    [ScreenShot saveImage:image->getData() width:image->getWidth() height:image->getHeight()];#else    renderTexture->saveToFile("curScene.png", kCCImageFormatPNG);#endif

//OC部分的代码@interface ScreenShot : NSObject+(void) saveImage: (GLubyte*)imageData width: (int)width height:(int)height;@end@implementation ScreenShot+(void) saveImage: (GLubyte*)imageData width: (int)width height:(int)height{    NSInteger myDataLength = width * height * 4;    // make data provider with data.    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, imageData, myDataLength, NULL);        // prep the ingredients    int bitsPerComponent = 8;    int bitsPerPixel = 32;    int bytesPerRow = 4 * width;    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();    CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;    CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;        // make the cgimage    CGImageRef imageRef = CGImageCreate(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);        // then make the uiimage from that    UIImage *myImage = [UIImage imageWithCGImage:imageRef];    UIImageWriteToSavedPhotosAlbum(myImage, nil, nil, nil);}@end

通过renderTexture->newCCImage()->getData()获取unsigned char* 像素数据,然后再saveImage函数中转换为UIImage对象最后保存,由此实现在IOS平台中将截图保存到相册的功能。




0 0