javaapache-poipresentation

With Apache POI XMLSlideShow, unable to create shapes like Balloon, Callouts


With Apache POI 5.2.5, in an XMLSlideShow, I am able to create few basic shapes, like triangle, rectangle. But for some reason, unable to create balloons and callouts.

Here is relevant piece of code (in Kotlin)

        val slideShow: SlideShow<*, *> = XMLSlideShow()
        val slide = slideShow.createSlide()

        var autoShape = slide.createAutoShape()
        autoShape.shapeType = ShapeType.ACCENT_CALLOUT_1
        autoShape.fillColor = Color.BLUE
        autoShape.anchor = Rectangle(100, 400, 50, 50)

        autoShape = slide.createAutoShape()
        autoShape.shapeType = ShapeType.BALLOON
        autoShape.fillColor = Color.GREEN
        autoShape.anchor = Rectangle(200, 400, 50, 50)

        autoShape = slide.createAutoShape()
        autoShape.shapeType = ShapeType.BENT_ARROW
        autoShape.fillColor = Color.YELLOW
        autoShape.anchor = Rectangle(300, 400, 50, 50)

        // this is working
        autoShape = slide.createAutoShape()
        autoShape.shapeType = ShapeType.ROUND_1_RECT
        autoShape.fillColor = Color.CYAN
        autoShape.anchor = Rectangle(400, 400, 50, 50)

        val line = slide.createAutoShape()
        line.shapeType = ShapeType.LINE
        line.anchor = Rectangle(250, 250, 100, 200)
        line.fillColor = Color(0, 128, 0)

It can be something very basic attribute or a property which I am missing, but unable to figure out as I am new the library. Any pointers are much appreciated.


Solution

  • The idea behind org.apache.poi.sl.usermodel.ShapeType was to protect both, the old binary OLE *.ppt file format as well as the current Office Open XML *.pptx file format. But as Microsoft is not really good in providing backwards compatibility, some of the old binary PowerPoint shape types are not usable using the current PowerPoint versions. Some simply will not be displayed and some not even have got a ooxmlId. For the latter current PowerPoint throws an error while opening the file when used in *.pptx file.

    If you check the output of:

    for (ShapeType shapeType : ShapeType.values()) {
     System.out.println(shapeType.name());
     System.out.print("Native " + shapeType.nativeId);
     System.out.println(" - " + shapeType.nativeName);
     System.out.print("OOXML " + shapeType.ooxmlId);
     System.out.println(" - " + shapeType.getOoxmlName());
     System.out.println("----------------------------");
    }
    

    you wil see that some of the shape types only have nativeId and ooxmlId is -1. Those cannot be used using XMLSlideShow but using HSLFSlideShow only. Vice versa some have ooxmlId and nativeId is -1. Those cannot be used using HSLFSlideShow but using XMLSlideShow only.

    Following example creates auto-shapes using all possible shape types. When used with SlideShow slideShow = new HSLFSlideShow(); FileOutputStream out = new FileOutputStream("./CreatePPTXShapeTypes.ppt");, then for binary *.ppt and when used with SlideShow slideShow = new XMLSlideShow(); FileOutputStream out = new FileOutputStream("./CreatePPTXShapeTypes.pptx"); then for current *.pptx.

    import java.io.FileOutputStream;
    
    import org.apache.poi.sl.usermodel.*;
    import org.apache.poi.xslf.usermodel.*;
    import org.apache.poi.hslf.usermodel.*;
    
    import java.awt.Rectangle;
    import java.awt.Color;
    
    public class CreatePowerPointShapeTypes {
    
     public static void main(String[] args) throws Exception {
    
      try ( 
       SlideShow slideShow = new XMLSlideShow(); FileOutputStream out = new FileOutputStream("./CreatePPTXShapeTypes.pptx");
       //SlideShow slideShow = new HSLFSlideShow(); FileOutputStream out = new FileOutputStream("./CreatePPTXShapeTypes.ppt");
       ) {
          
       Slide slide = slideShow.createSlide();
        
       int x = 20;
       int y = 20;
       int width = 100;
       int height = 100;
       
       for (ShapeType shapeType : ShapeType.values()) {
        if ((slideShow instanceof XMLSlideShow && shapeType.ooxmlId > -1) ||
            (slideShow instanceof HSLFSlideShow && shapeType.nativeId > -1)) {
         AutoShape autoShape = slide.createAutoShape();
         autoShape.setText(shapeType.name());
         autoShape.setShapeType(shapeType);
         autoShape.setFillColor(Color.BLUE);
         autoShape.setAnchor(new Rectangle(x, y, width, height));
         x = x + width + 5; 
         if (x > 600) {
          x = 20; 
          y = y + height + 5;
         }
         if (y > 400) {
          slide = slideShow.createSlide();
          x = 20;
          y = 20;     
         }
        }
       }
    
       slideShow.write(out);
       
      }
     }
    }