package com.camnter.newlife.utils.camera;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.ImageFormat;
import android.hardware.Camera;
import android.os.Build;
import android.support.annotation.DrawableRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import com.camnter.newlife.utils.BitmapUtils;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* Description:CameraManager
* Created by:CaMnter
*/
public final class CameraManager {
/*******************************
* 输出格式尽量保持 1280 x 720 *
*******************************/
public static final int PICTURE_OUTPUT_WIDTH = 1280;
public static final int PICTURE_OUTPUT_HEIGHT = 720;
private static final String TAG = CameraManager.class.getSimpleName();
// 1kb
private static final int ONE_KB = 1024;
private static final int ONE_MB = ONE_KB * 1024;
private static final int REQUEST_CAMERA_ID = -1;
private static final int ID_CARD_EXPECT_HEIGHT = 720;
private volatile static CameraManager instance = null;
private final Comparator<Camera.Size> sizeComparator = new Comparator<Camera.Size>() {
@Override
public int compare(Camera.Size lhs, Camera.Size rhs) {
if (lhs.width > rhs.width) {
return -1;
} else if (lhs.width == rhs.width) {
return 0;
} else {
// lhs.width < rhs.width
return 1;
}
}
};
private Camera camera;
private int cameraId;
private Camera.Parameters cameraParameters;
private AutoFocusManager autoFocusManager;
private boolean isPreviewing = false;
private CameraManager() {
}
public static CameraManager getInstance() {
CameraManager inst = instance;
if (inst == null) {
synchronized (CameraManager.class) {
inst = instance;
if (inst == null) {
inst = new CameraManager();
instance = inst;
}
}
}
return inst;
}
public synchronized boolean isCameraCanUse() {
boolean canUse = true;
Camera mCamera = null;
try {
mCamera = Camera.open();
} catch (Exception e) {
canUse = false;
}
if (canUse) {
try {
mCamera.release();
} catch (Exception e) {
} finally {
mCamera = null;
}
}
return canUse;
}
/**
* 打开 Camera
*
* @param surfaceHolder surfaceHolder
* @throws Exception e
*/
public synchronized void openCamera(@NonNull final Activity activity,
@NonNull final SurfaceHolder surfaceHolder,
final int surfaceViewWidth,
final int surfaceViewHeight) throws Exception {
Log.i(TAG, "[openCamera]:......");
Camera cameraTemp = this.camera;
if (cameraTemp == null) {
cameraTemp = this.obtainCamera(REQUEST_CAMERA_ID);
if (cameraTemp == null) {
throw new Exception(TAG + "\t\t\t[openCamera]\t\t\t camera == null ");
}
this.camera = cameraTemp;
}
this.adjustCamera(activity, this.cameraId);
this.camera.setPreviewDisplay(surfaceHolder);
this.cameraParameters = this.camera.getParameters();
this.cameraParameters.setPictureFormat(ImageFormat.JPEG);
this.cameraParameters.setJpegQuality(100);
// set previewSize
final Camera.Size suitablePreviewSize = this.getSuitablePreviewSizeForSurfaceView(
this.camera, surfaceViewWidth, surfaceViewHeight);
this.cameraParameters.setPreviewSize(suitablePreviewSize.width, suitablePreviewSize.height);
// set pictureSize
final Camera.Size suitablePictureSize = this.getPictureSizeByPreviewSize(this.camera,
suitablePreviewSize);
this.cameraParameters.setPictureSize(suitablePictureSize.width, suitablePictureSize.height);
final Camera.Size previewSize = this.cameraParameters.getPreviewSize();
final Camera.Size pictureSize = this.cameraParameters.getPictureSize();
Log.d(TAG,
"CameraParameters >>>>>> PreviewSize >>>>> width=" + previewSize.width + " height=" +
previewSize.height);
Log.d(TAG,
"CameraParameters >>>>>> PictureSize >>>>> width=" + pictureSize.width + " height=" +
pictureSize.height);
this.camera.setParameters(this.cameraParameters);
}
private Camera.Size getSuitablePreviewSizeForSurfaceView(@NonNull Camera camera,
int surfaceViewWidth,
int surfaceViewHeight) {
final Camera.Parameters parameters = camera.getParameters();
List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes();
// 因为 SurfaceView 旋转了 90度
final float targetRatio = (float) surfaceViewHeight / (float) surfaceViewWidth;
float minDiff = Float.MAX_VALUE;
Camera.Size suitableSize = null;
for (Camera.Size previewSize : previewSizes) {
final float previewWidth = previewSize.width;
final float previewHeight = previewSize.height;
final float diff = Math.abs(targetRatio - (previewWidth / previewHeight));
if (diff < minDiff && previewWidth > 1000) {
minDiff = diff;
suitableSize = previewSize;
}
}
return suitableSize;
}
private Camera.Size getPictureSizeByPreviewSize(
@NonNull Camera camera, @NonNull final Camera.Size preiviewSize) {
final Camera.Parameters parameters = camera.getParameters();
List<Camera.Size> pictureSizes = parameters.getSupportedPictureSizes();
Collections.sort(pictureSizes, sizeComparator);
// 寻找和 previewSize 相同的 pictureSize
Camera.Size expectPictureSize = null;
for (Camera.Size pictureSize : pictureSizes) {
if (pictureSize.width == preiviewSize.width &&
pictureSize.height == preiviewSize.height) {
expectPictureSize = pictureSize;
}
}
if (expectPictureSize == null) {
/**
* 寻找差不多比例的 pictureSize,但是 width > 1000 && < 2000
* > 2000 容易 OOM
*/
final float targetRatio = (float) preiviewSize.width / (float) preiviewSize.height;
float minDiff = Float.MAX_VALUE;
Camera.Size suitableSize = null;
for (Camera.Size pictureSize : pictureSizes) {
final float pictureWidth = pictureSize.width;
final float pictureHeight = pictureSize.height;
final float diff = Math.abs(targetRatio - (pictureWidth / pictureHeight));
if (diff < minDiff && pictureWidth > 1000 && pictureWidth < 2000) {
minDiff = diff;
suitableSize = pictureSize;
}
}
expectPictureSize = suitableSize;
// 实在找不到,才拿最优画质
return expectPictureSize == null ? pictureSizes.get(0) : expectPictureSize;
} else {
return expectPictureSize;
}
}
/**
* 查看了源码,没有进行排序
* 不同机型 和 系统版本会导致不同版本
* 所有这里会先进行排序
*
* 尽量优先找 1280 x 720 的
* 然后再按照一下规则找
*
* 由于是自定义相机,所以采用最好的 previewSize
* 然后为了图片查看页面和预览页面的图片一致 pictureSize 采用和 previewSize 相同尺寸
*
* @param parameters parameters
*/
private void setBestPreviewAndPictureSize(@NonNull Camera.Parameters parameters) {
final List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes();
if (previewSizes == null || previewSizes.size() == 0) return;
Collections.sort(previewSizes, sizeComparator);
/**********************
* 1280 x 720 优先逻辑 *
**********************/
// 1280 x 720
boolean foundExpectPreview = false;
for (Camera.Size previewSize : previewSizes) {
if (previewSize.width == PICTURE_OUTPUT_WIDTH &&
previewSize.height == PICTURE_OUTPUT_HEIGHT) {
foundExpectPreview = true;
}
}
if (foundExpectPreview) {
boolean foundExpectSize = false;
for (Camera.Size size : parameters.getSupportedPictureSizes()) {
if (size.width == PICTURE_OUTPUT_WIDTH && size.height == PICTURE_OUTPUT_HEIGHT) {
foundExpectSize = true;
}
}
if (foundExpectSize) {
parameters.setPreviewSize(PICTURE_OUTPUT_WIDTH, PICTURE_OUTPUT_HEIGHT);
parameters.setPictureSize(PICTURE_OUTPUT_WIDTH, PICTURE_OUTPUT_HEIGHT);
return;
}
}
/********************
* 最髙 Preview 逻辑 *
********************/
Camera.Size bestPreviewSize = previewSizes.get(0);
// preview size
parameters.setPreviewSize(bestPreviewSize.width, bestPreviewSize.height);
boolean foundPicture = false;
for (Camera.Size size : parameters.getSupportedPictureSizes()) {
if (size.width == bestPreviewSize.width && size.height == bestPreviewSize.height) {
foundPicture = true;
}
}
if (foundPicture) {
this.cameraParameters.setPictureSize(bestPreviewSize.width, bestPreviewSize.height);
} else {
final List<Camera.Size> pictureSizes = parameters.getSupportedPictureSizes();
if (pictureSizes == null || pictureSizes.size() == 0) return;
Collections.sort(pictureSizes, sizeComparator);
final Camera.Size bestPictureSize = pictureSizes.get(0);
this.cameraParameters.setPictureSize(bestPictureSize.width, bestPictureSize.height);
}
}
private void adjustCamera(@NonNull final Activity activity, int cameraId) {
if (this.camera != null) {
this.setCameraDisplayOrientation(activity, cameraId, camera);
this.camera.setDisplayOrientation(90);
}
}
/**
* Google 祖传代码
* 用于解决不同 ROM 上的相机默认显示问题
*
* @param activity activity
* @param cameraId cameraId
* @param camera camera
*/
private void setCameraDisplayOrientation(@NonNull final Activity activity,
int cameraId,
@NonNull final android.hardware.Camera camera) {
android.hardware.Camera.CameraInfo info =
new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
int rotation = activity.getWindowManager().getDefaultDisplay()
.getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;
case Surface.ROTATION_270:
degrees = 270;
break;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
camera.setDisplayOrientation(result);
}
/**
* 关闭 Camera
*/
public synchronized void closeCamera() {
Log.i(TAG, "[closeCamera]:......");
if (this.camera == null) return;
this.camera.release();
this.camera = null;
}
/**
* 打开预览
*/
public synchronized void startPreview() {
Log.i(TAG, "[startPreview]:......");
final Camera cameraTemp = this.camera;
if (cameraTemp != null && !this.isPreviewing) {
cameraTemp.startPreview();
this.isPreviewing = true;
this.autoFocusManager = new AutoFocusManager(this.camera);
}
}
public synchronized void mustPreview() {
Log.i(TAG, "[mustPreview]:......");
final Camera cameraTemp = this.camera;
if (cameraTemp == null) return;
cameraTemp.startPreview();
}
/**
* 关闭预览
*/
public synchronized void stopPreview() {
Log.i(TAG, "[stopPreview]:......");
if (this.autoFocusManager != null) {
this.autoFocusManager.stopFocus();
this.autoFocusManager = null;
}
if (this.camera != null && this.isPreviewing) {
this.camera.stopPreview();
this.isPreviewing = false;
}
}
/**
* 打开闪光灯
*/
public synchronized void openLight() {
Log.i(TAG, "[openLight]:......");
if (this.camera == null) return;
this.cameraParameters = this.camera.getParameters();
this.cameraParameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
this.camera.setParameters(this.cameraParameters);
}
/**
* 关闭闪光灯
*/
public synchronized void closeLight() {
Log.i(TAG, "[closeLight]:......");
if (this.camera == null) return;
this.cameraParameters = this.camera.getParameters();
this.cameraParameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
this.camera.setParameters(this.cameraParameters);
}
public synchronized void takePicture(@Nullable final Camera.ShutterCallback shutter,
@Nullable final Camera.PictureCallback raw,
@Nullable final Camera.PictureCallback jpeg) {
Log.i(TAG, "[takePicture]:......");
try {
this.camera.takePicture(shutter, raw, jpeg);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 是否打开 Camera
*
* @return 是否打开
*/
public synchronized boolean isOpen() {
return this.camera != null;
}
public synchronized boolean isLightOpen() {
try {
if (camera != null) {
Camera.Parameters parameter = camera.getParameters();
return parameter.getFlashMode() == Camera.Parameters.FLASH_MODE_TORCH;
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/**
* 获取 背面摄像头
*
* @param cameraId cameraId
* @return Camera
*/
private Camera obtainCamera(int cameraId) {
final int numberOfCameras = Camera.getNumberOfCameras();
if (numberOfCameras <= 0) {
Log.e(TAG, "[obtainCamera]\t\t\t the number of cameras was 0");
return null;
}
final boolean explicitRequest = cameraId >= 0;
if (!explicitRequest) {
int backFocusIndex = 0;
for (int i = 0; i < numberOfCameras; i++) {
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
Camera.getCameraInfo(i, cameraInfo);
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
backFocusIndex = i;
break;
}
}
cameraId = backFocusIndex;
}
Camera camera;
if (cameraId < numberOfCameras) {
Log.i(TAG, "[obtainCamera]\t\t\t open the camera: " + cameraId);
camera = Camera.open(cameraId);
this.cameraId = cameraId;
} else {
if (explicitRequest) {
Log.e(TAG, "[obtainCamera]\t\t\t Requested camera does not exist: " + cameraId);
camera = null;
} else {
Log.e(TAG, "[obtainCamera]\t\t\t No camera facing back; returning camera #0");
camera = Camera.open(0);
this.cameraId = 0;
}
}
return camera;
}
private int getBitmapSize(@NonNull final Bitmap bitmap) {
// API 19
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
return bitmap.getAllocationByteCount();
}
// API 12
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
return bitmap.getByteCount();
}
// earlier version
return bitmap.getRowBytes() * bitmap.getHeight();
}
/**
* 压缩图片
* 根据 height 压到 720,width 的话,根据 高度缩放比例,压到对应的宽度
*
* @param originalBitmap originalBitmap
* @return Bitmap
*/
public Bitmap compressForIdCard(@NonNull final Bitmap originalBitmap) {
if (this.getBitmapSize(originalBitmap) > ONE_MB) {
return BitmapUtils.getBitmapCompressedByHeight(originalBitmap, ID_CARD_EXPECT_HEIGHT);
} else {
return originalBitmap;
}
}
/**
* 添加 身份证水印
*
* @param context context
* @param originalBitmap originalBitmap
* @param watermarkRes watermarkRes
* @return watermarkBitmap
*/
public Bitmap addWatermarkBitmap(@NonNull final Context context,
@NonNull final Bitmap originalBitmap,
@DrawableRes final int watermarkRes) {
if (watermarkRes == 0) return originalBitmap;
final float backgroundBitmapWidth = originalBitmap.getWidth();
final float backgroundBitmapHeight = originalBitmap.getHeight();
final Bitmap backgroundBitmap = Bitmap.createBitmap((int) backgroundBitmapWidth,
(int) backgroundBitmapHeight, Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(backgroundBitmap);
// 背景
canvas.drawBitmap(originalBitmap, 0, 0, null);
final Bitmap markBitmap = BitmapFactory.decodeResource(context.getResources(),
watermarkRes);
final float markBitmapWidth = markBitmap.getWidth();
final float markBitmapHeight = markBitmap.getHeight();
final float marginTop = backgroundBitmapHeight / 2 - markBitmapHeight / 2;
final float marginLeft = backgroundBitmapWidth / 2 - markBitmapWidth / 2;
canvas.drawBitmap(markBitmap, marginLeft, marginTop, null);
canvas.save(Canvas.ALL_SAVE_FLAG);
canvas.restore();
return backgroundBitmap;
}
}