cocos2d-x调用摄像头和相册并裁减图片
2015-12-31 14:56
489 查看
最近做个小游戏需要调用手机图库和摄像头并裁减图片,发现网上很多教程不是太全,有的安卓端裁减不了大图,下面是完整代码,可以裁减高清图的。
完整拼图游戏下载:
https://github.com/sky068/Puzzles
1、首先是跨平台入口代码,iOS平台需要把ImageCrop.cpp改成ImageCrop.mm,并且在AppController.mm里调用setViewController(void* viewController)把rootView传进来初始化m_viewController
#ifndef ImageCrop_hpp #define ImageCrop_hpp #include <stdio.h> #include "cocos2d.h" USING_NS_CC; #define kImageCropEvent "ImageCropEvent" class ImageCrop { public: ImageCrop(); static ImageCrop* getInstance(); static void destroyInstance(); void openCamera(std::function<void(std::string)> callback); void openPhoto(std::function<void(std::string)> callback); #if ( CC_TARGET_PLATFORM == CC_PLATFORM_IOS) //设置AppController iOS平台在AppController.mm里调用把rootViewController传递过来 void setViewController(void* viewController); void *m_viewController; #endif private: static ImageCrop* _instance; std::function<void(std::string)> _callback; }; #endif // // ImageCrop.cpp // PhotoCrop // // Created by xujw on 15/12/28. // // #include "ImageCrop.hpp" #if ( CC_TARGET_PLATFORM == CC_PLATFORM_IOS) #import "ImagePickerViewController.h" #import "RootViewController.h" #endif #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) #include "platform/android/jni/JniHelper.h" #include <jni.h> #define JAVA_CLASS "org/cocos2dx/cpp/ImageCrop" #define JAVA_FUNC_OPEN_PHOTO "openPhoto" #define JAVA_FUNC_OPEN_CAMERA "openCamera" #endif ImageCrop::ImageCrop() :_callback(nullptr) { Director::getInstance()->getEventDispatcher()->addCustomEventListener(kImageCropEvent, [=](EventCustom *event) { std::string *imgPath = (std::string*)event->getUserData(); _callback(*imgPath); }); } ImageCrop* ImageCrop::_instance = nullptr; ImageCrop* ImageCrop::getInstance() { if (!_instance) { _instance = new (std::nothrow) ImageCrop(); } return _instance; } void ImageCrop::destroyInstance() { CC_SAFE_DELETE(_instance); } void ImageCrop::openCamera(std::function<void (std::string)> callback) { _callback = callback; #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) ImagePickerViewController * imagePickerViewController = [[ImagePickerViewController alloc]initWithNibName:nil bundle:nil]; RootViewController *_viewController = (RootViewController*)m_viewController; [_viewController.view addSubview:imagePickerViewController.view]; [imagePickerViewController takePhoto]; #endif #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) JniMethodInfo info; bool ret = JniHelper::getStaticMethodInfo(info,JAVA_CLASS,JAVA_FUNC_OPEN_CAMERA,"()V"); if (ret) { info.env->CallStaticVoidMethod(info.classID,info.methodID); } #endif } void ImageCrop::openPhoto(std::function<void (std::string)> callback) { _callback = callback; #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) ImagePickerViewController * imagePickerViewController = [[ImagePickerViewController alloc]initWithNibName:nil bundle:nil]; RootViewController *_viewController = (RootViewController*)m_viewController; [_viewController.view addSubview:imagePickerViewController.view]; [imagePickerViewController localPhoto]; #endif #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) JniMethodInfo info; bool ret = JniHelper::getStaticMethodInfo(info,JAVA_CLASS,JAVA_FUNC_OPEN_PHOTO,"()V"); if (ret) { info.env->CallStaticVoidMethod(info.classID,info.methodID); } #endif } #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) void ImageCrop::setViewController(void *viewController) { m_viewController = viewController; } #endif //--------Java回调C++--------native 方法 #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) extern "C" { void Java_org_cocos2dx_cpp_ImageCrop_onImageSaved(JNIEnv *env,jobject thiz,jstring path) { std::string strPath = JniHelper::jstring2string(path); //必须这样,否则由于线程问题会显示黑块无法正常创建精灵 Director::getInstance()->getScheduler()->performFunctionInCocosThread([=,strPath]()mutable{ Director::getInstance()->getEventDispatcher()->dispatchCustomEvent(kImageCropEvent,&strPath); }); } } #endif
2、iOS端代码,.m文件改成.mm文件
#ifndef ImagePickerViewController_h #define ImagePickerViewController_h #import <UIKit/UIKit.h> @interface ImagePickerViewController:UIViewController<UINavigationControllerDelegate,UIImagePickerControllerDelegate> { NSString *filePath; } //打开本地相册 -(void)localPhoto; //打开相机 -(void)takePhoto; @end #endif #import <Foundation/Foundation.h> #import "ImagePickerViewController.h" @interface ImagePickerViewController () @end @implementation ImagePickerViewController -(void)viewDidLoad { [super viewDidLoad]; } -(void)viewDidUnload { [super viewDidUnload]; } -(void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; } -(void)localPhoto { NSLog(@"-(void)localPhoto"); UIImagePickerController *picker = [[UIImagePickerController alloc]init]; picker.delegate = self; picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; picker.allowsEditing = YES; [self presentViewController:picker animated:YES completion:^(void) { NSLog(@"ImageViewController is presented"); }]; [picker release]; } -(void)takePhoto { UIImagePickerControllerSourceType sourceType = UIImagePickerControllerSourceTypeCamera; if ([UIImagePickerController isSourceTypeAvailable:sourceType]) { UIImagePickerController *picker = [[UIImagePickerController alloc]init]; picker.delegate = self; //设置拍照后可以编辑 picker.allowsEditing = YES; picker.sourceType = sourceType; [self presentViewController:picker animated:YES completion:^(void) { NSLog(@"ImageViewController is presented"); }]; } else { NSLog(@"模拟器无法使用相机,请在真机中调试"); } NSLog(@"-(void)takePhoto"); } -(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info { NSString *type = [info objectForKey:@"UIImagePickerControllerMediaType"]; if ([type isEqualToString:@"public.image"]) { //先把图片转成NSData //原始图 // UIImage *image = [info objectForKey:@"UIImagePickerControllerOriginalImage"]; UIImage *image = [info objectForKey:@"UIImagePickerControllerEditedImage"]; NSData *data; if (UIImagePNGRepresentation(image) == nil) { data = UIImageJPEGRepresentation(image, 1.0); } else { data = UIImagePNGRepresentation(image); } //图片保存路径 //这里将图片放在沙盒的documents/image文件夹中 NSString *documentsPath = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"]; NSString *imgPath = [documentsPath stringByAppendingPathComponent:@"image"]; //文件管理器 NSFileManager *fileManager = [NSFileManager defaultManager]; //生成唯一字符串 NSString *uuid = [[NSUUID UUID]UUIDString]; //生成文件名 NSString *fileName = [NSString stringWithFormat:@"%@.png",uuid]; //把刚刚由图片转成的data对象拷贝至沙盒中 并保存为xxxxx-xxxx-xxx...xxx.png /******保存之前最好先清空下,不然占用磁盘越来越大********/ [fileManager removeItemAtPath:imgPath error:nil]; /*************************************************/ [fileManager createDirectoryAtPath:imgPath withIntermediateDirectories:YES attributes:nil error:nil]; [fileManager createFileAtPath:[imgPath stringByAppendingPathComponent:fileName] contents:data attributes:nil]; //得到选择后沙盒中图片的完整路径 filePath = [[NSString alloc]initWithFormat:@"%@",[imgPath stringByAppendingPathComponent:fileName]]; //关闭相册界面 [picker dismissViewControllerAnimated:YES completion:^(void){}]; //通知ImageCrop完成取图 std::string strFilePath = [filePath UTF8String]; cocos2d::Director::getInstance()->getEventDispatcher()->dispatchCustomEvent("ImageCropEvent",&strFilePath); } } -(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker { NSLog(@"您取消了照片选择"); [picker dismissViewControllerAnimated:YES completion:^(void){}]; } @end
3、安卓端,安卓平台需要把ImageCrop.java导入工程包里(src下org.cocos2dx.cpp包里),在主activity(AppActivity.java)的onCreate里调用ImageCrop.getInstance().initImageCrop(this)初始化,然后重载onActivityResult并回调ImageCrop的onActivityResult方法
ImageCrop.java:
package org.cocos2dx.cpp; import java.io.File; import java.io.FileNotFoundException; import android.app.Activity; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Environment; import android.provider.MediaStore; import android.util.Log; public class ImageCrop { public static final int NONE = 0; public static final int PHOTOHRAPH = 1; public static final int PHOTOZOOM = 2; public static final int PHOTORESOULT = 3; public static final String IMAGE_UNSPECIFIED = "image/*"; private static ImageCrop instance = null; private static Activity activity = null; private static String TAG = "ImageCrop"; public static native void onImageSaved(String path); //拍摄照片保存路径 private static String savePath = Environment.getExternalStorageDirectory() +"/CropImage"; private static String photoName = ""; private static Uri imgUri = null; public static ImageCrop getInstance() { if(null == instance) { instance = new ImageCrop(); } return instance; } //初始化 public void init(Activity activity) { ImageCrop.activity = activity; } //打开相册 static public void openPhoto() { Intent intent = new Intent(Intent.ACTION_PICK, null); intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, IMAGE_UNSPECIFIED); activity.startActivityForResult(intent, PHOTOZOOM); } //打开相机 static public void openCamera() { File destDir = new File(savePath); if (!destDir.exists()) { destDir.mkdirs(); } photoName = "temp.jpg"; File file = new File(savePath + "/" + photoName); imgUri = Uri.fromFile(file); Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); intent.putExtra(MediaStore.EXTRA_OUTPUT, imgUri); activity.startActivityForResult(intent, PHOTOHRAPH); } //回调 public void onActivityResult(int requestCode,int resultCode,Intent data) { if (resultCode == NONE) return; // 拍照 不能使用data,因为没有返回是空的 if (requestCode == PHOTOHRAPH) { if (imgUri == null) { Log.e(TAG, "PHOTOHRAPH imgUri is null"); return; } startPhotoZoom(imgUri); } if (requestCode == PHOTOZOOM) { // 读取相册缩放图片 if (data==null ) { Log.e(TAG, "data is null"); return; } if (data.getData()==null) { Log.e(TAG, "data.getData() is null"); return; } startPhotoZoom(data.getData()); } // 处理结果 if (requestCode == PHOTORESOULT) { Bitmap bitmap = decodeUriAsBitmap(imgUri); if (bitmap == null) { Log.e(TAG, "bitmap is null"); } Log.e("ImageCrop", "图片已经保存,通知c++层,"); onImageSaved(savePath + "/" + photoName); } } public void startPhotoZoom(Uri uri) { photoName = System.currentTimeMillis() + ".jpg"; File file = new File(savePath,photoName); imgUri = Uri.fromFile(file); Intent intent = new Intent("com.android.camera.action.CROP"); intent.setDataAndType(uri, IMAGE_UNSPECIFIED); intent.putExtra("crop", "true"); intent.putExtra("aspectX", 1); intent.putExtra("aspectY", 1); intent.putExtra("outputX", 600); intent.putExtra("outputY", 600); intent.putExtra("return-data", false); intent.putExtra(MediaStore.EXTRA_OUTPUT, imgUri); activity.startActivityForResult(intent, PHOTORESOULT); } private Bitmap decodeUriAsBitmap(Uri uri) { Bitmap bitmap = null; try { bitmap = BitmapFactory.decodeStream(activity.getContentResolver().openInputStream(uri)); } catch (FileNotFoundException e) { // TODO: handle exception e.printStackTrace(); return null; } return bitmap; } }
4、示例
HelloWorld工程里直接引入ImageCrop.hpp,调用拍照或者打开相册即可,裁减完成后会返回图片保存路径,直接就可以在C++环境里创建精灵等操作了,欧了!
#include "HelloWorldScene.h" #include "ImageCrop.hpp" USING_NS_CC; Scene* HelloWorld::createScene() { // 'scene' is an autorelease object auto scene = Scene::create(); // 'layer' is an autorelease object auto layer = HelloWorld::create(); // add layer as a child to scene scene->addChild(layer); // return the scene return scene; } // on "init" you need to initialize your instance bool HelloWorld::init() { ////////////////////////////// // 1. super init first if ( !Layer::init() ) { return false; } Size visibleSize = Director::getInstance()->getVisibleSize(); Vec2 origin = Director::getInstance()->getVisibleOrigin(); ///////////////////////////// // 2. add a menu item with "X" image, which is clicked to quit the program // you may modify it. // add a "close" icon to exit the progress. it's an autorelease object auto closeItem = MenuItemImage::create( "CloseNormal.png", "CloseSelected.png", CC_CALLBACK_1(HelloWorld::menuCloseCallback, this)); closeItem->setPosition(Vec2(origin.x + visibleSize.width - closeItem->getContentSize().width/2 , origin.y + closeItem->getContentSize().height/2)); auto openPhoto = MenuItemFont::create("打开相册", [=](Ref*) { ImageCrop::getInstance()->openPhoto([=](std::string path) { CCLOG("photo path:%s",path.c_str()); _img -> removeFromParent(); _img = Sprite::create(path); this->addChild(_img); _img->setPosition(Vec2(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y)); }); }); openPhoto->setPosition(Vec2(origin.x + openPhoto->getContentSize().width/2 , origin.y + openPhoto->getContentSize().height/2)); auto openCamera = MenuItemFont::create("打开相机", [=](Ref*) { ImageCrop::getInstance()->openCamera([=](std::string path) { CCLOG("photo path:%s",path.c_str()); _img -> removeFromParent(); _img = Sprite::create(path); this->addChild(_img); _img->setPosition(Vec2(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y)); }); }); openCamera->setPosition(Vec2(origin.x + openCamera->getContentSize().width/2 , origin.y + openCamera->getContentSize().height)); auto menu = Menu::create(closeItem,openPhoto,openCamera, NULL); menu->setPosition(Vec2::ZERO); this->addChild(menu, 1); ///////////////////////////// // 3. add your codes below... // add a label shows "Hello World" // create and initialize a label auto label = Label::createWithTTF("Hello World", "fonts/Marker Felt.ttf", 24); // position the label on the center of the screen label->setPosition(Vec2(origin.x + visibleSize.width/2, origin.y + visibleSize.height - label->getContentSize().height)); // add the label as a child to this layer this->addChild(label, 1); // add "HelloWorld" splash screen" _img = Sprite::create("HelloWorld.png"); // position the sprite on the center of the screen _img->setPosition(Vec2(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y)); // add the sprite as a child to this layer this->addChild(_img, 0); return true; } void HelloWorld::menuCloseCallback(Ref* pSender) { Director::getInstance()->end(); #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) exit(0); #endif }
本文参考:
http://blog.csdn.net/floodingfire/article/details/8144587
http://www.myexception.cn/operating-system/1937511.html
相关文章推荐
- cocos2d-x调用摄像头和相册并裁减图片
- cocos2dx内嵌gamecenter时的解决方案
- cocosjs+ccs在iphone6上花屏进展
- cocos run -p android 无法真机调试
- [Cocos2d-x开发问题-3] cocos2dx动画Animation介绍
- 【cocos2d-x 3.x 学习与应用总结】3: CallFunc系列
- cocos2d-x 3.0游戏实例学习笔记《卡牌塔防》第八部---怪物出场
- Cocos2d_android你所需要知道的一切(下)
- 【Cocos2d-x源码分析】 FileUtils如何跨平台查找文件
- 【cocos2d-x 3.4】全屏显示窗口,隐藏标题栏
- Cocos2d-x 3.0坐标系详解
- cocostudio1.6UI编辑器中动画使用 cocos2dx3.3 播放问题记录
- 用COCOS-2DX做一个RPG游戏(一)
- 19.cocos2d-x获取当前时间
- cocos2d-x(十二)Lua开发飞机大战-7-加入敌机
- cocos2d-x在eclipse上搭建开发环境(全网最标准方法,不要cywin)
- cocos2dx(3.9)工程项目,使用android studio打包并调试
- 【解决办法】使用Cocos Code IDE 导出 Android 工程「执行命令出错,返回值:2。」
- cocos2dx+lua注册事件函数详解
- cocos2dx的模板容器简单使用(Vector,Map,Value)