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中,沒啥問題的。

至於如何調節分辨率啥的,有空再研究吧。

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM