<?xml version="1.0" encoding="UTF-8"?><!--
   ====================================================================
   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.
   ====================================================================
-->
<!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V2.0//EN" "document-v20.dtd">

<document>
    <header>
        <title>Rendering slideshows, WMF, EMF and EMF+</title>
    </header>
    <body>
        <note>Please be aware, that the documentation on this page reflects the current development, which might not
            have been released. If you rely on an unreleased feature, either use a
            <a href="site:download">nightly development build</a> or feel free to ask on the
            <a href="site:mailinglists">mailing list</a> for the release schedule.</note>
        <section>
            <title>Rendering slideshows, WMF, EMF and EMF+</title>
            <p>
                For rendering slideshow (HSLF/XSLF), WMF, EMF and EMF+ pictures, POI provides an utility class
                <a href="https://github.com/apache/poi/tree/trunk/poi-ooxml/src/main/java/org/apache/poi/xslf/util/PPTX2PNG.java?view=markup">
                    PPTX2PNG</a>:
            </p>

            <source><![CDATA[
                Usage: PPTX2PNG [options] <.ppt/.pptx/.emf/.wmf file or 'stdin'>

                Options:
                    -scale <float>    scale factor
                    -fixSide <side>   specify side (long,short,width,height) to fix - use <scale> as amount of pixels
                    -slide <integer>  1-based index of a slide to render
                    -format <type>    png,gif,jpg,svg,pdf (log,null for testing)
                    -outdir <dir>     output directory, defaults to origin of the ppt/pptx file
                    -outfile <file>   output filename, defaults to "${basename}-${slideno}.${format}"
                    -outpat <pattern> output filename pattern, defaults to "${basename}-${slideno}.${format}"
                                      patterns: basename, slideno, format, ext
                    -dump <file>      dump the annotated records to a file
                    -quiet            do not write to console (for normal processing)
                    -ignoreParse      ignore parsing error and continue with the records read until the error
                    -extractEmbedded  extract embedded parts
                    -inputType <type> default input file type (OLE2,WMF,EMF), default is OLE2 = Powerpoint
                                      some files (usually wmf) don't have a header, i.e. an identifiable file magic
                    -textAsShapes     text elements are saved as shapes in SVG, necessary for variable spacing
                                      often found in math formulas
                    -charset <cs>     sets the default charset to be used, defaults to Windows-1252
                    -emfHeaderBounds  force the usage of the emf header bounds to calculate the bounding box

                    -fontdir <dir>    (PDF only) font directories separated by ";" - use $HOME for current users home dir
                                      defaults to the usual plattform directories
                    -fontTtf <regex>  (PDF only) regex to match the .ttf filenames
                    -fontMap <map>    ";"-separated list of font mappings <typeface from>:<typeface to>
                ]]>
            </source>

            <section>
                <title>Instructions to run</title>
                <p>
                    Download the <a href="https://ci-builds.apache.org/job/POI/job/POI-DSL-1.8/lastSuccessfulBuild/artifact/build/dist/">current nightly</a>
                    and for SVG/PDF the <a href="site:components/index/batikpdf">additional dependencies</a>.</p>
                <p>Execute the java command (Unix-paths needs to be replaced for Windows - use "-charset" for non-western WMF/EMFs):</p>
                <source>
                    java -cp poi-5.4.1.jar:poi-ooxml-5.4.1.jar:poi-ooxml-lite-5.4.1.jar:poi-scratchpad-5.4.1.jar:lib/*:ooxml-lib/*:auxiliary/* org.apache.poi.xslf.util.PPTX2PNG -format png -fixside long -scale 1000 -charset GBK file.pptx
                </source>
                <p>
                    If you want to use the renderer on the module path (JPMS) there a currently a few more steps necessary:
                </p>
                <ul>
                    <li>Create a build project using Maven, Gradle or your favorite build tool.</li>
                    <li>Alternatively, download the jars from https://repo1.maven.org/maven2/org/apache/poi/</li>
                    <li>Exclude poi-ooxml-full-5.4.1.jar,poi-javadoc-5.4.1.jar and auxiliary/xml-apis-1.4.01.jar (Java 11+) into new subdirectory "unused"</li>
                    <li>Move all other jars in current directory into a new subdirectory "poi"</li>
                    <li>Invoke PPTX2PNG:
                        <source>
                            java --module-path poi:lib:auxiliary:ooxml-lib --module org.apache.poi.ooxml/org.apache.poi.xslf.util.PPTX2PNG -format png -fixside long -scale 1000 file.pptx
                        </source>
                    </li>
                </ul>
                <note>
                    JDK 1.8 is by default using the PiscesRenderingEngine and affected by
                    <a href="https://github.com/AdoptOpenJDK/openjdk-build/issues/716">Busy loop hangs</a>.
                    To workaround this, use the MarlinRenderingEngine which is experimental provided starting from
                    <a href="https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8143849">openjdk8u252 (JDK-8143849)</a>
                    via <code>-Dsun.java2d.renderer=sun.java2d.marlin.MarlinRenderingEngine</code> or for older jdk builds,
                    <a href="https://github.com/bourgesl/marlin-renderer/wiki/How-to-use">preload the marlin jar</a>.
                </note>
            </section>

        </section>
        <section>
            <title>Integrate rendering in your code</title>
            <section>
                <title>#1 - Use PPTX2PNG via file or stdin</title>
                <p>For file system access, you need to save your slideshow/WMF/EMF/EMF+ first to disc and then call <code>
                    PPTX2PNG.main()
                </code> with the corresponding parameters.
                </p>

                <p>for stdin access, you need to redirect <code>System.in</code> before:
                </p>
                <source><![CDATA[
                    /* the file content */
                    InputStream is = ...;
                    /* Save and set System.in */
                    InputStream oldIn = System.in;
                    try {
                        System.setIn(is);

                        String[] args = {
                            "-format", "png", // png,gif,jpg,svg or null for test
                            "-outdir", new File("out/").getCanonicalPath(),
                            "-outfile", "export.png",
                            "-fixside", "long",
                            "-scale", "800",
                            "-ignoreParse",
                            "stdin"
                        };
                        PPTX2PNG.main(args);

                    } finally {
                        System.setIn(oldIn);
                    }
                ]]></source>
            </section>
            <section>
                <title>#2 - Render WMF / EMF / EMF+ via the *Picture classes</title>
                <source><![CDATA[
                    File f = samples.getFile("santa.wmf");
                    try (FileInputStream fis = new FileInputStream(f)) {
                        // for WMF
                        HwmfPicture wmf = new HwmfPicture(fis);

                        // for EMF / EMF+
                        HemfPicture emf = new HemfPicture(fis);

                        Dimension dim = wmf.getSize();
                        int width = Units.pointsToPixel(dim.getWidth());
                        // keep aspect ratio for height
                        int height = Units.pointsToPixel(dim.getHeight());
                        double max = Math.max(width, height);
                        if (max > 1500) {
                        width *= 1500/max;
                        height *= 1500/max;
                        }

                        BufferedImage bufImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
                        Graphics2D g = bufImg.createGraphics();
                        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                        g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
                        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
                        g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);

                        wmf.draw(g, new Rectangle2D.Double(0,0,width,height));

                        g.dispose();

                        ImageIO.write(bufImg, "PNG", new File("bla.png"));
                    }
                    ]]>
                </source>
            </section>
            <section>
                <title>#3 - Render slideshows directly</title>
                <source><![CDATA[
                    File file = new File("example.pptx");
                    double scale = 1.5;
                    try (SlideShow<?, ?> ss = SlideShowFactory.create(file, null, true)) {
                        Dimension pgsize = ss.getPageSize();
                        int width = (int) (pgsize.width * scale);
                        int height = (int) (pgsize.height * scale);

                        for (Slide<?, ?> slide : ss.getSlides()) {
                            BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
                            Graphics2D graphics = img.createGraphics();

                            // default rendering options
                            graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                            graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
                            graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
                            graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
                            graphics.setRenderingHint(Drawable.BUFFERED_IMAGE, new WeakReference<>(img));

                            graphics.scale(scale, scale);

                            // draw stuff
                            slide.draw(graphics);

                            ImageIO.write(img, "PNG", new File("output.png"));
                            graphics.dispose();
                            img.flush();
                        }
                    }
                ]]></source>
            </section>
        </section>
    </body>
</document>