import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.lang.ref.WeakReference;
import javax.imageio.ImageIO;
import org.apache.poi.hslf.usermodel.HSLFSlide;
import org.apache.poi.hslf.usermodel.HSLFSlideShow;
+import org.apache.poi.sl.draw.Drawable;
+import org.apache.poi.xslf.util.PPTX2PNG;
/**
* Demonstrates how you can use HSLF to convert each slide into a PNG image
*/
-public final class PPT2PNG {
-
- public static void main(String args[]) throws IOException {
-
- if (args.length == 0) {
- usage();
- return;
- }
-
- int slidenum = -1;
- float scale = 1;
- String file = null;
-
- for (int i = 0; i < args.length; i++) {
- if (args[i].startsWith("-")) {
- if ("-scale".equals(args[i])){
- scale = Float.parseFloat(args[++i]);
- } else if ("-slide".equals(args[i])) {
- slidenum = Integer.parseInt(args[++i]);
- }
- } else {
- file = args[i];
- }
- }
- if(file == null){
- usage();
- return;
- }
-
- FileInputStream is = new FileInputStream(file);
- HSLFSlideShow ppt = new HSLFSlideShow(is);
- is.close();
-
- Dimension pgsize = ppt.getPageSize();
- int width = (int)(pgsize.width*scale);
- int height = (int)(pgsize.height*scale);
-
- for (HSLFSlide slide : ppt.getSlides()) {
- if (slidenum != -1 && slidenum != slide.getSlideNumber()) {
- continue;
- }
-
- String title = slide.getTitle();
- System.out.println("Rendering slide "+slide.getSlideNumber() + (title == null ? "" : ": " + title));
-
- BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
- Graphics2D graphics = img.createGraphics();
- 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.setPaint(Color.white);
- graphics.fill(new Rectangle2D.Float(0, 0, width, height));
-
- graphics.scale((double)width/pgsize.width, (double)height/pgsize.height);
-
- slide.draw(graphics);
-
- String fname = file.replaceAll("\\.ppt", "-" + slide.getSlideNumber() + ".png");
- FileOutputStream out = new FileOutputStream(fname);
- ImageIO.write(img, "png", out);
- out.close();
- }
-
- ppt.close();
- }
+public final class PPT2PNG extends PPTX2PNG {
private static void usage(){
System.out.println("Usage: PPT2PNG [-scale <scale> -slide <num>] ppt");
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.lang.ref.WeakReference;
-import org.apache.poi.sl.draw.DrawFactory;
+import org.apache.poi.sl.draw.Drawable;
import org.apache.poi.sl.usermodel.PictureData;
import org.apache.poi.sl.usermodel.Shape;
import org.apache.poi.sl.usermodel.ShapeContainer;
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));
// draw stuff
s.draw(graphics);
@Override
public void drawContent(Graphics2D graphics) {
- PictureData data = getShape().getPictureData();
- if(data == null) return;
-
- Rectangle2D anchor = getAnchor(graphics, getShape());
- Insets insets = getShape().getClipping();
-
- try {
- ImageRenderer renderer = getImageRenderer(graphics, data.getContentType());
- renderer.loadImage(data.getData(), data.getContentType());
- renderer.drawImage(graphics, anchor, insets);
- } catch (IOException e) {
- LOG.log(POILogger.ERROR, "image can't be loaded/rendered.", e);
+ PictureShape<?,?> ps = getShape();
+
+ Rectangle2D anchor = getAnchor(graphics, ps);
+ Insets insets = ps.getClipping();
+
+ PictureData[] pics = { ps.getAlternativePictureData(), ps.getPictureData() };
+ for (PictureData data : pics) {
+ if (data == null) {
+ continue;
+ }
+
+ try {
+ ImageRenderer renderer = getImageRenderer(graphics, data.getContentType());
+ if (renderer.canRender(data.getContentType())) {
+ renderer.loadImage(data.getData(), data.getContentType());
+ renderer.drawImage(graphics, anchor, insets);
+ return;
+ }
+ } catch (IOException e) {
+ LOG.log(POILogger.ERROR, "image can't be loaded/rendered.", e);
+ }
}
- }
+ }
/**
* Returns an ImageRenderer for the PictureData
* are printed. In this situation we need to have a way to access the current slide
*/
DrawableHint CURRENT_SLIDE = new DrawableHint(12);
-
-
+
+ /**
+ * Stores a reference (WEAK_REFERENCE) to the buffered image, if the rendering is
+ * based on a buffered image
+ */
+ DrawableHint BUFFERED_IMAGE = new DrawableHint(13);
+
/**
* Apply 2-D transforms before drawing this shape. This includes rotation and flipping.
*
*/
PictureData getPictureData();
+ /**
+ * Returns an alternative picture data, e.g. an embedded SVG image
+ *
+ * @return an alternative picture data
+ *
+ * @since POI 4.1.0
+ */
+ default PictureData getAlternativePictureData() { return null; }
+
+
/**
* Returns the clipping values as percent ratio relatively to the image size.
* The clipping are returned as insets converted/scaled to 100000 (=100%).
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.RenderingHints;
+import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
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.Drawable;
import org.apache.poi.sl.draw.ImageRenderer;
import org.apache.poi.sl.usermodel.PictureData;
import org.w3c.dom.Document;
@Override
public boolean drawImage(Graphics2D graphics, Rectangle2D anchor, Insets clip) {
+ graphics.setRenderingHint(RenderingHintsKeyExt.KEY_BUFFERED_IMAGE, graphics.getRenderingHint(Drawable.BUFFERED_IMAGE));
+
+ Dimension bounds = getDimension();
+
+ AffineTransform at = new AffineTransform();
+ at.translate(anchor.getX(), anchor.getY());
+ at.scale(anchor.getWidth()/bounds.getWidth(), anchor.getHeight()/bounds.getHeight());
+ svgRoot.setTransform(at);
+
if (clip == null) {
svgRoot.setClip(null);
} else {
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackageRelationship;
+import org.apache.poi.sl.usermodel.PictureData;
import org.apache.poi.sl.usermodel.PictureData.PictureType;
import org.apache.poi.sl.usermodel.PictureShape;
import org.apache.poi.sl.usermodel.Placeholder;
/**
* Add a SVG image reference
* @param svgPic a previously imported svg image
+ *
+ * @since POI 4.1.0
*/
public void setSvgImage(XSLFPictureData svgPic) {
CTBlip blip = getBlip();
cur.dispose();
}
+ @Override
+ public PictureData getAlternativePictureData() {
+ return getSvgImage();
+ }
+
+ public XSLFPictureData getSvgImage() {
+ CTBlip blip = getBlip();
+ CTOfficeArtExtensionList extLst = blip.getExtLst();
+ if (extLst == null) {
+ return null;
+ }
+
+ int size = extLst.sizeOfExtArray();
+ for (int i=0; i<size; i++) {
+ XmlCursor cur = extLst.getExtArray(i).newCursor();
+ try {
+ if (cur.toChild(SVG_NS, "svgBlip")) {
+ String svgRelId = cur.getAttributeText(new QName(CORE_PROPERTIES_ECMA376_NS, "embed"));
+ return (svgRelId != null) ? (XSLFPictureData)getSheet().getRelationById(svgRelId) : null;
+ }
+ } finally {
+ cur.dispose();
+ }
+ }
+
+ return null;
+ }
+
+
/**
* Convienence method for adding SVG images, which generates the preview image
* @param sheet the sheet 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)
+ *
+ * @since POI 4.1.0
*/
public static XSLFPictureShape addSvgImage(XSLFSheet sheet, XSLFPictureData svgPic, PictureType previewType, Rectangle2D anchor) throws IOException {
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
+import java.lang.ref.WeakReference;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import javax.imageio.ImageIO;
-import org.apache.poi.sl.draw.DrawFactory;
+import org.apache.poi.sl.draw.Drawable;
import org.apache.poi.sl.usermodel.Slide;
import org.apache.poi.sl.usermodel.SlideShow;
import org.apache.poi.sl.usermodel.SlideShowFactory;
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);
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import org.apache.poi.POIDataSamples;
import org.apache.poi.sl.usermodel.PictureData.PictureType;
import org.apache.poi.util.IOUtils;
+import org.apache.poi.util.TempFile;
import org.apache.poi.xslf.XSLFTestDataSamples;
+import org.apache.poi.xslf.util.PPTX2PNG;
import org.junit.Test;
import org.openxmlformats.schemas.presentationml.x2006.main.CTPicture;
anchor.setRect(100, 100, anchor.getWidth(), anchor.getHeight());
shape.setAnchor(anchor);
-// try (FileOutputStream fos = new FileOutputStream("svgtest.pptx")) {
-// ppt.write(fos);
-// }
+ assertNotNull(shape.getSvgImage());
+
+ final File tmpFile = TempFile.createTempFile("svgtest", ".pptx");
+ System.out.println(tmpFile);
+ try (FileOutputStream fos = new FileOutputStream(tmpFile)) {
+ ppt.write(fos);
+ }
+
+ String[] args = {
+ "-format", "png", // png,gif,jpg or null for test
+ "-slide", "-1", // -1 for all
+ "-outdir", tmpFile.getParentFile().getCanonicalPath(),
+ "-quiet",
+ tmpFile.getAbsolutePath()
+ };
+ PPTX2PNG.main(args);
}
}
\ No newline at end of file