feat: Implement DevExpressPdfProcessor.ExtractAttachmentsAsync with ZIP packaging

This commit is contained in:
2026-07-21 09:26:18 +02:00
parent 2c673ea98e
commit 26458a4017

View File

@@ -234,6 +234,68 @@ public class DevExpressPdfProcessor : IPdfProcessor
);
}
/// <summary>
/// Extracts all embedded files from a PDF document and returns them as a ZIP archive.
/// Uses DevExpress PdfDocument.FileAttachments to retrieve attachment data.
/// </summary>
/// <param name="pdfStream">PDF content as stream (caller is responsible for disposal)</param>
/// <returns>ZIP archive byte array containing all extracted attachments</returns>
/// <exception cref="BadRequestException">Thrown when stream is empty</exception>
/// <exception cref="NotFoundException">Thrown when PDF contains no attachments</exception>
public async Task<byte[]> ExtractAttachmentsAsync(Stream pdfStream)
{
// 1. Input Validation
ArgumentNullException.ThrowIfNull(pdfStream, nameof(pdfStream));
if (pdfStream.Length == 0)
{
throw new BadRequestException("PDF stream cannot be empty");
}
// Defensive validation: Seekable streams must be at Position = 0
if (pdfStream.CanSeek && pdfStream.Position != 0)
{
throw new BadRequestException("PDF stream must be positioned at the beginning (Position = 0).");
}
// 2. Load PDF with DevExpress Document API
using var processor = new PdfDocumentProcessor();
processor.LoadDocument(pdfStream);
var document = processor.Document;
// 3. Extract attachment data using DevExpress FileAttachments collection
var fileAttachments = document.FileAttachments;
// 4. No attachments case
if (fileAttachments == null || !fileAttachments.Any())
{
throw new NotFoundException("PDF does not contain any attachments");
}
// 5. Create ZIP archive in memory
using var zipStream = new MemoryStream();
using (var zipArchive = new System.IO.Compression.ZipArchive(zipStream, System.IO.Compression.ZipArchiveMode.Create, leaveOpen: true))
{
foreach (var attachment in fileAttachments)
{
// Get attachment metadata
string fileName = attachment.FileName ?? "unnamed";
byte[] fileData = attachment.Data;
// Create entry in ZIP
var entry = zipArchive.CreateEntry(fileName, System.IO.Compression.CompressionLevel.Optimal);
// Write attachment data to ZIP entry
using var entryStream = entry.Open();
await entryStream.WriteAsync(fileData, 0, fileData.Length);
}
}
// 6. Return ZIP byte array
return zipStream.ToArray();
}
#endregion
#region Private Helpers