Add a watermark to pages of PDF document in .NET

Blog category: PDF.NET

September 11, 2020

A "watermark" is a text or an image that appears in front of existing document content. For example, you could apply a "Confidential" watermark to PDF pages with sensitive information.

"PDF Reader+Writer" edition of VintaSoft PDF .NET Plug-in provides functionality for adding watermarks to pages of PDF document.

In order to don't overlap the text of PDF document the watermark should be added in "Multiply" color blending mode.
One watermark resource is used for all pages of document to create a PDF with optimal size.
A raster image or vector PDF document can be defined as watermark.

Here is C# code, which allows to add a watermark into PDF document:
// The project, which uses this code, must have references to the following assemblies:
// - Vintasoft.Imaging
// - Vintasoft.Imaging.Pdf

/// <summary>
/// Adds the watermark image to the PDF document.
/// </summary>
/// <param name="inPdfFilename">The filename of input PDF document.</param>
/// <param name="outPdfFilename">The filename of output PDF document.</param>
/// <param name="watermarkImageFilename">The filename of watermark image.</param>
public static void AddWatermarkToPdfDocument(string inPdfFilename, string outPdfFilename, string watermarkImageFilename)
{
    AddWatermarkToPdfDocument(inPdfFilename, outPdfFilename, watermarkImageFilename, 0.25f, new Vintasoft.Imaging.PaddingF(0.1f), false);
}

/// <summary>
/// Adds the watermark image to the PDF document.
/// </summary>
/// <param name="inPdfFilename">The filename of input PDF document.</param>
/// <param name="outPdfFilename">The filename of output PDF document.</param>
/// <param name="watermarkImageFilename">The filename of watermark image.</param>
/// <param name="watermarkImageAlpha">The watermark image alpha.</param>
/// <param name="watermarkImagePadding">The watermark image padding.</param>
/// <param name="ignorePageRotation">Indicates that value of Vintasoft.Imaging.Pdf.Tree.PdfPage.Rotate property should be ignored.</param>
public static void AddWatermarkToPdfDocument(
    string inPdfFilename,
    string outPdfFilename,
    string watermarkImageFilename, 
    float watermarkImageAlpha,
    Vintasoft.Imaging.PaddingF watermarkImagePadding,
    bool ignorePageRotation)
{
    // check watermark padding
    if (watermarkImagePadding.Horizontal < 0 || watermarkImagePadding.Vertical < 0)
        throw new System.ArgumentOutOfRangeException("watermarkImagePadding");

    // open PDF document
    using (Vintasoft.Imaging.Pdf.PdfDocument document = new Vintasoft.Imaging.Pdf.PdfDocument(inPdfFilename))
    {
        // create "watermark" resource
        Vintasoft.Imaging.Pdf.Tree.PdfResource watermakResource;
        using (Vintasoft.Imaging.VintasoftImage watermarkImage = new Vintasoft.Imaging.VintasoftImage(watermarkImageFilename))
        {
            // if watermarkImage is PDF page
            if (watermarkImage.SourceInfo.DecoderName == "Pdf")
            {
                // create form resource based on PDF page
                Vintasoft.Imaging.Pdf.Tree.PdfPage page = Vintasoft.Imaging.Pdf.PdfDocumentController.GetPageAssociatedWithImage(watermarkImage);
                watermakResource = new Vintasoft.Imaging.Pdf.Tree.PdfFormXObjectResource(document, page);
            }
            else
            {
                // create watermark image resource with JPEG compression
                Vintasoft.Imaging.Pdf.PdfCompression watermarkResourceCompression = Vintasoft.Imaging.Pdf.PdfCompression.Jpeg;
                watermakResource = new Vintasoft.Imaging.Pdf.Tree.PdfImageResource(document, watermarkImage, watermarkResourceCompression);
            }
        }

        // for each page in PDF document
        foreach (Vintasoft.Imaging.Pdf.Tree.PdfPage page in document.Pages)
        {
            // add watermark on PDF page
            AddWatermarkToPdfPage(page, watermakResource, watermarkImagePadding, watermarkImageAlpha, ignorePageRotation);
        }

        // pack PDF document to an output file
        document.Pack(outPdfFilename);
    }
}

/// <summary>
/// Adds the watermark image to the PDF page.
/// </summary>
/// <param name="page">The PDF page.</param>
/// <param name="watermarkResource">The PDF resource that contains watermark.</param>
/// <param name="watermarkImagePadding">The watermark image padding.</param>
/// <param name="watermarkImageAlpha">The watermark image alpha.</param>
/// <param name="ignorePageRotation">Indicates that value of Vintasoft.Imaging.Pdf.Tree.PdfPage.Rotate property should be ignored.</param>
public static void AddWatermarkToPdfPage(
    Vintasoft.Imaging.Pdf.Tree.PdfPage page,
    Vintasoft.Imaging.Pdf.Tree.PdfResource watermarkResource,
    Vintasoft.Imaging.PaddingF watermarkImagePadding,
    float watermarkImageAlpha,
    bool ignorePageRotation)
{
    Vintasoft.Imaging.Pdf.Tree.PdfImageResource watermarkImageResource = watermarkResource as Vintasoft.Imaging.Pdf.Tree.PdfImageResource;
    Vintasoft.Imaging.Pdf.Tree.PdfFormXObjectResource watermarkFormResource = watermarkResource as Vintasoft.Imaging.Pdf.Tree.PdfFormXObjectResource;

    // gets the size of watermark resource
    System.Drawing.SizeF watermarkResourceSize;
    if (watermarkImageResource != null)
        watermarkResourceSize = new System.Drawing.SizeF(watermarkImageResource.Width, watermarkImageResource.Height);
    else
        watermarkResourceSize = new System.Drawing.SizeF(watermarkFormResource.BoundingBox.Width, watermarkFormResource.BoundingBox.Height);

    // create PDF graphics from PDF page and specify that graphics must clear and add new content
    using (Vintasoft.Imaging.Pdf.Drawing.PdfGraphics graphics = Vintasoft.Imaging.Pdf.Drawing.PdfGraphics.FromPage(page))
    {
        // get mediabox of PDF page
        System.Drawing.RectangleF pageMediaBox = page.MediaBox;

        // if watermark image must be rotated
        if (!ignorePageRotation && page.Rotate != 0)
        {
            // rotate padding
            watermarkImagePadding.Rotate(page.Rotate);
        }

        // calculate watermark rectangle
        System.Drawing.RectangleF watermarkRect = new System.Drawing.RectangleF(
            pageMediaBox.X + watermarkImagePadding.Left * pageMediaBox.Width,
            pageMediaBox.Y + watermarkImagePadding.Bottom * pageMediaBox.Height,
            pageMediaBox.Width - watermarkImagePadding.Horizontal * pageMediaBox.Width,
            pageMediaBox.Height - watermarkImagePadding.Vertical * pageMediaBox.Height);
        float scale = System.Math.Min(watermarkRect.Width / watermarkResourceSize.Width, watermarkRect.Height / watermarkResourceSize.Height);
        System.Drawing.RectangleF watermarkImageRect = new System.Drawing.RectangleF(
            watermarkRect.X + (watermarkRect.Width - watermarkResourceSize.Width * scale) / 2,
            watermarkRect.Y + (watermarkRect.Height - watermarkResourceSize.Height * scale) / 2,
            watermarkResourceSize.Width * scale,
            watermarkResourceSize.Height * scale);

        // create graphics state parameters
        Vintasoft.Imaging.Pdf.Tree.PdfGraphicsStateParameters gsParams = new Vintasoft.Imaging.Pdf.Tree.PdfGraphicsStateParameters(page.Document);
        // set blending mode to "Multiply"
        gsParams.BlendMode = Vintasoft.Imaging.Pdf.Tree.GraphicsStateBlendMode.Multiply;
        // set alpha transparency
        gsParams.AlphaForNonStrokingOperations = watermarkImageAlpha;

        // save graphics state
        graphics.SaveGraphicsState();

        // set graphics state parameters
        graphics.SetGraphicsStateParameters(gsParams);

        // if watermark image must be rotated
        if (!ignorePageRotation && page.Rotate != 0)
        {
            // apply rotation to the PdfGraphics
            Vintasoft.Imaging.AffineMatrix matrix = new Vintasoft.Imaging.AffineMatrix();
            matrix.RotateAt(
                page.Rotate,
                watermarkImageRect.X + watermarkImageRect.Width / 2,
                watermarkImageRect.Y + watermarkImageRect.Height / 2);
            graphics.MultiplyTransform(matrix);
        }

        // if watermark is an image
        if (watermarkImageResource != null)
            // draw watermark image
            graphics.DrawImage(watermarkImageResource, watermarkImageRect);
        else
            // draw watermark form
            graphics.DrawForm(watermarkFormResource, watermarkImageRect);

        // restore graphics state
        graphics.RestoreGraphicsState();
    }
}     


Here is an example of PDF document each page of which contains the added watermark: testDocument_marked.pdf.