Android 简单相机和照片查看器的制作

来源:互联网 发布:mac os 10.11原版镜像 编辑:程序博客网 时间:2024/05/13 05:51

第一篇:本人的第一篇博客

相机是手机内部必不可少的一个软件…那我们如何做出一个简单的相机呢?在Android内部提供了一个内部类android.view.SurfaceHolder这个类,这个类提供了SurfaceView,这个类可以帮助我们实现照相功能…


1.实现拍照

  • 实现拍照就必须要有对相机的访问权限
  • 拍照所得的照片的存储就需要有对SD卡的访问权限以及对SD卡中文件夹的创建和删除的权限
    -
    添加到AndroidManifest.xml中
 <uses-permission android:name="android.permission.WRITE_EXTENAL_STORAGE"/> //sdcard的写权限    <uses-permission    android:name="android.permission.READ_EXTERNAL_STORAGE"/>    //sdcard的读权限    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>    //允许挂载和反挂载文件系统可移动存储

调用摄像机
//现在的相机一般都有两个摄像头,我们需要定义我们想要打开哪个摄像头,默认的是后置的摄像头...这里打开的也是后置的摄像头...
if(Camera.getNumberOfCameras()==2){
camera=Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
}else{
camera=Camera.open(0);
}

获取相机参数
Parameters param=Camera1.this.camera.getParameters()
//Camera1是我所建的类名,根据实际情况更改

预览
try { Camera1.this.camera.setPreviewDisplay(Camera1.this.surfaceHolder);//设置我们预览时的SurfaceHolder...
} catch (IOException e) {
e.printStackTrace();
}
Camera1.this.camera.startPreview();//开始预览...

拍照

Camera1.this.camera.takePicture(shutter, raw, jpeg);//Camera.takePicture(shutterCallback,rawCallback,pictureCallback ); 三个回调参数分别代表:按下快门执行的代码;如需要处理raw执行的代码;图片存储执行的代码。 

存储
针对Android 6.0以上,除了需要静态权限,还需要动态权限。
ActivityCompat.requestPermissions(Camera1.this, new String[]{android
.Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);

弹出请求后获得权限立马进入public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)中。

     @Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,@NonNull int[] grantResults) {        switch (requestCode) {            case 1:                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {                    //创建文件夹                    if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {                      //这里执行获取权限的代码。                     }                    break;                }        }    }   

新建文件夹

String filename = Environment.getExternalStorageDirectory().getAbsolutePath()+File.separator + "CameraPhoto"  ;File file = new File(filename);if (!file.exists()) {//如果不存在,就创建一个。最后一般来说会在根目录下找到CameraPhoto文件夹    file.mkdirs();}

将照片转化成字节数据

Bitmap bmp = BitmapFactory.decodeByteArray(data, 0, data.length);

将照片存入file里面

FileOutputStream buf = new FileOutputStream(filename+File.separator+"picture.jpg");                                           bmp.compress(Bitmap.CompressFormat.JPEG, 100, buf);

最后我们可以在CameraPhoto文件中找到名为picture.jpg的照片。因为这里是固定的照片名,每次拍照存储都把之前的照片替换掉了,所以只能存储一张照片。当然可以在文件名上面加上System.currentTimeMillis()函数,这样每次照片的名字都不一样。
完整代码

  1. Activity代码
package com.example.myapplication;import android.annotation.SuppressLint;import android.app.Activity;import android.content.Context;import android.content.Intent;import android.content.pm.PackageManager;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.PixelFormat;import android.hardware.Camera;import android.os.Bundle;import android.os.Environment;import android.support.annotation.NonNull;import android.support.v4.app.ActivityCompat;import android.view.Display;import android.view.SurfaceHolder;import android.view.SurfaceView;import android.view.View;import android.view.WindowManager;import android.widget.Button;import android.widget.Toast;import java.io.BufferedOutputStream;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;/** * Created by 邓磊 on 2017/7/30. */public class Camera1 extends Activity implements View.OnClickListener {    private SurfaceView surfaceView;    private SurfaceHolder surfaceHolder;    private Camera camera = null;    private boolean previewrunning = true;    private Button TakePhoto;    @SuppressWarnings("deprecation")    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        super.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);//全屏显示...        super.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);//高亮显示...        setContentView(R.layout.camera_main);        TakePhoto = (Button) findViewById(R.id.TakePhoto);        TakePhoto.setOnClickListener(this);        surfaceView = (SurfaceView) findViewById(R.id.surfaceView);        surfaceHolder = surfaceView.getHolder();        surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);        surfaceHolder.setFixedSize(480, 800);        surfaceHolder.addCallback(new SurfaceHolder.Callback() {            //这里就很清晰了,在使用到了SurfaceView时必然要获取SurfaceHolder接口,然后进行回调..            @Override            public void surfaceDestroyed(SurfaceHolder holder) {                // TODO Auto-generated method stub                if (Camera1.this.camera != null) {                    if (Camera1.this.previewrunning) {                        Camera1.this.camera.stopPreview();                        Camera1.this.previewrunning = false;                    }                    Camera1.this.camera.release();                }            }            @SuppressLint("NewApi")            @Override            public void surfaceCreated(SurfaceHolder holder) {                // TODO Auto-generated method stub                if (Camera.getNumberOfCameras() == 2) {//获取相机...                    camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);                } else {                    camera = Camera.open(0);                }                camera.setDisplayOrientation(90);//这个就是设置屏幕需要旋转90度,一般没这句话屏幕内的东西都是纵向的...                WindowManager manager = (WindowManager) Camera1.this.getSystemService(Context.WINDOW_SERVICE);//获取窗口服务..                Display display = manager.getDefaultDisplay();//获取display对象..                Camera.Parameters param = Camera1.this.camera.getParameters();//获取参数                param.setPreviewSize(display.getWidth(), display.getHeight());//设置预览时图片的大小..                param.setPictureSize(display.getWidth(), display.getHeight());//设置拍照后图片的大小..                param.setPreviewFrameRate(5);//设置预览的时候以每秒五帧进行显示...                param.setPictureFormat(PixelFormat.JPEG);//设置图片的格式为JPEG...                param.set("jpeg-quality", 80);//设置图片的质量...                try {                    Camera1.this.camera.setPreviewDisplay(Camera1.this.surfaceHolder);//设置我们预览时的SurfaceHolder...                } catch (IOException e) {                    e.printStackTrace();                }                Camera1.this.camera.startPreview();//开始预览...                Camera1.this.previewrunning = true;            }            @Override            public void surfaceChanged(SurfaceHolder holder, int format, int width,                                       int height) {            }        });    }    @Override    public void onClick(View v) {        ActivityCompat.requestPermissions(Camera1.this, new String[]{android                .Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);    }    @Override    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,                                           @NonNull int[] grantResults) {        //super.onRequestPermissionsResult(requestCode, permissions, grantResults);        switch (requestCode) {            case 1:                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {                    //创建文件夹                    if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {                        // TODO Auto-generated method stub                        if (Camera1.this.camera != null) {                            Camera1.this.camera.autoFocus(new Camera.AutoFocusCallback() {//这里就是触发按钮来完成事件..这里是自动聚焦函数..内部需要实现三种方法..                                @Override                                public void onAutoFocus(boolean success, Camera camera) {                                    if (success) {                                        Camera1.this.camera.takePicture(null, null, jpeg);                                    }                                }                                private Camera.PictureCallback jpeg = new Camera.PictureCallback() {                                    @Override                                    public void onPictureTaken(byte[] data, Camera camera) {                                        Bitmap bmp = BitmapFactory.decodeByteArray(data, 0, data.length);//把图片转化成字节数据...                                        String filename = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "CameraPhoto"  ;                                        File file = new File(filename);                                        if (!file.exists()) {                                            file.mkdirs();                                        }                                        try {                                            FileOutputStream buf = new FileOutputStream(filename+File.separator+"picture.jpg");                                            bmp.compress(Bitmap.CompressFormat.JPEG, 100, buf);//                                            buf.flush();//                                            buf.close();                                            Intent intent=new Intent(Camera1.this,PhotoActivity.class);                                            intent.putExtra("path",filename+File.separator+"picture.jpg");                                            startActivity(intent);                                        } catch (Exception e) {                                            e.printStackTrace();                                        }                                    }                                };                            });                        }                    }                    break;                }        }    }}

Layout.xml代码

<?xml version="1.0" encoding="utf-8"?><android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    xmlns:tools="http://schemas.android.com/tools"    android:orientation="vertical" android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context="com.example.myapplication.Camera1"    tools:layout_editor_absoluteY="81dp"    tools:layout_editor_absoluteX="0dp">    <Button        android:id="@+id/TakePhoto"        android:layout_width="0dp"        android:layout_height="48dp"        android:text="拍照"        android:layout_marginStart="3dp"        tools:layout_constraintRight_creator="1"        tools:layout_constraintBottom_creator="1"        app:layout_constraintBottom_toBottomOf="parent"        android:layout_marginEnd="3dp"        app:layout_constraintRight_toRightOf="parent"        tools:layout_constraintLeft_creator="1"        android:layout_marginBottom="2dp"        app:layout_constraintLeft_toLeftOf="parent"        android:layout_marginLeft="3dp"        android:layout_marginRight="3dp" />    <SurfaceView        android:id="@+id/surfaceView"        android:layout_width="0dp"        android:layout_height="0dp"        tools:layout_constraintTop_creator="1"        tools:layout_constraintRight_creator="1"        tools:layout_constraintBottom_creator="1"        app:layout_constraintBottom_toTopOf="@+id/TakePhoto"        android:layout_marginStart="1dp"        android:layout_marginEnd="1dp"        app:layout_constraintRight_toRightOf="parent"        android:layout_marginTop="1dp"        tools:layout_constraintLeft_creator="1"        android:layout_marginBottom="12dp"        app:layout_constraintLeft_toLeftOf="parent"        app:layout_constraintTop_toTopOf="parent"        android:layout_marginLeft="1dp"        android:layout_marginRight="1dp"        app:layout_constraintHorizontal_bias="0.0"        app:layout_constraintVertical_bias="0.0" /></android.support.constraint.ConstraintLayout>

附上一张图片

这里写图片描述

2.照片查看

实现里拍照,接下来就是照片查看了。先附上一个图片。

这里写图片描述

最上面显示图片的路径
然后是图片
再就是button,分别代表删除照片,返回上一步拍照界面,以及进行下一步功能,这里不涉及。

  1. 这个页面执行的前提是照片能够传过来。
    在照相机制作中有段这样的代码
    Intent(Camera1.this,PhotoActivity.class);//从Camera1这个类跳到PhotoActivity类中,也就是照片查看的那个类中。当然是需要在startActivity(intent)后才可以做到。
    intent.putExtra("path",filename+File.separator+"picture.jpg");//这里我们定义一个变量叫做path,其中path是等于filename+File.separator+"picture.jpg";
    startActivity(intent);

    在照片查看中就要接收这个path。
 String path = getIntent().getStringExtra("path");

2.显示路径

tv_path.setText(path);//tv_path对应layout中的那个TextView.

3.图片显示

 try {            FileInputStream file = new FileInputStream(path);            Bitmap bitmap = BitmapFactory.decodeStream(file);            // 矩阵            Matrix matrix = new Matrix();            matrix.setRotate(90);            bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),                    bitmap.getHeight(), matrix, true);            iv_photo.setImageBitmap(bitmap);        } catch (FileNotFoundException e) {            e.printStackTrace();        }    }

4.删除

 File file1 = new File(tv_path.getText().toString());               if(file1.exists()) {                   file1.delete();                   Toast toast = Toast.makeText(PhotoActivity.this, "删除成功!", Toast.LENGTH_LONG);                   toast.setGravity(Gravity.CENTER, 0, 0);                   toast.show();                   tv_path.setText("文件已删除!请点击上一步重新拍照!");               }               else               {                   Toast toast = Toast.makeText(PhotoActivity.this, "文件已删除!请点击上一步重新拍照!", Toast.LENGTH_LONG);                   toast.setGravity(Gravity.CENTER, 0, 0);                   toast.show();               }

5.回到上一步拍照的界面

Intent i=new Intent(PhotoActivity.this,Camera1.class);                startActivity(i);

PS:从一个Activity跳到另外一个Activity还需要在Manifest中添加相应Activity事件。并且如果每个Activity中都是

<category android:name="android.intent.category.LAUNCHER" />

运行时,就会下载多个与App相同图片的应用。为了避免这个,我们可以在之后创建的Activity中换成

<category android:name="android.intent.category.DEFAULT" />

最后附上完整代码
Activity代码

package com.example.myapplication;/** * Created by 邓磊 on 2017/8/1. */import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import android.app.Activity;import android.content.Intent;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Matrix;import android.os.Bundle;import android.view.Gravity;import android.view.View;import android.widget.Button;import android.widget.ImageView;import android.widget.TextView;import android.widget.Toast;public class PhotoActivity extends Activity implements View.OnClickListener {    private TextView tv_path=null;    private ImageView iv_photo=null;    private Button next=null;    private Button delete=null;    private Button previous=null;    @Override    protected void onCreate(Bundle savedInstanceState) {        // TODO Auto-generated method stub        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_photo);        String path = getIntent().getStringExtra("path");       tv_path = (TextView) findViewById(R.id.tv_path);        next=(Button)findViewById(R.id.next);        delete=(Button)findViewById(R.id.delete);        previous=(Button)findViewById(R.id.previous);        // 显示路径        tv_path.setText(path);        iv_photo = (ImageView) findViewById(R.id.iv_photo);        next.setOnClickListener(this);        delete.setOnClickListener(this);        previous.setOnClickListener(this);        // 调整角度        try {            FileInputStream file = new FileInputStream(path);            Bitmap bitmap = BitmapFactory.decodeStream(file);            // 矩阵            Matrix matrix = new Matrix();            matrix.setRotate(90);            bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),                    bitmap.getHeight(), matrix, true);            iv_photo.setImageBitmap(bitmap);        } catch (FileNotFoundException e) {            e.printStackTrace();        }    }    @Override    public void onClick(View v) {        switch (v.getId()){            case R.id.delete:                File file1 = new File(tv_path.getText().toString());               if(file1.exists()) {                   file1.delete();                   Toast toast = Toast.makeText(PhotoActivity.this, "删除成功!", Toast.LENGTH_LONG);                   toast.setGravity(Gravity.CENTER, 0, 0);                   toast.show();                   tv_path.setText("文件已删除!请点击上一步重新拍照!");               }               else               {                   Toast toast = Toast.makeText(PhotoActivity.this, "文件已删除!请点击上一步重新拍照!", Toast.LENGTH_LONG);                   toast.setGravity(Gravity.CENTER, 0, 0);                   toast.show();               }                break;            case R.id.previous:                Intent i=new Intent(PhotoActivity.this,Camera1.class);                startActivity(i);                break;            case R.id.next:                Intent j=new Intent(PhotoActivity.this,QRcode.class);               startActivity(j);                break;        }    }}

Layout.xml代码

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="vertical" android:layout_width="match_parent"    android:layout_height="match_parent">    <TextView        android:id="@+id/tv_path"        android:gravity="center"        android:layout_width="match_parent"        android:layout_height="30dp" />    <ImageView        android:id="@+id/iv_photo"        android:layout_width="385dp"        android:layout_height="347dp" />    <Button        android:id="@+id/delete"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="删除" />    <Button        android:id="@+id/previous"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="上一步" />    <Button        android:id="@+id/next"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:text="下一步" /></LinearLayout>