zoukankan      html  css  js  c++  java
  • cocos2d-x调用摄像头和相册并裁减图片

    最近做个小游戏需要调用手机图库和摄像头并裁减图片,发现网上很多教程不是太全,有的安卓端裁减不了大图,下面是完整代码,可以裁减高清图的。

    完整拼图游戏下载:
    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

  • 相关阅读:
    一个关于状态机的问题
    8位同步码修改变4位同步码
    BT1120时序,可以用于自测用
    欧几理德,扩展欧几里德和模线性方程组。
    "旋转的风车"----windows(GDI)绘图
    草滩小恪的学习链接(汇总版)
    酒鬼随机漫步(一个矢量类)
    小题精炼-----初试C语言
    大二(上)------我欠青春一份疯狂
    HDU 1027 Ignatius and the Princess II(康托逆展开)
  • 原文地址:https://www.cnblogs.com/skyxu123/p/9543809.html
Copyright © 2011-2022 走看看