Word to html - fit table to page width height

Hi,
We are using aspose words for Java 11.4 for converting word document to html.
In word document we have table which is within page .But when converted to html it shows bigger table going across border of the page.

The problem is that not all contents of cell is visible in word , but html shows all content.

Example
32.1659 is value visible in word , but html shows actual full value 32.16599999999999.
This increases width.
Similarly list AQA is getting longer increasing height.

In html we tried table-layout: fixed; but this fixes width only (and also content visible varies a bit different).

Also we tried table.setAllowAutofit(false); Do we need to set any cell property also alongwith this?

Please let us know aspose options to export table exactly same in html as it looks in word ,without expanding cells/rows/contents.

Document and html are attached.

Thank you.

Hi Sonali,

Thanks for your query. The Aspose.Words mimics the same behavior as MS Word do. Please find the output html file in attachment. If you convert the document to html by using MS Word you will get the same behavior for followings:

Example 32.1659 is value visible in word , but html shows actual full value 32.16599999999999.
This increases width.
Similarly list AQA is getting longer increasing height.

Hope this answers your query. Please let us know if you have any more queries.

Hi there,

Thanks for your inquiry.

Have you tried using different settings of HtmlSaveOptions.TableWidthOutputMode? Do any of these help?

Thanks,

Hi,
Thank you. Yes we tried. It is not giving expected output.

Hi Sonali,

I have managed to reproduce the table’s width issue at my side. I have logged this issue as WORDSNET-6783 in our issue tracking system. I have linked this forum thread to the same issue and you will be notified via this forum thread once this issue is resolved.

We apologize for your inconvenience.

Hi Tahir,

Thank you. Will this issue get fix in next release? If so ,can you please let us know the next release date ?

Can we save this table as image and show at same location in document where the table is ? Can you please provide sample code for 11.4?

Also the image should be exactly as seen in word document . For example some issues that may arise like : image may show extra characters like dashesh below cell contents, images within table not at their expected position etc.

Thanks.

Hi Sonali,

Thanks for your inquiry. Unfortunately, your issue is not resolved yet. Currently, this issue is pending for analysis and is in the queue. I am afraid, I can’t provide you any reliable estimate at the moment. Once your issue is analyzed, we will then be able to provide you an estimate.

Please use the following code snippet to convert Table to Image and save document to HTML format. Hope this helps you. Please let us know if you have any more queries.

Document doc = new Document(MyDir + "dummy_big_table.doc");
Table table = doc.FirstSection.Body.Tables[0];
Image image = RenderNode(table, null);
table.Remove();
Document doc2 = new Document();
DocumentBuilder builder = new DocumentBuilder(doc2);
builder.PageSetup.PageHeight = image.Height;
builder.PageSetup.PageWidth = image.Width;
// Insert image rendered from table.
builder.InsertImage(image);
doc2.Save(MyDir + "AsposeOut.html");
/// 
/// Renders any node in a document to the path specified using the image save options.
/// 
public 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(MyDir + "tableimage.png", imageOptions);
    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;
}

/// 
/// Finds the minimum bounding box around non-transparent pixels in a Bitmap.
/// 
public Rectangle FindBoundingBoxAroundNode(Bitmap originalBitmap)
{
    Point min = new Point(int.MaxValue, int.MaxValue);
    Point max = new Point(int.MinValue, int.MinValue);
    for (int x = 0; x < originalBitmap.Width; ++x)
    {
        for (int y = 0; y < originalBitmap.Height; ++y)
        {
            // Note that you can speed up this part of the algorithm by using LockBits and unsafe code instead of GetPixel.
            Color pixelColor = originalBitmap.GetPixel(x, y);
            // For each pixel that is not transparent calculate the bounding box around it.
            if (pixelColor.ToArgb() != Color.Empty.ToArgb())
            {
                min.X = System.Math.Min(x, min.X);
                min.Y = System.Math.Min(y, min.Y);
                max.X = System.Math.Max(x, max.X);
                max.Y = System.Math.Max(y, max.Y);
            }
        }
    }
    // Add one pixel to the width and height to avoid clipping.
    return new Rectangle(min.X, min.Y, (max.X - min.X) + 1, (max.Y - min.Y) + 1);
}

Hi Tahir,
Thank you. Could you please provide code in Java as I did not find any Color.Transparent and few other elements in java.
Also the table may spread across pages . So we want to set image for available contents of table on that page. (height,width,position etc may not always be as per page).
Also we found that any nested image (image inside the table) with some position set (absolute from column/page) is not coming at expected position after converting table to image.

Hi Sonali,

Thanks for your query. I will write the java code for your request and will update you asap.

Hi Sonali,

Please accept my apologies for late response. Please use the following code snippet to convert the table Node to image. I have attached the output Doc file with this post.

Document doc = new Document(MYDir + "dummy_big_table.doc");
ImageSaveOptions option = new ImageSaveOptions(SaveFormat.PNG);
renderNode(doc.getChild(NodeType.TABLE, 0, true), option);
doc = new Document();
DocumentBuilder builder = new DocumentBuilder(doc);
Shape shape = builder.insertImage(MYDir + "tableimage.png");
shape.setWrapType(WrapType.SQUARE);
shape.setLeft(0.0);
shape.setTop(0.0);
doc.save(MYDir + "AsposeOut.doc");
public static void renderNode(Node node, ImageSaveOptions imageOptions) throws Exception
{
    // Run some argument checks.
    if (node == null)
        throw new Exception("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.getPaperColor();
    imageOptions.setPaperColor(Color.white);
    // 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.getDocument()).deepClone();
    node = doc.getChild(NodeType.ANY, node.getDocument().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.TEXT_BOX);
    Section parentSection = (Section)node.getAncestor(NodeType.SECTION);
    // Assume that the node cannot be larger than the page in size.
    shape.setWidth(parentSection.getPageSetup().getPageWidth());
    shape.setHeight(parentSection.getPageSetup().getPageHeight());
    shape.setFillColor(Color.WHITE); // We must make the shape and paper color transparent.
    // Don't draw a surronding line on the shape.
    shape.setStroked(false);
    Node currentNode = node;
    // If the node contains block level nodes then just add a copy of these nodes to the shape.
    if (currentNode instanceof InlineStory || currentNode instanceof Story)
    {
        CompositeNode composite = (CompositeNode)currentNode;
        for (Node childNode : (Iterable)composite.getChildNodes())
        {
            shape.appendChild(childNode.deepClone(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.getParentNode() instanceof InlineStory || currentNode.getParentNode() instanceof Story || currentNode.getParentNode() instanceof ShapeBase || currentNode.getNodeType() == NodeType.PARAGRAPH))
        {
            CompositeNode parent = (CompositeNode)currentNode.getParentNode().deepClone(false);
            currentNode = currentNode.getParentNode();
            parent.appendChild(node.deepClone(true));
            node = parent; // Store this new node to be inserted into the shape.
        }
        // Add the node to the shape.
        shape.appendChild(node.deepClone(true));
    }
    // We must add the shape to the document tree to have it rendered.
    parentSection.getBody().getFirstParagraph().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.
    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    shape.getShapeRenderer().save(MYDir + "tableimage.png", imageOptions);
}

Please feel free to ask if you have any question about Aspose.Words, we will be happy to help you.

Hi Tahir,
Thank you.
Can you please let us know how to get exact height of the table to apply to shape in case table height is not page height ? Similarly for width ? Also how to handle any nested image inside table? We found that nested image position changes in table image.
Thanks.

Hi Sonali,

Thanks for your query. You can get the table’s height and width by using following code snippet. Please let us know if you have any more queries.

double height = 0;
for (Row row : table.getRows())
    height += row.getRowFormat().getHeight();
double width = 0;
width = table.getPreferredWidth().getValue();

Hi Tahir,
Thank you.
1.We tried the code given earlier for setting table as image but some left part was missing , so we need to set left indent.Is there any other way?
2.The row height can be zero for some/all rows. We need to add some default value 50 to get last row displayed.How to fix it?
3. How to get width in inches if table prefereed width in percent (100% etc)?
4. Instead of calculating height/width, do we have any auto fit shape to content method?
We tried textBox.setFitShapeToText(true); but no use.
5.The picture in last row is moving to left and text 2.4 is not visible due to that.
This is because the picture shape node is coming before Run node(2.4) in aspose tree structure even if absolute postion ( 5" to right of column ) is set.
Please let us know how to fix the picture position inside table image . The document is attached.
6. Also the text below table is not visible in html.It is getting overlapped by table image.

Below is sample code we are trying:

Table table = (Table)cloneNode;
double height = 0;
for (Row row : table.getRows())
{
    LOGGER.info("row height : " + row.getRowFormat().getHeight());
    height += row.getRowFormat().getHeight();
}
double width = table.getPreferredWidth().getValue();
Paragraph para = new Paragraph(newDstDoc);
Shape shape = new Shape(newDstDoc, ShapeType.TEXT_BOX);
shape.appendChild(table.deepClone(true));
shape.setWidth(width);
shape.setHeight(height);
shape.setFillColor(Color.WHITE); // We must make the shape and paper color transparent. 
shape.setStroked(false);// Don’t draw a surronding line on the shape. 
TextBox tb = shape.getTextBox();
double left = table.getLeftIndent();
if (left < 0)
{
    left *= -1;
}
tb.setInternalMarginLeft(left);
para.appendChild(shape);

Hi Sonali,

Thanks for your inquiry. We are working over your queries and will update asap.

Hi,
Any update on this? or let us know any other way of converting table to image which can resolve the above issues.

Any updates?

Hi Sonali,

Please accept my apologies for late response. Please see the following code snippet for your questions 1, 2 and 3.

Document doc = new Document(MYDir + "table_pages.doc");
Table table = (Table)doc.getChild(NodeType.TABLE, 0, true);
//1.We tried the code given earlier for setting table as image but some left part was missing , so we need to set left indent.Is 
table.setLeftIndent(10.0);
//2.The row height can be zero for some/all rows. We need to add some default value 50 to get last row displayed.How to fix it?
double height = 0;
for (Row row : table.getRows())
    height += row.getRowFormat().getHeight();
if (height == 0.0)
{
    System.out.println(height);
    table.getLastRow().getRowFormat().setHeight(50.0);
}
//3.How to get width in inches if table prefereed width in percent (100% etc)?
System.out.println(ConvertUtil.pointToInch(table.getPreferredWidth().getValue()));
doc.save(MYDir + "AsposeOut-Java.doc");

4. Instead of calculating height/width, do we have any auto fit shape to content method?
We tried textBox.setFitShapeToText(true); but no use.

There is no such method. In this case you need to set table’s row height according to shape size.

5.The picture in last row is moving to left and text 2.4 is not visible due to that.
This
is because the picture shape node is coming before Run node(2.4) in
aspose tree structure even if absolute postion ( 5" to right of column )
is set.
6. Also the text below table is not visible in html.It is getting overlapped by table image.

The shared code (renderNode method) is workaround of issue (WORDSNET-6783) shared at first post. However, I will further look into the code of renderNode Method and try to share code with you.

Hope this answers your query. Please let us know if you have any more queries.

Hi Tahir,
Thank you.

// 2.The row height can be zero for some/all rows. We need to add some default value 50 to get last row displayed.How to fix it?
double height = 0;
for (Row row : table.getRows())
height += row.getRowFormat().getHeight();
if(height == 0.0)
{
System.out.println(height);
table.getLastRow().getRowFormat().setHeight(50.0);
}|

No . we do not want to set height for last row.
We want if any/all rows height is zero , then how to get actual displayed hieght of rows.

  1. Instead of calculating height/width, do we have any auto fit shape to content method?
    We tried textBox.setFitShapeToText(true); but no use.*
    There is no such method. In this case you need to set table’s row height according to shape size.|

What is shape size here ? it is 0,0 by default ? . Our shape will contain table and we are trying to set shape size as per table width/height, and not vice versa.

5.The picture in last row is moving to left and text 2.4 is not visible due to that.
This is because the picture shape node is coming before Run node(2.4) in aspose tree structure even if absolute postion ( 5" to right of column ) is set.
6. Also the text below table is not visible in html.It is getting overlapped by table image.*
The shared code (renderNode method) is workaround of issue (WORDSNET-6783) shared at first post. However, I will further look into the code of renderNode Method and try to share code with you.

Using renderNode only below is getting use:

// Add the node to the shape.
shape.appendChild(node.deepClone(true));

That is, it will add table directly to shape. So please check why the image inside table is getting moved to left .

Hi Sonali,

Thanks for your queries. Please note that Aspose.Words mimics the same behavior as MS Word do.

We want if any/all rows height is zero , then how to get actual displayed hieght of rows.

You can get the height of row specified in table’s row properties (Please see the attached image Table-Height.png).
What is shape size here ? it is 0,0 by default ? .
Yes, the default height and width of shape is 0. Please read this documentation link for com.aspose.words.
That is, it will add table directly to shape. So please check why the image inside table is getting moved to left .

If you insert a table which contains the shape into TextBox by using MS Word, MS Word do not allow you to insert such table inside TextBox. Please see the attached image (Image2.png).

I have modified the code, please use the following code snippet.

Document doc = new Document(MYDir + "table_pages.doc");
DocumentBuilder builder = new DocumentBuilder(doc);
Shape shape = new Shape(doc, ShapeType.TEXT_BOX);
shape.setFillColor(Color.WHITE); 
// Don't draw a surronding line on the shape.
shape.setStroked(false);
Table table = (Table)doc.getChild(NodeType.TABLE, 0, true);
shape.appendChild(table.deepClone(true));
double height = 0;
for (Row row : table.getRows())
height += row.getRowFormat().getHeight();
shape.setWidth(table.getPreferredWidth().getValue());
shape.setHeight(height);
ImageSaveOptions imageOptions = new ImageSaveOptions(SaveFormat.PNG);
imageOptions.setPaperColor(Color.white);
shape.getShapeRenderer().save(MYDir + "tableimage.png", imageOptions);
builder.insertNode(shape);
table.remove();
shape.setWrapType(WrapType.SQUARE);
shape.setLeft(0.0);
shape.setTop(0.0);
table = (Table)doc.getChild(NodeType.TABLE, 0, true);
table.setLeftIndent(10.0);
doc.save(MYDir + "AsposeOut-Java.doc");

Hope this answers your queries. Regarding your issue WORDSNET-6783, We will update you via this forum thread once this issue is resolved.

We appreciate your patience.

Any update on WORDSNET-6783, ?

Also ,the java equivalent code for renderNode method provided earlier by you missed the settings and method to crop image.
Can you provide java equivalent for below code, at the earliest?

    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;
}
/// 
/// Finds the minimum bounding box around non-transparent pixels in a Bitmap.
/// 
public Rectangle FindBoundingBoxAroundNode(Bitmap originalBitmap)
{
    Point min = new Point(int.MaxValue, int.MaxValue);
    Point max = new Point(int.MinValue, int.MinValue);
    for (int x = 0; x < originalBitmap.Width; ++x)
    {
        for (int y = 0; y < originalBitmap.Height; ++y)
        {
            // Note that you can speed up this part of the algorithm by using LockBits and unsafe code instead of GetPixel.
            Color pixelColor = originalBitmap.GetPixel(x, y);
            // For each pixel that is not transparent calculate the bounding box around it.
            if (pixelColor.ToArgb() != Color.Empty.ToArgb())
            {
                min.X = System.Math.Min(x, min.X);
                min.Y = System.Math.Min(y, min.Y);
                max.X = System.Math.Max(x, max.X);
                max.Y = System.Math.Max(y, max.Y);
            }
        }
    }
    // Add one pixel to the width and height to avoid clipping.
    return new Rectangle(min.X, min.Y, (max.X - min.X) + 1, (max.Y - min.Y) + 1);
}