diff --git a/UtilitatPdf.sln b/UtilitatPdf.sln new file mode 100644 index 0000000..c9c3b56 --- /dev/null +++ b/UtilitatPdf.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30717.126 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UtilitatPdf", "UtilitatPdf\UtilitatPdf.csproj", "{A9DF4881-D24E-47F7-BA67-3DFC73ECE9FD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A9DF4881-D24E-47F7-BA67-3DFC73ECE9FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A9DF4881-D24E-47F7-BA67-3DFC73ECE9FD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A9DF4881-D24E-47F7-BA67-3DFC73ECE9FD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A9DF4881-D24E-47F7-BA67-3DFC73ECE9FD}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {B8A8AFEB-F7F6-49A6-A01F-39778DA34AC2} + EndGlobalSection +EndGlobal diff --git a/UtilitatPdf/App.xaml b/UtilitatPdf/App.xaml new file mode 100644 index 0000000..29a97bd --- /dev/null +++ b/UtilitatPdf/App.xaml @@ -0,0 +1,9 @@ + + + + + diff --git a/UtilitatPdf/App.xaml.cs b/UtilitatPdf/App.xaml.cs new file mode 100644 index 0000000..874e192 --- /dev/null +++ b/UtilitatPdf/App.xaml.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace UtilitatPdf +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} diff --git a/UtilitatPdf/AssemblyInfo.cs b/UtilitatPdf/AssemblyInfo.cs new file mode 100644 index 0000000..8b5504e --- /dev/null +++ b/UtilitatPdf/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Windows; + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] diff --git a/UtilitatPdf/MainWindow.xaml b/UtilitatPdf/MainWindow.xaml new file mode 100644 index 0000000..3491df2 --- /dev/null +++ b/UtilitatPdf/MainWindow.xaml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + Destinació: + + + + + + + + + + + + + + Origen: + + + + + Destinació: + + + + + + + + + diff --git a/UtilitatPdf/MainWindow.xaml.cs b/UtilitatPdf/MainWindow.xaml.cs new file mode 100644 index 0000000..08e7417 --- /dev/null +++ b/UtilitatPdf/MainWindow.xaml.cs @@ -0,0 +1,286 @@ +using System; +using System.IO; +using System.Windows; +using Microsoft.Win32; +using iText.Kernel.Pdf; +using iText.Forms; +using iText.Signatures; +using iText.Kernel.Pdf.Annot; +using iText.Forms.Fields; +using Org.BouncyCastle.X509; +using iText.Kernel.Pdf.Xobject; +using iText.Kernel.Pdf.Canvas.Parser.Listener; +using iText.Kernel.Pdf.Canvas.Parser; +using System.Text.RegularExpressions; +using iText.Layout.Element; +using Paragraph = iText.Layout.Element.Paragraph; +using Rectangle = iText.Kernel.Geom.Rectangle; +using System.Windows.Controls; +using Canvas = iText.Layout.Canvas; +using System.Collections.ObjectModel; + +namespace UtilitatPdf +{ + + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow : Window + { + ObservableCollection list = new ObservableCollection(); + public MainWindow() + { + InitializeComponent(); + } + #region ButtonText + private void SelectOpenFile_Button_Click(object sender, RoutedEventArgs e) + { + string content = (sender as Button).Name; + string FileSelected = SelectOpenPDFile(); + if(content == "AfegirPdf") + { + if (!string.IsNullOrEmpty(FileSelected)) + { + list.Add(new PdfInfo(FileSelected)); + SetOrder(list); + } + } + else if(content == "SelectFile5") + { + InSignFile.Text = FileSelected; + } + } + private void SelectSaveFile_Button_Click(object sender, RoutedEventArgs e) + { + string content = (sender as Button).Name; + string FileSelected = SaveFileDialog(); + if (content == "SelectFile6") + { + OutSignFile.Text = FileSelected; + } + else if (content == "SelectFile7") + { + MergeFileOut.Text = FileSelected; + } + } + #endregion + public void SetOrder(ObservableCollection data) + { + for (int i = 0; i < data.Count; i++) + { + PdfInfo ei = (PdfInfo)data[i]; + ei.Index = i.ToString(); + } + } + + private void btnDelete_Click(object sender, RoutedEventArgs e) + { + Button btn = (Button)sender; + int index = int.Parse(btn.Tag.ToString()); + list.RemoveAt(index); + SetOrder(list); + MyListView.ItemsSource = null; + MyListView.ItemsSource = list; + } + + private void Window_Loaded(object sender, RoutedEventArgs e) + { + MyListView.ItemsSource = list; + } + + #region ActionsRegion + private void MergeFile_Button_Click(object sender, RoutedEventArgs e) + { + if (list.Count == 0) + { + MessageBox.Show("Per a poder fusionar, has de seleccionar un fitxer com a mínim", "Error", MessageBoxButton.OK, MessageBoxImage.Error); + } + else + { + string FinalPdfFile = MergeFileOut.Text; + if (string.IsNullOrEmpty(FinalPdfFile)) + { + MessageBox.Show("El Fitxer de destí no pot estar buit.", "Error", MessageBoxButton.OK, MessageBoxImage.Error); + } + else + { + FileInfo currentFile = new FileInfo(FinalPdfFile); + if (currentFile.Exists) File.Delete(FinalPdfFile); + if(list.Count == 1) + { + File.Copy(list[0].FileName, FinalPdfFile); + } + else + { + try + { + PdfMergeFiles mClas = new PdfMergeFiles(FinalPdfFile); + + foreach (PdfInfo fi in list) + { + mClas.AddFile(fi.FileName); + } + mClas.Copy(); + } + catch (IOException ex) + { + MessageBox.Show("S'ha produit un error quan s'intentava escriure el fitxer:\n" + ex.Message,"Error", MessageBoxButton.OK,MessageBoxImage.Error); + } + catch(Exception exc) + { + MessageBox.Show("S'ha produit un error desconegut:\n" + exc.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error); + } + } + MergeFileOut.Text = string.Empty; + list.Clear(); + MessageBox.Show("S'han fusionat correctament el fitxers.", "Info", MessageBoxButton.OK, MessageBoxImage.Information); + } + } + } + private void RemoveSign_Button_Click(object sender, RoutedEventArgs e) + { + if (string.IsNullOrEmpty(InSignFile.Text) || string.IsNullOrEmpty(OutSignFile.Text)) + { + MessageBox.Show("Has de seleccioner l'arxiu d'origen i destí.", "Error", MessageBoxButton.OK, MessageBoxImage.Error); + } + else + { + if (ManipulatePdf(InSignFile.Text, OutSignFile.Text)) + { + InSignFile.Text = string.Empty; + OutSignFile.Text = string.Empty; + MessageBox.Show("S'ha ocultat el Cif/Nif de les signatures del document.", "Info", MessageBoxButton.OK, MessageBoxImage.Information); + } + } + } + #endregion + #region File Dialogs + private string SaveFileDialog() + { + SaveFileDialog saveFileDialog = new SaveFileDialog(); + saveFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); + saveFileDialog.Filter = "pdf files (*.pdf)|*.pdf"; + saveFileDialog.FilterIndex = 2; + if (saveFileDialog.ShowDialog() == true) + { + return saveFileDialog.FileName; + } + + return string.Empty; + } + + private string SelectOpenPDFile() + { + string fichero = string.Empty; + try + { + OpenFileDialog openFileDialog = new OpenFileDialog(); + openFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); + openFileDialog.Filter = "pdf files (*.pdf)|*.pdf"; + openFileDialog.FilterIndex = 2; + openFileDialog.RestoreDirectory = true; + + if (openFileDialog.ShowDialog() == true) + { + fichero = openFileDialog.FileName; + } + } + catch (Exception ex) + { + MessageBox.Show("Error: No es pot llegir el fitxer del disc.\n Original error: " + ex.Message); + return null; + } + + return fichero; + } + #endregion + #region RemoveSignature + private bool ManipulatePdf(string resource, string result) + { + string patronCif = @"([a-zA-Z]-?[0-9]{8})"; + string patronNif = @"([0-9]{8}-?[a-zA-Z])"; + string cleanRegex = string.Empty; + string widgetText = string.Empty; + bool doneOk = false; + + try + { + using (PdfReader pdfReader = new PdfReader(resource)) + using (PdfWriter pdfWriter = new PdfWriter(result)) + using (PdfDocument pdfDocument = new PdfDocument(pdfReader, pdfWriter)) + { + SignatureUtil signatureUtil = new SignatureUtil(pdfDocument); + PdfAcroForm acroForm = PdfAcroForm.GetAcroForm(pdfDocument, false); + + foreach (String name in signatureUtil.GetSignatureNames()) + { + PdfPKCS7 pkcs7 = signatureUtil.ReadSignatureData(name); + X509Certificate signerCert = (X509Certificate)pkcs7.GetSigningCertificate(); + String signerName = CertificateInfo.GetSubjectFields(signerCert).GetField("CN"); + PdfFormField field = acroForm.GetField(name); + field.SetModified(); + foreach (PdfWidgetAnnotation pdfWidgetAnnotation in field.GetWidgets()) + { + widgetText = extractText(pdfWidgetAnnotation); + + Regex regCif = new Regex(patronCif); + Regex regNif = new Regex(patronNif); + + MatchCollection matchesCif = regCif.Matches(widgetText); + MatchCollection matchesNif = regNif.Matches(widgetText); + + if (matchesCif.Count > 0 || matchesNif.Count > 0) + { + + cleanRegex = Regex.Replace(widgetText, patronCif, ""); + cleanRegex = Regex.Replace(cleanRegex, patronNif, ""); + + PdfArray annotationRect = pdfWidgetAnnotation.GetRectangle(); + pdfWidgetAnnotation.SetRectangle(annotationRect); + + PdfFormXObject form = new PdfFormXObject(new Rectangle(annotationRect.ToRectangle())); + Canvas canvas = new Canvas(form, pdfDocument); + canvas.Add(CreateNewCell(cleanRegex.Replace("\n", "").Replace("\r", "")).SetFontSize(7)); + + pdfWidgetAnnotation.SetNormalAppearance(form.GetPdfObject()); + } + acroForm.PartialFormFlattening(name); + } + } + acroForm.FlattenFields(); + doneOk = true; + } + } + catch (IOException ioException) + { + MessageBox.Show("S'ha produit un error:\n" + ioException.Message, "Eror", MessageBoxButton.OK, MessageBoxImage.Error); + } + + return doneOk; + } + private static Cell CreateNewCell(string texto) + { + Cell celda = new Cell(); + Paragraph p = new Paragraph(texto); + celda.Add(p); + return celda; + } + private String extractText(PdfWidgetAnnotation pdfWidgetAnnotation) + { + PdfDictionary normal = pdfWidgetAnnotation.GetNormalAppearanceObject(); + if (normal is PdfStream appearance) + { + PdfDictionary resourceDictionary = appearance.GetAsDictionary(PdfName.Resources); + PdfResources resources = resourceDictionary != null ? new PdfResources(resourceDictionary) : new PdfResources(); + ITextExtractionStrategy strategy = new SimpleTextExtractionStrategy(); + PdfCanvasProcessor parser = new PdfCanvasProcessor(strategy); + parser.ProcessContent(appearance.GetBytes(), resources); + return strategy.GetResultantText(); + } + return string.Empty; + } + #endregion + } // END Window Class + + +} // END Namespace diff --git a/UtilitatPdf/PdfInfo.cs b/UtilitatPdf/PdfInfo.cs new file mode 100644 index 0000000..c6d373c --- /dev/null +++ b/UtilitatPdf/PdfInfo.cs @@ -0,0 +1,24 @@ + +namespace UtilitatPdf +{ + /// + /// Class for ListView Filenames + /// + public class PdfInfo + { + private string _fileName; + public string FileName + { + get { return _fileName; } + set { _fileName = value; } + } + + public string Index { set; get; } + + + public PdfInfo(string filename) + { + _fileName = filename; + } + } // END PdfInfo Class +} diff --git a/UtilitatPdf/PdfMergeFiles.cs b/UtilitatPdf/PdfMergeFiles.cs new file mode 100644 index 0000000..80a50e2 --- /dev/null +++ b/UtilitatPdf/PdfMergeFiles.cs @@ -0,0 +1,100 @@ +using System; +using System.IO; +using iText.Kernel.Pdf; +using iText.Kernel.Utils; + +namespace UtilitatPdf +{ + public class PdfMergeFiles + { + private PdfDocument _pdfDocument = null; + private PdfDocument _pdfDocument2 = null; + private PdfMerger _pdfMerger = null; + + private static string tmpFolder = System.IO.Path.GetTempPath(); + private string _oldtmpFile = string.Empty; + private string _tmpFile = string.Empty; + private string _tmpFile2 = string.Empty; + private bool _mergeOK = false; + private string _FinalPdfFile = string.Empty; + + public PdfMergeFiles(string FinalPdfFile, bool DeleteIfExists = true) + { + if (string.IsNullOrEmpty(FinalPdfFile)) + { + throw new Exception(); + } + else + { + _FinalPdfFile = FinalPdfFile; + if (DeleteIfExists) + { + if (new FileInfo(_FinalPdfFile).Exists) File.Delete(_FinalPdfFile); + } + + } + } + public bool AddFile(string PdfFilename) + { + checkVars(PdfFilename); + + if (_mergeOK) + { + Random numr = new Random(); + _oldtmpFile = tmpFolder + numr.Next(1, 99999).ToString() + "tmpfile.pdf"; + + try + { + _pdfDocument = new PdfDocument(new PdfReader(_tmpFile), new PdfWriter(_oldtmpFile), new StampingProperties().UseAppendMode()); + + _pdfDocument2 = new PdfDocument(new PdfReader(_tmpFile2)); + + _pdfMerger = new PdfMerger(_pdfDocument); + _pdfMerger.Merge(_pdfDocument2, 1, _pdfDocument2.GetNumberOfPages()); + + this.Close(); + } + catch (IOException) + { + throw new IOException(); + } + catch(Exception) + { + throw new Exception(); + } + finally + { + _tmpFile = _oldtmpFile; + _tmpFile2 = string.Empty; + _oldtmpFile = string.Empty; + _mergeOK = false; + } + } + return true; + } + public void Copy() + { + File.Copy(_tmpFile, _FinalPdfFile); + } + private void Close() + { + _pdfDocument?.Close(); + _pdfDocument2?.Close(); + _pdfMerger?.Close(); + } + private void checkVars(string file) + { + if (string.IsNullOrEmpty(_tmpFile)) + { + _tmpFile = file; + } + else + { + _tmpFile2 = file; + } + + if (!string.IsNullOrEmpty(_tmpFile) && !string.IsNullOrEmpty(_tmpFile2)) _mergeOK = true; + } + + } +} diff --git a/UtilitatPdf/Properties/PublishProfiles/FolderProfile.pubxml b/UtilitatPdf/Properties/PublishProfiles/FolderProfile.pubxml new file mode 100644 index 0000000..69e61dc --- /dev/null +++ b/UtilitatPdf/Properties/PublishProfiles/FolderProfile.pubxml @@ -0,0 +1,17 @@ + + + + + Release + Any CPU + C:\Users\Vicente\git-repos\UtilitatPdf\bin + FileSystem + netcoreapp3.1 + false + win-x64 + True + False + + \ No newline at end of file diff --git a/UtilitatPdf/UtilitatPdf.csproj b/UtilitatPdf/UtilitatPdf.csproj new file mode 100644 index 0000000..60e8129 --- /dev/null +++ b/UtilitatPdf/UtilitatPdf.csproj @@ -0,0 +1,33 @@ + + + + WinExe + netcoreapp3.1 + true + + + + embedded + true + + + + embedded + true + + + + + + + + + + + + + + + + + diff --git a/UtilitatPdf/delete.png b/UtilitatPdf/delete.png new file mode 100644 index 0000000..eee6faf Binary files /dev/null and b/UtilitatPdf/delete.png differ diff --git a/UtilitatPdf/pdf.ico b/UtilitatPdf/pdf.ico new file mode 100644 index 0000000..ae2f6f3 Binary files /dev/null and b/UtilitatPdf/pdf.ico differ