`FreeText` `/CL`: relaxed validation lowers the bar to V1.4, but real-world files declare `%PDF-1.3`
Problem
In ValidationRelaxed, validateAnnotationDictFreeTextPart1 lowers the version
requirement for /CL from V1.6 to V1.4 (pkg/pdfcpu/validate/annotation.go,
v0.15.0):
// CL, optional, number array, since V1.6, len: 4 or 6
validateCL := func(a types.Array) bool { return len(a) == 4 || len(a) == 6 }
sinceVersion = model.V16
if xRefTable.ValidationMode == model.ValidationRelaxed {
sinceVersion = model.V14
validateCL = nil
}Files that declare %PDF-1.3 in the header therefore still fail, even in relaxed
mode. The immediately preceding entry in the same function relaxes to V1.3:
// DS, optional, text string, since V1.5
sinceVersion = model.V15
if xRefTable.ValidationMode == model.ValidationRelaxed {
sinceVersion = model.V13
}So the relaxed floors for two adjacent optional entries differ by one version,
and %PDF-1.3 happens to fall in between.
Reproducer
491 bytes, ASCII only — header says %PDF-1.3, one FreeText annotation with /CL:
%PDF-1.3
1 0 obj
<< /Type /Catalog /Pages 2 0 R >>
endobj
2 0 obj
<< /Type /Pages /Kids [3 0 R] /Count 1 >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 200 200] /Annots [4 0 R] >>
endobj
4 0 obj
<< /Type /Annot /Subtype /FreeText /Rect [10 10 60 60] /F 4 /DA (0 g) /Contents (x) /CL [10 10 30 30 60 60] >>
endobj
xref
0 5
0000000000 65535 f
0000000009 00000 n
0000000058 00000 n
0000000115 00000 n
0000000202 00000 n
trailer
<< /Size 5 /Root 1 0 R >>
startxref
328
%%EOFv0.15.0, default configuration (ValidationRelaxed):
prepare PDF context: validation error (obj#:4): document catalog: page annotations:
page annotations: page 1: page annotation obj#4: validate:
dict=FreeText entry=CL: unsupported in version 1.3How we ran into it
We are migrating a document pipeline from pdf-lib (JavaScript) to Go. We scanned
our whole corpus — 6,254 distinct PDFs produced by many tools over many years —
and pdfcpu rejected 5 files. 4 of them are this case: all produced by
Adobe PDF Library 15.0, all declaring %PDF-1.3 while carrying a 1.6 annotation
entry. The documents render fine everywhere else we tried.
Proposal
Smallest fix: lower the relaxed floor for /CL to model.V13, matching /DS
just above it.
Broader (entirely your call): this is the seventh-or-so report of the shape
dict=X entry=Y: unsupported in version Z (#93, #839, #903, #1058, #1100, #1230,
#1417), each resolved by adjusting one entry. Understated header versions seem
common enough that treating the check as advisory in ValidationRelaxed —
rather than tuning per-entry floors — might retire the whole category. There is
related discussion in #1223 about returning a typed error from
XRefTable.ValidateVersion so callers can distinguish this from real structural
damage; that would work for us too.
Happy to send a PR for whichever direction you prefer.
Source: pdfcpu/pdfcpu