aboutsummaryrefslogtreecommitdiffstats
path: root/src/ooxml/java/org
diff options
context:
space:
mode:
authorAndreas Beeker <kiwiwings@apache.org>2018-12-16 16:51:08 +0000
committerAndreas Beeker <kiwiwings@apache.org>2018-12-16 16:51:08 +0000
commitabe662db86034a0676bc0160e0878fbecefef488 (patch)
treeae844a12de4aafedf5dd44c625c0b1703f668de1 /src/ooxml/java/org
parentcda119e3b8d47bff4ff0b02ccb021d27e31b1aab (diff)
parenta308c6467e7efa4ed128ce6424cbf34e02ae59ec (diff)
downloadpoi-abe662db86034a0676bc0160e0878fbecefef488.tar.gz
poi-abe662db86034a0676bc0160e0878fbecefef488.zip
merge trunkhemf
git-svn-id: https://svn.apache.org/repos/asf/poi/branches/hemf@1849036 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/ooxml/java/org')
-rw-r--r--src/ooxml/java/org/apache/poi/poifs/crypt/dsig/DSigRelation.java62
-rw-r--r--src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureConfig.java28
-rw-r--r--src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java85
-rw-r--r--src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignaturePart.java4
-rw-r--r--src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/KeyInfoSignatureFacet.java6
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/draw/SVGImageRenderer.java136
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureData.java3
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureShape.java114
-rw-r--r--src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFRelation.java35
9 files changed, 413 insertions, 60 deletions
diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/DSigRelation.java b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/DSigRelation.java
new file mode 100644
index 0000000000..707233b074
--- /dev/null
+++ b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/DSigRelation.java
@@ -0,0 +1,62 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.poifs.crypt.dsig;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.poi.ooxml.POIXMLDocumentPart;
+import org.apache.poi.ooxml.POIXMLRelation;
+import org.apache.poi.openxml4j.opc.ContentTypes;
+import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;
+
+public class DSigRelation extends POIXMLRelation {
+ /**
+ * A map to lookup POIXMLRelation by its relation type
+ */
+ private static final Map<String, DSigRelation> _table = new HashMap<>();
+
+ public static final DSigRelation ORIGIN_SIGS = new DSigRelation(
+ ContentTypes.DIGITAL_SIGNATURE_ORIGIN_PART,
+ PackageRelationshipTypes.DIGITAL_SIGNATURE_ORIGIN,
+ "/_xmlsignatures/origin.sigs", null
+ );
+
+ public static final DSigRelation SIG = new DSigRelation(
+ ContentTypes.DIGITAL_SIGNATURE_XML_SIGNATURE_PART,
+ PackageRelationshipTypes.DIGITAL_SIGNATURE,
+ "/_xmlsignatures/sig#.xml", null
+ );
+
+ private DSigRelation(String type, String rel, String defaultName, Class<? extends POIXMLDocumentPart> cls) {
+ super(type, rel, defaultName, cls);
+ _table.put(rel, this);
+ }
+
+ /**
+ * Get POIXMLRelation by relation type
+ *
+ * @param rel relation type, for example,
+ * <code>http://schemas.openxmlformats.org/officeDocument/2006/relationships/image</code>
+ * @return registered POIXMLRelation or null if not found
+ */
+ public static DSigRelation getInstance(String rel) {
+ return _table.get(rel);
+ }
+
+}
diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureConfig.java b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureConfig.java
index 8e276f896e..71a42ef9e1 100644
--- a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureConfig.java
+++ b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureConfig.java
@@ -174,6 +174,13 @@ public class SignatureConfig {
*/
private boolean updateConfigOnValidate = false;
+ /**
+ * if true, the signature is added to the existing signatures
+ *
+ * @since POI 4.0.2
+ */
+ private boolean allowMultipleSignatures = false;
+
/**
* Inits and checks the config object.
@@ -1008,4 +1015,25 @@ public class SignatureConfig {
public void setUpdateConfigOnValidate(boolean updateConfigOnValidate) {
this.updateConfigOnValidate = updateConfigOnValidate;
}
+
+ /**
+ * @return true, if multiple signatures can be attached
+ *
+ * @since POI 4.0.2
+ */
+ public boolean isAllowMultipleSignatures() {
+ return allowMultipleSignatures;
+ }
+
+ /**
+ * Activate multiple signatures
+ *
+ * @param allowMultipleSignatures if true, the signature will be added,
+ * otherwise all existing signatures will be replaced by the current
+ *
+ * @since POI 4.0.2
+ */
+ public void setAllowMultipleSignatures(boolean allowMultipleSignatures) {
+ this.allowMultipleSignatures = allowMultipleSignatures;
+ }
} \ No newline at end of file
diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java
index 20c347d4d7..1cb6e3ca1d 100644
--- a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java
+++ b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java
@@ -59,7 +59,6 @@ import org.apache.jcp.xml.dsig.internal.dom.DOMSignedInfo;
import org.apache.jcp.xml.dsig.internal.dom.DOMSubTreeData;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
-import org.apache.poi.openxml4j.opc.ContentTypes;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackagePartName;
@@ -377,9 +376,8 @@ public class SignatureInfo implements SignatureConfigurable {
xmlSignContext.setURIDereferencer(uriDereferencer);
}
- for (Map.Entry<String,String> me : signatureConfig.getNamespacePrefixes().entrySet()) {
- xmlSignContext.putNamespacePrefix(me.getKey(), me.getValue());
- }
+ signatureConfig.getNamespacePrefixes().forEach(xmlSignContext::putNamespacePrefix);
+
xmlSignContext.setDefaultNamespacePrefix("");
// signatureConfig.getNamespacePrefixes().get(XML_DIGSIG_NS));
@@ -516,9 +514,7 @@ public class SignatureInfo implements SignatureConfigurable {
protected void writeDocument(Document document) throws MarshalException {
XmlOptions xo = new XmlOptions();
Map<String,String> namespaceMap = new HashMap<>();
- for(Map.Entry<String,String> entry : signatureConfig.getNamespacePrefixes().entrySet()){
- namespaceMap.put(entry.getValue(), entry.getKey());
- }
+ signatureConfig.getNamespacePrefixes().forEach((k,v) -> namespaceMap.put(v,k));
xo.setSaveSuggestedPrefixes(namespaceMap);
xo.setUseDefaultNamespace();
@@ -530,43 +526,58 @@ public class SignatureInfo implements SignatureConfigurable {
*/
OPCPackage pkg = signatureConfig.getOpcPackage();
- PackagePartName sigPartName, sigsPartName;
try {
- // <Override PartName="/_xmlsignatures/sig1.xml" ContentType="application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml"/>
- sigPartName = PackagingURIHelper.createPartName("/_xmlsignatures/sig1.xml");
// <Default Extension="sigs" ContentType="application/vnd.openxmlformats-package.digital-signature-origin"/>
- sigsPartName = PackagingURIHelper.createPartName("/_xmlsignatures/origin.sigs");
- } catch (InvalidFormatException e) {
- throw new MarshalException(e);
- }
+ final DSigRelation originDesc = DSigRelation.ORIGIN_SIGS;
+ PackagePartName originPartName = PackagingURIHelper.createPartName(originDesc.getFileName(0));
+
+ PackagePart originPart = pkg.getPart(originPartName);
+ if (originPart == null) {
+ // touch empty marker file
+ originPart = pkg.createPart(originPartName, originDesc.getContentType());
+ pkg.addRelationship(originPartName, TargetMode.INTERNAL, originDesc.getRelation());
+ }
- PackagePart sigPart = pkg.getPart(sigPartName);
- if (sigPart == null) {
- sigPart = pkg.createPart(sigPartName, ContentTypes.DIGITAL_SIGNATURE_XML_SIGNATURE_PART);
- }
+ // <Override PartName="/_xmlsignatures/sig1.xml" ContentType="application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml"/>
+ final DSigRelation sigDesc = DSigRelation.SIG;
+ int nextSigIdx = pkg.getUnusedPartIndex(sigDesc.getDefaultFileName());
+
+ if (!signatureConfig.isAllowMultipleSignatures()) {
+ PackageRelationshipCollection prc = originPart.getRelationshipsByType(sigDesc.getRelation());
+ for (int i=2; i<nextSigIdx; i++) {
+ PackagePartName pn = PackagingURIHelper.createPartName(sigDesc.getFileName(i));
+ for (PackageRelationship rel : prc) {
+ PackagePart pp = originPart.getRelatedPart(rel);
+ if (pp.getPartName().equals(pn)) {
+ originPart.removeRelationship(rel.getId());
+ prc.removeRelationship(rel.getId());
+ break;
+ }
+ }
- try {
- OutputStream os = sigPart.getOutputStream();
- SignatureDocument sigDoc = SignatureDocument.Factory.parse(document, DEFAULT_XML_OPTIONS);
- sigDoc.save(os, xo);
- os.close();
- } catch (Exception e) {
- throw new MarshalException("Unable to write signature document", e);
- }
+ pkg.removePart(pkg.getPart(pn));
+ }
+ nextSigIdx = 1;
+ }
- PackagePart sigsPart = pkg.getPart(sigsPartName);
- if (sigsPart == null) {
- // touch empty marker file
- sigsPart = pkg.createPart(sigsPartName, ContentTypes.DIGITAL_SIGNATURE_ORIGIN_PART);
- }
- PackageRelationshipCollection relCol = pkg.getRelationshipsByType(PackageRelationshipTypes.DIGITAL_SIGNATURE_ORIGIN);
- for (PackageRelationship pr : relCol) {
- pkg.removeRelationship(pr.getId());
- }
- pkg.addRelationship(sigsPartName, TargetMode.INTERNAL, PackageRelationshipTypes.DIGITAL_SIGNATURE_ORIGIN);
+ PackagePartName sigPartName = PackagingURIHelper.createPartName(sigDesc.getFileName(nextSigIdx));
+ PackagePart sigPart = pkg.getPart(sigPartName);
+ if (sigPart == null) {
+ sigPart = pkg.createPart(sigPartName, sigDesc.getContentType());
+ originPart.addRelationship(sigPartName, TargetMode.INTERNAL, sigDesc.getRelation());
+ } else {
+ sigPart.clear();
+ }
+
+ try (OutputStream os = sigPart.getOutputStream()) {
+ SignatureDocument sigDoc = SignatureDocument.Factory.parse(document, DEFAULT_XML_OPTIONS);
+ sigDoc.save(os, xo);
+ }
- sigsPart.addRelationship(sigPartName, TargetMode.INTERNAL, PackageRelationshipTypes.DIGITAL_SIGNATURE);
+ } catch (Exception e) {
+ throw new MarshalException("Unable to write signature document", e);
+ }
}
private Element getDsigElement(final Document document, final String localName) {
diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignaturePart.java b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignaturePart.java
index 81e5b21971..e68b7a72d0 100644
--- a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignaturePart.java
+++ b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignaturePart.java
@@ -185,9 +185,7 @@ public class SignaturePart {
final Map<String,String> nsMap = new HashMap<>();
{
- for (Map.Entry<String,String> me : signatureConfig.getNamespacePrefixes().entrySet()) {
- nsMap.put(me.getValue(), me.getKey());
- }
+ signatureConfig.getNamespacePrefixes().forEach((k,v) -> nsMap.put(v,k));
nsMap.put("dsss", MS_DIGSIG_NS);
nsMap.put("ds", XML_DIGSIG_NS);
}
diff --git a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/KeyInfoSignatureFacet.java b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/KeyInfoSignatureFacet.java
index b3bfe9ecfb..e7797e942d 100644
--- a/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/KeyInfoSignatureFacet.java
+++ b/src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/KeyInfoSignatureFacet.java
@@ -129,10 +129,8 @@ public class KeyInfoSignatureFacet extends SignatureFacet {
DOMSignContext domSignContext = (nextSibling == null)
? new DOMSignContext(key, n)
: new DOMSignContext(key, n, nextSibling);
- for (Map.Entry<String,String> me : signatureConfig.getNamespacePrefixes().entrySet()) {
- domSignContext.putNamespacePrefix(me.getKey(), me.getValue());
- }
-
+ signatureConfig.getNamespacePrefixes().forEach(domSignContext::putNamespacePrefix);
+
DOMStructure domStructure = new DOMStructure(n);
domKeyInfo.marshal(domStructure, domSignContext);
diff --git a/src/ooxml/java/org/apache/poi/xslf/draw/SVGImageRenderer.java b/src/ooxml/java/org/apache/poi/xslf/draw/SVGImageRenderer.java
new file mode 100644
index 0000000000..2a03dda691
--- /dev/null
+++ b/src/ooxml/java/org/apache/poi/xslf/draw/SVGImageRenderer.java
@@ -0,0 +1,136 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.xslf.draw;
+
+import java.awt.Dimension;
+import java.awt.Graphics2D;
+import java.awt.Insets;
+import java.awt.RenderingHints;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.ref.WeakReference;
+
+import org.apache.batik.anim.dom.SAXSVGDocumentFactory;
+import org.apache.batik.bridge.BridgeContext;
+import org.apache.batik.bridge.DocumentLoader;
+import org.apache.batik.bridge.GVTBuilder;
+import org.apache.batik.bridge.UserAgent;
+import org.apache.batik.bridge.UserAgentAdapter;
+import org.apache.batik.ext.awt.RenderingHintsKeyExt;
+import org.apache.batik.ext.awt.image.renderable.ClipRable8Bit;
+import org.apache.batik.gvt.GraphicsNode;
+import org.apache.batik.util.XMLResourceDescriptor;
+import org.apache.poi.sl.draw.ImageRenderer;
+import org.w3c.dom.Document;
+
+public class SVGImageRenderer implements ImageRenderer {
+ private final GVTBuilder builder = new GVTBuilder();
+ private final BridgeContext context;
+ private final SAXSVGDocumentFactory svgFact;
+ private GraphicsNode svgRoot;
+ private double alpha = 1.0;
+
+ public SVGImageRenderer() {
+ String parser = XMLResourceDescriptor.getXMLParserClassName();
+ // TOOO: tell the batik guys to use secure parsing feature
+ svgFact = new SAXSVGDocumentFactory(parser);
+
+ UserAgent agent = new UserAgentAdapter();
+ DocumentLoader loader = new DocumentLoader(agent);
+ context = new BridgeContext(agent, loader);
+ context.setDynamic(true);
+ }
+
+
+ @Override
+ public void loadImage(InputStream data, String contentType) throws IOException {
+ Document document = svgFact.createDocument("", data);
+ svgRoot = builder.build(context, document);
+ }
+
+ @Override
+ public void loadImage(byte[] data, String contentType) throws IOException {
+ loadImage(new ByteArrayInputStream(data), contentType);
+ }
+
+ @Override
+ public Dimension getDimension() {
+ Rectangle2D r = svgRoot.getPrimitiveBounds();
+ return new Dimension((int)Math.ceil(r.getWidth()), (int)Math.ceil(r.getHeight()));
+ }
+
+ @Override
+ public void setAlpha(double alpha) {
+ this.alpha = alpha;
+ }
+
+ @Override
+ public BufferedImage getImage() {
+ return getImage(getDimension());
+ }
+
+ @Override
+ public BufferedImage getImage(Dimension dim) {
+ BufferedImage bi = new BufferedImage((int)dim.getWidth(), (int)dim.getHeight(), BufferedImage.TYPE_INT_ARGB);
+ Graphics2D g2d = (Graphics2D) bi.getGraphics();
+ g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
+ g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
+ g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+ g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
+ g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
+ g2d.setRenderingHint(RenderingHintsKeyExt.KEY_BUFFERED_IMAGE, new WeakReference(bi));
+ Dimension dimSVG = getDimension();
+
+ double scaleX = dim.getWidth() / dimSVG.getWidth();
+ double scaleY = dim.getHeight() / dimSVG.getHeight();
+ g2d.scale(scaleX, scaleY);
+
+ svgRoot.paint(g2d);
+ g2d.dispose();
+
+ return bi;
+ }
+
+ @Override
+ public boolean drawImage(Graphics2D graphics, Rectangle2D anchor) {
+ return drawImage(graphics, anchor, null);
+ }
+
+ @Override
+ public boolean drawImage(Graphics2D graphics, Rectangle2D anchor, Insets clip) {
+ if (clip == null) {
+ svgRoot.setClip(null);
+ } else {
+ Rectangle2D clippedRect = new Rectangle2D.Double(
+ anchor.getX()+clip.left,
+ anchor.getY()+clip.top,
+ anchor.getWidth()-(clip.left+clip.right),
+ anchor.getHeight()-(clip.top+clip.bottom)
+ );
+ svgRoot.setClip(new ClipRable8Bit(null, clippedRect));
+ }
+
+ svgRoot.paint(graphics);
+
+ return true;
+ }
+}
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureData.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureData.java
index 881f5fc29b..b95b8ed356 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureData.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureData.java
@@ -218,6 +218,8 @@ public final class XSLFPictureData extends POIXMLDocumentPart implements Picture
return PictureType.WDP;
} else if (XSLFRelation.IMAGE_TIFF.getContentType().equals(ct)) {
return PictureType.TIFF;
+ } else if (XSLFRelation.IMAGE_SVG.getContentType().equals(ct)) {
+ return PictureType.SVG;
} else {
return null;
}
@@ -237,6 +239,7 @@ public final class XSLFPictureData extends POIXMLDocumentPart implements Picture
case WPG: return XSLFRelation.IMAGE_WPG;
case WDP: return XSLFRelation.IMAGE_WDP;
case TIFF: return XSLFRelation.IMAGE_TIFF;
+ case SVG: return XSLFRelation.IMAGE_SVG;
default: return null;
}
}
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureShape.java
index 9f07b18bac..b8de623683 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureShape.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureShape.java
@@ -19,18 +19,31 @@
package org.apache.poi.xslf.usermodel;
+import static org.apache.poi.openxml4j.opc.PackageRelationshipTypes.CORE_PROPERTIES_ECMA376_NS;
+
+import java.awt.Dimension;
import java.awt.Insets;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
import java.net.URI;
+import javax.imageio.ImageIO;
import javax.xml.namespace.QName;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackageRelationship;
+import org.apache.poi.sl.usermodel.PictureData.PictureType;
import org.apache.poi.sl.usermodel.PictureShape;
import org.apache.poi.sl.usermodel.Placeholder;
import org.apache.poi.util.Beta;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
+import org.apache.poi.util.Units;
+import org.apache.poi.xslf.draw.SVGImageRenderer;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlObject;
@@ -55,6 +68,11 @@ public class XSLFPictureShape extends XSLFSimpleShape
implements PictureShape<XSLFShape,XSLFTextParagraph> {
private static final POILogger LOG = POILogFactory.getLogger(XSLFPictureShape.class);
+ private static final String DML_NS = "http://schemas.microsoft.com/office/drawing/2010/main";
+ private static final String SVG_NS = "http://schemas.microsoft.com/office/drawing/2016/SVG/main";
+ private static final String BITMAP_URI = "{28A0092B-C50C-407E-A947-70E740481C1C}";
+ private static final String SVG_URI = "{96DAC541-7B7A-43D3-8B79-37D633B846F1}";
+
private XSLFPictureData _data;
/*package*/ XSLFPictureShape(CTPicture shape, XSLFSheet sheet) {
@@ -196,6 +214,97 @@ public class XSLFPictureShape extends XSLFSimpleShape
return (r == null) ? null : new Insets(r.getT(), r.getL(), r.getB(), r.getR());
}
+ /**
+ * Add a SVG image reference
+ * @param svgPic a previously imported svg image
+ */
+ public void setSvgImage(XSLFPictureData svgPic) {
+ CTBlip blip = getBlip();
+ CTOfficeArtExtensionList extLst = blip.isSetExtLst() ? blip.getExtLst() : blip.addNewExtLst();
+
+ final int bitmapId = getExt(extLst, BITMAP_URI);
+ CTOfficeArtExtension extBitmap;
+ if (bitmapId == -1) {
+ extBitmap = extLst.addNewExt();
+ extBitmap.setUri(BITMAP_URI);
+ XmlCursor cur = extBitmap.newCursor();
+ cur.toEndToken();
+ cur.beginElement(new QName(DML_NS, "useLocalDpi", "a14"));
+ cur.insertNamespace("a14", DML_NS);
+ cur.insertAttributeWithValue("val", "0");
+ cur.dispose();
+ }
+
+ final int svgId = getExt(extLst, SVG_URI);;
+ if (svgId != -1) {
+ extLst.removeExt(svgId);
+ }
+
+ String svgRelId = getSheet().getRelationId(svgPic);
+ if (svgRelId == null) {
+ svgRelId = getSheet().addRelation(null, XSLFRelation.IMAGE_SVG, svgPic).getRelationship().getId();
+ }
+
+ CTOfficeArtExtension svgBitmap = extLst.addNewExt();
+ svgBitmap.setUri(SVG_URI);
+ XmlCursor cur = svgBitmap.newCursor();
+ cur.toEndToken();
+ cur.beginElement(new QName(SVG_NS, "svgBlip", "asvg"));
+ cur.insertNamespace("asvg", SVG_NS);
+ cur.insertAttributeWithValue(new QName(CORE_PROPERTIES_ECMA376_NS, "embed", "rel"), svgRelId);
+ cur.dispose();
+ }
+
+ /**
+ * Convienence method for adding SVG images, which generates the preview image
+ * @param sheet the sheet to add
+ * @param svgPic the svg picture to add
+ * @param previewType the preview picture type or null (defaults to PNG) - currently only JPEG,GIF,PNG are allowed
+ * @param anchor the image anchor (for calculating the preview image size) or
+ * null (the preview size is taken from the svg picture bounds)
+ */
+ public static XSLFPictureShape addSvgImage(XSLFSheet sheet, XSLFPictureData svgPic, PictureType previewType, Rectangle2D anchor) throws IOException {
+
+ SVGImageRenderer renderer = new SVGImageRenderer();
+ try (InputStream is = svgPic.getInputStream()) {
+ renderer.loadImage(is, svgPic.getType().contentType);
+ }
+
+ Dimension dim = renderer.getDimension();
+ Rectangle2D anc = (anchor != null) ? anchor
+ : new Rectangle2D.Double(0,0, Units.pixelToPoints((int)dim.getWidth()), Units.pixelToPoints((int)dim.getHeight()));
+
+ PictureType pt = (previewType != null) ? previewType : PictureType.PNG;
+ if (pt != PictureType.JPEG || pt != PictureType.GIF || pt != PictureType.PNG) {
+ pt = PictureType.PNG;
+ }
+
+ BufferedImage thmBI = renderer.getImage(dim);
+ ByteArrayOutputStream bos = new ByteArrayOutputStream(100000);
+ // use extension instead of enum name, because of "jpeg"
+ ImageIO.write(thmBI, pt.extension.substring(1), bos);
+
+ XSLFPictureData pngPic = sheet.getSlideShow().addPicture(new ByteArrayInputStream(bos.toByteArray()), pt);
+
+ XSLFPictureShape shape = sheet.createPicture(pngPic);
+ shape.setAnchor(anc);
+ shape.setSvgImage(svgPic);
+ return shape;
+ }
+
+
+ private int getExt(CTOfficeArtExtensionList extLst, String uri) {
+ final int size = extLst.sizeOfExtArray();
+ for (int i=0; i<size; i++) {
+ CTOfficeArtExtension ext = extLst.getExtArray(i);
+ if (uri.equals(ext.getUri())) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+
@Override
void copy(XSLFShape sh){
super.copy(sh);
@@ -219,11 +328,11 @@ public class XSLFPictureShape extends XSLFSimpleShape
nvPr.unsetCustDataLst();
}
if(blip.isSetExtLst()) {
-
+ // TODO: check for SVG copying
CTOfficeArtExtensionList extLst = blip.getExtLst();
//noinspection deprecation
for(CTOfficeArtExtension ext : extLst.getExtArray()){
- String xpath = "declare namespace a14='http://schemas.microsoft.com/office/drawing/2010/main' $this//a14:imgProps/a14:imgLayer";
+ String xpath = "declare namespace a14='"+ DML_NS +"' $this//a14:imgProps/a14:imgLayer";
XmlObject[] obj = ext.selectPath(xpath);
if(obj != null && obj.length == 1){
XmlCursor c = obj[0].newCursor();
@@ -234,6 +343,5 @@ public class XSLFPictureShape extends XSLFSimpleShape
}
}
}
-
}
} \ No newline at end of file
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFRelation.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFRelation.java
index 0ea5e34916..9b9fc9c844 100644
--- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFRelation.java
+++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFRelation.java
@@ -16,6 +16,8 @@
==================================================================== */
package org.apache.poi.xslf.usermodel;
+import static org.apache.poi.openxml4j.opc.PackageRelationshipTypes.IMAGE_PART;
+
import java.util.HashMap;
import java.util.Map;
@@ -159,80 +161,87 @@ public final class XSLFRelation extends POIXMLRelation {
public static final XSLFRelation IMAGE_EMF = new XSLFRelation(
PictureType.EMF.contentType,
- "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
+ IMAGE_PART,
"/ppt/media/image#.emf",
XSLFPictureData.class
);
public static final XSLFRelation IMAGE_WMF = new XSLFRelation(
PictureType.WMF.contentType,
- "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
+ IMAGE_PART,
"/ppt/media/image#.wmf",
XSLFPictureData.class
);
public static final XSLFRelation IMAGE_PICT = new XSLFRelation(
PictureType.PICT.contentType,
- "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
+ IMAGE_PART,
"/ppt/media/image#.pict",
XSLFPictureData.class
);
public static final XSLFRelation IMAGE_JPEG = new XSLFRelation(
PictureType.JPEG.contentType,
- "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
+ IMAGE_PART,
"/ppt/media/image#.jpeg",
XSLFPictureData.class
);
public static final XSLFRelation IMAGE_PNG = new XSLFRelation(
PictureType.PNG.contentType,
- "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
+ IMAGE_PART,
"/ppt/media/image#.png",
XSLFPictureData.class
);
public static final XSLFRelation IMAGE_DIB = new XSLFRelation(
PictureType.DIB.contentType,
- "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
+ IMAGE_PART,
"/ppt/media/image#.dib",
XSLFPictureData.class
);
public static final XSLFRelation IMAGE_GIF = new XSLFRelation(
PictureType.GIF.contentType,
- "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
+ IMAGE_PART,
"/ppt/media/image#.gif",
XSLFPictureData.class
);
public static final XSLFRelation IMAGE_TIFF = new XSLFRelation(
PictureType.TIFF.contentType,
- "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
+ IMAGE_PART,
"/ppt/media/image#.tiff",
XSLFPictureData.class
);
public static final XSLFRelation IMAGE_EPS = new XSLFRelation(
PictureType.EPS.contentType,
- "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
+ IMAGE_PART,
"/ppt/media/image#.eps",
XSLFPictureData.class
);
public static final XSLFRelation IMAGE_BMP = new XSLFRelation(
PictureType.BMP.contentType,
- "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
+ IMAGE_PART,
"/ppt/media/image#.bmp",
XSLFPictureData.class
);
public static final XSLFRelation IMAGE_WPG = new XSLFRelation(
PictureType.WPG.contentType,
- "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
+ IMAGE_PART,
"/ppt/media/image#.wpg",
XSLFPictureData.class
);
public static final XSLFRelation IMAGE_WDP = new XSLFRelation(
PictureType.WDP.contentType,
- "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
+ IMAGE_PART,
"/ppt/media/image#.wdp",
XSLFPictureData.class
);
+ public static final XSLFRelation IMAGE_SVG = new XSLFRelation(
+ PictureType.SVG.contentType,
+ IMAGE_PART,
+ "/ppt/media/image#.svg",
+ XSLFPictureData.class
+ );
+
public static final XSLFRelation IMAGES = new XSLFRelation(
null,
- "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
+ IMAGE_PART,
null,
XSLFPictureData.class
);