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

Hii team,

Thank you very much for your support.
Imageissue.PNG (109.8 KB)

How can I fix this image issue??? could you please help me??

@nethmi Could you please attach your input and output documents and provide the expected output? We will check your documents and provide you more information. Unfortunately, from screenshot it is not quite clear what is your expected output.

In here Imageissue.PNG (109.8 KB) image is out of the margin.

I want to adjust it according to the margins.expectedOutput.PNG (117.6 KB)

@nethmi Could you please attach actual documents? It is impossible to analyze the problem without actual document you process.

this zip file includes both html file and converted word file. In the second page, image is out of the margin. Could you please help me to fix it??
documents.zip (230.5 KB)

@nethmi I think the only way to achieve what you need is using layout information. You can achieve this using LayoutCollector and LayoutEnumerator classes. I created a code example that postprocess your DOCX document to produce the expected output:

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.
    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;

    // 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");

Hii Team,

the above code is not working for me.
I put my full code below. could you please check it??

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);
            document.Save(outputStream, SaveFormat.Docx);
            byteArray.Add(outputStream.ToArray());
        }
    }
    return byteArray;
}

private static void FormatOutput(Func<DependentContent, Task<ContentsDto>> GetDependency, Aspose.Words.Document document, HtmlDocument htmlDocument)
{
    document.Sections[0].PageSetup.LeftMargin = 50f;
    document.Sections[0].PageSetup.RightMargin = 50f;
    document.Sections[0].PageSetup.TopMargin = 50f;
    document.Sections[0].PageSetup.BottomMargin = 60f;

    AddHeader(document, GetDependency);
    AddFooter(document);
}

private static void AddHeader(Document document, System.Func<DependentContent, Task<ContentsDto>> GetDependency)
{

    var dependentContent = new DependentContent()
    {
        Id = "fa197b43-5b2a-4c53-bddd-3dad534f0284",
    };
    var content = GetDependency(dependentContent).Result;
    if (content.Found)
    {

        DocumentBuilder builder = new DocumentBuilder(document);

        Section currentSection = builder.CurrentSection;
        PageSetup pageSetup = currentSection.PageSetup;

        pageSetup.HeaderDistance = 20;
        pageSetup.DifferentFirstPageHeaderFooter = true;

        builder.MoveToHeaderFooter(HeaderFooterType.HeaderFirst);
        builder.ParagraphFormat.Alignment = ParagraphAlignment.Center;

        //Initialize a Header Instance

        using (var inputStream = new MemoryStream(content.Data))
        {

            var inputImageFromStream = Image.FromStream(inputStream);

            builder.InsertImage(inputImageFromStream, RelativeHorizontalPosition.Page, 10, RelativeVerticalPosition.Page, 10, 50, 50, WrapType.Through);
            builder.ParagraphFormat.Alignment = ParagraphAlignment.Right;

        }
    }
}

private static void AddFooter(Document document)
{
    DocumentBuilder builder = new DocumentBuilder(document);

    builder.MoveToHeaderFooter(HeaderFooterType.FooterPrimary);
    builder.Write("Page ");
    builder.InsertField("PAGE", "");
    builder.Write(" of ");
    builder.InsertField("NUMPAGES", "");
}

private static void ApplyImageFormatting(Document document, HtmlDocument htmlDocument)
{
    HtmlNodeCollection images = htmlDocument.DocumentNode.SelectNodes("//img");
    Node node = document;
    NodeCollection shapes = document.GetChildNodes(NodeType.Shape, true);
    DocumentBuilder builder = new DocumentBuilder(document);
    var img = 0;

    if (images != null)
    {
        var imgCount = 0;
        foreach (Shape shape in shapes)
        {
            var image = images.ElementAt(imgCount);
            if (image.HasClass("fr-fil"))
            {
                shape.WrapType = WrapType.Square;

            }
            else
            {
                shape.HorizontalAlignment = HorizontalAlignment.Center;
            }
            shape.AllowOverlap = false;
            imgCount++;
        }
    }
}

@nethmi Thank you for additional information, but could you please be more specific and elaborate you problem a bit more? Also, it would be great if you create a simple console application that will allow us to reproduce the problem, since some classes used in your code are not available on my side and I cannot simply run the code. And as usual, please, provide your input, output and expected output documents.

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.