4.14 Android 拍照

来源:互联网 发布:移动网络初始密码 编辑:程序博客网 时间:2024/05/18 10:49
拍照基本上三种方式:
1)隐式意图,拍缩略图 Bitmap,上传服务器使用
2)隐式意图,直接生成大图文件,
3)自定义拍照,复古风,这些都是通过自定义拍照来做的 。


开发步骤:
1:设置权限 CAMERA
<自定义照相机时使用的权限>
<use-permission android:name="android.permission.CAMERA"/>

2:如果要发布到应用市场里面,<uses-feature>这个功能
硬件拍照功能的要求,用于告诉应用市场,当前软件需要拍照的功能,是否是必须要有拍照的要求,
<use-feature android:name="android.hardware.camera" android:required="true">
不要写camera2,注意name 属性不是包名

3:使用MediaStore.ACTION_IMAGE_CAPTURE
如果是录像就是使用MediaStore.ACTION_VIDEO_CAPTURE

4: startActivityForResult

在布局上添加一个ImageView,用来显示牌出来的照片

第一个button,隐式意图拍照 ,返回缩略图 
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent,998);

onActivityResult(int requestCode, int resultCode, intent data){
if(requestCode ==998){
//代表拍照返回缩略图
if(resultCode==RESULT_OK){
// Intent data 中,包含了缩略图,缩略图名称为“”
Bitmap bitmap = data.getParcelableExtra("data");
imageView.setImageBitmap(bitmap);
}
}
}

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
public class MainActivity extends AppCompatActivity {    private ImageView imageView;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        imageView = (ImageView)findViewById(R.id.preview);    }    public void btnTakePicture(View view) {        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);        startActivityForResult(intent,998);    }    @Override    protected void onActivityResult(int requestCode, int resultCode, Intent data) {        super.onActivityResult(requestCode, resultCode, data);        if(requestCode==998){            if(resultCode==RESULT_OK){               Bitmap bitmap= data.getParcelableExtra("data");                imageView.setImageBitmap(bitmap);            }        }    }}
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


--------------------------------------------------------------

第二种:2)隐式意图,直接生成大图文件,

-------------------------------------------------------------

简单一句话:其实相对于上面的方法仅仅是多了一个intent.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile(picFile)),而这个extra后面要接一个Uri的类型的存储图片的文件.

-----------------------------------------------------------------


再新建一个新的 button

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
//1:考虑extra的设置,名称
//2: extra的内容类型
//3: Uri 存储位置,可以使用文件来保存。
//     获取文件File对象,来创建Uri
//TODO:检测存储卡的状态, 照片目录使用的是StoreagePublicDirectory里面。


记得要设置权限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

File directory = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DCIM);

if(!directory.exists()){
directory.mkdirs();
}

//使用成员变量,代表拍照成功的情况下的,文件对象,再进行显示。
File picFile = new File(directory,"Pic"+System.currentTimeMillis()+".jpeg")

//设置EXTRA_OUTPUT参数,只要设置了这个参数,
//那么在回调的时候,Intent中,就不会包含缩略图了;

intent.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile(picFile))
startActivityForResult(intent,199);

在onActivitResult里面
else if(requestCode ==199){
//代表直接村文件的方式的排至,返回,data 就没有缩略图了
现在有一个要求,要求拍照之后的大图片显示出来。
把上面的picFile作为成员变量来做。
if(resultCode==RESULT_OK){
mImageView.setImageUri(Uri.fromFile(picFile));

//最好还是使用BitMapFactory 因为可以缩小,

注意:这里如果使用setImageUri 会抱错:4.14-1 图片太大遇到的问题,Bitmap too large to be uploaded into a texture (2340x4160, max=4096x4096)

}

}


完整代码:

public class MainActivity extends AppCompatActivity {    private ImageView imageView;    private File file;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        imageView = (ImageView)findViewById(R.id.preview);    }    public void btnTakePicture(View view) {        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);        startActivityForResult(intent, 998);    }    @Override    protected void onActivityResult(int requestCode, int resultCode, Intent data) {        super.onActivityResult(requestCode, resultCode, data);        if(requestCode==998){            if(resultCode==RESULT_OK){                Bitmap bitmap = data.getParcelableExtra("data");                imageView.setImageBitmap(bitmap);            }        }else if(requestCode==199){            if(resultCode==RESULT_OK){                //imageView.setImageURI(Uri.fromFile(file));                //02-16 22:28:32.618 19893-19935/com.example.kodulf.devicepicture W/OpenGLRenderer: Bitmap too large to be uploaded into a texture (2340x4160, max=4096x4096)                BitmapFactory.Options options = new BitmapFactory.Options();                options.inSampleSize = 32;                Bitmap bitmap = BitmapFactory.decodeFile(file.getPath(),options);                imageView.setImageBitmap(bitmap);                Log.d("Kodulf", "RESULT_OK" + file.getPath());            }        }    }    public void btnTakeBigPicture(View view) {        Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);        File directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);        if(directory==null){            directory.mkdir();        }        file = new File(directory,"Pic"+System.currentTimeMillis()+".jpeg");        intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file));        startActivityForResult(intent, 199);    }}



--------------------------------------------

第三种:自定义拍照的内容:

--------------------------------------------

如果想要缩小点,一个像素,

1:使用camera类,进行照相机的控制,
2:照相机必须要设置预览界面,这个预览界面是一个SurfaceView
SurfaceView 有callback的回调接口,onSurfaceCreate,里面基尼系那个设置
3:Camera 设置各种参数。配合SurfaceView,来进行相机的预览。
4:照相机使用完成,必须关系和释放,否则手机只能重启,因为操作照相机是系独占的,
如果不关闭的话,只有关闭手机再重新开才行。也就是说退了但是照相机没有关闭,那么摄像头是用不了的。


新建一个新的activity:CameraActivity
自定义摄像头的功能,使用旧版本的Camera API
需要使用CAMERA权限,
需要SurfaceView 作为拍照的预览窗口。



照相机应该及时的释放,应该,照相机在activity的生命周期中进行相应的打开和释放。
在SurfaceView 准备好,就可以创建照相机,在SurfaceView 销毁的时候,释放照相机。


可以onResume()里面或者在onCreat()里面写打开,最好在SurfaceView create里面打开


onCreate(){
....
Surface furfaceView = (SurfaceView)findViewById()
surfaceView.getHolder().addCallback(this);
//如果是Android 6.0 在onCreate 里面要申请权限
//为了兼容新版Android,
if(Build.VERSION.SDK_INT>=23)
int p=checkSelfPermission(Manifest.permission.CAMERA);//检查自身是否有照相机权限
结果是权限允许,权限不允许
if(Build.VERSION.SDK_INT>=23){    int p = checkSelfPermission(android.Manifest.permission.CAMERA);    if(p== PackageManager.PERMISSION_DENIED)    requestPermissions(new String[]{android.Manifest.permission.CAMERA},998);}else{    checkPermission(android.Manifest.permission.CAMERA, Binder.getCallingPid(),Binder.getCallingUid());}

onRequestPermissionsResult(int){
//TODO:

}

@Overridepublic void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {    super.onRequestPermissionsResult(requestCode, permissions, grantResults);    StringBuilder sb = new StringBuilder();    for(int i=0;i<permissions.length;i++){        sb.append(permissions[i].toString()+";");    }    Log.d("Kodulf","getPermission"+sb);}

然后把surfaceView 接口的三个方法创建出来。

surfaceCreated(){
//开启照相机,设置照相机,进行预览
mCamera = Camera.open(); //打开第一个后置摄像头,如果只有一个摄像头就写open(0)
//记住要求权限CAMERA
//如果是Android 6.0 在onCreate 里面要申请权限

//获取照相机的参数,例如照相机的闪光灯是开的。
Camera.Parameters parameters = mCamera.getParameters();

//设置自定义的参数
parameters.setColorEffect(Camera.Parameters.EFFECT_NEGATIVE);

//更新照相机参数
mCamera.setParameters(parameters);
try{
//设置预览的显示界面
mCamera.setPreviewDisplay(holder);

//因为默认的预览是点到的,需要设置方向

mCamera.setDisplayOrientation(90);


//开始预览
mCamera.startPreview();
}
}

在surfaceView的surfaceDestoryed(){
mCamera.stopPreview();
//释放照相机,否则,手机需要重启,也有的支持自动释放了,为了严谨还是写一下。
mCamera=null;
}


private Camera mCamera;


public void btnTakePhoto(View view){
camera的选择一定不要选graphics的那个。graphics 是控件的摄像,这个在3d里面用到的。
/**
拍照,最终的图片数据,通过回调接口传回来;
mCamera.takePicture(
null,//Camera.ShutterCallback
null,//Camera.PictureCallback raw RAW 格式拍照的时候,数据会回调给这个接口,RAW的格式是没有经过压缩的,有的可鞥44MB大小
null,//Camera.PictureCallback postview postView 拍照之后,显示的回调
null//Camera.PictureCallback jpeg  JPEG格式拍照的死后,数据会回调给这个接口。
);
如果没有raw,下面的额才执行
有了raw的,后面的不hi行。


*/
//上面的是4个参数的。一般使用3个参数的,少了一个postView
mCamera.takePicture(
null, 
null, //RAW,很多手机也不支持
this  //JPEG,Android 的手机上面用是这个。用于接受JPEG格式的拍照的结构
);

}


当PictureCallBack接口,当takePicture 方法执行成功,并且拍照完成
返回数据点额时候,调用这个接口
data 就是图片文件数据


上面的this会写一个onPictureTaken(byte[] data,Camera camera){
Log.d("CameraActivity","onPictureTaken data "+data.length);
//TODO:保存文件,拍照之后,如果还希望继续拍照,那么照相机必须再进入预览才可以拍照。否则就抛出异常
File directory=Environment.getExternalStoragePublicDirectory(Envir);


if(!directory.existes()){
{
directory.mkdirs();
}


File file=new File(directory,"Pic-"+..);


FileOutputStream fout = null;
try{
fout = new FileOutputStream(file);
fout.write(data);
}


finally{
fout.close()



//拍照只要要注意的,如果我想要拍一张以后再拍。那么照相机必须再进入预览才可以拍照。否则就抛出异常

camera.startPreview();
}


——————————————————————————————————————

代码:

package com.example.kodulf.devicepicture;import android.content.pm.PackageManager;import android.hardware.Camera;import android.os.Binder;import android.os.Build;import android.os.Environment;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;import android.view.SurfaceHolder;import android.view.SurfaceView;import android.view.View;import java.io.File;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.util.jar.Manifest;public class CameraActivity extends AppCompatActivity implements SurfaceHolder.Callback, Camera.PictureCallback {    private SurfaceView mSurfaceView;    private Camera mCamera;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_camera);        mSurfaceView = (SurfaceView) findViewById(R.id.preview);        mSurfaceView.getHolder().addCallback(this);        //记住要求权限CAMERA        //如果是Android 6.0 onCreate 里面要申请权限        if(Build.VERSION.SDK_INT>=23){            int p = checkSelfPermission(android.Manifest.permission.CAMERA);            if(p== PackageManager.PERMISSION_DENIED)            requestPermissions(new String[]{android.Manifest.permission.CAMERA},998);        }else{            checkPermission(android.Manifest.permission.CAMERA, Binder.getCallingPid(),Binder.getCallingUid());        }    }    @Override    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {        super.onRequestPermissionsResult(requestCode, permissions, grantResults);        StringBuilder sb = new StringBuilder();        for(int i=0;i<permissions.length;i++){            sb.append(permissions[i].toString()+";");        }        Log.d("Kodulf","getPermission"+sb);    }    public void btnTakePhoto(View view) {            mCamera.takePicture(                    null,                    null,                    this            );    }    @Override    public void surfaceCreated(SurfaceHolder holder) {        //开启照相机,设置照相机,进行预览        mCamera = Camera.open();//打开第一个后置摄像头,如果只有一个摄像头就写open(0)        Camera.Parameters parameters = mCamera.getParameters();        parameters.setColorEffect(Camera.Parameters.EFFECT_NEGATIVE);        parameters.setFlashMode(Camera.Parameters.FLASH_MODE_ON);        mCamera.setParameters(parameters);        try {            mCamera.setPreviewDisplay(holder);            mCamera.setDisplayOrientation(90);            mCamera.startPreview();        } catch (IOException e) {            e.printStackTrace();        }    }    @Override    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {    }    @Override    public void surfaceDestroyed(SurfaceHolder holder) {        mCamera.stopPreview();        //释放照相机,否则,手机需要重启,也有的支持自动释放了,为了严谨还是写一下。        mCamera=null;    }    @Override    public void onPictureTaken(byte[] data, Camera camera) {        Log.d("CameraActivity","onPictureTaken data "+data.length);        File directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);        if(!directory.exists()){            directory.mkdirs();        }        File file = new File(directory,"Pic"+System.currentTimeMillis()+".jpeg");        FileOutputStream fout =null;        try {            fout = new FileOutputStream(file);            fout.write(data);        } catch (FileNotFoundException e) {            e.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        }finally{            try {                fout.close();            } catch (IOException e) {                e.printStackTrace();            }        }        //拍照只要要注意的,如果我想要拍一张以后再拍。那么照相机必须再进入预览才可以拍照。否则就抛出异常        camera.startPreview();    }}


——————————————————————————————————————————————

老张的代码:


package com.qianfeng.devicefeaturedemos;


import android.Manifest;
import android.hardware.Camera;
import android.os.Binder;
import android.os.Build;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;


import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;


/**
 * 自定义照相机的功能(使用旧版本的Camera API)
 * 需要使用 CAMERA 权限
 * 需要 SurfaceView 作为拍照的预览窗口
 */
public class CameraActivity extends AppCompatActivity implements SurfaceHolder.Callback, Camera.PictureCallback {


    /**
     * 照相机应该及时的释放,因此,照相机应该在Activity声明
     * 周期中,进行相应的打开和释放;
     * <p/>
     * 在 SurfaceView 准备好,就可以创建照相机,
     * 在 SurfaceView 销毁的时候,释放照相机
     */
    private Camera mCamera;




    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_camera);


        SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview);
        surfaceView.getHolder().addCallback(this);


        // 为了兼容新版Android,需要检查和申请权限
        if (Build.VERSION.SDK_INT >= 23) {
            // 返回禁止和允许
            int p = checkSelfPermission(Manifest.permission.CAMERA); // 检查自身是否有照相机权限;


            requestPermissions(new String[]{
                    Manifest.permission.CAMERA
            }, 998);


        } else {
            checkPermission(Manifest.permission.CAMERA, Binder.getCallingPid(), Binder.getCallingUid());
        }
    }


    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        // TODO: 再次开始照相机的预览
    }


    public void btnTakePhoto(View view) {
        // 拍照,最终的图片数据,通过回调接口传会来;
        //mCamera.takePicture(
        //        null, // ShutterCallback 快门回调接口
        //        null, // RAW 格式拍照的时候,数据会回调给这个接口,
        //        null, // postView  拍照之后,显示的回调
        //        null  // JPEG 格式拍照的时候,数据会回调给这个接口;
        //);


        mCamera.takePicture(
                null,
                null,  // RAW
                this   // JPEG 用于接收JPEG格式的拍照结果
        );


    }


    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        // 开启照相机,设置照相机,进行预览


        mCamera = Camera.open(); // 打开第一个后置摄像头,要求权限 CAMERA


        // 获取照相机的参数
        Camera.Parameters parameters = mCamera.getParameters();


        // 设置自定义的参数
        parameters.setColorEffect(Camera.Parameters.EFFECT_NEGATIVE);
        parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
        parameters.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_SHADE);


        // 更新照相机参数
        mCamera.setParameters(parameters);


        try {
            // 设置预览的显示界面
            mCamera.setPreviewDisplay(holder);
            // 因为默认的预览是颠倒的,需要设置方向
            mCamera.setDisplayOrientation(90);
            // 开始预览
            mCamera.startPreview();


        } catch (IOException e) {
            e.printStackTrace();
        }


    }


    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {


    }


    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        mCamera.stopPreview();


        // 释放照相机,否则,手机需要重启;
        mCamera.release();


        mCamera = null;
    }


    /**
     * PictureCallback 接口,当 takePicture 方法执行成功,并且拍照完成,
     * 返回数据的时候,调用这个接口
     *
     * @param data   图片的文件数据
     * @param camera
     */
    @Override
    public void onPictureTaken(byte[] data, Camera camera) {
        Log.d("CameraActivity", "onPictureTaken data " + data.length);


        // TODO: 保存文件, 拍照之后,如果还希望继续拍照,那么,
        //       照相机必须再进入预览,才可以拍照,否则抛异常;


        File directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);


        if (!directory.exists()) {
            directory.mkdirs();
        }


        File file = new File(directory, "Pic-" + System.currentTimeMillis() + ".jpeg");


        FileOutputStream fout = null;


        try {
            fout = new FileOutputStream(file);
            fout.write(data);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fout != null) {
                try {
                    fout.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }


        // 如果希望继续拍照,必须在这,进行 重新预览的操作
        camera.startPreview();




    }
}







API Guides
0 0