如何将 SVG 图像添加到 XSSFWorkBook
How to add SVG image to XSSFWorkBook
在尝试将 SVG
图像添加到 XSSFWorkbook
时,我注意到没有选项可以将 PictureType
设置为 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。
有没有办法将 SVG
图片添加到 XSSFWorkbook
?
对 SVG
的支持是 Microsoft Office 365
的一项新功能。这就是为什么它直到现在(2021 年 5 月,apache poi 5.0.0
)才得到 apache poi
的完全支持。
要在 Excel
中实现该支持,需要了解 Excel
如何插入 SVG
图像。它将图像转换为 PNG
以实现向后兼容性。它将 SVG
图像和 PNG
图像都放入工作簿中。然后它将 PNG
图像显示为绘图中的形状。该形状对 SVG
图像有额外的引用,因此如果使用 Excel 365
,也可以获得 SVG
图像。
要在 apache poi
中实施该支持,需要以下内容:
一个 SVG
到 PNG
的转换器。那里可以用Apache Batik Transcoder
扩展的 XSSFWorkbook
提供单独的 addSVGPicture
方法或在 addPicture
方法中提供对 SVG
的支持。但是扩展 XSSF...
类 并不像它想象的那么简单,因为一些将成员或方法设为私有的奇怪决定。
A XSSFRelation.IMAGE_SVG
在创建图片和形状时提供创建关系。但是 XSSFRelation
根本不可扩展。所以需要延长低位POIXMLRelation
扩展的 XSSFPictureData
为新 POIXMLRelation
所需的图片构造器提供支持。
以下代码提供了所有这些。在需要的地方进行了评论。
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
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
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
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
时,我注意到没有选项可以将 PictureType
设置为 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。
有没有办法将 SVG
图片添加到 XSSFWorkbook
?
对 SVG
的支持是 Microsoft Office 365
的一项新功能。这就是为什么它直到现在(2021 年 5 月,apache poi 5.0.0
)才得到 apache poi
的完全支持。
要在 Excel
中实现该支持,需要了解 Excel
如何插入 SVG
图像。它将图像转换为 PNG
以实现向后兼容性。它将 SVG
图像和 PNG
图像都放入工作簿中。然后它将 PNG
图像显示为绘图中的形状。该形状对 SVG
图像有额外的引用,因此如果使用 Excel 365
,也可以获得 SVG
图像。
要在 apache poi
中实施该支持,需要以下内容:
一个
SVG
到PNG
的转换器。那里可以用Apache Batik Transcoder扩展的
XSSFWorkbook
提供单独的addSVGPicture
方法或在addPicture
方法中提供对SVG
的支持。但是扩展XSSF...
类 并不像它想象的那么简单,因为一些将成员或方法设为私有的奇怪决定。A
XSSFRelation.IMAGE_SVG
在创建图片和形状时提供创建关系。但是XSSFRelation
根本不可扩展。所以需要延长低位POIXMLRelation
扩展的
XSSFPictureData
为新POIXMLRelation
所需的图片构造器提供支持。
以下代码提供了所有这些。在需要的地方进行了评论。
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
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
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
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);
}
}