完善需求功能:使用用户配置的水印样式和图片质量,添加标题/内容文字样式配置

This commit is contained in:
2026-02-28 00:44:52 +08:00
parent aadfd5a296
commit d8fe374a16
5 changed files with 157 additions and 9 deletions

View File

@@ -62,6 +62,7 @@ import androidx.lifecycle.LifecycleOwner
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.rememberMultiplePermissionsState
import com.inspection.camera.data.PreferencesManager
import com.inspection.camera.data.models.ImageQuality
import com.inspection.camera.data.models.WatermarkStyle
import com.inspection.camera.util.ImageProcessor
import com.inspection.camera.util.LocationHelper
@@ -90,6 +91,7 @@ fun CameraScreen(
var locationText by remember { mutableStateOf("") }
var manualAddress by remember { mutableStateOf("") }
var currentWatermarkStyle by remember { mutableStateOf(WatermarkStyle.Default) }
var currentImageQuality by remember { mutableStateOf(ImageQuality.Standard) }
var showPermissionDeniedDialog by remember { mutableStateOf(false) }
val capturedImages = remember { mutableStateListOf<Uri>() }
@@ -120,6 +122,9 @@ fun CameraScreen(
preferencesManager.manualAddress.collect { address ->
manualAddress = address
}
preferencesManager.imageQuality.collect { quality ->
currentImageQuality = quality
}
}
// 获取位置
@@ -148,6 +153,7 @@ fun CameraScreen(
context = context,
flashMode = flashMode,
watermarkStyle = currentWatermarkStyle,
imageQuality = currentImageQuality,
locationText = if (locationText.isNotBlank()) locationText else "未知地点",
onComplete = { uri ->
capturedImages.add(uri)
@@ -398,6 +404,7 @@ private fun capturePhoto(
context: Context,
flashMode: Int,
watermarkStyle: WatermarkStyle,
imageQuality: ImageQuality,
locationText: String,
onComplete: (Uri) -> Unit
) {
@@ -431,7 +438,7 @@ private fun capturePhoto(
// 保存到相册
val fileName = ImageProcessor.generateFileName("")
val uri = ImageProcessor.saveToGallery(context, watermarkedBitmap, fileName)
val uri = ImageProcessor.saveToGallery(context, watermarkedBitmap, fileName, imageQuality.quality)
bitmap.recycle()
watermarkedBitmap.recycle()

View File

@@ -56,7 +56,9 @@ import androidx.compose.ui.unit.dp
import coil.compose.AsyncImage
import coil.request.ImageRequest
import com.inspection.camera.data.PreferencesManager
import com.inspection.camera.data.models.ImageQuality
import com.inspection.camera.data.models.MergeLayoutType
import com.inspection.camera.data.models.WatermarkStyle
import com.inspection.camera.ui.theme.Primary
import com.inspection.camera.util.ImageProcessor
import kotlinx.coroutines.Dispatchers
@@ -76,12 +78,29 @@ fun MergeScreen(
val images = remember { mutableStateListOf<Uri>().apply { addAll(imageUris) } }
var layoutType by remember { mutableStateOf(MergeLayoutType.Grid2x2) }
var imageQuality by remember { mutableStateOf(ImageQuality.Standard) }
var titleStyle by remember { mutableStateOf(WatermarkStyle.Default) }
var contentStyle by remember { mutableStateOf(WatermarkStyle.Default) }
var showPreview by remember { mutableStateOf(false) }
var previewBitmap by remember { mutableStateOf<Bitmap?>(null) }
var title by remember { mutableStateOf("") }
var content by remember { mutableStateOf("") }
var showSaveDialog by remember { mutableStateOf(false) }
// 加载用户配置
LaunchedEffect(Unit) {
preferencesManager.mergeLayout.collect { layoutType = it }
}
LaunchedEffect(Unit) {
preferencesManager.imageQuality.collect { imageQuality = it }
}
LaunchedEffect(Unit) {
preferencesManager.titleStyle.collect { titleStyle = it }
}
LaunchedEffect(Unit) {
preferencesManager.contentStyle.collect { contentStyle = it }
}
Scaffold(
topBar = {
TopAppBar(
@@ -206,15 +225,15 @@ fun MergeScreen(
ImageProcessor.mergeImages(
images.toList(),
layoutType,
com.inspection.camera.data.models.ImageQuality.Standard
imageQuality
).let { bitmap ->
if (title.isNotBlank() || content.isNotBlank()) {
ImageProcessor.addTextToBitmap(
bitmap,
title,
content,
com.inspection.camera.data.models.WatermarkStyle.Default,
com.inspection.camera.data.models.WatermarkStyle.Default
titleStyle,
contentStyle
)
} else {
bitmap
@@ -273,15 +292,15 @@ fun MergeScreen(
ImageProcessor.mergeImages(
images.toList(),
layoutType,
com.inspection.camera.data.models.ImageQuality.Standard
imageQuality
).let { mergedBitmap ->
if (title.isNotBlank() || content.isNotBlank()) {
ImageProcessor.addTextToBitmap(
mergedBitmap,
title,
content,
com.inspection.camera.data.models.WatermarkStyle.Default,
com.inspection.camera.data.models.WatermarkStyle.Default
titleStyle,
contentStyle
)
} else {
mergedBitmap

View File

@@ -56,6 +56,8 @@ fun SettingsScreen(
var locationMode by remember { mutableStateOf(LocationMode.Network) }
var mergeLayout by remember { mutableStateOf(MergeLayoutType.Grid2x2) }
var imageQuality by remember { mutableStateOf(ImageQuality.Standard) }
var titleStyle by remember { mutableStateOf(WatermarkStyle.Default) }
var contentStyle by remember { mutableStateOf(WatermarkStyle.Default) }
var defaultTheme by remember { mutableStateOf("") }
var inspectorName by remember { mutableStateOf("") }
var manualAddress by remember { mutableStateOf("") }
@@ -73,6 +75,12 @@ fun SettingsScreen(
scope.launch {
preferencesManager.imageQuality.collect { imageQuality = it }
}
scope.launch {
preferencesManager.titleStyle.collect { titleStyle = it }
}
scope.launch {
preferencesManager.contentStyle.collect { contentStyle = it }
}
scope.launch {
preferencesManager.defaultTheme.collect { defaultTheme = it }
}
@@ -210,6 +218,48 @@ fun SettingsScreen(
}
}
}
HorizontalDivider()
SettingsItem(title = "默认标题样式") {
WatermarkStyle.entries.forEach { style ->
Row(
modifier = Modifier
.fillMaxWidth()
.clickable { scope.launch { preferencesManager.setTitleStyle(style) } }
.padding(vertical = 8.dp),
verticalAlignment = Alignment.CenterVertically
) {
RadioButton(
selected = titleStyle.name == style.name,
onClick = { scope.launch { preferencesManager.setTitleStyle(style) } }
)
Spacer(modifier = Modifier.width(8.dp))
Text(style.name)
}
}
}
HorizontalDivider()
SettingsItem(title = "默认内容样式") {
WatermarkStyle.entries.forEach { style ->
Row(
modifier = Modifier
.fillMaxWidth()
.clickable { scope.launch { preferencesManager.setContentStyle(style) } }
.padding(vertical = 8.dp),
verticalAlignment = Alignment.CenterVertically
) {
RadioButton(
selected = contentStyle.name == style.name,
onClick = { scope.launch { preferencesManager.setContentStyle(style) } }
)
Spacer(modifier = Modifier.width(8.dp))
Text(style.name)
}
}
}
}
Spacer(modifier = Modifier.height(16.dp))

View File

@@ -79,9 +79,11 @@ object ImageProcessor {
val y = result.height - padding
// 绘制背景
if (style.backgroundColor != android.graphics.Color.TRANSPARENT) {
// 通过ARGB判断来决定是否绘制背景避免混用 Android Color 与 Compose Color 的类型问题
val bgColorInt = style.backgroundColor.toArgb()
if (bgColorInt != 0) {
val bgPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
color = style.backgroundColor.toArgb()
color = bgColorInt
}
val bgRect = RectF(
x - 10,