Add PDF attachment and PDF/A conversion features

Introduced endpoints for embedding attachments in PDFs and converting
between standard PDFs and PDF/A formats. Added `PdfAttachmentController`
and `PdfConversionController` with multipart/form-data and Base64-based
support. Implemented commands, handlers, and validators for these
operations.

Extended `IPdfProcessor` with methods for adding attachments and
PDF/A conversion. Partially implemented functionality in
`DevExpressPdfProcessor`, including `ConvertFromPdfAAsync`.

Added `attachment.xml` and `withoutAttachment.pdf` as resources for
testing. Marked endpoints as `[Obsolete]` to indicate incomplete
implementation. Improved validation and error handling for commands.
This commit is contained in:
2026-07-30 13:43:55 +02:00
parent a242458d2f
commit a6694bfce7
9 changed files with 876 additions and 0 deletions

View File

@@ -145,4 +145,47 @@ public interface IPdfProcessor
Domain.Models.ValueObjects.StampPlacement placement = Domain.Models.ValueObjects.StampPlacement.Foreground,
byte[]? imageBytes = null,
Domain.Models.ValueObjects.PredefinedStampType? predefinedType = null);
/// <summary>
/// Embeds one or more files as attachments in a PDF document (supports PDF/A-3).
/// </summary>
/// <param name="pdfStream">
/// PDF document stream. Must be readable and positioned at the beginning (Position = 0).
/// Non-seekable streams are supported. Caller is responsible for disposal.
/// </param>
/// <param name="attachments">List of files to embed (filename, content, optional MIME type)</param>
/// <returns>PDF with embedded attachments as byte array</returns>
/// <exception cref="Domain.Common.Exceptions.BadRequestException">
/// Thrown when stream is empty/invalid, or attachments list is empty
/// </exception>
Task<byte[]> AddAttachmentsAsync(
Stream pdfStream,
IReadOnlyList<(string FileName, byte[] Content, string? MimeType)> attachments);
/// <summary>
/// Converts a standard PDF to PDF/A format.
/// </summary>
/// <param name="pdfStream">
/// PDF document stream. Must be readable and positioned at the beginning (Position = 0).
/// Non-seekable streams are supported. Caller is responsible for disposal.
/// </param>
/// <param name="pdfALevel">Target PDF/A level (e.g., "PDF/A-1b", "PDF/A-2b", "PDF/A-3b")</param>
/// <returns>PDF/A compliant document as byte array</returns>
/// <exception cref="Domain.Common.Exceptions.BadRequestException">
/// Thrown when stream is empty/invalid or PDF/A level is unsupported
/// </exception>
Task<byte[]> ConvertToPdfAAsync(Stream pdfStream, string pdfALevel);
/// <summary>
/// Converts a PDF/A document to a standard PDF (removes PDF/A restrictions).
/// </summary>
/// <param name="pdfStream">
/// PDF/A document stream. Must be readable and positioned at the beginning (Position = 0).
/// Non-seekable streams are supported. Caller is responsible for disposal.
/// </param>
/// <returns>Standard PDF document as byte array</returns>
/// <exception cref="Domain.Common.Exceptions.BadRequestException">
/// Thrown when stream is empty/invalid
/// </exception>
Task<byte[]> ConvertFromPdfAAsync(Stream pdfStream);
}