android自定义相机(带边框和按钮)

前两个月项目要求不能调用系统的相机,那就只能用自定义的了,查了一些资料,自己再研究了一下,自定义的相机还是有点复杂的,布局和代码中都要用到一个重要的SurfaceView

一、建立布局,布局的背景框可以让美工给出,这里姑且就是一个蓝色的边框,然后下面有三个按钮,我里布局文件activity_custom_camera.xml




    
        

            
            
            

                

                

                    
                    
                    
                    

                    
                

                
                    

效果图:左边是取消,右边的按钮当点击拍照按钮后才会出来

android自定义相机(带边框和按钮)_第1张图片

二、在Activity中实现SurfaceView和拍照,这里给出相机的主要代码,初始化View就省略了。

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setBaseContentLayoutWithoutTitle(R.layout.activity_custom_camera);
        //初始化相机
        initCamera();
        //初始化照片存储路径
        getFileSavePath();
    }

方法initCamera():

SurfaceHolder holder;
    private void initCamera(){
        surfaceview.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                if(!status && camera != null){
                    camera.autoFocus(autoFocusCallback);
                }
                return false;
            }
        });
        MySurfaceCallback mySurfaceCallback = new MySurfaceCallback();
        holder = surfaceview.getHolder();
        holder.setKeepScreenOn(true);// 屏幕常亮
        holder.addCallback(mySurfaceCallback);
        holder.lockCanvas();
    }
    
     class MySurfaceCallback implements SurfaceHolder.Callback {
        @Override
        public void surfaceCreated(SurfaceHolder surfaceHolder) {
            initCameraParamsAndOpen();
        }

        @Override
        public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
            //当surface的格式或大小发生改变,这个方法就被调用,或者View被隐藏
            status = false;
            btnTakePhoto.setVisibility(View.VISIBLE);  //拍照按钮显示
            btnFinish.setVisibility(View.GONE); //拍照完成按钮隐藏
            camera.release();
            camera = null;
            initCameraParamsAndOpen();  //重新初始化相机
        }

        @Override
        public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
            if (camera != null) {
                camera.stopPreview();
                camera.release();
                camera = null;
            }
        }
    }

    private void initCameraParamsAndOpen(){
        try {
            // surfaceview创建之后,就去打开相机
            camera = getCameraInstance();
            camera.setPreviewDisplay(holder);
            camera.setDisplayOrientation(90);
            updateCameraParameters();
            camera.startPreview();
        } catch (Exception e) {
            if(camera != null){
                camera.release();
            }
            e.printStackTrace();
        }
    }

    private void updateCameraParameters() {
        if (camera != null) {
            Camera.Parameters mParameters = camera.getParameters();
            Camera.Size picSize = mParameters.getPreviewSize();
            Camera.Size previewSize = getOptimalPreviewSize(mParameters.getSupportedPreviewSizes(), (double) picSize.width / picSize.height);
            if (previewSize != null) {
                mParameters.setPreviewSize(previewSize.width, previewSize.height);
            }
            picSize = mParameters.getPictureSize();
            Camera.Size pictureSize = getOptimalPictureSize(mParameters.getSupportedPictureSizes(), (double) picSize.width / picSize.height);

            if (pictureSize != null) {
                mParameters.setPictureSize(pictureSize.width, pictureSize.height);
            }
            mParameters.setRotation(90);//防止保存的图片旋转
            camera.setParameters(mParameters);

        }
    }
     
public static Camera getCameraInstance(){
        Camera c = null;
        try {
            c = Camera.open(0); // attempt to get a Camera instance
        }
        catch (Exception e){
            // Camera is not available (in use or does not exist)
        }
        return c; // returns null if camera is unavailable }
    /**      * 设定的屏幕的比例不是图片的比例      *@date 创建时间 2017/4/15      *@author      *@company      *@name:zhongshuiping      *@Description 匹配分辨率      */     private Camera.Size getOptimalPreviewSize(List sizes, double targetRatio) {         if (sizes == null)             return null;         Camera.Size optimalSize = null;         Collections.sort(sizes, new Comparator() {             @Override             public int compare(Camera.Size lhs, Camera.Size rhs) {                 return new Double(lhs.width).compareTo(new Double(rhs.width));             }         });         for (int i=sizes.size()-1;i>=0;i--) {             Camera.Size size = sizes.get(i);             if ((( Constants.EIGHT_HUNDRED < size.width && size.width < Constants.TWO_THOUSAND)                     || (Constants.EIGHT_HUNDRED< size.height && size.height < Constants.TWO_THOUSAND))                     && ((size.width * 9) == (size.height * 16) )) {                 optimalSize = size;                 break;             }         }         return optimalSize;     }
    /**      * 设置的是拍照的图片的比例      *@date 创建时间 2017/4/15      *@author      *@company      *@name:zhongshuiping      *@Description 匹配分辨率      */     private Camera.Size getOptimalPictureSize(List sizes, double targetRatio) {         if (sizes == null)             return null;         Camera.Size optimalSize = null;         Collections.sort(sizes, new Comparator() {             @Override             public int compare(Camera.Size lhs, Camera.Size rhs) {                 return new Double(lhs.width).compareTo(new Double(rhs.width));             }         });         for (int i=sizes.size()-1;i>=0;i--) {             Camera.Size size = sizes.get(i);             if (((Constants.NUMBER_ONE_THOUSAN < size.width && size.width < Constants.NUMBER_TWO_THOUSAND)                     || (Constants.NUMBER_ONE_THOUSAN < size.height && size.height < Constants.NUMBER_TWO_THOUSAND))                     && ((size.width * 10) ==(size.height * 16) )) {                 optimalSize = size;                 break;             }         }         /**如果没找到16/9的就选择最接近的*/         if(optimalSize == null)         {             double dMin = 100.0;             Camera.Size RightSize = null;             for (Camera.Size size : sizes) {                 double fRate = size.width/(float)size.height;                 double fDistance = Math.abs(fRate - 16.0/10);                 //找最接近16比9的size;                 if(fDistance < dMin)                 {                     dMin = fDistance;                     RightSize = size;                 }             }             //最接近的值赋给变量optimalSize             optimalSize = RightSize;         }         return optimalSize;     }
    Camera.AutoFocusCallback autoFocusCallback = new Camera.AutoFocusCallback() {         @Override         public void onAutoFocus(boolean b, Camera camera) {
        }     } ;

存储路径getFileSavePath(), File  tempFile为拍照预留的存储位置文件,最后拍照完毕将会把照片流写入该文件中。

 private File mediaStorageDir;
    private void getFileSavePath(){
        try
        {
            mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "test");
        } catch (Exception e) {
            e.printStackTrace();
            showShortToastCenter("创建test失败");
            LogUtils.LogError("lenita", "Error in Creating mediaStorageDir: " + mediaStorageDir);
        }
        if (!mediaStorageDir.exists())
        {
            if (!mediaStorageDir.mkdirs())
            {
                // 在SD卡上创建文件夹需要权限:
                // 
                showShortToastCenter("创建test失败");
                LogUtils.LogError("lenita", "failed to create directory, check if you have the WRITE_EXTERNAL_STORAGE permission");
            }
        }
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
                .format(new Date());
        tempFile = new File(mediaStorageDir.getPath() + File.separator
                + "IMG_" + timeStamp + ".jpg");
}    

相机调用,点击btnTakePhoto按钮(R.id.btn_take_photo),此处对拍照后的图片进行压缩,免得太大导致上传服务器出错:

//点击拍照
@Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.btn_take_photo:
                if(camera != null){
                    camera.takePicture(null, null, myPictureCallback);
                    status = true;
                    btnTakePhoto.setVisibility(View.GONE);
                    btnFinish.setVisibility(View.VISIBLE);
                }else {
                    showShortToastCenter("请重新拍摄");
                    status = false;
                    btnTakePhoto.setVisibility(View.VISIBLE);
                    btnFinish.setVisibility(View.GONE);
                    camera.release();
                    camera = null;
                    initCameraParamsAndOpen();
                }
                break;
            case R.id.btn_finish:  //点击完成,进行图片的上传,上传到服务器代码省略
                if(tempBitmap == null || tempFile == null){
                    showShortToastCenter("拍照失败,请重新拍摄");
                    status = false;
                    btnFinish.setVisibility(View.GONE);
                    btnTakePhoto.setVisibility(View.VISIBLE);
                    camera.release();
                    camera = null;
                    initCameraParamsAndOpen();
                    return;
                }
                LogUtils.LogError("lenita","tempFile path = "+tempFile.getPath());
                formatFile();  //TODO 压缩查看
                //上传到服务器的代码省略。。。File tempFile为图片转换成的文件流
                break;
        }
    }
   
    private File mImageFile;
    private void formatFile(){
        try {
            //当大于2MB时用到
            String lRealFilePath = tempFile.getPath();
            String stringAll[] = lRealFilePath.split("\\.");
            int length = stringAll.length;
            String imageSuffix = stringAll[length - 1];
            String string[] = lRealFilePath.split("\\."+imageSuffix);
            String newFileSavePath = string[0] + "_compress.jpg";
            long fileLong = FileSizeUtil.getFileSize(tempFile);
            String fileString = FileSizeUtil.formatFileSizeUnder2MB(fileLong);
            if (TextUtils.isEmpty(fileString)) {   //TODO 证明是大于2MB的,要进行压缩
                Toast.Long(this,"正在压缩图片,请稍等片刻...");
                compressImageUtilbelow2MB(lRealFilePath,newFileSavePath);
                //压缩后替换要上传的路径
                lRealFilePath = newFileSavePath;
                mImageFile = new File(lRealFilePath);
                tempFile = mImageFile;
            }
        }catch (Exception e) {
            Log.e("lenita","e e = "+e.toString());
        }
    }

    private void compressImageUtilbelow2MB(String filePath,String newFilePath){
        //TODO 大于2MB的进行压缩
        ImageFactory imageFactory = new ImageFactory();
        try {
            imageFactory.compressAndGenImage(filePath,newFilePath,1024,false);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    Camera.PictureCallback myPictureCallback = new Camera.PictureCallback(){
        @Override
        public void onPictureTaken(byte[] data, Camera camera) {
            LogUtils.LogError("lenita"," onPictureTaken");
            //卡住预览页面,让用户看  
            camera.stopPreview();
            //保存图片
            tempBitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
            saveBitmap(tempBitmap);
        }
    };

    public void saveBitmap(Bitmap bitmap) {
        if(tempFile != null){
            try {
                FileOutputStream out = new FileOutputStream(tempFile);
                bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
                out.flush();
                out.close();
            } catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                LogUtils.LogError("lenita","saveBitmap e = "+e);
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                LogUtils.LogError("lenita","saveBitmap e = "+e);
                e.printStackTrace();
            }
        }else {
            LogUtils.LogError("lenita","tempFile == null");
        }

    }
以上就是拍照的相关的代码,这里要注意的是,拍照之后最好调用camera.stopPreview();这个方法,否则有些手机会一直在preview,导致无法定在当前的拍照中,当然,如果你是想拍照完直接存下,而不要定下来查看的话,就不需要camera.stopPreview();来定住画面了,效果图如下所示:

 android自定义相机(带边框和按钮)_第2张图片

保存的文件就会在Picture/test文件夹下,图片如下图:

android自定义相机(带边框和按钮)_第3张图片

最后给个参考文章,还是值得借鉴一下的:

http://blog.csdn.net/ming_csdn_/article/details/70154381





你可能感兴趣的:(Android)