SVG, точно представляющий то, что нарисовал пользователь.
Цель: Получить данные о пути из введенной пользователем подписи, которая точно представляет его рисунок в приложении.
Проблема: Текущее решение предоставляет неточные данные о пути, которые не неточно представляют рисунок пользователя. Ниже приведен пример того, что в настоящее время печатается, когда пользователь завершает рисование подписи:
Код: Выделить всё
M 390 294 L 391 294 L 392 294 L 393 294 L 394 294 L 395 294 L 396 294 L 397 294 L 398 294 L 399 294 L 400 294 L 401 294 M 384 295 L 385 295 L 386 295 L 387 295 L 388 295 L 389 295 L 390 295 L 391 295 L 392 295 L 393 295 L 394 295 L 395 295 L 396 295 L 397 295 L 398 295 L 399 295 L 400 295 L 401 295 M 376 296 L 377 296 L 378 29...Текущее решение:
Я использую этот пакет для ввода данных пользователем. После того как пользователь завершит свою подпись, пакет возвращает ImageBitmap. Если я отображаю его в пользовательском интерфейсе с помощью компонента Image, он отображается правильно.
Однако, когда я анализирую ImageBitmap с помощью приведенной ниже функции, результирующие данные пути SVG не неточно представляет нарисованную подпись при вставке в реальный SVG.
Вот основной код, обрабатывающий ввод пользователя:
Код: Выделить всё
var imageBitmap: ImageBitmap? by remember { mutableStateOf(null) }
val state = remember { SignatureState() }
var isLoading by remember { mutableStateOf(false) }
Sain(
state = state,
modifier = Modifier.fillMaxWidth().height(159.dp),
signatureThickness = 2.dp,
onComplete = { signatureBitmap ->
if (signatureBitmap != null) {
imageBitmap = signatureBitmap
} else {
println("Signature is empty")
}
},
) { action ->
Row() {
Button(
onClick = {
imageBitmap = null
action(SignatureAction.CLEAR)
}) {
Icon(Icons.Outlined.Delete, contentDescription = "Clear", modifier = Modifier.size(24.dp), tint = Color.Gray)
}
}
Column(modifier = Modifier.fillMaxWidth()) {
Row(modifier = Modifier.fillMaxWidth()) {
Button(onClick = {
isLoading = true
coroutineScope.launch {
action(SignatureAction.COMPLETE)
withContext(Dispatchers.Default) {
val pathData = extractSVGPath(imageBitmap!!)
//print the returned data for testing
println(pathData)
}
withContext(Dispatchers.Main) {
isLoading = false
}
}
},
modifier = Modifier.fillMaxWidth(),
) {
if (isLoading) {
//show a loading icon
} else {
Text(text = "Add Signature")
}
}
}
}
}
Код: Выделить всё
fun extractSVGPath(imageBitmap: ImageBitmap): String {
val bmp = imageBitmap.asAndroidBitmap()
val width = bmp.width
val height = bmp.height
var pathData = StringBuilder("M ")
var lastX = -1
var lastY = -1
for (y in 0 until height) {
for (x in 0 until width) {
val pixel = bmp.getPixel(x, y)
val alpha = (pixel shr 24) and 0xff
if (alpha > 0) {
if (lastX == -1 && lastY == -1) {
pathData.append("$x $y ")
} else {
if (abs(x - lastX) > 1 || abs(y - lastY) > 1) {
pathData.append("M $x $y ")
} else {
pathData.append("L $x $y ")
}
}
lastX = x
lastY = y
}
}
}
return pathData.toString().trim { it
[code]
>
Подробнее здесь: https://stackoverflow.com/questions/783 ... ck-compose
Мобильная версия