The whole package of PdfSharp comes with lots of sample applications, one of them is watermark sample which shows three variations how to add a watermark to an existing PDF file.
You can see the resulting PDF as shown below.
The following is the original C# console application of Watermark sample. The C# source code was released under MIT and it was written by Thomas Hövel.
using System; using System.Diagnostics; using System.IO; using PdfSharp.Drawing; using PdfSharp.Pdf.IO; namespace Watermark { /// This sample shows three variations how to add a watermark text to an existing PDF file. class Program { static void Main() { const string watermark = "PDFsharp"; const int emSize = 150; // Get a fresh copy of the sample PDF file. const string filename = "Portable Document Format.pdf"; var file = Path.Combine(Directory.GetCurrentDirectory(), filename); File.Copy(Path.Combine("../../../../assets/PDFs/", filename), file, true); // Remove ReadOnly attribute from the copy. File.SetAttributes(file, File.GetAttributes(file) & ~FileAttributes.ReadOnly); // Create the font for drawing the watermark. var font = new XFont("Times New Roman", emSize, XFontStyle.BoldItalic); // Open an existing document for editing and loop through its pages. var document = PdfReader.Open(filename); // Set version to PDF 1.4 (Acrobat 5) because we use transparency. if (document.Version < 14) document.Version = 14; for (var idx = 0; idx < document.Pages.Count; idx++) { var page = document.Pages[idx]; switch (idx % 3) { case 0: { // Variation 1: Draw a watermark as a text string. // Get an XGraphics object for drawing beneath the existing content. var gfx = XGraphics.FromPdfPage(page, XGraphicsPdfPageOptions.Prepend); // Get the size (in points) of the text. var size = gfx.MeasureString(watermark, font); // Define a rotation transformation at the center of the page. gfx.TranslateTransform(page.Width / 2, page.Height / 2); gfx.RotateTransform(-Math.Atan(page.Height / page.Width) * 180 / Math.PI); gfx.TranslateTransform(-page.Width / 2, -page.Height / 2); // Create a string format. var format = new XStringFormat(); format.Alignment = XStringAlignment.Near; format.LineAlignment = XLineAlignment.Near; // Create a dimmed red brush. XBrush brush = new XSolidBrush(XColor.FromArgb(128, 255, 0, 0)); // Draw the string. gfx.DrawString(watermark, font, brush, new XPoint((page.Width - size.Width) / 2, (page.Height - size.Height) / 2), format); } break; case 1: { // Variation 2: Draw a watermark as an outlined graphical path. // NYI: Does not work in Core build. // Get an XGraphics object for drawing beneath the existing content. var gfx = XGraphics.FromPdfPage(page, XGraphicsPdfPageOptions.Prepend); // Get the size (in points) of the text. var size = gfx.MeasureString(watermark, font); // Define a rotation transformation at the center of the page. gfx.TranslateTransform(page.Width / 2, page.Height / 2); gfx.RotateTransform(-Math.Atan(page.Height / page.Width) * 180 / Math.PI); gfx.TranslateTransform(-page.Width / 2, -page.Height / 2); // Create a graphical path. var path = new XGraphicsPath(); // Create a string format. var format = new XStringFormat(); format.Alignment = XStringAlignment.Near; format.LineAlignment = XLineAlignment.Near; // Add the text to the path. // AddString is not implemented in PDFsharp Core. path.AddString(watermark, font.FontFamily, XFontStyle.BoldItalic, 150, new XPoint((page.Width - size.Width) / 2, (page.Height - size.Height) / 2), format); // Create a dimmed red pen. var pen = new XPen(XColor.FromArgb(128, 255, 0, 0), 2); // Stroke the outline of the path. gfx.DrawPath(pen, path); } break; case 2: { // Variation 3: Draw a watermark as a transparent graphical path above text. // NYI: Does not work in Core build. // Get an XGraphics object for drawing above the existing content. var gfx = XGraphics.FromPdfPage(page, XGraphicsPdfPageOptions.Append); // Get the size (in points) of the text. var size = gfx.MeasureString(watermark, font); // Define a rotation transformation at the center of the page. gfx.TranslateTransform(page.Width / 2, page.Height / 2); gfx.RotateTransform(-Math.Atan(page.Height / page.Width) * 180 / Math.PI); gfx.TranslateTransform(-page.Width / 2, -page.Height / 2); // Create a graphical path. var path = new XGraphicsPath(); // Create a string format. var format = new XStringFormat(); format.Alignment = XStringAlignment.Near; format.LineAlignment = XLineAlignment.Near; // Add the text to the path. // AddString is not implemented in PDFsharp Core. path.AddString(watermark, font.FontFamily, XFontStyle.BoldItalic, 150, new XPoint((page.Width - size.Width) / 2, (page.Height - size.Height) / 2), format); // Create a dimmed red pen and brush. var pen = new XPen(XColor.FromArgb(50, 75, 0, 130), 3); XBrush brush = new XSolidBrush(XColor.FromArgb(50, 106, 90, 205)); // Stroke the outline of the path. gfx.DrawPath(pen, brush, path); } break; } } // Save the document... document.Save(filename); // ...and start a viewer Process.Start(filename); } } }
In the previous article, we talked about how to use xInterop C++ .NET Bridge with Native C++ to .NET Bridge to generate the native C++ bridge DLL for PDFsharp .NET library assembly. In this Watermark example, we will need to use the native C++ bridge DLL PdbSharpgidBridge.DLL.
The following is the complete source code of the example.
// ---------------------------------------------------------------------------- // <copyright file="TestApp.cpp" company="xInterop Software, LLC"> // Copyright (c) 2016 xInterop Software, LLC. All rights reserved. // http://www.xinterop.com // </copyright> // // NOTICE: All information contained herein is, and remains the property of // xInterop Software, LLC, if any. The intellectual and technical concepts // contained herein are proprietary to xInterop Software, LLC and may be // covered by U.S. and Foreign Patents, patents in process, and are protected // by trade secret or copyright law. Dissemination of this information or // reproduction of this material is strictly forbidden unless prior written // permission is obtained from xInterop Software, LLC. // // This copyright header must be kept intact without any change under any circumstances. // // The source code of this file can NOT be re-distributed to any third parties // unless certain OEM license has been arranged and written permission has been // authorized by xInterop Software, LLC. // // ---------------------------------------------------------------------------- #include "stdafx.h" #include <Ole2.h> #include "../Native/Include/PdfSharpgdiBridge.h" #ifdef _WIN64 #pragma comment(lib, "../Native/Lib/x64/PdfSharpgdiBridge.lib") #else #pragma comment(lib, "../Native/Lib/win32/PdfSharpgdiBridge.lib") #endif using namespace::xinterop; using namespace::System::IO; using namespace::PdfSharp::Drawing; using namespace::PdfSharp::Pdf; using namespace::PdfSharp::Pdf::IO; using namespace::System::Diagnostics; int _tmain(int argc, _TCHAR* argv[]) { /////////////////////////////////////////////////////////////////////////////////////////////// // // Notes: // // This file was created when "Load .NET bridge assembly automatically" option was turned on. // // The C# bridge assembly shall be loaded and initialized automatically when any c++ // class of the C++ bridge DLL is accessed. // // The C# bridge assembly can also be loaded and initialized by calling xiInitializeBridgeAssembly. // /////////////////////////////////////////////////////////////////////////////////////////////// CoInitializeEx(0, COINIT_APARTMENTTHREADED); /////////////////////////////////////////////////////////////////////////////////////////////// // Add your code here. /////////////////////////////////////////////////////////////////////////////////////////////// const TCHAR* watermark = _T("xInterop"); const int emSize = 150; // Get a fresh copy of the sample PDF file. const TCHAR* filename = _T("Portable Document Format.pdf"); TCHAR currentDirectory[MAX_PATH]; GetCurrentDirectory(sizeof(currentDirectory), currentDirectory); auto file = Path::Combine(currentDirectory, filename); File::Copy(Path::Combine(_T("..//..//assets//PDFs//"), filename).c_str(), file.c_str(), true); // Remove ReadOnly attribute from the copy. File::SetAttributes(file.c_str(), File::GetAttributes(file.c_str()) & ~FileAttributes::ReadOnly); // Create the font for drawing the watermark. XFont font(_T("Times New Roman"), emSize, XFontStyle::BoldItalic); // Open an existing document for editing and loop through its pages. auto document = PdfReader::Open(filename); // Set version to PDF 1.4 (Acrobat 5) because we use transparency. if (document->Version < 14) document->Version = 14; auto pages = document->get_Pages(); for (int idx = 0; idx < pages->Count; idx++) { auto page = (*pages)[idx]; switch (idx % 3) { case 0: { // Variation 1: Draw a watermark as a text string. // Get an XGraphics object for drawing beneath the existing content. auto gfx = XGraphics::FromPdfPage(page.get(), XGraphicsPdfPageOptions::Prepend); // Get the size (in points) of the text. auto size = gfx->MeasureString(watermark, &font); // Define a rotation transformation at the center of the page. gfx->TranslateTransform(page->Width->Value / 2, page->Height->Value / 2); gfx->RotateTransform(-System::Math::Atan(page->Height->Value / page->Width->Value) * 180 / System::Math::XI_PI); gfx->TranslateTransform(-page->Width->Value / 2, -page->Height->Value / 2); // Create a string format. XStringFormat format; format.set_Alignment(XStringAlignment::Near); format.set_LineAlignment(XLineAlignment::Near); // Create a dimmed red brush. XSolidBrush brush(XColor::FromArgb(128, 255, 0, 0).get()); // Draw the string. XPoint point((page->Width->Value - size->Width) / 2, (page->Height->Value - size->Height) / 2); gfx->DrawString(watermark, &font, &brush, &point, &format); } break; case 1: { // Variation 2: Draw a watermark as an outlined graphical path. // NYI: Does not work in Core build. // Get an XGraphics object for drawing beneath the existing content. auto gfx = XGraphics::FromPdfPage(page.get(), XGraphicsPdfPageOptions::Prepend); // Get the size (in points) of the text. auto size = gfx->MeasureString(watermark, &font); // Define a rotation transformation at the center of the page. gfx->TranslateTransform(page->Width->Value / 2, page->Height->Value / 2); gfx->RotateTransform(-System::Math::Atan(page->Height->Value / page->Width->Value) * 180 / System::Math::XI_PI); gfx->TranslateTransform(-page->Width->Value / 2, -page->Height->Value / 2); // Create a graphical path. XGraphicsPath path; // Create a string format. XStringFormat format; format.set_Alignment(XStringAlignment::Near); format.set_LineAlignment(XLineAlignment::Near); // Add the text to the path. // AddString is not implemented in PDFsharp Core. XPoint point((page->Width->Value - size->Width) / 2, (page->Height->Value - size->Height) / 2); path.AddString(watermark, font.get_FontFamily().get(), XFontStyle::BoldItalic, 150, &point, &format); // Create a dimmed red pen. XPen pen(XColor::FromArgb(128, 255, 0, 0).get()); // Stroke the outline of the path. gfx->DrawPath(&pen, &path); } break; case 2: { // Variation 3: Draw a watermark as a transparent graphical path above text. // NYI: Does not work in Core build. // Get an XGraphics object for drawing beneath the existing content. auto gfx = XGraphics::FromPdfPage(page.get(), XGraphicsPdfPageOptions::Prepend); // Get the size (in points) of the text. auto size = gfx->MeasureString(watermark, &font); // Define a rotation transformation at the center of the page. gfx->TranslateTransform(page->Width->Value / 2, page->Height->Value / 2); gfx->RotateTransform(-System::Math::Atan(page->Height->Value / page->Width->Value) * 180 / System::Math::XI_PI); gfx->TranslateTransform(-page->Width->Value / 2, -page->Height->Value / 2); // Create a graphical path. XGraphicsPath path; // Create a string format. XStringFormat format; format.set_Alignment(XStringAlignment::Near); format.set_LineAlignment(XLineAlignment::Near); // Add the text to the path. // AddString is not implemented in PDFsharp Core. XPoint point((page->Width->Value - size->Width) / 2, (page->Height->Value - size->Height) / 2); path.AddString(watermark, font.get_FontFamily().get(), XFontStyle::BoldItalic, 150, &point, &format); // Create a dimmed red pen and brush. XPen pen(XColor::FromArgb(50, 75, 0, 130).get(), 3); XSolidBrush brush(XColor::FromArgb(50, 106, 90, 205).get()); // Stroke the outline of the path. gfx->DrawPath(&pen, &brush, &path); } break; } } // Save the document... document->Save(filename); // ...and start a viewer Process::Start(filename); /////////////////////////////////////////////////////////////////////////////////////////////// // End of your code. /////////////////////////////////////////////////////////////////////////////////////////////// CoUninitialize(); exit(0); return 0; }
The C++ code is very similar to the C# counterpart since we can simulate the C# property in the C++ code. The native C++ application creates exactly same PDF file as the one generated by the C# console sample application. Let’s go over the important steps before we can start calling the functions.
1. Include the header file for the native C++ Bridge DLL.
2. Reference the native C++ Bridge lib files.
3. Define all the required namespace inclusion.
See the difference between .NET namespace and Native C++ namespace
There are a few things worth mentioning in the C++ code.
1. Open an existing document.
2. Using properties.
In the preceding screen-shot, Version is a property. We are using them just like using the properties in the C# code.
3. System.Diagnostics.Process class
We also created the native C++ bridge class for the .NET class of Process, the screen-shot above shows how to use them.
The post Using PdfSharp for Processing PDF from Native C++ : Watermark Sample appeared first on xInterop C++ .NET Bridge.