前两个月项目要求不能调用系统的相机,那就只能用自定义的了,查了一些资料,自己再研究了一下,自定义的相机还是有点复杂的,布局和代码中都要用到一个重要的SurfaceView。
一、建立布局,布局的背景框可以让美工给出,这里姑且就是一个蓝色的边框,然后下面有三个按钮,我里布局文件activity_custom_camera.xml
效果图:左边是取消,右边的按钮当点击拍照按钮后才会出来
二、在Activity中实现SurfaceView和拍照,这里给出相机的主要代码,初始化View就省略了。
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setBaseContentLayoutWithoutTitle(R.layout.activity_custom_camera);
//初始化相机
initCamera();
//初始化照片存储路径
getFileSavePath();
}
方法initCamera():
SurfaceHolder holder;
private void initCamera(){
surfaceview.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if(!status && camera != null){
camera.autoFocus(autoFocusCallback);
}
return false;
}
});
MySurfaceCallback mySurfaceCallback = new MySurfaceCallback();
holder = surfaceview.getHolder();
holder.setKeepScreenOn(true);// 屏幕常亮
holder.addCallback(mySurfaceCallback);
holder.lockCanvas();
}
class MySurfaceCallback implements SurfaceHolder.Callback {
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
initCameraParamsAndOpen();
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
//当surface的格式或大小发生改变,这个方法就被调用,或者View被隐藏
status = false;
btnTakePhoto.setVisibility(View.VISIBLE); //拍照按钮显示
btnFinish.setVisibility(View.GONE); //拍照完成按钮隐藏
camera.release();
camera = null;
initCameraParamsAndOpen(); //重新初始化相机
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
if (camera != null) {
camera.stopPreview();
camera.release();
camera = null;
}
}
}
private void initCameraParamsAndOpen(){
try {
// surfaceview创建之后,就去打开相机
camera = getCameraInstance();
camera.setPreviewDisplay(holder);
camera.setDisplayOrientation(90);
updateCameraParameters();
camera.startPreview();
} catch (Exception e) {
if(camera != null){
camera.release();
}
e.printStackTrace();
}
}
private void updateCameraParameters() {
if (camera != null) {
Camera.Parameters mParameters = camera.getParameters();
Camera.Size picSize = mParameters.getPreviewSize();
Camera.Size previewSize = getOptimalPreviewSize(mParameters.getSupportedPreviewSizes(), (double) picSize.width / picSize.height);
if (previewSize != null) {
mParameters.setPreviewSize(previewSize.width, previewSize.height);
}
picSize = mParameters.getPictureSize();
Camera.Size pictureSize = getOptimalPictureSize(mParameters.getSupportedPictureSizes(), (double) picSize.width / picSize.height);
if (pictureSize != null) {
mParameters.setPictureSize(pictureSize.width, pictureSize.height);
}
mParameters.setRotation(90);//防止保存的图片旋转
camera.setParameters(mParameters);
}
}
public static Camera getCameraInstance(){
Camera c = null;
try {
c = Camera.open(0); // attempt to get a Camera instance
}
catch (Exception e){
// Camera is not available (in use or does not exist)
}
return c; // returns null if camera is unavailable }
/** * 设定的屏幕的比例不是图片的比例 *@date 创建时间 2017/4/15 *@author *@company *@name:zhongshuiping *@Description 匹配分辨率 */ private Camera.Size getOptimalPreviewSize(List sizes, double targetRatio) { if (sizes == null) return null; Camera.Size optimalSize = null; Collections.sort(sizes, new Comparator() { @Override public int compare(Camera.Size lhs, Camera.Size rhs) { return new Double(lhs.width).compareTo(new Double(rhs.width)); } }); for (int i=sizes.size()-1;i>=0;i--) { Camera.Size size = sizes.get(i); if ((( Constants.EIGHT_HUNDRED < size.width && size.width < Constants.TWO_THOUSAND) || (Constants.EIGHT_HUNDRED< size.height && size.height < Constants.TWO_THOUSAND)) && ((size.width * 9) == (size.height * 16) )) { optimalSize = size; break; } } return optimalSize; }
/** * 设置的是拍照的图片的比例 *@date 创建时间 2017/4/15 *@author *@company *@name:zhongshuiping *@Description 匹配分辨率 */ private Camera.Size getOptimalPictureSize(List sizes, double targetRatio) { if (sizes == null) return null; Camera.Size optimalSize = null; Collections.sort(sizes, new Comparator() { @Override public int compare(Camera.Size lhs, Camera.Size rhs) { return new Double(lhs.width).compareTo(new Double(rhs.width)); } }); for (int i=sizes.size()-1;i>=0;i--) { Camera.Size size = sizes.get(i); if (((Constants.NUMBER_ONE_THOUSAN < size.width && size.width < Constants.NUMBER_TWO_THOUSAND) || (Constants.NUMBER_ONE_THOUSAN < size.height && size.height < Constants.NUMBER_TWO_THOUSAND)) && ((size.width * 10) ==(size.height * 16) )) { optimalSize = size; break; } } /**如果没找到16/9的就选择最接近的*/ if(optimalSize == null) { double dMin = 100.0; Camera.Size RightSize = null; for (Camera.Size size : sizes) { double fRate = size.width/(float)size.height; double fDistance = Math.abs(fRate - 16.0/10); //找最接近16比9的size; if(fDistance < dMin) { dMin = fDistance; RightSize = size; } } //最接近的值赋给变量optimalSize optimalSize = RightSize; } return optimalSize; }
Camera.AutoFocusCallback autoFocusCallback = new Camera.AutoFocusCallback() { @Override public void onAutoFocus(boolean b, Camera camera) {
} } ;
存储路径getFileSavePath(), File tempFile为拍照预留的存储位置文件,最后拍照完毕将会把照片流写入该文件中。
private File mediaStorageDir;
private void getFileSavePath(){
try
{
mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "test");
} catch (Exception e) {
e.printStackTrace();
showShortToastCenter("创建test失败");
LogUtils.LogError("lenita", "Error in Creating mediaStorageDir: " + mediaStorageDir);
}
if (!mediaStorageDir.exists())
{
if (!mediaStorageDir.mkdirs())
{
// 在SD卡上创建文件夹需要权限:
//
showShortToastCenter("创建test失败");
LogUtils.LogError("lenita", "failed to create directory, check if you have the WRITE_EXTERNAL_STORAGE permission");
}
}
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
.format(new Date());
tempFile = new File(mediaStorageDir.getPath() + File.separator
+ "IMG_" + timeStamp + ".jpg");
}
相机调用,点击btnTakePhoto按钮(R.id.btn_take_photo),此处对拍照后的图片进行压缩,免得太大导致上传服务器出错:
//点击拍照
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_take_photo:
if(camera != null){
camera.takePicture(null, null, myPictureCallback);
status = true;
btnTakePhoto.setVisibility(View.GONE);
btnFinish.setVisibility(View.VISIBLE);
}else {
showShortToastCenter("请重新拍摄");
status = false;
btnTakePhoto.setVisibility(View.VISIBLE);
btnFinish.setVisibility(View.GONE);
camera.release();
camera = null;
initCameraParamsAndOpen();
}
break;
case R.id.btn_finish: //点击完成,进行图片的上传,上传到服务器代码省略
if(tempBitmap == null || tempFile == null){
showShortToastCenter("拍照失败,请重新拍摄");
status = false;
btnFinish.setVisibility(View.GONE);
btnTakePhoto.setVisibility(View.VISIBLE);
camera.release();
camera = null;
initCameraParamsAndOpen();
return;
}
LogUtils.LogError("lenita","tempFile path = "+tempFile.getPath());
formatFile(); //TODO 压缩查看
//上传到服务器的代码省略。。。File tempFile为图片转换成的文件流
break;
}
}
private File mImageFile;
private void formatFile(){
try {
//当大于2MB时用到
String lRealFilePath = tempFile.getPath();
String stringAll[] = lRealFilePath.split("\\.");
int length = stringAll.length;
String imageSuffix = stringAll[length - 1];
String string[] = lRealFilePath.split("\\."+imageSuffix);
String newFileSavePath = string[0] + "_compress.jpg";
long fileLong = FileSizeUtil.getFileSize(tempFile);
String fileString = FileSizeUtil.formatFileSizeUnder2MB(fileLong);
if (TextUtils.isEmpty(fileString)) { //TODO 证明是大于2MB的,要进行压缩
Toast.Long(this,"正在压缩图片,请稍等片刻...");
compressImageUtilbelow2MB(lRealFilePath,newFileSavePath);
//压缩后替换要上传的路径
lRealFilePath = newFileSavePath;
mImageFile = new File(lRealFilePath);
tempFile = mImageFile;
}
}catch (Exception e) {
Log.e("lenita","e e = "+e.toString());
}
}
private void compressImageUtilbelow2MB(String filePath,String newFilePath){
//TODO 大于2MB的进行压缩
ImageFactory imageFactory = new ImageFactory();
try {
imageFactory.compressAndGenImage(filePath,newFilePath,1024,false);
} catch (IOException e) {
e.printStackTrace();
}
}
Camera.PictureCallback myPictureCallback = new Camera.PictureCallback(){
@Override
public void onPictureTaken(byte[] data, Camera camera) {
LogUtils.LogError("lenita"," onPictureTaken");
//卡住预览页面,让用户看
camera.stopPreview();
//保存图片
tempBitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
saveBitmap(tempBitmap);
}
};
public void saveBitmap(Bitmap bitmap) {
if(tempFile != null){
try {
FileOutputStream out = new FileOutputStream(tempFile);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
out.flush();
out.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
LogUtils.LogError("lenita","saveBitmap e = "+e);
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
LogUtils.LogError("lenita","saveBitmap e = "+e);
e.printStackTrace();
}
}else {
LogUtils.LogError("lenita","tempFile == null");
}
}
以上就是拍照的相关的代码,这里要注意的是,拍照之后最好调用camera.stopPreview();这个方法,否则有些手机会一直在preview,导致无法定在当前的拍照中,当然,如果你是想拍照完直接存下,而不要定下来查看的话,就不需要camera.stopPreview();来定住画面了,效果图如下所示:
保存的文件就会在Picture/test文件夹下,图片如下图:
最后给个参考文章,还是值得借鉴一下的:
http://blog.csdn.net/ming_csdn_/article/details/70154381