4.14 Android 拍照

拍照基本上三种方式:
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:

}

@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);
}

然后把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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值