ISO 32000 conformance
pdfboss keeps a ledger of ISO 32000 clauses in iso32000/Iso32000/Catalogue/, one row per
clause with the status pdfboss claims: implemented, incomplete, not implemented or out of
scope. Clause numbers follow ISO 32000-1:2008; where ISO 32000-2:2020 numbers a clause
differently the row carries both.
The ledger is checked by Lean 4 on every push (make iso32000-gate). Six theorems in
iso32000/Iso32000/Gate.lean establish that every row is unique, that every clause of chapters
7 to 14 and the normative annexes has a row speaking to it, that every implemented row is cited
by both implementation code and a test in the source tree, that every incomplete row is cited by
implementation code and explains what is missing, that every other row explains itself, and that
no first-edition citation names a clause the standard does not have. They are decided by Lean's
compiled evaluator (native_decide), so they trust the Lean compiler as well as its kernel; the
decode-after-encode theorems of the reference filter decoders in iso32000/Iso32000/Reference/,
whose vectors the Rust tests replay, are checked by the kernel alone. Citation counts below are
the number of source comments naming the clause or a sub-clause of it, in implementation code
and in tests.
This page is generated by make iso32000-report. Edit the ledger, not the page.
| Status | Rows |
|---|---|
| implemented | 185 |
| incomplete | 98 |
| not implemented | 117 |
| out of scope | 74 |
7 Syntax
| Clause | Feature | Status | Code citations | Test citations | Note |
|---|---|---|---|---|---|
| 7.2.2 | Character Set | implemented | 7 | 2 | Table 1 white-space bytes, Table 2 delimiters and regular bytes classify every token; the writer escapes delimiter bytes in names (crates/pdfboss-write/src/ser.rs write_name). |
| 7.2.3 | Comments | implemented | 1 | 2 | A percent sign skips to CR or LF everywhere tokens are read; the header and startxref comments are read by their own scanners (document.rs, xref.rs). |
| 7.3.2 | Boolean Objects | implemented | 2 | 2 | The true and false keywords parse to Object::Bool; the writer serializes them (crates/pdfboss-write/src/ser.rs, test ser.rs scalars_serialize_exactly). |
| 7.3.3 | Numeric Objects | implemented | 2 | 4 | Integers read as i64 and reals as f64 with sign and leading-dot forms, malformed runs cleaned leniently; the writer emits plain decimals without exponents (crates/pdfboss-write/src/ser.rs, test ser.rs real_pins_exact_bytes). |
| 7.3.4 | String Objects | implemented | 5 | 9 | Both string forms decode to raw bytes in Object::String; the writer picks the literal or hex form from the bytes (crates/pdfboss-write/src/ser.rs write_string, tests ser.rs strings_use_literal_form_with_escapes and ser.rs strings_fall_back_to_hex_form). |
| 7.3.4.2 | Literal Strings | implemented | 1 | 4 | Balanced parentheses, all Table 3 escapes, one to three digit octal codes, backslash line continuation and EOL normalization to LF are covered, and an unknown escape drops the backslash as the clause requires. |
| 7.3.4.3 | Hexadecimal Strings | implemented | 2 | 2 | White space inside the brackets is skipped and an odd final digit is read as the high nibble; non-hex bytes are skipped leniently (the implementation comment at lexer.rs cites the clause, the tests do not). |
| 7.3.5 | Name Objects | implemented | 1 | 1 | Number-sign escapes decode, the empty name is accepted and a bad escape is kept literally; the writer escapes bytes outside 0x21-0x7E and rejects NUL (crates/pdfboss-write/src/ser.rs and ser.rs, tests ser.rs names_escape_irregular_bytes and ser.rs names_with_nul_bytes_are_rejected). |
| 7.3.6 | Array Objects | implemented | 1 | 3 | Heterogeneous nested arrays parse with a nesting cap and an unterminated array ends leniently at end of input; the writer separates items with single spaces (crates/pdfboss-write/src/ser.rs arrays_separate_items_with_single_spaces). |
| 7.3.7 | Dictionary Objects | implemented | 2 | 3 | Name keys with any value parse, a non-name key is dropped and a value-less key maps to null; a null-valued entry is stored rather than treated as absent and a repeated key keeps the last value, while the writer sorts keys bytewise (crates/pdfboss-write/src/ser.rs dicts_sort_keys_bytewise). |
| 7.3.8 | Stream Objects | incomplete | 11 | 11 | The dictionary plus stream/endstream body, /Length, /Filter and /DecodeParms are handled, but the external-file entries (/F, /FFilter, /FDecodeParms) and /DL are never read; the writer refuses a stream nested inside another object (crates/pdfboss-write/src/error.rs, test ser.rs nested_streams_are_errors). |
| 7.3.8.1 | General | incomplete | 5 | 4 | Of the Table 5 entries only /Length, /Filter and /DecodeParms are consumed, so stream data kept in an external file (/F with /FFilter and /FDecodeParms) is never fetched and /DL is ignored. |
| 7.3.8.2 | Stream Extent | implemented | 1 | 5 | The EOL after the stream keyword (CRLF or LF, a lone CR tolerated) is skipped, a direct or indirect /Length is verified against the following endstream, and a wrong or missing length falls back to a scan for endstream that trims one trailing EOL. |
| 7.3.9 | Null Object | implemented | 2 | 3 | The null keyword parses to Object::Null and a reference to a missing object resolves to null; a null /Filter reads as no filter. |
| 7.3.10 | Indirect Objects | implemented | 4 | 8 | Object headers, endobj (lenient when missing), the N G R lookahead and the rule that a reference to a missing object is null are all covered, with generation mismatches tolerated; the writer emits N G R and numbers objects densely (crates/pdfboss-write/src/ser.rs refs_serialize_as_num_gen_r). |
| 7.4.2 | ASCIIHexDecode Filter | implemented | 3 | 7 | Hex pairs with white space skipped, the > EOD marker and an odd final digit padded with zero decode, and the AHx abbreviation is accepted. |
| 7.4.3 | ASCII85Decode Filter | implemented | 3 | 7 | Five-character groups, the z shorthand, the |
| 7.4.4 | LZWDecode and FlateDecode Filters | incomplete | 13 | 29 | Both filters decode with their parameters and PNG predictors, but TIFF predictor 2 is undone for 8-bit components only (see 7.4.4.4); the writer compresses streams with Flate (crates/pdfboss-write/src/writer.rs compress_into, test writer.rs compressed_stream_round_trips). |
| 7.4.4.1 | General | implemented | 2 | 5 | FlateDecode accepts zlib (RFC 1950) and raw deflate data, returns the decoded prefix of a truncated stream and caps output size; LZWDecode is assessed under 7.4.4.2. |
| 7.4.4.2 | Details of LZW Encoding | implemented | 2 | 5 | Codes grow from 9 to 12 bits, clear-table (256) and EOD (257) codes, the KwKwK case and both EarlyChange width schedules decode; corrupt or truncated data keeps the decoded prefix. |
| 7.4.4.3 | LZWDecode and FlateDecode Parameters | implemented | 2 | 7 | Table 8 parameters (/Predictor, /Colors, /BitsPerComponent, /Columns, /EarlyChange) are read with their defaults, /DecodeParms arrays stay aligned with the /Filter array and indirect values resolve. |
| 7.4.4.4 | LZW and Flate Predictor Functions | implemented | 3 | 9 | PNG predictors 10 to 15 (per-row filter byte, all five filter types, sub-byte samples) and TIFF predictor 2 at 1, 2, 4, 8 and 16 bits per component decode (crates/pdfboss-core/src/filters/predictor.rs tiff_horizontal: bytes in place, big-endian 16-bit components, packed sub-byte components per colour with a row's padding bits left as stored). Tests: predictor.rs tiff_horizontal_diff_round_trips, tiff_16bit_samples_add_big_endian, tiff_4bit_samples_add_within_packed_bytes, tiff_2bit_samples_add_per_colour, tiff_1bit_samples_add_modulo_two, png_every_row_type_round_trips and png_row_length_rounds_up_for_sub_byte_samples. |
| 7.4.5 | RunLengthDecode Filter | implemented | 2 | 6 | Literal runs (0-127), repeat runs (129-255) and the 128 EOD byte decode, a missing EOD is tolerated and output size is capped. |
| 7.4.6 | CCITTFaxDecode Filter | implemented | 10 | 17 | Group 4 (K<0), pure 1-D Group 3 (K=0) and mixed Group 3 (K>0) decode to packed 1-bit samples, reading /K, /Columns, /Rows, /EncodedByteAlign, /BlackIs1 and /EndOfLine with Table 11 defaults; /EndOfBlock and /DamagedRowsBeforeError are described in comments but never read, the row count being inferred from the data instead. |
| 7.4.7 | JBIG2Decode Filter | implemented | 2 | 8 | The PDF embedded-stream organization with /JBIG2Globals decodes through a cleanroom codec (generic, refinement, symbol/text, pattern/halftone regions and MMR) and 1 bits are inverted to DeviceGray ink as the clause requires; the filter must be last in the chain. |
| 7.4.8 | DCTDecode Filter | implemented | 6 | 11 | The filter chain passes JPEG bytes through (crates/pdfboss-core/src/filters/mod.rs decode_stream) and the image layer decodes them with the external jpeg-decoder 0.3 crate (crates/pdfboss-render/src/image.rs decode_jpeg: gray, RGB and CMYK layouts, baseline and progressive). The colour transform follows Table 13: the Adobe APP14 flag when present (adobe_transform), else /ColorTransform from the trailing filter's decode parameters (dct_color_transform), else the crate's default of YCbCr for three components and none for four (jpeg_color_transform). Four-component samples are ink values as stored, the crate's 255 - ink output undone, and /Decode applies per component. Two-component JPEGs, which the clause allows, are refused by the crate; and the image's /ColorSpace is not consulted for JPEG data, which takes the device conversion for its component count (a limitation of the colour space rows under 8.6, not of the filter). Tests: image.rs dct_color_transform_zero_keeps_three_components_as_stored, dct_adobe_marker_overrides_color_transform, dct_color_transform_one_reads_four_components_as_ycck, dct_cmyk_samples_are_direct_ink_values. |
| 7.4.9 | JPXDecode Filter | implemented | 16 | 15 | A cleanroom JPEG 2000 decoder handles the codestream, the colour space comes from the codestream when the dictionary has none, /Decode is ignored except for image masks, /SMaskInData 1 and 2 (image.rs) and Indexed over JPX are honoured, and the filter must be last in the chain. |
| 7.4.10 | Crypt Filter | implemented | 6 | 6 | The decryptor reads a stream's own /Crypt filter when it loads the object (crates/pdfboss-core/src/crypt.rs stream_crypt_filter): /Name Identity, or no /Name, leaves the data as stored, a name from /CF decrypts with that filter's method and the file key as is, as the clause asks, and a name matching no /CF entry leaves the data as stored; decode_stream then treats Crypt as a no-op (crates/pdfboss-core/src/filters/mod.rs). Tests: crypt.rs a_stream_crypt_filter_naming_identity_is_left_as_stored, a_stream_crypt_filter_without_a_name_means_identity and a_stream_crypt_filter_naming_a_cf_entry_uses_the_file_key_as_is; filters/mod.rs crypt_filter_leaves_data_as_stored and crypt_filter_first_in_a_chain_is_a_no_op. |
| 7.5.2 | File Header | implemented | 2 | 2 | The %PDF-M.m header is searched in the first 1 KiB and defaults to 1.4 when absent, without shifting xref offsets for a header not at byte 0 (the recovery scan covers that case); the writer emits the header and a binary comment line (crates/pdfboss-write/src/writer.rs write_header, test writer.rs table_mode_minimal_document_loads). |
| 7.5.3 | File Body | implemented | 2 | 5 | Indirect objects are read at their cross-reference offsets, and when the table is unusable a whole-file scan for N G obj headers rebuilds it with the last occurrence winning. |
| 7.5.4 | Cross-Reference Table | implemented | 5 | 4 | Subsection headers and n/f entries are read token-wise so 19 and 21 byte lines load as well as 20 byte ones, though the free-entry linked list is not tracked; the writer emits exact 20-byte entries (crates/pdfboss-write/src/writer.rs emit_table and writer.rs table_offset, test writer.rs table_offsets_past_ten_digits_are_rejected). |
| 7.5.5 | File Trailer | implemented | 3 | 5 | The startxref offset is found in the last 1 KiB widening to 64 KiB and the trailer's /Size, /Root, /Info, /ID and /Encrypt are consumed, with %%EOF itself not required; the writer emits the trailer, startxref and %%EOF (crates/pdfboss-write/src/writer.rs trailer_dict). |
| 7.5.6 | Incremental Updates | implemented | 4 | 3 | The newest section wins and /Prev is followed with a visited-offset loop guard; the writer appends update sections chained by /Prev (crates/pdfboss-write/src/update.rs cites the clause; tests crates/pdfboss-write/tests/update_append.rs two_appends_chain and tests/test_update.py test_update_appends_and_preserves_bytes). |
| 7.5.7 | Object Streams | implemented | 6 | 3 | The /N and /First header pairs are parsed once and members are addressed by index and never decrypted separately, while /Extends is not needed for reading and not read; the writer packs objects into streams (crates/pdfboss-write/src/writer.rs build_objstm, test writer.rs object_streams_pack_and_resolve). |
| 7.5.8 | Cross-Reference Streams | implemented | 9 | 11 | Cross-reference streams are decoded through the ordinary filter chain and their dictionary serves as the trailer; the writer emits them by default (crates/pdfboss-write/src/writer.rs emit_stream, test writer.rs stream_mode_minimal_document_loads). |
| 7.5.8.2 | Cross-Reference Stream Dictionary | implemented | 1 | 2 | /W field widths of 0 to 8 bytes, /Size, /Index (defaulting to [0 Size]) and /Prev are read; /Type /XRef is not checked. |
| 7.5.8.3 | Cross-Reference Stream Data | implemented | 2 | 3 | Type 0, 1 and 2 entries are decoded as big-endian fields per /W, a zero-width type field defaults to type 1, unknown types read as free and truncated data ends the table leniently. |
| 7.5.8.4 | Compatibility with Applications That Do Not Support Compressed Reference Streams | implemented | 4 | 3 | A classic trailer's /XRefStm section merges ahead of its own table and before /Prev is followed (the fixture crates/pdfboss-testkit/src/lib.rs hybrid_doc documents the clause); the writer appends a classic table to a hybrid base (crates/pdfboss-write/tests/update_append.rs hybrid_base_appends_a_classic_table). |
| 7.6.2 | General Encryption Algorithm | implemented | 4 | 6 | Algorithm 1 per-object keys (with the sAlT suffix for AES-128) and the direct AES-256 file key decrypt strings and stream bodies, object-stream members are left alone and /Encrypt and /ID are never decrypted; the writer encrypts the same way with AES-256 (crates/pdfboss-write/src/writer.rs new_encrypted; tests crates/pdfboss-write/tests/encrypt.rs encrypt_dict_strings_are_never_encrypted and encrypt.rs xref_stream_is_never_encrypted). |
| 7.6.3 | Standard Security Handler | incomplete | 15 | 25 | V1/V2 RC4, V4 with the V2 or AESV2 crypt filter and V5 R5/R6 AES-256 files open under user or owner passwords, but a V4 file whose stream crypt filter is /Identity is refused (see 7.6.3.2 and 7.6.5); the writer produces AES-256 R6 files (crates/pdfboss-core/src/crypt.rs aes256_encrypt_dict). |
| 7.6.3.2 | Standard Encryption Dictionary | implemented | 11 | 10 | /Filter /Standard, /V, /R, /Length, /P, /O, /U, /OE, /UE, /Perms, /EncryptMetadata, /CF, /StmF, /StrF and /EFF are read (crates/pdfboss-core/src/crypt.rs from_standard_with_password and CryptFilters::parse; tests crypt.rs string_filter_is_chosen_independently_of_the_stream_filter and embedded_file_filter_applies_to_embedded_file_streams); /SubFilter names the formats of public-key handlers (adbe.pkcs7.*), so a reader with only the Standard handler has nothing to read there. |
| 7.6.3.3 | Encryption Key Algorithm | implemented | 11 | 5 | Algorithm 2 with the 32-byte pad, the 50-round MD5 for R3 and up and the R4 EncryptMetadata-false suffix derives the RC4/AES-128 key, and Algorithms 2.A and 2.B recover the AES-256 key for R5 and R6; every RC4 fixture is /V 2 /R 3 or /V 4 /R 4, so the R2 40-bit branch (crypt.rs) has no test. |
| 7.6.3.4 | Password Algorithms | implemented | 9 | 6 | The user password is verified through /U (Algorithms 4 and 5), the owner password recovers the padded user password from /O (Algorithm 7) and the R5/R6 checks use /O, /U, /OE, /UE and /Perms, while Algorithm 3 (computing /O) lives only in fixtures (crates/pdfboss-testkit/src/crypt.rs) and the R2 branch (crypt.rs) is untested; the writer computes /O, /U, /OE, /UE and /Perms for R6 (crates/pdfboss-core/src/crypt.rs, test crates/pdfboss-write/tests/encrypt.rs owner_password_also_opens). |
| 7.6.4 | Public-Key Security Handlers | out of scope | 12 | 0 | Only /Filter /Standard is accepted (crypt.rs) and every other handler fails with Error::Encrypted, because certificate and private-key handling is deliberately left out of pdfboss. |
| 7.6.5 | Crypt Filters | implemented | 7 | 13 | The /CF filters are read by name with /CFM V2, AESV2 or AESV3, /StmF, /StrF and /EFF pick among them with the standard Identity filter as the default and as a pass-through (crates/pdfboss-core/src/crypt.rs CryptFilters::parse), the crypt filter /Length sets the V4 key size (v4_key_length), /CFM None or an unknown method refuses the file as Error::Encrypted, and a stream's own /Crypt filter overrides /StmF (see 7.4.10); /EFF is recognised through /Type /EmbeddedFile, which Table 45 makes optional, so an untyped embedded file stream takes /StmF. /AuthEvent is not consulted: the password arrives when the document opens, Table 25 says readers ignore the entry for the /StmF and /StrF filters, and the Standard handler has the one file key for /EFF too. Tests: crypt.rs identity_stream_filter_leaves_streams_as_stored, string_filter_is_chosen_independently_of_the_stream_filter, embedded_file_filter_applies_to_embedded_file_streams, crypt_filter_length_sets_the_key_size and aesv3_identity_string_filter_leaves_strings_as_stored. |
| 7.7.2 | Document Catalog | incomplete | 5 | 3 | Only /Pages, /OCProperties and /StructTreeRoot are read from the catalog; /Version never overrides the header and /Names, /Dests, /PageLabels, /Outlines, /Metadata, /MarkInfo, /Lang, /AcroForm, /PageMode and /PageLayout are not consumed, while the writer emits /Pages, /Outlines, /Metadata, /Names, /PageLabels and viewer entries (crates/pdfboss-write/src/pdf.rs and pdf.rs). |
| 7.7.3 | Page Tree | incomplete | 19 | 18 | The tree walk, inheritance and page count are handled, with page-level gaps listed under 7.7.3.3; the writer builds page trees (crates/pdfboss-write/src/pdf.rs, crates/pdfboss-write/src/assemble.rs cites the clause). |
| 7.7.3.2 | Page Tree Nodes | implemented | 2 | 6 | /Kids are walked depth-first in document order, /Count is used when plausible, /Type /Page ends descent and cycles and depth are capped; /Parent is not needed for reading. |
| 7.7.3.3 | Page Objects | incomplete | 9 | 6 | /Contents (single stream or array joined by newlines with nulls skipped), the five boxes with Table 30 defaults, /Rotate, /Resources, /Annots and /StructParents are consumed; /UserUnit and the page-level /Group transparency dictionary are never read, and the viewer entries (/Dur, /Trans, /AA, /Tabs) are ignored. |
| 7.7.3.4 | Inheritance of Page Attributes | implemented | 5 | 4 | /Resources, /MediaBox, /CropBox and /Rotate flow down the /Pages nodes with the nearest ancestor winning and the non-inheritable boxes staying on the leaf (the fixture at parity.rs cites the clause, the test does not). |
| 7.7.4 | Name Dictionary | not implemented | 0 | 0 | No consuming code reads the catalog /Names dictionary; the writer emits /Names /EmbeddedFiles (crates/pdfboss-write/src/pdf.rs, test crates/pdfboss-write/tests/roundtrip.rs attachments_sort_by_name_and_round_trip_bytes). |
| 7.8.2 | Content Streams | implemented | 2 | 5 | Operands followed by an operator are tokenized with unknown operators skipped, inline images with their abbreviations are parsed, and a /Contents array is concatenated with a newline between parts; the writer produces content streams (crates/pdfboss-write/src/canvas.rs and crates/pdfboss-write/src/content.rs). |
| 7.8.3 | Resource Dictionaries | implemented | 3 | 4 | Category/name lookups walk the resource chain innermost first (form, then caller, then page, with a page missing /Resources inheriting from /Pages), and text extraction and rendering apply the same rule. |
| 7.9.2 | String Object Types | implemented | 9 | 12 | Text strings decode from UTF-16BE, UTF-8 or PDFDocEncoding by their byte-order mark (crates/pdfboss-core/src/object.rs decode_text_string) and byte strings stay raw; the writer encodes text strings as ASCII or UTF-16BE (crates/pdfboss-write/src/pdf.rs text_string cites 7.9.2.2). |
| 7.9.2.2 | Text String Type | implemented | 3 | 3 | UTF-16BE with a BOM and the PDF 2.0 UTF-8 BOM form decode with lone surrogates and odd trailing bytes replaced by U+FFFD, while language escape sequences inside UTF-16 text are kept unchanged; the writer writes ASCII plainly and everything else as UTF-16BE with a BOM (crates/pdfboss-write/src/pdf.rs). |
| 7.9.2.3 | PDFDocEncoded String Type | implemented | 2 | 5 | A string without a BOM decodes through the PDFDocEncoding table (crates/pdfboss-core/src/object.rs pdf_doc_char): the accents at 0x18-0x1F, the punctuation and ligatures at 0x80-0x9E and the Euro at 0xA0 map to their characters, the undefined codes become U+FFFD, and every other code agrees with Latin-1 (tests object.rs decode_pdf_doc_encoding_accents_at_0x18, decode_pdf_doc_encoding_punctuation_at_0x80, decode_pdf_doc_encoding_undefined_codes_are_replaced). |
| 7.9.2.4 | Byte String Type | implemented | 2 | 2 | Strings are kept as raw bytes in Object::String and exposed through as_str_bytes with no character interpretation, which is what /ID, /O and /U consumers rely on. |
| 7.9.3 | Text Streams | not implemented | 0 | 0 | No consumer reads a text stream (used by JavaScript and similar viewer features); decode_text_string is only applied to string objects. |
| 7.9.4 | Dates | implemented | 11 | 8 | One Date type in the core crate (crates/pdfboss-core/src/date.rs, re-exported by pdfboss-write) parses the D:YYYYMMDDHHmmSSOHH'mm form with the clause's defaults and field ranges, taking the deviations producers write (a trailing apostrophe, Z followed by offset digits, an offset without apostrophes, no D: prefix) and refusing out-of-range fields; it formats back to the D: form and to ISO 8601. Metadata keeps /CreationDate and /ModDate as written and reads them through creation_date_parsed and mod_date_parsed (document.rs); the CLI info command prints a parsed date as ISO 8601. The Python metadata dict still carries the strings as written. Tests: date.rs parse_pdf_the_clause_example, parse_pdf_partial_fields_take_their_defaults, parse_pdf_accepts_the_common_deviations, parse_pdf_refuses_out_of_range_fields; document.rs metadata_dates_parse_per_the_date_clause. |
| 7.9.5 | Rectangles | implemented | 2 | 3 | Four-number arrays with indirect elements resolved are normalized so that any two opposite corners define the rectangle. |
| 7.9.6 | Name Trees | not implemented | 0 | 0 | No name-tree walker exists on the consuming side (nothing reads /Dests, /EmbeddedFiles or any other /Names tree); the writer emits a single flat /Names leaf without /Kids or /Limits (crates/pdfboss-write/src/pdf.rs). |
| 7.9.7 | Number Trees | implemented | 2 | 2 | /Nums leaves, /Kids subtrees and /Limits are honoured under a node budget for the structure /ParentTree lookup; the writer emits a /PageLabels /Nums tree (crates/pdfboss-write/src/pdf.rs, test crates/pdfboss-write/tests/roundtrip.rs page_labels_resolve_roman_front_matter_and_offset_decimal). |
| 7.10.2 | Type 0 (Sampled) Functions | implemented | 2 | 7 | /Size, /BitsPerSample of 1 to 32, /Encode and /Decode with their defaults and multilinear interpolation between the 2^m nearest samples are covered, and /Order 3 is not honoured (the clause permits linear interpolation). |
| 7.10.3 | Type 2 (Exponential Interpolation) Functions | implemented | 2 | 3 | C0 + x^N (C1 - C0) with the C0, C1 and N defaults evaluates for shadings and tint transforms, the first input only as the clause defines. |
| 7.10.4 | Type 3 (Stitching) Functions | implemented | 2 | 2 | /Functions, /Bounds (k-1 of them, checked) and /Encode with its default remap the input into the selected subfunction, with subfunctions loaded under a MAX_FUNCTIONS budget. |
| 7.10.5 | Type 4 (PostScript Calculator) Functions | implemented | 4 | 11 | The full Table 42 operator set (arithmetic, relational, boolean, bitwise, stack and if/ifelse compiled to jumps) is parsed from the brace-delimited program with comments skipped, and the result feeds shadings and Separation/DeviceN tint transforms. |
| 7.10.5.2 | Errors in Type 4 Functions | implemented | 2 | 4 | Syntax errors reject the function at load time, and runtime failures (stack underflow or overflow, type mismatch, division by zero and other domain errors, runaway programs) clamp every output to the bottom of /Range rather than aborting the paint. |
| 7.11.2 | File Specification Strings | not implemented | 0 | 0 | No consumer reads /F or /UF file specification strings, and the writer stores the attachment name as both /F and /UF without any platform-dependent conversion (crates/pdfboss-write/src/pdf.rs). |
| 7.11.3 | File Specification Dictionaries | not implemented | 0 | 0 | Nothing on the consuming side reads /Type /Filespec dictionaries; the writer emits them with /F, /UF, /Desc and /EF (crates/pdfboss-write/src/pdf.rs, test crates/pdfboss-write/tests/roundtrip.rs attachments_sort_by_name_and_round_trip_bytes). |
| 7.11.4 | Embedded File Streams | not implemented | 1 | 0 | Embedded files are never extracted or listed on the consuming side; the writer emits /Type /EmbeddedFile streams with /Subtype and /Params /Size and /ModDate but no related-files array (crates/pdfboss-write/src/pdf.rs embedded_files_dict, whose doc at pdf.rs cites the clause; tests crates/pdfboss-write/tests/roundtrip.rs attachment_params_size_and_conditional_moddate and tests/test_write.py test_multiple_attachments_and_page_labels_compose). |
| 7.11.5 | URL Specifications | not implemented | 0 | 0 | /FS /URL file specifications are neither read nor written (crates/pdfboss-write/src/pdf.rs writes a /URI action, which belongs to chapter 12, not a file specification). |
| 7.11.6 | Collection Items | not implemented | 0 | 0 | No /CI collection item dictionaries are read or written. |
| 7.11.7 | Maintenance of File Specifications | out of scope | 0 | 0 | This clause describes how applications that move or rename files keep specifications valid, a file-management duty pdfboss has no role in. |
| 7.12.2 | Developer Extensions Dictionary | not implemented | 0 | 0 | The catalog /Extensions dictionary is never read or written. |
| 7.12.3 | BaseVersion | not implemented | 0 | 0 | No /BaseVersion handling exists; only the header version is reported (document.rs). |
| 7.12.4 | ExtensionLevel | not implemented | 0 | 0 | No /ExtensionLevel handling exists. |
8 Graphics
| Clause | Feature | Status | Code citations | Test citations | Note |
|---|---|---|---|---|---|
| 8.2 | Graphics Objects | implemented | 3 | 5 | Path, text, XObject, inline image and shading objects all execute, BX/EX parse and unknown operators are skipped; the object nesting rules bind writers and are not validated on read. |
| 8.3.2.2 | Device Space | implemented | 2 | 3 | The crop box, /Rotate and the scale factor build the base matrix with the y flip that puts the first device row at the top. |
| 8.3.2.3 | User Space | implemented | 2 | 2 | The page's default user space is the base matrix, cm concatenates onto the CTM and q/Q restores it. |
| 8.3.2.4 | Other Coordinate Spaces | implemented | 2 | 4 | Form, image (unit square), pattern, text and Type3 glyph spaces each map through their own matrix onto the CTM. |
| 8.3.2.5 | Relationships among Coordinate Spaces | implemented | 2 | 2 | Transformations compose by matrix concatenation from the innermost space out to device space. |
| 8.3.3 | Common Transformations | implemented | 2 | 1 | Translation, scaling and rotation constructors follow the clause's matrix forms; skew is expressed through the general six-element matrix. |
| 8.3.4 | Transformation Matrices | implemented | 2 | 4 | The six-element matrix, its concatenation order and inversion follow the clause; a non-finite cm operand is skipped. |
| 8.4.1 | General | incomplete | 2 | 2 | Table 52's CTM, clip, colour spaces and colours, line width/cap/join/miter/dash, alpha, blend mode, soft mask and text state are tracked with the clause's initial values; rendering intent, stroke adjustment and alpha source are not, and none of Table 53 (overprint, black generation, undercolor removal, transfer, halftone, flatness, smoothness) is tracked. |
| 8.4.2 | Graphics State Stack | implemented | 2 | 5 | q pushes and Q pops the whole state including clip and soft mask, a form's unbalanced Q cannot pop its caller's state (case form_with_unbalanced_restore), and nesting is capped at 64 levels. |
| 8.4.3.2 | Line Width | implemented | 3 | 3 | The pen is a user-space circle carried through the CTM (anisotropic scaling widens it correctly) and a zero or sub-pixel width paints the thinnest visible hairline; the writer emits w through canvas.rs set_line_width. |
| 8.4.3.3 | Line Cap Style | implemented | 7 | 5 | J and /LC set stroke.rs LineCap, which stroke_path reads at every run end: butt caps stop at the endpoint, round caps add the pen disc, projecting square caps carry the band on by half the line width in user space (stroke.rs butt_caps_stop_at_the_endpoints, square_caps_extend_the_band_by_half_the_width, executor.rs line_caps_follow_j_and_lc); zero-length dashes take the cap style along the path's direction; a J operand outside 0 to 2 sets butt; the writer emits J through canvas.rs set_line_cap. |
| 8.4.3.4 | Line Join Style | implemented | 7 | 7 | j and /LJ set stroke.rs LineJoin, which stroke_path reads at every interior vertex and at the start of a closed subpath: a miter carries the two bands' outer edges to their meeting point, a bevel cuts across their ends, a round join adds the pen disc; collinear segments get no join and a segment turning straight back gets only the round disc (stroke.rs miter_joins_fill_the_outer_corner, bevel_joins_cut_the_corner, round_joins_keep_the_pen_disc, joins_follow_a_flipped_matrix, executor.rs line_joins_follow_j_lj_m_and_ml); a j operand outside 0 to 2 sets miter; the writer emits j through canvas.rs set_line_join. |
| 8.4.3.5 | Miter Limit | implemented | 6 | 3 | M and /ML set miter_limit (values under 1 are ignored, default 10); stroke.rs miter_fits measures the two segment directions in user space and cuts a miter to a bevel when 1/sin(angle/2) is over the limit (stroke.rs the_miter_limit_cuts_sharp_joins_to_bevels, executor.rs line_joins_follow_j_lj_m_and_ml); the writer emits M through canvas.rs set_miter_limit. |
| 8.4.3.6 | Line Dash Pattern | implemented | 3 | 6 | The dash array and phase are measured in user space through the inverse CTM, an empty array restores solid strokes and /D in an ExtGState is honored; the writer emits d through canvas.rs set_dash. |
| 8.4.4 | Graphics State Operators | implemented | 2 | 3 | All eleven operators parse and set their state, and ri and i are accepted with no effect as the clause allows. |
| 8.4.5 | Graphics State Parameter Dictionaries | incomplete | 4 | 7 | /LW /LC /LJ /ML /D /CA /ca /BM /SMask are applied from the named resource; /RI /Font /OP /op /OPM /TR /TR2 /HT /FL /SM /SA /BG /BG2 /UCR /UCR2 /TK /AIS are ignored; the writer emits /ca /CA /BM only. |
| 8.5.2.1 | General | implemented | 3 | 4 | All seven construction operators build subpaths with the current point semantics of Table 59, re starts a closed rectangle subpath, and a segment before any m starts at the origin leniently instead of erroring. |
| 8.5.2.2 | Cubic Bezier Curves | implemented | 2 | 4 | c, v and y build the four control points per Table 59 and the curve is flattened adaptively within tolerance; the writer emits c through canvas.rs curve_to. |
| 8.5.3.1 | General | implemented | 2 | 3 | Every painting operator ends the path, the closing variants close the subpath first, F is accepted as f, and n discards the path while still applying a pending clip. |
| 8.5.3.2 | Stroking | implemented | 4 | 9 | Strokes are offset quads under the full CTM with dashes, stroke patterns and the cap style applied; path.rs keeps a degenerate subpath (a closed single point or coincident points), which stroke_path paints as a filled disc under round caps and not at all under butt or square caps, while a single-point open subpath paints nothing and zero-length dashes keep their caps (stroke.rs degenerate_subpaths_paint_a_dot_only_under_round_caps, zero_length_dashes_take_the_cap_style, executor.rs tests of the same names, path.rs degenerate_subpaths_are_kept_for_the_stroker); joins follow 8.4.3.4 and 8.4.3.5. |
| 8.5.3.3.1 | General | implemented | 2 | 2 | Open subpaths are implicitly closed before filling and coverage is anti-aliased per pixel. |
| 8.5.3.3.2 | Nonzero Winding Number Rule | implemented | 2 | 2 | f, B and b accumulate signed winding per scanline span and paint where it is nonzero. |
| 8.5.3.3.3 | Even-Odd Rule | implemented | 1 | 3 | f*, B* and b* count crossings and paint where the count is odd; the writer emits f* through canvas.rs fill_even_odd. |
| 8.5.4 | Clipping Path Operators | implemented | 2 | 4 | W and W* mark a pending clip that intersects the current clip after the following painting operator (n included), nested clips and a clip straddling a form (cases nested_clips, clip_straddling_a_form) intersect correctly, and the writer emits W n and W* n through canvas.rs clip. |
| 8.6.2 | Colour Values | implemented | 2 | 3 | Each family declares its component count and decode range, operands are clamped to the space's range, and every colour ends as RGB for compositing. |
| 8.6.3 | Colour Space Families | implemented | 2 | 2 | The device, CIE-based (CalGray, CalRGB, Lab, ICCBased) and special (Indexed, Separation, DeviceN, Pattern) families all parse from name or array form, with unknown names falling back to DeviceGray. |
| 8.6.4.2 | DeviceGray Colour Space | implemented | 1 | 2 | g/G and DeviceGray image samples convert gray to equal RGB channels (case device_colorspaces). |
| 8.6.4.3 | DeviceRGB Colour Space | implemented | 1 | 2 | rg/RG and DeviceRGB image samples pass through unchanged. |
| 8.6.4.4 | DeviceCMYK Colour Space | incomplete | 1 | 3 | k/K and CMYK images convert, but by a deliberate multiplicative formula (1-c)(1-k) rather than the clause's 1 - min(1, c + k), chosen so deep colours keep their hue. |
| 8.6.5.2 | CalGray Colour Spaces | implemented | 2 | 2 | /Gamma and /WhitePoint are read and gray decodes through XYZ to sRGB; /BlackPoint is ignored and a bare /CalGray name reads as DeviceGray. |
| 8.6.5.3 | CalRGB Colour Spaces | implemented | 1 | 2 | Per-channel /Gamma and the column-major /Matrix map to XYZ with identity defaults; /BlackPoint is ignored and a bare /CalRGB name or a dictionary without /WhitePoint falls back to DeviceRGB. |
| 8.6.5.4 | Lab Colour Spaces | implemented | 3 | 4 | /Range defaults to plus or minus 100, the default image decode is the Lab range, and the inverse transfer follows the clause's two-branch form (the source comment at math.rs cites the clause). |
| 8.6.5.5 | ICCBased Colour Spaces | implemented | 1 | 6 | Matrix/TRC, lut8/lut16 and lutAtoB profiles transform through the PCS, sRGB-equivalent profiles take the device path, /N mismatches and unparseable profiles fall back to /N or /Alternate, and /Range and /Metadata are ignored. |
| 8.6.5.6 | Default Colour Spaces | not implemented | 0 | 0 | No code reads /DefaultGray, /DefaultRGB or /DefaultCMYK from the /ColorSpace resource dictionary, so device colours are never remapped. |
| 8.6.5.7 | Implicit Conversion of CIE-Based Colour Spaces | implemented | 2 | 3 | Every CIE-based colour converts to the sRGB output space through XYZ with Bradford adaptation of the declared white point; the output space is fixed to sRGB. |
| 8.6.5.8 | Rendering Intents | incomplete | 2 | 1 | ri parses and is accepted, but neither it nor /RI changes anything; the ICC pipeline uses one fixed transform regardless of the requested intent. |
| 8.6.6.2 | Pattern Colour Spaces | incomplete | 2 | 5 | /Pattern and [/Pattern base] spaces select tiling and shading patterns for path fills and strokes, but text glyphs (executor.rs) and image stencils (executor.rs) painted with a pattern colour get a mid-gray stand-in and a report entry. |
| 8.6.6.3 | Indexed Colour Spaces | implemented | 3 | 5 | String and stream lookup tables over any base (Lab and nested Indexed included) resolve, out-of-range indices clamp, and the image decode default is [0 2^bpc-1] (case indexed_image_and_stencil). |
| 8.6.6.4 | Separation Colour Spaces | implemented | 10 | 10 | The tint transform (function types 0, 2, 3, 4) runs into the alternate space with initial tint 1.0 (crates/pdfboss-render/src/color.rs parse_with and to_rgb, executor.rs initial_color). The special colorant All ignores the alternate space and the transform and puts the tint on every colorant, gray 1 - tint on the composite output (ColorSpace::SeparationAll). None never marks the page: fills, strokes and text carry a zero-alpha colour (executor.rs fill_rgba8, stroke_rgba8), a stencil mask returns before painting (blit_image), an image in the space returns from image.rs draw, and a shading from shading.rs paint and paint_background. Not caught: a Type3 glyph that sets its own colour inside a None fill, and an Indexed space over a None base; a DeviceN whose colorants are all None belongs to 8.6.6.5. Tests: executor.rs separation_none_never_marks_the_page and separation_all_paints_the_tint_on_every_colorant, color.rs separation_all_and_none_ignore_the_alternate_and_transform. |
| 8.6.6.5 | DeviceN Colour Spaces | incomplete | 1 | 4 | n-colourant tint transforms evaluate into the alternate space, but spaces with more than 8 colourants (the clause allows 32) fall back to an ink approximation and the attributes dictionary is ignored. |
| 8.6.6.6 | Multitone Examples | implemented | 1 | 1 | Informative examples of 8.6.6.5; a two-colourant DeviceN with a sampled tint transform (the duotone shape) evaluates through the general DeviceN path. |
| 8.6.7 | Overprint Control | not implemented | 0 | 0 | Nothing reads /OP, /op or /OPM; every paint composites over the backdrop in RGB with no overprint simulation. |
| 8.6.8 | Colour Operators | implemented | 3 | 5 | All twelve operators set the stroking or nonstroking space and colour, black DeviceGray is the initial colour and cs/CS applies the space's initial colour; the writer emits rg/RG/g/G/k/K through canvas.rs set_fill and 219 set_stroke. |
| 8.7.2 | General Properties of Patterns | implemented | 2 | 3 | The pattern matrix maps pattern space to the default space of the page or of the form whose resource it is, not to the CTM at painting time, and loaded patterns are cached per document. |
| 8.7.3.1 | General | implemented | 2 | 6 | Table 75's /BBox, /XStep, /YStep, /Resources and /Matrix are read (a zero or missing step falls back to the bbox size), /TilingType is ignored as a spacing hint, and the tile count is capped at 65536 with a report. |
| 8.7.3.2 | Coloured Tiling Patterns | implemented | 2 | 3 | /PaintType 1 cells run with their own colour operators and inherit the paint site's blend mode and soft mask. |
| 8.7.3.3 | Uncoloured Tiling Patterns | implemented | 2 | 2 | /PaintType 2 cells paint in the scn colour given in the [/Pattern base] underlying space with the cell's own colour operators locked out. |
| 8.7.4.1 | General | incomplete | 1 | 3 | /Shading and /Matrix of a Table 76 pattern dictionary are read and the fill paints through the path with /Background, but the pattern's own /ExtGState entry is not applied. |
| 8.7.4.2 | Shading Operator | implemented | 2 | 4 | sh paints the named shading over the current clip intersected with its /BBox, ignores /Background as the clause requires, and reports a singular CTM instead of painting; the writer serializes sh at content.rs. |
| 8.7.4.3 | Shading Dictionaries | implemented | 1 | 4 | /ShadingType, /ColorSpace, /Background and /BBox are honored (/Background only behind pattern fills, per Table 78); /AntiAlias is ignored as a hint. |
| 8.7.4.4 | Colour Space: Special Considerations | incomplete | 2 | 2 | A /Function turns colour data into one parametric value and mesh vertex colours decode through the shading's space, but an /Indexed space combined with /Function and a /Pattern shading space are not rejected as the clause requires. |
| 8.7.4.5.2 | Type 1 (Function-Based) Shadings | implemented | 1 | 2 | The 2-in function evaluates per pixel over /Domain under /Matrix and points outside the domain stay unpainted. |
| 8.7.4.5.3 | Type 2 (Axial) Shadings | implemented | 2 | 3 | /Coords, /Domain, /Extend and a single or array-valued /Function are honored. |
| 8.7.4.5.4 | Type 3 (Radial) Shadings | implemented | 1 | 1 | The two circles, /Domain and /Extend are honored and a negative radius is rejected; the test covers concentric circles without extension. |
| 8.7.4.5.5 | Type 4 Shadings (Free-Form Gouraud-Shaded Triangle Meshes) | implemented | 2 | 4 | Flags 0, 1 and 2 with /BitsPerCoordinate, /BitsPerComponent, /BitsPerFlag and /Decode are read from the stream and Gouraud interpolation paints each triangle. |
| 8.7.4.5.6 | Type 5 Shadings (Lattice-Form Gouraud-Shaded Triangle Meshes) | implemented | 2 | 1 | /VerticesPerRow rows are split into triangle pairs and painted like type 4. |
| 8.7.4.5.7 | Type 6 Shadings (Coons Patch Meshes) | implemented | 2 | 3 | The 12 control points per patch in Table 85 order, edge sharing for flags 1 to 3, and interior points derived by the Coons formula are all handled. |
| 8.7.4.5.8 | Type 7 Shadings (Tensor-Product Patch Meshes) | implemented | 2 | 1 | The four extra interior points are read in Table 86 order and the patch is evaluated as a bicubic tensor patch. |
| 8.8.1 | General | implemented | 2 | 3 | Do dispatches on /Subtype (indirect values resolved) to image or form drawing and reports a missing or untyped XObject; the writer emits Do for images and form groups (canvas.rs draw_image, 387 draw_group). |
| 8.8.2 | PostScript XObjects | out of scope | 0 | 0 | pdfboss does not interpret PostScript, so a /PS XObject is skipped with an Unsupported report entry, which is what the clause tells a non-PostScript reader to do. |
| 8.9.2 | Image Parameters | implemented | 2 | 4 | /Width, /Height, /BitsPerComponent and /ColorSpace drive decoding; bad dimensions are rejected and short sample data reports as truncated. |
| 8.9.3 | Sample Representation | implemented | 2 | 3 | 1, 2, 4, 8 and 16 bit samples are read big-endian with each row padded to a whole byte, 16-bit samples scaling by 65535. |
| 8.9.4 | Image Coordinate System | implemented | 2 | 3 | The image fills the unit square under the CTM with row 0 at the top edge (v = 1) by inverse mapping of each device pixel. |
| 8.9.5.1 | General | incomplete | 3 | 4 | Of Table 89 the entries Width, Height, BitsPerComponent, ColorSpace, Decode, ImageMask, Mask, SMask, SMaskInData and OC are honored, while Intent, Interpolate, Alternates, Name, StructParent, ID, OPI and Metadata are ignored. |
| 8.9.5.2 | Decode Arrays | implemented | 6 | 7 | /Decode maps native samples, stencils and the Lab and Indexed defaults per Table 90 (crates/pdfboss-render/src/image.rs decode_samples, decode_stencil), maps DCTDecode samples per component through apply_decode (so a Photoshop-style CMYK JPEG with /Decode [1 0 1 0 1 0 1 0] comes out right), and is ignored for JPXDecode as 7.4.9 asks. Tests: image.rs decode_array_inverts_gray, dct_decode_array_applies_to_jpeg_samples and dct_decode_array_inverts_photoshop_cmyk. |
| 8.9.5.3 | Image Interpolation | not implemented | 0 | 0 | /Interpolate (and the inline /I abbreviation) is expanded at content.rs but never read; images sample nearest-neighbor when magnified, with box averaging only when minified. |
| 8.9.5.4 | Alternate Images | not implemented | 1 | 0 | No code reads /Alternates; the base image is always drawn, which the clause permits a reader to do. |
| 8.9.6.1 | General | implemented | 1 | 3 | Stencil, explicit and colour key masking are dispatched from one place, with /SMask taking precedence over /Mask when both are present. |
| 8.9.6.2 | Stencil Masking | incomplete | 2 | 5 | /ImageMask true paints the nonstroking colour where the decoded sample is 0 (with /Decode [1 0] inverting and JPX stencils repacked to 1 bit), but a pattern nonstroking colour paints a mid-gray stand-in with a report entry. |
| 8.9.6.3 | Explicit Masking | implemented | 2 | 1 | A stream-valued /Mask must be an /ImageMask stencil, its 1 samples hide the base image and a mask of different dimensions is resampled onto the base's unit square; a non-stencil /Mask stream is reported; the test comment cites §8.9.6.4, which is not the -1 number for explicit masking. |
| 8.9.6.4 | Colour Key Masking | implemented | 2 | 1 | An array /Mask of 2n integer ranges hides samples whose raw values all fall inside, on native sample data only (DCT and JPX images decline with a report, since the clause warns the result is unpredictable there). |
| 8.9.7 | Inline Images | implemented | 5 | 7 | BI/ID/EI with the Table 93 key abbreviations, the /G /RGB /CMYK /I colour space abbreviations, the Table 94 filter abbreviations and /L are honored and a named colour space resolves through the /ColorSpace resource; the writer serializes inline images with /L. |
| 8.10.2 | Form Dictionaries | implemented | 2 | 6 | /Matrix, /BBox (as a clip) and /Resources (prepended to the lookup chain with page fallback; output lib.rs cites the clause) are honored to depth 16 (cases nested_forms, form_resource_shadowing), /Group /Ref /Metadata /PieceInfo /StructParent are ignored, and the writer emits form XObjects with /BBox and /Resources at pdf.rs. |
| 8.10.3 | Group XObjects | incomplete | 2 | 2 | Only the /G form of a soft mask runs as an offscreen group; a form carrying a /Group entry that is drawn with Do runs inline with no group compositing, so /S /Transparency, /CS, /I and /K have no effect. |
| 8.10.4.1 | General | incomplete | 1 | 0 | /Ref is never read, so a reference XObject paints its own proxy content as an ordinary form, which the clause permits when the referenced file is not consulted. |
| 8.10.4.2 | Printing Reference XObjects | out of scope | 0 | 0 | Printer-side substitution of the referenced page has no meaning for a rasterizer that never opens the referenced file. |
| 8.10.4.3 | Special Considerations | out of scope | 0 | 0 | The guidance on /Page and /ID matching against the referenced file does not apply while /Ref is not consulted. |
| 8.11.2.1 | General | implemented | 2 | 3 | A group is identified by its indirect reference and is off when the default configuration says so; /Name, /Intent and /Usage are not read. |
| 8.11.2.2 | Optional Content Membership Dictionaries | implemented | 2 | 6 | /OCGs (single or array, null entries ignored) under /P AnyOn, AllOn, AnyOff, AllOff and /VE And/Or/Not expressions with nesting all evaluate, /VE taking precedence; oc.rs cites the visibility expression as §8.11.2.3. |
| 8.11.2.3 | Intent | not implemented | 0 | 0 | No code reads /Intent on groups or configurations, so /Design groups are treated like /View groups. |
| 8.11.3.2 | Optional Content in Content Streams | implemented | 2 | 8 | BDC /OC with a named /Properties resource or an inline dictionary opens a span whose painting is suppressed while graphics state, text position and clipping still take effect, spans nest and EMC balances; text extraction applies the same gating. |
| 8.11.3.3 | Optional Content in XObjects and Annotations | implemented | 2 | 3 | An /OC entry on an image or form XObject or on an annotation dictionary hides it (counted, not reported as a drop); the code cites this as §8.11.3.5, which is not the -1 number. |
| 8.11.4.2 | Optional Content Properties Dictionary | implemented | 2 | 3 | /OCGs and the default /D configuration are read from the catalog; /Configs alternates are ignored because only /D applies when a document opens. |
| 8.11.4.3 | Optional Content Configuration Dictionaries | incomplete | 4 | 3 | /BaseState, /ON and /OFF apply in specification order, while /Intent and /AS are ignored and /Name /Creator /Order /ListMode /RBGroups /Locked are viewer UI entries with no rendering effect. |
| 8.11.4.4 | Usage and Usage Application Dictionaries | not implemented | 0 | 0 | No code reads a group's /Usage dictionary or the configuration's /AS array, so View, Print, Export and Zoom usage never changes a group's state. |
| 8.11.4.5 | Determining the State of Optional Content Groups | incomplete | 2 | 3 | The state comes from /BaseState then /ON then /OFF of the default configuration and a document without /OCProperties shows everything, but the usage application step (/AS with the View event) is skipped. |
9 Text
| Clause | Feature | Status | Code citations | Test citations | Note |
|---|---|---|---|---|---|
| 9.2.2 | Basics of Showing Text | implemented | 2 | 4 | BT, Tf, Td, Tj and ET are parsed, executed for extraction and painted by the renderer; the writer emits the same five-operator sequence from Canvas::text (crates/pdfboss-write/src/canvas.rs). |
| 9.2.3 | Achieving Special Graphical Effects | incomplete | 1 | 2 | Invisible modes 3 and 7 are honored, but stroked text (modes 1, 2, 5, 6) paints as a plain fill and text clipping (modes 4 to 7) never joins the clip path; the renderer reports the clip approximation as SkippedKind::TextClip. |
| 9.2.4 | Glyph Positioning and Metrics | implemented | 3 | 3 | Widths are read in 1/1000 text-space units (Type3 through /FontMatrix), the horizontal displacement w0 advances the text matrix and vertical fonts use w1 with the position vector; the writer's Standard14::text_width sums AFM widths the same way (crates/pdfboss-write/src/font.rs). |
| 9.3.1 | General | implemented | 2 | 5 | The Table 104 text state parameters live in the graphics state on both the extraction and the render side, so q/Q restore them and BT/ET leave them alone; Tf takes the font resource name and size. |
| 9.3.2 | Character Spacing | implemented | 2 | 3 | Tc is added to every glyph displacement, scaled by Th horizontally and unscaled in vertical writing; only the render tests measure the Tc advance, extraction has no dedicated one. |
| 9.3.3 | Word Spacing | implemented | 3 | 4 | Tw applies to the single-byte code 32 only, including composite fonts whose CMap has a one-byte codespace covering it; the writer's justified paragraphs set Tw per line and reset it (crates/pdfboss-write/src/element.rs). |
| 9.3.4 | Horizontal Scaling | implemented | 2 | 2 | Tz/100 scales horizontal advances, TJ offsets and the glyph rendering matrix and is not applied to vertical displacements; only the extraction side has an advance test. |
| 9.3.5 | Leading | implemented | 1 | 2 | TL sets the leading, TD sets it to -ty, and T*, ' and " move the line matrix down by it. |
| 9.3.6 | Text Rendering Mode | incomplete | 7 | 6 | Modes 3 and 7 paint nothing and mark extracted spans invisible, and Tr is restored by Q; modes 1, 2, 5 and 6 are painted as fills instead of strokes, and modes 4 to 7 never add the glyphs to the clipping path (reported as unsupported). |
| 9.3.7 | Text Rise | implemented | 2 | 2 | Ts shifts the glyph origin in unscaled text space and is recorded on each TextSpan; the renderer applies it in the text rendering matrix without a dedicated test. |
| 9.3.8 | Text Knockout | not implemented | 0 | 0 | The ExtGState /TK flag is never read; glyphs are composited one at a time as they paint, which matches only the TK false behavior. |
| 9.4.1 | General | implemented | 3 | 2 | BT resets Tm and Tlm to identity and ET ends the object while the text state parameters survive across text objects; nested BT is not diagnosed. |
| 9.4.2 | Text-Positioning Operators | implemented | 2 | 4 | Td, TD, Tm and T* update Tlm and Tm per Table 108 in both consumers; the writer positions text with Td (crates/pdfboss-write/src/canvas.rs). |
| 9.4.3 | Text-Showing Operators | implemented | 2 | 4 | Tj, TJ (number offsets as -n/1000 times Tfs and Th, or ty in vertical mode), ' and " are all executed; TJ offsets and the two quote operators have parser tests only, no extraction or render test; the writer emits Tj. |
| 9.4.4 | Text Space Details | implemented | 6 | 3 | The rendering matrix [Tfs*Th 0 0 Tfs 0 Ts] x Tm x CTM and the tx/ty displacement formulas are applied per glyph, with the vertical position vector v shifting the glyph origin. |
| 9.5 | Introduction to Font Data Structures | implemented | 2 | 4 | Font dictionaries dispatch on /Subtype to the Type0, Type1/MMType1, TrueType and Type3 loaders on both consuming sides; the writer emits /Type /Font dictionaries for the standard 14 (crates/pdfboss-write/src/font.rs). |
| 9.6.2 | Type 1 Fonts | incomplete | 7 | 12 | Parent row: see 9.6.2.1 (implemented), 9.6.2.2 (incomplete) and 9.6.2.3 (incomplete). |
| 9.6.2.1 | General | implemented | 2 | 5 | Table 111 entries BaseFont, FirstChar, Widths, FontDescriptor, Encoding and ToUnicode are read (LastChar is implied by the Widths length); the writer emits Type, Subtype, BaseFont and Encoding for the standard 14 (crates/pdfboss-write/src/font.rs). |
| 9.6.2.2 | Standard Type 1 Fonts (Standard 14 Fonts) | incomplete | 3 | 7 | The twelve text faces (plus Arial, TimesNewRoman and CourierNew aliases) get AFM widths without /Widths and Croscore substitute faces at GlyphPainting::Full (bundled only with the substitute-fonts feature, on by default in the CLI), and the writer emits them WinAnsi-encoded; Symbol and ZapfDingbats have no metrics, no built-in encoding table and no substitute, so they stay unpainted and the writer rejects every character for them (crates/pdfboss-write/src/font.rs symbol_faces_reject_every_char_for_now). |
| 9.6.2.3 | Multiple Master Fonts | incomplete | 2 | 0 | /MMType1 is dispatched like /Type1 by the renderer and falls into the simple-font loader in extraction, but no test names an /MMType1 font. |
| 9.6.3 | TrueType Fonts | implemented | 2 | 4 | Simple /TrueType fonts with a FontFile2 program are parsed (head, maxp, loca, glyf, cmap, hmtx, post) and painted at every tier with /Widths taking precedence over hmtx; extraction reads the cmap platform ids to decide the WinAnsi gap fill. |
| 9.6.4 | Font Subsets | implemented | 4 | 2 | The six-uppercase-plus tag is stripped before standard-14 metric lookup, substitution and picture-font detection while extracted spans keep /BaseFont as written; the writer embeds no programs, so it never subsets. |
| 9.6.5 | Type 3 Fonts | implemented | 11 | 12 | FontMatrix, CharProcs, Encoding, Widths and the font's own Resources are read, CharProcs run as nested frames, d1 glyphs ignore their own color operators and the advance comes from /Widths through FontMatrix; FontBBox is not used, and several comments cite "9.6.5.2", a subclause number the 32000-1 outline does not have. |
| 9.6.6 | Character Encoding | incomplete | 14 | 20 | Parent row: see 9.6.6.1 (incomplete), 9.6.6.2 (incomplete), 9.6.6.3 (implemented) and 9.6.6.4 (incomplete). |
| 9.6.6.1 | General | incomplete | 2 | 5 | Named encodings and encoding dictionaries with /BaseEncoding and /Differences are applied for WinAnsiEncoding, MacRomanEncoding and StandardEncoding; MacExpertEncoding is not implemented and silently falls back to StandardEncoding. |
| 9.6.6.2 | Encodings for Type 1 Fonts | incomplete | 4 | 7 | An embedded program's built-in /Encoding (dup/put entries or the StandardEncoding token) is the base when the PDF names none, /Differences apply over it, a named encoding outranks it, and a nonsymbolic or standard-14 font without /Encoding defaults to StandardEncoding; the built-in encodings of the non-embedded Symbol and ZapfDingbats faces are not available. |
| 9.6.6.3 | Encodings for Type 3 Fonts | implemented | 2 | 3 | The /Encoding dictionary's /Differences names select CharProcs (StandardEncoding names fill unmapped codes as a leniency); extraction decodes Type3 codes through the same simple-font encoding path. |
| 9.6.6.4 | Encodings for TrueType Fonts | incomplete | 4 | 5 | Differences names resolve through post then the glyph list into the cmap, base-encoding characters go through the (3,1) subtable, and the raw code and 0xF000+code fall back through the symbol (3,0) table; one subtable is chosen by preference instead of trying each, the (1,0) path looks up the raw code without the standard-name-to-Mac-Roman step, and in a program with no cmap every code without a post-resolvable Differences name stays at gid 0. |
| 9.7.2 | CID-Keyed Fonts Overview | implemented | 2 | 3 | The code to CID (CMap) to glyph (CIDToGIDMap or CFF charset) pipeline is in place for CIDFontType0 and CIDFontType2 descendants. |
| 9.7.3 | CIDSystemInfo Dictionaries | incomplete | 3 | 1 | Only /Ordering is read, to pick the Japan1, GB1, CNS1, Korea1 or KR CID-to-Unicode table; /Registry and /Supplement are ignored and the CMap-versus-CIDFont collection compatibility rule is not checked. |
| 9.7.4 | CIDFonts | implemented | 16 | 17 | Parent row: see 9.7.4.1, 9.7.4.2 and 9.7.4.3, all implemented (crates/pdfboss-render/src/glyph.rs load_type0 and load_cff_cid; tests there cover each child). |
| 9.7.4.1 | General | implemented | 2 | 3 | Table 117 entries Subtype, CIDSystemInfo, FontDescriptor, DW, W, DW2, W2 and CIDToGIDMap are read from the first descendant; BaseFont is used only as style evidence. |
| 9.7.4.2 | Glyph Selection in CIDFonts | implemented | 6 | 8 | CIDFontType2 honours /CIDToGIDMap as /Identity or a stream (crates/pdfboss-render/src/glyph.rs). CIDFontType0 maps CIDs through the CFF charset when the Top DICT carries CIDFont operators and uses the CID directly as the glyph index when it does not (glyph.rs load_cff_cid over cff.rs cid_to_gid, None for the second case). A FontFile3 of /Subtype /OpenType is read from the container's CFF table (cff.rs parse, cff_table). Tests: glyph.rs cff_cid_font_paints_at_all_embedded_not_embedded_truetype_only, cff_cid_font_over_a_non_cid_program_uses_cids_as_gids, cff_cid_font_in_an_opentype_wrapper_paints; cff.rs an_opentype_wrapped_cff_parses_from_its_cff_table. |
| 9.7.4.3 | Glyph Metrics in CIDFonts | implemented | 6 | 6 | Both forms of /W and /W2 are parsed, /DW defaults to 1000, /DW2 to [880 -1000] and the default position vector is (w0/2, vy); ranges are capped at 65536 entries as a hostile-input guard. |
| 9.7.5 | CMaps | implemented | 14 | 11 | Parent row: see 9.7.5.1 to 9.7.5.4, all implemented. |
| 9.7.5.1 | General | implemented | 2 | 3 | CMaps split one to four byte codes by codespace range, map them to CIDs and carry the writing mode; the CID value domain is kept apart from the ToUnicode parser. |
| 9.7.5.2 | Predefined CMaps | implemented | 7 | 1 | All Table 118 names (20 Japan1, 14 GB1, 14 CNS1, 11 Korea1, Identity-H/V) plus UniAKR-UTF16-H load from packed Adobe data behind the predefined-cmaps feature, which is off in pdfboss-core by default but on in the CLI defaults and in pdfboss-py; without it every name but Identity falls back to the Identity assumption. |
| 9.7.5.3 | Embedded CMap Files | implemented | 2 | 3 | A CMap stream as /Encoding is parsed with its /WMode and /UseCMap chain (names or streams, depth bounded at 4) and the in-content usecmap operator; the stream dictionary's CMapName and CIDSystemInfo are not read. |
| 9.7.5.4 | CMap Example and Operator Summary | implemented | 1 | 4 | begincodespacerange, begincidchar, begincidrange, beginnotdefchar, beginnotdefrange and usecmap are executed and the remaining Table 119 operators (begincmap, endcmap, CMapName, def) are skipped as inert; the bf* operators belong to ToUnicode (9.10.3). |
| 9.7.6 | Type 0 Font Dictionaries | incomplete | 7 | 9 | Parent row: see 9.7.6.1 (implemented), 9.7.6.2 (implemented) and 9.7.6.3 (incomplete). |
| 9.7.6.1 | General | implemented | 2 | 3 | Table 121 entries Subtype, Encoding, DescendantFonts (first element) and ToUnicode are read; BaseFont feeds style detection only. |
| 9.7.6.2 | CMap Mapping | implemented | 3 | 3 | Codes are matched byte-wise against the codespace ranges (shortest match wins) and looked up by (length, value), so equal values of different lengths stay distinct; with no codespaces at all two-byte codes are assumed. |
| 9.7.6.3 | Handling Undefined Characters | incomplete | 2 | 3 | Notdef ranges are consulted after every real mapping, an invalid code consumes the shortest codespace whose first byte fits and maps to CID 0, and CID 0 still advances by /W or /DW; the renderer never draws the notdef glyph (gid 0 is skipped and reported as NoGlyph) and with no partial match one byte is consumed instead of the shortest codespace length. |
| 9.8.1 | General | implemented | 4 | 5 | Table 122 entries FontName, Flags, ItalicAngle, Ascent, Descent, CapHeight, StemV, FontWeight, MissingWidth and the three FontFile keys are consumed for metrics, style and substitution; FontBBox, XHeight, StemH, Leading, AvgWidth, MaxWidth and CharSet are not read. |
| 9.8.2 | Font Descriptor Flags | implemented | 12 | 8 | FixedPitch, Serif, Nonsymbolic, Italic and ForceBold (Table 123 bits 1, 2, 6, 7 and 19) drive span style, substitute face choice and the StandardEncoding default; Symbolic, Script, AllCap and SmallCap are not consulted. |
| 9.8.3 | Font Descriptors for CIDFonts | not implemented | 2 | 2 | Parent row: see 9.8.3.1 (incomplete), 9.8.3.2 (notImplemented) and 9.8.3.3 (notImplemented). |
| 9.8.3.1 | General | incomplete | 2 | 2 | The descendant's descriptor is read through the same Table 122 path as simple fonts (Flags, metrics, FontFile2 and FontFile3), but none of the Table 124 CIDFont-only entries (Style, Lang, FD, CIDSet) is consulted. |
| 9.8.3.2 | Style | not implemented | 0 | 0 | The /Style dictionary and its /Panose string are never read. |
| 9.8.3.3 | FD | not implemented | 0 | 0 | The /FD dictionary of per-class descriptors is never read; only the top-level descriptor metrics apply. |
| 9.9 | Embedded Font Programs | incomplete | 4 | 6 | FontFile (Type 1 as PFA or PFB, eexec decrypted), FontFile2 (TrueType) and FontFile3 as bare CFF (Type1C and CIDFontType0C) are parsed and painted; the FontFile3 /Subtype is never read, OpenType-wrapped programs (OTTO) are rejected by both parsers, Length1, Length2 and Length3 are not used, and the writer embeds no font programs. |
| 9.10.2 | Mapping Character Codes to Unicode Values | incomplete | 3 | 4 | ToUnicode is consulted first, simple fonts then map through the encoding's glyph names (Adobe Glyph List, uniXXXX and uXXXX[XX] forms, underscore ligatures, period variants) and composite fonts through the collection's Uni*-UTF16-H inverse keyed by /Ordering; /ActualText marked content is never used and gXX or cidXX style glyph names are not resolved. |
| 9.10.3 | ToUnicode CMaps | implemented | 2 | 6 | begincodespacerange, beginbfchar and both beginbfrange forms are parsed with UTF-16BE destinations (multi-character and surrogate pairs) for simple and Type0 fonts alike; a lone U+FFFD destination is treated as no mapping and usecmap inside a ToUnicode CMap is not followed. |
10 Rendering
| Clause | Feature | Status | Code citations | Test citations | Note |
|---|---|---|---|---|---|
| 10.2 | CIE-Based Colour to Device Colour | implemented | 1 | 4 | CalRGB, CalGray, Lab and ICCBased colours convert through XYZ with Bradford adaptation into sRGB, the only output device; /BlackPoint is never read and the ri operator and /RI are parsed then discarded. |
| 10.3.2 | Conversion between DeviceGray and DeviceRGB | implemented | 2 | 2 | Gray to RGB replicates the value; RGB to gray uses the clause's 0.3/0.59/0.11 weights inside blend luminosity and Rec. 601 integer weights (77/150/29 over 256) for luminosity soft masks, and no gray output device exists. |
| 10.3.3 | Conversion between DeviceGray and DeviceCMYK | out of scope | 0 | 0 | The rasterizer targets only an RGB device, so gray never converts to or from CMYK. |
| 10.3.4 | Conversion from DeviceRGB to DeviceCMYK | out of scope | 0 | 0 | There is no CMYK output device, so RGB is never converted to CMYK. |
| 10.3.5 | Conversion from DeviceCMYK to DeviceRGB | implemented | 1 | 3 | Every CMYK fill, stroke and image sample converts to RGB, but on purpose with the multiplicative (1-c)(1-k) form rather than the clause's 1-min(1, c+k) so deep colours keep their hue. |
| 10.4 | Transfer Functions | out of scope | 0 | 0 | ExtGState /TR and /TR2 are output-device calibration hints a screen rasterizer ignores and they are never read; the soft-mask dictionary /TR is applied and assessed under 11.6.5.2. |
| 10.5.2 | Halftone Screens | out of scope | 0 | 0 | Halftoning is a printer feature; /HT is never read and the rasterizer paints continuous-tone anti-aliased RGB. |
| 10.5.3 | Spot Functions | out of scope | 0 | 0 | No halftone screens exist, so spot functions have nothing to drive. |
| 10.5.4 | Threshold Arrays | out of scope | 0 | 0 | No halftone screens exist, so threshold arrays are never read. |
| 10.5.5 | Halftone Dictionaries | out of scope | 0 | 0 | Halftone dictionaries of every type (1, 5, 6, 10, 16) are never parsed; the code does not distinguish 10.5.5.2 to 10.5.5.6. |
| 10.6.2 | Flatness Tolerance | incomplete | 2 | 2 | Curves flatten to a fixed 0.1 device-pixel error bound, which satisfies any permitted flatness, but the i operator is parsed then discarded and ExtGState /FL is never read. |
| 10.6.3 | Smoothness Tolerance | incomplete | 2 | 0 | Shadings are evaluated per device pixel, so any smoothness tolerance is met, but ExtGState /SM is never read. |
| 10.6.4 | Scan Conversion Rules | implemented | 2 | 6 | Anti-aliased analytic coverage (vertical subsamples, exact horizontal spans) under the nonzero and even-odd rules, clips applied as coverage masks, and open subpaths closed for filling. |
| 10.6.5 | Automatic Stroke Adjustment | not implemented | 0 | 0 | ExtGState /SA is never read; the 0.75 device-pixel minimum pen width at stroke.rs is a hairline floor, not stroke adjustment. |
11 Transparency
| Clause | Feature | Status | Code citations | Test citations | Note |
|---|---|---|---|---|---|
| 11.2 | Overview of Transparency | incomplete | 2 | 2 | Constant alpha, blend modes and soft masks are painted object by object, but transparency groups (group alpha, isolated, knockout) are never composited as groups. |
| 11.3.2 | Basic Notation for Compositing Computations | incomplete | 1 | 0 | Definitions only; the formula they name is assessed under 11.3.3. |
| 11.3.3 | Basic Compositing Formula | incomplete | 2 | 2 | Union alpha and alpha-weighted colour follow the formula, but the blend result enters unweighted by backdrop alpha (the (1-ab)Cs + abB(Cb,Cs) term is missing), so a non-Normal mode over a transparent backdrop such as an /S /Alpha mask group blends against black. |
| 11.3.4 | Blending Colour Space | incomplete | 1 | 0 | Blending always happens in 8-bit device sRGB after colour conversion; a group /CS is never read, so CMYK or Lab content blends in RGB rather than its own space. |
| 11.3.5 | Blend Mode | implemented | 9 | 12 | All sixteen Table 136 and 137 modes are parsed (name or array form, unknown names read as Normal) and painted on fills, strokes, glyphs, images, shadings and pattern tiles; the twelve separable formulas (32000-2 §11.3.5.2) are coded with Multiply and Screen checked against their formula, and the four non-separable modes (32000-2 §11.3.5.3) are checked against hand-computed vectors. |
| 11.3.6 | Interpretation of Alpha | incomplete | 2 | 1 | One alpha per paint (coverage times constant alpha times soft mask times image sample alpha) stands in for shape and opacity, which are never carried as separate values; the difference only shows in knockout groups (11.4.6). |
| 11.3.7 | Shape and Opacity Computations | incomplete | 5 | 5 | Source shape and opacity combine as the clause asks (11.3.7.2); result shape and opacity are not tracked (11.3.7.3). |
| 11.3.7.2 | Source Shape and Opacity | implemented | 2 | 4 | Source alpha is the product of anti-aliased object coverage, the graphics-state soft mask intersected with the clip, the constant alpha and any image sample alpha, matching fjfmqk with the constant shape fixed at 1. |
| 11.3.7.3 | Result Shape and Opacity | incomplete | 1 | 0 | composite_over unions alpha (as + ab*(1-as)) on the page and offscreen mask buffers, but result shape and opacity are never kept apart, so group results (11.4) cannot be formed. |
| 11.3.8 | Summary of Basic Compositing Computations | incomplete | 1 | 0 | Summary only; see 11.3.3 for the missing backdrop-alpha weighting of the blend result. |
| 11.4.2 | Notation for Group Compositing Computations | not implemented | 0 | 0 | Definitions only; group compositing itself is absent (11.4.4). |
| 11.4.3 | Group Structure and Nomenclature | not implemented | 0 | 0 | Definitions only; no group tree is built because /Group is never read (11.4.4). |
| 11.4.4 | Group Compositing Computations | not implemented | 0 | 0 | form_frame at executor.rs reads only /Matrix, /BBox and /Resources, so a form with /Group paints straight onto the page and group alpha, blend mode and soft mask apply per object instead of to the group composite. |
| 11.4.5 | Isolated Groups | not implemented | 0 | 0 | The /Group /I flag is never read; the only render onto a fresh backdrop is the /SMask /G form (executor.rs), which belongs to 11.5. |
| 11.4.6 | Knockout Groups | not implemented | 0 | 0 | /Group /K and ExtGState /TK are never read; overlapping objects, and glyphs painted one at a time through fill_spans (executor.rs), always composite over each other. |
| 11.4.7 | Page Group | incomplete | 1 | 0 | The page renders onto an opaque white pixmap, matching a page group composited against white, but the page dictionary's /Group (/CS, /I, /K) is never read. |
| 11.4.8 | Summary of Group Compositing Computations | not implemented | 0 | 0 | Summary only; see 11.4.4. |
| 11.5.2 | Deriving a Soft Mask from Group Alpha | implemented | 2 | 1 | The /G form renders on a transparent offscreen page as an isolated group and its alpha channel becomes the mask. |
| 11.5.3 | Deriving a Soft Mask from Group Luminosity | implemented | 2 | 2 | The group renders over an opaque black or /BC backdrop and Rec. 601 luma times alpha becomes the mask with /TR applied; /BC is read as one gray component whatever the group colour space and has no test, and luminosity is taken in device RGB rather than the group /CS. |
| 11.6.2 | Specifying Source and Backdrop Colours | implemented | 1 | 2 | The source colour is the current fill or stroke colour, image sample or shading value converted to RGB, and the backdrop is the pixel already on the page or offscreen mask buffer; no group backdrop exists (11.4). |
| 11.6.3 | Specifying Blending Colour Space and Blend Mode | incomplete | 2 | 2 | /BM as a name or array is honoured, but the blending colour space is never read from a group /CS and is always device RGB. |
| 11.6.4 | Specifying Shape and Opacity | implemented | 7 | 12 | Object coverage, the graphics-state soft mask and the constant alpha all feed one source alpha; see 11.6.4.2 to 11.6.4.4. |
| 11.6.4.2 | Object Shape and Opacity | implemented | 2 | 3 | Fills, strokes, glyph outlines and stencil masks contribute anti-aliased coverage as shape, and image sample alpha (/SMask, /Mask, JPX alpha) contributes opacity. |
| 11.6.4.3 | Mask Shape and Opacity | implemented | 2 | 4 | The ExtGState soft mask multiplies into the alpha of every paint (fills, strokes, glyphs, images, shadings, tiles) and follows q/Q; it is folded into one alpha rather than kept as mask opacity distinct from shape. |
| 11.6.4.4 | Constant Shape and Opacity | implemented | 1 | 3 | /ca and /CA are clamped to 0..=1 and applied to fills, glyphs, images, shadings and tiles (ca) and to strokes (CA); stroke alpha /CA has no test anywhere in the tree. |
| 11.6.5 | Specifying Soft Masks | incomplete | 6 | 14 | Soft-mask dictionaries are complete (11.6.5.2); soft-mask images lack /Matte handling (11.6.5.3). |
| 11.6.5.2 | Soft-Mask Dictionaries | implemented | 2 | 8 | /S (Alpha or Luminosity), /G rendered at the CTM in force at gs from a fresh graphics state, /BC, /TR (function, /Identity, /Default) and /SMask /None are handled with failures reported; /BC is approximated as gray and untested. |
| 11.6.5.3 | Soft-Mask Images | incomplete | 2 | 4 | An image /SMask (with /Decode, any dimensions) and JPX /SMaskInData 1 and 2 give per-sample alpha, but /Matte pre-blended colours are only reported, never un-blended. |
| 11.6.6 | Transparency Group XObjects | not implemented | 0 | 0 | form_frame (executor.rs) never reads /Group, so /S /Transparency forms paint inline like plain forms and /CS, /I and /K have no effect; the only /S /Transparency in the tree is a test fixture at executor.rs. |
| 11.6.7 | Patterns and Transparency | incomplete | 2 | 6 | Shading patterns and tiling cells take the invoking state's constant alpha, blend mode and soft mask, but a tiling cell is not composited as one transparency group, so translucent or overlapping tiles composite tile by tile. |
| 11.7.2 | Colour Spaces for Transparency Groups | not implemented | 0 | 0 | Group /CS is never read and no group colour space exists; everything blends in device RGB. |
| 11.7.3 | Spot Colours and Transparency | out of scope | 0 | 0 | Separation and DeviceN colours pass through their tint transforms into RGB before compositing, so this screen device has no spot colourants to composite separately. |
| 11.7.4 | Overprinting and Transparency | out of scope | 0 | 0 | /OP, /op and /OPM are never read; overprint simulation is a print-preview feature the screen rasterizer does not attempt, which covers 11.7.4.2 to 11.7.4.5 alike. |
| 11.7.5 | Rendering Parameters and Transparency | not implemented | 0 | 0 | Neither halftone and transfer parameters (11.7.5.2) nor rendering intents (11.7.5.3) take part in compositing. |
| 11.7.5.2 | Halftone and Transfer Function | out of scope | 0 | 0 | No halftones or graphics-state transfer functions exist (10.4, 10.5), so there is nothing to apply after group compositing. |
| 11.7.5.3 | Rendering Intent and Colour Conversions | not implemented | 0 | 0 | ri and /RI are parsed then discarded (executor.rs), the ICC crate uses only a profile's default transform (icc lib.rs), and all colour converts to sRGB at paint time rather than at group compositing. |
12 Interactive Features
| Clause | Feature | Status | Code citations | Test citations | Note |
|---|---|---|---|---|---|
| 12.2 | Viewer Preferences | not implemented | 0 | 0 | The /ViewerPreferences dictionary (HideToolbar, HideMenubar, FitWindow, Direction, PrintScaling, Duplex and the rest) is never read or written; the writer's Viewer struct at crates/pdfboss-write/src/pdf.rs emits the catalog's /PageLayout, /PageMode and /OpenAction, which belong to §7.7.2. |
| 12.3.2 | Destinations | incomplete | 3 | 7 | Explicit /XYZ destinations are written for links, outline items and /OpenAction; no destination is ever read, followed or rewritten, and named destinations are absent. |
| 12.3.2.2 | Explicit Destinations | incomplete | 1 | 4 | Every emitted destination is [page /XYZ null null null]; the other fit forms (Fit, FitH, FitV, FitR, FitB, FitBH, FitBV) are never written, no reader parses a destination array, and the importer copies a source /GoTo /D unchanged instead of rewriting it onto the imported page (pinned by the importer test). |
| 12.3.2.3 | Named Destinations | not implemented | 0 | 0 | Neither the catalog /Dests dictionary nor the /Names /Dests name tree is read or written, and no writer API accepts a destination by name. |
| 12.3.3 | Document Outline | incomplete | 2 | 5 | The writer emits a complete outline tree (/Outlines with /First, /Last and /Count; items with /Title, /Parent, /Prev, /Next, /First, /Last, /Count and /Dest) with every item open; nothing reads or lists an existing outline, and item /A, /SE, /C and /F are never written. |
| 12.3.4 | Thumbnail Images | not implemented | 0 | 0 | Page /Thumb images are never read, rendered or written. |
| 12.3.5 | Collections | not implemented | 0 | 0 | The catalog /Collection dictionary and collection schemas are never read or written (the only Collection identifiers in the code are CJK CMap character collections). |
| 12.4.2 | Page Labels | incomplete | 4 | 6 | The writer emits the /PageLabels number tree with /S, /P and /St per range and validates the page-0 range, duplicate first pages and start_at; no reader parses /PageLabels or computes a page's label, so the CLI, TUI and Python bindings never show labels. |
| 12.4.3 | Articles | not implemented | 1 | 0 | Article threads (the catalog /Threads array, thread and bead dictionaries) are never read or written. |
| 12.4.4 | Presentations | not implemented | 0 | 0 | Page /Trans transition dictionaries (Table 162), /Dur and /PresSteps are never read or written; the writer's FullScreen page mode is a §7.7.2 catalog entry, and playing a presentation is viewer behavior. |
| 12.4.4.2 | Sub-page Navigation | out of scope | 0 | 0 | Navigation nodes (/PresSteps) drive keyboard-stepped presentation playback, which needs a viewer; pdfboss neither reads nor writes them. |
| 12.5.2 | Annotation Dictionaries | incomplete | 2 | 5 | The renderer reads /Subtype, /Rect, /F, /AP, /AS and /OC, the element listings (core, aio, TUI, Python) expose only /Subtype per annotation, and the writer emits /Type, /Subtype, /Rect, /Border and /A for links; /Contents, /P, /NM, /M, /C and /StructParent are never read or written. |
| 12.5.3 | Annotation Flags | incomplete | 2 | 2 | Hidden (bit 2) and NoView (bit 6) suppress painting and /OC gating is honored; Invisible, Print, NoZoom, NoRotate, ReadOnly, Locked, ToggleNoView and LockedContents are ignored, so NoRotate annotations turn with a rotated page and the Print flag never affects output. |
| 12.5.4 | Border Styles | incomplete | 1 | 1 | The writer puts /Border [0 0 0] on every link so no border shows, and no test asserts that entry; the renderer never reads /Border or /BS, so an annotation with a border style but no /AP paints nothing. |
| 12.5.5 | Appearance Streams | implemented | 3 | 5 | The /AP /N normal appearance is selected (through /AS for a state dictionary, a single-state dictionary needing no /AS), its /BBox transformed by /Matrix is fitted onto the normalized /Rect per the clause's algorithm and run as a form XObject, and a declared appearance that cannot be read or placed is reported; /R and /D are pointer states a rasterizer does not show. |
| 12.5.6 | Annotation Types | incomplete | 24 | 18 | Assessed as a group: the renderer is subtype-blind and paints every type through its /AP /N appearance, the only special handling being that /Popup annotations are skipped, /AS state selection serves Widget check boxes and radio buttons, and pdfboss-write emits /Link annotations; no type-specific key is read and no appearance is synthesized when /AP is missing. |
| 12.5.6.2 | Markup Annotations | not implemented | 0 | 0 | No Table 170 entry (/T, /Popup, /CA, /RC, /CreationDate, /IRT, /Subj, /RT, /IT, /ExData) is read, and in particular the /CA constant opacity is not applied when the appearance stream is painted. |
| 12.5.6.3 | Annotation States | not implemented | 0 | 0 | /State and /StateModel on reply annotations are never read, so review status is not exposed. |
| 12.5.6.4 | Text Annotations | incomplete | 1 | 0 | Painted only through the group /AP path (tested with /Stamp and Widget fixtures, not /Text); /Open and /Name are ignored, no icon is synthesized without /AP, and the fixed-size NoZoom/NoRotate behavior the clause expects is not applied. |
| 12.5.6.5 | Link Annotations | implemented | 3 | 8 | Link annotations with /Rect, /Border [0 0 0] and a /URI or /GoTo action are written from Rust, Python, Markdown and the TOML manifest and read back structurally, and a Link without /AP paints nothing; /Dest on the annotation itself, /H, /PA and /QuadPoints are not written or read, and text extraction does not report link targets. |
| 12.5.6.6 | Free Text Annotations | incomplete | 1 | 0 | Painted only through the group /AP path; /DA, /Q, /RC, /DS, /CL, /IT, /BE and /RD are ignored and no appearance is generated from them. |
| 12.5.6.7 | Line Annotations | incomplete | 1 | 0 | Painted only through the group /AP path; /L, /LE, /IC, /LL, /LLE, /Cap and /Measure are ignored and no line is drawn without /AP. |
| 12.5.6.8 | Square and Circle Annotations | incomplete | 1 | 0 | Painted only through the group /AP path; /IC, /BE and /RD are ignored and no shape is drawn without /AP. |
| 12.5.6.9 | Polygon and Polyline Annotations | incomplete | 1 | 0 | Painted only through the group /AP path; /Vertices, /LE, /BE, /IC, /IT and /Measure are ignored. |
| 12.5.6.10 | Text Markup Annotations | incomplete | 1 | 0 | Painted only through the group /AP path; /QuadPoints are never read, so highlights, underlines, squiggles and strike-outs without /AP paint nothing and text extraction does not report marked-up spans. |
| 12.5.6.11 | Caret Annotations | incomplete | 1 | 0 | Painted only through the group /AP path; /RD and /Sy are ignored. |
| 12.5.6.12 | /Stamp annotations | implemented | 2 | 5 | /Stamp fixtures are the group's main test subject: the /AP appearance is fitted onto /Rect, hidden and OC-gated ones stay silent, and unreadable ones are reported; the /Name icon is not synthesized when /AP is absent. |
| 12.5.6.13 | Ink Annotations | incomplete | 1 | 0 | Painted only through the group /AP path; /InkList and /BS are ignored, so an ink annotation without /AP paints nothing. |
| 12.5.6.14 | Pop-up Annotations | implemented | 1 | 1 | Pop-up annotations are skipped by subtype even when they carry an /AP, which matches a static page render where the pop-up window is viewer UI; /Open and /Parent are not read. |
| 12.5.6.15 | File Attachment Annotations | incomplete | 1 | 0 | Painted only through the group /AP path; /FS and /Name are ignored and the attached file is not extracted (the writer's Attachment type is the document-level /EmbeddedFiles name tree of §7.11.4, not an annotation). |
| 12.5.6.16 | Sound Annotations | incomplete | 1 | 0 | Painted only through the group /AP path; /Sound and /Name are ignored and playback is viewer behavior. |
| 12.5.6.17 | Movie Annotations | incomplete | 1 | 0 | Painted only through the group /AP path; /Movie, /A and /T are ignored and playback is viewer behavior. |
| 12.5.6.18 | Screen Annotations | incomplete | 1 | 0 | Painted only through the group /AP path; /MK, /A and /AA are ignored and media playback is viewer behavior. |
| 12.5.6.19 | Widget Annotations | implemented | 1 | 1 | A widget's appearance comes from /AP /N with /AS selecting among the state dictionary's streams, and an /AS naming no state is reported as a dropped annotation; /H, /MK and /BS are not read, so no appearance is generated for a widget lacking /AP. |
| 12.5.6.20 | Printer’s Mark Annotations | incomplete | 1 | 0 | Painted through the group /AP path like any other annotation; /MN is ignored and there is no print-versus-display distinction, so marks always show. |
| 12.5.6.21 | Trap Network Annotations | incomplete | 1 | 0 | Painted through the group /AP path; /LastModified, /Version, /AnnotStates and /FontFauxing are ignored and the page /LastModified consistency rule is not checked. |
| 12.5.6.22 | Watermark Annotations | incomplete | 1 | 0 | Painted through the group /AP path with the page; the /FixedPrint dictionary (/Matrix, /H, /V) is ignored, and the overlay command in crates/pdfboss-write/src/update.rs adds page content rather than a /Watermark annotation. |
| 12.5.6.23 | Redaction Annotations | incomplete | 1 | 0 | Painted through the group /AP path; /QuadPoints, /IC, /RO, /OverlayText, /Repeat, /DA and /Q are ignored, and applying a redaction (removing the content beneath) is not offered. |
| 12.6.2 | Action Dictionaries | incomplete | 1 | 3 | The writer emits /URI and /GoTo action dictionaries (/S plus the type's own entries) on link annotations and tests read them back; /Next chaining is never written or followed and no reader parses an arbitrary action dictionary. |
| 12.6.3 | Trigger Events | incomplete | 1 | 3 | The catalog /OpenAction is written as an explicit destination to the open_to page and range-checked; additional-actions (/AA) dictionaries on the catalog, pages, annotations and fields are never read or written, and firing triggers is viewer behavior. |
| 12.6.4 | Action Types | incomplete | 5 | 9 | Only /URI and /GoTo actions are written; the fourteen other action types are neither written nor read, and no action of any type is executed. |
| 12.6.4.2 | Go-To Actions | implemented | 1 | 2 | /GoTo actions with /S /GoTo and an explicit /D destination are written for page-target links with the target page range-checked, and the action is read back in tests; on read a /GoTo is never followed (viewer behavior) and the importer copies it unchanged. |
| 12.6.4.3 | Remote Go-To Actions | not implemented | 0 | 0 | No /GoToR action is written or read. |
| 12.6.4.4 | Embedded Go-To Actions | not implemented | 0 | 0 | No /GoToE action or target dictionary is written or read. |
| 12.6.4.5 | Launch Actions | not implemented | 0 | 0 | No /Launch action is written or read; launching an application would be viewer behavior in any case. |
| 12.6.4.6 | Thread Actions | out of scope | 0 | 0 | Thread actions step through article beads inside a viewer; pdfboss executes no actions and does not model article threads. |
| 12.6.4.7 | URI Actions | implemented | 3 | 5 | /URI actions with /S /URI and the URI as a text string are written for external links from every writer front end and read back structurally in tests; /IsMap and the catalog-level /URI base dictionary are not handled, and text extraction does not report URIs. |
| 12.6.4.8 | Sound Actions | out of scope | 0 | 0 | Sound playback needs a viewer with audio output; pdfboss executes no actions. |
| 12.6.4.9 | Movie Actions | out of scope | 0 | 0 | Movie playback needs a viewer with media output; pdfboss executes no actions. |
| 12.6.4.10 | Hide Actions | out of scope | 0 | 0 | Hiding or showing annotations at run time is viewer state; the renderer honors only the static Hidden flag. |
| 12.6.4.11 | Named Actions | out of scope | 0 | 0 | NextPage, PrevPage, FirstPage and LastPage are viewer navigation; pdfboss executes no actions. |
| 12.6.4.12 | Set-OCG-State Actions | out of scope | 0 | 0 | Toggling optional content groups at run time is viewer state; the renderer applies only the document's default /OCProperties /D configuration. |
| 12.6.4.13 | Rendition Actions | out of scope | 0 | 0 | Multimedia rendition playback needs a viewer; pdfboss executes no actions. |
| 12.6.4.14 | Transition Actions | out of scope | 0 | 0 | Page transitions are presentation playback inside a viewer; pdfboss executes no actions. |
| 12.6.4.15 | Go-To-3D-View Actions | out of scope | 0 | 0 | 3D artwork views need a 3D-capable viewer; pdfboss neither renders 3D streams nor executes actions. |
| 12.6.4.16 | JavaScript Actions | out of scope | 0 | 0 | pdfboss has no JavaScript engine and never executes document scripts. |
| 12.7.2 | Interactive Form Dictionary | not implemented | 0 | 0 | The catalog /AcroForm dictionary (/Fields, /NeedAppearances, /SigFlags, /CO, /DR, /DA, /Q, /XFA) is never read or written; widgets are painted only from their own /AP. |
| 12.7.3 | Field Dictionaries | not implemented | 0 | 0 | Field dictionaries (Table 220: /FT, /Parent, /Kids, /T, /TU, /TM, /Ff, /V, /DV, /AA) are never read or written; only a merged widget's /AP is rendered. |
| 12.7.3.2 | Field Names | not implemented | 0 | 0 | Fully qualified field names from the /T chain are never computed. |
| 12.7.3.3 | Variable Text | not implemented | 0 | 0 | /DA, /Q, /DS and /RV are never read and no appearance stream is generated for text-bearing fields, so /NeedAppearances documents show only pre-existing /AP streams. |
| 12.7.3.4 | Rich Text Strings | not implemented | 0 | 0 | /RV rich text is never parsed. |
| 12.7.4 | Field Types | incomplete | 4 | 4 | Only the widget-level /AS state selection that check boxes and radio buttons rely on is handled; /FT, /V, /Ff and /Opt are never read for any field type. |
| 12.7.4.2 | Button Fields | incomplete | 3 | 3 | Check box and radio button appearance states are selected through /AS; the button flags (Pushbutton, Radio, NoToggleToOff, RadiosInUnison) and /V are never read. |
| 12.7.4.2.2 | Pushbuttons | not implemented | 0 | 0 | A pushbutton's /MK caption and icon entries are never read; only a pre-existing /AP paints through the generic widget path. |
| 12.7.4.2.3 | Check Boxes | incomplete | 1 | 1 | The on or off appearance is selected by /AS from the /AP /N state dictionary (tested with an /On state); the field's /V, /Opt export values and /Ff are never read, so the checked state is not exposed as data. |
| 12.7.4.2.4 | Radio Buttons | incomplete | 1 | 1 | Each kid widget's appearance is selected by /AS like a check box; the parent field's /V, /Opt and the NoToggleToOff and RadiosInUnison flags are never read. |
| 12.7.4.3 | Text Fields | not implemented | 0 | 0 | /V, /MaxLen and the text-field flags are never read and no appearance is generated, so a text field shows only a pre-existing /AP. |
| 12.7.4.4 | Choice Fields | not implemented | 0 | 0 | /Opt, /TI, /I, /V and the choice-field flags are never read. |
| 12.7.4.5 | Signature Fields | not implemented | 0 | 0 | A signature field's /V signature dictionary, /Lock and /SV are never read. |
| 12.7.5 | Form Actions | out of scope | 0 | 0 | Submit, reset and import-data actions need a viewer, a form-filling state and a network; pdfboss executes no actions. |
| 12.7.5.2 | Submit-Form Action | out of scope | 0 | 0 | Submitting field data over HTTP is viewer behavior; pdfboss executes no actions. |
| 12.7.5.3 | Reset-Form Action | out of scope | 0 | 0 | Resetting fields to their defaults needs a form-filling state; pdfboss executes no actions. |
| 12.7.5.4 | Import-Data Action | out of scope | 0 | 0 | Importing FDF data into a form needs a form-filling state; pdfboss executes no actions. |
| 12.7.6 | Named Pages | not implemented | 0 | 0 | The /Names /Pages and /Names /Templates name trees are never read or written. |
| 12.7.7 | Forms Data Format | not implemented | 0 | 0 | No FDF file is parsed or written anywhere in the code. |
| 12.7.7.2 | FDF File Structure | not implemented | 0 | 0 | The document loader recognizes only %PDF headers and never reads an FDF header, body or trailer. |
| 12.7.7.2.2 | FDF Header | not implemented | 0 | 0 | The %FDF header is not recognized. |
| 12.7.7.2.3 | FDF Body | not implemented | 0 | 0 | FDF body objects are never parsed. |
| 12.7.7.2.4 | FDF Trailer | not implemented | 0 | 0 | An FDF trailer (/Root only, no xref) is never parsed. |
| 12.7.7.3 | FDF Catalog | not implemented | 0 | 0 | The FDF catalog and its /FDF dictionary are never read or written. |
| 12.7.7.3.2 | FDF Fields | not implemented | 0 | 0 | FDF field dictionaries are never read or written. |
| 12.7.7.3.3 | FDF Pages | not implemented | 0 | 0 | FDF page and template dictionaries are never read or written. |
| 12.7.7.3.4 | FDF Annotation Dictionaries | not implemented | 0 | 0 | FDF annotation dictionaries with /Page are never read or written. |
| 12.7.8 | XFA Forms | not implemented | 0 | 0 | The /AcroForm /XFA entry and XFA packets are never read, so an XFA document renders only its PDF page content. |
| 12.8.1 | General | not implemented | 0 | 0 | The signature dictionary (Table 252: /Filter, /SubFilter, /Contents, /ByteRange, /Reference, /M, /Name) is never read or written, and there is no signing or verification. |
| 12.8.2 | Transform Methods | not implemented | 0 | 0 | Signature reference dictionaries and their /TransformMethod are never read. |
| 12.8.2.2 | DocMDP | not implemented | 0 | 0 | DocMDP transform parameters (/P, /V) are never read. |
| 12.8.2.2.2 | Validating Signatures That Use the DocMDP Transform Method | not implemented | 0 | 0 | No DocMDP validation exists, and the incremental-update writer in crates/pdfboss-write/src/update.rs appends changes without checking for a certifying signature. |
| 12.8.2.3 | UR | not implemented | 0 | 0 | Usage-rights transform parameters are never read. |
| 12.8.2.4 | FieldMDP | not implemented | 0 | 0 | FieldMDP transform parameters (/Action, /Fields) are never read. |
| 12.8.3 | Signature Interoperability | not implemented | 0 | 0 | No /SubFilter value is recognized and no signature bytes are decoded. |
| 12.8.3.2 | PKCS#1 Signatures | not implemented | 0 | 0 | adbe.x509.rsa_sha1 signatures and /Cert chains are never decoded or verified. |
| 12.8.3.3 | PKCS#7 Signatures as used in ISO 32000 | not implemented | 0 | 0 | PKCS#7 signature containers are never decoded or verified. |
| 12.8.3.3.2 | Revocation Information | not implemented | 0 | 0 | Embedded CRL and OCSP data are never read. |
| 12.8.4 | Permissions | not implemented | 0 | 0 | The catalog /Perms dictionary (/DocMDP, /UR3) is never read; the /Perms handling in crates/pdfboss-core/src/crypt.rs is the AES-256 encryption dictionary entry of §7.6.3.3. |
| 12.8.5 | Legal Content Attestations | not implemented | 0 | 0 | The /Legal attestation dictionary is never read or written (Legal in the code is a page size). |
| 12.9 | Measurement Properties | not implemented | 0 | 0 | Viewport (/VP), /Measure and number-format dictionaries are never read or written. |
| 12.10.1 | General | not implemented | 0 | 0 | The catalog /Requirements array and requirement dictionaries (Table 266) are never read or written. |
| 12.10.2 | Requirement Handlers | not implemented | 0 | 0 | Requirement handler dictionaries (/S /JS, /S /NoOp) are never read or written. |
13 Multimedia Features
| Clause | Feature | Status | Code citations | Test citations | Note |
|---|---|---|---|---|---|
| 13.1 | General | out of scope | 0 | 0 | pdfboss parses, extracts, renders and creates PDFs and is not a viewer, so multimedia playback has no place in it. |
| 13.2 | Multimedia | out of scope | 0 | 0 | No crate reads a rendition, media clip or media player dictionary; a grep for those key names finds nothing in the Rust sources. |
| 13.2.1 | General | out of scope | 0 | 0 | A Screen annotation's /AP /N appearance still paints generically through crates/pdfboss-render/src/executor.rs, but its /A rendition action and /MK are never read because playback is a viewer concern. |
| 13.2.2 | Viability | out of scope | 0 | 0 | Viability (the /MH must-honor and /BE best-effort dictionaries) only matters when choosing a player to run, which pdfboss never does. |
| 13.2.3 | Renditions | out of scope | 0 | 0 | Rendition dictionaries are never read because pdfboss does not play media. |
| 13.2.3.1 | General | out of scope | 0 | 0 | Same as 13.2.3: no rendition dictionary is read. |
| 13.2.3.2 | Media Renditions | out of scope | 0 | 0 | Media rendition dictionaries (/S /MR) are never read because pdfboss does not play media. |
| 13.2.3.3 | Selector Renditions | out of scope | 0 | 0 | Selector renditions (/S /SR) are never read because pdfboss does not play media. |
| 13.2.4 | Media Clip Objects | out of scope | 0 | 0 | Media clip dictionaries are never read because pdfboss does not play media. |
| 13.2.4.1 | General | out of scope | 0 | 0 | Same as 13.2.4: no media clip dictionary is read. |
| 13.2.4.2 | Media Clip Data | out of scope | 0 | 0 | Media clip data (/S /MCD) and its file specification are never read; pdfboss neither extracts nor plays embedded media. |
| 13.2.4.3 | Media Clip Section | out of scope | 0 | 0 | Media clip sections (/S /MCS) are never read because pdfboss does not play media. |
| 13.2.5 | Media Play Parameters | out of scope | 0 | 0 | Play parameters (volume, repeat, duration) only apply during playback, which pdfboss never does. |
| 13.2.6 | Media Screen Parameters | out of scope | 0 | 0 | Screen parameters (window, floating window, background) describe a viewer's playback window and are never read. |
| 13.2.6.1 | General | out of scope | 0 | 0 | Same as 13.2.6: no screen parameter dictionary is read. |
| 13.2.6.2 | Media Offset Dictionary | out of scope | 0 | 0 | Media offsets (time, frame, marker) are only meaningful during playback and are never read. |
| 13.2.6.3 | Timespan Dictionary | out of scope | 0 | 0 | Timespan dictionaries are only meaningful during playback and are never read. |
| 13.2.7 | Other Multimedia Objects | out of scope | 0 | 0 | Media players, player info, software identifiers and monitor specifiers describe a viewer's environment and are never read. |
| 13.2.7.1 | General | out of scope | 0 | 0 | Same as 13.2.7: none of these dictionaries is read. |
| 13.2.7.2 | Media Players Dictionary | out of scope | 0 | 0 | Player selection lists (/MU, /A, /NU) are never read because pdfboss does not select or run players. |
| 13.2.7.3 | Media Player Info Dictionary | out of scope | 0 | 0 | Player info dictionaries are never read because pdfboss does not select or run players. |
| 13.2.7.4 | Software Identifier Dictionary | out of scope | 0 | 0 | Software identifiers are never read because pdfboss does not select or run players. |
| 13.2.7.4.1 | General | out of scope | 0 | 0 | Same as 13.2.7.4: no software identifier is read. |
| 13.2.7.4.2 | Software URIs | out of scope | 0 | 0 | Software URIs are never read because pdfboss does not select or run players. |
| 13.2.7.4.3 | Version arrays | out of scope | 0 | 0 | Player version arrays are never read because pdfboss does not select or run players. |
| 13.2.7.5 | Monitor Specifier | out of scope | 0 | 0 | Monitor specifiers describe the viewer's display and are never read. |
| 13.3 | Sounds | out of scope | 0 | 0 | Sound objects and a Sound annotation's /Sound stream are never read; the annotation's /AP /N appearance paints generically through crates/pdfboss-render/src/executor.rs and crates/pdfboss-core/src/elements.rs lists it by subtype like any other annotation. |
| 13.4 | Movies | out of scope | 0 | 0 | Movie dictionaries and movie activation dictionaries are never read; a Movie annotation's /AP /N appearance paints generically through crates/pdfboss-render/src/executor.rs. |
| 13.5 | Alternate Presentations | out of scope | 0 | 0 | The /AlternatePresentations name tree and SlideShow dictionaries are never read because pdfboss does not present documents. |
| 13.6.1 | General | out of scope | 0 | 0 | 3D artwork (3D annotations, 3D streams, U3D data) is never read because pdfboss neither renders nor extracts 3D content. |
| 13.6.3.1 | General | out of scope | 0 | 0 | 3D stream dictionaries (/Type /3D) are never read; pdfboss does no 3D work. |
| 13.6.4.1 | General | out of scope | 0 | 0 | 3D view dictionaries are never read; pdfboss does no 3D work. |
| 13.6.4.2 | Projection Dictionaries | out of scope | 0 | 0 | 3D projection dictionaries are never read; pdfboss does no 3D work. |
| 13.6.5 | Coordinate Systems for 3D | out of scope | 0 | 0 | 3D coordinate systems are never used; pdfboss does no 3D work. |
14 Document Interchange
| Clause | Feature | Status | Code citations | Test citations | Note |
|---|---|---|---|---|---|
| 14.2 | Procedure Sets | not implemented | 0 | 0 | Nothing reads or emits /ProcSet: the reader ignores the resource (which the clause allows) and pdfboss-write never adds a /ProcSet array to the resource dictionaries it writes. |
| 14.3.2 | Metadata Streams | incomplete | 2 | 4 | The writer emits an unfiltered /Type /Metadata /Subtype /XML packet on the catalog and rewrites it on update, and the reader honors EncryptMetadata false for that stream, but no reader path parses XMP (Document::metadata reads only /Info) and metadata streams on pages, XObjects or other components are neither read nor written. |
| 14.3.3 | Document Information Dictionary | incomplete | 2 | 5 | Title, Author, Subject, Keywords, Creator, Producer, CreationDate and ModDate are read as decoded text strings and written back (with the XMP packet kept in step on update), but the /Trapped entry of Table 317 is neither read nor written. |
| 14.4 | File Identifiers | implemented | 2 | 4 | The writer emits a two-element /ID of 16-byte SHA-256-derived strings, an incremental update keeps the first half and replaces the second, the strings stay unencrypted, and the reader consumes the trailer /ID for the encryption key. |
| 14.5 | Page-Piece Dictionaries | not implemented | 0 | 0 | Nothing reads or writes /PieceInfo or its /LastModified and /Private entries. |
| 14.6.1 | General | implemented | 2 | 2 | MP, DP, BMC, BDC and EMC (Table 320) parse into distinct operators, and the text and render executors keep a nesting stack per content stream so EMC pops the matching open. |
| 14.6.2 | Property Lists | implemented | 2 | 3 | BDC and DP operands are accepted as an inline dictionary or as a name looked up in the resource chain's /Properties subdictionary, and the named form keeps the indirect-reference identity the optional-content code keys on. |
| 14.6.3 | Marked Content and Clipping | incomplete | 2 | 0 | Marked-content nesting is tracked on its own stack and EMC never touches the graphics state, so a clip set inside a sequence persists as the clause requires, but no test exercises a clipping path or q/Q pair that straddles a marked-content sequence. |
| 14.7.2 | Structure Hierarchy | incomplete | 2 | 3 | The catalog's /StructTreeRoot is loaded and elements are walked through /K (single or array) and /P up to the root, but /RoleMap, /ClassMap, /IDTree, /ParentTreeNextKey and the element entries /S, /T, /ID, /Lang, /Alt, /E and /ActualText are never read, and pdfboss-write neither emits a structure tree nor carries a base document's tree through assembly. |
| 14.7.3 | Structure Types | not implemented | 0 | 0 | No code reads an element's /S or the root's /RoleMap, so structure types are never identified or mapped to standard types. |
| 14.7.4 | Structure Content | incomplete | 7 | 9 | Marked-content sequences are located as content items and resolved through the parent tree, but object references (OBJR) and the /Stm form of marked-content references are not handled; the depth-4 rows give the detail. |
| 14.7.4.2 | Marked-Content Sequences as Content Items | incomplete | 2 | 3 | Bare integer MCIDs (matched against the element's /Pg) and marked-content reference dictionaries with /Pg and /MCID are matched, and MCIDs are collected from BDC in page and form content, but the /Stm and /StmOwn entries of Table 324 are never consulted, so a form's sequence is told apart from the page's only by its /StructParents key. |
| 14.7.4.3 | PDF Objects as Content Items | not implemented | 0 | 0 | Object reference dictionaries (/Type /OBJR with /Obj) are never read, so annotations and XObjects placed in the tree as whole objects are invisible to structure-order extraction. |
| 14.7.4.4 | Finding Structure Elements from Content Items | incomplete | 3 | 4 | The /ParentTree number tree (/Nums, /Kids, /Limits) is searched under the /StructParents key of the page or of a form XObject that declares its own, but the singular /StructParent key of whole-object content items is never used because OBJR items are not supported. |
| 14.7.5 | Structure Attributes | not implemented | 0 | 0 | Element /A and /C entries are never read, so no attribute object, class or revision is interpreted. |
| 14.7.5.2 | Attribute Classes | not implemented | 0 | 0 | Neither /C on elements nor /ClassMap on the root is read. |
| 14.7.5.3 | Attribute Revision Numbers | not implemented | 0 | 0 | Nothing reads /R on elements, attribute objects or class entries. |
| 14.7.5.4 | User Properties | not implemented | 0 | 0 | No code recognizes /O /UserProperties attribute objects or their /P arrays. |
| 14.7.6 | Example of Logical Structure | out of scope | 0 | 0 | A worked example of a structure tree with no requirement of its own; the structure it illustrates is assessed under 14.7.2 to 14.7.5. |
| 14.8.2 | Tagged PDF and Page Content | incomplete | 11 | 18 | Structure-tree reading order is offered on every extraction entry point, but artifacts, annotation sequencing, reversed show strings and ActualText are not handled; the depth-4 rows give the detail. |
| 14.8.2.2 | Real Content and Artifacts | not implemented | 0 | 0 | The /Artifact tag and its property list (/Type, /BBox, /Attached, /Subtype) are never recognized, so page headers, footers and page numbers extract as ordinary text; the test at crates/pdfboss-text/src/lib.rs untagged_content_keeps_its_place_after_the_tagged_content_before_it shows an /Artifact BMC footer kept in the output. |
| 14.8.2.3 | Page Content Order | incomplete | 2 | 4 | Under ReadingOrder::StructureTree each marked-content sequence is ranked by its depth-first position in the tree and untagged content keeps its place, but annotations are never sequenced into the order and /ReversedChars is ignored. |
| 14.8.2.3.2 | Sequencing of Annotations | not implemented | 0 | 0 | Annotations are not part of text extraction and OBJR items are not read, so a tagged annotation never takes its place in the reading order. |
| 14.8.2.3.3 | Reverse-Order Show Strings | not implemented | 0 | 0 | Nothing looks for the /ReversedChars marked-content tag, so right-to-left text shown in reverse order stays reversed. |
| 14.8.2.4 | Extraction of Character Properties | incomplete | 5 | 9 | Unicode values and font style come from ToUnicode, encodings, glyph names and the FontDescriptor, but ActualText, FontFamily and FontStretch are never read; the depth-4 rows give the detail. |
| 14.8.2.4.2 | Unicode Mapping in Tagged PDF | incomplete | 2 | 3 | Characters map through /ToUnicode first, then the /Encoding-derived table and StandardEncoding, Adobe Glyph List names, and the CIDSystemInfo ordering for CID fonts, but the /ActualText property that overrides all of these on a marked-content sequence is never read. |
| 14.8.2.4.3 | Font Characteristics | incomplete | 1 | 4 | Weight, italic, serif and fixed-pitch come from /Flags, /FontWeight, /StemV, /ItalicAngle and the /BaseFont name, but /FontFamily and /FontStretch are never read. |
| 14.8.2.5 | Identifying Word Breaks | incomplete | 2 | 3 | Word breaks come from space glyphs and from horizontal gaps between spans, which covers the clause's positional fallback, but the tagged-PDF rules (ActualText carrying the space, breaks implied by block-level element edges) are not applied because tags are never read. |
| 14.8.3 | Basic Layout Model | not implemented | 0 | 0 | Block-level and inline-level structure elements are never identified; paragraphs, headings and tables in Markdown output come from geometry and font size, not from the tree. |
| 14.8.4 | Standard Structure Types | not implemented | 0 | 0 | No element's /S is read, so none of the standard types in 14.8.4.2 through 14.8.4.5 is recognized. |
| 14.8.4.2 | Grouping Elements | not implemented | 0 | 0 | Document, Part, Art, Sect, Div, BlockQuote, Caption, TOC, TOCI, Index, NonStruct and Private are never recognized because /S is not read. |
| 14.8.4.3 | Block-Level Structure Elements | not implemented | 0 | 0 | P, H1 to H6, L, LI, Lbl, LBody, Table, TR, TH, TD and their usage rules are not recognized; headings and lists in Markdown output are inferred from layout instead. |
| 14.8.4.4 | Inline-Level Structure Elements | not implemented | 0 | 0 | Span, Quote, Note, Reference, BibEntry, Code, Link, Annot, Ruby and Warichu elements are never recognized. |
| 14.8.4.5 | Illustration Elements | not implemented | 0 | 0 | Figure, Formula and Form elements are never recognized; image extraction works from XObjects, not from the tree. |
| 14.8.5 | Standard Structure Attributes | not implemented | 0 | 0 | Attribute objects are never read, so no standard attribute owner or value is interpreted. |
| 14.8.5.2 | Standard Attribute Owners | not implemented | 0 | 0 | The /O entry of attribute objects is never read. |
| 14.8.5.3 | Attribute Values and Inheritance | not implemented | 0 | 0 | No attribute is read, so nothing is inherited down the tree. |
| 14.8.5.4 | Layout Attributes | not implemented | 0 | 0 | Placement, WritingMode, BBox, spacing, color and column attributes are never read. |
| 14.8.5.5 | List Attribute | not implemented | 0 | 0 | /ListNumbering is never read; list markers in output come from the page's text. |
| 14.8.5.6 | PrintField Attributes | not implemented | 0 | 0 | Role, checked and Desc attributes of form-field elements are never read. |
| 14.8.5.7 | Table Attributes | not implemented | 0 | 0 | RowSpan, ColSpan, Headers, Scope and Summary are never read; table structure in output is inferred from column gaps and rulings. |
| 14.9.2 | Natural Language Specification | not implemented | 0 | 0 | /Lang is read nowhere (catalog, structure elements or marked-content property lists), so no language is reported. |
| 14.9.2.2 | Language Identifiers | not implemented | 0 | 0 | No language tag is parsed. |
| 14.9.2.3 | Language Specification Hierarchy | not implemented | 0 | 0 | No /Lang lookup exists at any level. |
| 14.9.2.4 | Multi-language Text Arrays | not implemented | 0 | 0 | Multi-language text arrays are not parsed. |
| 14.9.3 | Alternate Descriptions | not implemented | 0 | 0 | /Alt is never read on structure elements or in property lists. |
| 14.9.4 | Replacement Text | not implemented | 0 | 0 | /ActualText is never read, so replacement text never substitutes the shown glyphs in extraction. |
| 14.9.5 | Expansion of Abbreviations and Acronyms | not implemented | 0 | 0 | /E is never read. |
| 14.10.2 | Web Capture Information Dictionary | out of scope | 0 | 0 | pdfboss reads, renders and writes PDFs and is not a web-capture tool, so /SpiderInfo is ignored. |
| 14.10.3 | Content Database | out of scope | 0 | 0 | Web capture is outside pdfboss's scope; the /IDS and /URLS name trees are ignored. |
| 14.10.4 | Content Sets | out of scope | 0 | 0 | Web capture is outside pdfboss's scope; /SPS and /SIS content sets are ignored. |
| 14.10.5 | Source Information | out of scope | 0 | 0 | Web capture is outside pdfboss's scope; source information dictionaries are ignored. |
| 14.10.6 | Object Attributes Related to Web Capture | out of scope | 0 | 0 | Web capture is outside pdfboss's scope; the /ID entry on page and XObject dictionaries is ignored (the trailer /ID is a different key and is handled under 14.4). |
| 14.11.2 | Page boxes | implemented | 6 | 5 | MediaBox, CropBox, BleedBox, TrimBox and ArtBox are read with the clause's defaults (crop falls back to media, the other three to crop), clipped to the media box and treated as non-inheritable, in the sync, async and Python APIs. |
| 14.11.2.2 | Display of page boxes | incomplete | 1 | 0 | Rendering maps the CropBox (turned by /Rotate) onto the output image as the clause's default visible area, but /BoxColorInfo is never read, no option renders the media, bleed, trim or art box instead, and no test renders a page whose CropBox is narrower than its MediaBox. |
| 14.11.3 | Printer’s Marks | not implemented | 0 | 0 | Nothing recognizes the PrinterMark annotation subtype or its /MN entry; such an annotation paints only incidentally through the generic appearance-stream path at crates/pdfboss-render/src/executor.rs, which skips only Popup, Hidden and NoView annotations. |
| 14.11.4 | Separation Dictionaries | not implemented | 0 | 0 | /SeparationInfo on page objects is never read. |
| 14.11.5 | Output Intents | not implemented | 0 | 0 | /OutputIntents on the catalog is never read, so rendering never applies an output intent's ICC profile even though pdfboss-icc could. |
| 14.11.6 | Trapping Support | out of scope | 0 | 0 | Trapping is a prepress step pdfboss does not perform; /TrapNet annotations get no special reading or painting (an appearance stream would paint like any other annotation). |
| 14.11.7 | Open Prepress Interface (OPI) | out of scope | 0 | 0 | OPI proxy substitution is a prepress workflow pdfboss does not take part in; /OPI on image and form XObjects is ignored and the XObject itself is used. |
Annexes
| Clause | Feature | Status | Code citations | Test citations | Note |
|---|---|---|---|---|---|
| A.2 | PDF Content Stream Operators | implemented | 2 | 19 | Every operator in Table A.1 parses into an Op (BI, ID and EI become one InlineImage op; f and F share Op::Fill) and none is unparsed; the rasterizer treats ri and i as an explicit no-op (executor.rs) and lets MP, DP, BX, EX, ET and d0 fall to the empty arm at executor.rs, while d1 is only checked for presence at executor.rs to choose the uncolored Type3 glyph path. |
| B.2 | Arithmetic Operators | implemented | 2 | 4 | All 21 arithmetic operators (abs add atan ceiling cos cvi cvr div exp floor idiv ln log mod mul neg round sin sqrt sub truncate) are recognized at shading.rs and evaluated by run_calculator; the tests feed add, mul, exp, log, sqrt, div, ln, atan, idiv, mod, round, truncate, floor, ceiling and cvi, leaving abs, neg, sub, sin, cos and cvr without a direct test. |
| B.3 | Relational, Boolean and Bitwise Operators | implemented | 2 | 3 | and bitshift eq false ge gt le lt ne not or true xor are all recognized; and, or, xor and not split on boolean versus integer operands, bitshift shifts in both directions, and eq/ne handle mixed-type operands. |
| B.4 | Conditional Operators | implemented | 1 | 1 | if and ifelse compile procedure blocks into forward jumps, nested conditionals branch correctly, and a block not followed by if or ifelse is a load error (shading.rs). |
| B.5 | Stack Operators | implemented | 2 | 2 | copy dup exch index pop roll are recognized, roll rotates in both directions, and the operand stack is capped at 100 entries (CALC_STACK, shading.rs) as §7.10.5.1 requires, with a 10,000-step runaway limit. |
| C.2 | Architectural Limits | implemented | 2 | 8 | The parser meets or exceeds every Table C.1 minimum (integers are i64 and reals f64 with integer overflow degrading to a real, no cap on string, name, array or dictionary size, CID range 0 to 0xFFFF) and sets its own caps above the spec's minima: object nesting 128 (spec 28), q/Q depth 64 (spec 28), indirect-reference chain 32 (MAX_RESOLVE_DEPTH), page-tree depth 256, form nesting 16; it never rejects a file for exceeding Table C.1. |
| C.3 | Memory Limits | implemented | 2 | 2 | Memory is bounded per stream rather than per document: each decoded stream is capped at 256 MiB (MAX_DECODED_LEN) so a decompression bomb is an error, CCITT checks its packed size against that cap and JBIG2 budgets its regions up front, and the aio tail scan stops at 64 KiB; there is no document-wide object-count or total-memory cap. |
| D.2 | Latin Character Set and Encodings | incomplete | 6 | 9 | The StandardEncoding, MacRomanEncoding and WinAnsiEncoding columns exist as code-to-Unicode tables (glyph-name tables only for Standard and WinAnsi), the PDFDocEncoding column decodes text strings (crates/pdfboss-core/src/object.rs pdf_doc_char) and pdfboss-write encodes text as WinAnsi; missing are a MacRoman glyph-name table, the WinAnsi footnote mapping unused codes above 0x27 to bullet (0x81, 0x8D, 0x8F, 0x90 and 0x9D return None), and /StandardEncoding named explicitly is only honored because it falls through the default arm at font.rs. |
| D.3 | PDFDocEncoding Character Set | implemented | 2 | 5 | The full PDFDocEncoding table decodes text strings without a BOM (crates/pdfboss-core/src/object.rs pdf_doc_char: accents at 0x18-0x1F, punctuation and ligatures at 0x80-0x9E, Euro at 0xA0, undefined codes to U+FFFD); the writer emits text strings as ASCII or UTF-16BE, which the clause allows, so no encoder is needed. |
| D.4 | Expert Set and MacExpertEncoding | not implemented | 0 | 0 | No MacExpertEncoding table exists anywhere; a font naming /MacExpertEncoding falls through the default arm at crates/pdfboss-text/src/font.rs and is decoded as StandardEncoding. |
| D.5 | Symbol Set and Encoding | not implemented | 0 | 0 | No built-in Symbol encoding table exists: text extraction declines to guess at Symbol's high codes (crates/pdfboss-text/src/font.rs a_picture_font_does_not_guess_at_its_high_codes), rendering leaves non-embedded Symbol unpainted (crates/pdfboss-render/src/substitute.rs symbol_and_zapfdingbats_have_no_substitute), and pdfboss-write rejects every character for it (crates/pdfboss-write/src/font.rs symbol_faces_reject_every_char_for_now), with the comments calling the tables a later phase. |
| D.6 | ZapfDingbats Set and Encoding | not implemented | 0 | 0 | Same state as Symbol: no ZapfDingbats encoding table exists, the same three tests document the refusal, and crates/pdfboss-write/src/font.rs says the table comes with a later phase. |
| E.2 | Name Registry | out of scope | 0 | 0 | pdfboss neither registers names nor checks second-class or third-class prefixes; unknown dictionary keys pass through as plain names, and registration is a publishing process rather than a parser feature. |
| F.2 | Background and Assumptions | out of scope | 0 | 0 | Design background for linearization with no requirement of its own; the file structure it motivates is assessed under F.3 and F.4. |
| F.3 | Linearized PDF Document Structure | not implemented | 0 | 0 | No crate reads the linearization parameter dictionary: pdfboss-aio locates objects by scanning the tail for startxref and following the xref chain (crates/pdfboss-aio/src/document.rs find_tail) and fetches byte ranges per object, and pdfboss-write emits no /Linearized dictionary or first-page section (crates/pdfboss-write/src/writer.rs writes a plain header). |
| F.4 | Hint Tables | not implemented | 0 | 0 | No hint stream is parsed or produced; the /H offsets and the page offset and shared object hint tables are never read. |
| I | PDF Versions and Compatibility | incomplete | 2 | 5 | The %PDF-M.m header is parsed within the first 1 KiB with one to three digit components, a missing or malformed header silently defaults to 1.4, any parsed version including future ones is accepted without a warning, unknown operators and keys are skipped as Annex I asks, and pdfboss-write emits a configurable header; missing is the catalog /Version override, which no crate reads. |