Watermarking word documents having table contents

Hi Team,

We are using Aspose.Words (v 14.10.0.0) APIs to apply watermark on MS word documents.
We are using following method, which is evolved after a series of discussion with your team (<Error while saving word document - Unexpected subdocument type)

public static void InsertWatermarkImageAtEachPage(Document doc, string watermarkImagePath)
{
    DocumentBuilder builder = new DocumentBuilder(doc);
    LayoutCollector collector = new LayoutCollector(doc);
    Paragraph anchorPara = null;
    int pageIndex = 1;
    foreach (Section section in doc.Sections)
    {
        foreach (Paragraph para in section.Body.Paragraphs)
        {
            if (collector.GetStartPageIndex(para) == pageIndex)
            {
                anchorPara = para;
                Shape watermark = new Shape(doc, Aspose.Words.Drawing.ShapeType.Image);
                watermark.ImageData.SetImage(watermarkImagePath);
                watermark.Width = 300;
                watermark.Height = 300;
                watermark.Left = 0;
                watermark.Top = 0;
                watermark.BehindText = true;
                anchorPara.AppendChild(watermark);
                pageIndex++;
            }
        }
    }
}

Now we are facing an issue while watermarking documents having table contents covering multiple pages.

In the above method, we are iterating through paragraphs and if the document is having a table covering multiple pages, then the iteration will run only for the page where table starts and it skips remaining pages and continues after the end of the table.

Because of this, watermark is getting missed on pages and this is a matter of concern for us. Our requirement is to have watermark on each page of the document.

Please look into the issue and suggest any possible solution.
I have attached a sample document, with which we can easily recreate this issue with the above mentioned code.

Thank you,
Kiran

Hi Kiran,

Thanks for your inquiry. Please use CompositeNode.GetChildNodes method as shown in following highlighted code snippet to fix the shared issue. Please let us know if you have any more queries.

public static void InsertWatermarkImageAtEachPage(Document doc, string watermarkImagePath)
{
    DocumentBuilder builder = new DocumentBuilder(doc);
    LayoutCollector collector = new LayoutCollector(doc);
    Paragraph anchorPara = null;
    int pageIndex = 1;
    foreach (Section section in doc.Sections)
    {
        foreach (Paragraph para in section.Body.GetChildNodes(NodeType.Paragraph, true))
        {
            if (collector.GetStartPageIndex(para) == pageIndex)
            {
                anchorPara = para;
                Shape watermark = new Shape(doc, Aspose.Words.Drawing.ShapeType.Image);
                watermark.ImageData.SetImage(watermarkImagePath);
                watermark.Width = 300;
                watermark.Height = 300;
                watermark.Left = 0;
                watermark.Top = 0;
                watermark.BehindText = true;
                anchorPara.AppendChild(watermark);
                pageIndex++;
            }
        }
    }
}

Thank you Tahir Manzoor. This helped to resolve the issue. Now i am able to see watermark on each page of the document.
But now a new issue has come, the alignment of watermark image is getting missed and it is going to the right side whereas it needs to be at the top left position.

I have tried changing the relative position of the shape object using following code, but it didn’t work.

shape.RelativeHorizontalPosition = Aspose.Words.Drawing.RelativeHorizontalPosition.Page;
shape.RelativeVerticalPosition = Aspose.Words.Drawing.RelativeVerticalPosition.Page;
shape.VerticalAlignment = Aspose.Words.Drawing.VerticalAlignment.Top;
shape.HorizontalAlignment = Aspose.Words.Drawing.HorizontalAlignment.Left;

It looks like the issue is with the paragraph on which we are trying to add watermark image. The watermark gets added to the paragraph but not to the page and it takes the position of the paragraph.

I have attached the sample document where you can find the issue.

Please check and provide any possible solution.

Thank you,
Kiran

Hi Kiran,

Thanks for your inquiry. You are facing this issue because the image (Shape) is inserted to paragraph node. The position of first paragraph at each page is different. Please use following modified code example to fix this issue. Hope this helps you.

If you still face problem, please manually create your expected Word document using Microsoft Word and attach it here for our reference. We will investigate how you want your final Word output be generated like. We will then provide you more information on this along with code.

public static void InsertWatermarkImageAtEachPage001(Document doc, string watermarkImagePath)
{
    DocumentBuilder builder = new DocumentBuilder(doc);
    LayoutCollector collector = new LayoutCollector(doc);
    LayoutEnumerator layoutEnumerator = new LayoutEnumerator(doc);
    Paragraph anchorPara = null;
    int pageIndex = 1;
    foreach (Section section in doc.Sections)
    {
        foreach (Paragraph para in section.Body.GetChildNodes(NodeType.Paragraph, true))
        {
            if (collector.GetStartPageIndex(para) == pageIndex)
            {
                anchorPara = para;
                Shape watermark = new Shape(doc, Aspose.Words.Drawing.ShapeType.Image);
                watermark.ImageData.SetImage(watermarkImagePath);
                // Set the width height according to your requirements
                watermark.Width = 600;
                watermark.Height = 60;
                watermark.BehindText = true;
                anchorPara.AppendChild(watermark);
                if (para.GetAncestor(NodeType.Cell) != null)
                {
                    watermark.RelativeHorizontalPosition = Aspose.Words.Drawing.RelativeHorizontalPosition.Page;
                    watermark.RelativeVerticalPosition = Aspose.Words.Drawing.RelativeVerticalPosition.Page;
                    var renderObject = collector.GetEntity(para);
                    layoutEnumerator.Current = renderObject;
                    RectangleF location = layoutEnumerator.Rectangle;
                    watermark.Left = -location.X;
                    watermark.Top = -para.ParentSection.PageSetup.TopMargin;
                }
                else
                {
                    watermark.Left = -para.ParentSection.PageSetup.LeftMargin;
                    watermark.Top = -para.ParentSection.PageSetup.TopMargin;
                }
                pageIndex++;
            }
        }
    }
}

Thank you Tahir Manzoor, It fixed watermark exactly at the top left position of the page (on each page).

I was trying to bring watermark to the bottom of the page and also to the center of the page for different requirements, but couldn’t place it exactly at the center/bottom of the page.
I tried changing the values of watermark.Left and watermark.Top, but didn’t help.

When I am setting following properties it takes the required position but gets shifted with paragraph,

for bottom :

watermark.VerticalAlignment = Aspose.Words.Drawing.VerticalAlignment.Bottom;
watermark.HorizontalAlignment=Aspose.Words.Drawing.HorizontalAlignment.Left;

and for center :

watermark.VerticalAlignment = Aspose.Words.Drawing.VerticalAlignment.Center;
watermark.HorizontalAlignment = Aspose.Words.Drawing.HorizontalAlignment.Center

Please help me to bring the watermark to the center and to the bottom positions of the page.

Thank you,
Kiran

Hi Kiran,

Thanks for your inquiry. In your case, we suggest you please set the shape’s Left and Top properties according to your requirements. Please check following highlighted code snippet to set the shape’s position at the top, center and bottom of page. Hope this helps you.

public static void InsertWatermarkImageAtEachPage001(Document doc, string watermarkImagePath)
{
    DocumentBuilder builder = new DocumentBuilder(doc);
    LayoutCollector collector = new LayoutCollector(doc);
    LayoutEnumerator layoutEnumerator = new LayoutEnumerator(doc);
    Paragraph anchorPara = null;
    int pageIndex = 1;
    foreach (Section section in doc.Sections)
    {
        foreach (Paragraph para in section.Body.GetChildNodes(NodeType.Paragraph, true))
        {
            if (collector.GetStartPageIndex(para) == pageIndex)
            {
                anchorPara = para;
                Shape watermark = new Shape(doc, Aspose.Words.Drawing.ShapeType.Image);
                watermark.ImageData.SetImage(watermarkImagePath);
                // Set the width height according to your requirements
                watermark.Width = 600;
                watermark.Height = 60;
                watermark.BehindText = true;
                anchorPara.AppendChild(watermark);
                if (para.GetAncestor(NodeType.Cell) != null)
                {
                    watermark.RelativeHorizontalPosition = Aspose.Words.Drawing.RelativeHorizontalPosition.Page;
                    watermark.RelativeVerticalPosition = Aspose.Words.Drawing.RelativeVerticalPosition.Page;
                    var renderObject = collector.GetEntity(para);
                    layoutEnumerator.Current = renderObject;
                    RectangleF location = layoutEnumerator.Rectangle;
                    watermark.Left = -location.X;
                    // Watermark at the Top of the page
                    // watermark.Top = -para.ParentSection.PageSetup.TopMargin;
                    // Watermark at the center of the page
                    // watermark.Top = para.ParentSection.PageSetup.PageHeight / 2 - watermark.Height / 2;
                    // Watermark at the bottom of the page
                    watermark.Top = para.ParentSection.PageSetup.PageHeight - para.ParentSection.PageSetup.FooterDistance - para.ParentSection.PageSetup.HeaderDistance - watermark.Height;
                }
                else
                {
                    watermark.Left = -para.ParentSection.PageSetup.LeftMargin;
                    // Watermark at the Top of the page
                    // watermark.Top = -para.ParentSection.PageSetup.TopMargin;
                    // Watermark at the center of the page
                    // watermark.Top = para.ParentSection.PageSetup.PageHeight / 2 - watermark.Height / 2;
                    // Watermark at the bottom of the page
                    watermark.Top = para.ParentSection.PageSetup.PageHeight - para.ParentSection.PageSetup.FooterDistance - para.ParentSection.PageSetup.HeaderDistance - watermark.Height;
                }
                pageIndex++;
            }
        }
    }
}

Thank you so much Tahir, it helped to fix the issue and to bring the watermark to the center/bottom position.
I used exact code and tried with word documents having different contents, and I found following outputs,

  • Watermark getting shifted with left and right margins.
  • No watermark getting applied if there is no contents in page.

I have attached a sample document where the watermark is getting shifted with the margins.

Please check and let me know how we can resolve this issue.

Thank you,
Kiran

Team,

Can we have an update on this please? This is very critical and we need to fix this on high priority.
Please check and let us know any possible solution for this issue.

Thank you,
Kiran

Hi Kiran,

Thanks for your inquiry.

rrdonnelleypa:
Watermark getting shifted with left and right margins.

Please spare us some more time for the investigation of this issue. We will get back to you as soon as we can. We apologize for any inconvenience.

rrdonnelleypa:
No watermark getting applied if there is no contents in page.

Could you please share the input document for which you are getting this issue? We will investigate the issue and provide you more information.

Tahir,

Please find the attached documents, where the second document is watermarked, but the watermark is missing in the last page which is blank (having only header and footer).

Thanks,
Kiran

Hi Kiran,

Thanks for sharing the documents. We have logged a ticket as WORDSNET-13193 for your issue in our issue tracking system. Please spare us some more time for the analysis of this issue. We will update you via this forum thread soon. Thanks for your patience and understanding.

Hi Tahir,

Is there any update on the resolution for the issue that Kiran asked for ? I am from the same team as Kiran. We are urgently in need of a resolution for this issue. Will the fix for this issue be available only in the next release ? Or will it be available within one to two days ?

Regards,
Anto Paul Thekkan

Hi Anto Paul,

Thanks for your patience. After further investigation, we noticed that LayoutEnumerator.Rectangle property does not return correct value. We have logged this issue as WORDSNET-13217 in our issue tracking system. You will be notified via this forum thread once this issue is resolved. After the fix of this issue we will share the code example to add watermark at the top, center and bottom of page.

We apologize for your inconvenience.

Hi Tahir,

Thanks for your update. While you continue to investigate this issue, could you let me know (or atleast estimate) if a possible fix could be out in the current release or next release. Based on your reply, we may have to plan our release too.

Regards,
Anto Paul Thekkan

Hi Anto Paul,

Thanks for your patience. It is to inform you that we have completed the work on issue (WORDSNET-13217) and have come to a conclusion that this is not a bug in Aspose.Words. So, we have closed this issue as ‘Not a Bug’.

As you know that the method InsertWatermarkImageAtEachPage is workaround of inserting watermark in the document. This code example appends the image (watermark) to the first paragraph of each page. The first paragraph of page might be child node of table’s cell. LayoutEnumerator.Rectangle property returns correct values when bookmark/paragraphs is inside table’s cell. The incorrect position of shape is due to “Layout in table cell” property of shape which is set to true.

We have modified the code example according to your requirements. You just need to change the values of PageRelativeY and PageRelativeX to set the watermark’s position. We have attached input and output documents with this post for your kind reference. Please check highlighted code snippet. Hope this helps you.

public static void InsertWatermarkImageAtEachPage(Document doc, string watermarkImagePath, string position)
{
    DocumentBuilder builder = new DocumentBuilder(doc);
    LayoutCollector collector = new LayoutCollector(doc);
    int pageIndex = 1;
    foreach (Section section in doc.Sections)
    {
        NodeCollection paragraphs = section.Body.GetChildNodes(NodeType.Paragraph, true);
        foreach (Paragraph para in paragraphs)
        {
            if (collector.GetStartPageIndex(para) == pageIndex)
            {
                builder.MoveToParagraph(paragraphs.IndexOf(para), 0);
                builder.StartBookmark("BM_Page" + pageIndex);
                builder.EndBookmark("BM_Page" + pageIndex);
                pageIndex++;
            }
        }
    }
    collector = new LayoutCollector(doc);
    LayoutEnumerator layoutEnumerator = new LayoutEnumerator(doc);
    // ************* Let’s assume we want the image here on each page:
    // Please set these values according to your requirements. 
    // CenterOut.docx --> PageRelativeY = 400
    // TopOut.docx --> PageRelativeY = 0
    // BottomOut.docx --> PageRelativeY = 700
    const int PageRelativeY = 0;
    const int PageRelativeX = 0;
    foreach (Bookmark bookmark in doc.Range.Bookmarks)
    {
        if (bookmark.Name.StartsWith("BM_"))
        {
            Paragraph para = (Paragraph)bookmark.BookmarkStart.ParentNode;
            Shape watermark = new Shape(doc, Aspose.Words.Drawing.ShapeType.Image);
            // ************** This should work the same way for all images not nested in cells.
            watermark.Top = PageRelativeY;
            watermark.Left = PageRelativeX;
            watermark.ImageData.SetImage(watermarkImagePath);
            // Set the width height according to your requirements
            watermark.Width = 600;
            watermark.Height = 60;
            watermark.BehindText = true;
            para.AppendChild(watermark);
            watermark.RelativeHorizontalPosition = Aspose.Words.Drawing.RelativeHorizontalPosition.Page;
            watermark.RelativeVerticalPosition = Aspose.Words.Drawing.RelativeVerticalPosition.Page;
            bool isInCell = bookmark.BookmarkStart.GetAncestor(NodeType.Cell) != null;
            if (isInCell)
            {
                var renderObject = collector.GetEntity(bookmark.BookmarkStart);
                layoutEnumerator.Current = renderObject;
                layoutEnumerator.MoveParent(LayoutEntityType.Cell);
                RectangleF location = layoutEnumerator.Rectangle;
                watermark.Top = PageRelativeY - location.Y;
                watermark.Left = PageRelativeX - location.X;
            }
        }
    }
}