XWPF POI footer different in last page - header

How to set footer diferrent only in last page. I mean, in last page no footer or different. in first page and other are same.
enter link description here
this is my docx

There is not a header/footer only for the last page in Microsoft Word.
There are different header/footer settings possible for first page, even pages and default pages. There the default header/footer gets used for each pages if not else is defined. So if there is a header/footer for even pages and a setting that odd and even pages shall be different, then default header/footer gets used as header/footer for odd pages only. If there is no such setting, then the default header/footer gets used for each page. This is except first page, if there is a special header/footer for first page set.
But a Word document can be separated into different sections. And each section may have own header/footer settings. So if, and only if, the last page is in its own section, then there can be a different header/footer for the last page (last section) only.
Unfortunately apache poi do not provide methods to set sections in XWPF. And it only provides methods to set the three different header/footer types in document. So to get a XWPFDocument separated into sections and to set different header/footer settings for those sections, a little bit cheating is necessary.
One could create one of the three possible header/footer types only to set it to be the default header/footer for an own section later. The following example shows this. It creates a footer for even pages in document, which never gets used but later gets referenced as the default footer for the last section. Note the further comments in the code.
Of course that only can work if one at least knows where the last page starts. That must be known because the section break needs to be set before the content of the lase page.
import java.io.*;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.poi.wp.usermodel.HeaderFooterType;
public class CreateWordDifferentFooters {
public static void main(String[] args) throws Exception {
XWPFDocument document = new XWPFDocument();
XWPFParagraph paragraph;
XWPFRun run;
XWPFFooter footer;
//create footers
//footer for first page
footer = document.createFooter(HeaderFooterType.FIRST);
paragraph = footer.createParagraph();
run = paragraph.createRun();
run.setText("Footer FIRST");
//default footer = footer for each what is not else defined
footer = document.createFooter(HeaderFooterType.DEFAULT);
paragraph = footer.createParagraph();
run = paragraph.createRun();
run.setText("Footer DEFAULT");
//footer for even pages - gets default footer for page in last section later
footer = document.createFooter(HeaderFooterType.EVEN);
paragraph = footer.createParagraph();
run = paragraph.createRun();
run.setText("Footer EVEN = DEFAULT in last section");
//the body content
//section 1
paragraph = document.createParagraph();
run = paragraph.createRun();
run.setText("First page in first section ...");
paragraph = document.createParagraph();
run = paragraph.createRun();
run.addBreak(BreakType.PAGE);
paragraph = document.createParagraph();
run = paragraph.createRun();
run.setText("Second page in first section ...");
paragraph = document.createParagraph();
run = paragraph.createRun();
run.addBreak(BreakType.PAGE);
paragraph = document.createParagraph();
run = paragraph.createRun();
run.setText("Third page in first section ...");
paragraph = document.createParagraph();
//paragraph with section setting for section above and section break
paragraph = document.createParagraph();
org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSectPr ctSectPrSect1 = paragraph.getCTP().addNewPPr().addNewSectPr(); //we need ctSectPrSect1 later
//section 2
paragraph = document.createParagraph();
run = paragraph.createRun();
run.setText("Fourth and last page. Only page in last section ...");
//section setting for section above = last section in 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 ctSectPrLastSect = ctBody.getSectPr(); //there must be a SectPr already because of the footer settings above
//move first and default footer to section 1
org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHdrFtrRef ctHdrFtrRef0 = ctSectPrLastSect.getFooterReferenceArray(0); // first footer
org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHdrFtrRef ctHdrFtrRef1 = ctSectPrLastSect.getFooterReferenceArray(1); // default footer
org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHdrFtrRef[] ctHdrFtrRefs = new org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHdrFtrRef[]{ctHdrFtrRef0, ctHdrFtrRef1};
ctSectPrSect1.setFooterReferenceArray(ctHdrFtrRefs);
//set "there is a title page" for section 1 to make first footer work
org.openxmlformats.schemas.wordprocessingml.x2006.main.CTOnOff ctOnOff = org.openxmlformats.schemas.wordprocessingml.x2006.main.CTOnOff.Factory.newInstance();
ctOnOff.setVal(true);
ctSectPrSect1.setTitlePg(ctOnOff);
//set footer reference of even footer to be default footer reference for last section
org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHdrFtrRef ctHdrFtrRef = ctSectPrLastSect.getFooterReferenceArray(2);
ctHdrFtrRef.setType(org.openxmlformats.schemas.wordprocessingml.x2006.main.STHdrFtr.DEFAULT); //change this from STHdrFtr.EVEN to STHdrFtr.DEFAULT
//unset "there is a title page" for the last section
ctSectPrLastSect.unsetTitlePg();
//remove first and old default footer references from last section
ctSectPrLastSect.removeFooterReference(1);
ctSectPrLastSect.removeFooterReference(0);
FileOutputStream out = new FileOutputStream("./CreateWordDifferentFooters.docx");
document.write(out);
out.close();
document.close();
}
}
This is tested and works using current apache poi 5.2.0.

Related

Header in a XWPFDocument is only on the last page when adding section breaks

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();
}
}

Splitting at a specific point in PDFBox

I would like to split to generate a new pdf by concatenating certain individual pages, but the last page has to be split at a certain point (i.e. all content above a limit to be included and everything below to be excluded - I only care about the ones having their upper left corner above a line). Is that possible using PDFbox?
One way to achieve the task, i.e. to split a page at a certain point (i.e. all content above a limit to be included and everything below to be excluded) would be to prepend a clip path.
You can use this method:
void clipPage(PDDocument document, PDPage page, BoundingBox clipBox) throws IOException
{
PDPageContentStream pageContentStream = new PDPageContentStream(document, page, true, false);
pageContentStream.addRect(clipBox.getLowerLeftX(), clipBox.getLowerLeftY(), clipBox.getWidth(), clipBox.getHeight());
pageContentStream.clipPath(PathIterator.WIND_NON_ZERO);
pageContentStream.close();
COSArray newContents = new COSArray();
COSStreamArray contents = (COSStreamArray) page.getContents().getStream();
newContents.add(contents.get(contents.getStreamCount()-1));
for (int i = 0; i < contents.getStreamCount()-1; i++)
{
newContents.add(contents.get(i));
}
page.setContents(new PDStream(new COSStreamArray(newContents)));
}
to clip the given page along the given clipBox. (It first creates a new content stream defining the clip path and then arranges this stream to be the first one of the page.)
E.g. to clip the content of a page along the horizontal line 650 units above the bottom, do this:
PDPage page = ...
PDRectangle cropBox = page.findCropBox();
clipPage(document, page, new BoundingBox(
cropBox.getLowerLeftX(),
cropBox.getLowerLeftY() + 650,
cropBox.getUpperRightX(),
cropBox.getUpperRightY()));
For a running example look here: ClipPage.java.

RichTextBlock overflow, keep paragraphs together on one page (in one overflow control)

I am printing RichTextBlock contents, using RichTextOverflow for pagination, it's working great but I would like to keep paragraphs together on one page, and now sometimes I have page breaks in middle of paragraph.
Here is the example :
Paragraph 3 should be on the next page, it seems that ITextParagraphFormat.KeepTogether is just what I need but don't know how to get that for RichTextBlock.
If you put your paragraph inside TextBlock/RTB inside InlineUIContainer it will be treated as a single element and will carry over to the next page unbroken if needed. This approach may have some side effects, but I believe it should work for printing.
After all I made a method that will "push" paragraphs that are broken on two pages on to a next page, I am not very happy about this solution but I didn't found another way
public static void BreakBeforeLastParagraph(RichTextBlockOverflow rto)
{
if (!rto.HasOverflowContent)
return;
var pageBreak = rto.ContentEnd.Offset;
var brokenPar = rto.ContentSource.Blocks.FirstOrDefault(pr => pr.ElementStart.Offset <= pageBreak && pr.ElementEnd.Offset >= pageBreak);
if (brokenPar != null)
{
double spacerSize = pageBreak - brokenPar.ElementStart.Offset;
var spacer = new Paragraph();
spacer.Margin = new Windows.UI.Xaml.Thickness(0,spacerSize, 0,0);
rto.ContentSource.Blocks.Insert(rto.ContentSource.Blocks.IndexOf(brokenPar), spacer);
}
rto.UpdateLayout();
}

DOMPDF: page_script(): Check current page content?

I am using dompdf to generate reports which sometimes has a front page, and sometimes has some attachments. The main content has a header and a footer, but the front page and the attachments (the last 3 to 5 pages of the pdf) should not contain header and footer. I'm placing the header and footer with a inline php page_script(), like this:
<script type="text/php">
if (isset($pdf) ) {
$pdf->page_script('
if ( $PAGE_COUNT > 10 && $PAGE_NUM == 1) {
//front page footer
}else{
//other pages' header and footer
}
');
}
</script>
The whole report is built by a database engine which outputs it all as a temporary html.txt-file which is then read into DOMPDF.
Now, to recognize the front page I just have to check if the page number is = 1. If any attachments are added (which are comprised of 1000px-height jpg images, each on their own page)
Does anyone have an idea for how to identify these "attachment"-pages and get DOMPDF to not render a header and footer on those pages? Or is there any way I could check within the page_script()-script whether the current page contains only an image (or perhaps an image with a specific class or identifier)?
Thanks for any help,
David
Detecting the current page contents may be possible, but I'd have to research exactly what you can do at this level. An easier method would be if you could inject some inline script in your generated document. After the main content and before the attachments you could add something like $GLOBALS['attachments'] = true; and then add a check on the status of this variable to your conditional.
<script type="text/php">
if (isset($pdf) ) {
$pdf->page_script('
if ( $PAGE_COUNT > 10 && $PAGE_NUM == 1) {
//front page footer
}elseif ($GLOBALS['attachments']) {
//attachments actions
}else{
//other pages' header and footer
}
');
}
</script>
Of course, don't forget to initialize the variable to false at the top of the document.
(from https://groups.google.com/d/topic/dompdf/mDsYi8Efnhc/discussion)

TCPDF with FPDI templates and THEAD

I have a html table with THEAD output with writeHTML which should be displayed on every page at the top of the table. It works but when I use a template loaded by FPDI the head is white and disappears on the second page and further. I can mark the head field with the mouse but the appear white. The border only appears as a little point on the left.
I already tried to add $this->setPageMark() to the addPage method. But its still the same issue.
public function AddPage($orientation = '', $format = ''){
parent::AddPage($orientation, $format);
if($this->template != null){
$this->useTemplate($this->template);
$this->setPageMark();
}
}
you need to enable page breaks at the beginning which is causing the issue you are having;
this is a sample code snippet ;
require_once('tcpdf/tcpdf.php'); //main code
require_once('tcpdf/fpdi.php'); //read existing pdf and sends to fpdf
$pdf = new FPDI();
$pdf->setPrintHeader(false); //no header
$pdf->setPrintFooter(false);//no footer
$pdf->SetAutoPageBreak(FALSE, 0); // set auto page breaks
//loop starts here
{
$pdf->setSourceFile($page_background); //set page
$templateId = $pdf->importPage(1); //we only need the first page
$pdf->useTemplate($templateId); //use the imported page
//your write html code and any other tcpdf related code comes here
}
$pdf->Output(outcome.pdf, 'I'); //use F instead of I to show generated pdf.