安卓开发——相机:拍照并处理图片

本次使用的是Camera API来实现的,并不是使用隐式Intent与照相机进行交互的。所以我们使用SurfaceView类和相机硬件来实现实时展示拍照界面,以及拍照后的图片处理。

  相机是一种独占性资源:也就是说一次只能有一个activity可以调用相机。因此,我们在使用相机硬件资源时需要时刻注意,使用完资源后要释放资源!!!
SurfaceView实例可以用来充当相机的取景器。SurfaceView是一种特殊的视图,可直接将想要显示的内容渲染输出到设备上(也可以用来播放视频)。

拍照

获取权限

要使用相机,首先我们就要获取相关的权限:(AndroidMenifest.xml)

<uses-permission android:name="android.permission.CAMERA"/>  
<uses-permission android:name="android.permission.FLASHLIGHT"/>  
<uses-feature android:name="android.hardware.Camera"/>
<uses-feature android:name="android.hardware.camera.autofocus" />

PS:屏幕显示方向可以在activity中的android:screenOrientation标签定义:
1. landscape : 横屏
2. portrait : 竖屏

<activity android:name=".CameraActivity"
    android:screenOrientation="landscape">
</activity>

Camera API

这里使用的是android.hardware.Camera包中的Camera类来打开相机的。
其中Camera操作主要包括以下三个方法:
1. public static Camera open(int);
2. public static Camera open();
3. public final void release();

open()可以打开一个Camera资源,含参数的open方法则是在API9以后加入的(推荐使用这个)。release()方法则用于释放获取的相机资源。一般情况下只有当activity视图为在前台可见时才需要使用相机,所以我们考虑在onResume()方法中申请使用相机,而当视图离开前台时,即在onPause()方法中释放获取的相机资源。

    @Override
    public void onResume() {
        super.onResume();

        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD)
            mCamera = Camera.open(0);
        else
            mCamera = Camera.open();
    }

    @Override
    public void onPause() {
        super.onPause();
        if(mCamera != null){
            mCamera.release();
            mCamera = null;
        }
    }

SurfaceView实现取景器

SurfaceView:是我们用来显示图像的视图组件。
Surface:可以看成是原始像素数据的缓冲区。
SurfaceHolder:是和Surface对象连接的重要纽带。(可以理解为通过SurfaceHolder给Surface对象设置像素数据)。
Surface对象是有生命周期的,即当SurfaceView在前台显示时会生成Surface对象,当SurfaceView消失时,Surface对象也会被销毁。因为当Surface不存在时我们需要保证Surface中没有需要绘制的对象。所以我们可以在Surface创建后把相机连接到SurfaceHolder上,当Surface被销毁后,我们把SurfaceHolder和相机的连接取消。为了实现这个我们需要使用SurfaceView.Callback接口中的三个方法。

    mSurfaceView = (SurfaceView) v.findViewById(R.id.camera_surfaceView);
        SurfaceHolder holder = mSurfaceView.getHolder();
        //holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

        holder.addCallback(new SurfaceHolder.Callback() {
            /* 当SurfaceView创建时候调用 */
            @Override
            public void surfaceCreated(SurfaceHolder surfaceHolder) {
                /* 设置当前surfaceview为相机的显示区域 */
                try {
                    if (mCamera != null)
                        mCamera.setPreviewDisplay(surfaceHolder);
                } catch (IOException e) {
                    Log.e(TAG_CAMERA, "surfaceView fail...");
                    e.printStackTrace();
                }
            }

            /* 首次显示到屏幕是调用的方法 */
            @Override
            public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
                if(mCamera == null)
                    return;

                try {
                    /* 开始绘制帧 */
                    mCamera.startPreview();
                } catch (Exception e) {
                    Log.e(TAG_CAMERA, "camera start preview fail...");
                    mCamera.release();
                    mCamera = null;
                    e.printStackTrace();
                }
            }
            /* 当SurfaceView从屏幕上移除时 */
            @Override
            public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
                /* 设置相机不再在这个域显示 */
                if (mCamera != null)
                    /* 停止绘制帧 */
                    mCamera.stopPreview();
            }
        });

实现相机的回调方法

捕获图像,并存为JPEG图片。
public final void takePicture(Camera.ShutterCallback shutter, Camera.PictureCallback raw, Camera.PictureCallback jpeg);

  1. ShutterCallback回调方法在相机捕获图片时调用。此时图像数据还没有完成。
  2. PictureCallback raw,原始数据可用时调用的回调函数。
  3. PicryreCallback jpeg,在jpeg版本的图像可用时调用的回调函数。

下面就是两个接口ShutterCallback,PictureCallbak的实现:

    private Camera.ShutterCallback mShutterCallback = new Camera.ShutterCallback() {
        @Override
        public void onShutter() {
            mProgressBarContainer.setVisibility(View.VISIBLE);
        }
    };

    private Camera.PictureCallback mJpegCallback = new Camera.PictureCallback() {
        @Override
        public void onPictureTaken(byte[] bytes, Camera camera) {
            /* 随机生成一个文件名 */
            String fileName = UUID.randomUUID().toString() + ".jpg";
            /* 创建一个文件输出流,生成jpeg文件 */
            FileOutputStream os = null;
            boolean success = true;

            try {
                os = getActivity().openFileOutput(fileName, Context.MODE_PRIVATE);
                os.write(bytes);
            } catch (IOException e) {
                success = false;
                e.printStackTrace();
            } finally {
                try {
                    if (os != null)
                        os.close();
                } catch (IOException e) {
                    success = false;
                    e.printStackTrace();
                }
            }
            if(success) {
                //Log.d(TAG_CAMERA, "save picture " + fileName + " success.");
                /* 返回生成的文件名给父Activity */
                Intent i = new Intent();
                i.putExtra(EXTRA_PHOTO, fileName);
                getActivity().setResult(Activity.RESULT_OK, i);
            }
            else
                getActivity().setResult(Activity.RESULT_CANCELED);

            /* 关闭拍照界面 */
            getActivity().finish();
        }
    };

拍照功能的实现是在拍照按钮的监听器事件中触发的:

    mTakePhoto = (Button) v.findViewById(R.id.camera_take_photo);
    mTakePhoto.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if(mCamera != null)
                /* 这里只处理生成jpeg图像后的事件 */
                mCamera.takePicture(mShutterCallback, null, mJpegCallback);
        }
    });

图片处理与显示

图片显示可以使用ImageView视图:

<ImageView
    android:id="@+id/imageView"
    android:layout_width="80dp"
    android:layout_height="80dp"
    android:scaleType="centerInside"
    android:cropToPadding="true"/>

由于现在的图片的尺寸都是比较大的,一般我们在显示图片之前都会对图片进行处理。接下来就是一个类来适当的缩放图片尺寸来适合在ImageView中的显示。

    import android.app.Activity;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.drawable.BitmapDrawable;
    import android.view.Display;
    import android.widget.ImageView;

    public class PictureUtils {
        /* 获取适当尺寸的图片大小,path为图片文字路径 */
        public static BitmapDrawable getScaledDrawble(Activity a, String path){
            Display display = a.getWindowManager().getDefaultDisplay();
            float desWidth = display.getWidth();
            float desHeight = display.getHeight();

            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeFile(path, options);

            float srcWidth = options.outWidth;
            float srcHeight = options.outHeight;

            int scaleSize = 1;
            if(srcWidth > desWidth || srcHeight > desHeight){
                if(srcWidth > srcHeight)
                    scaleSize = Math.round(srcHeight/desHeight);
                else
                    scaleSize = Math.round(srcWidth/desWidth);
            }

            options = new BitmapFactory.Options();
            options.inSampleSize = scaleSize;

            Bitmap bitmap = BitmapFactory.decodeFile(path, options);
            return new BitmapDrawable(a.getResources(), bitmap);
        }

        /* 回收ImageView对象中图像数据 */
        public static void cleanImageView(ImageView imageView){
            if(!(imageView.getDrawable() instanceof BitmapDrawable))
                return;

            BitmapDrawable b = (BitmapDrawable) imageView.getDrawable();
            b.getBitmap().recycle();
            imageView.setImageDrawable(null);
        }
    }

然后就是把处理后的图片显示到ImageView上。

    public void showPhoto(){
        String path = ...;
        BitmapDrawable b = PictureUtils.getScaledDrawble(getActivity(), path);
        mImageView.setImageDrawable(b);
    }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值