如何解决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笔画路径虽未显式闭合,但节点布局导致渲染引擎判定为闭合区域,最终出现填充效果。
修复步骤
给所有路径添加
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')添加全局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>'优化笔画端点(可选)
对个别特殊路径,可添加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
相关产品推荐
相关产品推荐

