Wiki
Download
Manual
Eggs
API
Tests
Bugs
show
edit
You can edit this page using
wiki syntax
for markup.
Article contents:
[[tags: egg]] == pdfa [[toc:]] === Description Writes PDF/A-1b archival documents with the [[pdf]] egg. PDF/A (ISO 19005) is the PDF format for documents that must be kept for a long time. A PDF/A file contains everything needed to draw it the same way on any viewer, now or decades from now: its fonts, a color profile that says what its colors mean, and metadata that describes it. {{pdfa}} supports conformance level B ("basic") of PDF/A-1, which guarantees that pages look the same everywhere. Level A, which also needs a tagged logical structure, is not supported. {{pdfa}} adds three things to a {{pdf}} document: * the metadata PDF/A requires: an {{/Info}} dictionary, a matching XMP metadata stream, a trailer {{/ID}} and a binary header comment; * an output intent: an embedded ICC color profile that defines the document's colors; * conformance checks, run before the file is written, which reject a document that breaks a PDF/A-1b rule and list every problem found. Fonts must be embedded, using [[pdf-truetype]]; the standard fonts from {{pdf}}'s {{build-font}} are rejected. === Requirements [[pdf]], [[pdf-truetype]], [[srfi-1]], [[srfi-13]], [[message-digest]], [[md5]], [[sxml-transforms]], [[datatype]] === Documentation ==== Overview A PDF/A document is a record of type {{pdfa-document}}. It wraps an ordinary {{pdf}} document (a {{doc}}, at PDF version 1.4) together with its metadata and output intent. Pages, fonts and drawing use the wrapped {{doc}} and the usual {{pdf}} and {{pdf-truetype}} procedures; metadata and the output intent use the {{pdfa-document}}. A typical document: # creates a {{pdfa-document}}, usually with {{with-pdfa-document-to-file}}; # records its metadata with {{set-document-info!}}; # sets its output intent with {{set-output-intent!}}; # embeds its fonts with {{build-embedded-font}} from [[pdf-truetype]]; # draws its pages with {{with-page}}, drawing text with {{draw-encoded-text}}; # is checked and written by {{write-pdfa-document}}, which {{with-pdfa-document-to-file}} calls for you. Each document has a conformance mode. With {{'pdfa-1b}} (the default), the finished document is checked before it is written; if it breaks a rule, an error lists every problem and no file is written, and if it passes, its metadata records the claim that it conforms to PDF/A-1b. With {{#f}}, the same metadata is written with no checks and no claim. ==== What a conforming document may contain The checks accept a document that uses only: * fonts embedded with {{build-embedded-font}}; * DeviceRGB color ({{set-rgb-fill}}, {{set-rgb-stroke}}) with an RGB output intent, or DeviceCMYK color ({{set-cmyk-fill}}, {{set-cmyk-stroke}}) with a CMYK one; DeviceGray color ({{set-gray-fill}}, {{set-gray-stroke}}) with either; * vector graphics, clipping and graphics states, without transparency: an ExtGState from {{build-ext-gstate}} must keep both alphas at {{1.0}} and the blend mode {{"/Normal"}}; * numbers, strings and {{q}} nesting within the PDF/A-1 limits (real numbers up to 32767 in size, strings up to 65535 bytes, at most 28 nested {{save-graphics-state}} calls). ==== Building and writing documents ===== build-pdfa-document <procedure>(build-pdfa-document [COMPRESS-STREAMS? [CONFORMANCE]])</procedure> Creates and returns a new, empty PDF/A document, wrapping a new PDF 1.4 {{pdf}} document. {{COMPRESS-STREAMS?}} (default {{#t}}) sets whether streams are compressed; the XMP metadata stream is always stored uncompressed, as PDF/A requires. {{CONFORMANCE}} is {{'pdfa-1b}} (the default) to check the document and claim PDF/A-1b, or {{#f}} for metadata only; any other value is an error. ===== with-pdfa-document-to-file <macro>(with-pdfa-document-to-file (PDFA-DOC DOC [COMPRESS-STREAMS? [CONFORMANCE]]) FILENAME BODY ...)</macro> Creates a PDF/A document (as {{build-pdfa-document}}), binds {{PDFA-DOC}} to it and {{DOC}} to its wrapped {{pdf}} document, runs {{BODY}}, then writes the finished document to {{FILENAME}} with {{write-pdfa-document}}. Use {{PDFA-DOC}} for metadata and the output intent, and {{DOC}} for fonts and pages. ===== write-pdfa-document <procedure>(write-pdfa-document PDFA-DOC FILENAME)</procedure> Finishes {{PDFA-DOC}} with {{finalize-document-metadata!}} and writes it to {{FILENAME}}, with the binary header comment and the trailer {{/Info}} and {{/ID}} entries. In conformance mode, a document that fails the checks raises an error and no file is written. Call it once, after all pages have been added. ===== pdfa-document? <procedure>(pdfa-document? X)</procedure> Tests whether {{X}} is a PDF/A document. ===== pdfa-document-doc <procedure>(pdfa-document-doc PDFA-DOC)</procedure> Returns the {{pdf}} document wrapped by {{PDFA-DOC}}. ===== pdfa-document-conformance <procedure>(pdfa-document-conformance PDFA-DOC)</procedure> Returns {{PDFA-DOC}}'s conformance mode: {{'pdfa-1b}} or {{#f}}. ==== Metadata and output intent ===== set-document-info! <procedure>(set-document-info! PDFA-DOC #!key TITLE AUTHOR SUBJECT KEYWORDS CREATOR)</procedure> Records the document's descriptive properties, all strings. {{CREATOR}} is the name of the application that produced the content; the producer is always recorded as this egg. The values are written twice, as the {{/Info}} dictionary and as the XMP packet, and PDF/A requires the two copies to agree, so: * fields given as {{#f}} or {{""}} are left out of both; * non-ASCII text is allowed: {{/Info}} values are written as UTF-16 and the XMP packet as UTF-8; * a value that is not a string, or that contains a control character other than tab, line feed or carriage return, is an error, since XML cannot represent such characters. The creation date is set automatically when the document is written. ===== set-output-intent! <procedure>(set-output-intent! PDFA-DOC ICC-PATH #!key (N 3) (CONDITION-IDENTIFIER "sRGB") (INFO "sRGB IEC61966-2.1"))</procedure> Sets the document's output intent: the ICC color profile in the file {{ICC-PATH}}, which defines what the document's colors mean. {{N}} is the profile's number of color components (3 for RGB, 4 for CMYK, 1 for gray). {{CONDITION-IDENTIFIER}} names the output condition and {{INFO}} describes it. PDF/A-1 needs a monitor or printer profile, in RGB, CMYK or gray, with a version below 4. Most Linux systems have a suitable sRGB profile at {{/usr/share/color/icc/sRGB.icc}}. In conformance mode the profile's header is checked straight away (see {{icc-profile-problems}}), and an unsuitable profile raises an error here. ===== icc-profile-problems <procedure>(icc-profile-problems BYTEVECTOR N)</procedure> Checks the header of the ICC profile in {{BYTEVECTOR}} for use as a PDF/A-1 output intent with {{N}} color components. Returns a list of strings describing each problem, or {{'()}} if there are none. The checks are: the declared size matches the data; the device class is a monitor or printer profile; the color space is RGB, CMYK or gray, and matches {{N}}; and the major version is below 4. ==== Conformance checks ===== check-pdfa-conformance <procedure>(check-pdfa-conformance PDFA-DOC)</procedure> Checks {{PDFA-DOC}} against the PDF/A-1b rules a document built with {{pdf}} can break, and returns the list of violations found, or {{'()}} if it conforms. It checks the output intent, every font, every ExtGState resource, and every page's content stream. It does not change the document, so it can be called at any time, for example to report problems without raising an error. {{write-pdfa-document}} calls it automatically in conformance mode. ===== pdfa-violation? <procedure>(pdfa-violation? X)</procedure> Tests whether {{X}} is a violation returned by {{check-pdfa-conformance}}. ===== pdfa-violation-kind <procedure>(pdfa-violation-kind VIOLATION)</procedure> Returns the kind of {{VIOLATION}}, as one of these symbols (clause numbers refer to ISO 19005-1:2005): ; {{missing-output-intent}} : the document has no output intent (6.2.2) ; {{icc-profile-invalid}} : the output intent's ICC profile is unsuitable (6.2.2) ; {{unembedded-font}} : a font is not embedded, such as one from {{build-font}} (6.3.4) ; {{restricted-font-license}} : an embedded font's licence (OS/2 fsType) does not allow embedding (6.3.4) ; {{colour-space-mismatch}} : a page uses a device color space that does not match the output intent, or uses device color with no output intent (6.2.3.3) ; {{transparency}} : an ExtGState sets an alpha below 1, a blend mode other than normal, or a soft mask (6.4) ; {{limit-exceeded}} : a number, string, name or {{q}} nesting exceeds a PDF/A-1 implementation limit (6.1.12) Each kind is reported at most once per value; for example, using {{set-cmyk-fill}} many times under an RGB intent gives one violation. ===== pdfa-violation->string <procedure>(pdfa-violation->string VIOLATION)</procedure> Describes {{VIOLATION}} in one line of text, naming the font, operator or resource involved and the clause it breaks. ==== Lower-level procedures These are used by {{write-pdfa-document}}, and are exported for programs that assemble the parts themselves. ===== finalize-document-metadata! <procedure>(finalize-document-metadata! PDFA-DOC)</procedure> Adds the {{/Info}} dictionary, XMP metadata stream and output intent to {{PDFA-DOC}}'s wrapped document, and computes its {{/ID}}. In conformance mode it first runs {{check-pdfa-conformance}}, and raises an error listing every violation before changing anything. Call it once, after all pages are added and before writing. ===== info-trailer-fragment <procedure>(info-trailer-fragment PDFA-DOC)</procedure> Returns the {{/Info}} and {{/ID}} trailer entries for a finalized {{PDFA-DOC}}, as text to pass to {{pdf}}'s {{write-document}} as its {{TRAILER-EXTRA}} argument. ===== pdf-text-string <procedure>(pdf-text-string STRING)</procedure> Encodes {{STRING}} as a PDF text string: printable ASCII text as an escaped literal string such as {{"(A Report)"}}, and any other text as a UTF-16BE hex string with a byte-order mark, such as {{"<FEFF...>"}}. ===== build-xmp-packet <procedure>(build-xmp-packet #!key TITLE AUTHOR SUBJECT KEYWORDS PRODUCER CREATOR-TOOL CREATE-DATE PDFA-PART PDFA-CONFORMANCE)</procedure> Returns an XMP metadata packet as a string. Fields given as {{#f}} or {{""}} are left out. When {{PDFA-PART}} and {{PDFA-CONFORMANCE}} are both given (for PDF/A-1b, {{"1"}} and {{"B"}}), the packet includes the PDF/A identification fields, which claim conformance. ===== pdf-date-string <procedure>(pdf-date-string SECONDS)</procedure> <procedure>(xmp-date-string SECONDS)</procedure> Format a Unix time (as from {{current-seconds}}) in UTC, as a PDF date string ({{"D:20261018120000Z"}}) or an XMP date string ({{"2026-10-18T12:00:00Z"}}). ===== md5-hex <procedure>(md5-hex STRING)</procedure> Returns the MD5 digest of {{STRING}} as 32 lowercase hex digits; used for the trailer {{/ID}}. ==== Validating the result The conformance checks cover what a document built with {{pdf}} can do wrong, but they are not a full PDF/A validator. To confirm that a file conforms, check it with [[https://verapdf.org|veraPDF]], the reference PDF/A validator: verapdf --flavour 1b document.pdf The egg's source includes {{tests/verapdf-check.sh}}, which writes a set of test documents and validates each one with veraPDF. === Examples A one-page report. The source distribution's {{pdfa-examples.scm}} has a longer version, with wrapped text and a bar chart. <enscript highlight="scheme"> (import scheme (chicken base) pdf pdfa pdf-truetype) (define font-file "/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf") (define icc-profile "/usr/share/color/icc/sRGB.icc") (with-pdfa-document-to-file (pdfa-doc doc) "report.pdf" ;; metadata, stored as both /Info and XMP (set-document-info! pdfa-doc title: "Quarterly report \x2014; caf\xe9; division" author: "Example Author") ;; the colour profile every color in the file refers to (set-output-intent! pdfa-doc icc-profile) ;; fonts must be embedded (let ((font (build-embedded-font doc font-file))) (with-page doc (page) (set-gray-fill page 0) (in-text-mode page (set-font page (embedded-font-name font) 24) (move-text page 72 700) (draw-encoded-text page font "Quarterly report")) (in-text-mode page (set-font page (embedded-font-name font) 12) (move-text page 72 670) (draw-encoded-text page font "Sales rose to \x20ac;1.2 million.")) ;; RGB color is allowed, because the output intent is RGB (set-rgb-fill page 0.16 0.38 0.62) (basic-rect page 72 500 300 100) (fill-path page)))) </enscript> Finding out why a document does not conform: <enscript highlight="scheme"> (import scheme (chicken base) pdf pdfa) (let* ((pdfa-doc (build-pdfa-document)) (doc (pdfa-document-doc pdfa-doc)) (helvetica (build-font doc "Helvetica"))) ; not embedded ;; no output intent (with-page doc (page) (set-cmyk-fill page 0 0.8 0.8 0) ; device color (in-text-mode page (set-font page (font-name helvetica) 12) (move-text page 72 700) (draw-text page "Not PDF/A"))) (for-each (lambda (v) (print (pdfa-violation->string v))) (check-pdfa-conformance pdfa-doc))) </enscript> This prints: no output intent: call set-output-intent! with an ICC profile (6.2.2) font /CLF101 (/Helvetica) is not embedded; use build-embedded-font from pdf-truetype (6.3.4) content stream operator k sets a device color, which needs an output intent (6.2.3.3) === Author [[/users/ivan-raikov|Ivan Raikov]] === License Copyright (c) 2026, Ivan Raikov Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. === Repository [[https://github.com/iraikov/chicken-pdfa|https://github.com/iraikov/chicken-pdfa]] === Version history ; 1.0 : Initial release: PDF/A-1b metadata, output intents and conformance checks
Description of your changes:
I would like to authenticate
Authentication
Username:
Password:
Spam control
What do you get when you add 15 to 9?