feat(thumbnails): persist pageCount from PDDocument / 1 for images

Groups the first-page BufferedImage and the source's total page count
into a SourcePreview record so both values travel through generate()
together. PDFs get pdf.getNumberOfPages(); image uploads always get 1
(a scan is one page from the user's perspective). The page badge on
the thumbnail row uses this value to show "1 / N" for multi-page
letters without a separate round-trip.

Refs #305

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-04-23 14:25:29 +02:00
committed by marcel
parent b48533be26
commit e6d55e47b1
2 changed files with 57 additions and 18 deletions

View File

@@ -168,6 +168,31 @@ class ThumbnailServiceTest {
verify(documentRepository, never()).save(any());
}
@Test
void generate_persistsPageCount_ofOne_forSingleImageUpload() throws IOException {
// Image uploads are always a single page from the user's perspective.
Document doc = makeDoc("image/png", "documents/scan.png");
when(fileService.downloadFileStream(anyString()))
.thenReturn(new ByteArrayInputStream(createSamplePng(600, 800)));
ThumbnailService.Outcome outcome = thumbnailService.generate(doc);
assertThat(outcome).isEqualTo(ThumbnailService.Outcome.SUCCESS);
assertThat(doc.getPageCount()).isEqualTo(1);
}
@Test
void generate_persistsPageCount_fromPdfDocument() throws IOException {
Document doc = makeDoc("application/pdf", "documents/multi.pdf");
when(fileService.downloadFileStream(anyString()))
.thenReturn(new ByteArrayInputStream(createSamplePdf(3)));
ThumbnailService.Outcome outcome = thumbnailService.generate(doc);
assertThat(outcome).isEqualTo(ThumbnailService.Outcome.SUCCESS);
assertThat(doc.getPageCount()).isEqualTo(3);
}
@Test
void generate_persistsPortraitAspect_forTypicalPortraitSourceImage() throws IOException {
// 600x800 → ratio w/h = 0.75 → below 1.1 threshold → PORTRAIT.
@@ -288,15 +313,21 @@ class ThumbnailServiceTest {
}
private static byte[] createSamplePdf() throws IOException {
return createSamplePdf(1);
}
private static byte[] createSamplePdf(int pageCount) throws IOException {
try (PDDocument doc = new PDDocument()) {
PDPage page = new PDPage(PDRectangle.A4);
doc.addPage(page);
try (PDPageContentStream content = new PDPageContentStream(doc, page)) {
content.beginText();
content.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA), 24);
content.newLineAtOffset(100, 700);
content.showText("Lieber Hans,");
content.endText();
for (int i = 0; i < pageCount; i++) {
PDPage page = new PDPage(PDRectangle.A4);
doc.addPage(page);
try (PDPageContentStream content = new PDPageContentStream(doc, page)) {
content.beginText();
content.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA), 24);
content.newLineAtOffset(100, 700);
content.showText("Lieber Hans,");
content.endText();
}
}
ByteArrayOutputStream bos = new ByteArrayOutputStream();
doc.save(bos);