Feature request - watermark visibility - foreground/stamp option

Hi!

Currently watermarks appear behind the text/grid/etc. (see attached picture)
I’d like an option to set watermark visibility to foreground, act as a stamp, always visible, and on top of everything else.

Thank you!

watermark.png (69.7 KB)

@EPluribusUnum,

The problem occurs because watermark shape resides inside header footer story and main content is inside body story (please see Story class). If you insert a watermark using Microsoft Word 2019, you will observe the same behavior. All content of document’s header/footer is always behind the main content of the document.

However, you may overcome this problem by manually inserting watermarks in each Page. You can achieve this by moving the cursor to the first Run in each Page of your document and then making those Runs as an anchor points for your watermarks. Please see the following code for example:

Document doc = new Document(MyDir + @"input.doc");

Node[] runs = doc.GetChildNodes(NodeType.Run, true).ToArray();
for (int i = 0; i < runs.Length; i++)
{
    Run run = (Run)runs[i];
    int length = run.Text.Length;

    Run currentNode = run;
    for (int x = 1; x < length; x++)
    {
        currentNode = SplitRun(currentNode, 1);
    }
}

DocumentBuilder builder = new DocumentBuilder(doc);
PageSetup ps = builder.PageSetup;

NodeCollection smallRuns = doc.GetChildNodes(NodeType.Run, true);
LayoutCollector collector = new LayoutCollector(doc);

int pageIndex = 1;
foreach (Run run in smallRuns)
{
    if (collector.GetStartPageIndex(run) == pageIndex)
    {
        Shape watermark = new Shape(doc, Aspose.Words.Drawing.ShapeType.TextPlainText);
        watermark.RelativeHorizontalPosition = RelativeHorizontalPosition.Page;
        watermark.RelativeVerticalPosition = RelativeVerticalPosition.Page;

        watermark.Width = 300;
        watermark.Height = 70;
        watermark.HorizontalAlignment = HorizontalAlignment.Center;
        watermark.VerticalAlignment = VerticalAlignment.Center;

        watermark.Rotation = -40;
        watermark.Fill.Color = Color.Gray;
        watermark.StrokeColor = Color.Gray;

        watermark.TextPath.Text = "watermarkText";
        watermark.TextPath.FontFamily = "Arial";

        watermark.Name = string.Format("WaterMark_{0}", Guid.NewGuid());
        watermark.WrapType = WrapType.None;

        builder.MoveTo(run);
        builder.InsertNode(watermark);

        pageIndex++;
    }
}

doc.Save(MyDir + @"output.doc");

private static Run SplitRun(Run run, int position)
{
    Run afterRun = (Run)run.Clone(true);
    afterRun.Text = run.Text.Substring(position);
    run.Text = run.Text.Substring((0), (0) + (position));
    run.ParentNode.InsertAfter(afterRun, run);
    return afterRun;
}

This solution looks promising, but has some issues. The text does not appear in all pages, and alignment is not right. See attached file. Any idea how to fix it?

Thank you!

Szamla_84097704_2.pdf (288.9 KB)

I would love for there to be a solution to this problem as I have been struggling with it for some time.

@EPluribusUnum,

Can you please also ZIP and upload the source Word document (that you had Szamla_84097704_2.pdf file generated from) here for testing? We will then investigate the issue further on our end and provide you more information.

@awais.hafeez, attached the dotx.

Thank you!

szamla.zip (17.1 KB)

@EPluribusUnum,

Please use the following updated code:

Document doc = new Document(@"C:\Temp\szamla\\szamla.dotx");

Node[] runs = doc.GetChildNodes(NodeType.Run, true).ToArray();
for (int i = 0; i < runs.Length; i++)
{
    Run run = (Run)runs[i];
    int length = run.Text.Length;

    Run currentNode = run;
    for (int x = 1; x < length; x++)
    {
        currentNode = SplitRun(currentNode, 1);
    }
}

DocumentBuilder builder = new DocumentBuilder(doc);

NodeCollection smallRuns = doc.GetChildNodes(NodeType.Run, true);
LayoutCollector collector = new LayoutCollector(doc);

int pageIndex = 1;
foreach (Run run in smallRuns)
{
    if (collector.GetStartPageIndex(run) == pageIndex)
    {
        bool checkIfRunIsInsideField = false;
        foreach (Field field in run.ParentParagraph.Range.Fields)
        {
            if (IsRunInsideField(field, run))
            {
                checkIfRunIsInsideField = true;
                break;
            }
        }

        if (checkIfRunIsInsideField)
            continue;

        Shape watermark = new Shape(doc, Aspose.Words.Drawing.ShapeType.TextPlainText);

        watermark.RelativeHorizontalPosition = RelativeHorizontalPosition.Page;
        watermark.RelativeVerticalPosition = RelativeVerticalPosition.Page;

        watermark.Width = 300;
        watermark.Height = 70;
        watermark.HorizontalAlignment = Aspose.Words.Drawing.HorizontalAlignment.Center;
        watermark.VerticalAlignment = VerticalAlignment.Center;

        watermark.Rotation = -40;
        watermark.Fill.Color = Color.Gray;
        watermark.StrokeColor = Color.Gray;

        watermark.TextPath.Text = "watermarkText";
        watermark.TextPath.FontFamily = "Arial";

        watermark.Name = string.Format("WaterMark_{0}", Guid.NewGuid());
        watermark.WrapType = WrapType.None;
        watermark.IsLayoutInCell = false;

        builder.MoveTo(run);
        builder.InsertNode(watermark);

        pageIndex++;
    }
}

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

private static bool IsRunInsideField(Field field, Run run)
{
    bool isInside = false;

    Node currentNode = field.Start;
    while (currentNode != field.End && !isInside)
    {
        if (currentNode.NodeType == NodeType.Run && currentNode.Equals(run))
            isInside = true;

        Node nextNode = currentNode.NextPreOrder(currentNode.Document);
        currentNode = nextNode;
    }

    return isInside;
}

private static Run SplitRun(Run run, int position)
{
    Run afterRun = (Run)run.Clone(true);
    afterRun.Text = run.Text.Substring(position);
    run.Text = run.Text.Substring((0), (0) + (position));
    run.ParentNode.InsertAfter(afterRun, run);
    return afterRun;
}

@awais.hafeez, thank you, this is good for us.

1 Like

Hello @awais.hafeez!

The last sample worked for all case until now.
I attached a template and the created pdf, where the watermark/stamp is off, not centered. (tried with latest 22.2)
Please update your last code, so it could work for this case also. Also it would be great if there will be a simple method call for watermark/stamp.

template.zip (119.6 KB)

Thank you!

@EPluribusUnum The problem is cause by compatibility options set in your document. You can use the following code to get the desired result:

doc.CompatibilityOptions.OptimizeFor(MsWordVersion.Word2007);
doc.UpdatePageLayout();
doc.Save(@"C:\Temp\\out.pdf");

@alexey.noskov, Thank you, it works!

Hi @alexey.noskov!

Unfortunately compability option switch to MS2007 messes the layout of the pdf output created (with other dotx. (e.g.: attached layout_problem.zip (275.1 KB)
)
CompabilityOption is not the proper solution. Has any other ideas?

Thank you!

@EPluribusUnum The problem is that MS Word has different rules of table layout. In MS Word 2010+ compatibility mode Shape.IsLayoutInCell does not work.
As a workaround you can avoid inserting watermark shape into the table. You can use the following condition:

if (run.GetAncestor(NodeType.Table) != null)
    continue;

However, this will not work if the whole page is ocupped by a table.
As another option, you can put a watermark later, by postprocessing your output PDF document.

@alexey.noskov

If i put the condition before int length = run.Text.Length; then the doc layout is OK, but the watermak placement is wrong, not centered.
If i put the condition to other places the watermar does not appear.

It would be great if Asposw.Words had a single method call what would did all the things needed for this, dealing with all format version. We’re not MS Word experts, we use the dotx provided by the user, and the only change we want is this watermark/stamp.

@EPluribusUnum Aspose.Words has a built-in method for inserting watermarks into the document Watermark.SetText. But in this case watermark is inserted in the header and is behind the documents content, just like watermark inserted in MS Word.
Inserting watermark in foreground is not directly supported by MS Word as well as in Aspose.Words because there might be many nuances. First of all MS Word document is flow document and if the document is edited after inserting a watermark, the watermark will be shifted.
So I would recommend to use built-in method for inserting watermark and put it in background instead of foreground.

@alexey.noskov, we switched to the generated pdf watermarking, thank you for the tip.