废话不多说直接上代码
fun getBitmapFromView(window: Window, targetView: View, width: Int? = null): Bitmap {
val finalWidth = width ?: targetView.width
if (finalWidth <= 0) {
//Log.w(TAG, "finalWidth=$finalWidth")
throw IllegalArgumentException("宽度小于等于0, finalWidth=$finalWidth")
}
// 这里做了 一个安卓版本判断
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
copyPixelFromView(window, targetView, finalWidth)
} else {
convertViewToBitmap(targetView, finalWidth)
}
}
/**
/**
* Android 26(O)(8.0)以下的版本,使用此方法,某些情况下颜色有偏差,已经View采集不全,比如Android14上摄像头内容未采集到
* 如果采用drawingCache.copy宽高未生效,还是View原始的宽高,要生效需采用Canvas方式
* drawingCache.copy耗时:6-9ms, Canvas方式还更快,所以目前改为Canvas实现
*/
*/
@Throws
fun convertViewToBitmap(targetView: View, width: Int): Bitmap {
// 优化宽高
val recordWidth = if (width % 2 != 0) {
width - 1
} else {
width
}
var recordHeight = if (recordWidth == targetView.width) {
// 宽度不变,则高度也不变
targetView.height
} else {
(targetView.height * (recordWidth.toFloat() / targetView.width)).toInt()
}
if (recordHeight % 2 != 0) {
recordHeight -= 1
}
val bitmap = Bitmap.createBitmap(recordWidth, recordHeight, mBitmapConfig)
val canvas = Canvas(bitmap)
// 保存当前状态,目前只改变一次,多余
//val saveCount = canvas.save()
// 缩放Canvas来匹配目标Bitmap
canvas.scale(recordWidth.toFloat() / targetView.width, recordHeight.toFloat() / targetView.height)
// 将View绘制到Canvas上
targetView.draw(canvas)
// 恢复Canvas状态
//canvas.restoreToCount(saveCount)
return bitmap
}
/**
* @param width 指定宽度,等比例缩放高度
* @param targetView 只是为了算坐标,没其他用
*/
@RequiresApi(Build.VERSION_CODES.O)
@Throws
fun copyPixelFromView(window: Window, targetView: View, width: Int): Bitmap {
//Log.i(TAG, "current Thread: ${Thread.currentThread().name}")
// 优化宽高
val recordWidth = if (width % 2 != 0) {
width - 1
} else {
width
}
var recordHeight = if (recordWidth == targetView.width) {
// 宽度不变,则高度也不变
targetView.height
} else {
(targetView.height * (recordWidth.toFloat() / targetView.width)).toInt()
}
if (recordHeight % 2 != 0) {
recordHeight -= 1
}
// 黑屏
// val bitmap = Bitmap.createBitmap(recordWidth, recordHeight, Bitmap.Config.RGB_565)
//准备一个bitmap对象,用来将copy出来的区域绘制到此对象中,view应该是没有alpha的
val bitmap = Bitmap.createBitmap(recordWidth, recordHeight, mBitmapConfig)
//获取view在Window中的left-top顶点位置,基本上取的当前的window,且录的都是全部,所以都是[0,0]
val location = IntArray(2)
targetView.getLocationInWindow(location)
var isSuccessful = false
//请求转换
//val start = System.currentTimeMillis()
if (!window.isActive) {
return bitmap
}
//val start = System.currentTimeMillis()
//val latch = CountDownLatch(1)
val future = CompletableFuture<Boolean>()
try {
PixelCopy.request(
window,
// 截图区域的取值,左上右下
Rect(
location[0],
location[1],
location[0] + targetView.width,
location[1] + targetView.height
),
bitmap,
{ copyResult ->
// 走完外面才有回调,问题不大,当然最稳妥是回调,但是回调不能同步,得加协程
//Log.i(TAG, "回调内isSuccessful=${copyResult == PixelCopy.SUCCESS}, 耗时=${System.currentTimeMillis() - start}ms")
//isSuccessful = copyResult == PixelCopy.SUCCESS
//latch.countDown()
future.complete(copyResult == PixelCopy.SUCCESS)
},
mMainHandler
)
//latch.await(100, TimeUnit.MILLISECONDS)
isSuccessful = future.get(100, TimeUnit.MILLISECONDS)
} catch (e: Exception) {
e.printStackTrace()
}
return bitmap
}
调用 方式
return RecordViewUtil.getBitmapFromView(window, view, view.width)
}
2.bitmap 转保存 成图片
fun addPhoto(bitmap: Bitmap) {
viewModelScope.launch(Dispatchers.Main) {
val awa = viewModelScope.async(Dispatchers.IO) {
val name = "${System.currentTimeMillis()}.png"
// App.install.cacheDir.absolutePath 是你自定义的地址
val filePath = "${App.install.cacheDir.absolutePath}/image/${name}"
BitmapUtil.saveBitToPath(bitmap, filePath)
bitmap.recycle()
return@async DBUtil.getInstall(App.install)
.addVideoPhoto(VideoPhoto(name, 0, filePath, System.currentTimeMillis()))
}
val id = awa.await()
}
}
```language
/ **保存文件的方法 **/
fun saveBitToPath(bit: Bitmap, filePath: String) {
val file = File(filePath)
file.parentFile?.let {
if (!it.exists()) it.mkdirs()
}
if (!file.exists()) {
file.createNewFile()
}
val bitData = bitToByteArray(bit)
val outputStream = FileOutputStream(file)
outputStream.write(bitData)
outputStream.flush()
outputStream.close()
}
最后 addPhoto(viewScreenshotBit(window ,view)) 窗口 和 需要截图的View
最后 查看保存的图片
然后 我想说的是现在ai 很火 大家有问题就会直接 问gpt dk 等还是希望大家 问ai 的同时 自己的大脑也思考一下为什么 要这样写 不然只做 一个只会问ai 的人 自己本身技术不会有提升 。