PNG转SVG转换报错:Invalid byte 1 of 1-byte UTF-8 sequence
问题:使用Apache Batik将PNG转SVG时出现UTF-8编码错误
我尝试通过以下Java代码使用Apache Batik的PNGTranscoder将PNG图片转换为SVG:
public class ImageToSVGConverterTool { public static void main(String[] args) { String inputImagePath = "C:\\Users\\path\\facebook.png"; // 替换为你的输入图片路径 String outputSVGPath = "C:\\Users\\path\\OUTPUT\\output_image.svg"; // 替换为目标SVG输出路径 //FileUtils.createNewFile(outputSVGPath); System.out.println(FileUtils.isImageFile(outputSVGPath)); System.out.println(new File(outputSVGPath).isFile()); try { convertImageToSVG(inputImagePath, outputSVGPath); System.out.println("Image converted to SVG successfully."); } catch (Exception e) { e.printStackTrace(); } } public static void convertImageToSVG(String inputImagePath, String outputSVGPath) throws IOException, TranscoderException { File inputFile = new File(inputImagePath); File outputFile = new File(outputSVGPath); ImageTranscoder transcoder = new PNGTranscoder(); // 输入为PNG时改用PNGTranscoder //ImageTranscoder transcoder = new JPEGTranscoder(); // 输入为PNG时改用PNGTranscoder // 设置输出文件 FileOutputStream outputStream = new FileOutputStream(outputFile); TranscoderOutput transcoderOutput = new TranscoderOutput(outputStream); // 设置输入图片 TranscoderInput transcoderInput = new TranscoderInput(inputFile.toURI().toString()); // 执行转换 transcoder.transcode(transcoderInput, transcoderOutput); // 关闭输出流 outputStream.close(); } }
输入文件是从网上下载的facebook.png,输出SVG文件为空,且运行时出现如下错误:
org.apache.batik.transcoder.TranscoderException: null Enclosed Exception: Invalid byte 1 of 1-byte UTF-8 sequence. com.uml.svg.tools.ImageToSVGConverterTool.convertImageToSVG(ImageToSVGConverterTool.java:50) at com.uml.svg.tools.ImageToSVGConverterTool.main(ImageToSVGConverterTool.java:24) Caused by: org.apache.batik.dom.util.SAXIOException: Invalid byte 1 of 1-byte UTF-8 sequence. Caused by: org.xml.sax.SAXParseException; systemId: file:/C:/Users/ravmaddi/Desktop/facebook.png; lineNumber: 1; columnNumber: 1; Invalid byte
请问该如何解决此问题?
解决方案
1. 错误根源:转码方向完全搞反了
Apache Batik的PNGTranscoder核心功能是把SVG文件转成PNG位图,而非将PNG转成SVG。它内部会用SAX解析器读取输入的SVG(XML格式),但你传入的是PNG二进制文件,解析器试图把二进制当作UTF-8编码的XML处理,自然会抛出编码错误。
2. 正确实现方式
根据需求分两种场景处理:
场景一:将PNG嵌入SVG(最简单方案)
如果只是需要生成一个包含该PNG的SVG文件(用<image>标签引用或嵌入),可以直接手动构建SVG内容,无需使用Batik:
import java.io.FileOutputStream; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Base64; import java.io.File; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; public class ImageToSVGConverterTool { public static void main(String[] args) { String inputImagePath = "C:\\Users\\path\\facebook.png"; String outputSVGPath = "C:\\Users\\path\\OUTPUT\\output_image.svg"; try { embedPngIntoSvg(inputImagePath, outputSVGPath); System.out.println("Image embedded into SVG successfully."); } catch (Exception e) { e.printStackTrace(); } } public static void embedPngIntoSvg(String inputImagePath, String outputSVGPath) throws IOException { // 读取PNG并转为Base64(嵌入SVG,无需外部文件依赖) byte[] imageBytes = Files.readAllBytes(Paths.get(inputImagePath)); String base64Image = Base64.getEncoder().encodeToString(imageBytes); // 获取图片原始尺寸 BufferedImage img = ImageIO.read(new File(inputImagePath)); int width = img.getWidth(); int height = img.getHeight(); // 构建标准SVG内容 String svgContent = String.format(""" <svg xmlns="http://www.w3.org/2000/svg" width="%d" height="%d" viewBox="0 0 %d %d"> <image href="data:image/png;base64,%s" width="%d" height="%d"/> </svg> """, width, height, width, height, base64Image, width, height); // 写入SVG文件 try (FileOutputStream outputStream = new FileOutputStream(outputSVGPath)) { outputStream.write(svgContent.getBytes("UTF-8")); } } }
场景二:将PNG矢量化(转为矢量图形)
如果需要把PNG的像素内容转为SVG的矢量路径(比如线条、形状),Batik不支持这个功能,需要使用其他工具:
- 开源工具:可以调用Potrace(命令行工具)或Inkscape的命令行接口来完成矢量化
- 第三方库:比如使用Apache Commons Imaging配合自定义逻辑,或商业矢量转换库
内容的提问来源于stack exchange,提问作者Sun
相关产品推荐
相关产品推荐

