using ComPDFKit.DigitalSign; using ComPDFKit.Import; using ComPDFKit.PDFAnnotation; using ComPDFKit.PDFAnnotation.Form; using ComPDFKit.PDFDocument; using ComPDFKit.PDFPage; using ComPDFKit.Controls.Helper; using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Reflection; using System.Runtime.InteropServices; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Ink; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using Pen = System.Windows.Media.Pen; using PixelFormat = System.Windows.Media.PixelFormat; using Point = System.Windows.Point; using Window = System.Windows.Window; namespace ComPDFKit.Controls.PDFControl { /// /// Interaction logic for CPDFSignControl.xaml /// public partial class FillDigitalSignatureControl : UserControl { private readonly string logoPath = "Logo_opa40.png"; private string imagePath = string.Empty; private string Text = string.Empty; private Dictionary TabDict { get; set; } private CPDFSignatureConfig tempSignatureConfig = new CPDFSignatureConfig(); private CPDFSignatureCertificate signatureCertificate; public CPDFDocument Document; private string signatureName = string.Empty; private string location = string.Empty; private string reason = string.Empty; private float[] textColor = new float[] { 0, 0, 0 }; private string _signaturePath = string.Empty; public string SignaturePath { get => _signaturePath; set { _signaturePath = value; } } private string _password = string.Empty; public string Password { get => _password; set { _password = value; signatureCertificate = CPDFPKCS12CertHelper.GetCertificateWithPKCS12Path(SignaturePath, Password); signatureName = DictionaryValueConverter.GetGrantorFromDictionary(signatureCertificate.SubjectDict); tempSignatureConfig.Text = signatureName; InitTempSignature(); } } private void InitTempSignature() { NameChk.IsChecked = true; DateChk.IsChecked = true; LogoChk.IsChecked = true; TabChk.IsChecked = true; SetProperty(); CreateTempSignature(); KeyboardInPutTextBox.Text = signatureName; } public CPDFSignatureWidget signatureWidget { get; set; } public event EventHandler AfterFillSignature; public FillDigitalSignatureControl() { InitializeComponent(); TabDict = new Dictionary { ["Keyboard"] = KeyboardBorder, ["Trackpad"] = TrackpadBorder, ["Image"] = ImageBorder, ["None"] = NoneBorder }; SetCheckedTab("Keyboard"); ReasonCmb.SelectedIndex = 0; } private void CreateTempSignature() { CPDFDocument tempDocument = CPDFDocument.CreateDocument(); tempDocument.InsertPage(0, 200, 200, string.Empty); CPDFPage page = tempDocument.PageAtIndex(0); CPDFSignatureWidget signatureWidget = page.CreateWidget(C_WIDGET_TYPE.WIDGET_SIGNATUREFIELDS) as CPDFSignatureWidget; signatureWidget.SetRect(new CRect(0, 100, 300, 0)); tempSignatureConfig.IsDrawLogo = (bool)LogoChk.IsChecked; if (tempSignatureConfig.IsDrawLogo) { if(!string.IsNullOrEmpty(logoPath)) { byte[] imageData = null; int imageWidth = 0; int imageHeight = 0; ComPDFKit.Tool.Help.PDFHelp.ImagePathToByte(logoPath, ref imageData, ref imageWidth, ref imageHeight); if (imageData != null && imageWidth > 0 && imageHeight > 0) { if (signatureWidget.IsValid()) { tempSignatureConfig.LogoData = imageData; tempSignatureConfig.LogoWidth = imageWidth; tempSignatureConfig.LogoHeight = imageHeight; } } } } tempSignatureConfig.Content = Text; tempSignatureConfig.TextColor = textColor; tempSignatureConfig.ContentColor = new float[] { 0, 0, 0 }; signatureWidget.UpdataApWithSignature(tempSignatureConfig); byte[] signatureBitmapBytes = GetTempSignatureImage(signatureWidget, out int width, out int height); signatureWidget.ReleaseAnnot(); if (signatureBitmapBytes.Length > 0) { PixelFormat fmt = PixelFormats.Bgra32; BitmapSource bps = BitmapSource.Create(width, height, 96, 96, fmt, null, signatureBitmapBytes, (width * fmt.BitsPerPixel + 7) / 8); imageControl.Source = bps; } else { imageControl.Source = null; } } public static byte[] GetTempSignatureImage(CPDFSignatureWidget signatureWidget, out int width, out int height) { CRect rect = signatureWidget.GetRect(); var flags = BindingFlags.NonPublic | BindingFlags.Static; var dpiProperty = typeof(SystemParameters).GetProperty("Dpi", flags); int dpi = (int)dpiProperty.GetValue(null, null); width = (int)(rect.width() * dpi / 72D * 2); height = (int)(rect.height() * dpi / 72D * 2); byte[] imageData = new byte[width * height * 4]; signatureWidget.RenderAnnot(width, height, imageData, CPDFAppearanceType.Normal); return imageData; } private void TextAlignBtn_Click(object sender, RoutedEventArgs e) { ToggleButton checkBtn = sender as ToggleButton; if (checkBtn == null) { return; } checkBtn.IsChecked = true; if (checkBtn != TextAlignLeftBtn) { tempSignatureConfig.IsContentAlignLeft = true; TextAlignLeftBtn.IsChecked = false; } if (checkBtn != TextAlignRightBtn) { tempSignatureConfig.IsContentAlignLeft = false; TextAlignRightBtn.IsChecked = false; } CreateTempSignature(); } private void Border_MouseDown(object sender, MouseButtonEventArgs e) { Border clickBorder = sender as Border; if (clickBorder == null || clickBorder.Tag == null) { return; } SetCheckedTab(clickBorder.Tag.ToString()); ImagePickPanel.Visibility = Visibility.Hidden; if (clickBorder == NoneBorder) { tempSignatureConfig.IsDrawOnlyContent = true; } else { tempSignatureConfig.IsDrawOnlyContent = false; if (clickBorder == KeyboardBorder) { tempSignatureConfig.Text = signatureName; //tempSignatureConfig.ImageBitmap = null; KeyboardPopup.Visibility = Visibility.Visible; } else { tempSignatureConfig.Text = string.Empty; if (clickBorder == TrackpadBorder) { CanvaDrawPopup.Visibility = Visibility.Visible; } else if (clickBorder == ImageBorder) { ImagePickPanel.Visibility = Visibility.Visible; if (!string.IsNullOrEmpty(imagePath)) { byte[] imageData = null; int imageWidth = 0; int imageHeight = 0; ComPDFKit.Tool.Help.PDFHelp.ImagePathToByte(imagePath, ref imageData, ref imageWidth, ref imageHeight); if (imageData != null && imageWidth > 0 && imageHeight > 0) { if (signatureWidget.IsValid()) { tempSignatureConfig.ImageData = imageData; tempSignatureConfig.ImageWidth = imageWidth; tempSignatureConfig.ImageHeight = imageHeight; } } } } } } SetProperty(); CreateTempSignature(); } private void SetCheckedTab(string tab) { if (TabDict != null && TabDict.ContainsKey(tab)) { foreach (string key in TabDict.Keys) { Border checkBorder = TabDict[key]; if (checkBorder == null) { continue; } checkBorder.BorderThickness = new Thickness(0); if (key == tab) { checkBorder.BorderThickness = new Thickness(0, 0, 0, 2); } } } } private void CanvasPopupClose_Click(object sender, RoutedEventArgs e) { CanvaDrawPopup.Visibility = Visibility.Collapsed; } private void CanvasClearBtn_Click(object sender, RoutedEventArgs e) { DrawInkCanvas.Strokes.Clear(); } private void CanvasPopupConfirm_Click(object sender, RoutedEventArgs e) { int height = 0; int width = 0; tempSignatureConfig.ImageData = GetDrawInk(ref height,ref width); tempSignatureConfig.ImageWidth = width; tempSignatureConfig.ImageHeight = height; CanvaDrawPopup.Visibility = Visibility.Collapsed; SetProperty(); CreateTempSignature(); } public byte[] GetDrawInk(ref int height, ref int width) { if (DrawInkCanvas != null && DrawInkCanvas.Strokes != null && DrawInkCanvas.Strokes.Count > 0) { Rect bound = DrawInkCanvas.Strokes.GetBounds(); DrawingVisual drawVisual = new DrawingVisual(); DrawingContext drawContext = drawVisual.RenderOpen(); foreach (Stroke drawStroke in DrawInkCanvas.Strokes) { Pen drawPen = new Pen(new SolidColorBrush(drawStroke.DrawingAttributes.Color), drawStroke.DrawingAttributes.Width); PathGeometry drawPath = new PathGeometry(); PathFigureCollection Figures = new PathFigureCollection(); PathFigure AddFigure = new PathFigure(); Figures.Add(AddFigure); drawPath.Figures = Figures; if (drawStroke.StylusPoints.Count > 1) { StylusPoint startPoint = drawStroke.StylusPoints[0]; AddFigure.StartPoint = new Point(startPoint.X - bound.X, startPoint.Y - bound.Y); for (int i = 1; i < drawStroke.StylusPoints.Count; i++) { StylusPoint drawPoint = drawStroke.StylusPoints[i]; Point offsetPoint = new Point(drawPoint.X - bound.X, drawPoint.Y - bound.Y); LineSegment drawSegment = new LineSegment(); drawSegment.Point = offsetPoint; AddFigure.Segments.Add(drawSegment); } } if (AddFigure.Segments.Count > 0) { drawContext.DrawGeometry(null, drawPen, drawPath); } } drawContext.Close(); RenderTargetBitmap renderBitmap = new RenderTargetBitmap((int)bound.Width, (int)bound.Height, 96, 96, PixelFormats.Pbgra32); renderBitmap.Render(drawVisual); BitmapFrame newFrame = BitmapFrame.Create(renderBitmap); PngBitmapEncoder pngEncoder = new PngBitmapEncoder(); pngEncoder.Frames.Add(newFrame); using (MemoryStream newStream = new MemoryStream()) { pngEncoder.Save(newStream); Bitmap bitmap = new Bitmap(newStream); height = bitmap.Height; width = bitmap.Width; return GetBitmapData(bitmap); } } else { return null; } } private byte[] GetBitmapData(Bitmap bitmap) { // Lock the bitmap's bits. Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height); BitmapData bmpData = bitmap.LockBits(rect, ImageLockMode.ReadWrite, bitmap.PixelFormat); // Get the address of the first line. IntPtr ptr = bmpData.Scan0; // Declare an array to hold the bytes of the bitmap. int bytes = Math.Abs(bmpData.Stride) * bitmap.Height; byte[] rgbValues = new byte[bytes]; // Copy the RGB values into the array. System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes); // Unlock the bits. bitmap.UnlockBits(bmpData); return rgbValues; } private void SetProperty() { Text = string.Empty; if ((bool)NameChk.IsChecked) { if ((bool)TabChk.IsChecked) { Text += "Name: "; } Text += DictionaryValueConverter.GetGrantorFromDictionary(signatureCertificate.SubjectDict) + "\n"; } if ((bool)DateChk.IsChecked) { if ((bool)TabChk.IsChecked) { Text += "Date: "; } DateTime currentDateTime = DateTime.Now; string customFormat = "yyyy.MM.dd HH:mm:ss"; string formattedDateTime = currentDateTime.ToString(customFormat); Text += formattedDateTime + "\n"; } if ((bool)LogoChk.IsChecked) { tempSignatureConfig.IsDrawLogo = true; } else { tempSignatureConfig.IsDrawLogo = false; } if ((bool)ReasonChk.IsChecked) { if ((bool)TabChk.IsChecked) { Text += "Reason: "; } Text += (ReasonCmb.SelectedItem as ComboBoxItem).Content.ToString() + "\n"; } if ((bool)DistinguishableNameChk.IsChecked) { if ((bool)TabChk.IsChecked) { Text += "DN: "; } var keyOrder = new List { "CN", "O", "OU", "emailAddress", "L", "ST", "C" }; var keyMapping = new Dictionary { { "CN", "cn" }, { "OU", "ou" }, { "O", "o" }, { "L", "l" }, { "ST", "st" }, { "C", "c" }, { "emailAddress", "email" } }; var stringBuilder = new StringBuilder(); foreach (var originalKey in keyOrder) { if (keyMapping.TryGetValue(originalKey, out string newKey) && signatureCertificate.SubjectDict.TryGetValue(originalKey, out string value) && !string.IsNullOrEmpty(value)) { if (stringBuilder.Length > 0) { stringBuilder.Append(","); } stringBuilder.Append(newKey + "=" + value); } } Text += stringBuilder.ToString()+"\n"; } if ((bool)ComPDFKitVersionChk.IsChecked) { Assembly assembly = Assembly.GetExecutingAssembly(); Version version = assembly.GetName().Version; if ((bool)TabChk.IsChecked) { Text += "ComPDFKit Version: "; } Text += version.Major.ToString() + "." + version.Minor.ToString() + "." + version.Build.ToString() + "." + version.Revision.ToString() + "\n"; } if ((bool)PositionChk.IsChecked) { if ((bool)TabChk.IsChecked) { Text += "Position: "; } Text += PositionTbx.Text + "\n"; } } private void ReasonCheckBox_Click(object sender, RoutedEventArgs e) { CheckBox checkItem = sender as CheckBox; if (checkItem == null) { return; } ReasonPanel.Visibility = checkItem.IsChecked == true ? Visibility.Visible : Visibility.Collapsed; } private void BrowseTxt_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { string filter = "Image files (*.jpg, *.jpeg, *.png, *.bmp)|*.jpg;*.jpeg;*.png;*.bmp"; string pngPath = CommonHelper.GetExistedPathOrEmpty(filter); if (!string.IsNullOrEmpty(pngPath)) { try { byte[] imageData = null; int imageWidth = 0; int imageHeight = 0; ComPDFKit.Tool.Help.PDFHelp.ImagePathToByte(pngPath, ref imageData, ref imageWidth, ref imageHeight); if (imageData != null && imageWidth > 0 && imageHeight > 0) { tempSignatureConfig.ImageData = imageData; tempSignatureConfig.ImageWidth = imageWidth; tempSignatureConfig.ImageHeight = imageHeight; } } catch (Exception exception) { MessageBox.Show("The image is invalid.", "Error", MessageBoxButton.OK, MessageBoxImage.Error); return; } SetProperty(); CreateTempSignature(); } } private void ClearTxt_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { imagePath = string.Empty; //tempSignatureConfig.ImageBitmap = null; SetProperty(); CreateTempSignature(); } private void NameChk_Click(object sender, RoutedEventArgs e) { SetProperty(); CreateTempSignature(); } private void DateChk_Click(object sender, RoutedEventArgs e) { SetProperty(); CreateTempSignature(); } private void LogoChk_Click(object sender, RoutedEventArgs e) { SetProperty(); CreateTempSignature(); } private void ReasonChk_Click(object sender, RoutedEventArgs e) { if (!(bool)ReasonChk.IsChecked) { Reasonstp.Visibility = Visibility.Collapsed; } else { Reasonstp.Visibility = Visibility.Visible; } SetProperty(); CreateTempSignature(); } private void DistinguishableNameChk_Click(object sender, RoutedEventArgs e) { SetProperty(); CreateTempSignature(); } private void PositionChk_Click(object sender, RoutedEventArgs e) { if (!(bool)PositionChk.IsChecked) { PositionStp.Visibility = Visibility.Collapsed; } else { PositionStp.Visibility = Visibility.Visible; } SetProperty(); CreateTempSignature(); } private void TabChk_Click(object sender, RoutedEventArgs e) { SetProperty(); CreateTempSignature(); } private void ReasonCmb_SelectionChanged(object sender, SelectionChangedEventArgs e) { SetProperty(); CreateTempSignature(); } private void ComPDFKitVersionChk_Click(object sender, RoutedEventArgs e) { SetProperty(); CreateTempSignature(); } private void PositionTbx_TextChanged(object sender, TextChangedEventArgs e) { if (!(bool)PositionChk.IsChecked) { PositionStp.Visibility = Visibility.Collapsed; } else { PositionStp.Visibility = Visibility.Visible; } SetProperty(); CreateTempSignature(); } private void ContinueBtn_Click(object sender, RoutedEventArgs e) { string filePath = CommonHelper.GetGeneratePathOrEmpty("PDF files (*.pdf)|*.pdf", Document.FileName + "_Signed.pdf"); if (string.IsNullOrEmpty(filePath)) { return; } if (filePath.ToLower() == Document.FilePath.ToLower()) { MessageBox.Show("Do not use the new file name that is the same as the current file name."); return; } if ((bool)ReasonChk.IsChecked) { reason = (ReasonCmb?.SelectedItem as ComboBoxItem)?.Content?.ToString(); } else { reason = string.Empty; } if ((bool)PositionChk.IsChecked) { location = PositionTbx.Text; } else { location = string.Empty; } signatureWidget.UpdataApWithSignature(tempSignatureConfig); if (Document.WriteSignatureToFilePath(signatureWidget, filePath, SignaturePath, Password, location, reason, CPDFSignaturePermissions.CPDFSignaturePermissionsNone)) { signatureCertificate.AddToTrustedCertificates(); AfterFillSignature?.Invoke(sender, filePath); } CloseWindow(sender); } private void CancelBtn_Click(object sender, RoutedEventArgs e) { CloseWindow(sender); } private void CloseWindow(object sender) { Window parentWindow = Window.GetWindow(sender as DependencyObject); parentWindow?.Close(); } private void TextColorPickerControl_Loaded(object sender, RoutedEventArgs e) { TextColorPickerControl.SetIsChecked(0); TextColorPickerControl.Brush = new SolidColorBrush(Colors.Black); } private void TextColorPickerControl_ColorChanged(object sender, EventArgs e) { KeyboardInPutTextBox.Foreground = TextColorPickerControl.Brush; } private void KeyboardCancel_Click(object sender, RoutedEventArgs e) { KeyboardPopup.Visibility = Visibility.Collapsed; } private void KeyboardClear_Click(object sender, RoutedEventArgs e) { KeyboardInPutTextBox.Text = string.Empty; } private void KeyboardSave_Click(object sender, RoutedEventArgs e) { signatureName = KeyboardInPutTextBox.Text; tempSignatureConfig.Text = signatureName; SolidColorBrush solidColorBrush = TextColorPickerControl.Brush as SolidColorBrush; float red = solidColorBrush.Color.R; float green = solidColorBrush.Color.G; float blue = solidColorBrush.Color.B; textColor = new[] { red / 255, green / 255, blue / 255 }; KeyboardPopup.Visibility = Visibility.Collapsed; SetProperty(); CreateTempSignature(); } private void KeyboardPopupClose_Click(object sender, RoutedEventArgs e) { KeyboardPopup.Visibility = Visibility.Collapsed; } } }