Add interfaces and DTOs for PDF operations support
Introduced multiple interfaces and DTOs to support a wide range of PDF-related operations, including attachment handling, conversion, validation, annotation, stamping, and metadata extraction. Key changes: - Added `DocumentServiceClientOptions` for HTTP client config. - Introduced `IPdfAttachmentClient` for attachment operations. - Added `IPdfConversionClient` for PDF/A conversion (marked obsolete). - Added `IPdfOperationsClient` for merge, annotate, and stamp ops. - Introduced `IPdfValidationClient` for PDF and PDF/A validation. - Added `ISwissQrCodeClient` for Swiss QR Code extraction. - Added `IZugferdClient` for ZUGFeRD detection and extraction. - Created request DTOs for Base64-encoded operations. - Added enums for annotation, stamp, and validation configurations. These changes provide a flexible and extensible foundation for interacting with PDF documents, supporting both multipart and Base64-encoded inputs, and ensuring type safety with enums and records.
This commit is contained in:
89
DocumentService.Client/Interfaces/IPdfAttachmentClient.cs
Normal file
89
DocumentService.Client/Interfaces/IPdfAttachmentClient.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
using DocumentService.Client.Models.Requests;
|
||||
|
||||
namespace DocumentService.Client.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Client for PDF attachment operations (check, extract, add).
|
||||
/// </summary>
|
||||
public interface IPdfAttachmentClient
|
||||
{
|
||||
/// <summary>
|
||||
/// Checks if PDF contains attachments (multipart).
|
||||
/// </summary>
|
||||
/// <param name="pdfStream">PDF file stream</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>Attachment check result with metadata</returns>
|
||||
Task<AttachmentCheckResult> CheckAttachmentsAsync(Stream pdfStream, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Checks if PDF contains attachments (Base64).
|
||||
/// </summary>
|
||||
/// <param name="pdfBytes">PDF file as byte array</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>Attachment check result with metadata</returns>
|
||||
Task<AttachmentCheckResult> CheckAttachmentsAsync(byte[] pdfBytes, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Extracts all embedded attachments from a PDF (multipart).
|
||||
/// The returned dictionary maps each file name to its decompressed content stream.
|
||||
/// </summary>
|
||||
/// <param name="pdfStream">PDF file stream</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>Dictionary of file name ? content stream for each extracted attachment</returns>
|
||||
Task<Dictionary<string, Stream>> ExtractAttachmentsAsync(Stream pdfStream, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Extracts all embedded attachments from a PDF (Base64).
|
||||
/// The returned dictionary maps each file name to its decompressed content stream.
|
||||
/// </summary>
|
||||
/// <param name="pdfBytes">PDF file as byte array</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>Dictionary of file name ? content stream for each extracted attachment</returns>
|
||||
Task<Dictionary<string, Stream>> ExtractAttachmentsAsync(byte[] pdfBytes, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Adds attachments to PDF (multipart). ?? Not implemented yet in API.
|
||||
/// </summary>
|
||||
/// <param name="pdfStream">PDF file stream</param>
|
||||
/// <param name="attachments">Attachments to add</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>Modified PDF as stream</returns>
|
||||
[Obsolete("API endpoint not implemented yet")]
|
||||
Task<Stream> AddAttachmentsAsync(Stream pdfStream, List<AttachmentRequestDto> attachments, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Adds attachments to PDF (Base64). ?? Not implemented yet in API.
|
||||
/// </summary>
|
||||
/// <param name="pdfBytes">PDF file as byte array</param>
|
||||
/// <param name="attachments">Attachments to add</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>Modified PDF as stream</returns>
|
||||
[Obsolete("API endpoint not implemented yet")]
|
||||
Task<Stream> AddAttachmentsAsync(byte[] pdfBytes, List<AttachmentRequestDto> attachments, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DTO for attachment check result
|
||||
/// </summary>
|
||||
public record AttachmentCheckResult
|
||||
{
|
||||
/// <summary>Whether the document contains any embedded file attachments.</summary>
|
||||
public bool HasAttachments { get; init; }
|
||||
/// <summary>Number of embedded file attachments found.</summary>
|
||||
public int AttachmentCount { get; init; }
|
||||
/// <summary>Metadata for each attachment found in the document.</summary>
|
||||
public List<AttachmentMetadata> Attachments { get; init; } = new();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DTO for attachment metadata
|
||||
/// </summary>
|
||||
public record AttachmentMetadata
|
||||
{
|
||||
/// <summary>Name of the embedded file.</summary>
|
||||
public string FileName { get; init; } = string.Empty;
|
||||
/// <summary>MIME type of the embedded file (e.g. "application/xml"), or <c>null</c> if unknown.</summary>
|
||||
public string? MimeType { get; init; }
|
||||
/// <summary>Size of the embedded file in bytes.</summary>
|
||||
public long Size { get; init; }
|
||||
}
|
||||
49
DocumentService.Client/Interfaces/IPdfConversionClient.cs
Normal file
49
DocumentService.Client/Interfaces/IPdfConversionClient.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
namespace DocumentService.Client.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Client for PDF conversion operations (PDF ? PDF/A).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// All methods on this interface are marked obsolete because the corresponding
|
||||
/// API endpoints are not yet implemented.
|
||||
/// </remarks>
|
||||
public interface IPdfConversionClient
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a standard PDF to PDF/A format (multipart).
|
||||
/// </summary>
|
||||
/// <param name="pdfStream">Source PDF stream</param>
|
||||
/// <param name="pdfALevel">Target PDF/A level (e.g., "PDF/A-3b")</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>PDF/A document as stream</returns>
|
||||
[Obsolete("API endpoint not implemented yet")]
|
||||
Task<Stream> ConvertToPdfAAsync(Stream pdfStream, string pdfALevel = "PDF/A-3b", CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Converts a standard PDF to PDF/A format (Base64).
|
||||
/// </summary>
|
||||
/// <param name="pdfBytes">Source PDF as byte array</param>
|
||||
/// <param name="pdfALevel">Target PDF/A level (e.g., "PDF/A-3b")</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>PDF/A document as stream</returns>
|
||||
[Obsolete("API endpoint not implemented yet")]
|
||||
Task<Stream> ConvertToPdfAAsync(byte[] pdfBytes, string pdfALevel = "PDF/A-3b", CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Converts a PDF/A document to standard PDF (multipart).
|
||||
/// </summary>
|
||||
/// <param name="pdfStream">Source PDF/A stream</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>Standard PDF as stream</returns>
|
||||
[Obsolete("API endpoint not implemented yet")]
|
||||
Task<Stream> ConvertFromPdfAAsync(Stream pdfStream, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Converts a PDF/A document to standard PDF (Base64).
|
||||
/// </summary>
|
||||
/// <param name="pdfBytes">Source PDF/A as byte array</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>Standard PDF as stream</returns>
|
||||
[Obsolete("API endpoint not implemented yet")]
|
||||
Task<Stream> ConvertFromPdfAAsync(byte[] pdfBytes, CancellationToken cancellationToken = default);
|
||||
}
|
||||
69
DocumentService.Client/Interfaces/IPdfOperationsClient.cs
Normal file
69
DocumentService.Client/Interfaces/IPdfOperationsClient.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using DocumentService.Client.Models.Requests;
|
||||
|
||||
namespace DocumentService.Client.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Client for PDF operations (merge, annotate, stamp).
|
||||
/// </summary>
|
||||
public interface IPdfOperationsClient
|
||||
{
|
||||
// ==================== MERGE OPERATIONS ====================
|
||||
|
||||
/// <summary>
|
||||
/// Merges multiple PDFs (multipart).
|
||||
/// </summary>
|
||||
/// <param name="pdfStreams">PDF file streams to merge</param>
|
||||
/// <param name="pageRanges">Optional page ranges per PDF (e.g., "1-3,5")</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>Merged PDF as stream</returns>
|
||||
Task<Stream> MergeAsync(IEnumerable<Stream> pdfStreams, List<string?>? pageRanges = null, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Merges multiple PDFs (Base64).
|
||||
/// </summary>
|
||||
/// <param name="pdfByteArrays">PDF files as byte arrays</param>
|
||||
/// <param name="pageRanges">Optional page ranges per PDF (e.g., "1-3,5")</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>Merged PDF as stream</returns>
|
||||
Task<Stream> MergeAsync(IEnumerable<byte[]> pdfByteArrays, List<string?>? pageRanges = null, CancellationToken cancellationToken = default);
|
||||
|
||||
// ==================== ANNOTATION OPERATIONS ====================
|
||||
|
||||
/// <summary>
|
||||
/// Adds annotation to PDF (multipart).
|
||||
/// </summary>
|
||||
/// <param name="pdfStream">PDF file stream</param>
|
||||
/// <param name="request">Annotation request with coordinates and style</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>Annotated PDF as stream</returns>
|
||||
Task<Stream> AnnotateAsync(Stream pdfStream, AddAnnotationBase64Request request, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Adds annotation to PDF (Base64).
|
||||
/// </summary>
|
||||
/// <param name="pdfBytes">PDF file as byte array</param>
|
||||
/// <param name="request">Annotation request with coordinates and style</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>Annotated PDF as stream</returns>
|
||||
Task<Stream> AnnotateAsync(byte[] pdfBytes, AddAnnotationBase64Request request, CancellationToken cancellationToken = default);
|
||||
|
||||
// ==================== STAMP OPERATIONS ====================
|
||||
|
||||
/// <summary>
|
||||
/// Adds stamp to PDF (multipart).
|
||||
/// </summary>
|
||||
/// <param name="pdfStream">PDF file stream</param>
|
||||
/// <param name="request">Stamp request with position and style</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>Stamped PDF as stream</returns>
|
||||
Task<Stream> StampAsync(Stream pdfStream, AddStampBase64Request request, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Adds stamp to PDF (Base64).
|
||||
/// </summary>
|
||||
/// <param name="pdfBytes">PDF file as byte array</param>
|
||||
/// <param name="request">Stamp request with position and style</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>Stamped PDF as stream</returns>
|
||||
Task<Stream> StampAsync(byte[] pdfBytes, AddStampBase64Request request, CancellationToken cancellationToken = default);
|
||||
}
|
||||
75
DocumentService.Client/Interfaces/IPdfValidationClient.cs
Normal file
75
DocumentService.Client/Interfaces/IPdfValidationClient.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
namespace DocumentService.Client.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Client for PDF validation operations (validate, validate PDF/A).
|
||||
/// </summary>
|
||||
public interface IPdfValidationClient
|
||||
{
|
||||
/// <summary>
|
||||
/// Validates a PDF from stream (multipart upload).
|
||||
/// </summary>
|
||||
/// <param name="pdfStream">PDF file stream</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>Validation result with metadata</returns>
|
||||
Task<PdfValidationResult> ValidatePdfAsync(Stream pdfStream, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Validates a PDF from byte array (Base64 JSON).
|
||||
/// </summary>
|
||||
/// <param name="pdfBytes">PDF file as byte array</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>Validation result with metadata</returns>
|
||||
Task<PdfValidationResult> ValidatePdfAsync(byte[] pdfBytes, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Validates a PDF/A from stream (multipart upload).
|
||||
/// </summary>
|
||||
/// <param name="pdfStream">PDF/A file stream</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>PDF/A validation result with conformance level and errors</returns>
|
||||
Task<PdfAValidationResult> ValidatePdfAAsync(Stream pdfStream, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Validates a PDF/A from byte array (Base64 JSON).
|
||||
/// </summary>
|
||||
/// <param name="pdfBytes">PDF/A file as byte array</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>PDF/A validation result with conformance level and errors</returns>
|
||||
Task<PdfAValidationResult> ValidatePdfAAsync(byte[] pdfBytes, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DTO for PDF validation result
|
||||
/// </summary>
|
||||
public record PdfValidationResult
|
||||
{
|
||||
/// <summary>Total number of pages in the document.</summary>
|
||||
public int PageCount { get; init; }
|
||||
/// <summary>File size in bytes.</summary>
|
||||
public long FileSizeBytes { get; init; }
|
||||
/// <summary>PDF specification version (e.g. "1.7").</summary>
|
||||
public string PdfVersion { get; init; } = string.Empty;
|
||||
/// <summary>Whether the document is password-protected.</summary>
|
||||
public bool IsEncrypted { get; init; }
|
||||
/// <summary>Whether the document contains embedded file attachments.</summary>
|
||||
public bool HasAttachments { get; init; }
|
||||
/// <summary>Number of embedded file attachments.</summary>
|
||||
public int AttachmentCount { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DTO for PDF/A validation result
|
||||
/// </summary>
|
||||
public record PdfAValidationResult
|
||||
{
|
||||
/// <summary>Whether the document is fully PDF/A conformant.</summary>
|
||||
public bool IsValid { get; init; }
|
||||
/// <summary>Detected PDF/A conformance level (e.g. "PDF/A-3b"), or <c>null</c> if not a PDF/A document.</summary>
|
||||
public string? PdfAVersion { get; init; }
|
||||
/// <summary>Total number of pages in the document.</summary>
|
||||
public int PageCount { get; init; }
|
||||
/// <summary>List of conformance errors found during validation.</summary>
|
||||
public List<string> Errors { get; init; } = new();
|
||||
/// <summary>List of conformance warnings found during validation.</summary>
|
||||
public List<string> Warnings { get; init; } = new();
|
||||
}
|
||||
36
DocumentService.Client/Interfaces/ISwissQrCodeClient.cs
Normal file
36
DocumentService.Client/Interfaces/ISwissQrCodeClient.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
namespace DocumentService.Client.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Client for Swiss QR Code extraction operations.
|
||||
/// </summary>
|
||||
public interface ISwissQrCodeClient
|
||||
{
|
||||
/// <summary>
|
||||
/// Extracts Swiss QR Code from PDF (multipart).
|
||||
/// </summary>
|
||||
/// <param name="pdfStream">PDF file stream</param>
|
||||
/// <param name="raw">If true, returns raw QR text lines instead of parsed Bill object</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>Swiss QR Code extraction result</returns>
|
||||
Task<SwissQrCodeExtractionResult> ExtractSwissQrCodeAsync(Stream pdfStream, bool raw = false, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Extracts Swiss QR Code from PDF (Base64).
|
||||
/// </summary>
|
||||
/// <param name="pdfBytes">PDF file as byte array</param>
|
||||
/// <param name="raw">If true, returns raw QR text lines instead of parsed Bill object</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>Swiss QR Code extraction result</returns>
|
||||
Task<SwissQrCodeExtractionResult> ExtractSwissQrCodeAsync(byte[] pdfBytes, bool raw = false, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DTO for Swiss QR Code extraction result
|
||||
/// </summary>
|
||||
public record SwissQrCodeExtractionResult
|
||||
{
|
||||
/// <summary>Parsed Swiss QR bill object. <c>null</c> when <c>raw=true</c> was requested.</summary>
|
||||
public object? Bill { get; init; }
|
||||
/// <summary>Raw QR code text lines. Populated when <c>raw=true</c> was requested.</summary>
|
||||
public List<string> RawLines { get; init; } = new();
|
||||
}
|
||||
79
DocumentService.Client/Interfaces/IZugferdClient.cs
Normal file
79
DocumentService.Client/Interfaces/IZugferdClient.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
namespace DocumentService.Client.Interfaces;
|
||||
|
||||
/// <summary>
|
||||
/// Client for ZUGFeRD operations (detection, extraction).
|
||||
/// </summary>
|
||||
public interface IZugferdClient
|
||||
{
|
||||
/// <summary>
|
||||
/// Checks whether a PDF contains a ZUGFeRD XML attachment (multipart).
|
||||
/// </summary>
|
||||
/// <param name="pdfStream">PDF file stream</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>ZUGFeRD check result</returns>
|
||||
Task<ZugferdCheckResult> HasZugferdAsync(Stream pdfStream, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether a PDF contains a ZUGFeRD XML attachment (Base64).
|
||||
/// </summary>
|
||||
/// <param name="pdfBytes">PDF file as byte array</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>ZUGFeRD check result</returns>
|
||||
Task<ZugferdCheckResult> HasZugferdAsync(byte[] pdfBytes, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Extracts the ZUGFeRD XML from a PDF and returns the raw XML stream (multipart).
|
||||
/// </summary>
|
||||
/// <param name="pdfStream">PDF file stream</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>ZUGFeRD XML content as stream</returns>
|
||||
Task<Stream> ExtractZugferdAsync(Stream pdfStream, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Extracts the ZUGFeRD XML from a PDF and returns the raw XML stream (Base64).
|
||||
/// </summary>
|
||||
/// <param name="pdfBytes">PDF file as byte array</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>ZUGFeRD XML content as stream</returns>
|
||||
Task<Stream> ExtractZugferdAsync(byte[] pdfBytes, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Extracts ZUGFeRD metadata and XML content as a structured result (multipart).
|
||||
/// </summary>
|
||||
/// <param name="pdfStream">PDF file stream</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>Structured ZUGFeRD extraction result</returns>
|
||||
Task<ZugferdExtractionResult> ExtractZugferdAsResultAsync(Stream pdfStream, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Extracts ZUGFeRD metadata and XML content as a structured result (Base64).
|
||||
/// </summary>
|
||||
/// <param name="pdfBytes">PDF file as byte array</param>
|
||||
/// <param name="cancellationToken">Cancellation token</param>
|
||||
/// <returns>Structured ZUGFeRD extraction result</returns>
|
||||
Task<ZugferdExtractionResult> ExtractZugferdAsResultAsync(byte[] pdfBytes, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
/// <summary>DTO for ZUGFeRD detection result</summary>
|
||||
public record ZugferdCheckResult
|
||||
{
|
||||
/// <summary>Whether the document contains a ZUGFeRD XML attachment.</summary>
|
||||
public bool HasZugferd { get; init; }
|
||||
/// <summary>Detected ZUGFeRD version (e.g. "2.1"), or <c>null</c> if not present.</summary>
|
||||
public string? Version { get; init; }
|
||||
/// <summary>ZUGFeRD profile name (e.g. "EN 16931"), or <c>null</c> if not present.</summary>
|
||||
public string? Profile { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>DTO for ZUGFeRD extraction result</summary>
|
||||
public record ZugferdExtractionResult
|
||||
{
|
||||
/// <summary>File name of the extracted XML attachment (e.g. "factur-x.xml").</summary>
|
||||
public string FileName { get; init; } = string.Empty;
|
||||
/// <summary>Full XML content of the ZUGFeRD attachment.</summary>
|
||||
public string XmlContent { get; init; } = string.Empty;
|
||||
/// <summary>ZUGFeRD version (e.g. "2.1"), or <c>null</c> if not detected.</summary>
|
||||
public string? Version { get; init; }
|
||||
/// <summary>ZUGFeRD profile name (e.g. "EN 16931"), or <c>null</c> if not detected.</summary>
|
||||
public string? Profile { get; init; }
|
||||
}
|
||||
Reference in New Issue
Block a user