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

发表于2018-05-21
评论0 4.5k浏览
使用Cocos2dx 进行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 = 11024 * 7768 * 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 <11024 * 4; x++)  
        {  
            buffer2[(767 - y) * 11024 * 4 + x] = buffer[y * 44 * 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 = 44 * 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 = 44 * 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平台中将截图保存到相册的功能。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引