Fix compilation errors: remove duplicate methods, add missing imports, fix location manager
This commit is contained in:
@@ -55,348 +55,14 @@ class CameraActivity : AppCompatActivity() {
|
||||
private lateinit var photoPreviewLayout: LinearLayout
|
||||
private var imageCapture: ImageCapture? = null
|
||||
private lateinit var cameraExecutor: ExecutorService
|
||||
private var locationManagerHelper: LocationManagerHelper? = null
|
||||
private var currentLocation: Location? = null
|
||||
|
||||
// 存储拍摄的图片URI
|
||||
private val capturedImageUris = mutableListOf<Uri>()
|
||||
// 图片合成器
|
||||
private val compositor = ImageCompositor()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_main)
|
||||
|
||||
// 初始化视图
|
||||
viewFinder = findViewById(R.id.viewFinder)
|
||||
captureButton = findViewById(R.id.captureButton)
|
||||
settingsButton = findViewById(R.id.settingsButton)
|
||||
photoPreviewLayout = findViewById(R.id.photoPreviewLayout)
|
||||
|
||||
// 请求权限
|
||||
if (allPermissionsGranted()) {
|
||||
startCamera()
|
||||
} else {
|
||||
ActivityCompat.requestPermissions(
|
||||
this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS
|
||||
)
|
||||
}
|
||||
|
||||
// 设置点击监听器
|
||||
captureButton.setOnClickListener { takePhoto() }
|
||||
settingsButton.setOnClickListener { openSettings() }
|
||||
|
||||
// 初始化线程池
|
||||
cameraExecutor = Executors.newSingleThreadExecutor()
|
||||
}
|
||||
|
||||
private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
|
||||
ContextCompat.checkSelfPermission(baseContext, it) == PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
|
||||
private fun startCamera() {
|
||||
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
|
||||
|
||||
cameraProviderFuture.addListener({
|
||||
val cameraProvider = cameraProviderFuture.get()
|
||||
|
||||
val preview = Preview.Builder()
|
||||
.build()
|
||||
.also {
|
||||
it.setSurfaceProvider(viewFinder.surfaceProvider)
|
||||
}
|
||||
|
||||
imageCapture = ImageCapture.Builder()
|
||||
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
|
||||
.build()
|
||||
|
||||
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
|
||||
|
||||
try {
|
||||
cameraProvider.unbindAll()
|
||||
cameraProvider.bindToLifecycle(
|
||||
this, cameraSelector, preview, imageCapture
|
||||
)
|
||||
|
||||
} catch (exc: Exception) {
|
||||
Log.e(TAG, "相机绑定失败", exc)
|
||||
}
|
||||
}, ContextCompat.getMainExecutor(this))
|
||||
}
|
||||
|
||||
private fun takePhoto() {
|
||||
val imageCapture = imageCapture ?: return
|
||||
|
||||
val outputFileOptions = ImageCapture.OutputFileOptions.Builder(
|
||||
createImageUri()
|
||||
).build()
|
||||
|
||||
imageCapture.takePicture(
|
||||
outputFileOptions,
|
||||
ContextCompat.getMainExecutor(this),
|
||||
object : ImageCapture.OnImageSavedCallback {
|
||||
override fun onError(exception: ImageCaptureException) {
|
||||
Log.e(TAG, "照片拍摄失败: ${exception.message}", exception)
|
||||
Toast.makeText(
|
||||
baseContext,
|
||||
"照片拍摄失败: ${exception.message}",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
|
||||
override fun onImageSaved(output: ImageCapture.OutputFileResults) {
|
||||
// 获取保存的URI
|
||||
val savedUri = output.savedUri ?: return
|
||||
|
||||
// 添加水印到已保存的照片
|
||||
addWatermarkToImage(savedUri)
|
||||
|
||||
// 添加到捕获的图片列表
|
||||
capturedImageUris.add(savedUri)
|
||||
|
||||
// 更新预览
|
||||
updatePhotoPreviews()
|
||||
|
||||
Toast.makeText(
|
||||
baseContext,
|
||||
"照片已保存",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
|
||||
// 刷新相册
|
||||
refreshGallery(savedUri)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun createImageUri(): Uri {
|
||||
val contentValues = ContentValues().apply {
|
||||
put(MediaStore.Images.Media.DISPLAY_NAME, "巡检_${System.currentTimeMillis()}.jpg")
|
||||
put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
|
||||
put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis())
|
||||
}
|
||||
}
|
||||
return contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
|
||||
?: throw IOException("无法创建图片URI")
|
||||
}
|
||||
|
||||
private fun addWatermarkToImage(imageUri: Uri) {
|
||||
try {
|
||||
val inputStream = contentResolver.openInputStream(imageUri)
|
||||
val originalBitmap = BitmapFactory.decodeStream(inputStream)
|
||||
inputStream?.close()
|
||||
|
||||
val watermarkedBitmap = addWatermark(originalBitmap)
|
||||
|
||||
// 将带水印的图片保存回原URI
|
||||
val outputStream = contentResolver.openOutputStream(imageUri, "rwt") // truncate and write
|
||||
watermarkedBitmap.compress(Bitmap.CompressFormat.JPEG, 95, outputStream)
|
||||
outputStream?.close()
|
||||
|
||||
// 回收位图以释放内存
|
||||
if (watermarkedBitmap != originalBitmap) {
|
||||
originalBitmap.recycle()
|
||||
}
|
||||
watermarkedBitmap.recycle()
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "添加水印失败: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun addWatermark(bitmap: Bitmap): Bitmap {
|
||||
val watermarkedBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true)
|
||||
val canvas = Canvas(watermarkedBitmap)
|
||||
val paint = Paint().apply {
|
||||
color = Color.WHITE
|
||||
textSize = 48f
|
||||
typeface = Typeface.DEFAULT_BOLD
|
||||
textAlign = Paint.Align.LEFT
|
||||
}
|
||||
|
||||
// 绘制时间水印
|
||||
val timestamp = formatDate(System.currentTimeMillis())
|
||||
canvas.drawText(timestamp, 50f, watermarkedBitmap.height - 100f, paint)
|
||||
|
||||
// 绘制位置水印
|
||||
getCurrentLocation()?.let { location ->
|
||||
val address = getAddressFromLocation(location.latitude, location.longitude)
|
||||
canvas.drawText(address, 50f, watermarkedBitmap.height - 50f, paint)
|
||||
}
|
||||
|
||||
return watermarkedBitmap
|
||||
}
|
||||
|
||||
private fun updatePhotoPreviews() {
|
||||
// 清空当前预览
|
||||
photoPreviewLayout.removeAllViews()
|
||||
|
||||
// 限制最多显示4张预览图
|
||||
val displayCount = minOf(capturedImageUris.size, 4)
|
||||
|
||||
for (i in 0 until displayCount) {
|
||||
val imageView = ImageView(this)
|
||||
val params = LinearLayout.LayoutParams(
|
||||
200, 200
|
||||
).apply {
|
||||
setMargins(8, 8, 8, 8)
|
||||
}
|
||||
imageView.layoutParams = params
|
||||
imageView.scaleType = ImageView.ScaleType.CENTER_CROP
|
||||
|
||||
// 加载并设置图片
|
||||
val uri = capturedImageUris[capturedImageUris.size - displayCount + i] // 显示最新的几张
|
||||
imageView.setImageURI(uri)
|
||||
|
||||
// 添加点击事件以查看大图
|
||||
imageView.setOnClickListener {
|
||||
// 可以在这里实现查看大图的功能
|
||||
}
|
||||
|
||||
photoPreviewLayout.addView(imageView)
|
||||
}
|
||||
|
||||
// 如果已有4张图片,添加合成按钮
|
||||
if (capturedImageUris.size >= 4) {
|
||||
addComposeButton()
|
||||
}
|
||||
}
|
||||
|
||||
private fun addComposeButton() {
|
||||
// 添加合成按钮
|
||||
val composeButton = Button(this)
|
||||
composeButton.text = "合成图片"
|
||||
composeButton.setBackgroundColor(ContextCompat.getColor(this, R.color.purple_200))
|
||||
composeButton.setTextColor(Color.WHITE)
|
||||
|
||||
val params = LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
).apply {
|
||||
setMargins(8, 8, 8, 8)
|
||||
gravity = android.view.Gravity.CENTER_HORIZONTAL
|
||||
}
|
||||
composeButton.layoutParams = params
|
||||
|
||||
composeButton.setOnClickListener {
|
||||
composeLastFourImages()
|
||||
}
|
||||
|
||||
photoPreviewLayout.addView(composeButton)
|
||||
}
|
||||
|
||||
private fun composeLastFourImages() {
|
||||
// 获取最近的4张图片
|
||||
val recentUris = if (capturedImageUris.size >= 4) {
|
||||
capturedImageUris.takeLast(4)
|
||||
} else {
|
||||
capturedImageUris
|
||||
}
|
||||
|
||||
// 将URI转换为Bitmap
|
||||
val bitmaps = mutableListOf<Bitmap>()
|
||||
for (uri in recentUris) {
|
||||
try {
|
||||
val inputStream = contentResolver.openInputStream(uri)
|
||||
val bitmap = BitmapFactory.decodeStream(inputStream)
|
||||
inputStream?.close()
|
||||
bitmaps.add(bitmap)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "加载图片失败: ${e.message}")
|
||||
}
|
||||
}
|
||||
|
||||
if (bitmaps.isEmpty()) {
|
||||
Toast.makeText(this, "没有图片可合成", Toast.LENGTH_SHORT).show()
|
||||
return
|
||||
}
|
||||
|
||||
// 合成图片
|
||||
val composedBitmap = compositor.composeImagesToGrid(bitmaps, 2000, 2000) // 目标尺寸2000x2000
|
||||
|
||||
// 添加标题和内容
|
||||
val finalBitmap = compositor.addTextOverlay(
|
||||
composedBitmap,
|
||||
"巡检报告",
|
||||
"这是巡检内容的详细描述"
|
||||
)
|
||||
|
||||
// 保存合成后的图片
|
||||
saveCompositedImage(finalBitmap)
|
||||
|
||||
// 回收位图
|
||||
for (bitmap in bitmaps) {
|
||||
if (bitmap != finalBitmap) {
|
||||
bitmap.recycle()
|
||||
}
|
||||
}
|
||||
if (finalBitmap != composedBitmap) {
|
||||
composedBitmap.recycle()
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveCompositedImage(bitmap: Bitmap) {
|
||||
try {
|
||||
val fileName = compositor.generateFileName()
|
||||
val contentValues = ContentValues().apply {
|
||||
put(MediaStore.Images.Media.DISPLAY_NAME, fileName)
|
||||
put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
|
||||
put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis())
|
||||
}
|
||||
}
|
||||
|
||||
val uri = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
|
||||
?: throw IOException("无法创建图片URI")
|
||||
|
||||
val outputStream = contentResolver.openOutputStream(uri)
|
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, 95, outputStream)
|
||||
outputStream?.close()
|
||||
|
||||
Toast.makeText(this, "合成图片已保存", Toast.LENGTH_SHORT).show()
|
||||
|
||||
// 刷新相册
|
||||
refreshGallery(uri)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "保存合成图片失败: ${e.message}")
|
||||
Toast.makeText(this, "保存合成图片失败", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun refreshGallery(uri: Uri) {
|
||||
// 通知相册更新
|
||||
val contentValues = ContentValues().apply {
|
||||
put(MediaStore.Images.Media.IS_PENDING, 0)
|
||||
}
|
||||
contentResolver.update(uri, contentValues, null, null)
|
||||
}
|
||||
|
||||
// 将时间戳转换为指定格式的日期时间字符串
|
||||
fun formatDate(timestamp: Long): String {
|
||||
val sdf = SimpleDateFormat("yyyy年-MM月-dd日 HH:mm:ss", Locale.getDefault())
|
||||
return sdf.format(Date(timestamp))
|
||||
}
|
||||
|
||||
// 使用Geocoder将经纬度转换为地址
|
||||
private fun getAddressFromLocation(latitude: Double, longitude: Double): String? {
|
||||
return try {
|
||||
val geocoder = Geocoder(this, Locale.getDefault())
|
||||
val addresses = geocoder.getFromLocation(latitude, longitude, 1)
|
||||
if (addresses?.isEmpty() == false) {
|
||||
val address = addresses[0]
|
||||
val addressLine = address.getAddressLine(0)
|
||||
addressLine ?: "${latitude}, ${longitude}"
|
||||
} else {
|
||||
"${latitude}, ${longitude}"
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "无法解析地址: ${e.message}")
|
||||
"${latitude}, ${longitude}"
|
||||
}
|
||||
}
|
||||
|
||||
private var locationManagerHelper: LocationManagerHelper? = null
|
||||
private var currentLocation: Location? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_main)
|
||||
@@ -451,6 +117,241 @@ class CameraActivity : AppCompatActivity() {
|
||||
cameraExecutor.shutdown()
|
||||
}
|
||||
|
||||
private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
|
||||
ContextCompat.checkSelfPermission(baseContext, it) == PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
|
||||
private fun startCamera() {
|
||||
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
|
||||
|
||||
cameraProviderFuture.addListener({
|
||||
val cameraProvider = cameraProviderFuture.get()
|
||||
|
||||
// 预览
|
||||
val preview = Preview.Builder()
|
||||
.build()
|
||||
.also {
|
||||
it.setSurfaceProvider(viewFinder.surfaceProvider)
|
||||
}
|
||||
|
||||
imageCapture = ImageCapture.Builder()
|
||||
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
|
||||
.build()
|
||||
|
||||
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
|
||||
|
||||
try {
|
||||
cameraProvider.unbindAll()
|
||||
cameraProvider.bindToLifecycle(
|
||||
this, cameraSelector, preview, imageCapture
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "相机绑定失败", e)
|
||||
}
|
||||
}, ContextCompat.getMainExecutor(this))
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
private fun takePhoto() {
|
||||
val imageCapture = this.imageCapture ?: return
|
||||
|
||||
val outputOptions = createOutputFileOptions()
|
||||
|
||||
imageCapture.takePicture(
|
||||
outputOptions,
|
||||
ContextCompat.getMainExecutor(this),
|
||||
object : ImageCapture.OnImageSavedCallback {
|
||||
override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
|
||||
val savedUri = outputFileResults.savedUri ?: return
|
||||
capturedImageUris.add(savedUri)
|
||||
showPhotoPreview(savedUri)
|
||||
|
||||
// 如果已经有4张照片,显示合成按钮
|
||||
if (capturedImageUris.size >= 4) {
|
||||
showComposeButton()
|
||||
}
|
||||
|
||||
val msg = "照片已保存: ${savedUri.lastPathSegment}"
|
||||
Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
|
||||
Log.d(TAG, msg)
|
||||
}
|
||||
|
||||
override fun onError(exception: ImageCaptureException) {
|
||||
Log.e(TAG, "拍照失败: ${exception.message}", exception)
|
||||
Toast.makeText(baseContext, "拍照失败", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun createOutputFileOptions(): ImageCapture.OutputFileOptions {
|
||||
val timestamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
|
||||
|
||||
val contentValues = ContentValues().apply {
|
||||
put(MediaStore.MediaColumns.DISPLAY_NAME, "巡检_$timestamp")
|
||||
put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
put(MediaStore.MediaColumns.RELATIVE_PATH, "Pictures/LogCam")
|
||||
}
|
||||
}
|
||||
|
||||
val contentResolver = contentResolver
|
||||
val uri = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
|
||||
|
||||
return ImageCapture.OutputFileOptions.Builder(contentResolver, uri).build()
|
||||
}
|
||||
|
||||
private fun showPhotoPreview(uri: Uri) {
|
||||
val imageView = ImageView(this)
|
||||
val layoutParams = LinearLayout.LayoutParams(120, 120)
|
||||
layoutParams.marginEnd = 8
|
||||
imageView.layoutParams = layoutParams
|
||||
imageView.scaleType = ImageView.ScaleType.CENTER_CROP
|
||||
|
||||
try {
|
||||
val inputStream = contentResolver.openInputStream(uri)
|
||||
val bitmap = BitmapFactory.decodeStream(inputStream)
|
||||
inputStream?.close()
|
||||
imageView.setImageBitmap(bitmap)
|
||||
} catch (e: IOException) {
|
||||
Log.e(TAG, "预览图片加载失败", e)
|
||||
}
|
||||
|
||||
photoPreviewLayout.addView(imageView)
|
||||
}
|
||||
|
||||
private fun showComposeButton() {
|
||||
// 添加合成按钮到预览区域
|
||||
val composeButton = Button(this)
|
||||
composeButton.text = "合成图片"
|
||||
composeButton.setOnClickListener { composeImages() }
|
||||
|
||||
val layoutParams = LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
layoutParams.marginStart = 16
|
||||
composeButton.layoutParams = layoutParams
|
||||
|
||||
photoPreviewLayout.addView(composeButton)
|
||||
}
|
||||
|
||||
private fun composeImages() {
|
||||
if (capturedImageUris.size < 4) {
|
||||
Toast.makeText(this, "需要至少4张图片进行合成", Toast.LENGTH_SHORT).show()
|
||||
return
|
||||
}
|
||||
|
||||
// 获取最近4张图片
|
||||
val recentUris = capturedImageUris.takeLast(4)
|
||||
val bitmaps = mutableListOf<Bitmap>()
|
||||
|
||||
for (uri in recentUris) {
|
||||
try {
|
||||
val inputStream = contentResolver.openInputStream(uri)
|
||||
val bitmap = BitmapFactory.decodeStream(inputStream)
|
||||
inputStream?.close()
|
||||
bitmap?.let { bitmaps.add(it) }
|
||||
} catch (e: IOException) {
|
||||
Log.e(TAG, "加载图片失败: $uri", e)
|
||||
}
|
||||
}
|
||||
|
||||
if (bitmaps.size < 4) {
|
||||
Toast.makeText(this, "部分图片加载失败", Toast.LENGTH_SHORT).show()
|
||||
return
|
||||
}
|
||||
|
||||
// 合成图片
|
||||
val composedBitmap = compositor.composeImages(bitmaps, "巡检报告", "合成时间: ${Date()}")
|
||||
|
||||
// 保存合成图片
|
||||
val timestamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
|
||||
val contentValues = ContentValues().apply {
|
||||
put(MediaStore.MediaColumns.DISPLAY_NAME, "巡检合成_$timestamp")
|
||||
put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
put(MediaStore.MediaColumns.RELATIVE_PATH, "Pictures/LogCam")
|
||||
}
|
||||
}
|
||||
|
||||
val contentResolver = contentResolver
|
||||
val uri = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
|
||||
|
||||
if (uri != null) {
|
||||
try {
|
||||
val outputStream: OutputStream? = contentResolver.openOutputStream(uri)
|
||||
if (outputStream != null) {
|
||||
composedBitmap.compress(Bitmap.CompressFormat.JPEG, 90, outputStream)
|
||||
outputStream.close()
|
||||
|
||||
Toast.makeText(this, "图片合成成功", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
Log.e(TAG, "保存合成图片失败", e)
|
||||
Toast.makeText(this, "保存失败", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAddressFromLocation(location: Location): String {
|
||||
val geocoder = Geocoder(this, Locale.getDefault())
|
||||
|
||||
return try {
|
||||
val addresses = geocoder.getFromLocation(
|
||||
location.latitude,
|
||||
location.longitude,
|
||||
1
|
||||
)
|
||||
|
||||
if (addresses != null && addresses.isNotEmpty()) {
|
||||
val address = addresses[0]
|
||||
"${address.locality}, ${address.subLocality}, ${address.thoroughfare}"
|
||||
} else {
|
||||
"${location.latitude.roundToInt()}, ${location.longitude.roundToInt()}"
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "无法解析地址: ${e.message}")
|
||||
"${location.latitude.roundToInt()}, ${location.longitude.roundToInt()}"
|
||||
}
|
||||
}
|
||||
|
||||
private fun getLocationString(): String {
|
||||
val location = getCurrentLocation()
|
||||
return if (location != null) {
|
||||
getAddressFromLocation(location)
|
||||
} else {
|
||||
"未知位置"
|
||||
}
|
||||
}
|
||||
|
||||
private fun addWatermarkToBitmap(originalBitmap: Bitmap): Bitmap {
|
||||
val timestamp = SimpleDateFormat("yyyy年-MM月-dd日 HH:mm:ss", Locale.getDefault()).format(Date())
|
||||
val location = getLocationString()
|
||||
|
||||
val watermarkText = "$timestamp\n$location"
|
||||
|
||||
val mutableBitmap = originalBitmap.copy(Bitmap.Config.ARGB_8888, true)
|
||||
val canvas = Canvas(mutableBitmap)
|
||||
|
||||
val paint = Paint().apply {
|
||||
color = Color.WHITE
|
||||
textSize = 32f
|
||||
typeface = Typeface.DEFAULT_BOLD
|
||||
setShadowLayer(5f, 0f, 0f, Color.BLACK)
|
||||
}
|
||||
|
||||
val textWidth = paint.measureText(watermarkText)
|
||||
val textHeight = paint.descent() - paint.ascent()
|
||||
|
||||
val x = 20f
|
||||
val y = mutableBitmap.height - textHeight - 20f
|
||||
|
||||
canvas.drawText(watermarkText, x, y, paint)
|
||||
|
||||
return mutableBitmap
|
||||
}
|
||||
|
||||
private fun openSettings() {
|
||||
// 打开设置页面
|
||||
val settingsFragment = SettingsFragment()
|
||||
@@ -472,9 +373,4 @@ class CameraActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
cameraExecutor.shutdown()
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.example.app
|
||||
|
||||
import android.graphics.*
|
||||
import android.text.StaticLayout
|
||||
import android.text.Layout
|
||||
import java.io.File
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
Reference in New Issue
Block a user