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

使用Batik转换WMF到SVG时出现NaN路径异常问题

问题

使用Batik的batik-transcoder-1.17和batik-codec-1.17版本将WMF转换为SVG时,生成的SVG路径中出现大量NaN值。转换代码如下:

package org.example;

import java.io.*;

import org.apache.batik.transcoder.TranscoderException;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.wmf.tosvg.WMFTranscoder;

public class WmfImagesToPng1 {

    public static void convert(String wmfFilePath, String svgFilePath) throws IOException, TranscoderException {

        File wmfFile = new File(wmfFilePath);
        File svgFile = new File(svgFilePath);        

        WMFTranscoder transcoder = new WMFTranscoder();

        // Set transcoder hints
        transcoder.addTranscodingHint(WMFTranscoder.KEY_WIDTH, (float) 800); // Set output width
        transcoder.addTranscodingHint(WMFTranscoder.KEY_HEIGHT, (float) 600); // Set output height

        TranscoderInput input = new TranscoderInput(new FileInputStream(wmfFile));

        // Use StringWriter to capture SVG output
        StringWriter writer = new StringWriter();
        TranscoderOutput output = new TranscoderOutput(writer);

        // Perform transcoding
        transcoder.transcode(input, output);

        // Write SVG content to file
        try (FileWriter fileWriter = new FileWriter(svgFile)) {
            fileWriter.write(writer.toString());
        }
    }

    public static void main(String[] args) throws IOException, TranscoderException {
        // Replace these paths with your actual file paths
        String wmfFilePath = "029.wmf";
        String svgFilePath = "output.svg";

        convert(wmfFilePath, svgFilePath);

        System.out.println("WMF file converted to SVG successfully!");
    }
}

转换后的SVG片段示例:

<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.0//EN'
          'http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd'>
<svg stroke-dasharray="none" shape-rendering="auto" xmlns="http://www.w3.org/2000/svg" font-family="'Dialog'" width="800" text-rendering="auto" fill-opacity="1" contentScriptType="text/ecmascript" color-interpolation="auto" color-rendering="auto" preserveAspectRatio="xMidYMid meet" font-size="12px" viewBox="0 0 800 619" fill="black" xmlns:xlink="http://www.w3.org/1999/xlink" stroke="black" image-rendering="auto" stroke-miterlimit="10" zoomAndPan="magnify" version="1.0" stroke-linecap="square" stroke-linejoin="miter" contentStyleType="text/css" font-style="normal" height="619" stroke-width="1" stroke-dashoffset="0" font-weight="normal" stroke-opacity="1"
><!--Generated by the Batik Graphics2D SVG Generator--><defs id="genericDefs"
  /><g
  ><g fill="rgb(102,51,0)" stroke-linecap="butt" stroke-linejoin="round" stroke="rgb(102,51,0)"
    ><path d="MNaN NaN LNaN NaN LNaN NaN LNaN NaN LNaN NaN.....

涉及的WMF文件在多个查看器中可正常渲染,且该问题并非特定图片独有,需明确:

  1. 输出SVG包含NaN的原因
  2. Batik是否支持所有WMF图片
  3. 可行的解决方案

解答

原因分析

  • WMF格式支持局限性:Batik的WMF转码器对WMF标准的实现并不完整,尤其是处理复杂GDI指令、非标准WMF变体时,无法正确解析部分图形操作,导致生成无效的坐标值(NaN)。
  • 强制尺寸引发计算错误:代码中手动指定KEY_WIDTH和KEY_HEIGHT,若原始WMF的尺寸信息未被正确读取,转码器在缩放计算时会出现无效数值运算,进而产生NaN。
  • 转码器版本bug:Batik 1.17的WMFTranscoder存在已知解析缺陷,部分图形指令的处理逻辑不完善,导致坐标计算失败。

解决方案

  • 移除强制尺寸设置:让转码器自动读取WMF原始尺寸,避免手动赋值引发的计算错误,修改代码时删除以下两行:
    // transcoder.addTranscodingHint(WMFTranscoder.KEY_WIDTH, (float) 800);
    // transcoder.addTranscodingHint(WMFTranscoder.KEY_HEIGHT, (float) 600);
    
  • 升级Batik版本:尝试使用Batik最新稳定版(如1.18+),新版本通常会修复旧版的WMF解析bug。
  • 替换转码工具:若Batik无法满足需求,可使用libwmf(通过JNI调用)或命令行工具inkscape(Java调用外部进程)完成WMF转SVG,这类工具对WMF的支持更全面。
  • 预处理转码(牺牲矢量特性):先将WMF转成PNG,再将PNG嵌入SVG,此方法仅适用于无需编辑SVG矢量内容的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 00:27:19