Android 拍身份证(自定义相机)

Android 自定义相机 身份证拍照 自定义身份证相机 项目中需要用到拍摄身份证,拍完照片后直接拿到和身份证比例一致的图片,做成功的结果如下:    拍完照后直接拿到裁剪好的图本文的核心技术来自: https://yq.aliyun.com/articles/26706 先看看xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 阅读详情
版权声明:本文为转载文章,原文遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.youkuaiyun.com/github_37847975/article/details/80338730

Android自定义相机拍摄二代身份证。

感谢开源,尊重他人劳动成果,本自定义相机拍照核心逻辑取自云栖社区上Android 手把手带你玩转自定义相机
文章,本文仅仅在此基础上再次封装了返回拍照地址等监听事件,另外拍摄按钮没有做动画效果(待优化)

这里写图片描述

布局文件:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
    <ccqlk.homestay.bean.CameraSurfaceView
        android:id="@+id/cameraSurfaceView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <ccqlk.homestay.bean.CameraTopRectView
        android:id="@+id/rectOnCamera"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

      <Button
            android:layout_alignParentBottom="true"
            android:layout_centerHorizontal="true"
            android:layout_marginBottom="60dp"
            android:id="@+id/takePic"
            android:layout_width="80dp"
            android:layout_height="50dp"
            android:background="@color/colorAccent"
            android:text="点击拍照"
            android:textColor="@color/white" />
    </RelativeLayout>


</FrameLayout>
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

activity文件:

public class MCamerActivity extends AppCompatActivity implements View.OnClickListener,RectOnCamera.IAutoFocus{

    private Button button;
    private CameraSurfaceView mCameraSurfaceView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_camera);
        mCameraSurfaceView = (CameraSurfaceView) findViewById(R.id.cameraSurfaceView);
        button = (Button) findViewById(R.id.takePic);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mCameraSurfaceView.takePicture();

                mCameraSurfaceView.setOnPathChangedListener(new CameraSurfaceView.OnPathChangedListener() {
                    @Override
                    public void onValueChange(String path) {
                        LogUtil.d("-----拍摄的照片路径:"+path);
                    }
                });
            }
        });
    }

    @Override
    protected void onRestart() {
        super.onRestart();
    }



    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.takePic:
                mCameraSurfaceView.takePicture();
                break;
            default:
                break;
        }
    }


    @Override
    public void autoFocus() {
        mCameraSurfaceView.setAutoFocus();
    }
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52

CameraSurfaceView类:(其中LogUtil为我自己的日志工具,各位可以换成自己的或者Android自带的LOG)

package ccqlk.homestay.bean;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.hardware.Camera;
import android.os.Environment;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.Toast;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;
import java.util.List;

import ccqlk.homestay.ryx.uitls.LogUtil;

/**
 * Created by LK-RYX on 2018/4/28.
 */

public class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback, Camera.AutoFocusCallback {

    private static final String TAG = "CameraSurfaceView";

    private Context mContext;
    private SurfaceHolder holder;
    private Camera mCamera;

    private int mScreenWidth;
    private int mScreenHeight;
    private CameraTopRectView topView;

    private File mFile;
    private OnPathChangedListener onPathChangedListener;

    public OnPathChangedListener getOnPathChangedListener() {
        return onPathChangedListener;
    }

    public void setOnPathChangedListener(OnPathChangedListener onPathChangedListener) {
        this.onPathChangedListener = onPathChangedListener;
    }

    public CameraSurfaceView(Context context) {
        this(context, null);
    }

    public CameraSurfaceView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CameraSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mContext = context;
        getScreenMetrix(context);
        topView = new CameraTopRectView(context, attrs);

        initView();

    }

    //拿到手机屏幕大小
    private void getScreenMetrix(Context context) {
        WindowManager WM = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics outMetrics = new DisplayMetrics();
        WM.getDefaultDisplay().getMetrics(outMetrics);
        mScreenWidth = outMetrics.widthPixels;
        mScreenHeight = outMetrics.heightPixels;

    }

    private void initView() {
        holder = getHolder();//获得surfaceHolder引用
        holder.addCallback(this);
//        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);//设置类型

    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        Log.i(TAG, "surfaceCreated");
        if (mCamera == null) {

            mCamera = Camera.open();

            try {
                mCamera.setPreviewDisplay(holder);//摄像头画面显示在Surface上
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

        LogUtil.d("------surfaceChanged");

        setCameraParams(mCamera, mScreenWidth, mScreenHeight);
        mCamera.startPreview();
//        mCamera.takePicture(null, null, jpeg);

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {

        LogUtil.d("------surfaceDestroyed");

        mCamera.stopPreview();//停止预览
        mCamera.release();//释放相机资源
        mCamera = null;
        holder = null;
    }

    @Override
    public void onAutoFocus(boolean success, Camera Camera) {
        if (success) {
            LogUtil.d("------onAutoFocus success=" + success);
            System.out.println(success);
        }
    }


    private void setCameraParams(Camera camera, int width, int height) {
        //LogUtil.d("------setCameraParams  width="+width+"  height="+height);
        Camera.Parameters parameters = mCamera.getParameters();
        // 获取摄像头支持的PictureSize列表
        List<Camera.Size> pictureSizeList = parameters.getSupportedPictureSizes();
        /**从列表中选取合适的分辨率*/
        Camera.Size picSize = getProperSize(pictureSizeList, ((float) height / width));
        if (null == picSize) {
            Log.i(TAG, "null == picSize");
            picSize = parameters.getPictureSize();
        }

        // 根据选出的PictureSize重新设置SurfaceView大小
        float w = picSize.width;
        float h = picSize.height;
        parameters.setPictureSize(picSize.width, picSize.height);
        this.setLayoutParams(new FrameLayout.LayoutParams((int) (height * (h / w)), height));

        // 获取摄像头支持的PreviewSize列表
        List<Camera.Size> previewSizeList = parameters.getSupportedPreviewSizes();

        Camera.Size preSize = getProperSize(previewSizeList, ((float) height) / width);
        if (null != preSize) {
            LogUtil.d("----------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();//自动对焦。
        mCamera.setDisplayOrientation(90);// 设置PreviewDisplay的方向,效果就是将捕获的画面旋转多少度显示
        mCamera.setParameters(parameters);

    }

    /**
     * 从列表中选取合适的分辨率
     * 默认w:h = 4:3
     * <p>注意:这里的w对应屏幕的height
     * h对应屏幕的width<p/>
     */
    private Camera.Size getProperSize(List<Camera.Size> pictureSizeList, float screenRatio) {
        Log.i(TAG, "screenRatio=" + 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:3
                    result = size;
                    break;
                }
            }
        }

        return result;
    }


    // 拍照瞬间调用
    private Camera.ShutterCallback shutter = new Camera.ShutterCallback() {
        @Override
        public void onShutter() {
            LogUtil.d("---------执行到这里了吗+1:shutter");
        }
    };

    // 获得没有压缩过的图片数据
    private Camera.PictureCallback raw = new Camera.PictureCallback() {

        @Override
        public void onPictureTaken(byte[] data, Camera Camera) {

            LogUtil.d("---------执行到这里了吗+:raw");
        }
    };

    //创建jpeg图片回调数据对象
    private Camera.PictureCallback jpeg = new Camera.PictureCallback() {

        private Bitmap bitmap;

        @Override
        public void onPictureTaken(byte[] data, Camera Camera) {

            topView.draw(new Canvas());

            BufferedOutputStream bos = null;
            Bitmap bm = null;
            if (data != null) {

            }

            try {
                // 获得图片
                bm = BitmapFactory.decodeByteArray(data, 0, data.length);

                if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {

//                  图片存储前旋转
                    Matrix m = new Matrix();
                    int height = bm.getHeight();
                    int width = bm.getWidth();
                    m.setRotate(90);
                    //旋转后的图片
                    bitmap = Bitmap.createBitmap(bm, 0, 0, width, height, m, true);

                    LogUtil.d("---------执行到这里了吗+3");

                    String photo = "IMMQY/IMG_" + String.valueOf(new Date().getTime() + ".jpg");
                    mFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsolutePath(), photo);
                    if (!mFile.getParentFile().exists()) mFile.getParentFile().mkdirs();

                    LogUtil.d("---------自定义照片保存路径:" + mFile.getPath());

                    bos = new BufferedOutputStream(new FileOutputStream(mFile));

//                    Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0,
//                            data.length);
                    Bitmap sizeBitmap = Bitmap.createScaledBitmap(bitmap,
                            topView.getViewWidth(), topView.getViewHeight(), true);
                    bm = Bitmap.createBitmap(sizeBitmap, topView.getRectLeft(),
                            topView.getRectTop(),
                            topView.getRectRight() - topView.getRectLeft(),
                            topView.getRectBottom() - topView.getRectTop());// 截取


                    bm.compress(Bitmap.CompressFormat.JPEG, 100, bos);//将图片压缩到流中


                } else {
                    Toast.makeText(mContext, "没有检测到内存卡", Toast.LENGTH_SHORT).show();
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    bos.flush();//输出
                    bos.close();//关闭
                    bm.recycle();// 回收bitmap空间
                    mCamera.stopPreview();// 关闭预览
                    mCamera.startPreview();// 开启预览
                    if (onPathChangedListener != null) {
                        LogUtil.d("------监听路径:" + mFile.getPath());
                        onPathChangedListener.onValueChange(mFile.getPath());
                    }

                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
    };

    public void takePicture() {
        //设置参数,并拍照
        setCameraParams(mCamera, mScreenWidth, mScreenHeight);
        // 当调用camera.takePiture方法后,camera关闭了预览,这时需要调用startPreview()来重新开启预览
        mCamera.takePicture(null, null, jpeg);
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    }

    public void setAutoFocus() {
        mCamera.autoFocus(this);
    }


    public interface OnPathChangedListener {
        void onValueChange(String path);
    }
}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325

CameraTopRectView类

package ccqlk.homestay.bean;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import android.view.WindowManager;

/**
 * Created by LK-RYX on 2018/4/28.
 */

class CameraTopRectView extends View {

    private int panelWidth;
    private int panelHeght;

    private int viewWidth;
    private int viewHeight;

    public int rectWidth;
    public int rectHeght;

    private int rectTop;
    private int rectLeft;
    private int rectRight;
    private int rectBottom;

    private int lineLen;
    private int lineWidht;
    private static final int LINE_WIDTH = 5;
    private static final int TOP_BAR_HEIGHT = 50;
    private static final int BOTTOM_BTN_HEIGHT = 66;

//    private static final int TOP_BAR_HEIGHT = Constant.RECT_VIEW_TOP;
//    private static final int BOTTOM_BTN_HEIGHT = Constant.RECT_VIEW_BOTTOM;

    private static final int LEFT_PADDING = 10;
    private static final int RIGHT_PADDING = 10;
    private static final String TIPS = "请将身份证放入到方框中";

    private Paint linePaint;
    private Paint wordPaint;
    private Rect rect;
    private int baseline;

    public CameraTopRectView(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
        Activity activity = (Activity) context;

        WindowManager wm = (WindowManager) activity.getSystemService(Context.WINDOW_SERVICE);
        panelWidth = wm.getDefaultDisplay().getWidth();//拿到屏幕的宽
        panelHeght = wm.getDefaultDisplay().getHeight();//拿到屏幕的高

        //高度不需要dp转换px,不然整体相机会向上移动一小节
//        viewHeight = panelHeght - (int) DisplayUtil.dp2px(activity,TOP_BAR_HEIGHT + BOTTOM_BTN_HEIGHT);

        viewHeight = panelHeght;
        //viewHeight,界面的高,viewWidth,界面的宽
        viewWidth = panelWidth;

        /*rectWidth = panelWidth
                - UnitUtils.getInstance(activity).dip2px(
                        LEFT_PADDING + RIGHT_PADDING);*/

        rectWidth = panelWidth - (int) DisplayUtil.dp2px(activity,LEFT_PADDING + RIGHT_PADDING);

        rectHeght = (int) (rectWidth * 54 / 85.6);
        // 相对于此view
        rectTop = (viewHeight - rectHeght) / 2;
        rectLeft = (viewWidth - rectWidth) / 2;
        rectBottom = rectTop + rectHeght;
        rectRight = rectLeft + rectWidth;

        lineLen = panelWidth / 8;

        linePaint = new Paint();
        linePaint.setAntiAlias(true);
        linePaint.setColor(Color.rgb(0xdd, 0x42, 0x2f));
        linePaint.setStyle(Paint.Style.STROKE);
        linePaint.setStrokeWidth(LINE_WIDTH);// 设置线宽
        linePaint.setAlpha(255);

        wordPaint = new Paint();
        wordPaint.setAntiAlias(true);
        wordPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        wordPaint.setStrokeWidth(3);
        wordPaint.setTextSize(35);

        rect = new Rect(rectLeft, rectTop - 80, rectRight, rectTop - 10);
        Paint.FontMetricsInt fontMetrics = wordPaint.getFontMetricsInt();
        baseline = rect.top + (rect.bottom - rect.top - fontMetrics.bottom + fontMetrics.top) / 2 - fontMetrics.top;
        wordPaint.setTextAlign(Paint.Align.CENTER);
    }

    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        wordPaint.setColor(Color.TRANSPARENT);
        canvas.drawRect(rect, wordPaint);

        //画蒙层
        wordPaint.setColor(0xa0000000);
        rect = new Rect(0, viewHeight/2+rectHeght/2, viewWidth, viewHeight);
        canvas.drawRect(rect, wordPaint);

        rect = new Rect(0, 0, viewWidth, viewHeight/2-rectHeght/2);
        canvas.drawRect(rect, wordPaint);

        rect = new Rect(0, viewHeight/2-rectHeght/2, (viewWidth-rectWidth)/2, viewHeight/2+rectHeght/2);
        canvas.drawRect(rect, wordPaint);

        rect = new Rect(viewWidth-(viewWidth-rectWidth)/2, viewHeight/2-rectHeght/2, viewWidth, viewHeight/2+rectHeght/2);
        canvas.drawRect(rect, wordPaint);


        //重制rect  并画文字  吧文字置于rect中间
        rect = new Rect(rectLeft, rectTop - 80, rectRight, rectTop - 10);
        wordPaint.setColor(Color.WHITE);
        canvas.drawText(TIPS, rect.centerX(), baseline, wordPaint);
        canvas.drawLine(rectLeft, rectTop, rectLeft + lineLen, rectTop,
                linePaint);
        canvas.drawLine(rectRight - lineLen, rectTop, rectRight, rectTop,
                linePaint);
        canvas.drawLine(rectLeft, rectTop, rectLeft, rectTop + lineLen,
                linePaint);
        canvas.drawLine(rectRight, rectTop, rectRight, rectTop + lineLen,
                linePaint);
        canvas.drawLine(rectLeft, rectBottom, rectLeft + lineLen, rectBottom,
                linePaint);
        canvas.drawLine(rectRight - lineLen, rectBottom, rectRight, rectBottom,
                linePaint);
        canvas.drawLine(rectLeft, rectBottom - lineLen, rectLeft, rectBottom,
                linePaint);
        canvas.drawLine(rectRight, rectBottom - lineLen, rectRight, rectBottom,
                linePaint);
    }

    public int getRectLeft() {
        return rectLeft;
    }

    public int getRectTop() {
        return rectTop;
    }

    public int getRectRight() {
        return rectRight;
    }

    public int getRectBottom() {
        return rectBottom;
    }

    public int getViewWidth() {
        return viewWidth;
    }

    public int getViewHeight() {
        return viewHeight;
    }

}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169

DisplayUtil工具类

package ccqlk.homestay.bean;

import android.content.Context;

/**
 * Created by LK-RYX on 2018/4/28.
 */

public class DisplayUtil {
    /**
     * 将px装换成dp,保证尺寸不变
     * @param context
     * @param pxValue
     * @return
     */
    public static int px2dp(Context context, float pxValue){
        float density = context.getResources().getDisplayMetrics().density;//得到设备的密度
        return (int) (pxValue/density+0.5f);
    }
    public static int dp2px(Context context, float dpValue){
        float density = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue*density+0.5f);
    }
    public static int px2sp(Context context, float pxValue){
        float scaleDensity = context.getResources().getDisplayMetrics().scaledDensity;//缩放密度
        return (int) (pxValue/scaleDensity+0.5f);
    }
    public static int sp2px(Context context, float spValue) {
        float scaleDensity = context.getResources().getDisplayMetrics().scaledDensity;
        return (int) (spValue*scaleDensity+0.5f);
    }
}

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

再次感谢前辈们的奉献,本文核心代码原文地址:https://yq.aliyun.com/articles/26706,该文章分析的很透彻!


为了向别人、向世界证明自己而努力拼搏,而一旦你真的取得了成绩,才会明白:人无须向别人证明什么,只要你能超越自己。

Android自定义相机的实现以及Camera框架分析 一:Android Camera框架分析: (1).Android Camera框架层结构是C/S结构,客户端提供调用 接口,服务器端实现具体的功能。客户端和服务器端是通过Binder机制进行通信的。 (2).首先客户端取得Binder机制的代理,然后Binder和服务器端进行通信。虽然客户端获得不到实质的Camera数据,但是服务器端为它提供了丰富的接口,可以获得Camer 阅读详情

相关推荐

Android身份证识别系统开发与实战

随着移动互联网的普及,身份证识别技术在金融、政务、实名认证等场景中发挥着越来越重要的作用。Android平台作为主流移动操作系统之一,为身份证识别技术的落地提供了丰富的开发资源和灵活的实现路径。本章将从身份证识别的应用背景入手,分析其在移动端的需求驱动与发展现状,帮助开发者理解为何要在Android平台上构建高效的身份证识别系统。同时,本章还将介绍身份证识别的核心流程,包括图像采集、预处理、OCR识别与数据校验等关键步骤,为后续章节的技术实现打下理论基础。

weixin_34640289的博客 1126

Android 好用的身份证拍照界面封装

ORCamera 项目地址:lvzhihao100/ORCamera 简介:Android 好用的身份证拍照界面封装 更多:作者提 Bug官网 标签: Android 好用的身份证拍照界面封装 手持身份证调用 Intent intent = new Intent(this, CameraActivity.class); ...

未来很长,但我会努力的走下去。 1746

Android代码-Android自定义相机实现身份证拍照,并加入自动对焦与图片不规则裁剪

Android自定义身份证相机-IDCardCamera 效果图: 功能特点 自定义相机界面 支持开启闪光灯 支持手动触摸屏幕对焦 支持自动对焦 支持图片自动裁剪 支持图片手动不规则裁剪 2 使用 Step 1. 添加JitPack仓库 在项目的build.gradle添加JitPack仓库 allprojects { repositories { ... maven { url "https://jitpack.io" } } } Step 2. 添加依赖 在需要使用的module中添加依赖 dependencies { compile 'com.github.wildma:IDCardCamera:1.0.1' } 或者引用本地lib compile project(':idcardcamera') Step 3. 调用CameraActivity类的toCameraActivity方法打开拍照界面 CameraActivity.toCameraActivity(this, CameraActivity.TYPE

Android 项目必备(十七)-->实现身份证认证功能

认证身份证的正反面

Kevin Learn Android 3749

Android开发指定区域拍照,身份证拍照,银行卡拍照

Android开发指定区域拍照,身份证拍照,银行卡拍照

IDCardCamera:Android自定义相机实现身份证截图,并加入自动对焦与图片不规则裁剪。https://www.jianshu.comp5e3cb0c63cd5

IDCardCamera Android自定义身份证相机 效果图 APK 功能特点 自定义相机界面 支持开启闪光灯 支持手动触摸屏幕对焦 支持自动聚焦 支持图片自动裁剪 支持图片手动不规则裁剪 使用 步骤1.添加JitPack仓库 在项目的build.gradle添加JitPack仓库 allprojects { repositories { ... maven { url "https://jitpack.io" } } } 步骤2.添加依赖 在需要使用的模块中添加依赖 dependencies { compile 'com.github.wildma:IDCardCamera:1.1.1' } 步骤3 .:拍照界面 身份证正面 IDCardCamera.create(this).openCamera(IDCardCamera.TY

【50】Android自定义身份证拍照相机

Android自定义身份证拍照相机1.亮点2.功能支持3.上传页面效果图4.拍摄身份证正面照5.裁剪身份证正面照6.拍摄身份证背面照7.身份证拍摄结果8.项目源代码结构。

青风百草 766

Android自定义相机——身份证扫描界面

Android自定义相机 身份证扫描界面 支持android6.0 8.0拍照适配

Android 自定义相机实现身份证拍照,并加入自动对焦与图片不规则裁剪

IDCardCamera 项目地址:wildma/IDCardCamera  简介:Android 自定义相机实现身份证拍照,并加入自动对焦与图片不规则裁剪 更多:作者   提 Bug    标签:      README of English 效果图 ...

未来很长,但我会努力的走下去。 1299

身份证,号码归属地查询

身份证,号码归属地查询源码可以查找相关身份证号码,还有某地区区号,电话号码归属地,简单小软件,供大家学习。

Win10/Win11系统下,用VSCode编译Betaflight固件最全避坑指南(从GCC安装到HEX生成)

本文详细介绍了在Win10/Win11系统下使用VSCode编译Betaflight固件的完整流程,包括GCC安装、环境变量配置、终端选择、Make工具安装等关键步骤,帮助开发者避开常见陷阱,高效生成HEX文件。特别针对VSCode环境优化和编译错误排查提供了实用解决方案。

weixin_42557803的博客 415

uniapp安卓App自定义相机(身份证相机)

本人也是第一次做app的自定义相机功能,找了相关文章后,发现uniapp自带的相机组件是不能实现在app中自定义相机的功能,因为不支持。所以使用了uniapp中的live-pusher组件实现自定义相机的功能。

a1122556464的博客 1万+

【日常小结】项目Modbus RTU 协议

Modbus RTU(远程终端) 协议 一、前言 最近因为码跺宽度测量项目推广升级,更换了摄像头(换成了基恩士摄像头)和光栅(换成了施莱格05LCM系列光栅),导致原来的程序用不了了,然而这个软件升级的任务落到了我身上,作为机械非科班出身的我要学习TCP和Modbus RTU通信协议,也算是自我突破了。本文只对Modbus/RTU/HEX 进行简单的小结。 二、Modbus Modbus是一种串行通信协议,是Modicon公司(现在的施耐德电气Schneider Electric)于1979年为使用可编程逻

weixin_39681471的博客 831

APP自定义身份证相机(Android +iOS)

【代码】APP自定义身份证相机(Android +iOS)

Rio_Gaven的博客 2078

PyTorch实战:3D U-Net医学图像分割从零搭建(附完整代码)

本文详细介绍了如何使用PyTorch从零搭建3D U-Net模型进行医学图像分割,涵盖三维卷积实现、模块化架构设计、医学图像专属优化策略及完整训练流程。通过实战代码演示,帮助开发者掌握UNet-3D在CT、MRI等三维医学图像分割中的应用,提升肝脏肿瘤分割、肺结节检测等任务的准确性。

weixin_29061997的博客 329

避开地图定位偏差!手把手教你用Python实现火星坐标与WGS84精准转换

本文深入解析了国内地图服务中火星坐标(GCJ-02)与国际标准WGS84坐标系之间的偏差问题,并提供了基于Python的精准转换解决方案。文章详细阐述了坐标转换的核心原理,手把手教你构建可复用的转换工具包,并演示如何将其集成到实际应用(如Flask API)中,帮助开发者和数据分析师有效解决地图定位不准、多源数据无法对齐的痛点,提升地理信息处理能力。

weixin_29250403的博客 125

安卓 自定义相机,身份证拍照

最近项目需要实现身份证拍照的功能,系统的相机并不能满足需求,故需要自定义相机,先上效果图,使用了Camera+ SurfaceView; 布局文件 xml version="1.0" encoding="utf-8"?> FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tool

LHBTM的博客 9426

Python通用编程规范-09 安全编程规范

1.9 安全编程规范 1.9.1 异常行为 1.9.1.1 禁止抑制或者忽略已检查异常 【说明】: 编码人员常常会通过一个空的或者无意义的catch块来抑制捕获的已检查异常。每一个catch块都应该确保程序只会在继续有效的情况下才会继续运行下去。因此,catch块必须要么从异常情况中恢复,要么重新抛出适合当前catch块上下文的另一个异常以允许最邻近的外层try-catch语句块来进行恢复工作。异常会打断应用原本预期的控制流程。例如,try块中位于异常发生点之后的任何表达式和语句都不会被执行。因此,异常必须

zhao12501的博客 2871

Android | 教你如何在安卓上实现二代身份证识别,一键实名认证

目录前言场景开发前准备android studio 安装在项目级gradle里添加华为maven仓在应用级的build.gradle里面加上SDK依赖在AndroidManifest.xml文件里面增量添加模型自动下载在AndroidManifest.xml文件里面申请相机、访问网络和存储权限代码开发关键步骤创建识别结果回调函数设置识别参数实现身份识别Demo效果 前言   就在近期华为HMS M...

华为开发者联盟 9784

CelebA-HQ数据集下载【详细明了版】分辨率包括【64,128,256,512,1024】

CelebA-HQ 是在ICLR2018上,nVidia发表了一篇名为Progressive Growing of GANs for Improved Quality, Stability, and Variation的论文,文中通过训练高分辨率GAN生成了一个新的人脸数据集CelebA-HQ.CelebA是港科大汤晓鸥组收集的人脸数据集(总共200k图片),包括了人脸特征点(landmark),人脸属性(attribute)等信息,详细介绍参考链接[1]和[2]

zik的博客 1万+

.net core 下的PostgreSQL 异常排查—— Exception while reading from stream (0x80004005)

最近以PostgreSQL为存储介质,实现了分布式缓存的一个组件开发,在经过开发环境的测试后,顺利推送到产品组的手里,经过开发环境的验证后,终于发布到测试环境了,但问题来了,产品组反应频繁出现访问异常,返回的信息大致是:Exception while reading from stream … (0x80004005) ????欢迎点赞 :???? 收藏 ⭐留言 ???? 如有错误敬请指正,赐人玫瑰,手留余香! ????本文作者:由webmote 原创,首发于 【优快云】 ????作者格言: 生活在

网尘的技术专栏 5842

Android 自定义相机

使用Android android.hardware.camera2 API开发的自定义相机。

唐诺 284

RK3588 ENV 环境配置之 fw_printenv

RK3588 ENV环境配置指南 本文详细介绍了在RK3588平台上配置ENV环境变量的完整流程。首先需要在parameter分区表中划分env分区,然后在U-Boot中配置MMC偏移地址。接着编译fw_printenv工具并部署到目标设备,配置fw_env.config文件指定存储位置。重点解决了内核中读写ENV时遇到的CRC校验问题,通过U-Boot的saveenv命令初始化环境变量存储区域。最后展示了如何使用fw_printenv/fw_setenv工具在内核中读写ENV变量,并建议将配置集成到根文件

501846585_QQAndroid_java 1033

IDCardCamera完全指南:如何用Android自定义相机实现高效身份证拍照

在移动应用开发中,身份证信息采集是金融、政务等领域的常见需求。IDCardCamera作为一款开源的Android自定义相机组件,通过智能取景框和自动裁剪技术,让身份证拍照识别变得简单高效。本文将带你从零开始了解这个强大工具的核心功能、集成方法和最佳实践,帮助开发者快速实现专业级的身份证采集模块。 ## 核心功能解析:为何选择IDCardCamera? IDCardCamera凭借三大核心优势

gitblog_00229的博客 1077

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

安卓身份证识别

OCR介绍 要实现一个可以识别身份证内容的app,就需要用到OCR(optical character recognition)技术,OCR详细介绍可以看百度百科:OCR文字识别_百度百科 (baidu.com)。简单来说,OCR可以将图片转换成文字。github上开源的Tesseract即实现了OCR算法,然而Tesseract是用C++写的,在安卓app中使用会很麻烦。这里介绍github上另一个开源项目tess-two,使安卓app可以轻松调用tesseract算法。(虽然tess-two项目原作者

SSSxCCC的博客 2050

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

下一篇: Thymeleaf模板引擎入门
Summer_Chun
博客等级 码龄7年 3粉丝 0原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值