cocos2dx cpp与oc混编打开ios摄像头或图库取图

为了完成这个需求,花了几天时间,各种求助。对于我这个菜鸟初学者而言确实有些难度。

在此整理一下,希望大家少走弯路。可能没考虑内存泄露等方面,因为我还没看这方面的东西,只满足需求先。

 

新建一个cocos2dx项目OpenCamera

由于要使用Cpp和OC混编,我们基于Cpp建一个混编类。

即先建一个C++类,再改后缀名到mm,主编码风格使用C++的。

在ios文件夹下新建C++类UtilBridge

将UtilBridge.cpp改名为UtilBridge.mm,在文件中随便打个空格保存一下。

声明静态方法后,各文件如下:

.h

 1 //
 2 //  UtilBridge.h
 3 //  OpenCamera
 4 //
 5 //  Created by HanHongmin on 13-12-30.
 6 //
 7 //
 8 
 9 #ifndef __OpenCamera__UtilBridge__
10 #define __OpenCamera__UtilBridge__
11 
12 #include "cocos2d.h"
13 using namespace cocos2d;
14 class UtilBridge:public CCObject{
15 public:
16     static void openCamera();
17 };
18 
19 #endif /* defined(__OpenCamera__UtilBridge__) */

.mm

 1 //
 2 //  UtilBridge.cpp
 3 //  OpenCamera
 4 //
 5 //  Created by HanHongmin on 13-12-30.
 6 //
 7 //
 8 
 9 #include "UtilBridge.h"
10 
11 void UtilBridge::openCamera(){
12     
13 }

 

打开ios摄像头等要用到oc代码,大家可以去搜一下原理。这里要用到一个代理类,我没有改RootViewController,而是新写了一个OC类,这么干我不知道会不会有问题,如果有请大家指出。

新建OC类PickerDelegate继承NSObject,文件创建好之后在声明中加上所需接口,之后文件内容如下:

.h

 1 //
 2 //  PickerDelegate.h
 3 //  OpenCamera
 4 //
 5 //  Created by HanHongmin on 13-12-30.
 6 //
 7 //
 8 
 9 #import <Foundation/Foundation.h>
10 
11 @interface PickerDelegate : NSObject<UINavigationControllerDelegate,UIImagePickerControllerDelegate>
12 
13 @end

.m

 1 //
 2 //  PickerDelegate.m
 3 //  OpenCamera
 4 //
 5 //  Created by HanHongmin on 13-12-30.
 6 //
 7 //
 8 
 9 #import "PickerDelegate.h"
10 
11 @implementation PickerDelegate
12 
13 
14 -(id) init
15 {
16     if(self = [super init])
17     {
18     }
19     return self;
20 }
21 
22 - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
23 {
24     //CCLog("selected");
25     //处理数据
26     UIImage* image = [info valueForKey:UIImagePickerControllerOriginalImage];
27     
28     [picker dismissModalViewControllerAnimated: YES];
29     [picker release];
30 }
31 
32 
33 - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
34 {
35     //CCLog("cancle");
36     [picker dismissModalViewControllerAnimated: YES];
37     [picker release];
38 }
39 
40 @end

 

 

回到UtilBridge.mm实现openCamera方法

注意:在mm中#include "PickerDelegate.h",不要写道.h文件中。

#include "PickerDelegate.h"

void UtilBridge::openCamera(){
    
    UIImagePickerController *picker = [[UIImagePickerController alloc] init];
    //设置图像来源类型(先判断系统中哪种图像源是可用的)
    if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
        picker.sourceType = UIImagePickerControllerSourceTypeCamera;
    }else if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]){
        picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
    }else {
        picker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
    }
    
    PickerDelegate* delegate = [[PickerDelegate alloc] init];
    picker.delegate = delegate;
    [[UIApplication sharedApplication].keyWindow.rootViewController presentModalViewController:picker animated:YES];
    
}

在HelloWorld::init方法中调用openCamera

bool HelloWorld::init()
{
    if ( !CCLayer::init() )
    {
        return false;
    }
    UtilBridge::openCamera();
    return true;
}

运行一下,报错了...

貌似跟横竖屏有关,把项目调整到竖屏,再试试。我的需求就是竖屏,所以深层次的原因我就不找啦~~~

模拟器没有摄像头设备,所以打开的是图库,试摄像头要到真机上。

 

我们在PickerDelegate中能够拿到UIImage,拿到后转变成cocos2dx可用的格式,回调HelloWord的方法再干一些事,比如显示出来。

关于把方法当参数传进来之类的我一概不懂,所以在PickerDelegate中直接调HelloWorld,所以.m改成.mm以实现混编。

我们先说UIImage的数据转换

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
    //CCLog("selected");
    //处理数据
    UIImage* image = [info valueForKey:UIImagePickerControllerOriginalImage];
    
    CGImageRef imageRef = [image CGImage];
    NSUInteger width = CGImageGetWidth(imageRef);
    NSUInteger height = CGImageGetHeight(imageRef);
    CCLog("%i,%i",width,height);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    unsigned char* rawData = (unsigned char*) calloc(height * width * 4, sizeof(unsigned char));
    NSUInteger bytesPerPixel = 4;
    NSUInteger bytesPerRow = bytesPerPixel * width;
    NSUInteger bitsPerComponent = 8;
    CGContextRef context = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
    CGColorSpaceRelease(colorSpace);
    CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
    CGContextRelease(context);
    cocos2d::CCTexture2D *pickedImage = new cocos2d::CCTexture2D();
    pickedImage->initWithData(rawData, cocos2d::kCCTexture2DPixelFormat_RGBA8888, width, height, cocos2d::CCSizeMake(width, height));
    CCLOG("%f,%f",pickedImage->getContentSize().width,pickedImage->getContentSize().height);
    
    [picker dismissModalViewControllerAnimated: YES];
    [picker release];
}

以上,我们已经把图片数据转换到了CCTexture2D,至于为何这么转,我也是搜来哒~注意引入响应头文件,这个以后就不说了。

HelloWorld声明和定义接口,接收CCTexture2D并干一些我们想干的事。

.h

void pickedPhoto(CCTexture2D* texture);

.cpp

void HelloWorld::pickedPhoto(CCTexture2D* texture){
    CCSprite* sprite = CCSprite::createWithTexture(texture);
    this->addChild(sprite);
}

OK,试一下。报错啦

断点停在了this->addChild(sprite);这一行。根据java的经验,this指针怎么可能是bad access...如果他是空指针,

delegate里的layer->pickedPhoto(pickedImage);就报啦。当然这不是java,比较纠结。

这里费死了劲,因为不会C++嘛,最后试来试去,HelloWorld的layer忘了设置tag。

CCScene* HelloWorld::scene()
{
    CCScene *scene = CCScene::create();
    HelloWorld *layer = HelloWorld::create();
    layer->setTag(1);
    scene->addChild(layer);

    return scene;
}

试一下是OK了,但是摄像头拍照的图为啥是横着的呢?

再次搜来搜去,解决之~

新建OC category扩展UIImage

 

UIImage+fixOrientation.h文件

 1 //
 2 //  UIImage+fixOrientation.h
 3 //  OpenCamera
 4 //
 5 //  Created by HanHongmin on 13-12-30.
 6 //
 7 //
 8 
 9 #import <UIKit/UIKit.h>
10 
11 @interface UIImage (fixOrientation)
12 -(UIImage*) fixOrientation;
13 @end

UIImage+fixOrientation.m文件

 1 //
 2 //  UIImage+fixOrientation.m
 3 //  OpenCamera
 4 //
 5 //  Created by HanHongmin on 13-12-30.
 6 //
 7 //
 8 
 9 #import "UIImage+fixOrientation.h"
10 
11 @implementation UIImage (fixOrientation)
12 - (UIImage *)fixOrientation {
13     if (self.imageOrientation == UIImageOrientationUp) return self;
14     
15     UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
16     [self drawInRect:(CGRect){0, 0, self.size}];
17     UIImage *normalizedImage = UIGraphicsGetImageFromCurrentImageContext();
18     UIGraphicsEndImageContext();
19     return normalizedImage;
20 }
21 @end

以上有啥不明白的,自己搜去吧我也说不明白。这个东西用了之后,据说手机内存会突然增大大概40-50M,求良药啊

在PickerDelegate中引用上面的头文件,得到UIImage后调一下。

UIImage* image = [info valueForKey:UIImagePickerControllerOriginalImage];

  image = [image fixOrientation];

试试~~

图片拾取后发现只显示了一部分,我在控制台看到摄像头拍完后图片是2448x3264的,所以这里应该没啥问题。

自行处理一下吧。我在项目中用的时候,sprite是早就创建好的,大小是整个屏幕,只是获得Texture的时候更换到了sprite中,没啥问题的。

至于如何调节分辨率啥的,有空再研究吧。

 

 

 

posted @ 2013-12-30 17:00  韩宏敏  阅读(3478)  评论(1编辑  收藏  举报