如何将 SVG 图像添加到 XSSFWorkBook [英] How to add SVG image to XSSFWorkBook

查看:31
本文介绍了如何将 SVG 图像添加到 XSSFWorkBook的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在尝试将 SVG 图像添加到 XSSFWorkbook 时,我注意到没有选项可以将 PictureType 设置为 SVG.

While trying to add an SVG image to XSSFWorkbook, I noticed there is no option to set the PictureType to SVG.

FileInputStream in = new FileInputStream("testWorkbook.xlsx");
XSSFWorkbook wb = (XSSFWorkbook)WorkbookFactory.create(in);
InputStream inputStream = new FileInputStream("/home/test/test1.svg");
//Get the contents of an InputStream as a byte[].
byte[] imageData = IOUtils.toByteArray(inputStream);
// XSSFWorkbook.PICTURE_TYPE_SVG is not supported yet.
int pictureIndex = wb.addPicture(imageData, XSSFWorkbook.PICTURE_TYPE_SVG); // Preferred support

但是,我注意到支持将 SVG 图像添加到 XSLF.

However, I noticed there is support for adding SVG images to XSLF.

有没有办法将 SVG 图像添加到 XSSFWorkbook 中?

Is there any way of adding an SVG image to a XSSFWorkbook?

推荐答案

支持 SVGMicrosoft Office 365 的一项新功能.这就是为什么 apache poi 直到现在(2021 年 5 月,apache poi 5.0.0)才完全支持它的原因.

Support for SVG is a new feature of Microsoft Office 365. That's why it is not fully supported by apache poi until now (May 2021, apache poi 5.0.0).

要在 Excel 中实现这种支持,需要知道 Excel 如何插入 SVG 图像.它将图像转换为 PNG 以实现向后兼容性.它将 SVG 图像和 PNG 图像都放入工作簿中.然后它将 PNG 图像显示为绘图中的形状.该形状具有对 SVG 图像的附加引用,因此如果使用 Excel 365,则也可以获得 SVG 图像.

To implement that support in Excel one needs to know how Excel inserts SVG images. It converts the images to PNG for backwards compatibility. And it puts both, the SVG image as well as the PNG image, into the workbook. Then it shows the PNG image as a shape in the drawing. That shape has an additional reference to the SVG image, so if Excel 365 is used, the SVG image can be got too.

要在 apache poi 中实现该支持,需要以下内容:

To implement that support in apache poi following is needed:

  1. SVGPNG 转换器.可以使用 Apache Batik Transcoder.

  1. A SVG to PNG converter. There Apache Batik Transcoder can be used.

扩展的XSSFWorkbook,它提供单独的addSVGPicture 方法或在addPicture 中提供对SVG 的支持> 方法.但是扩展 XSSF... 类并不像它想象的那么简单,因为一些奇怪的决定将成员或方法设为私有.

An extended XSSFWorkbook which provides either a separate addSVGPicture method or provides support for SVG in addPicture method. But extending XSSF... classes is not as simple as it could be, because of some weird decisions to make members or methods private.

A XSSFRelation.IMAGE_SVG 用于在创建图片和形状的同时提供创建关系.但是 XSSFRelation 根本不可扩展.所以需要扩展底层的POIXMLRelation.

A XSSFRelation.IMAGE_SVG to provide creating relations while creating pictures and shapes. But XSSFRelation is not extendable at all. So extending the low level POIXMLRelation is needed.

扩展的 XSSFPictureData 为新的 POIXMLRelation 提供所需的图片构造器的支持.

An extended XSSFPictureData to provide support for needed picture constructors for the new POIXMLRelation.

以下代码提供了所有这些.在需要的地方进行注释.

Following code provides all that. It is commented where needed.

import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;

import java.io.InputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;

class CreateExcelXSSFPictureSVG {
 
 // use org.apache.batik.transcoder to convert SVG to PNG 
 static byte[] svgToPng(InputStream svg) throws Exception {
  org.apache.batik.transcoder.image.PNGTranscoder t = new org.apache.batik.transcoder.image.PNGTranscoder();
  org.apache.batik.transcoder.TranscoderInput input = new org.apache.batik.transcoder.TranscoderInput(svg);
  
  java.io.ByteArrayOutputStream ostream = new java.io.ByteArrayOutputStream();
  org.apache.batik.transcoder.TranscoderOutput output = new org.apache.batik.transcoder.TranscoderOutput(ostream);

  t.transcode(input, output);
  ostream.flush();
  
  return ostream.toByteArray();  
 }
    
 public static void main(String[] args) throws Exception {
     
  String svgFilePath = "./Freesample.svg";
  
  MyXSSFWorkbook workbook = new MyXSSFWorkbook(); // see MyXSSFWorkbook.java

  // add SVG Image to workbook  
  FileInputStream is = new FileInputStream(svgFilePath);
  int svgPictureIdx = workbook.addSVGPicture(is);
  is.close();
  
  // add PNG image to workbook
  is = new FileInputStream(svgFilePath);
  int pngPictureIdx = workbook.addPicture(svgToPng(is), Workbook.PICTURE_TYPE_PNG);
  is.close();

  // create sheet and get drawing
  XSSFSheet sheet = workbook.createSheet("Sheet1");
  XSSFDrawing drawing = sheet.createDrawingPatriarch();
 
  // add SVG Image relation to drawing 
  XSSFPictureData pictureData = workbook.getAllPictures().get(svgPictureIdx);
  org.apache.poi.ooxml.POIXMLDocumentPart.RelationPart rp = drawing.addRelation(null, XSSFRelation.IMAGES, pictureData);
  String svgRId = rp.getRelationship().getId();

  // create anchor for picture shape
  XSSFCreationHelper helper = workbook.getCreationHelper();
  XSSFClientAnchor anchor = helper.createClientAnchor();
  anchor.setCol1(1);
  anchor.setRow1(1); 

  // create PNG picture shape
  XSSFPicture pngPicture = drawing.createPicture(anchor, pngPictureIdx);
  pngPicture.resize();
  
  // set SVG extension to PNG picture shape
  org.openxmlformats.schemas.drawingml.x2006.main.CTOfficeArtExtension ext = pngPicture.getCTPicture().getBlipFill().getBlip().addNewExtLst().addNewExt();
  ext.setUri("{96DAC541-7B7A-43D3-8B79-37D633B846F1}");
  org.apache.xmlbeans.XmlCursor cursor = ext.newCursor();
  cursor.toNextToken();
  cursor.toNextToken();
  cursor.beginElement(new javax.xml.namespace.QName("http://schemas.microsoft.com/office/drawing/2016/SVG/main", "svgBlip", "asvg"));
  cursor.insertNamespace("asvg", "http://schemas.microsoft.com/office/drawing/2016/SVG/main");
  cursor.insertAttributeWithValue(new javax.xml.namespace.QName("http://schemas.openxmlformats.org/officeDocument/2006/relationships", "embed", "r"), svgRId);
  cursor.dispose();

  FileOutputStream out = new FileOutputStream("CreateExcelXSSFPictureSVG.xlsx");
  workbook.write(out);
  out.close();
  workbook.close();

 }
}

使用的扩展类:

MyXSSFWorkbook.java

MyXSSFWorkbook.java

import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFPictureData;
import org.apache.poi.xssf.usermodel.XSSFFactory;
import org.apache.poi.util.IOUtils;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;

import java.lang.reflect.Field;

public class MyXSSFWorkbook extends XSSFWorkbook {

 public int addSVGPicture(InputStream is) throws Exception {
  Field _xssfFactory = XSSFWorkbook.class.getDeclaredField("xssfFactory");
  _xssfFactory.setAccessible(true);
  XSSFFactory xssfFactory = (XSSFFactory)_xssfFactory.get(this);
  
  int imageNumber = getAllPictures().size() + 1;
  
  Field _pictures = XSSFWorkbook.class.getDeclaredField("pictures");
  _pictures.setAccessible(true);
  @SuppressWarnings("unchecked")
  List<XSSFPictureData> pictures = (List<XSSFPictureData>)_pictures.get(this);

  MyXSSFPictureData img = createRelationship(MyXSSFRelation.IMAGE_SVG, xssfFactory, imageNumber, true).getDocumentPart(); // see MyXSSFPictureData.java and MyXSSFRelation.java
  try (OutputStream out = img.getPackagePart().getOutputStream()) {
   IOUtils.copy(is, out);
  }
  pictures.add(img);

  return imageNumber - 1;
 }

}

MyXSSFRelation.java

MyXSSFRelation.java

import org.apache.poi.ooxml.POIXMLRelation;
import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;

public final class MyXSSFRelation extends POIXMLRelation {

 public static final MyXSSFRelation IMAGE_SVG = new MyXSSFRelation(
  "image/svg",
  PackageRelationshipTypes.IMAGE_PART,
  "/xl/media/image#.svg",
  MyXSSFPictureData::new, MyXSSFPictureData::new // see MyXSSFPictureData.java
 );

 private MyXSSFRelation(String type, String rel, String defaultName,
                      NoArgConstructor noArgConstructor,
                      PackagePartConstructor packagePartConstructor) {
  super(type, rel, defaultName, noArgConstructor, packagePartConstructor, null);
 }

}

MyXSSFPictureData.java

MyXSSFPictureData.java

import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.xssf.usermodel.XSSFPictureData; 

public class MyXSSFPictureData extends XSSFPictureData {

 protected MyXSSFPictureData() {
  super();
 }
 
 protected MyXSSFPictureData(PackagePart part) {
  super(part);
 }

}

这篇关于如何将 SVG 图像添加到 XSSFWorkBook的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆