Android 实现无预览拍照功能
Android 实现无预览拍照功能
1.权限
需要相机、读写文件、悬浮窗权限
申请相机、读写文件
manifest.xml
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
相机、读写文件权限需要动态申请
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE}, 101);
悬浮窗权限
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW" />
需要申请
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.canDrawOverlays(this)) {
startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())), 0);
} else {
//TODO do something you need
}
}
2.布局与使用
布局
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".test1.Main2Activity">
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="拍照"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
使用
主要参数
Camera camera;
WindowManager wm;
SurfaceView preview;
String path = Environment.getExternalStorageDirectory().getAbsolutePath();
File fileTest = new File(path + "/test.jpg");
然后调用
public void onTakePhotoClicked() {
preview = new SurfaceView(this);
SurfaceHolder holder = preview.getHolder();
// deprecated setting, but required on Android versions prior to 3.0
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
holder.addCallback(new SurfaceHolder.Callback() {
@Override
//The preview must happen at or after this point or takePicture fails
public void surfaceCreated(SurfaceHolder holder) {
Log.d("zcf", "Surface created");
camera = null;
try {
camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
Log.d("zcf", "Opened camera");
try {
camera.setPreviewDisplay(holder);
} catch (IOException e) {
throw new RuntimeException(e);
}
camera.startPreview();
Log.d("zcf", "Started preview");
Log.e("zcf","开始拍照");
camera.takePicture(null, null, TestActivity.this);
} catch (Exception e) {
if (camera != null)
camera.release();
throw new RuntimeException(e);
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
});
wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
WindowManager.LayoutParams params = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
params = new WindowManager.LayoutParams(
1, 1, //Must be at least 1x1
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
0,
//Don't know if this is a safe default
PixelFormat.UNKNOWN);
}
//Don't set the preview visibility to GONE or INVISIBLE
wm.addView(preview, params);
}
@Override
public void onPictureTaken(byte[] bytes, Camera camera) {
Log.e("zcf", "拍照结束");
try {
FileOutputStream fos = new FileOutputStream(fileAdvert);
fos.write(bytes);
fos.close();
Log.e("zcf","保存结束");
Message message = handler.obtainMessage();
message.what = 1;
handler.sendEmptyMessageDelayed(1,1500);
} catch (FileNotFoundException e) {
Log.d("zcf", "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d("zcf", "Error accessing file: " + e.getMessage());
}
}
拍照结束需要把wm给remove掉,要不还是会挡着下边的东西。
3.完整代码
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.provider.Settings;
import android.util.Log;
import android.view.OrientationEventListener;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import com.arcsoft.face.FaceEngine;
import com.arcsoft.face.FaceFeature;
import com.arcsoft.face.FaceInfo;
import com.arcsoft.face.enums.DetectMode;
import com.arcsoft.face.enums.DetectModel;
import com.zg.massagerobot.R;
import com.zg.massagerobot.base.BaseActivity;
import com.zg.massagerobot.faceserver.CompareResult;
import com.zg.massagerobot.faceserver.FaceServer;
import com.zg.massagerobot.utils.ConfigUtil;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
public class Main2Activity extends BaseActivity implements Camera.PictureCallback {
Button button;
Camera camera;
WindowManager wm;
SurfaceView preview;
String path = Environment.getExternalStorageDirectory().getAbsolutePath();
File fileTest = new File(path + "/test.jpg");
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE}, 101);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.canDrawOverlays(this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivityForResult(intent, 1);
} else {
//TODO do something you need
}
}
FaceServer.getInstance().init(this);
initOrientate();
button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onTakePhotoClicked();
}
});
}
@SuppressLint("HandlerLeak")
private Handler handler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 1:
wm.removeViewImmediate(preview);
break;
}
}
};
public void onTakePhotoClicked() {
preview = new SurfaceView(this);
SurfaceHolder holder = preview.getHolder();
// deprecated setting, but required on Android versions prior to 3.0
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
holder.addCallback(new SurfaceHolder.Callback() {
@Override
//The preview must happen at or after this point or takePicture fails
public void surfaceCreated(SurfaceHolder holder) {
Log.d("zcf", "Surface created");
camera = null;
try {
camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);
Log.d("zcf", "Opened camera");
try {
camera.setPreviewDisplay(holder);
} catch (IOException e) {
throw new RuntimeException(e);
}
camera.startPreview();
Log.d("zcf", "Started preview");
Log.e("zcf", "开始拍照");
camera.takePicture(null, null, Main2Activity.this);
} catch (Exception e) {
if (camera != null)
camera.release();
throw new RuntimeException(e);
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
});
wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
WindowManager.LayoutParams params = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
params = new WindowManager.LayoutParams(
1, 1, //Must be at least 1x1
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
0,
//Don't know if this is a safe default
PixelFormat.UNKNOWN);
}
//Don't set the preview visibility to GONE or INVISIBLE
wm.addView(preview, params);
}
@Override
public void onPictureTaken(byte[] bytes, Camera camera) {
/*Log.e("zcf", "拍照结束");
try {
//图片需要向右旋转90度,然后提取特征比较
FileOutputStream fos = new FileOutputStream(fileTest);
fos.write(bytes);
fos.close();
Log.e("zcf", "保存结束");
Message message = handler.obtainMessage();
message.what = 1;
handler.sendEmptyMessageDelayed(1, 1500);
} catch (FileNotFoundException e) {
Log.d("zcf", "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d("zcf", "Error accessing file: " + e.getMessage());
}*/
Log.e("zcf", "拍照结束");
//图片需要向右旋转90度,然后提取特征比较
getPhotoPath(bytes, takePhotoOrientation);
}
@Override
protected void onDestroy() {
super.onDestroy();
}
private ExecutorService threadPool = Executors.newCachedThreadPool();
/**
* @return 返回路径
*/
private void getPhotoPath(final byte[] data, final int takePhotoOrientation) {
threadPool.execute(new Runnable() {
@Override
public void run() {
try {
FileOutputStream fos = new FileOutputStream(fileTest);
try {
//将数据写入文件
fos.write(data);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//将图片旋转
rotateImageView(Camera.CameraInfo.CAMERA_FACING_FRONT, takePhotoOrientation, fileTest.getAbsolutePath());
} catch (FileNotFoundException e) {
e.printStackTrace();
}
Log.e("zcf", "保存结束");
Message message = handler.obtainMessage();
message.what = 1;
handler.sendEmptyMessageDelayed(1, 1500);
}
});
}
/**
* 旋转图片
*
* @param cameraId 前置还是后置
* @param orientation 拍照时传感器方向
* @param path 图片路径
*/
private void rotateImageView(int cameraId, int orientation, String path) {
Bitmap bitmap = BitmapFactory.decodeFile(path);
Matrix matrix = new Matrix();
matrix.postRotate(Float.valueOf(orientation));
// 创建新的图片
Bitmap resizedBitmap;
if (cameraId == 1) {
if (orientation == 90) {
matrix.postRotate(180f);
}
}
// 创建新的图片
resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0,
bitmap.getWidth(), bitmap.getHeight(), matrix, true);
//新增 如果是前置 需要镜面翻转处理
if (cameraId == 1) {
Matrix matrix1 = new Matrix();
matrix1.postScale(-1f, 1f);
resizedBitmap = Bitmap.createBitmap(resizedBitmap, 0, 0,
resizedBitmap.getWidth(), resizedBitmap.getHeight(), matrix1, true);
}
File file = new File(path);
//重新写入文件
try {
// 写入文件
FileOutputStream fos;
fos = new FileOutputStream(file);
//默认jpg
resizedBitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.flush();
fos.close();
resizedBitmap.recycle();
} catch (Exception e) {
e.printStackTrace();
return;
}
}
//增加传感器
private OrientationEventListener mOrientationEventListener;
//当前角度
private float mCurrentOrientation = 0f;
//拍照时的传感器方向
private int takePhotoOrientation = 0;
/**
* 初始化传感器方向
*/
private void initOrientate() {
if (mOrientationEventListener == null) {
mOrientationEventListener = new OrientationEventListener(this) {
@Override
public void onOrientationChanged(int orientation) {
// i的范围是0-359
// 屏幕左边在顶部的时候 i = 90;
// 屏幕顶部在底部的时候 i = 180;
// 屏幕右边在底部的时候 i = 270;
// 正常的情况默认i = 0;
if (45 <= orientation && orientation < 135) {
takePhotoOrientation = 180;
mCurrentOrientation = -180;
} else if (135 <= orientation && orientation < 225) {
takePhotoOrientation = 270;
mCurrentOrientation = 90;
} else if (225 <= orientation && orientation < 315) {
takePhotoOrientation = 0;
mCurrentOrientation = 0;
} else {
takePhotoOrientation = 90;
mCurrentOrientation = -90;
}
}
};
}
mOrientationEventListener.enable();
}
}
还没有评论,来说两句吧...