通过安卓自带的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);
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();
}
}
};
}
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;
}
}