Márk Farkas
Márk Farkas

Reputation: 1546

Shrink text on overflow on a shape in Power Point

I have a Java app using Apache POI which generates a PPT (PowerPoint Presentation) with shapes and texts on these shapes. I would like these texts to automatically fit inside of the corresponding shape. There is definitely an option for this in PowerPoint, which works fine and called 'Shrink text on overflow'

With Apache POI I can set this option from the code. Example below:

private void drawRectWithText(XSLFSlide slide, int x, int y, int width, int height, String text) {
    XSLFAutoShape shape1 = slide.createAutoShape();
    Rectangle rect1 = new Rectangle(x, y, width, upperRectHeight);
    shape1.setAnchor(rect1.getBounds2D());
    shape1.setShapeType(ShapeType.RECT);
    shape1.setText(text);
    shape1.setTextDirection(TextDirection.HORIZONTAL);
    shape1.setVerticalAlignment(VerticalAlignment.MIDDLE);
    XSLFTextParagraph xslfTextParagraph = shape1.getTextParagraphs().get(0);
    xslfTextParagraph.setTextAlign(TextParagraph.TextAlign.CENTER);
    xslfTextParagraph.setFontAlign(FontAlign.AUTO);
    XSLFTextShape xslfTextShape = xslfTextParagraph.getParentShape();
    xslfTextShape.setTextAutofit(TextAutofit.NORMAL); // <-- This sets the 'Shrink text on overflow'
    xslfTextShape.setAnchor(rect1.getBounds2D());
}

This indeed sets the 'Shrink text on overflow' option properly, but nothing happens, the text does not shrink.

When I open the generated PPT, the text has the original size, and overflows, but I can see that the proper option is set. However, if I set anything on this shape or if I reset the slide, the text suddenly shrinks. So the option is set properly it just does not take affect until I refresh the shape.

Is there a way in Apache POI to somehow force refresh a shape? Or is there any other way to achieve the 'Shrink text on overflow' behaviour?

I'm using Apache POI 5.0.

Upvotes: 1

Views: 1216

Answers (1)

Axel Richter
Axel Richter

Reputation: 61945

In Office Open XML drawing, the Normal AutoFit needs a fontScale attribute which specifies the percentage of the original font size to which each run in the text body is scaled. If this attribute is omitted, then a value of 100% is implied. Apache POI does not have a method to set font scale nor will it auto calculate the font scale. So it is omitted. Only PowerPoint's GUI will auto calculate the font scale when necessary.

To present a workaround, one could use XSLFTextShape.resizeToFitText to calculate the size of a rectangle which would be needed to fit all the text in. If that size is bigger than the given size, then calculate the needed font scale to fit the text in the lower sized rectangle. However, XSLFTextShape.resizeToFitText will resize the shape, so the wanted size needs to be set again after that.

Example:

import java.io.FileOutputStream;

import org.apache.poi.xslf.usermodel.*;
import org.apache.poi.sl.usermodel.*;

import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;

public class CreatePPTXTextShape {
    
 static void drawRectWithText(XSLFSlide slide, int x, int y, int width, int height, String text) {
  XSLFAutoShape shape = slide.createAutoShape();
  Rectangle rect = new Rectangle(x, y, width, height);
  shape.setAnchor(rect.getBounds2D());
  shape.setShapeType(ShapeType.RECT);
  shape.setText(text);
  shape.setTextDirection(TextShape.TextDirection.HORIZONTAL);
  shape.setVerticalAlignment(VerticalAlignment.MIDDLE);
  shape.setTextAutofit(TextShape.TextAutofit.NORMAL); // <-- This sets the 'Shrink text to overflow'
  
  // calculate the needed font scaling
  Rectangle2D rect2D = shape.resizeToFitText();
  double upscaledHeight = rect2D.getHeight(); // needed height to fit the text in
  double hScale = 1d;
  if (upscaledHeight > height) hScale = height / upscaledHeight;
  System.out.println(hScale);
  // set font scale
  shape.getTextBody().getXmlObject().getBodyPr().getNormAutofit().setFontScale(hScale * 100000);
  // shape.resizeToFitText() had resized the shape, so set wanted size again
  shape.setAnchor(rect.getBounds2D());
  
  XSLFTextParagraph xslfTextParagraph = shape.getTextParagraphs().get(0);
  xslfTextParagraph.setTextAlign(TextParagraph.TextAlign.CENTER);
 }

 public static void main(String[] args) throws Exception {

  SlideShow slideShow = new XMLSlideShow();

  XSLFSlide slide = (XSLFSlide)slideShow.createSlide();

  drawRectWithText(slide, 100, 100, 50, 50, "This is a test text.");
  
  drawRectWithText(slide, 100, 200, 100, 50, "This is a longer test text.");
  
  drawRectWithText(slide, 300, 100, 50, 100, "This is a much longer test text.");

  FileOutputStream out = new FileOutputStream("./CreatePPTXTextShape.pptx");
  slideShow.write(out);
  out.close();
  slideShow.close();
 }
}

Upvotes: 3

Related Questions