Link
Skip to main content

Validate PDF files with the Arlington PDF Model

v2026.11

JPedal provides a parser and validator for the Arlington PDF Model

How to use the validator

JPedal comes bundled with a copy of the Arlington PDF Model for use with the Java API. However, if you want to use the command line, or use a custom version of the model, you will need to download a copy of the model in TSV format, which you can find on the PDF Association’s GitHub repo: https://github.com/pdf-association/arlington-pdf-model. Clone/download the repo and note the location of the tsv/latest directory.

Command line

The command line application allows you to validate one or more files against the model. You may specify a level filter to only show validation issues of a specific or worse severity.

java org.jpedal.arlington.validate.PdfArlingtonValidator --tsv <path-to-arlington-tsv-dir> [--level LEVEL] file1.pdf [file2.pdf ...]

All issues are printed in the following format: [level] path-in-pdf (arlington-object-definition): issue-message.

Example output:

[ERROR] Trailer/Root/Pages/Kids[0]/Resources/Font/F1/Encoding/Type (Encoding): Value of 'Type' (/Font) is not one of the permitted values [Encoding]
[ERROR] Trailer/Root/Pages/Kids[0]/Resources/Font/F1/Widths (FontType3): SpecialCase constraint violated: fn:Eval((fn:ArrayLength(Widths) == (1.0 + (@LastChar - @FirstChar))))
[ERROR] Trailer/Root/Pages/Kids[0]/Resources/Font/F2/FontDescriptor (FontCIDType0): Value must be an indirect reference (fn:MustBeIndirect) but is a direct object
[ERROR] Trailer/Root/Pages/Kids[0]/Resources/Font/F2/FontDescriptor/Style/Panose (StyleDict): SpecialCase constraint violated: fn:Eval((fn:StringLength(Panose) == 12.0))
[ERROR] Trailer/Root/Pages/Kids[0]/Resources/Font/F2/FontDescriptor/Descent (FontDescriptorCIDType0): Value of 'Descent' (123) is not one of the permitted values [fn:Eval((@Descent <= 0.0))]
[ERROR] Trailer/Root/PageLayout (Catalog): Value of 'PageLayout' (/AnUndefinedOption) is not one of the permitted values [SinglePage, OneColumn, TwoColumnLeft, TwoColumnRight, TwoPageLeft, TwoPageRight]
[INFO] Trailer/Root/CatalogCustomKey (Catalog): Key 'CatalogCustomKey' is not defined by the Arlington model for Catalog and no wildcard entry is present
[ERROR] Trailer/Root/MarkInfo/Suspects (MarkInfo): Value has type integer but the model expects one of boolean for key/index 'Suspects'
[ERROR] Trailer/Root/Lang (Catalog): Value has type name but the model expects one of string-text for key/index 'Lang'
[WARNING] Trailer/Root/OpenAction/URI (ActionURI): Value of 'URI' ((\003\006Bad ASCII)) contains unprintable ASCII characters

Java

The Java methods allow you to validate one or more files against the model. You may also load password-protected/encrypted files.

// Load model from Jar resources (the bundled model is at "arlington-pdf-model")
final Map<String, ArlingtonObject> model = ArlingtonModelLoader.loadClasspath("arlington-pdf-model");
// Load model from custom location on disk
final Map<String, ArlingtonObject> model = ArlingtonModelLoader.load(Path.of("~/Documents/tsv/latest"));

// Load file
final PdfArlingtonValidator.Result result = validateFile(new File("inputFile.pdf"), model);
// Load file with password
final PdfArlingtonValidator.Result result = validateFile(new File("inputFile.pdf"), "password".getBytes(), model);

Any issues are returned as a list which you can then iterate over and inspect.

Example output:

for (final ValidationIssue issue : result.issues()) {
    // Iterate over issues
}

Fix mode

The validator can also fix some issues, rather than just reporting them, and write out a fixed copy of the file. In fix mode the validator will:

  • Add a missing required key or array element, if the model gives it a default value
  • Remove an optional key with an invalid value (the wrong type, not a permitted value, or failing its special case)
  • Move a direct object to a new indirect object, where the model requires it to be indirect

Everything else is still reported as an issue. Name and number trees which contain entries, and the keys which describe how a stream is encoded, are never removed, as doing so would lose content.

Once the fixes have been made, the fixed file is validated again. It is only written out if no errors remain, so the issues reported are those in the fixed file, not the original. The fixed file is written out even if nothing needed fixing.

Encrypted files cannot be fixed. Attempting to fix one will throw an IOException.

Command line

Pass --fix with a directory to write the fixed files to. Each fixed file is given the same name as its input file, and the input file is never overwritten.

java org.jpedal.arlington.validate.PdfArlingtonValidator --tsv <path-to-arlington-tsv-dir> [--level LEVEL] --fix <output-dir> file1.pdf [file2.pdf ...]

Each fix is printed in the following format: [FIXED] path-in-pdf (arlington-object-definition): fix-message, followed by any issues which remain in the fixed file.

Example output:

[FIXED] Trailer/Root/PageLayout (Catalog): Removed optional key 'PageLayout' with an invalid value (Value of 'PageLayout' (/AnUndefinedOption) is not one of the permitted values [SinglePage, OneColumn, TwoColumnLeft, TwoColumnRight, TwoPageLeft, TwoPageRight])
[FIXED] Trailer/Root/Pages/Kids[0]/Resources/Font/F2/FontDescriptor (FontCIDType0): Moved direct object to indirect object 12 (Value must be an indirect reference (fn:MustBeIndirect) but is a direct object)
[FIXED] Trailer/Root/AF[0] (AFFileSpecification): Added default value /Unspecified (Required key/element 'AFRelationship' does not exist)
3 fix(es) applied, fixed file written to "fixed/file1.pdf"

Java

Use one of the fixFile() methods and provide the location to write the fixed file to, which must not be the input file. Files may be loaded from a File, byte[], or InputStream.

final Map<String, ArlingtonObject> model = ArlingtonModelLoader.loadClasspath("arlington-pdf-model");

final PdfArlingtonValidator.FixResult result = fixFile(new File("inputFile.pdf"), model, new File("outputFile.pdf"));

for (final AppliedFix fix : result.fixes()) {
    // Iterate over the fixes which were made
}
for (final ValidationIssue issue : result.issues()) {
    // Iterate over the issues which remain in the fixed file
}
if (!result.written()) {
    // Errors remain, so the fixed file was not written
}

Fixed files are held in memory while they are validated again, unless they are larger than the memory cache threshold, in which case they are written to an encrypted temporary file in the output directory. The default is 58MB.

PdfArlingtonValidator.setMemoryCacheThreshold(10_000_000); // 10MB

Why JPedal?

  • Actively developed commercial library with full support and no third party dependencies.
  • Process PDF files up to 3x faster than alternative Java PDF libraries.
  • Simple licensing options and source code access for OEM users.

Learn more about JPedal

Start Your Free Trial


Customer Downloads

Select Download