Index: ActivityCapture.java =================================================================== --- ActivityCapture.java (revision 0) ActivityCapture.java (revision 3) @@ -0,0 +1,638 @@ package com.cn.commoncamera; import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Matrix; import android.graphics.Rect; import android.hardware.Camera; import android.hardware.Camera.CameraInfo; import android.hardware.Camera.PictureCallback; import android.hardware.Camera.Size; import android.os.Bundle; import android.util.Log; import android.view.*; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.Toast; import java.io.File; import java.util.List; import com.cn.camerautils.BitmapUtil; import com.cn.camerautils.Debug; import com.cn.camerautils.PathManager; import com.cn.qsign.R; @SuppressLint("NewApi") //默认的相机为横平,所以Activity设置为横屏,拍出的照片才正确 public class ActivityCapture extends Activity implements View.OnClickListener, CaptureSensorsObserver.RefocuseListener { private ImageView bnToggleCamera; private ImageView bnCapture; private RelativeLayout layback; private FrameLayout framelayoutPreview; private CameraPreview preview; private CameraCropBorderView cropBorderView; private Camera camera; private PictureCallback pictureCallBack; private Camera.AutoFocusCallback focusCallback; private CaptureSensorsObserver observer; private View focuseView; private int currentCameraId; private int frontCameraId; private boolean _isCapturing; CaptureOrientationEventListener _orientationEventListener; private int _rotation; public static final int kPhotoMaxSaveSideLen = 1600; public static final String kPhotoPath = "photo_path"; // private ShutterCallback _shutterCallback = new ShutterCallback() { // @Override // public void onShutter() { // } // }; final static String TAG = "capture"; @Override protected void onCreate(Bundle savedInstanceState) { observer = new CaptureSensorsObserver(this); _orientationEventListener = new CaptureOrientationEventListener(this); super.onCreate(savedInstanceState); setContentView(R.layout.activity_capture); getViews(); initViews(); setListeners(); setupDevice(); } @Override protected void onDestroy() { if (null != observer) { observer.setRefocuseListener(null); observer = null; } _orientationEventListener = null; super.onDestroy(); } @Override protected void onPause() { super.onPause(); releaseCamera(); // release the camera immediately on pause event observer.stop(); _orientationEventListener.disable(); } @Override protected void onResume() { super.onResume(); //openCamera(); switchCamera(); } private void releaseCamera() { if (camera != null) { camera.release(); // release the camera for other applications camera = null; } if (null != preview) { framelayoutPreview.removeAllViews(); preview = null; } } protected void getViews() { bnToggleCamera = (ImageView) findViewById(R.id.bnToggleCamera); bnCapture = (ImageView) findViewById(R.id.bnCapture); framelayoutPreview = (FrameLayout) findViewById(R.id.cameraPreview); focuseView = findViewById(R.id.viewFocuse); layback=(RelativeLayout)findViewById(R.id.layback); } protected void initViews() { bnCapture.setRotation(-90); bnToggleCamera.setRotation(-90); } protected void setListeners() { bnToggleCamera.setOnClickListener(this); bnCapture.setOnClickListener(this); observer.setRefocuseListener(this); layback.setOnClickListener(this); pictureCallBack = new PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { _isCapturing = false; Bitmap bitmap = null; try { BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeByteArray(data, 0, data.length, options); // Debug.debug("width--:" + options.outWidth + " height--:" + options.outHeight); options.inJustDecodeBounds = false; options.inPreferredConfig = Bitmap.Config.ARGB_8888; //此处就把图片压缩了 options.inSampleSize = Math.max(options.outWidth / kPhotoMaxSaveSideLen, options.outHeight / kPhotoMaxSaveSideLen); bitmap = BitmapUtil.decodeByteArrayUnthrow(data, options); if (null == bitmap) { options.inSampleSize = Math.max(2, options.inSampleSize * 2); bitmap = BitmapUtil.decodeByteArrayUnthrow(data, options); } } catch (Throwable e) { } if (null == bitmap) { Toast.makeText(ActivityCapture.this, "内存不足,保存照片失败!", Toast.LENGTH_SHORT).show(); return; } //long start = System.currentTimeMillis(); Bitmap addBitmap = BitmapUtil.rotateAndScale(bitmap, _rotation, kPhotoMaxSaveSideLen, true); Bitmap finalBitmap = cropPhotoImage(addBitmap); File photoFile = PathManager.getCropPhotoPath(); boolean successful = BitmapUtil.saveBitmap2file(finalBitmap, photoFile, Bitmap.CompressFormat.JPEG, 100); while (!successful) { successful = BitmapUtil.saveBitmap2file(finalBitmap, photoFile, Bitmap.CompressFormat.JPEG, 100); } if (finalBitmap != null && !finalBitmap.isRecycled()) { addBitmap.recycle(); } Intent intent = new Intent(ActivityCapture.this,ShowImageActivity.class); intent.putExtra(kPhotoPath, photoFile.getAbsolutePath()); currentCameraId = 0; ActivityCapture.this.startActivity(intent); //setResult(1, intent); //ActivityCapture.this.finish(); } }; focusCallback = new Camera.AutoFocusCallback() { @Override public void onAutoFocus(boolean successed, Camera camera) { focuseView.setVisibility(View.INVISIBLE); } }; } //根据拍照的图片来剪裁 private Bitmap cropPhotoImage(Bitmap bmp) { int dw = bmp.getWidth(); int dh = bmp.getHeight(); int height; int width; if (dh > dw) {//图片竖直方向 //切图片时按照竖屏来计算 height = getWindowManager().getDefaultDisplay().getWidth(); width = getWindowManager().getDefaultDisplay().getHeight(); } else {//图片是水平方向 //切图片时按照横屏来计算 width = getWindowManager().getDefaultDisplay().getWidth(); height = getWindowManager().getDefaultDisplay().getHeight(); } Rect rect = new Rect(); int left = 0; int top = 0; int right = width; int bottom = height; rect.set(left, top, right, bottom); float scale = 1.0f; // 如果图片的宽或者高大于屏幕,则缩放至屏幕的宽或者高 if (dw > width && dh <= height) { scale = width * 1.0f / dw; } if (dh > height && dw <= width) { scale = height * 1.0f / dh; } // 如果宽和高都大于屏幕,则让其按按比例适应屏幕大小 if (dw > width && dh > height) { scale = Math.max(width * 1.0f / dw, height * 1.0f / dh); } //如果图片的宽度和高度都小于屏幕的宽度和高度,则放大至屏幕大小 if (dw < width && dh < height) { scale = width * 1.0f / dw; } Matrix matrix = new Matrix(); matrix.postScale(scale, scale); try { Bitmap b2 = Bitmap.createBitmap(bmp, 0, 0, dw, dh, matrix, true); if (null != b2 && bmp != b2) { bmp.recycle(); bmp = b2; } } catch (OutOfMemoryError e) { e.printStackTrace(); } try { Bitmap b3 = Bitmap.createBitmap(bmp, rect.left, rect.top, rect.width(), rect.height()); if (null != b3 && bmp != b3) { bmp.recycle(); bmp = b3; } } catch (OutOfMemoryError e) { e.printStackTrace(); } //将图片压缩至640*640 try { Bitmap b4 = Bitmap.createScaledBitmap(bmp, 640, 640, false); if (null != b4 && bmp != b4) { bmp.recycle(); bmp = b4; } } catch (OutOfMemoryError e) { e.printStackTrace(); } return bmp; } private void setupDevice() { if (android.os.Build.VERSION.SDK_INT > 8) { int cameraCount = Camera.getNumberOfCameras(); if (cameraCount < 1) { Toast.makeText(this, "你的设备木有摄像头。。。", Toast.LENGTH_SHORT).show(); finish(); return; } else if (cameraCount == 1) { bnToggleCamera.setVisibility(View.INVISIBLE); } else { bnToggleCamera.setVisibility(View.VISIBLE); } currentCameraId = 0; frontCameraId = findFrontFacingCamera(); if (-1 == frontCameraId) { bnToggleCamera.setVisibility(View.INVISIBLE); } } } private void openCamera() { if (android.os.Build.VERSION.SDK_INT > 8) { try { camera = Camera.open(currentCameraId); } catch (Exception e) { Toast.makeText(this, "摄像头打开失败", Toast.LENGTH_SHORT).show(); finish(); return; } setCameraDisplayOrientation(this, 0, camera); } else { try { camera = Camera.open(); } catch (Exception e) { Toast.makeText(this, "摄像头打开失败", Toast.LENGTH_SHORT).show(); finish(); return; } } Camera.Parameters camParmeters = camera.getParameters(); List<Size> sizes = camParmeters.getSupportedPreviewSizes(); for (Size size : sizes) { Log.v(TAG, "w:" + size.width + ",h:" + size.height); } preview = new CameraPreview(this, camera); cropBorderView = new CameraCropBorderView(this); FrameLayout.LayoutParams params1 = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT); FrameLayout.LayoutParams params2 = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT); framelayoutPreview.addView(preview, params1); //framelayoutPreview.addView(cropBorderView, params1); observer.start(); _orientationEventListener.enable(); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.bnToggleCamera: switchCamera(); break; case R.id.bnCapture: bnCaptureClicked(); break; case R.id.layback: finish(); break; } } @Override public void onBackPressed() { super.onBackPressed(); } //横竖屏切换的时候 @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); } private void switchCamera() { if (currentCameraId == 0) { currentCameraId = frontCameraId; } else { currentCameraId = 0; } releaseCamera(); openCamera(); } private void bnCaptureClicked() { if (_isCapturing) { return; } _isCapturing = true; focuseView.setVisibility(View.INVISIBLE); try { camera.takePicture(null, null, pictureCallBack); } catch (RuntimeException e) { e.printStackTrace(); _isCapturing = false; } } /** * A basic Camera preview class */ public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback { private SurfaceHolder mHolder; private Camera mCamera; @SuppressWarnings("deprecation") public CameraPreview(Context context, Camera camera) { super(context); mCamera = camera; // Install a SurfaceHolder.Callback so we get notified when the // underlying surface is created and destroyed. mHolder = getHolder(); mHolder.addCallback(this); // deprecated setting, but required on Android versions prior to 3.0 mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } public void surfaceCreated(SurfaceHolder holder) { // The Surface has been created, now tell the camera where to draw // the preview. try { mCamera.setPreviewDisplay(holder); mCamera.startPreview(); } catch (Exception e) { Log.d(TAG, "Error setting camera preview: " + e.getMessage()); } } public void surfaceDestroyed(SurfaceHolder holder) { // empty. Take care of releasing the Camera preview in your // activity. if (camera != null) { camera.setPreviewCallback(null); camera.stopPreview();// 停止预览 camera.release(); // 释放摄像头资源 camera = null; } } private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) { final double ASPECT_TOLERANCE = 0.05; double targetRatio = (double) w / h; if (sizes == null) return null; Size optimalSize = null; double minDiff = Double.MAX_VALUE; int targetHeight = h; // Try to find an size match aspect ratio and size for (Size size : sizes) { double ratio = (double) size.width / size.height; if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue; if (Math.abs(size.height - targetHeight) < minDiff) { optimalSize = size; minDiff = Math.abs(size.height - targetHeight); } } // Cannot find the one match the aspect ratio, ignore the // requirement if (optimalSize == null) { minDiff = Double.MAX_VALUE; for (Size size : sizes) { if (Math.abs(size.height - targetHeight) < minDiff) { optimalSize = size; minDiff = Math.abs(size.height - targetHeight); } } } return optimalSize; } private Size getOptimalPictureSize(List<Size> sizes, double targetRatio) { final double ASPECT_TOLERANCE = 0.05; if (sizes == null) return null; Size optimalSize = null; int optimalSideLen = 0; double optimalDiffRatio = Double.MAX_VALUE; for (Size size : sizes) { int sideLen = Math.max(size.width, size.height); //LogEx.i("size. " + size.width + ", size.height: " + size.height); boolean select = false; if (sideLen < kPhotoMaxSaveSideLen) { if (0 == optimalSideLen || sideLen > optimalSideLen) { select = true; } } else { if (kPhotoMaxSaveSideLen > optimalSideLen) { select = true; } else { double diffRatio = Math.abs((double) size.width / size.height - targetRatio); if (diffRatio + ASPECT_TOLERANCE < optimalDiffRatio) { select = true; } else if (diffRatio < optimalDiffRatio + ASPECT_TOLERANCE && sideLen < optimalSideLen) { select = true; } } } if (select) { optimalSize = size; optimalSideLen = sideLen; optimalDiffRatio = Math.abs((double) size.width / size.height - targetRatio); } } return optimalSize; } public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { // If your preview can change or rotate, take care of those events // here. // Make sure to stop the preview before resizing or reformatting it. Debug.debug("surfaceChanged format:" + format + ", w:" + w + ", h:" + h); if (mHolder.getSurface() == null) { // preview surface does not exist return; } // stop preview before making changes try { mCamera.stopPreview(); } catch (Exception e) { // ignore: tried to stop a non-existent preview } try { Camera.Parameters parameters = mCamera.getParameters(); List<Size> sizes = parameters.getSupportedPreviewSizes(); Size optimalSize = getOptimalPreviewSize(sizes, w, h); parameters.setPreviewSize(optimalSize.width, optimalSize.height); double targetRatio = (double) w / h; sizes = parameters.getSupportedPictureSizes(); optimalSize = getOptimalPictureSize(sizes, targetRatio); parameters.setPictureSize(optimalSize.width, optimalSize.height); parameters.setRotation(0); mCamera.setParameters(parameters); } catch (Exception e) { Debug.debug(e.toString()); } // set preview size and make any resize, rotate or // reformatting changes here // start preview with new settings try { mCamera.setPreviewDisplay(mHolder); mCamera.startPreview(); } catch (Exception e) { Debug.debug("Error starting camera preview: " + e.getMessage()); } } } private int findFrontFacingCamera() { int cameraId = -1; // Search for the front facing camera int numberOfCameras = Camera.getNumberOfCameras(); for (int i = 0; i < numberOfCameras; i++) { CameraInfo info = new CameraInfo(); Camera.getCameraInfo(i, info); if (info.facing == CameraInfo.CAMERA_FACING_FRONT) { Log.d(TAG, "Camera found"); cameraId = i; break; } } return cameraId; } private static void setCameraDisplayOrientation(Activity activity, int cameraId, Camera camera) { CameraInfo info = new CameraInfo(); 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 == 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; } //LogEx.i("result: " + result); camera.setDisplayOrientation(result); } @Override public void needFocuse() { //LogEx.i("_isCapturing: " + _isCapturing); if (null == camera || _isCapturing) { return; } //LogEx.i("autoFocus"); camera.cancelAutoFocus(); try { camera.autoFocus(focusCallback); } catch (Exception e) { Debug.debug(e.toString()); return; } if (View.INVISIBLE == focuseView.getVisibility()) { focuseView.setVisibility(View.VISIBLE); focuseView.getParent().requestTransparentRegion(preview); } } //相机旋转监听的类,最后保存图片时用到 private class CaptureOrientationEventListener extends OrientationEventListener { public CaptureOrientationEventListener(Context context) { super(context); } @Override public void onOrientationChanged(int orientation) { if (null == camera) return; if (orientation == ORIENTATION_UNKNOWN) return; orientation = (orientation + 45) / 90 * 90; if (android.os.Build.VERSION.SDK_INT <= 8) { _rotation = (90 + orientation) % 360; return; } CameraInfo info = new CameraInfo(); Camera.getCameraInfo(currentCameraId, info); if (info.facing == CameraInfo.CAMERA_FACING_FRONT) { _rotation = (info.orientation - orientation + 360) % 360; } else { // back-facing camera _rotation = (info.orientation + orientation) % 360; } } } }