Layout Class does not correctly support Table Cells spanning mulitple pages

Hi,

We are using the Layout API to convert out Word documents into PNG images (part of a Web Application…) and all is going well for Paragraphs and, initially, tables. The problem I’ve run into is that cells within a table can span multiple pages but the Layout API does not recognize or convey that information as a result of calling any of its methods.

I’ve attached an example project that shows the problem. The code is based on the Aspose examples (DocumentLayoutHelper class).

This is a major problem for us so any help with a work-around would be appreciated.

Thanks,
Andy.

Hi Andy,

Thanks for your inquiry. Could you please share some detail about your requirements what exact you want to achieve using Aspose.Words? We will then provide you more information about your query along with code.

Hi,

Did you get the sample code I attached with my first post? Basically, here is what I am trying to do:

  1. Loop through all Paragraphs and Tables within a specific word file
  2. Generate an exact bitmap representation for each Paragraph, including borders to the left and right. Each paragraph must be stored as one single bitmap, so if a paragraph spans multiple pages, it is all combined into a single bitmap. This all works in my sample code.
  3. Generate an exact bitmap representation for each Cell within a Table. The contents of each cell must be stored in a single bitmap,

The problems I am having is around the last requirement (3). I’m doing all this render work via the Layout API, but the problem is that it does NOT support table cells that span across multiple pages (unlike Paragraphs…). The API returns a RenderRow per line of a paragraph, so if a Paragraph is 3 lines then you get three rows, and each can be on a different page. For Tables, the API returns a RenderRow per row of a table. The problem is, this “Row” can have a cell that contains an unlimited length of text and it can span any number of pages. The RenderRow does not give any indication of this required information.

Hope that makes sense.

Andy.

Hi Andy,

Thanks for sharing the detail. Yes, we checked your code example but unfortunately did not get the requirements which you want using Aspose.Words.

In your case, we suggest you please use following code example to render Cell node to Png. Hope this helps you. Please let us know if you have any more queries.

Document doc = new Document(MyDir + "RFPTablesTest02.docx");
Cell cell = (Cell)doc.GetChild(NodeType.Cell, 0, true);
Image image = RenderNode(cell, new ImageSaveOptions(SaveFormat.Png));
image.Save(MyDir + "Cell Out.png");
/// 
/// Renders any node in a document to the path specified using the image save options.
/// 
public static Image RenderNode(Node node, ImageSaveOptions imageOptions)
{
    // Run some argument checks.
    if (node == null)
        throw new ArgumentException("Node cannot be null");
    // If no image options are supplied, create default options.
    if (imageOptions == null)
        imageOptions = new ImageSaveOptions(SaveFormat.Png);
    // Store the paper color to be used on the final image and change to transparent.
    // This will cause any content around the rendered node to be removed later on.
    Color savePaperColor = imageOptions.PaperColor;
    imageOptions.PaperColor = Color.Transparent;
    // There a bug which affects the cache of a cloned node. To avoid this we instead clone the entire document including all nodes,
    // find the matching node in the cloned document and render that instead.
    Document doc = (Document)node.Document.Clone(true);
    node = doc.GetChild(NodeType.Any, node.Document.GetChildNodes(NodeType.Any, true).IndexOf(node), true);
    // Create a temporary shape to store the target node in. This shape will be rendered to retrieve
    // the rendered content of the node.
    Shape shape = new Shape(doc, ShapeType.TextBox);
    Section parentSection = (Section)node.GetAncestor(NodeType.Section);
    // Assume that the node cannot be larger than the page in size.
    shape.Width = parentSection.PageSetup.PageWidth;
    shape.Height = parentSection.PageSetup.PageHeight;
    shape.FillColor = Color.Transparent; // We must make the shape and paper color transparent.
                                         // Don't draw a surronding line on the shape.
    shape.Stroked = false;
    Node currentNode = node;
    // If the node contains block level nodes then just add a copy of these nodes to the shape.
    if (currentNode is InlineStory || currentNode is Story)
    {
        CompositeNode composite = (CompositeNode)currentNode;
        foreach (Node childNode in composite.ChildNodes)
        {
            shape.AppendChild(childNode.Clone(true));
        }
    }
    else
    {
        // Move up through the DOM until we find node which is suitable to insert into a Shape (a node with a parent can contain paragraph, tables the same as a shape).
        // Each parent node is cloned on the way up so even a descendant node passed to this method can be rendered. 
        // Since we are working with the actual nodes of the document we need to clone the target node into the temporary shape.
        while (!(currentNode.ParentNode is InlineStory || currentNode.ParentNode is Story || currentNode.ParentNode is ShapeBase || currentNode.NodeType == NodeType.Paragraph))
        {
            CompositeNode parent = (CompositeNode)currentNode.ParentNode.Clone(false);
            currentNode = currentNode.ParentNode;
            parent.AppendChild(node.Clone(true));
            node = parent; // Store this new node to be inserted into the shape.
        }
        // Add the node to the shape.
        shape.AppendChild(node.Clone(true));
    }
    // We must add the shape to the document tree to have it rendered.
    parentSection.Body.FirstParagraph.AppendChild(shape);
    // Render the shape to stream so we can take advantage of the effects of the ImageSaveOptions class.
    // Retrieve the rendered image and remove the shape from the document.
    MemoryStream stream = new MemoryStream();
    shape.GetShapeRenderer().Save(stream, imageOptions);
    shape.Remove();
    Bitmap croppedImage;
    // Load the image into a new bitmap.
    using (Bitmap renderedImage = new Bitmap(stream))
    {
        // Extract the actual content of the image by cropping transparent space around
        // the rendered shape.
        Rectangle cropRectangle = FindBoundingBoxAroundNode(renderedImage);
        croppedImage = new Bitmap(cropRectangle.Width, cropRectangle.Height);
        croppedImage.SetResolution(imageOptions.Resolution, imageOptions.Resolution);
        // Create the final image with the proper background color.
        using (Graphics g = Graphics.FromImage(croppedImage))
        {
            g.Clear(savePaperColor);
            g.DrawImage(renderedImage, new Rectangle(0, 0, croppedImage.Width, croppedImage.Height), cropRectangle.X, cropRectangle.Y, cropRectangle.Width, cropRectangle.Height, GraphicsUnit.Pixel);
        }
    }
    return croppedImage;
}

Hi Tahir,

Thanks for the reply. I’ve seen this code from the example, but it will NOT work because it still has the limitation that it can only handle cells that fit on one page - there is even a comment in the code that states this:

//
Assume that the node cannot be larger than the page in size.

This is the whole problem I’m facing; having cells that span multiple pages. Basically, I need a solution that can handle single cells than span more than one page.

What wasn’t clear in my description of what we want to do? I’ll try and expand on that so you can understand what we are trying to do. We need to get a resolution to this problem.

Thanks,
Andy.

Hi Andy,

Thanks for your inquiry. The Aspose.Words.Layout namespace provides classes that allow to access information such as on what page and where on a page particular document elements are positioned, when the document is formatted into pages.

It would be great if you please share following detail for our reference. We will then provide you more information about your query.

  • Please share the contents length. How many pages a Cell or Node will contain?
  • What will be the max height and width of Cell or a Node?
  • The code example shared in your first post is very lengthy. Please create a standalone/runnable simple application (for example a Console Application Project) that demonstrates the incorrect values returned by Aspose.Words.Layout API.
  • Please share your complete use case. Perhaps, there is alternate way to achieve your requirements.