代码需要权限如下:
我的另一篇博客已经写到
调用手机相机拍照并返回图片
其中主要的代码就是:
//调用系统相机,拍照
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
//在onActivityResult()处理
startActivityForResult(intent , 1);
public class MyCameraActivity extends AppCompatActivity implements SurfaceHolder.Callback, android.hardware.Camera.AutoFocusCallback {
SurfaceView mySurfaceView;
SurfaceHolder holder;
android.hardware.Camera myCamera;
//照片保存路径
String filePath = null;
//拍照按钮
Button capture;
//照片缩略图
ImageView editPic;
Context mContext;
MyOrientoinListener myOrientoinListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_my_camera);
mySurfaceView = (SurfaceView) findViewById(R.id.camera_view);
holder = mySurfaceView.getHolder();
//回调
holder.addCallback(this);
mContext = this;
//设置类型,没有这句将调用失败
//当在Canvas中绘制完成后,调用函数unlockCanvasAndPost(Canvas canvas)来通知系统Surface已经绘制完成,
// 这样系统会把绘制完的内容显示出来。为了充分利用不同平台的资源,发挥平台的最优效果可以通过SurfaceHolder的setType函数来设置绘制的类型,
// 目前接收如下的参数:
//SURFACE_TYPE_NORMAL:用RAM缓存原生数据的普通Surface
//SURFACE_TYPE_HARDWARE:适用于DMA(Direct memory access )引擎和硬件加速的Surface
//SURFACE_TYPE_GPU:适用于GPU加速的Surface
//SURFACE_TYPE_PUSH_BUFFERS:表明该Surface不包含原生数据,Surface用到的数据由其他对象提供,
// 在Camera图像预览中就使用该类型的Surface,有Camera负责提供给预览Surface数据,这样图像预览会比较流畅。
// 如果设置这种类型则就不能调用lockCanvas来获取Canvas对象了
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
capture = (Button) findViewById(R.id.takeP);
editPic = (ImageView) findViewById(R.id.p_view);
//监听
capture.setOnClickListener(takePicture);
}
View.OnClickListener takePicture = new View.OnClickListener() {
@Override
public void onClick(View v) {
//自动对焦 并回调
myCamera.autoFocus(MyCameraActivity.this);
}
};
@Override
public void surfaceCreated(SurfaceHolder holder) {
if (myCamera == null) {
//得到相机实例
myCamera = android.hardware.Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);
try {
//相机预览传入surfaceholder
myCamera.setPreviewDisplay(holder);
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.i("TAG", "change");
//设置预览方向顺时针旋转90 ,摄像头预览方向与实际相差90度
myCamera.setDisplayOrientation(90);
//开始预览
myCamera.startPreview();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
//关闭预览并释放资源
myCamera.stopPreview();
myCamera.release();
myCamera = null;
}
@Override
public void onAutoFocus(boolean success, android.hardware.Camera camera) {
if (success) {
//设置相机参数
android.hardware.Camera.Parameters params = myCamera.getParameters();
params.setPictureFormat(PixelFormat.JPEG);
myCamera.setParameters(params);
//拍照 产生三个回调对应 (原始图像 压缩图 jpeg图) 这里只回调了jpeg图
myCamera.takePicture(null, null, jpeg);
}
}
android.hardware.Camera.PictureCallback jpeg = new android.hardware.Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, android.hardware.Camera camera) {
try {
//获得图片
Bitmap bm = BitmapFactory.decodeByteArray(data, 0, data.length);
SimpleDateFormat sDateFormate = new SimpleDateFormat("yyyyMMddHHmmss");
String date = sDateFormate.format(new Date());
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
Toast.makeText(mContext, "SD卡不可用", Toast.LENGTH_SHORT).show();
} else {
filePath = Environment.getExternalStorageDirectory().getAbsolutePath();
filePath = filePath + "/" + date + ".jpg";
}
File file = new File(filePath);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
//创建操作图片用的matrix
Matrix matrix = new Matrix();
//图片方向与实际相差270,所以在保存到bos之前将图片顺时针旋转270度
matrix.postRotate(270);
//创建新图片
Bitmap rotateBitmap = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true);
//将图片以jpeg格式压缩到流中
rotateBitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);
//输出
bos.flush();
//关闭
bos.close();
//显示缩略图
editPic.setBackgroundDrawable(changeBitmapToDrawable(rotateBitmap));
//缩略图点击时得到路径参数
editPic.setTag(filePath);
} catch (Exception e) {
e.printStackTrace();
}
//takePiture会停止预览,我们要重新开启预览
myCamera.startPreview();
}
};
private Drawable changeBitmapToDrawable(Bitmap bitmapOrg) {
int width = bitmapOrg.getWidth();
int height = bitmapOrg.getHeight();
//定义要转换成的图片的宽和高
int newWidth = 100;
//计算缩放率,新尺寸除以旧尺寸
float scaleWidth = (float) newWidth / width;
float scaleHeight = scaleWidth;
//创建操作图片用的matrix
Matrix matrix = new Matrix();
//缩放图片动作
matrix.postScale(scaleWidth, scaleHeight);
//创建新图片
Bitmap resizeBitmap = Bitmap.createBitmap(bitmapOrg, 0, 0, width, height, matrix, true);
//将Bitmap转换为Drawable
BitmapDrawable bitmapDrawable = new BitmapDrawable(resizeBitmap);
return bitmapDrawable;
}
}
对于简单的预览拍照,上面两种方式已经实现。
要想获取屏幕方向,需要在AndroidManifest.xml文件中,对某个Activity加入如下的设置:
然后还需要手机开启自动旋转的设置。
以上准备工作做好,我们接下来有两种方式实现横竖屏的切换:
//onConfigurationChanged
public void onConfigurationChanged(Configuration newConfig){
super.onConfigurationChanged(newConfig);
if(newConfig.orientation==Configuration.ORIENTATION_LANDSCAPE){
// Nothing need to be done here
Log.i("TAG","横屏");
//处理代码
} else {
// Nothing need to be done here
Log.i("TAG","竖屏");
//处理代码
}
}
由于屏幕方向自动旋转了,所以Activity自动旋转了,Camera也旋转了,不需要你手动旋转Camera。
不过如果旋转之后的 Camera方向不对,可以手动修改Camera的方向。myCamera.setDisplayOrientation(角度);
public class MyCameraActivity extends AppCompatActivity implements SurfaceHolder.Callback, android.hardware.Camera.AutoFocusCallback {
...
MyOrientoinListener myOrientoinListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_my_camera);
...
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
capture = (Button) findViewById(R.id.takeP);
editPic = (ImageView) findViewById(R.id.p_view);
capture.setOnClickListener(takePicture);
//第二种方式,监听屏幕旋转
myOrientoinListener = new MyOrientoinListener(this);
boolean autoRotateOn = (android.provider.Settings.System.getInt(getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 0) == 1);
//检查系统是否开启自动旋转
if (autoRotateOn) {
myOrientoinListener.enable();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
//销毁时取消监听
if (myOrientoinListener != null) {
myOrientoinListener.disable();
}
}
...
...
...
...
class MyOrientoinListener extends OrientationEventListener {
private Context context;
public MyOrientoinListener(Context context) {
super(context);
this.context = context;
}
@Override
public void onOrientationChanged(int orientation) {
Log.i("TAG", "orention" + orientation);
int screenOrientation = context.getResources().getConfiguration().orientation;
if (((orientation >= 0) && (orientation < 45)) || (orientation > 315)) {//设置竖屏
if (screenOrientation != ActivityInfo.SCREEN_ORIENTATION_PORTRAIT && orientation != ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT) {
Log.i("TAG", "设置竖屏");
myCamera.setDisplayOrientation(0);
}
} else if (orientation > 225 && orientation < 315) { //设置横屏
Log.i("TAG", "设置横屏");
if (screenOrientation != ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) {
myCamera.setDisplayOrientation(90);
}
} else if (orientation > 45 && orientation < 135) {// 设置反向横屏
Log.i("TAG", "反向横屏");
if (screenOrientation != ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE) {
myCamera.setDisplayOrientation(180);
}
} else if (orientation > 135 && orientation < 225) {
Log.i("TAG", "反向竖屏");
if (screenOrientation != ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT) {
myCamera.setDisplayOrientation(270);
}
}
}
}
}
在旋转角度oritention达到一定值的时候,上面代码中,我们手动的旋转了Camera的方向,如有90,180,270度的。
对于横屏,竖屏,到底需要需要旋转多少角度,上面我旋转的角度可能不对,你们自行修改。
还有就是在onDestroy()方法中要记得停止监听。