2

Excel automatically converts SVG to PNG and saves both the copies.

When we use apache poi v5.0.0to fetch the picture data,

XSSFPicture picture = (XSSFPicture) shape;
System.out.println(picture.getPictureData().suggestFileExtension()); // output: png

we get the PNG format of the picture.

If we want to get the original SVG picture data, we can make use of the following method(Traversal taken from here):

private void traverseShapeContainer(ShapeContainer<XSSFShape> container) {
        for (XSSFShape shape : container) {
            if (shape instanceof XSSFConnector) {
                
            } else if (shape instanceof XSSFGraphicFrame) {

            } else if (shape instanceof XSSFPicture) {
                XSSFPicture picture = (XSSFPicture) shape;
                System.out.println(picture.getPictureData().suggestFileExtension());
                if (picture.getPictureData().suggestFileExtension().equals("png")) {
                    XSSFPictureData svgPictureData = getSVGPicture(picture);
                    if (Objects.nonNull(svgPictureData)) {
                        byte[] svgData = svgPictureData.getData();
                    }
                }
            } else if (shape instanceof XSSFShapeGroup) { // we have a shape group
                XSSFShapeGroup shapeGroup = (XSSFShapeGroup) shape;
                System.out.println(shapeGroup);
                traverseShapeContainer(shapeGroup);
            } else if (shape instanceof XSSFSimpleShape) {
            
            }
        }
    }

    private XSSFPictureData getSVGPicture(XSSFPicture picture) {
        CTOfficeArtExtensionList extLst = picture.getCTPicture().getBlipFill().getBlip().getExtLst();
        if (Objects.nonNull(extLst)) {
            List<CTOfficeArtExtension> extList = extLst.getExtList();
            for (var ext : extList) {
                var extNodes = ext.getDomNode().getChildNodes();
                for (int i = 0; i < extNodes.getLength(); i++) {
                    var extNode = extNodes.item(i);
                    if (extNode.getNodeName().equals("asvg:svgBlip")) {
                        var attr = extNode.getAttributes().getNamedItem("r:embed");
                        if (Objects.nonNull(attr)) {
                            String relationId = attr.getNodeValue();
                            // accesses the drawings.xml.rels to get the data corresponding to the relationId
                            XSSFPictureData svgPictureData = (XSSFPictureData) picture.getDrawing()
                                    .getRelationById(relationId);
                            System.out.println(svgPictureData.suggestFileExtension()); // output: svg
                            return svgPictureData;
                        }
                    }
                }
            }
        }
        return null;
    }

This definitely solves the problem, however is there a better approach to geting the SVG picture data?

dodobird
  • 168
  • 11
  • 2
    Rendering of `SVG` pictures is a new feature of `Excel 365`. Former `Excel` versions was not able to show `SVG` pictures. So `Excel 365` does the conversion to `PNG` for backwards compatibility. `Apache poi` mainly is on level of `Excel 2007` when it comes to `Office Open XML`. So it takes the `*.xlsx` file as `Excel 2007` would do. And `Excel 2007` definitely will not use the `*.svg` image but only the `*.png` image. So no, there ist no better aproach up to now in my opinion. – Axel Richter May 21 '21 at 05:24

0 Answers0