Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iText 7 - Add and Remove Watermark on a PDF

I would like to add and remove a watermark to a PDF using iText 7. I was able to add the watermark, but unable to remove it again. I could only find relevant code/examples related to iText 5. Any pointers appreciated, thanks.

This is how I added the Watermark (using Layers):

            pdfDoc = new PdfDocument(new PdfReader(sourceFile), new PdfWriter(destinationPath));
            var numberOfPages = pdfDoc.GetNumberOfPages();

            PageSize ps = pdfDoc.GetDefaultPageSize();

            for (var i = 1; i <= numberOfPages; i++)
            {
                PdfPage page = pdfDoc.GetPage(i);
                PdfLayer layer = new PdfLayer("watermark", pdfDoc);
                var canvas = new PdfCanvas(page);
                var pageSize = page.GetPageSize();
                var paragraph = new Paragraph(message.WatermarkText).SetFontSize(60);
                paragraph.SetFontColor(Color.BLACK, 0.2f);

                Canvas canvasModel;
                canvas.BeginLayer(layer);
                canvasModel = new Canvas(canvas, pdfDoc, ps);
                canvasModel.ShowTextAligned(paragraph, pageSize.GetWidth() / 2, pageSize.GetHeight() / 2, pdfDoc.GetPageNumber(page), TextAlignment.CENTER, VerticalAlignment.MIDDLE, 45);
                canvasModel.SetFontColor(Color.GREEN, 0.2f);
                canvas.EndLayer();
            }
            pdfDoc.Close();

This is what I have tried to remove the watermark. I want to remove it completely, not just set the layer to not display.(any sample code appreciated):

            pdfDoc = new PdfDocument(new PdfReader(sourceFile), new PdfWriter(destinationPath));                     
             IList<PdfLayer> layers = pdfDoc.GetCatalog().GetOCProperties(true).GetLayers();              

            for (var i = 0; i <= layers.Count; i++)
            {
                var t = layers[i].GetPdfObject().Get(PdfName.Name);

                if (t.ToString().Equals("watermark"))
                {
                        //Not what I want..need to remove the layer
                        layers[i].SetOn(false);
                        //This does not work...
                        //layers.RemoveAt(i);
                    }
                }
                pdfDoc.Close();
like image 259
Ivan Avatar asked Mar 08 '23 17:03

Ivan


1 Answers

With help from the guys at iText I was able to solve this. If you intend to remove the watermark later, you will need to add it as a 'PDF watermark annotation'.

To add a watermark on every page:

    public void WatermarkPDF(string sourceFile, string destinationPath)
    {
        float watermarkTrimmingRectangleWidth = 300;
        float watermarkTrimmingRectangleHeight = 300;

        float formWidth = 300;
        float formHeight = 300;
        float formXOffset = 0;
        float formYOffset = 0;

        float xTranslation = 50;
        float yTranslation = 25;

        double rotationInRads = Math.PI / 3;

        PdfFont font = PdfFontFactory.CreateFont(FontConstants.TIMES_ROMAN);
        float fontSize = 50;

        PdfDocument pdfDoc = new PdfDocument(new PdfReader(sourceFile), new PdfWriter(destinationPath));
        var numberOfPages = pdfDoc.GetNumberOfPages();
        PdfPage page = null;

        for (var i = 1; i <= numberOfPages; i++)
        {
            page = pdfDoc.GetPage(i);
            Rectangle ps = page.GetPageSize();

            //Center the annotation
            float bottomLeftX = ps.GetWidth() / 2 - watermarkTrimmingRectangleWidth / 2;
            float bottomLeftY = ps.GetHeight() / 2 - watermarkTrimmingRectangleHeight / 2;
            Rectangle watermarkTrimmingRectangle = new Rectangle(bottomLeftX, bottomLeftY, watermarkTrimmingRectangleWidth, watermarkTrimmingRectangleHeight);

            PdfWatermarkAnnotation watermark = new PdfWatermarkAnnotation(watermarkTrimmingRectangle);

            //Apply linear algebra rotation math
            //Create identity matrix
            AffineTransform transform = new AffineTransform();//No-args constructor creates the identity transform
            //Apply translation
            transform.Translate(xTranslation, yTranslation);
            //Apply rotation
            transform.Rotate(rotationInRads);

            PdfFixedPrint fixedPrint = new PdfFixedPrint();
            watermark.SetFixedPrint(fixedPrint);
            //Create appearance
            Rectangle formRectangle = new Rectangle(formXOffset, formYOffset, formWidth, formHeight);

            //Observation: font XObject will be resized to fit inside the watermark rectangle
            PdfFormXObject form = new PdfFormXObject(formRectangle);
            PdfExtGState gs1 = new PdfExtGState().SetFillOpacity(0.6f);
            PdfCanvas canvas = new PdfCanvas(form, pdfDoc);

            float[] transformValues = new float[6];
            transform.GetMatrix(transformValues);
            canvas.SaveState()
                .BeginText().SetColor(Color.GRAY, true).SetExtGState(gs1)
                .SetTextMatrix(transformValues[0], transformValues[1], transformValues[2], transformValues[3], transformValues[4], transformValues[5])
                .SetFontAndSize(font, fontSize)
                .ShowText("watermark text")
                .EndText()
                .RestoreState();

            canvas.Release();

            watermark.SetAppearance(PdfName.N, new PdfAnnotationAppearance(form.GetPdfObject()));
            watermark.SetFlags(PdfAnnotation.PRINT);

            page.AddAnnotation(watermark);

        }
        page?.Flush();
        pdfDoc.Close();
    } 

To remove the watermark:

    public void RemovetWatermarkPDF(string sourceFile, string destinationPath)
    {
        PdfDocument pdfDoc = new PdfDocument(new PdfReader(sourceFile), new PdfWriter(destinationPath));
        var numberOfPages = pdfDoc.GetNumberOfPages();

        for (var i = 1; i <= numberOfPages; i++)
        {
            // PdfAnnotation 
            PdfDictionary pageDict = pdfDoc.GetPage(i).GetPdfObject();
            PdfArray annots = pageDict.GetAsArray(PdfName.Annots);
            for (int j = 0; j < annots.Size(); j++)
            {
                PdfDictionary annotation = annots.GetAsDictionary(j);
                if (PdfName.Watermark.Equals(annotation.GetAsName(PdfName.Subtype)))
                {
                    annotation.Clear();
                }
            }
        }
        pdfDoc.Close();
    }

What about variable length watermark text? How would you dynamically resize the rectangle to fit the text? This is not inbuilt into iText, you would need to play around with the following dimension parameters:

float watermarkTrimmingRectangleWidth = 600;
float watermarkTrimmingRectangleHeight = 600;
float formWidth = 600;
float formHeight = 600;
float formXOffset = -100;
float fontSize = 30;

For my use-case I checked the length of the watermark text and based on that adjusted the parameters accordingly eg:

        if (watermarkText.Length <= 14)
        {
            watermarkTrimmingRectangleWidth = 200;
            watermarkTrimmingRectangleHeight = 200;
            formWidth = 200;
            formHeight = 200;
            formXOffset = 0;
            fontSize = 30;
        }
        else if (watermarkText.Length <= 22)
        {
            watermarkTrimmingRectangleWidth = 300;
            watermarkTrimmingRectangleHeight = 300;
            formWidth = 300;
            formHeight = 300;
            formXOffset = 0;
            fontSize = 30;
        }
        else if (...)
        {
         ...           
        }
        .
        .
        etc.
        .
        .
        else if (watermarkText.Length <= 62)
        {
            watermarkTrimmingRectangleWidth = 600;
            watermarkTrimmingRectangleHeight = 600;
            formWidth = 600;
            formHeight = 600;
            formXOffset = -100;
            fontSize = 20;
        }
like image 134
Ivan Avatar answered Mar 23 '23 00:03

Ivan