How to inline images with text by using aspose.words for .NET

I’ll explain my problem step by step.

this is my full converted document currentOutput.docx (229.5 KB)

1.I fixed some images wrapping style as “square”. My problem is in those wrapped images,

2.In this png file expectedOutput.PNG (117.6 KB)the image width is 334.HTML code is like this(check the pic1 image)pic1.PNG (17.7 KB)

3.In this Imageissue.PNG (109.8 KB) the image width is 336. Check the HTML code(pic2)pic2.PNG (17.9 KB)

You can see when the image width increase, image is not going to the next page. it doesn’t adjust according to the page space. It breaks. It comes out of the margins. I want to fix this issue and adjust it according to the page space without breaking.

@nethmi Thank you for additional information. This looks like the same problem you have asked about yesterday. Have you tried using the approach I have suggested in this reply. LayoutCollector and LayoutEnumerator should help you to get the expected output.

It’s not working for me

@nethmi I have modified code a bit, so that image does not overlap footer. Please see the modified code:

Document doc = new Document(@"C:\Temp\currentOutput.docx");

// LayoutCollector and LayoutEnumerator will be used to calculate position of shapes.
LayoutCollector collector = new LayoutCollector(doc);
LayoutEnumerator enumerator = new LayoutEnumerator(doc);

NodeCollection shapes = doc.GetChildNodes(NodeType.Shape, true);
foreach (Shape s in shapes)
{
    // LayoutCollector and LayoutEnumerator do not work with nodes in header and footer.
    // Skip them.
    if (s.GetAncestor(NodeType.HeaderFooter) != null)
        continue;

    PageSetup ps = ((Section)s.GetAncestor(NodeType.Section)).PageSetup;
    // Rectangle inside page margin.
    double top = ps.TopMargin + ps.HeaderDistance;
    double bottom = ps.BottomMargin + ps.FooterDistance;
    float width = (float)(ps.PageWidth - ps.LeftMargin - ps.RightMargin);
    float height = (float)(ps.PageHeight - top - bottom);
    RectangleF rect = new RectangleF((float)ps.LeftMargin, (float)top, width, height);

    // Get shape rectangle on the page.
    enumerator.Current = collector.GetEntity(s);
    RectangleF shapeRect = enumerator.Rectangle;

    // Update shape position to place it inside page margins.
    if (shapeRect.Left < rect.Left)
        s.Left += (rect.Left - shapeRect.Left);

    if (shapeRect.Right > rect.Right)
        s.Left -= (shapeRect.Right - rect.Right);

    if (shapeRect.Top < rect.Top)
        s.Top += (rect.Top - shapeRect.Top);

    if (shapeRect.Bottom > rect.Bottom)
        s.Top -= (shapeRect.Bottom - rect.Bottom);
}

doc.Save(@"C:\Temp\out.docx");

Here is output document produced by this code: out.docx (229.5 KB)

It’s also not working for me. i think my code has a problem somewhere.

@nethmi As I can see in the code snippet you have provide you do not use the suggested approach with LayoutCollector and LayoutEnumerator. If possible could you please create a simple console application that will allow to reproduce the problem and analyze what is gong wrong.

Could you please check this code ??? I am calling the overlapIssue() method in my main method (Convert()). I think my method calling is wrong. because when I call the method (OverlapIssue(document);), I think I should pass the saved word document. Could you please help me to do that? How can I pass the saved word document to the method (OverlapIssue(document);??? I am not allowed to get the document from the machine. Do you have another way to get saved document???

///Main Method

public List<byte[]> Convert(ContentsDto content, IDictionary<string,string> options, System.Func<DependentContent, Task<ContentsDto>> GetDependency=null)
        {          
            License htmlLicense1 = new License(); 
            htmlLicense1.SetLicense("Aspose.Words.NET.lic");

            HtmlDocument htmlDocument = new HtmlDocument();
            using (var htmlStream = new MemoryStream(content.Data))
            {
                htmlDocument.Load(htmlStream);
            }
           
            var byteArray = new List<byte[]>();
           
            using (var dataStream = new MemoryStream(content.Data))
            {
                HtmlLoadOptions docOptions = new HtmlLoadOptions();

                docOptions.ResourceLoadingCallback = new AsposeWordsAuthHandler(_settingsProvider, _authSettings, _logger);
                var document = new Aspose.Words.Document(dataStream, docOptions);
               
                using (var outputStream = new MemoryStream())
                {          
                  
                    document.Save(outputStream, SaveFormat.Docx);
                    //in here i am calling your method.
                    OverlapIssue(document);
                    byteArray.Add(outputStream.ToArray());
                }
            }
            return byteArray;
        }
//Method , which adjust the overlap issue
 private static void OverlapIssue(Document doc)
        {
           
            LayoutCollector collector = new LayoutCollector(doc);
            LayoutEnumerator enumerator = new LayoutEnumerator(doc);

            NodeCollection shapes = doc.GetChildNodes(NodeType.Shape, true);
            foreach (Shape s in shapes)
            {
                // LayoutCollector and LayoutEnumerator do not work with nodes in header and footer.
                // Skip them.
                if (s.GetAncestor(NodeType.HeaderFooter) != null)
                    continue;

                PageSetup ps = ((Section)s.GetAncestor(NodeType.Section)).PageSetup;
                // Rectangle inside page margin.
                double top = ps.TopMargin + ps.HeaderDistance;
                double bottom = ps.BottomMargin + ps.FooterDistance;
                float width = (float)(ps.PageWidth - ps.LeftMargin - ps.RightMargin);
                float height = (float)(ps.PageHeight - top - bottom);
                RectangleF rect = new RectangleF((float)ps.LeftMargin, (float)top, width, height);

                // Get shape rectangle on the page.
                enumerator.Current = collector.GetEntity(s);
                RectangleF shapeRect = enumerator.Rectangle;

                // Update shape position to place it inside page margins.
                if (shapeRect.Left < rect.Left)
                    s.Left += (rect.Left - shapeRect.Left);

                if (shapeRect.Right > rect.Right)
                    s.Left -= (shapeRect.Right - rect.Right);

                if (shapeRect.Top < rect.Top)
                    s.Top += (rect.Top - shapeRect.Top);

                if (shapeRect.Bottom > rect.Bottom)
                    s.Top -= (shapeRect.Bottom - rect.Bottom);

            }   
        }

@nethmi The problem occurs because you make changes after saving the document to stream, so the changes are not reflected in in the output stream. You should modify code like:

//in here i am calling your method.
OverlapIssue(document);

using (var outputStream = new MemoryStream())
{
    document.Save(outputStream, SaveFormat.Docx);
    byteArray.Add(outputStream.ToArray());
}

I put that method before the outputStream. still getting the same issue. I think that method is only working with the saved word document. See this one. in the second method i am using the saved word document from the machine and calling that method in the main method before the outputStream. this is working. But the pervious one is not working.

public List<byte[]> Convert(ContentsDto content, IDictionary<string,string> options, System.Func<DependentContent, Task<ContentsDto>> GetDependency=null)
        {          
            License htmlLicense1 = new License(); 
            htmlLicense1.SetLicense("Aspose.Words.NET.lic");

            HtmlDocument htmlDocument = new HtmlDocument();
            using (var htmlStream = new MemoryStream(content.Data))
            {
                htmlDocument.Load(htmlStream);
            }
           
            var byteArray = new List<byte[]>();
           
            using (var dataStream = new MemoryStream(content.Data))
            {
                HtmlLoadOptions docOptions = new HtmlLoadOptions();

                docOptions.ResourceLoadingCallback = new AsposeWordsAuthHandler(_settingsProvider, _authSettings, _logger);
                var document = new Aspose.Words.Document(dataStream, docOptions);

                //in here i am calling your method.
                    OverlapIssue();

                using (var outputStream = new MemoryStream())
                {          
                  
                    document.Save(outputStream, SaveFormat.Docx);
                    byteArray.Add(outputStream.ToArray());
                }
            }
            return byteArray;
        }

//
//Method , which adjust the overlap issue
 private static void OverlapIssue(Document doc)
        {
           Document doc = new Document(@"D:\TestOutput\test.docx");
            LayoutCollector collector = new LayoutCollector(doc);
            LayoutEnumerator enumerator = new LayoutEnumerator(doc);

            NodeCollection shapes = doc.GetChildNodes(NodeType.Shape, true);
            foreach (Shape s in shapes)
            {
                // LayoutCollector and LayoutEnumerator do not work with nodes in header and footer.
                // Skip them.
                if (s.GetAncestor(NodeType.HeaderFooter) != null)
                    continue;

                PageSetup ps = ((Section)s.GetAncestor(NodeType.Section)).PageSetup;
                // Rectangle inside page margin.
                double top = ps.TopMargin + ps.HeaderDistance;
                double bottom = ps.BottomMargin + ps.FooterDistance;
                float width = (float)(ps.PageWidth - ps.LeftMargin - ps.RightMargin);
                float height = (float)(ps.PageHeight - top - bottom);
                RectangleF rect = new RectangleF((float)ps.LeftMargin, (float)top, width, height);

                // Get shape rectangle on the page.
                enumerator.Current = collector.GetEntity(s);
                RectangleF shapeRect = enumerator.Rectangle;

                // Update shape position to place it inside page margins.
                if (shapeRect.Left < rect.Left)
                    s.Left += (rect.Left - shapeRect.Left);

                if (shapeRect.Right > rect.Right)
                    s.Left -= (shapeRect.Right - rect.Right);

                if (shapeRect.Top < rect.Top)
                    s.Top += (rect.Top - shapeRect.Top);

                if (shapeRect.Bottom > rect.Bottom)
                    s.Top -= (shapeRect.Bottom - rect.Bottom);

            } doc.Save(@"D:\TestOutput\out.docx");
    }

I am not allowed to use this.
Document doc = new Document(@“D:\TestOutput\test.docx”);

Do you have any method to get the saved document??? Because I think It’s only working with saved word document. Do you have any suggestions?

@nethmi Thank you for additional information. The suggested method should be used together with the approach suggested earlier. First you should change the appropriate shapes WrapType and then process the document with the code that uses LayoutCollector and LayoutEnumerator.
Also, it is not required to use Document doc = new Document(@"D:\TestOutput\test.docx");. This line of code is used for demonstration purposes to check the output produced by the code.

You code should look like this:

public List<byte[]> Convert(ContentsDto content, IDictionary<string, string> options, System.Func<DependentContent, Task<ContentsDto>> GetDependency = null)
{
    License htmlLicense1 = new License();
    htmlLicense1.SetLicense("Aspose.Words.NET.lic");

    HtmlDocument htmlDocument = new HtmlDocument();
    using (var htmlStream = new MemoryStream(content.Data))
    {
        htmlDocument.Load(htmlStream);
    }

    var byteArray = new List<byte[]>();

    using (var dataStream = new MemoryStream(content.Data))
    {
        HtmlLoadOptions docOptions = new HtmlLoadOptions();

        docOptions.ResourceLoadingCallback = new AsposeWordsAuthHandler(_settingsProvider, _authSettings, _logger);

        var document = new Aspose.Words.Document(dataStream, docOptions);

        using (var outputStream = new MemoryStream())
        {
            using (var htmlStream = new MemoryStream(content.Data))
            {
                htmlDocument.Load(htmlStream);
            }

            ApplyImageFormatting(document, htmlDocument);
            FormatOutput(GetDependency, document, htmlDocument);
            
            // Here overlap issue is fixed by layout code.
            OverlapIssue(document);

            document.Save(outputStream, SaveFormat.Docx);
            byteArray.Add(outputStream.ToArray());
        }
    }
    return byteArray;
}

done. still getting the same issue.

@nethmi Could you please crate a simple console application and attach it here, so I can run it on my side and debug it? I will check what is going wrong and provide you more information.
Also, please modify OverlapIssue method like this:

//Method , which adjust the overlap issue
 private static void OverlapIssue(Document doc)
        {
            LayoutCollector collector = new LayoutCollector(doc);
            LayoutEnumerator enumerator = new LayoutEnumerator(doc);

            NodeCollection shapes = doc.GetChildNodes(NodeType.Shape, true);
            foreach (Shape s in shapes)
            {
                // LayoutCollector and LayoutEnumerator do not work with nodes in header and footer.
                // Skip them.
                if (s.GetAncestor(NodeType.HeaderFooter) != null)
                    continue;

                PageSetup ps = ((Section)s.GetAncestor(NodeType.Section)).PageSetup;
                // Rectangle inside page margin.
                double top = ps.TopMargin + ps.HeaderDistance;
                double bottom = ps.BottomMargin + ps.FooterDistance;
                float width = (float)(ps.PageWidth - ps.LeftMargin - ps.RightMargin);
                float height = (float)(ps.PageHeight - top - bottom);
                RectangleF rect = new RectangleF((float)ps.LeftMargin, (float)top, width, height);

                // Get shape rectangle on the page.
                enumerator.Current = collector.GetEntity(s);
                RectangleF shapeRect = enumerator.Rectangle;

                // Update shape position to place it inside page margins.
                if (shapeRect.Left < rect.Left)
                    s.Left += (rect.Left - shapeRect.Left);

                if (shapeRect.Right > rect.Right)
                    s.Left -= (shapeRect.Right - rect.Right);

                if (shapeRect.Top < rect.Top)
                    s.Top += (rect.Top - shapeRect.Top);

                if (shapeRect.Bottom > rect.Bottom)
                    s.Top -= (shapeRect.Bottom - rect.Bottom);
            } 
    }

sure I will.
Could you please try OverlapIssue(Document doc) method, with these two word documents???

If you can see a difference please let me know. I think both overlap images in the two documents run under same if condition. I think, That’s why we can’t get correct output for one document.

sample1.docx (29.6 KB)

sample2.docx (30.0 KB)

any update??

@nethmi Thank you for additional information. I have modified the code a bit more and now it gives better result. But please note that fonts used in the document must be available on the machine where code is used, because layout code requires fonts to build layout properly. Could you please check on your side:

private static void OverlapIssue(Document doc)
{
    LayoutCollector collector = new LayoutCollector(doc);
    LayoutEnumerator enumerator = new LayoutEnumerator(doc);

    NodeCollection shapes = doc.GetChildNodes(NodeType.Shape, true);
    foreach (Shape s in shapes)
    {
        // LayoutCollector and LayoutEnumerator do not work with nodes in header and footer.
        // Skip them.
        if (s.GetAncestor(NodeType.HeaderFooter) != null || !s.IsTopLevel)
            continue;

        PageSetup ps = ((Section)s.GetAncestor(NodeType.Section)).PageSetup;
        // Rectangle inside page margin.
        float width = (float)(ps.PageWidth - ps.LeftMargin - ps.RightMargin);
        float height = (float)(ps.PageHeight - ps.TopMargin - ps.BottomMargin);
        RectangleF rect = new RectangleF((float)ps.LeftMargin, (float)ps.TopMargin, width, height);

        // Get shape rectangle on the page.
        enumerator.Current = collector.GetEntity(s);
        RectangleF shapeRect = enumerator.Rectangle;

        double left = 0;
        double top = 0;

        // Update shape position to place it inside page margins.
        if (shapeRect.Left < rect.Left)
            left = rect.Left;

        if (shapeRect.Right > rect.Right)
            left = rect.Right - shapeRect.Width;

        if (shapeRect.Top < rect.Top)
            top = rect.Top;

        if (shapeRect.Bottom > rect.Bottom)
            top = rect.Bottom - shapeRect.Height;

        if (!IsZero(left) || !IsZero(top))
        {
            // Set relative shape position to page.
            s.RelativeHorizontalPosition = RelativeHorizontalPosition.Page;
            s.RelativeVerticalPosition = RelativeVerticalPosition.Page;
            s.Top = Math.Max(top, rect.Top);
            s.Left = Math.Max(left, rect.Left);
            doc.UpdatePageLayout();
        }
    }
}

public static bool IsZero(double value)
{
    return (Math.Abs(value) < Double.Epsilon);
}
1 Like

Hii

This is working. I checked several scenarios with this code. It’s working. Thank you very much for your support and effort. I really appreciate it. :slightly_smiling_face:

1 Like

A post was split to a new topic: How to change image wrap type using Aspose.Pdf?

Hii

I am using below code to wrap my images.

private static void SetImageLayout(Document document, HtmlDocument htmlDocument)
    {
        HtmlNodeCollection images = htmlDocument.DocumentNode.SelectNodes("//img");
        NodeCollection shapes = document.GetChildNodes(NodeType.Shape, true);

        if (images != null)
        {
            var imgIndex = 0;
            foreach (Shape shape in shapes)
            {
                var image = images.ElementAt(imgIndex);

                if (image.HasClass("fr-fil"))
                {
                    shape.WrapType = WrapType.Square;
                    shape.Top += shape.Height + 10;
                
                }
                else
                {
                    shape.HorizontalAlignment = HorizontalAlignment.Center;
                }
                shape.AllowOverlap = false;
                imgIndex++;
            }
        }
    }

but sometimes it doesn’t give the expected outcome.( When I reduce content between two images -you can understand this problem by using my expected and current outcomes. It has two wrapped images.)

Expected outcome expected.PNG.jpg (163.7 KB)

current outcome(this is happening when I reduce paragraph length between images.)current.PNG.jpg (161.8 KB)

HTML.zip (2.9 KB)

I can’t provide exact information because of the privacy reasons. So I have sent you a dummy HTML . My HTML is like that. You can check my issue with this HTML by changing paragraph length between those two images. images are in the third page.

Could you please help me to solve this issue?

@nethmi I am checking the issue and get back to you soon.

1 Like