基于Android TextureView与SurfaceTexture实现相机Camera拍照预览与保存照片

写一个简单的例子,实现一个常见的开发功能:拍照功能。
技术路线:通过TextureView的通道获取SurfaceTexture作为相机的预览,然后通过Camera的take方法把相机抓取的byte字节数据转换为Bitmap,然后存放到手机的存储器上,至此,一个最简单的拍照功能完成。
注意,本例如果运行在Android高版本(6.0+,7.0+或更高),需要多写运行时权限申请代码。本例出于功能演示,不再冗余的写这部分代码。只给出最骨干的关键代码逻辑。

布局文件activity_main.xml:

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout 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" 
    android:background="@android:color/holo_blue_light" 
    tools:context="zhangphil.view.MainActivity"> 
 
    <zhangphil.view.MyTextureView 
        android:id="@+id/textureView" 
        android:layout_width="300dp" 
        android:layout_height="200dp" 
        android:layout_centerInParent="true" /> 
 
    <Button 
        android:id="@+id/capture" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:layout_alignParentBottom="true" 
        android:layout_centerHorizontal="true" 
        android:text="拍摄" /> 
</RelativeLayout>

MyTextureView.java:

package zhangphil.view; 
 
import android.content.Context; 
import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
import android.graphics.SurfaceTexture; 
import android.hardware.Camera; 
import android.os.Environment; 
import android.util.AttributeSet; 
import android.util.Log; 
import android.view.TextureView; 
 
import java.io.BufferedOutputStream; 
import java.io.File; 
import java.io.FileOutputStream; 
 
/** 
 * Created by Phil on 2017/9/13. 
 */ 
 
public class MyTextureView extends TextureView { 
    public Camera mCamera; 
 
    public MyTextureView(Context context, AttributeSet attrs) { 
        super(context, attrs); 
        init(); 
    } 
 
    private void init() { 
        mCamera = Camera.open(); 
 
        this.setSurfaceTextureListener(new SurfaceTextureListener() { 
 
            @Override 
            public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) { 
                try { 
                    mCamera.setPreviewTexture(surfaceTexture); 
                    mCamera.startPreview(); 
                } catch (Exception e) { 
                    e.printStackTrace(); 
                } 
            } 
 
            @Override 
            public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width, int height) { 
 
            } 
 
            @Override 
            public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) { 
                mCamera.stopPreview(); 
                mCamera.release(); 
                mCamera = null; 
 
                return true; 
            } 
 
            @Override 
            public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) { 
 
            } 
        }); 
    } 
 
    public void take() { 
        if(mCamera!=null) 
            mCamera.takePicture(null, null, mPictureCallback); 
    } 
 
    Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() { 
        @Override 
        public void onPictureTaken(byte[] data, Camera camera) { 
            mCamera.stopPreview(); 
            new FileSaver(data).save(); 
        } 
    }; 
 
    private class FileSaver implements Runnable { 
        private byte[] buffer; 
 
        public FileSaver(byte[] buffer) { 
            this.buffer = buffer; 
        } 
 
        public void save() { 
            new Thread(this).start(); 
        } 
 
        @Override 
        public void run() { 
            try { 
                File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), "zhangphil.png"); 
                file.createNewFile(); 
 
                FileOutputStream os = new FileOutputStream(file); 
                BufferedOutputStream bos = new BufferedOutputStream(os); 
 
                Bitmap bitmap = BitmapFactory.decodeByteArray(buffer, 0, buffer.length); 
                bitmap.compress(Bitmap.CompressFormat.PNG, 100, bos); 
 
                bos.flush(); 
                bos.close(); 
                os.close(); 
 
                Log.d("照片已保存", file.getAbsolutePath()); 
 
                mCamera.startPreview(); 
            } catch (Exception e) { 
                e.printStackTrace(); 
            } 
        } 
    } 
}



MainActivity.java:


package zhangphil.view; 
 
import android.support.v7.app.AppCompatActivity; 
import android.os.Bundle; 
import android.view.View; 
 
public class MainActivity extends AppCompatActivity { 
    private MyTextureView textureView; 
 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.activity_main); 
        textureView = (MyTextureView) findViewById(R.id.textureView); 
        findViewById(R.id.capture).setOnClickListener(new View.OnClickListener() { 
            @Override 
            public void onClick(View view) { 
                textureView.take(); 
            } 
        }); 
    } 
}



权限:


<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 
    <uses-permission android:name="android.permission.CAMERA"/>



代码运行结果:


发布评论

分享到:

IT虾米网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!

Android Bluetooth蓝牙客户端发起对服务端连接建立请求过程(高版本Android兼容)详解
你是第一个吃螃蟹的人
发表评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。