zoukankan      html  css  js  c++  java
  • Android Camera+SurfaceView实现自己定义拍照

              对Activity强制横屏,保证预览方向正确。

    使用OrientationEventListener监听设备方向。推断竖拍时,旋转照片后再保存。保证竖拍时预览图片和保存后的图片方向一致。

          执行效果:

                         


    代码:

    TestCameraActivity.java

    package com.example.testcamera;
    
    import java.io.ByteArrayOutputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.util.List;
    import java.util.UUID;
    
    import android.annotation.SuppressLint;
    import android.app.Activity;
    import android.content.Context;
    import android.content.Intent;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.Matrix;
    import android.hardware.Camera;
    import android.hardware.Camera.Parameters;
    import android.hardware.Camera.Size;
    import android.os.Build;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.OrientationEventListener;
    import android.view.SurfaceHolder;
    import android.view.SurfaceView;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    
    public class TestCameraActivity extends Activity implements OnClickListener,
    		SurfaceHolder.Callback {
    	private static final String TAG = "TestCameraActivity";
    	public static final String KEY_FILENAME = "filename";
    	private Button mTakePhoto;
    	private SurfaceView mSurfaceView;
    	private Camera mCamera;
    	private String mFileName;
    	private OrientationEventListener mOrEventListener; // 设备方向监听器
    	private Boolean mCurrentOrientation; // 当前设备方向 横屏false,竖屏true
    
    	/* 图像数据处理还未完毕时的回调函数 */
    	private Camera.ShutterCallback mShutter = new Camera.ShutterCallback() {
    		@Override
    		public void onShutter() {
    			// 一般显示运行进度条
    		}
    	};
    
    	/* 图像数据处理完毕后的回调函数 */
    	private Camera.PictureCallback mJpeg = new Camera.PictureCallback() {
    
    		@Override
    		public void onPictureTaken(byte[] data, Camera camera) {
    			// 保存图片
    			mFileName = UUID.randomUUID().toString() + ".jpg";
    			Log.i(TAG, mFileName);
    			FileOutputStream out = null;
    			try {
    				out = openFileOutput(mFileName, Context.MODE_PRIVATE);
    				byte[] newData = null;
    				if (mCurrentOrientation) {
    					// 竖屏时。旋转图片再保存
    					Bitmap oldBitmap = BitmapFactory.decodeByteArray(data, 0,
    							data.length);
    					Matrix matrix = new Matrix();
    					matrix.setRotate(90);
    					Bitmap newBitmap = Bitmap.createBitmap(oldBitmap, 0, 0,
    							oldBitmap.getWidth(), oldBitmap.getHeight(),
    							matrix, true);
    					ByteArrayOutputStream baos = new ByteArrayOutputStream();
    					newBitmap.compress(Bitmap.CompressFormat.JPEG, 85, baos);
    					newData = baos.toByteArray();
    					out.write(newData);
    				} else {
    					out.write(data);
    				}
    
    			} catch (IOException e) {
    				e.printStackTrace();
    			} finally {
    				try {
    					if (out != null)
    						out.close();
    				} catch (IOException e) {
    					e.printStackTrace();
    				}
    			}
    			Intent i = new Intent(TestCameraActivity.this, ShowPicture.class);
    			i.putExtra(KEY_FILENAME, mFileName);
    			startActivity(i);
    			finish();
    		}
    	};
    
    	@SuppressWarnings("deprecation")
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.activity_test_camera);
    		mTakePhoto = (Button) findViewById(R.id.take_photo);
    		mTakePhoto.setOnClickListener(this); // 拍照button监听器
    
    		startOrientationChangeListener(); // 启动设备方向监听器
    		mSurfaceView = (SurfaceView) findViewById(R.id.my_surfaceView);
    		SurfaceHolder holder = mSurfaceView.getHolder();
    		holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    		holder.addCallback(this); // 回调接口
    
    	}
    
    	private final void startOrientationChangeListener() {
    		mOrEventListener = new OrientationEventListener(this) {
    			@Override
    			public void onOrientationChanged(int rotation) {
    				if (((rotation >= 0) && (rotation <= 45)) || (rotation >= 315)
    						|| ((rotation >= 135) && (rotation <= 225))) {// portrait
    					mCurrentOrientation = true;
    					Log.i(TAG, "竖屏");
    				} else if (((rotation > 45) && (rotation < 135))
    						|| ((rotation > 225) && (rotation < 315))) {// landscape
    					mCurrentOrientation = false;
    					Log.i(TAG, "横屏");
    				}
    			}
    		};
    		mOrEventListener.enable();
    	}
    
    	@Override
    	public void onClick(View v) {
    		// 点击拍照
    		switch (v.getId()) {
    		case R.id.take_photo:
    			mCamera.takePicture(mShutter, null, mJpeg);
    			break;
    		default:
    			break;
    		}
    
    	}
    
    	@Override
    	public void surfaceChanged(SurfaceHolder holder, int format, int width,
    			int height) {
    		// SurfaceView尺寸发生改变时(首次在屏幕上显示相同会调用此方法)。初始化mCamera參数,启动Camera预览
    
    		Parameters parameters = mCamera.getParameters();// 获取mCamera的參数对象
    		Size largestSize = getBestSupportedSize(parameters
    				.getSupportedPreviewSizes());
    		parameters.setPreviewSize(largestSize.width, largestSize.height);// 设置预览图片尺寸
    		largestSize = getBestSupportedSize(parameters
    				.getSupportedPictureSizes());// 设置捕捉图片尺寸
    		parameters.setPictureSize(largestSize.width, largestSize.height);
    		mCamera.setParameters(parameters);
    
    		try {
    			mCamera.startPreview();
    		} catch (Exception e) {
    			if (mCamera != null) {
    				mCamera.release();
    				mCamera = null;
    			}
    		}
    
    	}
    
    	@Override
    	public void surfaceCreated(SurfaceHolder holder) {
    		// SurfaceView创建时,建立Camera和SurfaceView的联系
    		if (mCamera != null) {
    			try {
    				mCamera.setPreviewDisplay(holder);
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		}
    
    	}
    
    	@Override
    	public void surfaceDestroyed(SurfaceHolder holder) {
    		// SurfaceView销毁时。取消Camera预览
    		if (mCamera != null) {
    			mCamera.stopPreview();
    		}
    	}
    
    	@SuppressLint("NewApi")
    	@Override
    	public void onResume() {
    		super.onResume();
    		// 开启相机
    		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
    			mCamera = Camera.open(0);
    			// i=0 表示后置相机
    		} else
    			mCamera = Camera.open();
    	}
    
    	@Override
    	public void onPause() {
    		super.onPause();
    		// 释放相机
    		if (mCamera != null) {
    			mCamera.release();
    			mCamera = null;
    		}
    
    	}
    
    	private Size getBestSupportedSize(List<Size> sizes) {
    		// 取能适用的最大的SIZE
    		Size largestSize = sizes.get(0);
    		int largestArea = sizes.get(0).height * sizes.get(0).width;
    		for (Size s : sizes) {
    			int area = s.width * s.height;
    			if (area > largestArea) {
    				largestArea = area;
    				largestSize = s;
    			}
    		}
    		return largestSize;
    	}
    }
    

    ShowPicture.java

    package com.example.testcamera;
    
    import android.app.Activity;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.drawable.BitmapDrawable;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.Display;
    import android.widget.ImageView;
    
    public class ShowPicture extends Activity {
    
    	private static final String TAG = "ShowPicture";
    	private ImageView mPicture;
    
    	public void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.activity_show_picture);
    
    		mPicture = (ImageView) findViewById(R.id.picture);
    		String fileName = getIntent().getStringExtra(
    				TestCameraActivity.KEY_FILENAME);
    		// 图片路径
    		Log.i(TAG, fileName);
    		String path = getFileStreamPath(fileName).getAbsolutePath();
    
    		Display display = getWindowManager().getDefaultDisplay(); // 显示屏尺寸
    		float destWidth = display.getWidth();
    		float destHeight = display.getHeight();
    
    		// 读取本地图片尺寸
    		BitmapFactory.Options options = new BitmapFactory.Options();
    		options.inJustDecodeBounds = true;
    		BitmapFactory.decodeFile(path, options);// 设置为true,options依旧相应此图片,但解码器不会为此图片分配内存
    
    		float srcWidth = options.outWidth;
    		float srcHeight = options.outHeight;
    
    		int inSampleSize = 1;
    		if (srcHeight > destHeight || srcWidth > destWidth) { // 当图片长宽大于屏幕长宽时
    			if (srcWidth > srcHeight) {
    				inSampleSize = Math.round(srcHeight / destHeight);
    			} else {
    				inSampleSize = Math.round(srcWidth / destWidth);
    			}
    		}
    		options = new BitmapFactory.Options();
    		options.inSampleSize = inSampleSize;
    
    		Bitmap bitmap = BitmapFactory.decodeFile(path, options);
    		BitmapDrawable bDrawable = new BitmapDrawable(getResources(), bitmap);
    		mPicture.setImageDrawable(bDrawable);
    	}
    
    	@Override
    	public void onDestroy() {
    		if (!(mPicture.getDrawable() instanceof BitmapDrawable))
    			return;
    		// 释放bitmap占用的空间
    		BitmapDrawable b = (BitmapDrawable) mPicture.getDrawable();
    		b.getBitmap().recycle();
    		mPicture.setImageDrawable(null);
    	}
    
    }
    


      源代码下载

       github:https://github.com/mandmLeee/CustomCameraDemo


  • 相关阅读:
    谈谈 在 .Net 生态里为什么没有 Hadoop 系列 ?
    谈谈在 .Net 平台上的 软件生态 和 软件生产力
    我发起了一个 用 物理服务器 和 .Net 平台 构建云平台 的 .Net 开源项目
    推荐一个 基于 WebSocket 和 Redis 的 即时通信 开源项目
    漫谈 12306 架构
    在提交代码的时候分支上出现detached head
    地铁线路查询算法
    .NET 动态脚本语言
    Socket连接池
    比较JqGrid与XtraGrid
  • 原文地址:https://www.cnblogs.com/blfbuaa/p/6921039.html
Copyright © 2011-2022 走看看