安卓自定义照相机(横竖屏感应)
发布日期:2021-06-28 19:37:25 浏览次数:2 分类:技术文章

本文共 24175 字,大约阅读时间需要 80 分钟。

实现功能:

通过安卓自带的SensorManager(传感器)来判断,当用户横向拍照时照片出来是竖向显示的

实现代码:

final Intent intent = new Intent(TakePic_Activity.this, PhotoActivity.class);String url=Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator        + "PICvkl" + File.separator + szCarNum + szCarNumType + StrCode + ".jpg";intent.putExtra("uri", url);startActivityForResult(intent,55);

PhotoActivity

public class PhotoActivity extends Activity {    private SurfaceView surfaceView;        //照片显示surfaceview    private Button takephotoBtn;            //拍照按钮    private TextView nameTv;                //项目名    private SurfaceHolder surfaceHolder;    //surfaceview控制器    private Camera camera;    private ImageView lightImg;             //闪光灯    private boolean isLightOpen = false;      //闪光灯是否开启    ProgressDialog dialog;    private String uri = "";    /**     * 新加缩放控件     */    private SeekBar mZoomSeekBar;    private ScreenSwitchUtils instance;//传感器工具类对象    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        requestWindowFeature(Window.FEATURE_NO_TITLE);        setContentView(R.layout.activity_photo);        instance = ScreenSwitchUtils.init(getApplicationContext());        initView();        initListener();    }    @Override    protected void onStart() {        super.onStart();        instance.start(this);    }    @Override    protected void onStop() {        super.onStop();        instance.stop();    }    private void initView() {        if (getIntent() != null) {            uri = getIntent().getStringExtra("uri");            Log.e("lcb", "照片的保留地方:" + uri);        }        nameTv = (TextView) findViewById(R.id.name_tv);        surfaceView = (SurfaceView) findViewById(R.id.surface_view);        takephotoBtn = (Button) findViewById(R.id.takephoto_btn);        lightImg = (ImageView) findViewById(R.id.light_img);        mZoomSeekBar = (SeekBar) findViewById(R.id.zoomSeekBar);        //设置标题文字   (请横拍)项目名:        nameTv.setText("支持横竖拍,竖拍左右倾斜不要超过45度\n横拍请向左,保证\"拍照\"按钮在右边");    }    private void initListener() {        surfaceHolder = surfaceView.getHolder();                        //设置Holder        surfaceHolder.addCallback(surfaceCallback);                     //加入回调        surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); //设置缓冲类型        //  图片大小在200K-600K之间 (检测线的规格是2080X1560)        surfaceHolder.setFixedSize(3264, 2448);        //闪光灯开关控制器        lightImg.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                if (!isLightOpen) {                    if (camera != null) {                        Camera.Parameters parameters = camera.getParameters();                        parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);                        camera.setParameters(parameters);                        camera.startPreview();                    }                    isLightOpen = true;                    lightImg.setImageResource(R.drawable.light_down);                } else {                    if (camera != null) {                        Camera.Parameters parameters = camera.getParameters();                        parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);                        camera.setParameters(parameters);                        camera.startPreview();                    }                    isLightOpen = false;                    lightImg.setImageResource(R.drawable.light_up);                }            }        });        //点击拍照按钮进行拍照。        takephotoBtn.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View arg0) {                /*                 * shutter:快门被按下                 * raw:相机所捕获的原始数据                 * jpeg:相机处理的数据                 */                takePhoto();            }        });    }    Camera.PictureCallback pictureCallback = new Camera.PictureCallback() {        @Override        public void onPictureTaken(byte[] data, Camera camera) {            //保存图片            new SavePictureTask().execute(data, null, null);            //开始预览            camera.startPreview();        }    };    /**     * 3、异步保存图片。     */    class SavePictureTask extends AsyncTask
{ @Override protected String doInBackground(byte[]... params) { File file = new File(uri); try {// BitmapFactory.Options options=new BitmapFactory.Options();// options.inSampleSize=8; Bitmap bitmap = BitmapFactory.decodeByteArray(params[0], 0, params[0].length); //水印格式:流水号:XXX 车辆识别代号:XXX 时间:XXX (如果有车牌号的,则把车牌号也输入上去)查验员代号:XXX 红色 左上方 Log.v("lcb","当前角度:"+instance.getOrientation()+" 是否竖屏:"+instance.isPortrait()); if (instance.isPortrait()) { /*如果是竖屏压缩bitmap时候设置方向*/ Matrix matrix = new Matrix(); matrix.reset(); matrix.postRotate(90); bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); } FileOutputStream fos = new FileOutputStream(file.getPath()); //图片压缩到70% //如果第一张,清楚 bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos); fos.flush(); fos.close(); //关流 bitmap.recycle(); //回收bitmap资源 dialog.dismiss(); setResult(Activity.RESULT_OK, null); finish(); } catch (Exception e) { Log.e("lcb", "photo156:" + e.toString()); } return null; } } /** * SurfaceHolder回调函数。重写SurfaceHolder.Callback接口的surfaceCreated、surfaceChanged、surfaceDestroyed方法。 */ SurfaceHolder.Callback surfaceCallback = new SurfaceHolder.Callback() { private static final String TAG = "CameraPreview"; public void surfaceCreated(SurfaceHolder holder) { camera = Camera.open(); //打开摄像头 try { camera.setDisplayOrientation(90); //设置camera预览的角度,因为默认图片是倾斜90度的 camera.setPreviewDisplay(holder); //设置holder主要是用于surfaceView的图片的实时预览,以及获取图片等功能 } catch (IOException e) { camera.release(); //释放 camera = null; } } public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {// Camera.Parameters parameters = camera.getParameters();// parameters.setPictureSize(3264, 2448);// camera.setParameters(parameters);// camera.startPreview(); //开始预览// camera.autoFocus(autoFocusCallback); //当SurfaceView尺寸变化时(包括设备横屏竖屏改变时时),需要重新设定相关参数 if (holder.getSurface() == null) { //检查SurfaceView是否存在 return; } //改变设置前先关闭相机 try { camera.stopPreview(); } catch (Exception e) { e.printStackTrace(); } //使用最佳比例配置重启相机 try { camera.setPreviewDisplay(holder); Camera.Parameters parameters = camera.getParameters(); Camera.Size size = getBestPreviewSize(width, height); parameters.setPreviewSize(size.width, size.height); parameters.setPictureSize(3264, 2448); camera.setParameters(parameters); camera.startPreview(); } catch (Exception e) { Log.d(TAG, "Error starting camera preview: " + e.getMessage()); } } public void surfaceDestroyed(SurfaceHolder holder) { camera.stopPreview(); // stop preview camera.release(); // Release camera resources camera = null; } }; /** * 拍照操作 */ private void takePhoto() { try { camera.takePicture(null, null, pictureCallback); } catch (Exception e) { e.printStackTrace(); Log.e("lcb", "拍照操作报错:" + e.toString()); } if (dialog == null) { dialog = new ProgressDialog(PhotoActivity.this); dialog.setMessage("图片处理中……"); } dialog.show(); // 2017/4/26 dialog十秒没关,自动关掉dialog new Thread() { @Override public void run() { super.run(); try { sleep(10000); if (!PhotoActivity.this.isFinishing()) { dialog.dismiss(); } } catch (InterruptedException e) { e.printStackTrace(); } } }.start(); } private Camera.Size getBestPreviewSize(int width, int height) { Camera.Size result = null; final Camera.Parameters p = camera.getParameters(); //特别注意此处需要规定rate的比是大的比小的,不然有可能出现rate = height/width,但是后面遍历的时候,current_rate = width/height,所以我们限定都为大的比小的。 float rate = (float) Math.max(width, height) / (float) Math.min(width, height); float tmp_diff; float min_diff = -1f; for (Camera.Size size : p.getSupportedPreviewSizes()) { float current_rate = (float) Math.max(size.width, size.height) / (float) Math.min(size.width, size.height); tmp_diff = Math.abs(current_rate - rate); if (min_diff < 0) { min_diff = tmp_diff; result = size; } if (tmp_diff < min_diff) { min_diff = tmp_diff; result = size; } } return result; } /** * 记录是拖拉照片模式还是放大缩小照片模式 */ private static final int MODE_INIT = 0; /** * 放大缩小照片模式 */ private static final int MODE_ZOOM = 1; private int mode = MODE_INIT;// 初始状态 private float startDis; @SuppressLint("HandlerLeak") private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); } }; @Override public boolean onTouchEvent(MotionEvent event) { /** 通过与运算保留最后八位 MotionEvent.ACTION_MASK = 255 */ switch (event.getAction() & MotionEvent.ACTION_MASK) { // 手指压下屏幕 case MotionEvent.ACTION_DOWN: mode = MODE_INIT; break; case MotionEvent.ACTION_POINTER_DOWN: //如果mZoomSeekBar为null 表示该设备不支持缩放 直接跳过设置mode Move指令也无法执行 if (mZoomSeekBar == null) return true; //移除token对象为mZoomSeekBar的延时任务 mHandler.removeCallbacksAndMessages(mZoomSeekBar);// mZoomSeekBar.setVisibility(View.VISIBLE); mZoomSeekBar.setVisibility(View.GONE); mode = MODE_ZOOM; /** 计算两个手指间的距离 */ startDis = spacing(event); break; case MotionEvent.ACTION_MOVE: if (mode == MODE_ZOOM) { //只有同时触屏两个点的时候才执行 if (event.getPointerCount() < 2) return true; float endDis = spacing(event);// 结束距离 //每变化10f zoom变1 int scale = (int) ((endDis - startDis) / 10f); if (scale != 0) { int zoom = getZoom() + scale; //zoom不能超出范围 if (zoom > getMaxZoom()) zoom = getMaxZoom(); if (zoom < 0) zoom = 0; setZoom(zoom); mZoomSeekBar.setProgress(zoom); //将最后一次的距离设为当前距离 startDis = endDis; } } break; // 手指离开屏幕 case MotionEvent.ACTION_UP: if (mode != MODE_ZOOM) { //设置聚焦 Point point = new Point((int) event.getX(), (int) event.getY()); onCameraFocus(point); } else { //ZOOM模式下 在结束两秒后隐藏seekbar 设置token为mZoomSeekBar用以在连续点击时移除前一个定时任务 mHandler.postAtTime(new Runnable() { @Override public void run() { // TODO Auto-generated method stub mZoomSeekBar.setVisibility(View.GONE); } }, mZoomSeekBar, SystemClock.uptimeMillis() + 2000); } break; } return true; } /** * 两点的距离 */ private float spacing(MotionEvent event) { if (event == null) { return 0; } float x = event.getX(0) - event.getX(1); float y = event.getY(0) - event.getY(1); return (float) Math.sqrt(x * x + y * y); } /** * 相机对焦 默认不需要延时 */ private void onCameraFocus(final Point point) { onCameraFocus(point, false); } /** * @param needDelay 是否需要延时 * @author Longchengbin * @description 相机对焦 * @since 2020-11-2 10:02 **/ public void onCameraFocus(final Point point, boolean needDelay) { if (camera == null) { return; }// getMaxNumFocusAreas:获取支持的对焦区域的个数// setFocusAreas:设置对焦区域列表// getFocusAreas:获取对焦区域列表// getMaxNumMeteringAreas: 获取支持的测光区域的个数// setMeteringAreas:设置测光区域列表// getMeteringAreas:获取测光区域列表 Camera.Parameters parameters = camera.getParameters(); //不支持设置自定义聚焦,则使用自动聚焦,返回 if (parameters.getMaxNumFocusAreas() <= 0) { camera.autoFocus(autoFocusCallback); return; } List
areas = new ArrayList
(); int left = point.x - 30; int top = point.y - 30; int right = point.x + 30; int bottom = point.y + 30; left = left < -1000 ? -1000 : left; top = top < -1000 ? -1000 : top; right = right > 1000 ? 1000 : right; bottom = bottom > 1000 ? 1000 : bottom; areas.add(new Camera.Area(new Rect(left, top, right, bottom), 100)); parameters.setFocusAreas(areas); camera.cancelAutoFocus();//结束上一次的对焦操作,不管是有没有完成对焦 try { camera.setParameters(parameters); } catch (Exception e) { Log.e("lcb", "相机对焦报错:" + e.toString()); } camera.autoFocus(autoFocusCallback);//执行一次对焦操作,通过Camera.AutoFocusCallback返回对焦结果 } /** * 当前缩放 */ private int mZoom; public int getMaxZoom() { if (surfaceView == null) return -1; Camera.Parameters parameters = camera.getParameters(); if (!parameters.isZoomSupported()) return -1; return parameters.getMaxZoom() > 40 ? 40 : parameters.getMaxZoom(); } public void setZoom(int zoom) { if (camera == null) return; Camera.Parameters parameters; //注意此处为录像模式下的setZoom方式。在Camera.unlock之后,调用getParameters方法会引起android框架底层的异常 //stackoverflow上看到的解释是由于多线程同时访问Camera导致的冲突,所以在此使用录像前保存的mParameters。 parameters = camera.getParameters(); if (!parameters.isZoomSupported()) return; parameters.setZoom(zoom); camera.setParameters(parameters); mZoom = zoom; } public int getZoom() { return mZoom; } /** * @author Longchengbin * @description 自动对焦回调 * @since 2020-11-2 10:06 **/ Camera.AutoFocusCallback autoFocusCallback = new Camera.AutoFocusCallback() { @Override public void onAutoFocus(boolean b, final Camera camera) { if (b) { camera.cancelAutoFocus(); new Thread() { @Override public void run() { super.run(); try { sleep(1000); } catch (Exception e) { e.printStackTrace(); } try { if (!PhotoActivity.this.isFinishing()) { // TODO: 2017/7/18 三星手机长时间自动对焦失败,取消自动对焦 camera.autoFocus(autoFocusCallback); } } catch (Exception e) { e.printStackTrace(); Log.e("lcb", "自动对焦回调报错:" + e.toString()); } } }.start(); } } };}

R.layout.activity_photo

ScreenSwitchUtils

public class ScreenSwitchUtils {    private int mOrientation;    private static final String TAG = "test";    private volatile static ScreenSwitchUtils mInstance;    private Activity mActivity;    // 是否是竖屏    private boolean isPortrait = true;    private SensorManager sm;    private OrientationSensorListener listener;    private Sensor sensor;    private SensorManager sm1;    private Sensor sensor1;    private OrientationSensorListener1 listener1;    /**     * 返回ScreenSwitchUtils单例     **/    public static ScreenSwitchUtils init(Context context) {        if (mInstance == null) {            synchronized (ScreenSwitchUtils.class) {                if (mInstance == null) {                    mInstance = new ScreenSwitchUtils(context);                }            }        }        return mInstance;    }    private ScreenSwitchUtils(Context context) {        Log.d(TAG, "初始化监听");        // 注册重力感应器,监听屏幕旋转        sm = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);        if (sm != null) {            sensor = sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);        }        //当前倾斜角度赋值        @SuppressLint("HandlerLeak")        Handler mHandler = new Handler() {            public void handleMessage(Message msg) {                switch (msg.what) {                    case 888:                        int orientation = msg.arg1;                        mOrientation = orientation;//当前倾斜角度赋值                        if (orientation > 45 && orientation < 135) {                            if (isPortrait) {                                isPortrait = false;                                Log.w("test", "切换成横屏 当前角度:" + getOrientation() + " 是否竖屏:" + isPortrait());                            }                        } else if (orientation > 135 && orientation < 225) {                            if (!isPortrait) {                                isPortrait = true;                                Log.e("test", "切换成竖屏 当前角度:" + getOrientation() + " 是否竖屏:" + isPortrait());                            }                        } else if (orientation > 225 && orientation < 315) {                            if (isPortrait) {                                isPortrait = false;                                Log.w("test", "切换成横屏 当前角度:" + getOrientation() + " 是否竖屏:" + isPortrait());                            }                        } else if ((orientation > 315 && orientation < 360) || (orientation > 0 && orientation < 45)) {                            if (!isPortrait) {                                isPortrait = true;                                Log.e("test", "切换成竖屏 当前角度:" + getOrientation() + " 是否竖屏:" + isPortrait());                            }                        }                        break;                    default:                        break;                }            }        };        listener = new OrientationSensorListener(mHandler);        // 根据 旋转之后/点击全屏之后 两者方向一致,激活sm.        sm1 = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);        if (sm1 != null) {            sensor1 = sm1.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);        }        listener1 = new OrientationSensorListener1();    }    public void start(Activity activity) {        Log.d(TAG, "开始监听");        mActivity = activity;        sm.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_UI);    }    public void stop() {        Log.d(TAG, "停止监听");        sm.unregisterListener(listener);        sm1.unregisterListener(listener1);    }    /**     * 手动横竖屏切换方向     */    public void toggleScreen() {        sm.unregisterListener(listener);        sm1.registerListener(listener1, sensor1, SensorManager.SENSOR_DELAY_UI);        if (isPortrait) {            isPortrait = false;            // 切换成横屏            mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);        } else {            isPortrait = true;            // 切换成竖屏            mActivity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);        }    }    /*当前是否竖屏*/    public boolean isPortrait() {        return this.isPortrait;    }    /**     * 重力感应监听者     */    public class OrientationSensorListener implements SensorEventListener {        private static final int _DATA_X = 0;        private static final int _DATA_Y = 1;        private static final int _DATA_Z = 2;        public static final int ORIENTATION_UNKNOWN = -1;        private Handler rotateHandler;        public OrientationSensorListener(Handler handler) {            rotateHandler = handler;        }        public void onAccuracyChanged(Sensor arg0, int arg1) {        }        public void onSensorChanged(SensorEvent event) {            float[] values = event.values;            int orientation = ORIENTATION_UNKNOWN;            float X = -values[_DATA_X];            float Y = -values[_DATA_Y];            float Z = -values[_DATA_Z];            float magnitude = X * X + Y * Y;            // Don't trust the angle if the magnitude is small compared to the y            // value            if (magnitude * 4 >= Z * Z) {                // 屏幕旋转时                float OneEightyOverPi = 57.29577957855f;                float angle = (float) Math.atan2(-Y, X) * OneEightyOverPi;                orientation = 90 - Math.round(angle);                // normalize to 0 - 359 range                while (orientation >= 360) {                    orientation -= 360;                }                while (orientation < 0) {                    orientation += 360;                }            }            if (rotateHandler != null) {                rotateHandler.obtainMessage(888, orientation, 0).sendToTarget();            }        }    }    public class OrientationSensorListener1 implements SensorEventListener {        private static final int _DATA_X = 0;        private static final int _DATA_Y = 1;        private static final int _DATA_Z = 2;        public static final int ORIENTATION_UNKNOWN = -1;        public OrientationSensorListener1() {        }        public void onAccuracyChanged(Sensor arg0, int arg1) {        }        public void onSensorChanged(SensorEvent event) {            float[] values = event.values;            int orientation = ORIENTATION_UNKNOWN;            float X = -values[_DATA_X];            float Y = -values[_DATA_Y];            float Z = -values[_DATA_Z];            float magnitude = X * X + Y * Y;            //如果幅度比y值小,则不要相信角度            if (magnitude * 4 >= Z * Z) {                // 屏幕旋转时                float OneEightyOverPi = 57.29577957855f;                float angle = (float) Math.atan2(-Y, X) * OneEightyOverPi;                orientation = 90 - Math.round(angle);                // normalize to 0 - 359 range                while (orientation >= 360) {                    orientation -= 360;                }                while (orientation < 0) {                    orientation += 360;                }            }            if (orientation > 225 && orientation < 315) {// 检测到当前实际是横屏                if (!isPortrait) {                    sm.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_UI);                    sm1.unregisterListener(listener1);                }            } else if ((orientation > 315 && orientation < 360) || (orientation > 0 && orientation < 45)) {// 检测到当前实际是竖屏                if (isPortrait) {                    sm.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_UI);                    sm1.unregisterListener(listener1);                }            }        }    }    /*返回当前角度*/    public int getOrientation() {        return mOrientation;    }}

 

 

转载地址:https://blog.csdn.net/xxdw1992/article/details/109449461 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:安卓调用科大讯飞语音
下一篇:安卓so包常见报错问题

发表评论

最新留言

表示我来过!
[***.240.166.169]2024年04月21日 12时35分38秒