zoukankan      html  css  js  c++  java
  • Android自定义照相机实现(拍照、保存到SD卡,利用Bundle在Acitivity交换数据)

    Android自定义照相机实现

    近期小巫在学校有一个创新项目,也不是最近,是一个拖了很久的项目,之前一直没有去搞,最近因为要中期检查,搞得我跟小组成员一阵忙活,其实开发一款照相机软件并不太难,下面就是通过自定义的方式来实现手机照相的功能。

    创建一个项目:FingerTakePicture

    首先来搞一下界面:

    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/FrameLayout1"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
        <!-- 显示预览图形 -->
        <SurfaceView 
            android:id="@+id/surfaceView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            />
        <!-- 相对布局,放置两个按钮 -->
             <RelativeLayout
                android:id="@+id/buttonLayout"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:visibility="gone"
            >
            <!-- 拍照按钮 -->
            <Button 
                android:id="@+id/takepicture"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                android:layout_alignParentBottom="true"
                android:background="@drawable/btn_tabkepicture_selector"
                android:onClick="btnOnclick"
                />
            <ImageView 
                android:id="@+id/scalePic"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:layout_alignParentBottom="true"
                android:layout_marginLeft="5dp"
                android:background="@drawable/img_showpic_selector"
                android:onClick="imageClick"
                />
        </RelativeLayout>
    </FrameLayout>

    界面效果(无法把预览给截屏下来滴):

    权限设置少不了:

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.wwj.finger"
        android:versionCode="1"
        android:versionName="1.0" >
    
        <uses-sdk
            android:minSdkVersion="4"
            android:targetSdkVersion="15" />
    
        <uses-permission android:name="android.permission.CAMERA" />
        <!-- 在SDCard中创建与删除文件权限 -->
        <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
        <!-- 往SDCard写入数据权限 -->
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <application
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name"
            android:theme="@style/AppTheme" >
            <activity
                android:name=".MainActivity"
                android:label="@string/title_activity_main" 
                >
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
            <activity 
                android:name=".ShowPicActivity"
                android:label="@string/app_name"
                android:theme="@style/AppTheme"
                android:configChanges="orientation|keyboardHidden"
                ></activity>
        </application>
    
    </manifest>

    主Activity:

    package com.wwj.finger;
    
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    
    import android.app.Activity;
    import android.content.Intent;
    import android.graphics.PixelFormat;
    import android.hardware.Camera;
    import android.hardware.Camera.PictureCallback;
    import android.os.Bundle;
    import android.os.Environment;
    import android.view.KeyEvent;
    import android.view.MotionEvent;
    import android.view.Surface;
    import android.view.SurfaceHolder;
    import android.view.SurfaceHolder.Callback;
    import android.view.SurfaceView;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.Toast;
    
    /**
     * Android手指拍照
     * 
     * @author wwj
     * @date 2013/4/29
     */
    public class MainActivity extends Activity {
        private View layout;
        private Camera camera;
        private Camera.Parameters parameters = null;
    
        Bundle bundle = null; // 声明一个Bundle对象,用来存储数据
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            // 显示界面
            setContentView(R.layout.activity_main);
    
            layout = this.findViewById(R.id.buttonLayout);
    
            SurfaceView surfaceView = (SurfaceView) this
                    .findViewById(R.id.surfaceView);
            surfaceView.getHolder()
                    .setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
            surfaceView.getHolder().setFixedSize(176, 144);    //设置Surface分辨率
            surfaceView.getHolder().setKeepScreenOn(true);// 屏幕常亮
            surfaceView.getHolder().addCallback(new SurfaceCallback());//为SurfaceView的句柄添加一个回调函数
        }
    
        /**
         * 按钮被点击触发的事件
         * 
         * @param v
         */
        public void btnOnclick(View v) {
            if (camera != null) {
                switch (v.getId()) {
                case R.id.takepicture:
                    // 拍照
                    camera.takePicture(null, null, new MyPictureCallback());
                    break;
                }
            }
        }
    
        /**
         * 图片被点击触发的时间
         * 
         * @param v
         */
        public void imageClick(View v) {
            if (v.getId() == R.id.scalePic) {
                if (bundle == null) {
                    Toast.makeText(getApplicationContext(), R.string.takephoto,
                            Toast.LENGTH_SHORT).show();
                } else {
                    Intent intent = new Intent(this, ShowPicActivity.class);
                    intent.putExtras(bundle);
                    startActivity(intent);
                }
            }
        }
    
        private final class MyPictureCallback implements PictureCallback {
    
            @Override
            public void onPictureTaken(byte[] data, Camera camera) {
                try {
                    bundle = new Bundle();
                    bundle.putByteArray("bytes", data);    //将图片字节数据保存在bundle当中,实现数据交换
                    saveToSDCard(data); // 保存图片到sd卡中
                    Toast.makeText(getApplicationContext(), R.string.success,
                            Toast.LENGTH_SHORT).show();
                    camera.startPreview(); // 拍完照后,重新开始预览
    
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    
        /**
         * 将拍下来的照片存放在SD卡中
         * @param data    
         * @throws IOException
         */
        public static void saveToSDCard(byte[] data) throws IOException {
            Date date = new Date();
            SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss"); // 格式化时间
            String filename = format.format(date) + ".jpg";
            File fileFolder = new File(Environment.getExternalStorageDirectory()
                    + "/finger/");
            if (!fileFolder.exists()) { // 如果目录不存在,则创建一个名为"finger"的目录
                fileFolder.mkdir();
            }
            File jpgFile = new File(fileFolder, filename);
            FileOutputStream outputStream = new FileOutputStream(jpgFile); // 文件输出流
            outputStream.write(data); // 写入sd卡中
            outputStream.close(); // 关闭输出流
        }
    
    
        private final class SurfaceCallback implements Callback {
    
            // 拍照状态变化时调用该方法
            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width,
                    int height) {
                parameters = camera.getParameters(); // 获取各项参数
                parameters.setPictureFormat(PixelFormat.JPEG); // 设置图片格式
                parameters.setPreviewSize(width, height); // 设置预览大小
                parameters.setPreviewFrameRate(5);    //设置每秒显示4帧
                parameters.setPictureSize(width, height); // 设置保存的图片尺寸
                parameters.setJpegQuality(80); // 设置照片质量
            }
    
            // 开始拍照时调用该方法
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                try {
                    camera = Camera.open(); // 打开摄像头
                    camera.setPreviewDisplay(holder); // 设置用于显示拍照影像的SurfaceHolder对象
                    camera.setDisplayOrientation(getPreviewDegree(MainActivity.this));
                    camera.startPreview(); // 开始预览
                } catch (Exception e) {
                    e.printStackTrace();
                }
    
            }
    
            // 停止拍照时调用该方法
            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                if (camera != null) {
                    camera.release(); // 释放照相机
                    camera = null;
                }
            }
        }
    
        /**
         * 点击手机屏幕是,显示两个按钮
         */
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                layout.setVisibility(ViewGroup.VISIBLE); // 设置视图可见
                break;
            }
            return true;
        }
    
        
        @Override
        public boolean onKeyDown(int keyCode, KeyEvent event) {
            switch (keyCode) {
            case KeyEvent.KEYCODE_CAMERA: // 按下拍照按钮
                if (camera != null && event.getRepeatCount() == 0) {
                    // 拍照
                    //注:调用takePicture()方法进行拍照是传入了一个PictureCallback对象——当程序获取了拍照所得的图片数据之后
                    //,PictureCallback对象将会被回调,该对象可以负责对相片进行保存或传入网络
                    camera.takePicture(null, null, new MyPictureCallback());
                }
            }
            return super.onKeyDown(keyCode, event);
        }
    
        // 提供一个静态方法,用于根据手机方向获得相机预览画面旋转的角度
        public static int getPreviewDegree(Activity activity) {
            // 获得手机的方向
            int rotation = activity.getWindowManager().getDefaultDisplay()
                    .getRotation();
            int degree = 0;
            // 根据手机的方向计算相机预览画面应该选择的角度
            switch (rotation) {
            case Surface.ROTATION_0:
                degree = 90;
                break;
            case Surface.ROTATION_90:
                degree = 0;
                break;
            case Surface.ROTATION_180:
                degree = 270;
                break;
            case Surface.ROTATION_270:
                degree = 180;
                break;
            }
            return degree;
        }
    }

    用来显示图片的Activity:

    package com.wwj.finger;
    
    
    import android.app.Activity;
    import android.content.Intent;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.Matrix;
    import android.os.Bundle;
    import android.widget.ImageView;
    
    public class ShowPicActivity extends Activity {
        private ImageView ivPic = null; // 显示图片控件
    
    
        /**
         * Activity在创建的时候回调的函数 主要用来初始化一些变量
         */
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.showpic);
            ivPic = (ImageView) findViewById(R.id.ivPic);
            setImageBitmap(getImageFormBundle());
    
        }
    
    
        /**
         * 将MainActivity传过来的图片显示在界面当中
         * 
         * @param bytes
         */
        public void setImageBitmap(byte[] bytes) {
            Bitmap cameraBitmap = byte2Bitmap();
            // 根据拍摄的方向旋转图像(纵向拍摄时要需要将图像选择90度)
            Matrix matrix = new Matrix();
            matrix.setRotate(MainActivity.getPreviewDegree(this));
            cameraBitmap = Bitmap
                    .createBitmap(cameraBitmap, 0, 0, cameraBitmap.getWidth(),
                            cameraBitmap.getHeight(), matrix, true);
            ivPic.setImageBitmap(cameraBitmap);
        }
    
        /**
         * 从Bundle对象中获取数据
         * 
         * @return
         */
        public byte[] getImageFormBundle() {
            Intent intent = getIntent();
            Bundle data = intent.getExtras();
            byte[] bytes = data.getByteArray("bytes");
            return bytes;
        }
    
        /**
         * 将字节数组的图形数据转换为Bitmap
         * 
         * @return
         */
        private Bitmap byte2Bitmap() {
            byte[] data = getImageFormBundle();
            // 将byte数组转换成Bitmap对象
            Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
            return bitmap;
        }
    }

    这是小巫那个创新项目的一小部分,已经完美实现简单的照相机功能了,保存图片不会像有些网友提供的代码给定一个特定的文件名,不能保存多张图片,还特定把一些方法封装了一下,有需要的朋友好好看看吧。

  • 相关阅读:
    redis参数AOF参数的bug
    tidb损坏tikv节点怎么恢复集群
    mysql主从延时临时解决办法
    python脚本批量杀死redis链接
    pt-online-schema-change 脚本化
    mysql查看锁等信息SQL
    mongo复制集脑裂问题如何处理
    日志收集及网络包收集方案
    各浏览器下载文件名不乱码的解决办法
    java 中 byte[]、File、InputStream 互相转换
  • 原文地址:https://www.cnblogs.com/zhujiabin/p/5139854.html
Copyright © 2011-2022 走看看