You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose中从ImageBitmap提取SVG路径数据的问题

Jetpack Compose签名转SVG路径的精准还原问题

我正在开发Jetpack Compose安卓应用,需要将用户手绘签名转换为SVG <path> 标签可用的格式,精准还原用户绘制内容。

目标

获取能精准还原用户手绘签名的SVG路径数据。

当前问题

现有方案生成的路径数据不准确,无法完整还原签名。比如简单线条会生成大量重复的M/L指令,导入SVG后无法完整显示签名。

当前实现方案

使用Sain包处理用户签名输入,完成后返回ImageBitmap,UI显示正常,但通过自定义extractSVGPath函数解析后得到的路径数据无法准确还原签名。

核心UI代码

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!!)
                        // 测试打印返回数据
                        println(pathData)
                    }
                    withContext(Dispatchers.Main) {
                        isLoading = false
                    }
                }
            },
                modifier = Modifier.fillMaxWidth(),
            ) {
                if (isLoading) {
                    // 显示加载图标
                } 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 <= ' ' }
}

正确SVG路径示例

<svg xmlns="http://www.w3.org/2000/svg" width="350" height="150" viewBox="0 0 350 150" fill="none">
<path d="M 150.40625 41.5 L 150.40625 41.5 L 150.40625 42.5 L 150.40625 50.5 L 150.40625 59.5 L 150.40625 63.5 L 149.40625 66.5 L 148.40625 68.5 L 146.40625 69.5 L 145.40625 69.5 L 145.40625 68.5 L 145.40625 68.5 L 149.40625 68.5 L 155.40625 68.5 L 162.40625 68.5" stroke="black" stroke-width="1" fill="none"/>
</svg>

寻求解决方案

现寻求以下方向的可行方案:

  • 替代的签名输入包(能直接输出SVG路径或原始触摸轨迹数据)
  • 更优的ImageBitmap解析方式,生成精准的SVG路径数据

内容的提问来源于stack exchange,提问作者timval

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 03:12:42