<h2>1. 前言</h2>
<p style="text-align: center"><img alt="" src="https://beijingoptbbs.oss-cn-hangzhou.aliyuncs.com/jb/2426819-fede128b67f73ff2711d3cfea1389491"></p>
<p>PS:最近在项目执行过程中有这样一个需求,要求拍完照的图片必须达到以上的效果。需求分析:</p>
<ol>
<li>使用用预览布局SurfaceView,在不局上方使用控件的方式来进行设计,最后通过截图的方式将画面进行保存。</li>
<li>使用图片添加水印的方式来完成。</li>
</ol>
<h2>2. 方法1 使用SurfaceView<br>
</h2>
<p>我心想这不简单吗?于是开始一顿balabala的操作,结果到最后一步时发现,SurfaceView居然不能进行截图,截图下来的图片居然是一张黑色的。简单地说这是因为SurfaceView的特性决定的,我们知道安卓中唯一可以在子线程中进行绘制的view就只有Surfaceview了。他可以独立于子线程中绘制,不会导致主线程的卡顿,至于造成surfaceView黑屏的原因,可以移步这里 Android视图SurfaceView的实现原理分析。如果非要使用此方式时还是有三种思路来进行解决: 采用三种思路:</p>
<p>1. 获取源头视频的截图作为SurfaceView的截图<br>
2. 获取SurfaceView的画布canvas,将canvas保存成Bitmap<br>
3. 直接截取整个屏幕,然后在截图SurfaceView位置的图</p>
<p>但是我觉得这种方式太过繁琐,所以选择用添加水印的式来完成。</p>
<h2>3. 方法2 给拍照下来的图片添加水印<br>
</h2>
<h3>第一步:获取拍照权限</h3>
<div class="blockcode">
<pre class="brush:xml;">
<!--相机权限-->
<uses-permission android:name="android.permission.CAMERA" />
<!--访问外部权限-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
</pre>
</div>
<p>这里使用到郭霖大佬的开源库PermissionX获取权限:</p>
<div class="blockcode">
<pre class="brush:java;">
PermissionX.init(this)
.permissions(Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO)
.onExplainRequestReason { scope, deniedList ->
val message = "需要您同意以下权限才能正常使用"
scope.showRequestReasonDialog(deniedList, message, "确定", "取消")
}
.request { allGranted, grantedList, deniedList ->
if (allGranted) {
openCamera()
} else {
Toast.makeText(activity, "您拒绝了如下权限:$deniedList", Toast.LENGTH_SHORT).show()
}
}
</pre>
</div>
<h3>第二步:拍照<br>
</h3>
<p>android 6.0以后,相机权限需要动态申请。</p>
<div class="blockcode">
<pre class="brush:java;">
// 申请相机权限的requestCode
private static final int PERMISSION_CAMERA_REQUEST_CODE = 0x00000012;
/**
* 检查权限并拍照。
* 调用相机前先检查权限。
*/
private void checkPermissionAndCamera() {
int hasCameraPermission = ContextCompat.checkSelfPermission(getApplication(),
Manifest.permission.CAMERA);
if (hasCameraPermission == PackageManager.PERMISSION_GRANTED) {
//有调起相机拍照。
openCamera();
} else {
//没有权限,申请权限。
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.CAMERA},
PERMISSION_CAMERA_REQUEST_CODE);
}
}
/**
* 处理权限申请的回调。
*/
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (requestCode == PERMISSION_CAMERA_REQUEST_CODE) {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//允许权限,有调起相机拍照。
openCamera();
} else {
//拒绝权限,弹出提示框。
Toast.makeText(this,"拍照权限被拒绝",Toast.LENGTH_LONG).show();
}
}
}
</pre>
</div>
<h4>调用相机进行拍照<br>
</h4>
<p>申请权限后,就可以调起相机拍照了。调用相机只需要调用startActivityForResult传一个Intent就可以了,但是这个Intent需要传递一个uri,用于保存拍出来的图片,创建这个uri时,各个Android版本有所不同,需要进行版本兼容。</p>
<div class="blockcode">
<pre class="brush:java;">
//用于保存拍照图片的uri
private Uri mCameraUri;
// 用于保存图片的文件路径,Android 10以下使用图片路径访问图片
private String mCameraImagePath;
// 是否是Android 10以上手机
private boolean isAndroidQ = Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q;
/**
* 调起相机拍照
*/
private void openCamera() {
Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// 判断是否有相机
if (captureIntent.resolveActivity(getPackageManager()) != null) {
File photoFile = null;
Uri photoUri = null;
if (isAndroidQ) {
// 适配android 10
photoUri = createImageUri();
} else {
try {
photoFile = createImageFile();
} c |
|