]> source.dussan.org Git - poi.git/commitdiff
#62365 - SVG image support in XSLF
authorAndreas Beeker <kiwiwings@apache.org>
Sun, 16 Dec 2018 14:55:23 +0000 (14:55 +0000)
committerAndreas Beeker <kiwiwings@apache.org>
Sun, 16 Dec 2018 14:55:23 +0000 (14:55 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1849030 13f79535-47bb-0310-9956-ffa450edef68

build.gradle
build.xml
sonar/ooxml/pom.xml
sonar/pom.xml
src/java/org/apache/poi/sl/usermodel/PictureData.java
src/ooxml/java/org/apache/poi/xslf/draw/SVGImageRenderer.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureData.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFPictureShape.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFRelation.java
src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFPictureShape.java

index 4a0f9a6e6faefafdfa108c90ef750f53a3cbc27d..63e1d34e8df91b26e0094e9a806f01b0485bc6b0 100644 (file)
@@ -91,7 +91,7 @@ subprojects {
     // See https://github.com/melix/japicmp-gradle-plugin 
     apply plugin: 'me.champeau.gradle.japicmp'
         
-    version = '4.0.1-SNAPSHOT'
+    version = '4.0.2-SNAPSHOT'
     ext {
         japicmpversion = '4.0.0'
     }
@@ -233,6 +233,11 @@ project('ooxml') {
         compile 'org.bouncycastle:bcpkix-jdk15on:1.60'
         compile 'com.github.virtuald:curvesapi:1.05'
 
+        // compile only, don't add it to our dist as it blows up the size
+        compile 'org.apache.xmlgraphics:batik-all:1.10'
+        compile 'xml-apis:xml-apis-ext:1.3.04'
+        compile 'org.apache.xmlgraphics:xmlgraphics-commons:2.3'
+
         // for ooxml-lite, should we move this somewhere else?
         compile 'junit:junit:4.12'
 
index ce3c83c860849a7fae72ceaefdfb36d98b8dae52..d7032dc1c2d949a2ef0b08a708a16b24b888b3ef 100644 (file)
--- a/build.xml
+++ b/build.xml
@@ -217,6 +217,14 @@ under the License.
     <property name="dsig.sl4j-api.jar" location="${compile.lib}/slf4j-api-1.7.25.jar"/>
     <property name="dsig.sl4j-api.url" value="${repository.m2}/maven2/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar"/>
 
+    <!-- svg/batik libs - not part of the distribution -->
+    <property name="svg.batik-all.url" value="${repository.m2}/maven2/org/apache/xmlgraphics/batik-all/1.10/batik-all-1.10.jar"/>
+    <property name="svg.batik-all.jar" value="${compile.lib}/batik-all-1.10.jar"/>
+    <property name="svg.xml-apis-ext.url" value="${repository.m2}/maven2/xml-apis/xml-apis-ext/1.3.04/xml-apis-ext-1.3.04.jar"/>
+    <property name="svg.xml-apis-ext.jar" value="${compile.lib}/xml-apis-ext-1.3.04.jar"/>
+    <property name="svg.xmlgraphics-commons.url" value="${repository.m2}/maven2/org/apache/xmlgraphics/xmlgraphics-commons/2.3/xmlgraphics-commons-2.3.jar"/>
+    <property name="svg.xmlgraphics-commons.jar" value="${compile.lib}/xmlgraphics-commons-2.3.jar"/>
+
     <!-- jars in the ooxml-lib directory, see the fetch-ooxml-jars target-->
     <property name="ooxml.curvesapi.jar" location="${ooxml.lib}/curvesapi-1.05.jar"/>
     <property name="ooxml.curvesapi.url"
@@ -395,6 +403,12 @@ under the License.
         <pathelement location="${scratchpad.output.dir}" unless:true="${scratchpad.ignore}"/>
     </path>
 
+    <path id="batik.classpath">
+        <pathelement location="${svg.batik-all.jar}"/>
+        <pathelement location="${svg.xml-apis-ext.jar}"/>
+        <pathelement location="${svg.xmlgraphics-commons.jar}"/>
+    </path>
+
     <path id="ooxml-lite.classpath">
         <path refid="ooxml.base.classpath"/>
         <!-- instead of ooxml-xsds.jar use the filtered classes-->
@@ -402,11 +416,13 @@ under the License.
         <pathelement location="${ooxml.output.dir}"/>
         <pathelement location="${ooxml.output.test.dir}"/>
         <pathelement location="${main.output.test.dir}"/>
+        <path refid="batik.classpath"/>
     </path>
 
     <path id="ooxml.classpath">
         <pathelement location="${ooxml.xsds.jar}"/>
         <path refid="ooxml.base.classpath"/>
+        <path refid="batik.classpath"/>
     </path>
 
     <path id="ooxml.lite.verify.classpath">
@@ -777,6 +793,9 @@ under the License.
                     <available file="${ooxml.test.reflections.jar}"/>
                     <available file="${ooxml.test.guava.jar}"/>
                     <available file="${ooxml.test.javassist.jar}"/>
+                    <available file="${svg.xml-apis-ext.jar}"/>
+                    <available file="${svg.batik-all.jar}"/>
+                    <available file="${svg.xmlgraphics-commons.jar}"/>
                 </and>
                 <isset property="disconnected"/>
             </or>
@@ -791,6 +810,9 @@ under the License.
         <downloadfile src="${ooxml.test.reflections.url}" dest="${ooxml.test.reflections.jar}"/>
         <downloadfile src="${ooxml.test.guava.url}" dest="${ooxml.test.guava.jar}"/>
         <downloadfile src="${ooxml.test.javassist.url}" dest="${ooxml.test.javassist.jar}"/>
+        <downloadfile src="${svg.batik-all.url}" dest="${svg.batik-all.jar}"/>
+        <downloadfile src="${svg.xml-apis-ext.url}" dest="${svg.xml-apis-ext.jar}"/>
+        <downloadfile src="${svg.xmlgraphics-commons.url}" dest="${svg.xmlgraphics-commons.jar}"/>
     </target>
     <target name="check-svn-jars">
         <condition property="svn.jars.present">
@@ -932,6 +954,7 @@ under the License.
             </xmlbean>
 
             <local name="loaderMethod"/>
+            <!-- the space between "public  static" is on purpose to prevent double execution -->
             <property name="loaderMethod"><![CDATA[
         private static java.lang.ref.SoftReference<org.apache.xmlbeans.SchemaTypeLoader> typeLoader;
 
@@ -944,7 +967,7 @@ under the License.
             return stl;
         }
 
-        public static \2 newInstance\(\) \{]]></property>
+        public  static \2 newInstance\(\) \{]]></property>
 
             <replaceregexp byline="true" match="(\s*)public static ([^ ]+) newInstance\(\) \{" replace="${loaderMethod}">
                 <fileset dir="${xmlbean.sources.dir}" includes="**/*.java" excludes="**/impl/**"/>
index dc4ffc8373ccc160805218b7fcd7a6bab8aa4e32..6a6232acaa074c4ae2b8861e2de029d393466c15 100644 (file)
             <version>1.19</version>
             <scope>test</scope>
         </dependency>
+
+        <dependency>
+            <!-- don't add it to the distribution -->
+            <groupId>org.apache.xmlgraphics</groupId>
+            <artifactId>batik-all</artifactId>
+            <version>1.10</version>
+        </dependency>
     </dependencies>
 </project>
index 3fcaf93e5d6a9ac498a69db76e6058f14065eb4a..c008c3a1c4505a5b6cc92317e70868fae6d0e2da 100644 (file)
                                 </goals>
                                 <configuration>
                                     <target>
-                                        <property name="xmlbean.sources.dir"
-                                                  location="${basedir}/target/generated-sources/xmlbeans"/>
-
+                                        <!-- the space between "public  static" is on purpose to prevent double execution -->
                                         <property name="loaderMethod"><![CDATA[
         private static java.lang.ref.SoftReference<org.apache.xmlbeans.SchemaTypeLoader> typeLoader;
 
             return stl;
         }
 
-        public static \2 newInstance\(\) \{]]></property>
+        public  static \2 newInstance\(\) \{]]></property>
+
+                                        <fileset id="xsrc" dir="${basedir}/target/generated-sources/xmlbeans" includes="**/*.java" excludes="**/impl/**"/>
 
                                         <replaceregexp byline="true"
                                                        match="(\s*)public static ([^ ]+) newInstance\(\) \{"
                                                        replace="${loaderMethod}">
-                                            <fileset dir="${xmlbean.sources.dir}" includes="**/*.java"
-                                                     excludes="**/impl/**"/>
+                                            <fileset refid="xsrc"/>
                                         </replaceregexp>
 
-                                        <replace dir="${xmlbean.sources.dir}" includes="**/*.java"
-                                                 excludes="**/impl/**">
+                                        <replace>
+                                            <fileset refid="xsrc"/>
                                             <replacetoken>org.apache.xmlbeans.XmlBeans.getContextTypeLoader
                                             </replacetoken>
                                             <replacevalue>getTypeLoader</replacevalue>
                                         </replace>
 
                                         <!-- remove deprecated warnings, as we prefer the array methods - see #56854 -->
-                                        <replace dir="${xmlbean.sources.dir}" includes="**/*.java"
-                                                 excludes="**/impl/**">
+                                        <replace>
+                                            <fileset refid="xsrc"/>
                                             <replacetoken><![CDATA[     * @deprecated
 ]]></replacetoken>
                                         </replace>
index 60e6266b7eeebc4656239352ff0f3ca66ddc88d5..0285dd584570209dd0bb735e1ba8c6e7e5c8b2fd 100644 (file)
@@ -46,7 +46,10 @@ public interface PictureData {
         /** WordPerfect graphics (.wpg) */
         WPG(-1,12,"image/x-wpg",".wpg"),
         /** Microsoft Windows Media Photo image (.wdp) */
-        WDP(-1,13,"image/vnd.ms-photo",".wdp");
+        WDP(-1,13,"image/vnd.ms-photo",".wdp"),
+        /** Scalable vector graphics (.svg) - supported by Office 2016 and higher */
+        SVG(-1, -1, "image/svg+xml", ".svg")
+        ;
         
         public final int nativeId, ooxmlId;
         public final String contentType,extension;
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 (file)
index 0000000..2a03dda
--- /dev/null
@@ -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;
+    }
+}
index 881f5fc29b17b1e20d2684cd92c216c7ae29e5b6..b95b8ed356b6ee751b515c681c06e57d880544a9 100644 (file)
@@ -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;
         }
     }
index 9f07b18bac41b85dd859b658bad3efda7d4a222f..b8de62368325a6c9448e068297dde619bad818cb 100644 (file)
 
 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
index 0ea5e349165a85d03f216182d1ec4d77abbcdeae..9b9fc9c8445b6bf20fdbabdb2a6fdb0409ef9ef1 100644 (file)
@@ -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
     );
index 7805bfdd2a3b1398b232b792a016da982f61a5f1..1c1fdf57fc1a75bf44d7bf13e057efd38a8bd021 100644 (file)
 ==================================================================== */
 package org.apache.poi.xslf.usermodel;
 
+import static org.apache.poi.POIDataSamples.TEST_PROPERTY;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
+import java.awt.geom.Rectangle2D;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
+import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.HashMap;
@@ -247,4 +250,24 @@ public class TestXSLFPictureShape {
         
         slideShow.close();
     }
+
+
+    @Test
+    public void renderSvgImage() throws Exception {
+        String dataDirName = System.getProperty(TEST_PROPERTY);
+        final String SVG_FILE = (dataDirName != null ? "../" : "") + "src/documentation/resources/images/project-header.svg";
+        XMLSlideShow ppt = new XMLSlideShow();
+        XSLFSlide slide = ppt.createSlide();
+
+        XSLFPictureData svgPic = ppt.addPicture(new File(dataDirName, SVG_FILE), PictureType.SVG);
+        XSLFPictureShape shape = XSLFPictureShape.addSvgImage(slide, svgPic, PictureType.JPEG, null);
+
+        Rectangle2D anchor = shape.getAnchor();
+        anchor.setRect(100, 100, anchor.getWidth(), anchor.getHeight());
+        shape.setAnchor(anchor);
+
+//        try (FileOutputStream fos = new FileOutputStream("svgtest.pptx")) {
+//            ppt.write(fos);
+//        }
+    }
 }
\ No newline at end of file