Skip to content

Commit 800a459

Browse files
authored
Merge pull request #69 from SyncfusionExamples/ESign_Sample
Added sample for E signing in PDF document using WPF PDFViewer
2 parents ca51838 + f71aa04 commit 800a459

17 files changed

+577
-0
lines changed

Signature/Add_ESign/App.config

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<configuration>
3+
<startup>
4+
5+
</startup>
6+
</configuration>

Signature/Add_ESign/App.xaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<Application x:Class="PDFViewer_WPF.App"
2+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4+
xmlns:local="clr-namespace:PDFViewer_WPF"
5+
StartupUri="MainWindow.xaml">
6+
<Application.Resources>
7+
8+
</Application.Resources>
9+
</Application>

Signature/Add_ESign/App.xaml.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Configuration;
4+
using System.Data;
5+
using System.Linq;
6+
using System.Threading.Tasks;
7+
using System.Windows;
8+
9+
namespace PDFViewer_WPF
10+
{
11+
/// <summary>
12+
/// Interaction logic for App.xaml
13+
/// </summary>
14+
public partial class App : Application
15+
{
16+
}
17+
}
61.1 KB
Binary file not shown.

Signature/Add_ESign/Data/John.png

2.84 KB
Loading

Signature/Add_ESign/Data/PDF.pfx

2.52 KB
Binary file not shown.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<Window xmlns:syncfusion="http://schemas.syncfusion.com/wpf" xmlns:PdfViewer="clr-namespace:Syncfusion.Windows.PdfViewer;assembly=Syncfusion.PdfViewer.WPF" x:Class="WPF_Sample_FW.MainWindow"
2+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
5+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
6+
xmlns:local="clr-namespace:WPF_Sample_FW"
7+
mc:Ignorable="d"
8+
Title="MainWindow" Height="450" Width="800">
9+
<Grid>
10+
<PdfViewer:PdfViewerControl Name="PDFViewer" PageClicked="PDFViewer_PageClicked"/>
11+
12+
</Grid>
13+
</Window>
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
using Syncfusion.Pdf;
2+
using Syncfusion.Pdf.Graphics;
3+
using Syncfusion.Pdf.Security;
4+
using Syncfusion.Windows.PdfViewer;
5+
using System;
6+
using System.Drawing;
7+
using System.IO;
8+
using System.Windows;
9+
using System.Windows.Controls;
10+
using System.Windows.Media;
11+
using Path = System.Windows.Shapes.Path;
12+
using Bitmap = System.Drawing.Bitmap;
13+
14+
namespace WPF_Sample_FW
15+
{
16+
/// <summary>
17+
/// Interaction logic for MainWindow.xaml
18+
/// </summary>
19+
public partial class MainWindow : Window
20+
{
21+
string filePath = "../../../Data/";
22+
bool addSignature = false;
23+
public MainWindow()
24+
{
25+
InitializeComponent();
26+
PDFViewer.Load(filePath + "Ink signature.pdf");
27+
PDFViewer.Loaded += PDFViewer_Loaded;
28+
PDFViewer.ZoomMode = ZoomMode.FitPage;
29+
}
30+
31+
private void PDFViewer_Loaded(object sender, RoutedEventArgs e)
32+
{
33+
// Find the default toolbar from the PDFViewer control template.
34+
DocumentToolbar toolbar = PDFViewer.Template.FindName("PART_Toolbar", PDFViewer) as DocumentToolbar;
35+
36+
// Find the stack panel inside the toolbar where buttons are arranged.
37+
StackPanel stackPanel = (StackPanel)toolbar.Template.FindName("PART_ToolbarStack", toolbar);
38+
39+
// Get the last stack panel in the toolbar stack (usually contains default buttons).
40+
StackPanel stack = stackPanel.Children[stackPanel.Children.Count - 1] as StackPanel;
41+
42+
// Get the first button from the stack to copy its style and icon.
43+
Button button = stack.Children[0] as Button;
44+
Path oldStylePath = button.Content as Path;
45+
46+
Button eSignButton = GetButton(oldStylePath, button);
47+
48+
// Add the new eSign button to the toolbar stack.
49+
stackPanel.Children.Add(eSignButton);
50+
}
51+
52+
private void eSignButton_Click(object sender, RoutedEventArgs e)
53+
{
54+
addSignature = true;
55+
}
56+
57+
private Button GetButton(System.Windows.Shapes.Path oldPath, Button button)
58+
{
59+
// Create a new custom button for eSign functionality.
60+
Button eSignButton = new Button();
61+
62+
// Create a new Path object to use as the icon for the eSign button.
63+
Path path = new Path();
64+
path.Data = System.Windows.Media.Geometry.Parse("M218.17 424.14c-2.95-5.92-8.09-6.52-10.17-6.52s-7.22.59-10.02 6.19l-7.67 15.34c-6.37 12.78-25.03 11.37-29.48-2.09L144 386.59l-10.61 31.88c-5.89 17.66-22.38 29.53-41 29.53H80c-8.84 0-16-7.16-16-16s7.16-16 16-16h12.39c4.83 0 9.11-3.08 10.64-7.66l18.19-54.64c3.3-9.81 12.44-16.41 22.78-16.41s19.48 6.59 22.77 16.41l13.88 41.64c19.75-16.19 54.06-9.7 66 14.16 1.89 3.78 5.49 5.95 9.36 6.26v-82.12l128-127.09V160H248c-13.2 0-24-10.8-24-24V0H24C10.7 0 0 10.7 0 24v464c0 13.3 10.7 24 24 24h336c13.3 0 24-10.7 24-24v-40l-128-.11c-16.12-.31-30.58-9.28-37.83-23.75zM384 121.9c0-6.3-2.5-12.4-7-16.9L279.1 7c-4.5-4.5-10.6-7-17-7H256v128h128v-6.1zm-96 225.06V416h68.99l161.68-162.78-67.88-67.88L288 346.96zm280.54-179.63l-31.87-31.87c-9.94-9.94-26.07-9.94-36.01 0l-27.25 27.25 67.88 67.88 27.25-27.25c9.95-9.94 9.95-26.07 0-36.01z");
65+
66+
// Copy the fill color from the existing button's icon.
67+
path.Fill = oldPath.Fill;
68+
69+
// Set the icon as the content of the new button.
70+
eSignButton.Content = path;
71+
72+
// Match the icon's size and layout to the original button.
73+
path.Stretch = Stretch.Uniform;
74+
path.Height = oldPath.Height;
75+
path.Width = oldPath.Width;
76+
77+
// Match the button's background and layout properties to the original button.
78+
eSignButton.Height = button.Height;
79+
eSignButton.Width = button.Width;
80+
eSignButton.Margin = button.Margin;
81+
eSignButton.Style = button.Style;
82+
// Attach the click event handler for eSign functionality.
83+
eSignButton.Click += eSignButton_Click;
84+
85+
return eSignButton;
86+
}
87+
88+
private void PDFViewer_PageClicked(object sender, PageClickedEventArgs args)
89+
{
90+
if (addSignature)
91+
{
92+
int pageIndex = PDFViewer.CurrentPageIndex - 1;
93+
CreateSignatureImage();
94+
95+
//Gets the first page of the document
96+
PdfLoadedPage page = PDFViewer.LoadedDocument.Pages[pageIndex] as PdfLoadedPage;
97+
98+
//Retrieve the clicked client area position
99+
System.Windows.Point clientPoint = args.Position;
100+
101+
// Convert client point to page point, which accounts for zoom mode.
102+
System.Windows.Point pagePoint = PDFViewer.ConvertClientPointToPagePoint(clientPoint, pageIndex + 1);
103+
double x = pagePoint.X;
104+
double y = pagePoint.Y;
105+
106+
//Creates a certificate instance from PFX file with private key.
107+
PdfCertificate pdfCert = new PdfCertificate( filePath + "PDF.pfx", "password123");
108+
109+
//Creates a digital signature
110+
PdfSignature Signature = new PdfSignature(PDFViewer.LoadedDocument, page, pdfCert, "Signature");
111+
112+
//Sets an image for signature field
113+
PdfBitmap signatureImage = new PdfBitmap( filePath + "ESign.png");
114+
115+
// Center the signature on the click position using dimensions in points.
116+
float signWidth = signatureImage.PhysicalDimension.Width;
117+
float signHeight = signatureImage.PhysicalDimension.Height;
118+
Signature.Bounds = new System.Drawing.RectangleF((float)(x), (float)(y), signWidth, signHeight);
119+
120+
Signature.ContactInfo = "[email protected]";
121+
Signature.LocationInfo = "Honolulu, Hawaii";
122+
Signature.Reason = "I am author of this document.";
123+
124+
//Draws the signature image
125+
Signature.Appearance.Normal.Graphics.DrawImage(signatureImage, 0, 0);
126+
127+
//Save the document into stream.
128+
MemoryStream stream = new MemoryStream();
129+
PDFViewer.LoadedDocument.Save(stream);
130+
stream.Position = 0;
131+
132+
//Reloads the document
133+
PDFViewer.Load(stream);
134+
addSignature = false;
135+
}
136+
137+
}
138+
139+
private void CreateSignatureImage()
140+
{
141+
int pageIndex = PDFViewer.CurrentPageIndex - 1;
142+
if(pageIndex < 0)
143+
return;
144+
145+
//Creating image for current date and time details
146+
CreateCurrentDataImage();
147+
148+
//Combine the name image and date-time image into a single image
149+
CombineSignatureAndDataImage();
150+
151+
}
152+
153+
private void CombineSignatureAndDataImage()
154+
{
155+
// Load the two images
156+
using (System.Drawing.Image nameImage = System.Drawing.Image.FromFile(filePath + "John.png"))
157+
using (System.Drawing.Image signImage = System.Drawing.Image.FromFile(filePath + "DigitalSignatureBlock.png"))
158+
{
159+
// Create a new bitmap with combined width and max height
160+
int signatureWidth = nameImage.Width + signImage.Width;
161+
int signatureHeight = Math.Max(nameImage.Height, signImage.Height);
162+
using (Bitmap combinedImage = new Bitmap(signatureWidth, signatureHeight))
163+
using (Graphics g = System.Drawing.Graphics.FromImage(combinedImage))
164+
{
165+
// Draw both images side by side
166+
g.DrawImage(nameImage, 0, 0);
167+
g.DrawImage(signImage, nameImage.Width, 0);
168+
// Save the result
169+
combinedImage.Save(filePath + "ESign.png", System.Drawing.Imaging.ImageFormat.Png);
170+
}
171+
}
172+
}
173+
174+
private void CreateCurrentDataImage()
175+
{
176+
int width = 200;
177+
int height = 100;
178+
string signerName = "John";
179+
string dateTime = DateTime.Now.ToString("yyyy.MM.dd\nHH:mm:ss zzz");
180+
string text = $"Digitally signed by {signerName}\nDate: {dateTime}\n\n";
181+
string outputPath = filePath + "DigitalSignatureBlock.png";
182+
Directory.CreateDirectory(System.IO.Path.GetDirectoryName(outputPath));
183+
using (Bitmap bitmap = new Bitmap(width, height))
184+
{
185+
using (Graphics graphics = System.Drawing.Graphics.FromImage(bitmap))
186+
{
187+
using (Font font = new Font("Arial", 9))
188+
using (SolidBrush backgroundBrush = new SolidBrush(System.Drawing.Color.White))
189+
{
190+
graphics.FillRectangle(backgroundBrush, 0, 0, width, height);
191+
RectangleF layoutRect = new RectangleF(10, 10, width - 20, height - 20);
192+
graphics.DrawString(text, font, System.Drawing.Brushes.Black, layoutRect);
193+
bitmap.Save(outputPath, System.Drawing.Imaging.ImageFormat.Png);
194+
}
195+
}
196+
}
197+
}
198+
}
199+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>WinExe</OutputType>
5+
</PropertyGroup>
6+
7+
<ItemGroup>
8+
<PackageReference Include="Syncfusion.PdfViewer.WPF" Version="*" />
9+
<PackageReference Include="System.Drawing.Common" Version="9.0.8" />
10+
</ItemGroup>
11+
<Import Project="targets\MultiTargeting.targets" />
12+
</Project>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.14.36401.2
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PDFViewer_WPF", "PDFViewer_WPF.csproj", "{0FAA7523-B034-4EA9-860A-A8936DFFD40E}"
7+
EndProject
8+
Global
9+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
10+
Debug|Any CPU = Debug|Any CPU
11+
Release|Any CPU = Release|Any CPU
12+
EndGlobalSection
13+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
14+
{0FAA7523-B034-4EA9-860A-A8936DFFD40E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15+
{0FAA7523-B034-4EA9-860A-A8936DFFD40E}.Debug|Any CPU.Build.0 = Debug|Any CPU
16+
{0FAA7523-B034-4EA9-860A-A8936DFFD40E}.Release|Any CPU.ActiveCfg = Release|Any CPU
17+
{0FAA7523-B034-4EA9-860A-A8936DFFD40E}.Release|Any CPU.Build.0 = Release|Any CPU
18+
EndGlobalSection
19+
GlobalSection(SolutionProperties) = preSolution
20+
HideSolutionNode = FALSE
21+
EndGlobalSection
22+
GlobalSection(ExtensibilityGlobals) = postSolution
23+
SolutionGuid = {BAAD6341-6945-42C7-8438-919E9DB8EB03}
24+
EndGlobalSection
25+
EndGlobal

0 commit comments

Comments
 (0)