Quantcast
Channel: xInterop C++ .NET Bridge
Viewing all articles
Browse latest Browse all 31

Using PdfSharp for Processing PDF from Native C++ : Watermark Sample

$
0
0

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.

image

image

image

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.

image

2. Reference the native C++ Bridge lib files.

image

3. Define all the required namespace inclusion.

image

See the difference between .NET namespace and Native C++ namespace

image

There are a few things worth mentioning in the C++ code.

1. Open an existing document.

image

2. Using properties.

image

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

image

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.


Viewing all articles
Browse latest Browse all 31

Trending Articles