diff --git a/docs/accessibility.md b/docs/accessibility.md index fab9eea..47aaf74 100644 --- a/docs/accessibility.md +++ b/docs/accessibility.md @@ -15,9 +15,11 @@ This checklist covers everything that is required to create a conformant Tagged details). * Pass the option `tagged: true` when creating your `PDFDocument` (technically, this sets the `Marked` property in the `Markings` dictionary to `true` in the PDF). + * Specify natural language in the document options and/or logical structure and/or + non-structure marked `Span` content. * Add logical structure with all significant content included. * Include accessibility information (such as alternative text, actual text, etc.) in the - logical structure. + logical structure and/or non-structure marked `Span` content. * Include all spaces which separate words/sentences/etc. in your marked structure content, even at the ends of lines, paragraphs, etc.. I.e. don't do `doc.text("Hello, world!")` but instead do `doc.text("Hello, world! ")`. @@ -53,6 +55,17 @@ When marking content, you can provide options (take care to use correct capitali coordinates * `attached` - used for `Pagination` artifact content, array of one or more strings: `Top`, `Bottom`, `Left`, `Right` + * `lang` - used for `Span` content: human language code (e.g. `en-AU`) which overrides default + document language, and any enclosing structure element language + * `alt` - used for `Span` content: alternative text for an image or other visual content + * `expanded` - used for `Span` content: the expanded form of an abbreviation or acronym + * `actual` - used for `Span` content: the actual text the content represents (e.g. if it is + rendered as vector graphics) + +It is advisable not to use `Span` content for specifying alternative text, expanded form, or +actual text, especially if there is a possibility of the content automatically wrapping, which +would result in the text appearing twice. Set these options on an associated structure element +instead. ## Logical Structure diff --git a/lib/document.js b/lib/document.js index 7d04fc4..fad0b4c 100644 --- a/lib/document.js +++ b/lib/document.js @@ -74,6 +74,10 @@ class PDFDocument extends stream.Readable { Names }); + if (this.options.lang) { + this._root.data.Lang = new String(this.options.lang); + } + // The current page this.page = null; diff --git a/lib/mixins/markings.js b/lib/mixins/markings.js index 50e4b09..a177fc0 100644 --- a/lib/mixins/markings.js +++ b/lib/mixins/markings.js @@ -57,6 +57,20 @@ export default { dictionary.Attached = options.attached; } } + if (tag === 'Span') { + if (options.lang) { + dictionary.Lang = new String(options.lang); + } + if (options.alt) { + dictionary.Alt = new String(options.alt); + } + if (options.expanded) { + dictionary.E = new String(options.expanded); + } + if (options.actual) { + dictionary.ActualText = new String(options.actual); + } + } this.addContent(`/${tag} ${PDFObject.convert(dictionary)} BDC`); return this; diff --git a/tests/unit/markings.spec.js b/tests/unit/markings.spec.js index 5df2149..abd1238 100644 --- a/tests/unit/markings.spec.js +++ b/tests/unit/markings.spec.js @@ -91,6 +91,13 @@ EMC /Attached [/Top] >> BDC EMC +/Span << +/Lang (en-AU) +/Alt (Hi, earth! ) +/E (Greetings, terrestrial sphere! ) +/ActualText (Hello, world! ) +>> BDC +EMC `, 'binary' ); @@ -101,6 +108,13 @@ EMC attached: [ "Top" ] }); document.endMarkedContent(); + document.markContent("Span", { + lang: "en-AU", + alt: "Hi, earth! ", + actual: "Hello, world! ", + expanded: "Greetings, terrestrial sphere! " + }); + document.endMarkedContent(); document.end(); expect(docData).toContainChunk([ @@ -447,18 +461,24 @@ EMC ]); }); - test('identified as tagged', () => { + test('identified as accessible', () => { document = new PDFDocument({ info: { CreationDate: new Date(Date.UTC(2018, 1, 1)) }, compress: false, pdfVersion: '1.5', - tagged: true + tagged: true, + lang: 'en-AU' }); const docData = logData(document); document.end(); + expect(docData).toContainChunk([ + `3 0 obj`, + /\/Lang \(en-AU\)/, + `endobj` + ]); expect(docData).toContainChunk([ `3 0 obj`, /\/Markings 5 0 R/,