From ed4fd6ce9667ca089a507eac57e0ab1f75636fe7 Mon Sep 17 00:00:00 2001 From: TekH Date: Wed, 24 Sep 2025 16:07:51 +0200 Subject: [PATCH] feat(Edit): created to handle pdf edit operations fluently --- EnvelopeGenerator.PdfEditor/Edit.cs | 92 +++++++++++++++++++ EnvelopeGenerator.PdfEditor/Extensions.cs | 16 +++- .../Controllers/EnvelopeController.cs | 12 +++ 3 files changed, 118 insertions(+), 2 deletions(-) create mode 100644 EnvelopeGenerator.PdfEditor/Edit.cs diff --git a/EnvelopeGenerator.PdfEditor/Edit.cs b/EnvelopeGenerator.PdfEditor/Edit.cs new file mode 100644 index 00000000..6012d1c9 --- /dev/null +++ b/EnvelopeGenerator.PdfEditor/Edit.cs @@ -0,0 +1,92 @@ +using iText.Kernel.Pdf; +#if NETFRAMEWORK +using System.IO; +using System; +using System.Threading.Tasks; +#endif + +namespace EnvelopeGenerator.PdfEditor +{ + public class Edit : IDisposable, IAsyncDisposable + where TInputStream : Stream + where TOutputStream : Stream + { + private readonly PdfDocument _doc; + private readonly TInputStream _inputStream; + private readonly TOutputStream _outputStream; + private readonly PdfReader _reader; + private readonly PdfWriter _writer; + private bool _disposed = false; + + public Edit(TInputStream inputStream, TOutputStream outputStream) + { + _inputStream = inputStream; + _outputStream = outputStream; + _reader = new PdfReader(inputStream); + _writer = new PdfWriter(outputStream); + _doc = new PdfDocument(_reader, _writer); + } + + public static Edit OnByte(byte[] documentBytes) + { + return new Edit(new MemoryStream(documentBytes), new MemoryStream()); + } + + // Finalizer + ~Edit() + { + // If Dispose is not called, clean up unmanaged resources + Dispose(false); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool disposing) + { + if (_disposed) + return; + + if (disposing) + { + // Managed resources + _doc?.Close(); + _inputStream?.Dispose(); + _outputStream?.Dispose(); + } + else + { + // When called by the finalizer, clean up only unmanaged resources + // Unmanaged resources such as PdfDocument, PdfReader, and PdfWriter are already IDisposable; we close them here + try { _doc?.Close(); } catch { } + try { _inputStream?.Dispose(); } catch { } + try { _outputStream?.Dispose(); } catch { } + } + + _disposed = true; + } + + public async ValueTask DisposeAsync() + { + if (_disposed) + return; + + _doc?.Close(); + if (_inputStream is IAsyncDisposable asyncInput) + await asyncInput.DisposeAsync(); + else + _inputStream.Dispose(); + + if (_outputStream is IAsyncDisposable asyncOutput) + await asyncOutput.DisposeAsync(); + else + _outputStream?.Dispose(); + + _disposed = true; + GC.SuppressFinalize(this); + } + } +} \ No newline at end of file diff --git a/EnvelopeGenerator.PdfEditor/Extensions.cs b/EnvelopeGenerator.PdfEditor/Extensions.cs index 26ebd97c..c6073670 100644 --- a/EnvelopeGenerator.PdfEditor/Extensions.cs +++ b/EnvelopeGenerator.PdfEditor/Extensions.cs @@ -1,5 +1,4 @@ -using iText.Kernel.Colors; -using iText.Kernel.Pdf; +using iText.Kernel.Pdf; using iText.Kernel.Pdf.Canvas; #if NETFRAMEWORK @@ -16,6 +15,7 @@ namespace EnvelopeGenerator.PdfEditor public static class Extensions { + #region Edit PDF document public static TStream Edit(this TStream inputStream, Action edit) where TStream : Stream, new() { @@ -36,6 +36,18 @@ namespace EnvelopeGenerator.PdfEditor return inputStream.Edit(edit).ToArray(); } } + #endregion + + public static byte[] Design(this byte[] pdfBytes, params (int pageIndex, Action design)[] pageDesign) + => pdfBytes.Edit(doc => + { + foreach((int pageIndex, Action design) in pageDesign) + { + var page = doc.GetPage(pageIndex); + var canvas = new PdfCanvas(page); + design(canvas); + } + }); } #if NETFRAMEWORK } diff --git a/EnvelopeGenerator.Web/Controllers/EnvelopeController.cs b/EnvelopeGenerator.Web/Controllers/EnvelopeController.cs index bd2af8a9..41b6d6ed 100644 --- a/EnvelopeGenerator.Web/Controllers/EnvelopeController.cs +++ b/EnvelopeGenerator.Web/Controllers/EnvelopeController.cs @@ -236,6 +236,18 @@ public class EnvelopeController : ViewControllerBase canvas.FillStroke(); }); + doc.ByteData = doc.ByteData.Edit(doc => + { + var page = doc.GetFirstPage(); + var canvas = new PdfCanvas(page); + canvas.SetStrokeColor(ColorConstants.RED); + canvas.SetFillColor(ColorConstants.CYAN); + canvas.SetFillColorRgb(222, 220, 215); + canvas.SetLineWidth(2); + canvas.Rectangle(100, 500, 200, 100); + canvas.FillStroke(); + }); + ViewData["DocumentBytes"] = doc.ByteData; } else