前几天,我写了一篇自定义相机加取景框的文章,这几天,我又研究了一下,进一步写了蒙板,并且拍照出来剪切只留取景框的照片。
加上对之前代码的调整。现在又记录下来
现在的效果是这样的
布局文件
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <FrameLayout android:id="@+id/myFramelayout" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <SurfaceView android:id="@+id/surfaceView" android:layout_width="match_parent" android:layout_height="match_parent" /> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/view1" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#FFFFFF" android:gravity="center_horizontal" android:text="\n请将方框对准证件拍摄" android:textSize="18dp" android:textColor="@color/colorAccent" android:alpha="0.6"/> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <View android:id="@+id/view2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#FFFFFF" android:alpha="0.6"/> <com.example.administrator.myapplication.MyView android:id="@+id/myView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" /> <View android:id="@+id/view3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#FFFFFF" android:alpha="0.6"/> </LinearLayout> <View android:id="@+id/view4" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#FFFFFF" android:alpha="0.6"/> </LinearLayout> </FrameLayout> <LinearLayout android:id="@+id/linear" android:layout_width="55dp" android:layout_height="match_parent" android:layout_alignParentRight="true" android:layout_marginRight="8dp" android:gravity="center_vertical"> <Button android:id="@+id/takepicture_button" android:layout_width="50dp" android:layout_height="50dp" android:background="@mipmap/xiang_ji" android:onClick="takepicture" /> </LinearLayout> </RelativeLayout>自定义MyView,这次MyView对于算取景框的线是灵活的,更改参数可以调整取景框的大小,并且取景框线也跟着移动
public class MyView extends View { //获取屏幕的宽和高。根据屏幕的宽和高来算取景框的位置 private int screenWidth, screenHeight, myViewPaddingLeft, myViewPaddingTop; private int langLine = 100, //取景框长线的长度 shortLine = 50, //取景框短线的长度 origin = 0;//原点 public MyView(Context context, AttributeSet attrs) { super(context, attrs); } public void setMyParams(int screenWidth, int screenHeight, int myViewPaddingLeft, int myViewPaddingTop) { this.screenWidth = screenWidth; this.screenHeight = screenHeight; this.myViewPaddingLeft = myViewPaddingLeft; this.myViewPaddingTop = myViewPaddingTop; } @Override public void onDraw(Canvas canvas) { Paint paint = new Paint(); paint.setColor(Color.RED); paint.setAlpha(250); paint.setAntiAlias(true); paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(5); // 下面是取景框的8条线 // xy的算法是:把屏幕横着(逆时针旋转90度的屏幕),相对这个view来讲(左上角是原点0,0),从左到右是x轴,从上到下是y轴 //左上角两条线 canvas.drawLine(origin, origin, langLine, origin, paint); canvas.drawLine(origin, origin, origin, shortLine, paint); //左下角两条线 canvas.drawLine(origin, screenHeight - myViewPaddingTop, langLine, screenHeight - myViewPaddingTop, paint); canvas.drawLine(origin, screenHeight - myViewPaddingTop, origin, screenHeight - myViewPaddingTop - shortLine, paint); //右上角两条线 canvas.drawLine(screenWidth - myViewPaddingLeft, origin, screenWidth - myViewPaddingLeft - langLine, origin, paint); canvas.drawLine(screenWidth - myViewPaddingLeft, origin, screenWidth - myViewPaddingLeft, shortLine, paint); //右下角两条线 canvas.drawLine(screenWidth - myViewPaddingLeft, screenHeight - myViewPaddingTop, screenWidth - myViewPaddingLeft - langLine, screenHeight - myViewPaddingTop, paint); canvas.drawLine(screenWidth - myViewPaddingLeft, screenHeight - myViewPaddingTop, screenWidth - myViewPaddingLeft, screenHeight - myViewPaddingTop - shortLine, paint); super.onDraw(canvas); } }最后是Acvitity代码
private MyView myView; private View view2, view3, view4;//3个蒙板 private TextView view1;//1个蒙板
private Camera camera;private Button takepicture_button ; private SurfaceView surfaceview ; private int screenWidth , screenHeight ; private int myViewPaddingLeft = 500 , //MyView 左右距离屏幕的距离(意思是 MyView 左右两边一共空了 500 ) myViewPaddingTop = 300 ; //MyView 上下距离屏幕的距离(意思是 MyView 上下两边一共空了 500 )
private ToneGenerator tone;private Camera.AutoFocusCallback myAutoFocusCallback = new Camera.AutoFocusCallback() { @Override public void onAutoFocus( boolean success , Camera camera) { Log. w( "print" , " 聚焦完成,,,, ") ; // 聚焦后发出提示音 tone = new ToneGenerator(AudioManager. STREAM_MUSIC ,ToneGenerator. MAX_VOLUME) ; tone.startTone(ToneGenerator. TONE_PROP_BEEP2) ; } } ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState) ; setRequestedOrientation(ActivityInfo. SCREEN_ORIENTATION_LANDSCAPE) ; // 把屏幕设置成横屏 setContentView(R.layout. test_layout) ; WindowManager wm = (WindowManager) this.getSystemService(Context. WINDOW_SERVICE) ; screenWidth = wm.getDefaultDisplay().getWidth() ; screenHeight = wm.getDefaultDisplay().getHeight() ; view1 = (TextView) findViewById(R.id. view1) ; LinearLayout.LayoutParams layoutParams1 = (LinearLayout.LayoutParams) view1.getLayoutParams() ; layoutParams1. height = myViewPaddingTop / 2 ; view1.setLayoutParams(layoutParams1) ; myView = (MyView) findViewById(R.id. myView) ; myView.setMyParams( screenWidth , screenHeight , myViewPaddingLeft , myViewPaddingTop) ; LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) myView.getLayoutParams() ; layoutParams. width = screenWidth - myViewPaddingLeft ; layoutParams. height = screenHeight - myViewPaddingTop ; myView.setLayoutParams(layoutParams) ; view2 = findViewById(R.id. view2) ; LinearLayout.LayoutParams layoutParams2 = (LinearLayout.LayoutParams) view2.getLayoutParams() ; layoutParams2. width = myViewPaddingLeft / 2 ; layoutParams2. height = screenHeight - myViewPaddingTop ; view2.setLayoutParams(layoutParams2) ; view3 = findViewById(R.id. view3) ; LinearLayout.LayoutParams layoutParams3 = (LinearLayout.LayoutParams) view3.getLayoutParams() ; layoutParams3. width = myViewPaddingLeft / 2 ; layoutParams3. height = screenHeight - myViewPaddingTop ; view3.setLayoutParams(layoutParams3) ; view4 = findViewById(R.id. view4) ; LinearLayout.LayoutParams layoutParams4 = (LinearLayout.LayoutParams) view4.getLayoutParams() ; layoutParams4. height = myViewPaddingTop / 2 ; view4.setLayoutParams(layoutParams4) ; surfaceview = (SurfaceView) findViewById(R.id. surfaceView) ; myView.setOnTouchListener( new View.OnTouchListener() { @Override public boolean onTouch(View v , MotionEvent event) { camera.autoFocus( myAutoFocusCallback) ; return false; } }) ; getWindow().setFlags(WindowManager.LayoutParams. FLAG_FULLSCREEN , WindowManager.LayoutParams. FLAG_FULLSCREEN) ; SurfaceHolder holder = surfaceview.getHolder() ; holder.setKeepScreenOn( true) ; // 屏幕常亮 holder.setType(SurfaceHolder. SURFACE_TYPE_NORMAL) ; holder.addCallback( new MySurfaceCallback()) ; holder.lockCanvas() ; } private final class MySurfaceCallback implements Callback { @Override public void surfaceChanged(SurfaceHolder holder , int format , int width , int height) { // 当 surface 的格式或大小发生改变,这个方法就被调用 } @Override public void surfaceCreated(SurfaceHolder holder) { try { camera = Camera. open() ; Camera.Parameters params = camera.getParameters() ; camera.setPreviewDisplay( surfaceview.getHolder()) ; // 开启预览 camera.startPreview() ; } catch (IOException e) { e.printStackTrace() ; } } @Override public void surfaceDestroyed(SurfaceHolder holder) { if ( camera != null) { camera.release() ; camera = null; } } } public void takepicture(View v) { camera.takePicture( mShutterCallback , null,mPicture Callback) ; }
Camera.ShutterCallback mShutterCallback = new Camera.ShutterCallback(){public void onShutter() { } } ; private Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() { @Override public void onPictureTaken( byte[] data , Camera camera) { Bitmap mBitmap = BitmapFactory. decodeByteArray(data , 0 , data. length) ; Bitmap mBitmapCut = ImageCrop(mBitmap) ; String rootPath = Environment. getExternalStorageDirectory().toString() + File. separator ; File file = new File(rootPath + System. currentTimeMillis() + ".jpg") ; try { file.createNewFile() ; BufferedOutputStream os = new BufferedOutputStream( new FileOutputStream(file)) ; mBitmapCut.compress(Bitmap.CompressFormat. JPEG , 100 , os) ; //100 是压缩率,100表示 不压缩 os.flush() ; os.close() ; Toast. makeText(getApplicationContext() , " 保存成功 " , Toast. LENGTH_SHORT).show() ; } catch (IOException e) { e.printStackTrace() ; } } } ; /** * 按图片比例裁切图片 */ public Bitmap ImageCrop(Bitmap bitmap) { int w = bitmap.getWidth() ; // 得到图片的宽,高 int h = bitmap.getHeight() ; // 剪切的初始 xy 位置,原点位置 都是根据比例来算的 int x = ( int) ((w * ( myViewPaddingLeft / 2)) / screenWidth) ; int y = ( int) (h * ( myViewPaddingTop / 2) / screenHeight) ; // 剪切的宽和高 int retX = ( int) ((w * ( screenWidth - myViewPaddingLeft)) / screenWidth) ; int retY = ( int) (h * ( screenHeight - myViewPaddingTop) / screenHeight) ; // 必须 x+retX 要小于或等于 bitmap.getWidth() , y+retY 要小于或等于 bitmap.getHeight(),不然会报错 return Bitmap. createBitmap(bitmap , x , y , retX , retY , null, false) ; } 最后放上一张保存下来,剪切后的照片,看看效果
扫描二维码关注公众号,回复:
3870085 查看本文章
如有不妥之处,请大家指正!!