您当前的位置: 首页 > 学无止境 > 心得笔记 网站首页心得笔记
73_采用照相机拍摄照片
发布时间:2021-03-13 18:27:09编辑:雪饮阅读()
这次要实现的效果是实现照相机拍照,主要功能就实现一个拍照和一个对焦功能即可。
所以布局文件中自然少不了这两个按钮,另外这个和视频播放器一样也需要SurfaceView。
所以布局文件activity_main.xml如:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<SurfaceView
android:layout_weight="100"
android:id="@+id/sv"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<RelativeLayout
android:layout_weight="0"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<Button
android:id="@+id/bt_take_pic"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="拍照" />
<Button
android:id="@+id/bt_auto_focus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toLeftOf="@id/bt_take_pic"
android:text="对焦" />
</RelativeLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<SurfaceView
android:layout_weight="100"
android:id="@+id/sv"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<RelativeLayout
android:layout_weight="0"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<Button
android:id="@+id/bt_take_pic"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="拍照" />
<Button
android:id="@+id/bt_auto_focus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toLeftOf="@id/bt_take_pic"
android:text="对焦" />
</RelativeLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
主程序MainActivity.java:
package com.example.camera;
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.os.Bundle;
import android.os.Environment;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.Toast;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private SurfaceView sv;
private Button bt_take_pic, bt_auto_focus;
private SurfaceHolder holder;
private Camera camera ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//隐藏掉activity的标题栏
// 必须写到setcontentview之前
requestWindowFeature(Window.FEATURE_NO_TITLE);
//实现窗体的全屏显示
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_main);
sv = (SurfaceView) this.findViewById(R.id.sv);
bt_take_pic = (Button) this.findViewById(R.id.bt_take_pic);
bt_auto_focus = (Button) this.findViewById(R.id.bt_auto_focus);
bt_take_pic.setOnClickListener(this);
bt_auto_focus.setOnClickListener(this);
holder = sv.getHolder();
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
//拍照依赖与holder,holder创建是异步的,所以在activity刚创建的时候就准备holder,这样当用户点击时候holder就“可用了”
holder.addCallback(new MyHolderCallback());
}
public void onClick(View v) {
switch (v.getId()) {
case R.id.bt_auto_focus:
//自动对焦
camera.autoFocus(null);
break;
case R.id.bt_take_pic:
//拍照
//ShutterCallback(咔嚓一下的声音对应的回调)
//raw 未经过处理的意思 (原始的图片 ,没有经过任何压缩 体积大 无损)
//这里只用到第三个参数,jpeg图片 将原始图片生成了jpeg图片的回调
camera.takePicture(null, null, new MyPicCallback());
break;
}
}
//拍照回调
private class MyPicCallback implements Camera.PictureCallback{
public void onPictureTaken(byte[] data, Camera camera) {
if(Environment.MEDIA_MOUNTED.equals( Environment.getExternalStorageState())){
try {
File file = new File(Environment.getExternalStorageDirectory(),System.currentTimeMillis()+".jpg");
FileOutputStream fos = new FileOutputStream(file);
fos.write(data);
fos.flush();
fos.close();
} catch (Exception e) {
Toast.makeText(getApplicationContext(), "保存照片失败",Toast.LENGTH_SHORT).show();
e.printStackTrace();
}finally{
camera.startPreview();
}
}else{
Toast.makeText(getApplicationContext(), "sd卡不可用", Toast.LENGTH_SHORT).show();
}
}
}
//holder生命周期回调
private class MyHolderCallback implements SurfaceHolder.Callback{
public void surfaceCreated(SurfaceHolder holder) {
System.out.println("holder 被创建 ");
MainActivity.this.holder = holder;
camera = Camera.open();
// 要想给照相机设置参数 必须要知道你的相机支持什么样子的参数
System.out.println("当前相机支持的一些参数:"+camera.getParameters().flatten());
//获取当前相机的参数对象并立用该参数对象进行当前相机的参数设置
Camera.Parameters parms = camera.getParameters();
//设置图片预览的帧速
//模拟器上用5可用,而在真机,这里是魅族16t测试用30
parms.setPreviewFrameRate(30);
//设置照片的大小
parms.setPictureSize(1280, 960);
//设置照片的输出格式
parms.setPictureFormat(PixelFormat.JPEG);
//照片质量
parms.set("jpeg-quality", 85);
//将设置好的相机参数应用到相机中
camera.setParameters(parms);
//通过SurfaceView显示取景画面
try {
camera.setPreviewDisplay(holder);
} catch (IOException e) {
e.printStackTrace();
}
//开始预览,设置显示到holder之后就可用开始预览了
camera.startPreview();
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {
}
public void surfaceDestroyed(SurfaceHolder holder) {
System.out.println("holder被销毁");
camera.release();
camera = null;
}
}
}
由于我们使用拍照要权限,拍照的照片我们逻辑中写的是写入到外存的,所以外存权限也是要的,所以清单文件中至少需要两个权限的声明。AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.camera">
<uses-permission android:name="android.permission.CAMERA" />
<!--
下面这两个选项是可选的
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
至少在我真机测试魅族16t中不需要,但据说有些设备需要这两个权限
-->
<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/Theme.Camera"
>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
那么部署到模拟器中进行测试时候这里需要注意下
在这个勾选权限的时候,如果是不小心将部署的应用图标拖到了这里,则从这里进去勾选权限就会出现下面的情况
也就是无法勾选了,这个时候还是要舍近求远,进入到那个launcher主界面中找到这个程序按照上面步骤操作才能勾选权限。
那么权限勾选之后在模拟器中大概如
第一次进入可能是这样的界面
第二次进入就没有提示了
然后我在模拟器中测试对焦没有什么问题(日志猫中没有错误产生,界面上没有明显效果,所以要真机测试),然后拍照也能成功,我一连拍了好几张(画面不动,还不都是同一样的图片),这里随便看一张
真机测试
上面进行了模拟器测试,当然对焦没有实际测试到,接下来就需要真机测试了
真机测试时需要注意控制台中对于我们在主程序中获取的摄像机的参数
可以看到这些个参数都是很长的一行,很不容易分析,我们可以将其复制到比如notepad++中
然后利用替换功能,将分号(这一行参数中可以发现每一个分号区分一个参数项)替换成换行
然后这样分析就比较可观了
那么此时有很大机率你的真机会出现activity中除了我们activity中定义的几个正常的view以外,你会发现拍照的预览界面不会出来,即前置摄像头中的画面没有捕获到当前activity中(这里仅仅实现了默认的拍照,默认一般不都是前置摄像头吗。。。)
那么此时八成你会在日志猫中看到有如下信息
这明显就是设置摄像头参数时候某个参数设置的不匹配你的真机,那么我们这里主要设置的几处参数无法如下这几个
parms.setPreviewFrameRate(30);
parms.setPictureSize(1280, 960);
parms.setPictureFormat(PixelFormat.JPEG);
parms.set("jpeg-quality", 85);
那么我这里出现的问题就是与这个setPreviewFrameRate设置的值有关,我这里之前设置的是5.那么我就在刚才处理过的notepad++中的这个文本中查找这个关键字rate
这才发现我这里的值合理的应该是15,24,30,那么我就设置为30于是问题得到了解决。
那么每个真机出现的问题可能都不一样,所以具体情况具体对待,主要就是用排除法一个个把这几个参数的设置都挨个注释,慢慢排查就能找到是否某个参数设置不合理,然后在这个处理过的notepad++中的这个文本中查找这个对应关键字查找到对应你的设备的合理值咯。
那么问题得解后我们就能正常运行我们的项目了
然后测试拍照,可以发现拍照下来的照片也是没有问题的
测试聚焦也有了点反应(其实聚焦本来就没有多大反应,就是聚焦到摄像头为中心,可能的反应也就是预览区域会产生边缘的一些位移而已,一般也是不明显的,除非预览区域预览头像被偏离太多时候聚焦才会效果明显,个人看法,没有实操过,其实不太喜欢照相,感觉没有什么乐趣,除非遇到非常好玩的想要记录下来。),而且控制台没有报错。那么这样一来就没有什么问题的了。
关键字词:照相机,拍摄,android,拍照
下一篇:75_视频的刻录器