using iText.Kernel.Pdf; #if NETFRAMEWORK using System.IO; using System; using System.Threading.Tasks; #endif namespace EnvelopeGenerator.PdfEditor { public static class Edit { public static Edit FromMemory(byte[] documentBytes) { return new Edit(new MemoryStream(documentBytes), new MemoryStream()); } } 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; public Edit(TInputStream inputStream, TOutputStream outputStream) { _inputStream = inputStream; _outputStream = outputStream; _reader = new PdfReader(inputStream); _writer = new PdfWriter(outputStream); _doc = new PdfDocument(_reader, _writer); } /// /// Gets the output stream containing the edited PDF document. /// /// /// Accessing this property will close the underlying to ensure /// all changes are flushed to the stream. After accessing this property, the PDF document /// can no longer be modified using this instance. /// /// /// The instance that contains the updated PDF bytes. /// public TOutputStream OutputStream { get { _doc.Close(); return _outputStream; } } public Edit Document(Action edit) { edit(_doc); return this; } #region Finalizer private bool _disposed = false; ~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); } #endregion } }