Dynamically Reduce Font Size until Table Fits within Page Bounds (Width Height) | C# .NET

Hi Team,

We are using Aspose .net/C# library to generate the Word and pdf files. But we are struggling with tables. Large tables are being cut off and it’s not fitting within page width. We don’t want to reduce font for all tables but want to adjust the table within the page. We have tried a couple of solutions provided on aspose side but so far we are not able to develop a proper solution to match the business expectations.
Please see below for tried links:

Please find the attached expected and output word and pdfs with the issue after applying the above and other fixes.

Could you please help us to fix the following two problems:
Issue 1: Maintain table within page width in exported documents.
Issue 2: if the table fits within one-page height, the table should not be split across multiple pages. See input Word document where table gets pushed to the second page in order to not be split.

Output.zip (2.1 MB)
Expected.zip (79.1 KB)

Thanks,
Kushal

@kushalpaliwal847,

The following C# code of Aspose.Words for .NET API keeps reducing the font size of Table content until the Table fits within the Page bounds (width):

Document doc = new Document("C:\\Temp\\output\\argentina-country-regulation-overview-word.docx");

Table table = doc.Sections[0].Body.Tables[1]; // target table
Section tableSection = (Section)table.GetAncestor(NodeType.Section);

double pageWidth = tableSection.PageSetup.PageWidth - tableSection.PageSetup.RightMargin;

while (Math.Round(GetTableWidth(table)) > Math.Round(pageWidth))
{
    foreach (Paragraph paragraph in table.GetChildNodes(NodeType.Paragraph, true))
    {
        paragraph.ParagraphBreakFont.Size = paragraph.ParagraphBreakFont.Size - 1;

        foreach (Run run in paragraph.GetChildNodes(NodeType.Run, true))
            run.Font.Size = run.Font.Size - 1;
    }

    doc.UpdateTableLayout();
    doc.UpdatePageLayout();
}

doc.Save("C:\\Temp\\output\\21.8.docx");
doc.Save("C:\\Temp\\output\\21.8.pdf");

public static double GetTableWidth(Table table)
{
    LayoutCollector collector = new LayoutCollector((Document)table.Document);
    LayoutEnumerator enumerator = new LayoutEnumerator((Document)table.Document);

    double maxWidth = 0;
    foreach (Row row in table.Rows) {
        enumerator.Current = collector.GetEntity(row.LastCell.FirstParagraph);

        while (enumerator.MoveParent())
            if (enumerator.Type == LayoutEntityType.Row)
                break;

        // Get the width of Row
        double rowWidth = enumerator.Rectangle.Right;

        if ((rowWidth > maxWidth))
            maxWidth = rowWidth;
    }
    return maxWidth;
}

Please refer to the following section of documentation:

Sample usage is as follows:

Document doc = new Document("C:\\Temp\\output\\argentina-country-regulation-overview-word.docx");

Table table = doc.Sections[0].Body.Tables[2]; // target table
foreach (Cell cell in table.GetChildNodes(NodeType.Cell, true))
{
    cell.EnsureMinimum();
    foreach (Paragraph para in cell.Paragraphs)
        if (!(cell.ParentRow.IsLastRow && para.IsEndOfCell))
            para.ParagraphFormat.KeepWithNext = true;
}

doc.UpdatePageLayout();

doc.Save("C:\\Temp\\output\\21.8.docx");
doc.Save("C:\\Temp\\output\\21.8.pdf");

Thanks for inputs @awais.hafeez

1 Like

@awais.hafeez- I am getting following error for some document when i am using above code to reduce the table font and set in page width:

5544 18:57:53 ERROR GenerateFiles
Exception: System.Threading.ThreadAbortException
Message: Thread was being aborted.
Source: mscorlib
   at System.String.IndexOf(Char value, Int32 startIndex, Int32 count)
   at    .(Char )
   at    .(Int32 )
   at    .()
   at    ..ctor(Inline ,     , String ,     )
   at    .(Inline , String , Boolean )
   at    . ()
   at    .()
   at ​  .()
   at Aspose.Words.Document.UpdatePageLayout()
   at Aspose.Words.Layout.LayoutEnumerator.Reset()
   at Informa.Library.Article.Helpers.ExportAssetFamilyHelper.GetTableWidth(Table table) in D:\JenkinsBuilds\workspace\Sitecore-UAT-Build\OmdiaUAT-Build\src\Informa.Library\Article\Helpers\ExportAssetFamilyHelper.cs:line 503
   at Informa.Library.Article.Helpers.ExportAssetFamilyHelper.StyleTables(Document doc) in D:\JenkinsBuilds\workspace\Sitecore-UAT-Build\OmdiaUAT-Build\src\Informa.Library\Article\Helpers\ExportAssetFamilyHelper.cs:line 484
   at Informa.Library.Article.Helpers.ExportAssetFamilyHelper.GenerateFiles(String articleName, String htmlContent, ExportHeader header, Configurations configs) in D:\JenkinsBuilds\workspace\Sitecore-UAT-Build\OmdiaUAT-Build\src\Informa.Library\Article\Helpers\ExportAssetFamilyHelper.cs:line 409
private static void StyleTables(Document doc)
        {
            NodeCollection tables = doc.GetChildNodes(NodeType.Table, true);

            foreach (Table table in tables)
            {
                foreach (Cell cell in table.GetChildNodes(NodeType.Cell, true))
                {
                    cell.EnsureMinimum();
                    foreach (Paragraph para in cell.Paragraphs)
                        if (!(cell.ParentRow.IsLastRow && para.IsEndOfCell))
                            para.ParagraphFormat.KeepWithNext = true;
                }

                Section tableSection = (Section)table.GetAncestor(NodeType.Section);

                double pageWidth = tableSection.PageSetup.PageWidth - tableSection.PageSetup.RightMargin;

                while (Math.Round(GetTableWidth(table)) > Math.Round(pageWidth))
                {
                    foreach (Paragraph paragraph in table.GetChildNodes(NodeType.Paragraph, true))
                    {
                        paragraph.ParagraphBreakFont.Size = paragraph.ParagraphBreakFont.Size - 1;

                        foreach (Run run in paragraph.GetChildNodes(NodeType.Run, true))
                            run.Font.Size = run.Font.Size - 1;
                    }

                    doc.UpdateTableLayout();
                    doc.UpdatePageLayout();
                }
            };
        }

        public static double GetTableWidth(Table table)
        {
            LayoutCollector collector = new LayoutCollector((Document)table.Document);
            **LayoutEnumerator enumerator = new LayoutEnumerator((Document)table.Document);**

            double maxWidth = 0;
            foreach (Row row in table.Rows)
            {
                if (row != null && row.LastCell != null && row.LastCell.FirstParagraph != null)
                {
                    var entity = collector.GetEntity(row.LastCell.FirstParagraph);

                    if (entity != null)
                    {
                        enumerator.Current = entity;
                        while (enumerator.MoveParent())
                            if (enumerator.Type == LayoutEntityType.Row)
                                break;

                        // Get the width of Row
                        double rowWidth = enumerator.Rectangle.Right;

                        if ((rowWidth > maxWidth))
                            maxWidth = rowWidth;
                    }
                }
            }
            return maxWidth;
        } 

Code line in ** where it is breaking. Could you please let me know the issue here? It blocking thread and site going in non responding state due to this.

Thanks

@kushalpaliwal847,

Please also ZIP and upload your input Word DOCX document (that you are getting this problem with) here for testing. We will then investigate the issue on our end and provide you more information.

@awais.hafeez- Please find attached doc which is having issue. display-dynamics–january-2021-latest-active-pen-application-update-word (1).docx (151.9 KB)

The earliest response will be really helpful as it is impacting customers.

Thanks,
Kushal

@kushalpaliwal847,

For this particular case, the following code does not produce any exception when running with 21.9 version of Aspose.Words for .NET on my end:

Document doc = new Document("C:\\Temp\\display-dynamics--january-2021-latest-active-pen-application-update-word (1).docx");

foreach (Section section in doc.Sections)
{
    NodeCollection tables = section.Body.GetChildNodes(NodeType.Table, true);
    foreach (Table table in tables)
    {
        foreach (Cell cell in table.GetChildNodes(NodeType.Cell, true))
        {
            cell.EnsureMinimum();
            foreach (Paragraph para in cell.Paragraphs)
                if (!(cell.ParentRow.IsLastRow && para.IsEndOfCell))
                    para.ParagraphFormat.KeepWithNext = true;
        }


        table.AutoFit(AutoFitBehavior.AutoFitToContents);
        Section tableSection = (Section)table.GetAncestor(NodeType.Section);

        double pageWidth = tableSection.PageSetup.PageWidth - tableSection.PageSetup.RightMargin;

        while (Math.Round(GetTableWidth(table)) > Math.Round(pageWidth))
        {
            foreach (Paragraph paragraph in table.GetChildNodes(NodeType.Paragraph, true))
            {
                paragraph.ParagraphBreakFont.Size = paragraph.ParagraphBreakFont.Size - 1;

                foreach (Run run in paragraph.GetChildNodes(NodeType.Run, true))
                    run.Font.Size = run.Font.Size - 1;
            }

            doc.UpdateTableLayout();
            doc.UpdatePageLayout();
        }

    }
}

// doc.UpdatePageLayout();

doc.Save("C:\\Temp\\21.9.docx");
doc.Save("C:\\Temp\\21.9.pdf");