100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > 自定义带取景框的camera

自定义带取景框的camera

时间:2023-04-26 20:25:54

相关推荐

自定义带取景框的camera

前言:公司项目需求,在图像信息采集时只采集肩部以上部位的图片(和我们平时的一寸证件照很像),首先想到的是用第三方的图片选择器,他们都自带裁剪功能,不过每次拍完照后的手动裁剪,结果老大说简化业务人员的操作,不过这也难不倒无所不能的程序猿,没有咱们可以new一个(女朋友)。言归正传,开启我们的自定义带取景框的camera...

转载链接:/ruancw/article/details/79907677

效果图:

技术实现:(Activity中实现)

1.SurfaceView

2.Camera

3.自定义矩形取景框view

SurfaceView

介绍:从API中可以看出SurfaceView属于View的子类,它的功能很强大,它支持OpenGL ES库,2D和3D的效果,可以制作游戏、视频等,这里我们用surfaceview和camera实现相机的拍照取景功能。首先,让我们创建了SurfaceView的类实现SurfaceHolder的CallBack接口,重写CallBack的3个方法用于监听SurfaceView的创建、改变、销毁状态。

//SurfaceHolder的callback接口public interface Callback {//对surfaceView的创建状态的监听void surfaceCreated(SurfaceHolder var1);//对SurfaceView的状态改变进行监听void surfaceChanged(SurfaceHolder var1, int var2, int var3, int var4);//对SurfaceView的销毁进行监听void surfaceDestroyed(SurfaceHolder var1);}

1.创建SurfaceView

这里我们使用Api自带的SurfaceView进行相机的预览(当然你也可以自定义surfaceView),在Activity的onCreate方法中进行初始化SurfaceView。

mCameraSurfaceView = (SurfaceView) findViewById(R.id.cameraSurfaceView);

2.使用SurfaceView

//根据layoutParams设置surfaceView的大小mCameraSurfaceView.setLayoutParams(new FrameLayout.LayoutParams((int) (height * (h / w)), height));

3.获取SrfaceView的SurfaceHoler

mHolder = mCameraSurfaceView.getHolder();//添加监听mHolder.addCallback(this);//设置类型mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

然后就是在三个监听方法中进行camera的相关的操作。

自定义view(矩形取景框)

刚才已经介绍了显示camera预览的surfaceView,那么surfaceView上的取景框该如何实现呢?canvas and paint,没错,今天我们就用paint和canvas画出效果图的矩形取景框,接下来我们来自定义view。

模块实现:

a.顶部文字

b.阴影区域

c.矩形取景框

d.四角红色短线

1.自定义View,继承自imageView

构造方法:

public OverLayerTopView(Context context) {this(context,null,0);}public OverLayerTopView(Context context, AttributeSet attrs) {this(context, attrs,0);}public OverLayerTopView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init(context);}

2.初始化view,实现四个模块

(1)顶部文字实现

a.初始化画笔

//顶部文字提示信息wordPaint = new Paint(Paint.ANTI_ALIAS_FLAG);//抗锯齿wordPaint.setColor(Color.WHITE);//字体颜色wordPaint.setTextAlign(Paint.Align.CENTER);//居中显示wordPaint.setStrokeWidth(3f);//画笔的宽度wordPaint.setTextSize(45);//字体大小

b.onDraw方法中绘画

注:必须在super.onDraw之前调用

/*** 画文字提示* @param canvas 画布*/private void drawTipText(Canvas canvas) {canvas.drawText(TIPS, mCenterRect.centerX(), mCenterRect.top-50, wordPaint);}

(2)矩形取景框实现

a.初始化画笔

//中间矩形取景框的边界mRectBorderPaint=new Paint(Paint.ANTI_ALIAS_FLAG);mRectBorderPaint.setColor(Color.RED);mRectBorderPaint.setStyle(Paint.Style.STROKE);mRectBorderPaint.setStrokeWidth(5f);mRectBorderPaint.setAlpha(0);//透明度

注:setAlpha(int value),value的值越小,透明度越高

b.onDraw方法中绘画

注:必须在super.onDraw之前调用

//判断取景框矩形是否为空if (mCenterRect==null) return;

//绘制中间矩形取景框canvas.drawRect(mCenterRect,mRectBorderPaint);

(3)阴影区域实现

a.初始化画笔

//阴影区域的画笔mShadePaint=new Paint(Paint.ANTI_ALIAS_FLAG);mShadePaint.setColor(Color.GRAY);mShadePaint.setStyle(Paint.Style.FILL);mShadePaint.setAlpha(100);

b.onDraw方法中绘画

注:必须在super.onDraw之前调用

canvas.drawRect(0,0,screenWidth,mCenterRect.top-2,mShadePaint);//顶部canvas.drawRect(0,mCenterRect.bottom+2,screenWidth,screenHeight,mShadePaint);//左侧canvas.drawRect(0,mCenterRect.top-2,mCenterRect.left-2,mCenterRect.bottom+2,mShadePaint);//下部canvas.drawRect(mCenterRect.right+2,mCenterRect.top-2,screenWidth,mCenterRect.bottom+2,mShadePaint);//右侧

(4)四角红色短线实现

a.初始化画笔

//矩形四角的短线mLinePaint=new Paint();mLinePaint.setColor(Color.RED);mLinePaint.setAlpha(150);

b.onDraw方法中绘画

注:必须在super.onDraw之前调用

//左下canvas.drawRect(mCenterRect.left-2,mCenterRect.bottom,mCenterRect.left+50,mCenterRect.bottom+2,mLinePaint);//底部canvas.drawRect(mCenterRect.left-2,mCenterRect.bottom-50,mCenterRect.left,mCenterRect.bottom,mLinePaint);//左侧//左上canvas.drawRect(mCenterRect.left-2,mCenterRect.top-2,mCenterRect.left+50,mCenterRect.top,mLinePaint);//顶部canvas.drawRect(mCenterRect.left-2,mCenterRect.top,mCenterRect.left,mCenterRect.top+50,mLinePaint);//左侧//右上canvas.drawRect(mCenterRect.right-50,mCenterRect.top-2,mCenterRect.right+2,mCenterRect.top,mLinePaint);//顶部canvas.drawRect(mCenterRect.right,mCenterRect.top,mCenterRect.right+2,mCenterRect.top+50,mLinePaint);//右侧//右下canvas.drawRect(mCenterRect.right-50,mCenterRect.bottom,mCenterRect.right+2,mCenterRect.bottom+2,mLinePaint);//右侧canvas.drawRect(mCenterRect.right,mCenterRect.bottom-50,mCenterRect.right+2,mCenterRect.bottom,mLinePaint);//底部

3.设置矩形框的大小

/*** 设置取景框的矩形区域大小* @param mCenterRect 取景框矩形*/public void setCenterRect(Rect mCenterRect){this.mCenterRect=mCenterRect;//postInvalidate();}

4.OverLayerTopView的使用(Activity中)

// 设置取景框的margin; 距 左 、上 、右、下的 距离 单位是dpmCenterRect = DisplayUtils.createCenterRect(this, new Rect(120, 180, 120, 300));mOverLayerView.setCenterRect(mCenterRect);

这样我们就实现了取景框的绘制,并能设置你想要的取景框的大小。

!!!重点就是下面的camera的实现了,让我们继续吧

Camera

介绍:android framework包括对设备上可用的各种相机及相机功能的支持,在应用中实现拍照和录制视频,不过,API 21(Android5.0)中将原来的camera API弃用转而推荐使用新增的camera 2 API,这是google对camera架构的一个大动作,因为API换了新架构,让开发者用起来有些难度,本文不对camera 2进行研究。这里使用的还是之前的camera API进行相机拍照实现。接下来我们将在surfaceView的接口方法中对camera进行初始化、设置参数以及资源释放等。

1.camera的初始化(surfaceCreated的方法中)

@Overridepublic void surfaceCreated(SurfaceHolder holder) {openCamera();}

openCamera方法

@TargetApi(Build.VERSION_CODES.GINGERBREAD)private void openCamera() {if (!isFrontCamera) {//是否是后置摄像头//打开相机mCamera = Camera.open();try {//摄像头画面显示在Surface上mCamera.setPreviewDisplay(mHolder);} catch (IOException e) {e.printStackTrace();}} else {//前置摄像头的操作//获取摄像头信息Camera.CameraInfo cameraInfo = new Camera.CameraInfo();//遍历所有摄像头信息,查找前置摄像头for (int i = 0; i < Camera.getNumberOfCameras(); i++) {Camera.getCameraInfo(i, cameraInfo);{//判断是否是前置摄像头if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {//打开前置摄像头mCamera = Camera.open(i);isFrontCamera = true;}}}}}

2.camera参数设置(surfaceChanged方法中)

@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {initCamera();}

initCamera方法

/*** 照相机参数设置*/public void initCamera() {if (mCamera != null && !isPreview) {//获取相机参数Camera.Parameters parameters = mCamera.getParameters();// 设置闪光灯为自动 前置摄像头时 不能设置if (!isFrontCamera) {parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);}//设置相机预览及图片参数setCameraParams(mPoint.x, mPoint.y);//开启预览mCamera.startPreview();isPreview = true;}}

setCameraparams方法

/*** 设置预览图片和裁剪图片的大小* @param width 屏幕宽度* @param height 屏幕高度*/private void setCameraParams(int width, int height) {Log.i(TAG, "setCameraParams width=" + width + " height=" + height);Camera.Parameters parameters = mCamera.getParameters();// 获取摄像头支持的PictureSize列表List<Camera.Size> pictureSizeList = parameters.getSupportedPictureSizes();for (Camera.Size size : pictureSizeList) {Log.i(TAG, "pictureSizeList size.width=" + size.width + " size.height=" + size.height);}//从列表中选取合适的分辨率Camera.Size picSize = getPreviewSize(pictureSizeList, ((float) height / width));Log.i(TAG, "picSize.width=" + picSize.width + " picSize.height=" + picSize.height);// 根据选出的PictureSize重新设置SurfaceView大小float w = picSize.width;float h = picSize.height;parameters.setPictureSize(picSize.width, picSize.height);//根据layoutParams设置surfaceView的大小mCameraSurfaceView.setLayoutParams(new FrameLayout.LayoutParams((int) (height * (h / w)), height));// 获取摄像头支持的PreviewSize列表List<Camera.Size> previewSizeList = parameters.getSupportedPreviewSizes();//获取预览图片的大小Camera.Size preSize = getPreviewSize(previewSizeList, ((float) height) / width);if (null != preSize) {Log.i(TAG, "preSize.width=" + preSize.width + " preSize.height=" + preSize.height);parameters.setPreviewSize(preSize.width, preSize.height);}// 设置照片质量parameters.setJpegQuality(100);if (parameters.getSupportedFocusModes().contains(android.hardware.Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {parameters.setFocusMode(android.hardware.Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);// 连续对焦模式}//自动对焦mCamera.cancelAutoFocus();// 设置PreviewDisplay的方向,效果就是将捕获的画面旋转多少度显示mCamera.setDisplayOrientation(90);//设置参数(不设置不会有效果)mCamera.setParameters(parameters);}

getPreviewSize方法:

/*** 从列表中选取合适的分辨率* 默认w:h = 4:3*/private Camera.Size getPreviewSize(List<Camera.Size> pictureSizeList, float screenRatio) {Camera.Size result = null;for (Camera.Size size : pictureSizeList) {float currentRatio = ((float) size.width) / size.height;if (currentRatio - screenRatio == 0) {result = size;break;}}if (null == result) {for (Camera.Size size : pictureSizeList) {float curRatio = ((float) size.width) / size.height;if (curRatio == 4f / 3) {// 默认w:h = 4:3result = size;break;}}}return result;}

3.释放camera(surfaceDestoryed方法中)

@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {// 当holder被回收时 释放硬件releaseCamera();}

releaseCamera方法:

/*** 释放camera资源*/private void releaseCamera() {if (mCamera != null) {if (isPreview) {//停止camera的预览mCamera.stopPreview();}//释放相机资源mCamera.release();//相机设置为nullmCamera = null;}isPreview = false;}

重点来啦,让我们来拍照吧

4.camera拍照

(1)设置camera的回调接口:Camera.pictureCallBack

/*** 相机拍照的返回接口*/private Camera.PictureCallback jpeg = new Camera.PictureCallback() {@Overridepublic void onPictureTaken(byte[] data, Camera camera) {isTake = false;if (data == null) return;// 获取拍照回调的图片数据。Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, opt);Bitmap bm;//获取相机的方向(横向或纵向)if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {//矩阵转换Matrix matrix = new Matrix();matrix.setRotate(90, 0.1f, 0.1f);bm = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),bitmap.getHeight(), matrix, false);if (isFrontCamera) {//前置摄像头旋转图片270度。matrix.setRotate(270);bm = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);}} else {bm = bitmap;}//判断矩形取景框是否为空if (mCenterRect != null) {//获取取景框大小的bitmapbitmap = BitmapUtils.getRectBitmap(mCenterRect, bm, mPoint);}//图片缩放到341x481大小Bitmap scaleBitmap=Bitmap.createScaledBitmap(bitmap,341,481,false);//将以矩形取景框大小的图片保存到sd卡if (SdcardUtils.existSdcard()) {SdcardUtils.saveBitmap2SD(scaleBitmap, filesDir, imageName);//SdcardUtils.saveBitmap2SD(bitmap, filesDir, imageName);} else ToastUtil.showT(CameraActivity.this, "未检测到SD卡");//释放图片资源,防止OOMBitmapUtils.recycleBitmap(bm);//显示预览图ivPreview.setImageBitmap(bitmap);//释放相机资源if (mCamera != null) {mCamera.stopPreview();mCamera.startPreview();isPreview = true;}//拍照成功返回setResult(-1);finish();}};

(2)点击拍照

注:camera调用takePicture方法前要设置相机参数,不然拍照次数多了会出现闪退

// 设置相机参数setCameraParams(mPoint.x,mPoint.y);//拍照mCamera.takePicture(null, null, jpeg);

jpeg就是我们刚才设置的接口回调名称

注:文中之前设置的自动对焦在华为等部分机型上会出现闪退,因为文中是在预览之前就让其对焦了,源码中已经更改了自动对焦的位置在预览显示之后。

源码地址:/ruancw/CustomCamerDemo

完结!!!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。