<p>SVG可以直接添加到Word中-只需在Word(2016)中手动试用即可。
我已经为您的用例创建了一个<a href="https://github.com/kiwiwings/poi-examples" rel="nofollow noreferrer">example Java project</a>作为POC。
无需调用inkscape,因为回退PNG是通过Batik动态创建的</p>
<p>当然,OP要求提供Python解决方案——但是如果Python openxml缺少一些功能,那么可能需要付出更多的努力,通过Python来运行它,而不是调用java运行时</p>
<p>关于通过EMF的变通解决方案,请注意,在EMF渲染器(我在POI中实现)中,有多种确定边界的方法,默认情况下,我扫描窗口和视口记录,只有在找不到任何其他内容或通过配置选项忽略扫描时,才使用EMF头边界。这通常会给我更好的结果</p>
<p>示例项目的相关代码snipplet如下所示:</p>
<pre><code>public class AddSvgToDocument {
public static void main(String[] args) throws IOException, InvalidFormatException {
File tmplDocx = new File(args[0]);
File svgFile = new File(args[1]);
File outDocx = new File(args[2]);
try (FileInputStream fis = new FileInputStream(tmplDocx);
XWPFDocument doc = new XWPFDocument(fis)) {
SVGImageRenderer rnd = new SVGImageRenderer();
try (FileInputStream fis2 = new FileInputStream(svgFile)) {
rnd.loadImage(fis2, PictureData.PictureType.SVG.contentType);
}
Rectangle2D nativeDim = rnd.getNativeBounds();
double widthPx = 500;
double heightPx = widthPx * nativeDim.getHeight() / nativeDim.getWidth();
BufferedImage bi = rnd.getImage(new Dimension2DDouble(widthPx, heightPx));
ByteArrayOutputStream bos = new ByteArrayOutputStream(100_000);
ImageIO.write(bi, "PNG", bos);
XWPFRun run = doc.createParagraph().createRun();
int widthEmu = Units.pixelToEMU((int)widthPx);
int heightEmu = Units.pixelToEMU((int)heightPx);
XWPFPicture pic = run.addPicture(new ByteArrayInputStream(bos.toByteArray()), PictureData.PictureType.PNG.ooxmlId, "image.png", widthEmu, heightEmu);
CTOfficeArtExtensionList extLst = pic.getCTPicture().getBlipFill().getBlip().addNewExtLst();
addExt(extLst, "{28A0092B-C50C-407E-A947-70E740481C1C}"
, "http://schemas.microsoft.com/office/drawing/2010/main", "a14:useLocalDpi"
, "val", "0");
addExt(extLst, "{96DAC541-7B7A-43D3-8B79-37D633B846F1}"
, "http://schemas.microsoft.com/office/drawing/2016/SVG/main", "asvg:svgBlip"
, "r:embed", addSVG(doc, svgFile));
try (FileOutputStream fos = new FileOutputStream(outDocx)) {
doc.write(fos);
}
}
}
private static void addExt(CTOfficeArtExtensionList extLst, String uri, String namespace, String name, String attribute, String value) {
CTOfficeArtExtension ext = extLst.addNewExt();
ext.setUri(uri);
XmlCursor cur = ext.newCursor();
cur.toEndToken();
String[] prefixName = name.split(":");
cur.beginElement(new QName(namespace, prefixName[1], prefixName[0]));
cur.insertNamespace(prefixName[0], namespace);
if (attribute.contains(":")) {
prefixName = attribute.split(":");
String prefix = prefixName[0];
String attrNamespace = DEFAULT_XML_OPTIONS
.getSaveSuggestedPrefixes().entrySet().stream()
.filter(me -> prefix.equals(me.getValue()))
.map(Map.Entry::getKey)
.findFirst().orElse(null);
cur.insertAttributeWithValue(new QName(attrNamespace, prefixName[1], prefix), value);
} else {
cur.insertAttributeWithValue(attribute, value);
}
cur.dispose();
}
private static String addSVG(XWPFDocument doc, File svgFile) throws InvalidFormatException, IOException {
// SVG is not thoroughly supported as of POI 5.0.0, hence we need to go the long way instead of adding a picture
OPCPackage pkg = doc.getPackage();
String svgNameTmpl = "/word/media/image#.svg";
int svgImageIdx = pkg.getUnusedPartIndex(svgNameTmpl);
PackagePartName svgPPName = PackagingURIHelper.createPartName(svgNameTmpl.replace("#", Integer.toString(svgImageIdx)));
PackagePart svgPart = pkg.createPart(svgPPName, PictureData.PictureType.SVG.contentType);
try (FileInputStream fis = new FileInputStream(svgFile);
OutputStream os = svgPart.getOutputStream()) {
IOUtils.copy(fis, os);
}
PackageRelationship svgRel = doc.getPackagePart().addRelationship(svgPPName, TargetMode.INTERNAL, IMAGE_PART);
return svgRel.getId();
}
}
</code></pre>