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

来源:互联网 发布:哔哩哔哩 for mac 编辑:程序博客网 时间:2024/05/17 06:15

本次使用的是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 0
原创粉丝点击