修复相机拍照问题,优化水印和合成功能
- 修复 ImageCapture 未绑定相机导致的拍照失败问题 - 添加标题/内容文字样式配置支持 - 使用用户配置的水印样式和图片质量 - 修复 Compose API 兼容性问题 (HorizontalDivider, entries) - 修复 Kotlin 版本兼容性问题 - 添加必要的依赖 (accompanist-permissions, coroutines-play-services)
This commit is contained in:
@@ -78,6 +78,7 @@ dependencies {
|
||||
|
||||
// Location
|
||||
implementation("com.google.android.gms:play-services-location:21.0.1")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.7.3")
|
||||
|
||||
// DataStore for preferences
|
||||
implementation("androidx.datastore:datastore-preferences:1.0.0")
|
||||
@@ -85,6 +86,9 @@ dependencies {
|
||||
// Coil for image loading
|
||||
implementation("io.coil-kt:coil-compose:2.5.0")
|
||||
|
||||
// Accompanist permissions
|
||||
implementation("com.google.accompanist:accompanist-permissions:0.32.0")
|
||||
|
||||
// Testing
|
||||
testImplementation("junit:junit:4.13.2")
|
||||
androidTestImplementation("androidx.test.ext:junit:1.1.5")
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.inspection.camera.data.models
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.alpha
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.sp
|
||||
|
||||
@@ -43,6 +43,7 @@ import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
@@ -145,12 +146,13 @@ fun CameraScreen(
|
||||
CameraContent(
|
||||
flashMode = flashMode,
|
||||
onFlashModeChange = { flashMode = it },
|
||||
onCapture = {
|
||||
onCapture = { imageCapture ->
|
||||
if (!isCapturing) {
|
||||
isCapturing = true
|
||||
scope.launch {
|
||||
capturePhoto(
|
||||
context = context,
|
||||
imageCapture = imageCapture,
|
||||
flashMode = flashMode,
|
||||
watermarkStyle = currentWatermarkStyle,
|
||||
imageQuality = currentImageQuality,
|
||||
@@ -183,7 +185,7 @@ fun CameraScreen(
|
||||
private fun CameraContent(
|
||||
flashMode: Int,
|
||||
onFlashModeChange: (Int) -> Unit,
|
||||
onCapture: () -> Unit,
|
||||
onCapture: (ImageCapture) -> Unit,
|
||||
onSettingsClick: () -> Unit,
|
||||
onGalleryClick: () -> Unit,
|
||||
onMergeClick: () -> Unit,
|
||||
@@ -203,7 +205,7 @@ private fun CameraContent(
|
||||
val cameraProvider = cameraProviderFuture.get()
|
||||
|
||||
val preview = Preview.Builder().build().also {
|
||||
it.surfaceProvider = previewView?.surfaceProvider
|
||||
it.setSurfaceProvider(previewView?.surfaceProvider)
|
||||
}
|
||||
|
||||
imageCapture = ImageCapture.Builder()
|
||||
@@ -254,6 +256,7 @@ private fun CameraContent(
|
||||
// 底部控制栏
|
||||
BottomControls(
|
||||
capturedCount = capturedCount,
|
||||
imageCapture = imageCapture,
|
||||
onCapture = onCapture,
|
||||
onGalleryClick = onGalleryClick,
|
||||
onMergeClick = onMergeClick,
|
||||
@@ -303,7 +306,8 @@ private fun TopControls(
|
||||
@Composable
|
||||
private fun BottomControls(
|
||||
capturedCount: Int,
|
||||
onCapture: () -> Unit,
|
||||
imageCapture: ImageCapture?,
|
||||
onCapture: (ImageCapture) -> Unit,
|
||||
onGalleryClick: () -> Unit,
|
||||
onMergeClick: () -> Unit,
|
||||
isCapturing: Boolean,
|
||||
@@ -333,7 +337,7 @@ private fun BottomControls(
|
||||
}
|
||||
|
||||
FloatingActionButton(
|
||||
onClick = onCapture,
|
||||
onClick = { imageCapture?.let { onCapture(it) } },
|
||||
modifier = Modifier.size(72.dp),
|
||||
containerColor = Color.White,
|
||||
shape = CircleShape
|
||||
@@ -402,17 +406,13 @@ private fun PermissionRequest(
|
||||
|
||||
private fun capturePhoto(
|
||||
context: Context,
|
||||
imageCapture: ImageCapture,
|
||||
flashMode: Int,
|
||||
watermarkStyle: WatermarkStyle,
|
||||
imageQuality: ImageQuality,
|
||||
locationText: String,
|
||||
onComplete: (Uri) -> Unit
|
||||
) {
|
||||
val imageCapture = ImageCapture.Builder()
|
||||
.setFlashMode(flashMode)
|
||||
.setCaptureMode(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY)
|
||||
.build()
|
||||
|
||||
val photoFile = File(
|
||||
context.cacheDir,
|
||||
"photo_${System.currentTimeMillis()}.jpg"
|
||||
|
||||
@@ -39,6 +39,7 @@ import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
@@ -56,6 +57,7 @@ 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.ImageItem
|
||||
import com.inspection.camera.data.models.ImageQuality
|
||||
import com.inspection.camera.data.models.MergeLayoutType
|
||||
import com.inspection.camera.data.models.WatermarkStyle
|
||||
@@ -222,8 +224,9 @@ fun MergeScreen(
|
||||
onClick = {
|
||||
scope.launch {
|
||||
previewBitmap = withContext(Dispatchers.Default) {
|
||||
val imageItems = images.map { ImageItem(uri = it, path = it.toString()) }
|
||||
ImageProcessor.mergeImages(
|
||||
images.toList(),
|
||||
imageItems,
|
||||
layoutType,
|
||||
imageQuality
|
||||
).let { bitmap ->
|
||||
@@ -289,8 +292,9 @@ fun MergeScreen(
|
||||
TextButton(onClick = {
|
||||
scope.launch {
|
||||
val bitmap = withContext(Dispatchers.Default) {
|
||||
val imageItems = images.map { ImageItem(uri = it, path = it.toString()) }
|
||||
ImageProcessor.mergeImages(
|
||||
images.toList(),
|
||||
imageItems,
|
||||
layoutType,
|
||||
imageQuality
|
||||
).let { mergedBitmap ->
|
||||
|
||||
@@ -15,8 +15,8 @@ import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.Divider
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
@@ -117,7 +117,7 @@ fun SettingsScreen(
|
||||
// 水印设置
|
||||
SettingsSection(title = "水印设置") {
|
||||
SettingsItem(title = "水印样式") {
|
||||
WatermarkStyle.entries.forEach { style ->
|
||||
listOf(WatermarkStyle.Default, WatermarkStyle.Simple, WatermarkStyle.Bold).forEach { style ->
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
@@ -135,10 +135,10 @@ fun SettingsScreen(
|
||||
}
|
||||
}
|
||||
|
||||
HorizontalDivider()
|
||||
Divider()
|
||||
|
||||
SettingsItem(title = "地点获取方式") {
|
||||
LocationMode.entries.forEach { mode ->
|
||||
LocationMode.values().forEach { mode ->
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
@@ -161,7 +161,7 @@ fun SettingsScreen(
|
||||
}
|
||||
}
|
||||
|
||||
HorizontalDivider()
|
||||
Divider()
|
||||
|
||||
SettingsItem(title = "手动输入地址") {
|
||||
OutlinedTextField(
|
||||
@@ -180,7 +180,7 @@ fun SettingsScreen(
|
||||
// 合成设置
|
||||
SettingsSection(title = "合成设置") {
|
||||
SettingsItem(title = "默认合成布局") {
|
||||
MergeLayoutType.entries.forEach { layout ->
|
||||
MergeLayoutType.values().forEach { layout ->
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
@@ -198,10 +198,10 @@ fun SettingsScreen(
|
||||
}
|
||||
}
|
||||
|
||||
HorizontalDivider()
|
||||
Divider()
|
||||
|
||||
SettingsItem(title = "合成图片质量") {
|
||||
ImageQuality.entries.forEach { quality ->
|
||||
ImageQuality.values().forEach { quality ->
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
@@ -219,10 +219,10 @@ fun SettingsScreen(
|
||||
}
|
||||
}
|
||||
|
||||
HorizontalDivider()
|
||||
Divider()
|
||||
|
||||
SettingsItem(title = "默认标题样式") {
|
||||
WatermarkStyle.entries.forEach { style ->
|
||||
listOf(WatermarkStyle.Default, WatermarkStyle.Simple, WatermarkStyle.Bold).forEach { style ->
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
@@ -240,10 +240,10 @@ fun SettingsScreen(
|
||||
}
|
||||
}
|
||||
|
||||
HorizontalDivider()
|
||||
Divider()
|
||||
|
||||
SettingsItem(title = "默认内容样式") {
|
||||
WatermarkStyle.entries.forEach { style ->
|
||||
listOf(WatermarkStyle.Default, WatermarkStyle.Simple, WatermarkStyle.Bold).forEach { style ->
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
@@ -277,7 +277,7 @@ fun SettingsScreen(
|
||||
)
|
||||
}
|
||||
|
||||
HorizontalDivider()
|
||||
Divider()
|
||||
|
||||
SettingsItem(title = "巡检员信息") {
|
||||
OutlinedTextField(
|
||||
|
||||
@@ -137,12 +137,6 @@ object ImageProcessor {
|
||||
val top = row * cellHeight
|
||||
|
||||
try {
|
||||
val inputStream = imageItem.uri.path?.let { path ->
|
||||
imageItem.uri.let { uri ->
|
||||
inputStream
|
||||
}
|
||||
}
|
||||
|
||||
val sourceBitmap = BitmapFactory.decodeFile(imageItem.path)
|
||||
?: return@forEachIndexed
|
||||
|
||||
|
||||
Reference in New Issue
Block a user