Free Support Forum - aspose.com

How to calculate header/footer sizes for dynamically sized headers/footers in Java

hi there,

I am working on a feature for our application that needs to resize images to fit on a page with headers and footers. I’ve previously had questions answered about resizing the images, but I’ve found that I need to be able to calculate header and footer sizes as well to ensure that they are not overlapped by the resized images, and I haven’t been able to find any functionality to do the header/footer calculation. is this function possible in Aspose.words? I’m looking for a Java implementation.

@zackforbing,

Please ZIP and attach the following resources here for testing:

  • Your simplified input Word document
  • Aspose.Words for Java 20.7 generated output file showing the undesired behavior
  • Your expected file showing the desired output. You can create this document by using MS Word.
  • A screenshot highlighting the header footer area that you want to calculate size of.

As soon as you get these pieces of information ready, we will start investigation into your particular scenario and provide you more information.

I do not have an input document - from looking for other posts on this topic, I’ve found that the LayoutCollector and LayoutEnumerator classes are incapable of finding nodes in headers and footers, which causes my solution to error. the way we construct our headers/footers, they are always a table of one row and three cells, so I came up with this, which would calculate cell heights, and return the tallest one (if it worked), passing in the table and builder once the table is created:

private double getHeaderFooterHeight(
Table table, DocumentBuilder builder) throws Exception {
Document doc = builder.getDocument();
doc.updatePageLayout();
LayoutCollector lc = new LayoutCollector(doc);
LayoutEnumerator le = new LayoutEnumerator(doc);
double headerFooterHeight = 0;
double cellHeight = 0;
CellCollection cells = table.getLastRow().getCells();
for (Cell cell : cells) {
  ParagraphCollection paragraphs = cell.getParagraphs();
  for (Paragraph para : paragraphs) {
    le.setCurrent(lc.getEntity(para));
    double paragraphHeight = le.getRectangle().getHeight();
    cellHeight += paragraphHeight;
  }
  if (cellHeight > headerFooterHeight) {
    headerFooterHeight = cellHeight;
  }
}
return headerFooterHeight;

}

does this help? our documents only have a primary header/footer, there are no other types, so each page has the same header/footer.

@zackforbing,

Please check these sample input/output Word documents (Docs 216337.zip (29.2 KB)) and try building logic on the following Java code to get the desired results. The code essentially will draw red lines at the very bottom of header’s content and at the very top of footer’s content:

Document doc = new Document("E:\\Temp\\input.docx");

LayoutEnumerator enumerator = new LayoutEnumerator(doc);
for (int pageIndex = 0; pageIndex < doc.getPageCount(); pageIndex++) {
    markHeaderFooterBoundaries(enumerator);
    enumerator.moveNext();
}

doc.save("E:\\Temp\\awjava-20.7.docx");

public static void markHeaderFooterBoundaries(LayoutEnumerator enumerator) throws Exception {
    do {
        if (enumerator.moveLastChild()) {
            markHeaderFooterBoundaries(enumerator);
            enumerator.moveParent();
        }

        if (enumerator.getType() == LayoutEntityType.HEADER_FOOTER) {
            addLine(enumerator);
        }

        // Stop after all elements on the page have been procesed.
        if (enumerator.getType() == LayoutEntityType.PAGE)
            return;

    } while (enumerator.movePrevious());
}

public static void addLine(LayoutEnumerator enumerator) throws Exception {
    double top = 0;

    DocumentBuilder builder = new DocumentBuilder(enumerator.getDocument());
    if (enumerator.getKind().equals("FIRSTPAGEFOOTER")) {
        builder.moveToHeaderFooter(HeaderFooterType.FOOTER_FIRST);
        top = enumerator.getRectangle().getY();
    } else if (enumerator.getKind().equals("PRIMARYFOOTER")) {
        builder.moveToHeaderFooter(HeaderFooterType.FOOTER_PRIMARY);
        top = enumerator.getRectangle().getY();
    } else if (enumerator.getKind().equals("EVENPAGESFOOTER")) {
        builder.moveToHeaderFooter(HeaderFooterType.FOOTER_EVEN);
        top = enumerator.getRectangle().getY();
    } else if (enumerator.getKind().equals("FIRSTPAGEHEADER")) {
        builder.moveToHeaderFooter(HeaderFooterType.HEADER_FIRST);
        top = enumerator.getRectangle().getY() + enumerator.getRectangle().getHeight();
    } else if (enumerator.getKind().equals("PRIMARYHEADER")) {
        builder.moveToHeaderFooter(HeaderFooterType.HEADER_PRIMARY);
        top = enumerator.getRectangle().getY() + enumerator.getRectangle().getHeight();
    } else if (enumerator.getKind().equals("EVENPAGESHEADER")) {
        builder.moveToHeaderFooter(HeaderFooterType.HEADER_EVEN);
        top = enumerator.getRectangle().getY() + enumerator.getRectangle().getHeight();
    } else {
        return;
    }

    Shape line = new Shape(enumerator.getDocument(), ShapeType.LINE);
    line.setStrokeColor(Color.RED);
    line.setRelativeHorizontalPosition(RelativeHorizontalPosition.PAGE);
    line.setRelativeVerticalPosition(RelativeVerticalPosition.PAGE);
    line.setWrapType(WrapType.NONE);

    builder.insertNode(line);

    line.setWidth(enumerator.getRectangle().getWidth());
    line.setLeft(0);
    line.setTop(top);
}
1 Like

perfect. that seems like I can adapt that to what I’m working on. thank you!

just as a note, here is how I adapted the function for our application. We have created a DocumentBuilderExtension class that inherits from DocumentBuilder and handles additional custom functonality. I added the new functionality there so it can be used in every section (just in case we ever allow the use of different headers/footers - we’d only need to add further if statements to the measureHeaderFooter function):

private double headerSize = 0;
private double footerSize = 0;
public void setHeaderFooterSize() throws Exception {
  LayoutEnumerator enumerator = new LayoutEnumerator(super.getDocument());
  findAndMeasureHeaderFooter(enumerator);
}

public double getHeaderSize() {
  return headerSize;
}

public double getFooterSize() {
  return footerSize;
}

private void findAndMeasureHeaderFooter(LayoutEnumerator enumerator) throws Exception {
  do {
    if (enumerator.moveLastChild()) {
      findAndMeasureHeaderFooter(enumerator);
      enumerator.moveParent();
    }
    if (enumerator.getType() == LayoutEntityType.HEADER_FOOTER) {
      measureHeaderFooter(enumerator);
    }
    if (enumerator.getType() == LayoutEntityType.PAGE)
      break;
  } while (enumerator.movePrevious());
}

private void measureHeaderFooter(LayoutEnumerator enumerator) throws Exception {
  if (enumerator.getKind().equals(PRIMARY_HEADER)) {
    headerSize = Math.ceil(enumerator.getRectangle().getHeight());
  } else if (enumerator.getKind().equals(PRIMARY_FOOTER)) {
    footerSize = Math.ceil(enumerator.getRectangle().getHeight());
  }
}

@zackforbing,

It is great that you were able to find what you were looking for and thanks for sharing your solution which may also help other developers who are looking to solve similar problem.