2021SC@SDUSC
前言
上几篇文章已经分析完了飞花令的项目,从这一篇开始分析camera的项目。开发人员的设计中,以手机相机为依托的camera项目不仅需要有基础的拍照功能,并且还需要对拍摄的照?进??系列处理,包括但不仅限于图?抗扭曲,曝光度,聚焦等。具体可以整理为以下功能: 1. 相机预览功能 2. 拍照的偏好设置,如闪光灯,聚焦,曝光补偿 3. 相机可随设备旋转,拍摄横屏和竖屏的照? 4. 拍照后保存在?机的pictures?件夹 5. 可以预览拍摄的照? 6. 图?抗扭曲处理 这篇将继续分析相机的预览。
一、项目环境
android studio版本 4.1.2
sdk版本 Compile SDK version:30
Build Tools Version 30.0.3
gradle版本 6.8.3
二、代码分析
1. 实现拍照
拍照主要用到的是Camera的takePicture()方法,通过指定回调函数,将照片数据写入到文件中。Camera API中,数据流主要是通过函数回调的方式,依照从下往上的方向,逐层 return 到 Applications 中。 引用https://blog.csdn.net/qq_16775897/article/details/77896218博主的流程图
调用mCamera.takePicture(),其第三个参数即指定回调函数Camera.PictureCallback(). 当相机拍照完成后,就会触发onPictureTaken(),其中data参数就是jpeg格式的照片数据。我们需要调用getOutputMediaFile()获取输出文件,并向此文件写入照片数据。 getOutputMediaFile()方法会返回一个已经按照格式命名好的mediaFile文件,并且保存在了sd卡相应位置,赋值给pictureFile之后,pictureFile就是生成的照片文件。判断pictureFile正确生成,就调用FileOutputStream()方法,创建FileOutputStream流以写入数据到pictureFile对象表示的文件。首先使用File对象打开本地文件,从文件读取数据,使用FileOutputStream 类的write(byte[] b)方法,将转换的byte数组写入文件,写入完毕后一定要关闭数据流fos。 onPictureTaken()触发后相机会停止预览,我们在getOutputMediaFile()中能获取到media文件的路径outputMediaFileUri,在相应的照片的Imageview设置显示该media文件图像,并且此时我们手动添加camera.startPreview()让相机持续预览。
public void takePicture(final ImageView view) {
mCamera.takePicture(null, null, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
if (pictureFile == null) {
Log.d(TAG, "Error creating media file, check storage permissions");
return;
}
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
view.setImageURI(outputMediaFileUri);
camera.startPreview();
} catch (FileNotFoundException e) {
Log.d(TAG, "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d(TAG, "Error accessing file: " + e.getMessage());
}
}
});
}
效果如下
2.预览页面设置
开发人员规划好的预览页面在activity_main.xml文件中设置 左下角的imageView保存刚刚拍下来的照片,拍照和设置两个button出发拍照和更改偏好设置两个事件。 之前开发人员没有对outputMediaFileType设置初始值,当还没有拍照时,点击imageView程序会闪退,此时outputMediaFileType中没有参数 mediaPreview.setOnClickListener()方法中接受不到getOutputMediaFileType()参数,无法进一步打开新的页面,所以会闪退,开发人员赋予outputMediaFileType初值为0,并且如果不等于image时,会出现提醒消息框,提醒用户要先进行拍照
Toast 是一个 View 视图,快速的为用户显示少量的信息。 Toast 在应用程序上浮动显示信息给用户,它永远不会获得焦点,不影响用户的输入等操作,主要用于给用户提供一些帮助提示。 Toast 最常见的创建方式是使用静态方法 Toast.makeText()
Toast toast=Toast.makeText(MainActivity.this,“先拍照才能预览哦”,Toast.LENGTH_LONG) toast.setGravity(Gravity.TOP|Gravity.CENTER, -50, 100); 第一个参数:设置toast在屏幕中显示的位置。Gravity.TOP|Gravity.CENTER是居中靠顶 第二个参数:相对于第一个参数设置toast位置的横向X轴的偏移量,正数向右偏移,负数向左偏移 第三个参数:同的第二个参数
mediaPreview.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(mPreview.getOutputMediaFileType().equals("image/*")){
Intent intent = new Intent(MainActivity.this, MainActivity2.class);
intent.setDataAndType(mPreview.getOutputMediaFileUri(), mPreview.getOutputMediaFileType());
startActivity(intent);
}else {
Toast.makeText(MainActivity.this,"先拍照才能预览哦",Toast.LENGTH_LONG).show();
}
}
});
}
3.大图预览
点开左下角的imageView,刚刚拍下的照片会大图预览,为mediaView(即所说的imageView)添加响mediaPreview.setOnClickListener(new View.OnClickListener() {},点击时打开新的界面,即activity_main2所设计的页面一样,并且此时需要一个新的intent来传递参数,然后通过Data和Type向这个Intent传递拍到的照片URI,使得拍下来的照片可以在新的页面中间显示 界面预览:
代码如下,intent从主程序MainActivity跳转到MainActivity2 MainActivity:
if(mPreview.getOutputMediaFileType().equals("image/*")){
Intent intent = new Intent(MainActivity.this, MainActivity2.class);
intent.setDataAndType(mPreview.getOutputMediaFileUri(), mPreview.getOutputMediaFileType());
startActivity(intent);
MainActivity2:
public class MainActivity2 extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
Uri uri = getIntent().getData();
FrameLayout preview = (FrameLayout) findViewById(R.id.preview);
if (getIntent().getType().equals("image/*")) {
ImageView view = new ImageView(this);
view.setImageURI(uri);
preview.addView(view);
}
}
}
三、总结
本次完成了相机预览设置的分析,下一篇将开始分析本项目的重点:图片抗扭曲处理,将扭曲的图片利用算法进行调整规划使之能够整齐地呈现在view中。
|