I am trying to create a word document using Apache POI. This document includes images, and I need to flip the page with the image to be landscape oriented, while keeping the rest of the document portrait oriented. However, I also need to use a header (and a footer, but I assume it is gonna work the same way as headers do).
The code I am using:
val document = XWPFDocument()
// the header I need to be on every page
document.createHeader(HeaderFooterType.DEFAULT).createParagraph().createRun().setText("Header")
// some text before the image
var par = document.createParagraph()
var run = par.createRun()
run.setText("I am text")
// add the image, flip the page with the image onto landscape
par = document.createParagraph()
val pageSize = par.ctp.addNewPPr().addNewSectPr().addNewPgSz() // this creates new section, so I can get the pageSize
pageSize.orient = STPageOrientation.LANDSCAPE
pageSize.h = BigInteger.valueOf(595 * 20) // unit used TWIPS (Twentieth of an Imperial Point)
pageSize.w = BigInteger.valueOf(842 * 20)
run = par.createRun()
val decodedByteArray = Base64.getDecoder().decode(PLACEHOLDER_IMAGE.substringAfter(','))
run.addPicture(
ByteArrayInputStream(decodedByteArray),
XWPFDocument.PICTURE_TYPE_PNG,
"",
pixelToEMU(400),
pixelToEMU(150)
)
// some text after the image
par = document.createParagraph()
run = par.createRun()
run.setText("Me too")
val out = FileOutputStream("Output.docx")
document.write(out)
out.close()
document.close()
The resulting document however has the header only after the last section break. I am aware, that every section has its' own header/footer, and that you can set the header to be the same as the previous, but the header I need seems to be always the last header, and I have no idea how to make it stick to the front of the document, where it can be used by the following sections.
Image of the resulting document
So my question is: How can I make the header appear on every page, while keeping the page formatting as is? If there is a way to make the individual pages, with the images, flip orientation without inserting section breaks, that would be a solution aswell.
In my attempts to solve this, I've been able to put data only into the header in the last section, but never have I managed to actually get my hands on the headers in the previous sections, or on the default header. Notice, that the header in the code I'm creating is set as default, but the real default header is empty and I haven't been able to access it.
NOTE: This is not the actual project, here I've only isolated the problem into a much simpler code without giving any real thought to coding style, etc.
The problem is that sections not only have separate page settings but have separate header/footer settings too.
XWPFDocumnet.createHeader
creates a header which reference gets stored in document body section properties. If you create a paragraph having own section properties - a section break paragraph - then the section properties in this section break paragraph also needs a reference to a header, else the section above that section break paragraph has no header.
Best solution I can think of is to always take a copy of the document body section properties to be the section properties of additional section break paragraphs. Then only change what needs to be changed. So the copy contains needed references to headers and/or footeres already.
The following complete example shows that. The method createSectionbreak
always takes a copy of the document body section properties, except there are none. Then it creates new section properties for the section break paragraph. The method setPageSizeLandscape
then changes the page size.
The code is Java code. Me not using Kotlin. But the principle shold be clear also from that.
import java.io.FileOutputStream;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.poi.wp.usermodel.HeaderFooterType;
public class CreateWordSectionsPageSizeHeader {
static org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSectPr getDocumentBodySectPr(XWPFDocument document) {
org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDocument1 ctDocument = document.getDocument();
org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBody ctBody = ctDocument.getBody();
org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSectPr ctSectPrDocumentBody = ctBody.getSectPr();
return ctSectPrDocumentBody;
}
static XWPFParagraph createSectionbreak(XWPFDocument document) {
XWPFParagraph sectionBreakParagraph = document.createParagraph();
org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSectPr ctSectPrDocumentBody = getDocumentBodySectPr(document);
if (ctSectPrDocumentBody != null) {
org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSectPr ctSectPrNewSect = (org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSectPr)ctSectPrDocumentBody.copy();
sectionBreakParagraph.getCTP().addNewPPr().setSectPr(ctSectPrNewSect);
} else {
sectionBreakParagraph.getCTP().addNewPPr().addNewSectPr();
}
return sectionBreakParagraph;
}
static void setPageSizeLandscape(XWPFParagraph sectionBreakParagraph) {
if (sectionBreakParagraph.getCTP().getPPr() == null) return;
if (sectionBreakParagraph.getCTP().getPPr().getSectPr() == null) return;
org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSectPr ctSectPr = sectionBreakParagraph.getCTP().getPPr().getSectPr();
org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPageSz ctPageSz = ctSectPr.getPgSz();
if (ctPageSz == null) ctPageSz = ctSectPr.addNewPgSz();
ctPageSz.setOrient​(org.openxmlformats.schemas.wordprocessingml.x2006.main.STPageOrientation.LANDSCAPE);
// paper format letter
ctPageSz.setH(java.math.BigInteger.valueOf(12240)); //12240 Twips = 12240/20 = 612 pt = 612/72 = 8.5"
ctPageSz.setW(java.math.BigInteger.valueOf(15840)); //15840 Twips = 15840/20 = 792 pt = 792/72 = 11"
}
public static void main(String[] args) throws Exception {
XWPFDocument document = new XWPFDocument();
XWPFParagraph paragraph;
XWPFRun run;
// create header start
XWPFHeader header = document.createHeader(HeaderFooterType.DEFAULT);
paragraph = header.getParagraphArray(0);
if (paragraph == null) paragraph = header.createParagraph();
paragraph.setAlignment(ParagraphAlignment.LEFT);
run = paragraph.createRun();
run.setText("Header");
// create header end
// create body content
paragraph = document.createParagraph();
run = paragraph.createRun();
run.setText("Text in section 1");
// create section break
paragraph = createSectionbreak(document);
setPageSizeLandscape(paragraph);
// create section break end
paragraph = document.createParagraph();
run = paragraph.createRun();
run.setText("Text in section 2");
// create body content end
FileOutputStream out = new FileOutputStream("./CreateWordSectionsPageSizeHeader.docx");
document.write(out);
out.close();
document.close();
}
}