Watermark visibility

Hello,

I have followed the example from Aspose to add a watermark to a file.

There are some cases where the watermark is under other objects found on the pages. For example, it is under highlighted text, under tables with background color, images, etc.

Is there any way to add the watermark in front of everything?

I have attached an example project that reproduces my issue.

Thank you,

Dan

Hi Dan,

Thanks for your inquiry. The problem occurs because watermark shape resides inside header footer story and images are inside body story (please see Story class). If you insert a watermark using Microsoft Word 2013 in source document, you will observe the same behaviour. However, you can overcome this problem by manually inserting watermarks in each Page. You can achieve this by moving the cursor to the first Paragraph in each Page of your document and then making those Paragraphs as an anchor points for your watermarks. Here is how you can achieve this:

public static void InsertWatermarkTextAtEachPage(Document doc, string watermarkText)
{
    DocumentBuilder builder = new DocumentBuilder(doc);
    PageSetup ps = builder.PageSetup;
    NodeCollection paragraphs = doc.GetChildNodes(NodeType.Paragraph, true);
    LayoutCollector collector = new LayoutCollector(doc);
    Paragraph anchorPara = null;
    int pageIndex = 1;
    foreach (Paragraph para in paragraphs)
    {
        if (collector.GetStartPageIndex(para) == pageIndex && para.GetAncestor(NodeType.GroupShape) == null)
        {
            anchorPara = para;
            Shape watermark = new Shape(doc, Aspose.Words.Drawing.ShapeType.TextPlainText);
            watermark.TextPath.Text = watermarkText;
            watermark.TextPath.FontFamily = "Arial";
            watermark.Width = 300;
            watermark.Height = 70;
            watermark.Left = 100;
            watermark.Top = 100;
            watermark.Rotation = -40;
            watermark.Fill.Color = Color.Gray;
            watermark.StrokeColor = Color.Gray;
            watermark.Name = string.Format("WaterMark_{0}", Guid.NewGuid());
            watermark.WrapType = WrapType.None;
            anchorPara.AppendChild(watermark);
            pageIndex++;
        }
    }
}

I hope, this helps.

Best regards,

Hello,

Thank you for the quick answer .

Wouldn’t this affect the performance? As if a document has a lot of pages and you have a lot of documents like that, it could really affect the time. Please, correct me if I am wrong.

So this would be the only way of doing that?

Thank you,

Dan

Hi Dan,

Thanks for your inquiry. Yes, the process of mapping of document nodes to layout objects and computing page numbers of nodes using LayoutCollector class is slower. This is required because we need to formats document into pages and updates the page layout. However, after executing this code, any rendering operation e.g rendering to PDF or image will be instantaneous.

Best regards,

Hello Awais,

Thank you for the support. I have tried it and the performance was better than I expected it.

Do you happen to know how can I insert the watermark on the highest z-order? I am asking this because I have found out that it is still behind word art or shapes.

Is there any way to get the highest z-order where I can put the watermark shape?

Thank you,

Dan

Edit: It seems to work with

watermark.ZOrder = Int32.MaxValue;

Hi Dan,

It is great you were able to find what you were looking for. Please let us know any time you have any further queries.

Best regards,

Hello again,

We have found a problem in the pagination. Basically the determination of a new page goes haywire if there is a table that continues on more pages.

As a result, the image(watermark)'s position is wrongfully calculated.

I have attached an example that shows the problem.

Is there any other way than the example above to get it right?

foreach (Aspose.Words.Paragraph para in paragraphs)
{
    if (collector.GetStartPageIndex(para) == pageIndex && para.GetAncestor(Aspose.Words.NodeType.GroupShape) == null)
    {
        var headerWaterMark = CreateWaterMarkShape(doc, wText, Color.Gray, 0.6);
        anchorPara = para;
        anchorPara.AppendChild(headerWaterMark);
        pageIndex++;
    }
}

Thank you,

Dan

Edit:

I have attached another file where the position of the image is broken on page9 . Didn’t find out why yet, but it may have something to to with paragraphs as well

I have also explained the issue here with updated info on the matter.:

The pagination that aspose has suggested in a few examples is not working in some important cases.

for (int page = 1; page <= doc.PageCount; page++)
{
    while (enumerator.MoveNext())
    {
        // Check if the current paragraph belongs to the target page.
        var paragraph = (Aspose.Words.Paragraph)enumerator.Current;
        int pageIndex = layoutCollector.GetStartPageIndex(paragraph);
        if (pageIndex == page)
        {
            InsertImage;
        }
    }
}

For example if you insert a big table that extends on more pages, the pagination goes haywire, as the following pages DO NOT have new paragraphs, so no image/any other object can be inserted there.

I also attached an example project that shows that problem with the file bigtable.docx.

Is there any other way of detecting and inserting an object/image in every page?

Thank you,

Dan

Hi Dan,

Thanks for being patient. But, I have executed the same code from here against your “bigtable.docx” and found no issue with output (see attached output document). Please upgrade to the latest version 14.5.0 and see how it goes on your end?

https://downloads.aspose.com/words/net

Best regards,

Hello Awais,

Just updated to 14.5.0 and I still get the same problem with the code attached in this message

However, I’ve recently changed the pagination type with something found on the aspose blog:

for (int page = 1; page <= doc.PageCount; page++)
{
    while (enumerator.MoveNext())
    {
        // Check if the current paragraph belongs to the target page.
        var paragraph = (Aspose.Words.Paragraph)enumerator.Current;
        int pageIndex = layoutCollector.GetStartPageIndex(paragraph);
        if (pageIndex == page)
        {
            InsertImage;
        }
    }
    enumerator.Reset();
}

While your pagination recommendation works on this particular file, it breaks the positioning on some other files with tables like the attached tables(2007).docx. This is why I switched from your pagination method to the above one, as it works with the other tests file, but not with the bigtable.docx file, unfortunately.

Thank you,

Dan

Hi Dan,

Thanks for your inquiry. Please do the following changes in your code to fix these issues:

public static void TestEachPage(string path, string wText)
{
    // Aspose.Words.License wordsLicense = new Aspose.Words.License();
    // wordsLicense.SetLicense("FREE LICENSE");
    Aspose.Words.FileFormatInfo info = Aspose.Words.FileFormatUtil.DetectFileFormat(path);
    if (info.LoadFormat == Aspose.Words.LoadFormat.Doc || info.LoadFormat == Aspose.Words.LoadFormat.Docx)
    {
        var doc = new Aspose.Words.Document(path);
        var builder = new Aspose.Words.DocumentBuilder(doc);
        var layoutCollector = new Aspose.Words.Layout.LayoutCollector(doc);
        // Images in a document are added to paragraphs, so to add an image 
        // to every page we need to find at any paragraph belonging to each page.
        //var enumerator = doc.SelectNodes("//Body/Paragraph").GetEnumerator();
        var enumerator = doc.GetChildNodes(NodeType.Paragraph, true).GetEnumerator();
        // Loop through each document page.
        for (int page = 1; page <= doc.PageCount; page++)
        {
            while (enumerator.MoveNext())
            {
                // Check if the current paragraph belongs to the target page.
                var paragraph = (Aspose.Words.Paragraph)enumerator.Current;
                int pageIndex = layoutCollector.GetStartPageIndex(paragraph);
                if (pageIndex == 2)
                {
                    // System.Windows.Forms.MessageBox.Show("PAGE 2 FOUND!");
                }
                if (pageIndex == page)
                {
                    Shape headerWaterMark = CreateWaterMarkShape(doc, wText, Color.Gray, 0.6);
                    if (paragraph.GetAncestor(NodeType.Table) != null)
                        headerWaterMark.HorizontalAlignment = HorizontalAlignment.None;
                    paragraph.AppendChild(headerWaterMark);
                    break;
                }
            }
            enumerator.Reset();
        }
        doc.Save(path);
    }
}

I hope, this helps.

Best regards,

Hello Awais,

Thank you for the suggestion. It works better now, but the positioning is still not quite correct on some pages with tables.

I have attached 2 examples in this message.

The problem can be reproduced only with a valid aspose license set. If it enters the trial mode, the library adds some paragraphs by default that hides the issue at hand.

Thank you,

Dan

Hi Dan,

The problem occurs because watermark Shape is anchored to Paragraph inside Table, and when a Shape is anchored inside Table, Microsoft Word handles it differently than when it is in the main Body. This is by Microsoft Word design. This code assumes that there must be a Paragraph on each page that is direct child of the Body. However, to overcome this problem, you must calculate the position of Shape on page where it should be displayed. For example, please see the following changes in your code:

public static void TestEachPage(string path, string wText)
{
    // Aspose.Words.License wordsLicense = new Aspose.Words.License();
    // wordsLicense.SetLicense("Aspose.Total.lic");

    Aspose.Words.FileFormatInfo info = Aspose.Words.FileFormatUtil.DetectFileFormat(path);
    if (info.LoadFormat == Aspose.Words.LoadFormat.Doc || info.LoadFormat == Aspose.Words.LoadFormat.Docx)
    {
        var doc = new Aspose.Words.Document(path);
        var builder = new Aspose.Words.DocumentBuilder(doc);
        var layoutCollector = new Aspose.Words.Layout.LayoutCollector(doc);
        // Images in a document are added to paragraphs, so to add an image
        // to every page we need to find at any paragraph belonging to each page.
        //var enumerator = doc.GetChildNodes(Aspose.Words.NodeType.Paragraph, true).GetEnumerator();
        var paragraphs = doc.GetChildNodes(Aspose.Words.NodeType.Paragraph, true);
        // Loop through each document page.
        for (int page = 1; page <= doc.PageCount; page++)
        {
            foreach (Aspose.Words.Paragraph para in paragraphs)
            {
                if (layoutCollector.GetStartPageIndex(para) == page && para.GetAncestor(Aspose.Words.NodeType.GroupShape) == null)
                {
                    var headerWaterMark = CreateWaterMarkShape(doc, wText, Color.Gray, 0.6);
                    para.AppendChild(headerWaterMark);
                    if (para.GetAncestor(Aspose.Words.NodeType.Table) != null)
                    {
                        if (para.GetAncestor(NodeType.Table) != null)
                        {
                            headerWaterMark.RelativeHorizontalPosition = RelativeHorizontalPosition.Default;
                            headerWaterMark.RelativeVerticalPosition = RelativeVerticalPosition.Paragraph;
                            headerWaterMark.HorizontalAlignment = HorizontalAlignment.Default;
                            headerWaterMark.VerticalAlignment = VerticalAlignment.Default;
                            layoutCollector = new LayoutCollector(doc);
                            LayoutEnumerator layoutEnumerator = new LayoutEnumerator(doc);
                            layoutEnumerator.Current = layoutCollector.GetEntity(headerWaterMark);
                            PageSetup ps = ((Section)para.GetAncestor(NodeType.Section)).PageSetup;
                            headerWaterMark.Top = (-1 * (layoutEnumerator.Rectangle.Top)) + (ps.PageHeight / 2) - headerWaterMark.Height / 2;
                            headerWaterMark.Left = (-1 * (layoutEnumerator.Rectangle.Left)) + (ps.PageWidth / 2) - (headerWaterMark.Width / 2);
                        }
                    }
                    break;
                }
            }
        }
        doc.Save(path);
    }
}

Please comment the following line in “CreateWaterMarkShape” method before running the above code:

// watermark.Rotation = -40;

I hope, this helps in understanding how you should calculate the position.

Best regards,