Incorrect Table Height returned by LayoutEnumerator after update page settings

Hi Team,

I have a requirement to calculate the total table height after setting the individual ROW and CELL Height and Width respectively. I loaded the HTML input file into the Document object as bytes and reset page properties. I tried using the Layout Collector and Enumerator according to this discussion but it seems the height is returning as 25px while the expected height is 605px according to the HTML input file attached.

Could you check the logic within the thread and suggest if any logic change required?

Sample Code for updating Page and Table settings:

HtmlLoadOptions options = new HtmlLoadOptions();
Document doc = AsposeWordUtility.createDocument(htmlBytes, options);
DocumentBuilder builder = AsposeWordUtility.createDocumentBuilder(doc);
PageSetup pageSetup = builder.getPageSetup();

double margin = 0;
pageSetup.setLeftMargin(margin);
pageSetup.setRightMargin(margin);
pageSetup.setTopMargin(margin);
pageSetup.setBottomMargin(margin);
pageSetup.setPageWidth(ConvertUtil.pixelToPoint(576));

Section section = doc.getFirstSection();
Body body = section.getBody();
TableCollection tables = body.getTables();
Table table = tables.get(0);
	
if (table != null) {
	table.setLeftIndent(0);
	int rowIndex = 0, colIndex = 0, cellPadding = 0;
	
	for (Row row : table.getRows()) {
		RowFormat rowFmt = row.getRowFormat();
		
		rowIndex = table.indexOf(row);
		
		rowFmt.setHeight(ReportUtils.pxToPt(visibleRowHeights.get(rowIndex)));
		rowFmt.setHeightRule(HeightRule.EXACTLY);
		rowFmt.setAllowBreakAcrossPages(false);
		
		for(Cell cell : row.getCells()) {
			double cellWidth = visibleColWidths.get(colIndex);
			
			CellFormat cellFmt = cell.getCellFormat();
			colIndex = row.indexOf(cell);
			
			cellFmt.setWidth(ReportUtils.pxToPt(cellWidth));
			cellFmt.setTopPadding(cellPadding);
			cellFmt.setBottomPadding(cellPadding);
			cellFmt.setRightPadding(cellPadding);
			cellFmt.setLeftPadding(cellPadding);
		}
	}
}

OoxmlSaveOptions ooxmlSaveOptions = new OoxmlSaveOptions();
doc.save("Sample Table 1.docx", options);
}

Attachment: Sample Table.zip (11.6 KB)

@oraspose Unfortunately, it is not quite clear how to reproduce the problem using your code. I tried rendering the table in your HTML using RenderTable method and it is rendered fine, so visible table height is detected properly. Here is the output of the table rendering:
out_0_0.png (15.1 KB)

Is the attached output a result of document save process? or is it a screenshot you have captured from the Document?

@oraspose The attached image is the result of RenderTable method.

@alexey.noskov Thanks for the confirmation. I will give a try and let you know if I need further clarifications on that table calculation logic.

1 Like

@alexey.noskov I was able to generate the same output as yours. Thanks for the Layout logic from this discussion other post which worked like charm.

1 Like

We used the above logic to perform DOCX to SVG image conversion, we noticed some visible white solid borders appearing on the column header cells in the SVG output image. These borders are not visible within DOCX file or within the original HTML file as attached in the ZIP file below.

DOCX to SVG conversion logic:

SvgSaveOptions svgOptions = new SvgSaveOptions();
svgOptions.setFitToViewPort(false);
svgOptions.setShowPageBorder(false);
svgOptions.setPageSet(new PageSet(0));
doc.save("Sample Table 1.svg", svgOptions);

Any idea what is happening during the DOCX to SVG conversion?

Snapshot Table 1.zip (15.8 KB)

White Border Issue in SVG output -

@oraspose
We have opened the following new ticket(s) in our internal issue tracking system and will deliver their fixes according to the terms mentioned in Free Support Policies.

Issue ID(s): WORDSNET-25005

You can obtain Paid Support services if you need support on a priority basis, along with the direct access to our Paid Support management team.

Hi @alexey.noskov,

I tried the same logic with another test case(attached files) but this time the generated DOCX document had Tables rendered into multiple sections or pages when using the same LayoutCollector logic. We are also aware about the restriction on the Document Page size from this discussion which is 1584pt but the Page height was not set explicitly. The default Document Page height picked up by the framework is 1056px and still we could see the Table being rendered into multiple sections.

Any idea what is happening during the rendering process? We could notice from the below logic that the bottom value is showing 93pt while top is 0 and we assume it is because of that the table is split.

Sample Code used for generating DOCX output:

    private void convertToImage(byte[] htmlBytes) {
    	try {
    		HtmlLoadOptions options = new HtmlLoadOptions();
    		
    		Document doc = new Document(htmlBytes, options);
    		DocumentBuilder builder = new DocumentBuilder(doc);
    		PageSetup pageSetup = builder.getPageSetup();
    		
    		//update page properties like size and margin
    		updatePageSettings(pageSetup);
    		
    		// For Last Paragraph within Document, set font size to 0 if no text
    		// so that it won't occupy the space after the table.
    		// Also, do page break between Table and Paragraph so that while
    		// saving 1st Document Page only Table is saved.
    		Section section = doc.getFirstSection();
    		Body body = section.getBody();
    		Paragraph lastPara = body.getLastParagraph();
    		String paratext = lastPara.getText();
    		if(StringUtils.isNullOrBlank(paratext)) {
    			ParagraphFormat paraFmt = lastPara.getParagraphFormat();
    			paraFmt.getStyle().getFont().setSize(0);
    			paraFmt.setPageBreakBefore(true);
    		}
    		
    		// Update Table Layout properties such as Margin, Padding and Size
    		TableCollection tables = body.getTables();
    		Table table = tables.get(0);
    		if (table != null) {
    			// Reset left indent. since table might be shifted left.
    			table.setLeftIndent(0);
    			
    			//update table ROW and CELL Layout
    			updateTableRowSettings(table);

    			//update Document Page height based on Table Height
    			renderTablePart(doc);
    			
    			... other logic
    		}
    		
    		// save as DOCX format
    		OoxmlSaveOptions ooxmlSaveOptions = new OoxmlSaveOptions();
    		doc.save("Sample Table 1.docx", ooxmlSaveOptions);
    	} catch(Exception ex) {
    		throw new IllegalStateException(ex.getMessage(), ex);
    	}
    }

    private void updatePageSettings(PageSetup pageSetup) {
    	double margin = 0;
    	pageSetup.setLeftMargin(margin);
    	pageSetup.setRightMargin(margin);
    	pageSetup.setTopMargin(margin);
    	pageSetup.setBottomMargin(margin);
    	
    	double widthpx = 402;
    	double widthpt = ConvertUtil.pixelToPoint(widthpx);
    	pageSetup.setPaperSize(PaperSize.CUSTOM);
    	pageSetup.setPageWidth(widthpt);
    }

    private void updateTableRowSettings(Table table) throws Exception{
    			
    	// set the default table top and bottom padding values
    	List<Double> colWidths = new ArrayList<>();
    	colWidths.add(161.28);
    	colWidths.add(85);
    	colWidths.add(85);
    	colWidths.add(70);
    	
    	for (Row row : table.getRows()) {
    		RowFormat rowFmt = row.getRowFormat();
    		rowFmt.setAllowBreakAcrossPages(false);		
    		rowFmt.setHeight(ConvertUtil.pixelToPoint(25.0));
    		rowFmt.setHeightRule(HeightRule.EXACTLY);   
    		
    		for(Cell cell : row.getCells()) {
    			int colIndex = row.indexOf(cell);
    			double cellWidth = colWidths.get(colIndex);
    			
    			CellFormat cellFmt = cell.getCellFormat();
    			cellFmt.setWidth(ConvertUtil.pixelToPoint((cellWidth));
    			cellFmt.setTopPadding(0);
    			cellFmt.setBottomPadding(0);
    		}
    	}
    }

    private void renderTablePart(Document oneTableDoc) throws Exception
    {
    	LayoutCollector collector = new LayoutCollector(oneTableDoc);
    	LayoutEnumerator enumerator = new LayoutEnumerator(oneTableDoc);
    	
    	Table table = oneTableDoc.getFirstSection().getBody().getTables().get(0);

    	// Calculate table size.
    	// For demonstration purposes the example purposes the while table is on the same page.
    	enumerator.setCurrent(collector.getEntity(table.getFirstRow().getFirstCell().getFirstParagraph()));
    	// Move enumerator to a row.
    	while (enumerator.getType()!= LayoutEntityType.ROW)
    		enumerator.moveParent();

    	double top = enumerator.getRectangle().y;
    	double left = enumerator.getRectangle().x;

    	// Move enumerator to the last row.
    	enumerator.setCurrent(collector.getEntity(table.getLastRow().getFirstCell().getFirstParagraph()));
    	// Move enumerator to a row.
    	while (enumerator.getType()!= LayoutEntityType.ROW)
    		enumerator.moveParent();

    	double bottom = enumerator.getRectangle().y + enumerator.getRectangle().height;
    	double right = enumerator.getRectangle().x + enumerator.getRectangle().width;

    	// Reset margins
    	PageSetup ps = oneTableDoc.getFirstSection().getPageSetup();
    	ps.setPageWidth(ps.getPageWidth()-ps.getLeftMargin()-ps.getRightMargin());
    	ps.setLeftMargin(0);
    	ps.setRightMargin(0);
    	ps.setPageHeight(ps.getPageHeight()-ps.getTopMargin()-ps.getBottomMargin());
    	ps.setTopMargin(0);
    	ps.setBottomMargin(0);

    	// Set calculated width
    	ps.setPageWidth(right - left);
    	ps.setPageHeight(bottom - top);

    	oneTableDoc.updatePageLayout();
    }

Attachment: Sample Table 1.7z (14.9 KB)

@oraspose In your case the table does not fit one page even if the maximum allowed page height is specified. You can modify your logic like this. In this case the table is shown on two pages:

private static void renderTablePart(Document oneTableDoc) throws Exception
{
    // Set maximum allowed page height
    oneTableDoc.getFirstSection().getPageSetup().setPageHeight(1584);

    LayoutCollector collector = new LayoutCollector(oneTableDoc);
    LayoutEnumerator enumerator = new LayoutEnumerator(oneTableDoc);

    Table table = oneTableDoc.getFirstSection().getBody().getTables().get(0);

    // Calculate table size.
    // For demonstration purposes the example purposes the while table is on the same page.
    enumerator.setCurrent(collector.getEntity(table.getFirstRow().getFirstCell().getFirstParagraph()));
    int startPageIndex = enumerator.getPageIndex();
    // Move enumerator to a row.
    while (enumerator.getType()!= LayoutEntityType.ROW)
        enumerator.moveParent();

    double top = enumerator.getRectangle().y;
    double left = enumerator.getRectangle().x;

    // Move enumerator to the last row.
    enumerator.setCurrent(collector.getEntity(table.getLastRow().getFirstCell().getFirstParagraph()));
    int endPageIndex = enumerator.getPageIndex();
    // Move enumerator to a row.
    while (enumerator.getType()!= LayoutEntityType.ROW)
        enumerator.moveParent();

    double bottom = enumerator.getRectangle().y + enumerator.getRectangle().height;
    double right = enumerator.getRectangle().x + enumerator.getRectangle().width;

    // Reset margins
    PageSetup ps = oneTableDoc.getFirstSection().getPageSetup();
    ps.setPageWidth(ps.getPageWidth()-ps.getLeftMargin()-ps.getRightMargin());
    ps.setLeftMargin(0);
    ps.setRightMargin(0);
    ps.setPageHeight(ps.getPageHeight()-ps.getTopMargin()-ps.getBottomMargin());
    ps.setTopMargin(0);
    ps.setBottomMargin(0);

    // Set calculated width
    ps.setPageWidth(right - left);
    // Do not set page height if table spans several pages.
    if(startPageIndex == endPageIndex)
        ps.setPageHeight(bottom - top);

    oneTableDoc.updatePageLayout();
}

out.docx (13.6 KB)

Hi,

Thanks for the solution, it worked fine for me by splitting pages based on Page Height set to maximum value of 1584pt.

1 Like

@alexey.noskov Could you share the ASPOSE Documentation link where the maximum supported page size is mentioned?

@oraspose Actually, this is not Aspose.Words limitation, this MS Word limitation and Aspose.Words mimics it. I cannot find a place where this limitation is described, at least, it is not described in the specification. However, you can check this in MS Word UI, where you cannot set page size greater than 1584 points.

1 Like