版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/I_do_can/article/details/72123161
本文主要记录一些零碎的东西
比扣扣上传头像时,可以拍照,需要选取拍照的应用,今天做的事就是提供供选择的拍照应用
使用我们的相机拍照,返回拍照数据
话不多说,看看效果
原理主要是向系统注册 action
给出的只是一个简单的测试代码,实际项目里camera的管理不能像我写的这样
看看实现:
app/src/main/AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.cl.slack.opencamera">
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<!-- IMAGE_CAPTURE 返回Bitmap or 图片文件 -->
<intent-filter>
<action android:name="android.media.action.IMAGE_CAPTURE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
</manifest>
CameraView.java
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.hardware.Camera;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import java.io.IOException;
/**
* Created by slack
* on 17/5/12 下午6:06
* 主要的surfaceView,负责展示预览图片,camera的开关
*/
public class CameraView extends SurfaceView implements SurfaceHolder.Callback{
private SurfaceHolder mHolder = null;
private Camera mCamera;
private final int mDegree = 90;
public CameraView(Context context) {
this(context,null);
}
public CameraView(Context context, AttributeSet attrs) {
super(context, attrs);
mHolder = this.getHolder();
mHolder.addCallback(this);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
mCamera = Camera.open();
try {
//设置camera预览的角度,因为默认图片是倾斜90度的
mCamera.setDisplayOrientation(mDegree);
//设置holder主要是用于surfaceView的图片的实时预览,以及获取图片等功能,可以理解为控制camera的操作..
mCamera.setPreviewDisplay(holder);
} catch (IOException e) {
mCamera.release();
mCamera = null;
e.printStackTrace();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Camera.Parameters parameters = mCamera.getParameters();
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
/**
* 如果使用正常拍照进行拍照,设置了这个 Rotation, 拍得的图片总是竖直的
*/
parameters.setRotation(mDegree);
mCamera.setParameters(parameters);
mCamera.startPreview();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
public void takePicture(PictureCallback callback){
mCamera.takePicture(null, null, new CameraPictureCallback(callback));
}
// 回调用的picture,实现里边的onPictureTaken方法,其中byte[]数组即为照相后获取到的图片信息
private class CameraPictureCallback implements Camera.PictureCallback {
private PictureCallback pictureCallback;
public CameraPictureCallback(PictureCallback callback) {
pictureCallback = callback;
}
@Override
public void onPictureTaken(byte[] data, Camera camera) {
Bitmap b = null;
if(null != data){
b = BitmapFactory.decodeByteArray(data, 0, data.length);//data是字节数据,将其解析成位图
mCamera.stopPreview();
}
//保存图片到sdcard
if(null != b)
{
if(pictureCallback != null){
pictureCallback.onPictureTaken(b);
}
//设置FOCUS_MODE_CONTINUOUS_VIDEO)之后,myParam.set("rotation", 90)失效。
//图片竟然不能旋转了,故这里要旋转下
// Bitmap rotaBitmap = getRotateBitmap(b, mDegree);
// b.recycle();
// if(pictureCallback != null){
// pictureCallback.onPictureTaken(rotaBitmap);
// }
}
//再次进入预览
mCamera.startPreview();
}
};
private Bitmap getRotateBitmap(Bitmap b, float rotateDegree){
Matrix matrix = new Matrix();
matrix.postRotate((float)rotateDegree);
Bitmap rotaBitmap = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(), matrix, false);
return rotaBitmap;
}
public interface PictureCallback {
void onPictureTaken(Bitmap bitmap);
}
}
主要功能代码
ImageCapture.java
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import android.widget.Toast;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.OutputStream;
/**
* Created by slack
* on 17/5/12 下午4:07
* 外部 调用 无他相机 拍照 返回照片
* 1.有读写外部文件权限
*/
public class ImageCapture {
public static final ImageCapture IMAGE_CAPTURE = new ImageCapture();
private ImageCapture(){}
public Uri mUri = null;
public File mFile = null;
public boolean isEmpty(){
return mUri == null;
}
public boolean updateCaptureAction(Intent intent){
if (intent.getAction() != null) {
if (intent.getAction().equals(MediaStore.ACTION_IMAGE_CAPTURE)) {
try {
Uri fileUri = intent.getExtras().getParcelable(MediaStore.EXTRA_OUTPUT);
updateUri(fileUri);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}
return true;
}
private void updateUri(Uri uri) {
mUri = uri;
if(uri != null){
mFile = new File(uri.getPath());
// 缓存空间
if (mFile.getAbsolutePath().equals("/scrapSpace")) {
mFile = new File(Environment.getExternalStorageDirectory()
.getAbsolutePath() + "/mms/scrapSpace/.temp.jpg");
}
mFile.mkdirs();
Log.i("slack","ImageCapture uri:" + uri + " file:" + mFile.getAbsolutePath());
}
}
/**
* call on main thread
*/
public void saveBitmapToFile(final Activity activity,final Bitmap bitmap){
Toast.makeText(activity,"正在生成图片...",Toast.LENGTH_LONG).show();
new AsyncTask<Void,Void,Void>(){
@Override
protected Void doInBackground(Void... params) {
if (mFile.exists()) {
mFile.delete();
}
OutputStream out;
try {
out = activity.getContentResolver().openOutputStream(mUri);
bitmap.compress(Bitmap.CompressFormat.PNG, 80, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}finally {
bitmap.recycle();
}
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
activity.setResult(Activity.RESULT_OK);
activity.finish();
Log.i("slack","ImageCapture saveImageToAlbum:" + mFile.exists() + " file:" + mFile.getAbsolutePath());
}
}.execute();
}
public void saveBitmapToFile(final Activity activity,final byte[] data){
Toast.makeText(activity,"正在生成图片...",Toast.LENGTH_SHORT).show();
new AsyncTask<Void,Void,Void>(){
@Override
protected Void doInBackground(Void... params) {
if (mFile.exists()) {
mFile.delete();
}
try {
OutputStream out = activity.getContentResolver().openOutputStream(mUri);
BufferedOutputStream bufferedOutput = new BufferedOutputStream(out);
bufferedOutput.write(data);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
activity.setResult(Activity.RESULT_OK);
activity.finish();
Log.i("slack","ImageCapture saveImageToAlbum:" + mFile.exists() + " file:" + mFile.getAbsolutePath());
}
}.execute();
}
public void clear(){
mFile = null;
mUri = null;
}
}
然后测试的代码:
布局文件:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.cl.slack.opencamera.MainActivity">
<com.cl.slack.opencamera.CameraView
android:id="@+id/slack_camera_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAllCaps="false"
android:text="点击拍照"
android:onClick="takePhoto"
android:layout_marginBottom="20dp"
android:layout_gravity="bottom|center"/>
</FrameLayout>
测试代码:
import android.graphics.Bitmap;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
/**
* ImageCapture MediaStore.ACTION_IMAGE_CAPTURE
* created by slack
* on 17/5/12 下午7:05
*/
public class MainActivity extends AppCompatActivity {
CameraView mCameraView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 判断是否 image capture
ImageCapture.IMAGE_CAPTURE.updateCaptureAction(this.getIntent());
setContentView(R.layout.activity_main);
mCameraView = (CameraView) findViewById(R.id.slack_camera_view);
}
public void takePhoto(View view) {
mCameraView.takePicture(mPictureCallback);
}
private CameraView.PictureCallback mPictureCallback = new CameraView.PictureCallback() {
@Override
public void onPictureTaken(Bitmap bitmap) {
if(ImageCapture.IMAGE_CAPTURE.isEmpty()){
// do normal things
Toast.makeText(MainActivity.this,"normal click",Toast.LENGTH_SHORT).show();
}else {
ImageCapture.IMAGE_CAPTURE.saveBitmapToFile(MainActivity.this,bitmap);
}
}
};
@Override
protected void onDestroy() {
super.onDestroy();
ImageCapture.IMAGE_CAPTURE.clear();
}
}
- - - - - - - - - - - - - -update 2017-06-05 - - - - - - - - - - - - - -
新增 对 没有指定存储路径的支持,类似调用系统相机拍照,直接返回 bitmap
ImageCapture.java :
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.widget.Toast;
import com.benqu.core.util.D;
import java.io.File;
import java.io.OutputStream;
/**
* Created by slack
* on 17/5/12 下午4:07
* 外部 调用 无他相机 拍照 返回照片
* 1.有读写外部文件权限
* 2.需要先初始化 菜单
* 支持 带输出路径 和 不带输出路径的调用
* 1. Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);// 启动系统相机
* startActivityForResult(intent, REQUEST_CAMERA_1);
* 2. Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);// 启动系统相机
* Uri photoUri = Uri.fromFile(new File(mFilePath)); // 传递路径
* intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);// 更改系统默认存储路径
* startActivityForResult(intent, REQUEST_CAMERA_2);
*/
public class ImageCapture {
public static final ImageCapture IMAGE_CAPTURE = new ImageCapture();
private ImageCapture(){}
public Uri mUri = null;
public File mFile = null;
private boolean mNeedImageCapture = false;
public boolean isEmpty(){
return !mNeedImageCapture;
}
public void updateCaptureAction(Intent intent){
if (intent.getAction() != null) {
if (intent.getAction().equals(MediaStore.ACTION_IMAGE_CAPTURE)) {
mNeedImageCapture = true;
Uri fileUri = null;
Bundle bundle = intent.getExtras();
if(bundle != null) {
fileUri = bundle.getParcelable(MediaStore.EXTRA_OUTPUT);
}
updateUri(fileUri);
}
}
}
private void updateUri(Uri uri) {
mUri = uri;
if(uri != null){
mFile = new File(uri.getPath());
// 缓存空间
if (mFile.getAbsolutePath().equals("/scrapSpace")) {
mFile = new File(Environment.getExternalStorageDirectory()
.getAbsolutePath() + "/mms/scrapSpace/.temp.jpg");
}
D.i("slack", "ImageCapture uri:" + uri + " file mkdirs " +
(mFile.mkdirs() ? "success" : "fail") + ", file path:" + mFile.getAbsolutePath());
}
}
/**
* call on main thread
*/
public void onObtainBitmap(final Activity activity, final Bitmap bitmap){
Toast.makeText(activity,"正在生成图片...",Toast.LENGTH_LONG).show();
if(mUri != null) {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
if (mFile.exists()) {
mFile.delete();
}
OutputStream out;
try {
out = activity.getContentResolver().openOutputStream(mUri);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
bitmap.recycle();
}
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
activity.setResult(Activity.RESULT_OK);
activity.finish();
D.i("slack", "ImageCapture saveImageToAlbum file exists:" + mFile.exists() + " file:" + mFile.getAbsolutePath());
}
}.execute();
} else {
// 此处只返回缩略图 Intent 传输数据 < 1M
Intent intent = new Intent();
intent.setAction("inline-data");
intent.putExtra("data", reSampleBitmap(bitmap));
activity.setResult(Activity.RESULT_OK, intent);
activity.finish();
}
}
/**
* 暂定拍照数据 1/16 TODO 修改这个大小
* @param bitmap
* @return
*/
private Bitmap reSampleBitmap(Bitmap bitmap) {
Matrix matrix = new Matrix();
matrix.setScale(0.25f, 0.25f);
Bitmap result = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
bitmap.getHeight(), matrix, true);
D.i("slack", "压缩后图片的大小" + (result.getByteCount() / 1024f / 1024f)
+ "M宽度为" + result.getWidth() + "高度为" + result.getHeight());
return result;
}
public void clear(){
mNeedImageCapture = false;
mFile = null;
mUri = null;
}
}
测试代码
// 拍照并显示图片
private void openCamera_1() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);// 启动系统相机
startActivityForResult(intent, REQUEST_CAMERA_1);
}
// 拍照后存储并显示图片
private void openCamera_2() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);// 启动系统相机
Uri photoUri = Uri.fromFile(new File(mFilePath)); // 传递路径
intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);// 更改系统默认存储路径
startActivityForResult(intent, REQUEST_CAMERA_2);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) { // 如果返回数据
if (requestCode == REQUEST_CAMERA_1 && data != null) { // 判断请求码是否为REQUEST_CAMERA,如果是代表是这个页面传过去的,需要进行获取
Bundle bundle = data.getExtras(); // 从data中取出传递回来缩略图的信息,图片质量差,适合传递小图片
Bitmap bitmap = (Bitmap) bundle.get("data"); // 将data中的信息流解析为Bitmap类型
ivShowPicture.setImageBitmap(bitmap);// 显示图片
} else if (requestCode == REQUEST_CAMERA_2) {
FileInputStream fis = null;
try {
fis = new FileInputStream(mFilePath); // 根据路径获取数据
Bitmap bitmap = BitmapFactory.decodeStream(fis);
ivShowPicture.setImageBitmap(bitmap);// 显示图片
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
try {
fis.close();// 关闭流
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}