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

如何解决KVG汉字定义渲染PNG时路径意外闭合的问题

解决KVG汉字路径意外闭合问题

问题背景

处理KVG汉字定义(对应部件⺕,Unicode码02E95)时,发现kvg:02e95-s1路径被意外填充成闭合区域,而需求是仅显示笔画轮廓。这类问题仅出现在部分汉字的部分笔画上,处理约6000个汉字时偶发。尝试过添加z指令、调整stroke-width、用L指令连接首尾坐标等方法,但首尾坐标不匹配,无法解决。

KVG汉字定义代码

<kanji id="kvg:kanji_02e95">
<g id="kvg:02e95" kvg:element="⺕" kvg:variant="true" kvg:original="彑" kvg:radical="tradit">
    <path id="kvg:02e95-s1" kvg:type="㇕" d="M22.62,22.19c3.12,1.18,6.1,1.24,9.49,1.02c15.13-0.97,31.51-2.34,43.51-3.22c3.24-0.24,5.38,1.25,5,5.17c-1.07,11.19-1.5,35.19-1.6,54.58C79.01,82.8,79,85.74,79,88.5"/>
    <path id="kvg:02e95-s2" kvg:type="㇐" d="M12.25,54.09c3.67,1.22,7.46,0.95,11.23,0.64c18.02-1.48,43.3-3.07,63.02-4.52c4.04-0.3,8.12-0.43,12.12,0.18"/>
    <path id="kvg:02e95-s3" kvg:type="㇐c" d="M22.88,86.88c3.25,1.24,6.03,1.29,9.22,0.93c15.03-1.69,33.02-3.48,46.14-3.95"/>
</g>
</kanji>

渲染代码(Python)

import xml.etree.ElementTree as ET
import cairosvg
from PIL import Image
import io
import os

root = ET.fromstring(xml_data)

# Loop through all elements in the XML
for element in root.iter():
    if 'kanji' in element.tag:
        try:
            # Debug print to check the character code extraction
            character_code = element.attrib.get('id')
            if character_code is None:
                print("Skipping element without 'id' attribute.")
                continue

            character_code = character_code.split('_')[-1]
            print(f"Character code: {character_code}")

            # Extract SVG data from the kanji element with added width and height attributes
            svg_data = f'<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100 "  stroke_width="1">{ET.tostring(element, encoding="unicode")}</svg>'

            # Render SVG to PNG using cairosvg
            png_data = cairosvg.svg2png(bytestring=svg_data.encode('utf-8'))

            # Convert PNG data to a PIL Image
            image = Image.open(io.BytesIO(png_data))

            # Save the image with the character code as the filename under the specified directory
            file_path = os.path.join(output_directory, f'{character_code}.png')
            
            # Display the image in the notebook
            display(image)

            # Display the file path
            print(f"Image saved to: {file_path}")
        except Exception as e:
            # Print any exception that occurred during image creation
            print(f"Error creating image: {e}")

问题现象

渲染后的PNG中,第一个笔画(kvg:02e95-s1)被填充为闭合区域,而非仅显示笔画轮廓。

解决方案

核心原因

SVG路径默认fill属性为black,会填充路径内部。部分KVG笔画路径虽未显式闭合,但节点布局导致渲染引擎判定为闭合区域,最终出现填充效果。

修复步骤

  1. 给所有路径添加fill="none"属性
    强制SVG仅渲染笔画、不填充路径内部,是最直接的解决方法。在生成SVG前遍历所有<path>元素,添加相关属性:

    # 预处理所有path元素,设置填充为无,明确笔画样式
    for path in root.iter('path'):
        path.set('fill', 'none')
        path.set('stroke', 'black')
        path.set('stroke-width', '1')
    
  2. 添加全局SVG样式
    在SVG根元素中插入全局样式,对所有路径统一应用无填充规则:

    svg_data = f'<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><style>path {{ fill: none; stroke: black; stroke-width: 1; }}</style>{ET.tostring(element, encoding="unicode")}</svg>'
    
  3. 优化笔画端点(可选)
    对个别特殊路径,可添加stroke-linecap="round"属性,优化笔画端点的显示效果,避免出现突兀的截断。

优化后的完整代码片段

import xml.etree.ElementTree as ET
import cairosvg
from PIL import Image
import io
import os

root = ET.fromstring(xml_data)

# 预处理所有path元素,设置填充为无,明确笔画样式
for path in root.iter('path'):
    path.set('fill', 'none')
    path.set('stroke', 'black')
    path.set('stroke-width', '1')

# Loop through all elements in the XML
for element in root.iter():
    if 'kanji' in element.tag:
        try:
            character_code = element.attrib.get('id')
            if character_code is None:
                print("Skipping element without 'id' attribute.")
                continue

            character_code = character_code.split('_')[-1]
            print(f"Character code: {character_code}")

            # 生成SVG数据
            svg_data = f'<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100">{ET.tostring(element, encoding="unicode")}</svg>'

            png_data = cairosvg.svg2png(bytestring=svg_data.encode('utf-8'))
            image = Image.open(io.BytesIO(png_data))

            file_path = os.path.join(output_directory, f'{character_code}.png')
            display(image)
            print(f"Image saved to: {file_path}")
        except Exception as e:
            print(f"Error creating image: {e}")

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 06:45:14