Search code examples
javaapache-poidocx

Apache poi : rotate text inside docx textbox


The client has asked the ability to add editable notes to a docx document automatically generated by a web application. I've implemented the requirement by adding some editable texboxes to the document. Now the customer whishes some of this notes have vertical text but i cannot find any example on how to implement this functionality. Should i rotate the textbox or the text contained? which class should i use ? can you provide any link with examples , i have found none till now? below is the code i use to add textboxes :

try {
                    CTGroup ctGroup = CTGroup.Factory.newInstance();

                    CTRect ctRect = ctGroup.addNewRect();
                    ctRect.setStyle(
                              String.format(
                                      "position:absolute;width: %scm;"   
                                    + "height:%scm;" 
                                    + "top:%scm;"
                                    + "left:%scm;"
                                    + "mso-position-horizontal-relative:page;"
                                    + "mso-position-vertical-relative:page;",
                                    nota.getWordPosition().getWidth()/10,//mm->cm
                                    nota.getWordPosition().getHeight()/10,//mm->cm
                                    nota.getWordPosition().getY(),
                                    nota.getWordPosition().getX()
                            )
                      );
                      CTTxbxContent ctTxbxContent = ctRect.addNewTextbox().addNewTxbxContent();
                      String[] noteLines = nota.getDescription().split("\n|\r\n");
                      CTP noteCTP = ctTxbxContent.addNewP();
                      for(String line : noteLines){
                         CTR noteCTR = noteCTP.addNewR();
                         noteCTR.addNewT().setStringValue(line);
                         noteCTR.addNewCr();
                      }
                      
                      Node ctGroupNode = ctGroup.getDomNode(); 
                      CTPicture ctPicture = CTPicture.Factory.parse(ctGroupNode);
                      
                      XWPFRun noteRun = imageParagraph.createRun(); 
                      
                      CTR cTR = noteRun.getCTR();
                      cTR.addNewPict();
                      cTR.setPictArray(0, ctPicture);
                     
                      
                } catch (Exception e) {
                    logger.warn("failed to add a note " +  e.getMessage(),e);
                    throw new ReportGeneratorException("error adding note on pages " + nota.getPages() + "(id " + nota.getId() +")");
                }

Solution

  • That would be the style of CTTextbox. There you can set "layout-flow:vertical;mso-layout-flow-alt:bottom-to-top". That means vertical text flow bottom to top.

    ...
    CTTextbox ctTextbox = ctRect.addNewTextbox();
    ctTextbox.setStyle("layout-flow:vertical;mso-layout-flow-alt:bottom-to-top");
    ...
    

    How to get? Create the default text box. Open the file using Word GUI. Set text direction there as wanted. Save the file. Unzip the *.docx and have a look into /word/document.xml. There you will find:

    <w:pict>
     <v:rect style="position:absolute;...">
      <v:textbox style="...;layout-flow:vertical;mso-layout-flow-alt:bottom-to-top;...">
       <w:txbxContent>
        ...
       </w:txbxContent>
      </v:textbox>
     </v:rect>
    </w:pict>
    

    Complete example (tested and works using apache poi 5.0.0):

    import java.io.FileOutputStream;
    
    import org.apache.poi.xwpf.usermodel.*;
    
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPicture;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTR;
    import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTxbxContent;
    
    import com.microsoft.schemas.vml.CTGroup;
    import com.microsoft.schemas.vml.CTRect;
    import com.microsoft.schemas.vml.CTTextbox;
    import com.microsoft.schemas.office.word.CTWrap;
    import com.microsoft.schemas.office.word.STWrapType;
    
    import org.w3c.dom.Node;
    
    public class CreateWordTextBox {
    
     public static void main(String[] args) throws Exception {
    
      XWPFDocument doc= new XWPFDocument();
    
      XWPFParagraph paragraph = doc.createParagraph();
      XWPFRun run=paragraph.createRun();  
      run.setText("The Body text: ");
    
      CTGroup ctGroup = CTGroup.Factory.newInstance();
    
      CTRect ctRect = ctGroup.addNewRect();
      //ctRect.addNewWrap().setType(STWrapType.SQUARE);
      ctRect.setStyle("position:absolute;mso-position-horizontal:center;margin-top:10pt;width:36pt;height:100pt");
      
      CTTextbox ctTextbox = ctRect.addNewTextbox();
      ctTextbox.setStyle("layout-flow:vertical;mso-layout-flow-alt:bottom-to-top");
    
      CTTxbxContent ctTxbxContent = ctTextbox.addNewTxbxContent();
      ctTxbxContent.addNewP().addNewR().addNewT().setStringValue("The TextBox text...");
    
      Node ctGroupNode = ctGroup.getDomNode(); 
      CTPicture ctPicture = CTPicture.Factory.parse(ctGroupNode);
      run=paragraph.createRun();  
      CTR cTR = run.getCTR();
      cTR.addNewPict();
      cTR.setPictArray(0, ctPicture);
    
      paragraph = doc.createParagraph();
      run=paragraph.createRun();  
      run.setText("Lorem ipsum semit color ... Lorem ipsum semit color ... Lorem ipsum semit color ... Lorem ipsum semit color ... Lorem ipsum semit color ... Lorem ipsum semit color ... Lorem ipsum semit color ... Lorem ipsum semit color ... Lorem ipsum semit color ... Lorem ipsum semit color ... Lorem ipsum semit color ... Lorem ipsum semit color ... Lorem ipsum semit color ... Lorem ipsum semit color ... Lorem ipsum semit color ... Lorem ipsum semit color ... ");
    
      FileOutputStream out = new FileOutputStream("WordTextBox.docx");
      doc.write(out);
      out.close();
      doc.close();
    
     }
    }