如何将 SVG 图像添加到 XSSFWorkBook [英] How to add SVG image to 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
?
推荐答案
支持 SVG
是 Microsoft 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:
SVG
到PNG
转换器.可以使用 Apache Batik Transcoder.
A
SVG
toPNG
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屋!