相机Camera(预览--拍照)--两种方式(包含横竖屏切换两种方式)

代码需要权限如下:




1.调用手机自带的相机,预览并拍照


我的另一篇博客已经写到

调用手机相机拍照并返回图片

其中主要的代码就是:

                //调用系统相机,拍照
                Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                //在onActivityResult()处理
                startActivityForResult(intent , 1);

 

2.自己写一个SurfaceView,预览Camera,并手动拍照Camera.takePicture();




    

    

public class MyCameraActivity extends AppCompatActivity implements SurfaceHolder.Callback, android.hardware.Camera.AutoFocusCallback {

    SurfaceView mySurfaceView;
    SurfaceHolder holder;
    android.hardware.Camera myCamera;
    //照片保存路径
    String filePath = null;
    //拍照按钮
    Button capture;
    //照片缩略图
    ImageView editPic;
    Context mContext;

    MyOrientoinListener myOrientoinListener;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_my_camera);
        mySurfaceView = (SurfaceView) findViewById(R.id.camera_view);
        holder = mySurfaceView.getHolder();
        //回调
        holder.addCallback(this);
        mContext = this;
        //设置类型,没有这句将调用失败
        //当在Canvas中绘制完成后,调用函数unlockCanvasAndPost(Canvas canvas)来通知系统Surface已经绘制完成,
        // 这样系统会把绘制完的内容显示出来。为了充分利用不同平台的资源,发挥平台的最优效果可以通过SurfaceHolder的setType函数来设置绘制的类型,
        // 目前接收如下的参数:
        //SURFACE_TYPE_NORMAL:用RAM缓存原生数据的普通Surface
        //SURFACE_TYPE_HARDWARE:适用于DMA(Direct memory access )引擎和硬件加速的Surface
        //SURFACE_TYPE_GPU:适用于GPU加速的Surface
        //SURFACE_TYPE_PUSH_BUFFERS:表明该Surface不包含原生数据,Surface用到的数据由其他对象提供,
        // 在Camera图像预览中就使用该类型的Surface,有Camera负责提供给预览Surface数据,这样图像预览会比较流畅。
        // 如果设置这种类型则就不能调用lockCanvas来获取Canvas对象了
        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        capture = (Button) findViewById(R.id.takeP);
        editPic = (ImageView) findViewById(R.id.p_view);
        //监听
        capture.setOnClickListener(takePicture);


    }

    View.OnClickListener takePicture = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            //自动对焦 并回调
            myCamera.autoFocus(MyCameraActivity.this);
        }
    };

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        if (myCamera == null) {
            //得到相机实例
            myCamera = android.hardware.Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);
            try {
                //相机预览传入surfaceholder
                myCamera.setPreviewDisplay(holder);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        Log.i("TAG", "change");
        //设置预览方向顺时针旋转90 ,摄像头预览方向与实际相差90度
        myCamera.setDisplayOrientation(90);
        //开始预览
        myCamera.startPreview();
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        //关闭预览并释放资源
        myCamera.stopPreview();
        myCamera.release();
        myCamera = null;
    }


    @Override
    public void onAutoFocus(boolean success, android.hardware.Camera camera) {
        if (success) {
            //设置相机参数
            android.hardware.Camera.Parameters params = myCamera.getParameters();
            params.setPictureFormat(PixelFormat.JPEG);
            myCamera.setParameters(params);
            //拍照 产生三个回调对应 (原始图像 压缩图 jpeg图) 这里只回调了jpeg图
            myCamera.takePicture(null, null, jpeg);
        }
    }

    android.hardware.Camera.PictureCallback jpeg = new android.hardware.Camera.PictureCallback() {
        @Override
        public void onPictureTaken(byte[] data, android.hardware.Camera camera) {
            try {
                //获得图片
                Bitmap bm = BitmapFactory.decodeByteArray(data, 0, data.length);
                SimpleDateFormat sDateFormate = new SimpleDateFormat("yyyyMMddHHmmss");
                String date = sDateFormate.format(new Date());
                if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
                    Toast.makeText(mContext, "SD卡不可用", Toast.LENGTH_SHORT).show();
                } else {
                    filePath = Environment.getExternalStorageDirectory().getAbsolutePath();
                    filePath = filePath + "/" + date + ".jpg";
                }

                File file = new File(filePath);
                BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
                //创建操作图片用的matrix
                Matrix matrix = new Matrix();
                //图片方向与实际相差270,所以在保存到bos之前将图片顺时针旋转270度
                matrix.postRotate(270);
                //创建新图片
                Bitmap rotateBitmap = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true);
                //将图片以jpeg格式压缩到流中
                rotateBitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);
                //输出
                bos.flush();
                //关闭
                bos.close();
                //显示缩略图
                editPic.setBackgroundDrawable(changeBitmapToDrawable(rotateBitmap));
                //缩略图点击时得到路径参数
                editPic.setTag(filePath);
            } catch (Exception e) {
                e.printStackTrace();
            }
            //takePiture会停止预览,我们要重新开启预览
            myCamera.startPreview();
        }
    };

    private Drawable changeBitmapToDrawable(Bitmap bitmapOrg) {
        int width = bitmapOrg.getWidth();
        int height = bitmapOrg.getHeight();
        //定义要转换成的图片的宽和高
        int newWidth = 100;
        //计算缩放率,新尺寸除以旧尺寸
        float scaleWidth = (float) newWidth / width;
        float scaleHeight = scaleWidth;
        //创建操作图片用的matrix
        Matrix matrix = new Matrix();
        //缩放图片动作
        matrix.postScale(scaleWidth, scaleHeight);
        //创建新图片
        Bitmap resizeBitmap = Bitmap.createBitmap(bitmapOrg, 0, 0, width, height, matrix, true);
        //将Bitmap转换为Drawable
        BitmapDrawable bitmapDrawable = new BitmapDrawable(resizeBitmap);
        return bitmapDrawable;
    }


}

对于简单的预览拍照,上面两种方式已经实现。

下面解决横竖屏切换的问题:(以第二段代码为例)

要想获取屏幕方向,需要在AndroidManifest.xml文件中,对某个Activity加入如下的设置:

  • android:configChanges="screenSize|orientation|keyboardHidden"

然后还需要手机开启自动旋转的设置。

 

以上准备工作做好,我们接下来有两种方式实现横竖屏的切换:

1.经典方法:activity重写onConfigurationChanged()监听屏幕旋转,而不重新执行onCreate()。

//onConfigurationChanged
    public void onConfigurationChanged(Configuration newConfig){
        super.onConfigurationChanged(newConfig);

        if(newConfig.orientation==Configuration.ORIENTATION_LANDSCAPE){
            // Nothing need to be done here
            Log.i("TAG","横屏");
//处理代码
        } else {
            // Nothing need to be done here
            Log.i("TAG","竖屏");
//处理代码
        }
    }

由于屏幕方向自动旋转了,所以Activity自动旋转了,Camera也旋转了,不需要你手动旋转Camera。

不过如果旋转之后的 Camera方向不对,可以手动修改Camera的方向。myCamera.setDisplayOrientation(角度);

 

2.用传感器监听屏幕旋转角度,当达到一定的角度了,手动旋转Camera,不过你的Activity方向还是不变。


public class MyCameraActivity extends AppCompatActivity implements SurfaceHolder.Callback, android.hardware.Camera.AutoFocusCallback {

   ...

    MyOrientoinListener myOrientoinListener;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_my_camera);
        ...
        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        capture = (Button) findViewById(R.id.takeP);
        editPic = (ImageView) findViewById(R.id.p_view);
        capture.setOnClickListener(takePicture);

//第二种方式,监听屏幕旋转
        myOrientoinListener = new MyOrientoinListener(this);
        boolean autoRotateOn = (android.provider.Settings.System.getInt(getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 0) == 1);
        //检查系统是否开启自动旋转
        if (autoRotateOn) {
            myOrientoinListener.enable();
        }

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //销毁时取消监听
        if (myOrientoinListener != null) {
            myOrientoinListener.disable();
        }
    }

    ...

    ...

    ...


    ...

    class MyOrientoinListener extends OrientationEventListener {
        private Context context;

        public MyOrientoinListener(Context context) {
            super(context);
            this.context = context;
        }

        @Override
        public void onOrientationChanged(int orientation) {
            Log.i("TAG", "orention" + orientation);
            int screenOrientation = context.getResources().getConfiguration().orientation;
            if (((orientation >= 0) && (orientation < 45)) || (orientation > 315)) {//设置竖屏
                if (screenOrientation != ActivityInfo.SCREEN_ORIENTATION_PORTRAIT && orientation != ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT) {
                    Log.i("TAG", "设置竖屏");
                    myCamera.setDisplayOrientation(0);
                }
            } else if (orientation > 225 && orientation < 315) { //设置横屏
                Log.i("TAG", "设置横屏");
                if (screenOrientation != ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
                    myCamera.setDisplayOrientation(90);
                }
            } else if (orientation > 45 && orientation < 135) {// 设置反向横屏
                Log.i("TAG", "反向横屏");
                if (screenOrientation != ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE) {
                    myCamera.setDisplayOrientation(180);
                }
            } else if (orientation > 135 && orientation < 225) {
                Log.i("TAG", "反向竖屏");
                if (screenOrientation != ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT) {
                    myCamera.setDisplayOrientation(270);
                }
            }
        }
    }


}

在旋转角度oritention达到一定值的时候,上面代码中,我们手动的旋转了Camera的方向,如有90,180,270度的。

对于横屏,竖屏,到底需要需要旋转多少角度,上面我旋转的角度可能不对,你们自行修改。

还有就是在onDestroy()方法中要记得停止监听。

 

 

你可能感兴趣的:(相机Camera(预览--拍照)--两种方式(包含横竖屏切换两种方式))