Repository navigation
PDF toolkit: watermark, page numbers and password for every PDF a preset writes - #436
Conversation
…set writes PdfFinishing (PDFsharp only) draws the watermark and page numbers as glyph outlines (GlyphOutlines, HarfBuzz, moved out of OutlinedTextPlayback) and locks the PDF with AES-256. JobQueue runs it through IPdfFinisher on each PDF a file became, from any engine, and once on a merged PDF. The preset editor shows the three options for PDF targets, in all 12 languages.
# Conflicts: # docs/ENGINES.md # src/Filee.Core/Conversion/JobQueue.cs # src/Filee.Engines/Pdf/PdfSharpConverter.cs
|
Merged
|
|
The |
The Windows CI runner didn't start the background check within 5 s, so the test failed although the catalog behaved right. The waits are now 30 s; the checks are unchanged.
|
Rather than wait for a re-run, the latest commit raises the 5 s waits in |
KnifeLemon
left a comment
There was a problem hiding this comment.
Thanks @cre8ive-marketing, this is a nice addition and it's well built: one pass with PDFsharp after whichever engine made the PDF, once on a merged PDF so the numbers run through, outlines instead of an embedded 13 MB font, AES-256, and all 14 languages. I built the branch and ran your tests plus a few of my own. Some things to fix before it goes in:
Where the stamps land
- Rotated pages. On a page with
/Rotate 90the page number doesn't end up at the bottom of the page as it's shown (I tried a blank A4 page withRotate = 90: nothing in the bottom strip, the number is elsewhere on the page). Scans and landscape exports use/Rotatea lot. Please draw in the page's displayed orientation and add a test. - Crop box. The position is worked out from the media box. On a page whose CropBox is smaller (MediaBox A4, CropBox inset by 100 pt in my test) the number falls outside the visible area and nothing shows. Please centre the watermark and place the number inside the CropBox.
Password
3. Long non-ASCII passwords can't be opened. AES-256 (revision 6) passwords are UTF-8, and readers use at most the first 127 bytes. A short Korean password and pässwörd open fine in PDFium, but a 54-character Korean one (162 bytes, under the box's limit of 64 characters) gives a PDF that PDFium won't open with that password. Please limit the password to 127 UTF-8 bytes in the editor (or truncate it exactly the way the spec says) and add a test that opens a non-ASCII password with PDFium, not only with PDFsharp.
4. Where else the password goes. Besides the preset in the library file:
- Settings → General → Export… writes the presets to a JSON file meant for sharing, password included. Please leave
Pdf.Passwordout of the export. - When files fail, history keeps a copy of the preset for "convert again" (
HistoryEntry.Preset), so the password stays in history.json after it's been removed from the preset or the preset is deleted. Please keep it out of that copy. A retry should then take the password from the preset if it still exists, and fail with a clear message if it doesn't, rather than write a PDF without the password.
Nothing logs it as far as I can see, good.
Smaller
5. If saving fails, <output>.pdf.finished stays next to the user's file. Please delete it on failure.
6. In JobQueue.cs the new <summary> landed under RunMergedAsync's, so FinishPdfsAsync has two summaries and RunMergedAsync none.
7. docs/ARCHITECTURE.md, step 5 (Run): one line that a PDF target's finishing (IPdfFinisher) runs after the last step, and once on a merged PDF.
8. PDF/A plus a password can't conform. The PDF/A identification does survive a watermark (I checked SVG → PDF/A with a watermark), so only the password is the problem: maybe say it in the password hint, or disable the box while PDF/A is ticked.
The 30 s waits in CatalogBackgroundCheckTests are fine to keep here. #429 touches the same lines in PresetEditorViewModel, Preset.cs and RenderTests, so whichever of the two goes in second will need a small rebase. Thanks!
Review of KnifeLemon#436: 1. Watermark and page numbers go on the page as it is shown: the page is drawn on unturned and mapped through its /Rotate (90, 180, 270), then its /Rotate put back. Tests render turned pages with PDFium. 2. Both are placed in the crop box (the media box when there is none). 3. The editor keeps a password to 127 UTF-8 bytes, all that AES-256 readers use; a longer one from elsewhere fails the file instead of writing a PDF nobody can open. Tests open non-ASCII passwords in PDFium. 4. The password is left out of a preset export and of the copy history keeps for "convert again". A retry takes it from the preset again and fails with error.pdf_password_gone when the preset has none. 5. <output>.pdf.finished is deleted when saving fails. 6. FinishPdfsAsync and RunMergedAsync each have their own summary. 7. ARCHITECTURE.md: the finishing step in "Run". 8. The password box is off while PDF/A is ticked, and its hint says why.
|
Thanks @KnifeLemon for the careful review. All eight points are fixed in dcebddc: Where the stamps land
Password
Smaller
I checked that the new rotation, crop-box and password-length tests fail on the previous code. |
main took OCR (KnifeLemon#429), which touches the same PDF options: - Preset.cs: both PdfOptions groups kept (watermark, page numbers, password next to Ocr, OcrLanguage, OcrTargets). - PresetEditorViewModel: both kept in the constructor, the properties and Apply (finishing, then OCR clearing what it doesn't do). - RenderTests: main's file with the two PDF finishing editor tests added back before the OCR one.
…ko.json Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…Fium PDFsharp reads a page whose media box is wider than tall as landscape and swaps its width and height when it is set to portrait, so forcing portrait drew the watermark and page number of a landscape page as if it were portrait: the number ended up in the middle of the page. The orientation now follows the media box while the page is drawn on unturned. Tests: a landscape page, unturned and turned 90, gets the number at the bottom of the shown page; a password of exactly 127 UTF-8 bytes opens in PDFium. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs/ARCHITECTURE.md: kept the PDF finishing line and KnifeLemon#481's Replace the original paragraph, in the order JobQueue runs them.
|
Merged One combination to be aware of, which I didn't change: a preset with "Only if smaller", a watermark or password, and "Replace the original" all on.
So the stamp is lost, and the notice says it was left as it is. If you'd rather keep the stamped copy in that case, the fix is to skip |
What does this change?
Three finishing options for every PDF a preset writes. They use only PDFsharp and the HarfBuzz/SkiaSharp Filee already ships, with no new package, download or engine:
They appear in the preset editor's PDF card for PDF targets, in all 12 languages.
Where it applies
JobQueuecalls a newIPdfFinisher(implemented byPdfSharpConverter→Pdf/PdfFinishing.cs) on each PDF a file became, whichever engine wrote it: images through PDFsharp, DOCX/XLSX/HWPX through rhwp, older formats through LibreOffice, PDF → PDF (split, page range, compress).PdfOptions.FinishesPdf).How the text is drawn
OutlinedTextPlayback's, moved unchanged intoVector/GlyphOutlines.csso both use it. SVG → PDF text output is the same as before; its tests pass.Password: the user and owner passwords are the same. Encryption is AES-256 (
SetEncryptionToV5). The password is saved with the preset in the settings file; the hint under the box says so. A PDF already locked with only an owner password is opened the way the compressor already does it (OpenForChanges, nowinternal).Light on low-end PCs: no new dependency, nothing new in the installer, one pass per PDF with PDFsharp.
Known limits (also in
docs/ENGINES.md):No settings schema change. It doesn't overlap my other open PRs: #429 also adds lines to the PDF card in
PresetEditorView.axaml, in a different place.How was it tested?
dotnet format --verify-no-changesdotnet testwith FFmpeg 9.0.2 and rhwp 0.8.7: Platform 48, Core 457, Cli 27, Setup 145, Engines 1463, App 809 pass, none fail.PdfFinishingQueueTests(Core):PdfFinishingTests(Engines, real PDFs rendered with PDFium):/AESV3);RenderTests(App), in English and Korean: the editor shows the options for a PDF target and saves them (the watermark trimmed), and a PNG target drops them.Screenshots (UI changes)
Checklist
src/Filee.App/Assets/i18n/*.jsonfiles (5 keys)THIRD-PARTY-NOTICES.md(none)