Search code examples
c#office-interopwatermark

Adding text watermark using Microsoft Interop does't work properly if there is a table or an image on header


here is my code to add text watermark to the center of a document.

foreach (Microsoft.Office.Interop.Word.Section section in wordDoc.Sections)
            {
                Microsoft.Office.Interop.Word.Shape wordShape = section.Headers[Microsoft.Office.Interop.Word.WdHeaderFooterIndex.wdHeaderFooterPrimary].Shapes.AddTextEffect
                (Microsoft.Office.Core.MsoPresetTextEffect.msoTextEffect1, "I am a watermark", "Arial", (float)30, Microsoft.Office.Core.MsoTriState.msoTrue,
                Microsoft.Office.Core.MsoTriState.msoFalse, 0, 0, o);
                
                wordShape.Fill.Visible = Microsoft.Office.Core.MsoTriState.msoTrue;
                wordShape.Fill.Solid();
                wordShape.Fill.ForeColor.RGB = (Int32)Microsoft.Office.Interop.Word.WdColor.wdColorGray15;
                wordShape.Line.Visible = Microsoft.Office.Core.MsoTriState.msoFalse;
                wordShape.WrapFormat.Type = Microsoft.Office.Interop.Word.WdWrapType.wdWrapBehind;
                wordShape.Rotation = -45;
                wordShape.Left = (float)Microsoft.Office.Interop.Word.WdShapePosition.wdShapeCenter;
                wordShape.Top = (float)Microsoft.Office.Interop.Word.WdShapePosition.wdShapeCenter;
                wordShape.RelativeHorizontalPosition = Microsoft.Office.Interop.Word.WdRelativeHorizontalPosition.wdRelativeHorizontalPositionPage;
                wordShape.RelativeVerticalPosition = Microsoft.Office.Interop.Word.WdRelativeVerticalPosition.wdRelativeVerticalPositionPage;
            }

The problem is that the watermark is placed oddly if there is a table or image added on header and not added on the first page of the document.It works well with documents without any header. 1

And I tried the following code to add the watermark on all pages.

 WdHeaderFooterIndex hfIndex = WdHeaderFooterIndex.wdHeaderFooterPrimary;
            HeaderFooter headerFooter;

            foreach (Microsoft.Office.Interop.Word.Section section in wordDoc.Sections)
            {
                Microsoft.Office.Interop.Word.Shape wordShapeFirstPage = section.Headers[WdHeaderFooterIndex.wdHeaderFooterFirstPage].Shapes.AddTextEffect
                (Microsoft.Office.Core.MsoPresetTextEffect.msoTextEffect1, "I am watermark", "Calibri", (float)30, Microsoft.Office.Core.MsoTriState.msoTrue,
                Microsoft.Office.Core.MsoTriState.msoFalse, 0, 0, o);

                Microsoft.Office.Interop.Word.Shape wordShapePrimary = section.Headers[WdHeaderFooterIndex.wdHeaderFooterPrimary].Shapes.AddTextEffect
                (Microsoft.Office.Core.MsoPresetTextEffect.msoTextEffect1, "I am watermark", "Calibri", (float)30, Microsoft.Office.Core.MsoTriState.msoTrue,
                Microsoft.Office.Core.MsoTriState.msoFalse, 0, 0, o);

                List<Microsoft.Office.Interop.Word.Shape> wordShapeList = new List<Microsoft.Office.Interop.Word.Shape>();
               
                wordShapeList.Add(wordShapePrimary);
                wordShapeList.Add(wordShapeFirstPage);

                foreach (Shape wordShape in wordShapeList)
                {
                    wordShape.Fill.Visible = Microsoft.Office.Core.MsoTriState.msoTrue;
                    wordShape.Fill.Solid();
                    wordShape.Fill.ForeColor.RGB = (Int32)Microsoft.Office.Interop.Word.WdColor.wdColorGray15;
                    wordShape.Line.Visible = Microsoft.Office.Core.MsoTriState.msoFalse;
                    wordShape.WrapFormat.AllowOverlap = -1;
                    wordShape.WrapFormat.Type = Microsoft.Office.Interop.Word.WdWrapType.wdWrapBehind;
                    wordShape.Rotation = -45;
                    wordShape.RelativeHorizontalPosition = Microsoft.Office.Interop.Word.WdRelativeHorizontalPosition.wdRelativeHorizontalPositionPage;
                    wordShape.RelativeVerticalPosition = Microsoft.Office.Interop.Word.WdRelativeVerticalPosition.wdRelativeVerticalPositionPage;
                    wordShape.Left = (float)Microsoft.Office.Interop.Word.WdShapePosition.wdShapeCenter;
                    wordShape.Top = (float)Microsoft.Office.Interop.Word.WdShapePosition.wdShapeCenter;
                  
                }
            }

Then the watermark is added on the first page, too, but still is misplaced on other pages. How can I fix it?


Solution

  • The Shapes.AddTextEffect method that is used to create the watermark has an Anchor parameter that was intended to allow developers to position the watermark's anchor. Unfortunately, this parameter has a long-existing bug that makes it nonfunctional. As such, Shapes.AddTextEffect will default to positioning the watermark relative to the top and left edges of the page or inside a table when one is within the header.

    To work around this issue, place the contents of the header on the Windows Clipboard, add the watermark, and then paste the header contents back into the header before (and without overwriting) the watermark anchor. Here is the code, with explanatory comments:

    Word.Document wordDoc = Globals.ThisAddIn.Application.ActiveDocument;
    
    foreach (Microsoft.Office.Interop.Word.Section section in wordDoc.Sections)
    {
        //Place the contents of the header on the Windows Clipboard
        section.Headers[Microsoft.Office.Interop.Word.WdHeaderFooterIndex.wdHeaderFooterPrimary].Range.Cut();
        
        //Your code
        Microsoft.Office.Interop.Word.Shape wordShape = section.Headers[Microsoft.Office.Interop.Word.WdHeaderFooterIndex.wdHeaderFooterPrimary].Shapes.AddTextEffect
        (Microsoft.Office.Core.MsoPresetTextEffect.msoTextEffect1, "I am a watermark", "Arial", (float)30, Microsoft.Office.Core.MsoTriState.msoTrue,
        Microsoft.Office.Core.MsoTriState.msoFalse, 0, 0);
        
        wordShape.Fill.Visible = Microsoft.Office.Core.MsoTriState.msoTrue;
        wordShape.Fill.Solid();
        wordShape.Fill.ForeColor.RGB = (Int32)Microsoft.Office.Interop.Word.WdColor.wdColorGray15;
        wordShape.Line.Visible = Microsoft.Office.Core.MsoTriState.msoFalse;
        wordShape.WrapFormat.Type = Microsoft.Office.Interop.Word.WdWrapType.wdWrapBehind;
        wordShape.Rotation = -45;
        wordShape.Left = (float)Microsoft.Office.Interop.Word.WdShapePosition.wdShapeCenter;
        wordShape.Top = (float)Microsoft.Office.Interop.Word.WdShapePosition.wdShapeCenter;
        wordShape.RelativeHorizontalPosition = Microsoft.Office.Interop.Word.WdRelativeHorizontalPosition.wdRelativeHorizontalPositionPage;
        wordShape.RelativeVerticalPosition = Microsoft.Office.Interop.Word.WdRelativeVerticalPosition.wdRelativeVerticalPositionPage;
    
        //Paste the Windows Clipboard contents in a collapsed range to avoid overwriting the watermark anchor
        Word.Range headerRange = section.Headers[Microsoft.Office.Interop.Word.WdHeaderFooterIndex.wdHeaderFooterPrimary].Range;
        headerRange.Collapse(Word.WdCollapseDirection.wdCollapseStart);
        headerRange.Paste();
        headerRange.Collapse(Word.WdCollapseDirection.wdCollapseEnd);
        headerRange.Delete(Word.WdUnits.wdCharacter, -1); //deletes paste-generated extra carriage return (Word ignores this when extra carriage return does not exist)
    }