data class JAFRSHO31020UiStateDate(
override var screenId: String="JAFRSHO31020",
val currentColor: String="",
val currentWidth: Int=0,
val lines: ArrayDeque<HandDrawnLineModel> = ArrayDeque(),
val currentPoints: List<Pair<Float, Float>> = emptyList(),
val bitmap: ImageBitmap? = null,
): JafUiStateData
data class JAFRSHO31020Model(
/** 画像ファイル */
val filefilePath: String,
) : JafNavModel by DefaultJafNavModel() @HiltViewModel
class JAFRSHO31020ViewModel @Inject constructor(
private val localStorage: LocalStorageRepository
) : JafViewModel<JAFRSHO31020UiStateDate>() {
/** 手書きラインメモリ*/
// private val handDrawnLineMemory = ArrayDeque<HandDrawnLineModel>()
private val _state = mutableStateOf(JAFRSHO31020UiStateDate())
val state: MutableState<JAFRSHO31020UiStateDate> = _state
private val _lines = mutableStateOf<ArrayDeque<HandDrawnLineModel>>(ArrayDeque())
val handDrawnLineMemory: State<ArrayDeque<HandDrawnLineModel>> = _lines
/** 線の色*/
var lineColor: String = ""
/** 線の太さ*/
var lineSize: String = ""
/** 画像ファイル*/
var file: File = File("")
/**
* システムイベント処理
* @param event
*/
override fun onEvent(event: JafEvent) {
when (event) {
is JafEvent.Companion.InitializeWithParameters<*> -> {
val initialParamTmp = event.params as JAFRSHO31020Model
launchWithLoading {
onPopupDisplay(initialParamTmp)
}
}
}
}
/**
* アクション処理
*
* @param action アクション
*/
override fun onAction(action: JafAction) {
when (action) {
is JAFRSHO31020Action.OnConfirm -> {
launchSilent { /*onPopupDisplay()*/ }
}
}
}
/**
* 【JAFRSHO31020E001】画面表示
* @param filePathParam 画像ファイルパス
*/
fun onPopupDisplay(filePathParam: JAFRSHO31020Model) {
//インスタンス変数.画像ファイルを取得する。
file = File(filePathParam.filefilePath)
viewModelScope.launch {
val bitmap = withContext(Dispatchers.IO) {
if (!file.exists()) {
file = File("[実行フォルダー]/Damage/original.jpg")
}
BitmapFactory.decodeFile(file.absolutePath)?.asImageBitmap()
}
_state.value = _state.value.copy(bitmap = bitmap)
}
viewModelScope.launch { // コルーチンを起動する
//インスタンス変数.線の色を設定する。
val lineColorTmp: String? =
localStorage.getMCarWorkSettingInfoList().find { it.parameterName == "線の色" }
?.let { it.parameterValue }
if (lineColorTmp.isNullOrEmpty()) {
lineColor = "#FF0000"//赤色
} else {
lineColor = lineColorTmp
}
//インスタンス変数.線のサイズを設定する。
val lineSizeTmp: String? =
localStorage.getMCarWorkSettingInfoList()
.find { it.parameterName == "線のサイズ" }
?.let { it.parameterValue }
if (lineSizeTmp.isNullOrEmpty()) {
lineSize = "1"//1pt
} else {
lineSize = lineSizeTmp
}
}
}
/**
* 【JAFRSHO31020E003】×(閉じる) - 押下
*/
fun onWindowClose(function: () -> Unit) {
//未確定手書き描画データの存在を判断する。
if (_lines.value.isNotEmpty()) {
showMessage(
Message.JAFRSHO99010IC00086.id,
listOf("未確定の編集画像があります。破棄して戻りますか?"),
onNo = { navigateBack() }
)
}
}
/**
* 【JAFRSHO31020E004】1つ前を削除 - 押下
*/
fun onDelete() {
if (_lines.value.isEmpty()) {
} else {
_lines.value.removeLast()
}
//手書き描画データを保持したメモリ情報の直前のデータを解放する。
}
/**
* 删除全部线条
*/
fun clearAllLines() {
_lines.value.clear()
}
// 添加新线条
fun addLine(line: HandDrawnLineModel) {
_lines.value.addLast(line)
}
fun setBitmap(bitmap: ImageBitmap) {
_state.value = _state.value.copy(bitmap = bitmap)
}
fun startDrawing(x: Float, y: Float) {
_state.value = _state.value.copy(currentPoints = listOf(Pair(x, y)))
}
fun updateDrawing(x: Float, y: Float) {
val newPoints = _state.value.currentPoints + Pair(x, y)
_state.value = _state.value.copy(currentPoints = newPoints)
}
fun endDrawing() {
val currentState = _state.value
if (currentState.currentPoints.size > 1) {
val newLine = HandDrawnLineModel(
color = currentState.currentColor,
width = currentState.currentWidth,
point = currentState.currentPoints
)
val newLines = ArrayDeque(currentState.lines)
newLines.addLast(newLine)
_state.value = currentState.copy(
lines = newLines,
currentPoints = emptyList()
)
}
}
@Composable
fun JAFRSHO31020Popup(
modifier: Modifier = Modifier,
model: JAFRSHO31020Model,
viewModel: JAFRSHO31020ViewModel = hiltViewModel(),
stateData: JAFRSHO31020UiStateDate=JAFRSHO31020UiStateDate(),
) {
JafUiStateHost(
modifier = modifier,
viewModel = viewModel,
params = model
) {
LaunchedEffect(model.filefilePath) {
// 从 File 加载图片
val bitmap = if (File(model.filefilePath).exists()) {
BitmapFactory.decodeFile(File(model.filefilePath).absolutePath)?.asImageBitmap()
} else {
createDefaultBitmap()
}
bitmap?.let { viewModel.setBitmap(it) }
}
Column {
// 操作按钮栏 - 只有三个按钮
Row(
modifier = Modifier
.fillMaxWidth()
.padding(),
horizontalArrangement = Arrangement.SpaceEvenly,
verticalAlignment = Alignment.CenterVertically
) {
// 撤销按钮
JafBottomButton(
text = "撤销",
style = MaterialTheme.typography.buttonText.copy(fontSize = 32.sp),
onClick = {
/*viewModel.onAction(JAFRSHO28060Action.OnRsSho)*/
},
modifier = Modifier.size(220.dp, 78.dp)
)
Button(
onClick = {},
enabled = stateData.lines.isNotEmpty()
) {
Text("撤销", modifier = Modifier.padding(start = 4.dp))
}
// 清空按钮
Button(
onClick = {},
enabled = stateData.lines.isNotEmpty() || stateData.currentPoints.isNotEmpty(),
colors = ButtonDefaults.buttonColors(containerColor = Color.Red)
) {
Icon(Icons.Default.Clear, contentDescription = "清空")
Text(
"清空",
modifier = Modifier.padding(start = 4.dp)
//modifier = Modifier.padding(start = 4.dp)
)
}
// 保存按钮
Button(onClick = {}) {
Text("保存", modifier = Modifier.padding(start = 4.dp))
}
}
// 图片编辑区域
Canvas(
modifier = Modifier
.fillMaxSize()
.background(Color.LightGray)
.pointerInput(Unit) {
detectDragGestures(
onDragStart = { offset ->
viewModel.startDrawing(offset.x, offset.y)
},
onDrag = { change, _ ->
viewModel.updateDrawing(change.position.x, change.position.y)
},
onDragEnd = {
viewModel.endDrawing()
}
)
}
) {
// 绘制原始图片
stateData.bitmap?.let { bitmap ->
drawImage(
image = bitmap,
dstSize = IntSize(size.width.toInt(), size.height.toInt())
)
}
// 绘制已保存的线条
stateData.lines.forEach { line ->
val path = Path().also { path ->
if (line.point.isNotEmpty()) {
path.moveTo(line.point.first().first, line.point.first().second)
line.point.forEach { point ->
path.lineTo(point.first, point.second)
}
}
}
drawPath(
path = path,
color = Color(viewModel.lineColor.toInt()),
style = Stroke(width = line.width.toFloat())
)
}
// 绘制当前正在绘制的线条
if (stateData.currentPoints.isNotEmpty()) {
val currentPath = Path().also { path ->
path.moveTo(
stateData.currentPoints.first().first,
stateData.currentPoints.first().second
)
stateData.currentPoints.forEach { point ->
path.lineTo(point.first, point.second)
}
}
drawPath(
path = currentPath,
color = Color(stateData.currentColor.toInt()),
style = Stroke(width = stateData.currentWidth.toFloat())
)
}
}
}
}
}
private fun createDefaultBitmap(): ImageBitmap? {
return try {
val bitmap = Bitmap.createBitmap(400, 400, Bitmap.Config.ARGB_8888)
val canvas = android.graphics.Canvas(bitmap)
// 填充浅灰色背景
canvas.drawColor(android.graphics.Color.parseColor("#F0F0F0"))
val paint = android.graphics.Paint().apply {
color = android.graphics.Color.DKGRAY
textSize = 36f
textAlign = android.graphics.Paint.Align.CENTER
isAntiAlias = true
}
// 绘制提示文字
canvas.drawText("No Image", 200f, 200f, paint)
bitmap.asImageBitmap()
} catch (e: Exception) {
e.printStackTrace()
null
}
分析一下这些代码,能否实现编辑图片的撤销,清除全部,以及保存,这些代码能否成功运行
最新发布