From 9b017f7c7cf391a061f2ca361eb6a970fe7fce69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Chudy?= Date: Thu, 28 May 2026 11:09:16 +0200 Subject: [PATCH 1/2] fix: table scope --- lib/structure_element.js | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/lib/structure_element.js b/lib/structure_element.js index 01644379..a771c74d 100644 --- a/lib/structure_element.js +++ b/lib/structure_element.js @@ -41,12 +41,12 @@ class PDFStructureElement { data.ActualText = new String(options.actual); } if ( - typeof options.bbox !== 'undefined' || - typeof options.placement !== 'undefined' + typeof options.bbox !== 'undefined' || + typeof options.placement !== 'undefined' ) { const attrs = { O: 'Layout' }; attrs.Placement = - typeof options.placement !== 'undefined' ? options.placement : 'Block'; + typeof options.placement !== 'undefined' ? options.placement : 'Block'; if (typeof options.bbox !== 'undefined') { const height = this.document.page.height; attrs.BBox = [ @@ -59,6 +59,14 @@ class PDFStructureElement { data.A = attrs; } + if (typeof options.scope !== 'undefined') { + data.A = { + ...(data.A || {}), + O: 'Table', + Scope: options.scope, + }; + } + this._children = []; if (children) { @@ -107,8 +115,8 @@ class PDFStructureElement { _addContentToParentTree(content) { content.refs.forEach(({ pageRef, mcid }) => { const pageStructParents = this.document - .getStructParentTree() - .get(pageRef.data.StructParents); + .getStructParentTree() + .get(pageRef.data.StructParents); pageStructParents[mcid] = this.dictionary; }); } @@ -157,8 +165,8 @@ class PDFStructureElement { } this._children - .filter((child) => child instanceof PDFStructureElement) - .forEach((child) => child.end()); + .filter((child) => child instanceof PDFStructureElement) + .forEach((child) => child.end()); this._ended = true; @@ -167,10 +175,10 @@ class PDFStructureElement { _isValidChild(child) { return ( - child instanceof PDFStructureElement || - child instanceof PDFStructureContent || - child instanceof PDFAnnotationReference || - typeof child === 'function' + child instanceof PDFStructureElement || + child instanceof PDFStructureContent || + child instanceof PDFAnnotationReference || + typeof child === 'function' ); } From ee1bb995da86037fca5ea665ff0915dbcd0358ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Chudy?= Date: Fri, 29 May 2026 08:32:21 +0200 Subject: [PATCH 2/2] fix: unit tests & changelog --- CHANGELOG.md | 4 ++++ lib/structure_element.js | 22 +++++++++++----------- package.json | 2 +- tests/unit/structure_element.spec.js | 28 ++++++++++++++++++++++++++++ 4 files changed, 44 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 635e1112..1eafca26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ - Add bbox and placement options to PDFStructureElement for PDF/UA compliance - Extend `roundedRect` with `borderRadius` as number for all corners or per-corner array (CSS order) +### [v0.18.1] - 2026-05-29 + +- Fix accessibility: scope in TH element +- ### [v0.18.0] - 2026-03-14 - Fix garbled text copying in Chrome/Edge for PDFs with >256 unique characters (#1659) diff --git a/lib/structure_element.js b/lib/structure_element.js index a771c74d..3db9cd4b 100644 --- a/lib/structure_element.js +++ b/lib/structure_element.js @@ -41,12 +41,12 @@ class PDFStructureElement { data.ActualText = new String(options.actual); } if ( - typeof options.bbox !== 'undefined' || - typeof options.placement !== 'undefined' + typeof options.bbox !== 'undefined' || + typeof options.placement !== 'undefined' ) { const attrs = { O: 'Layout' }; attrs.Placement = - typeof options.placement !== 'undefined' ? options.placement : 'Block'; + typeof options.placement !== 'undefined' ? options.placement : 'Block'; if (typeof options.bbox !== 'undefined') { const height = this.document.page.height; attrs.BBox = [ @@ -115,8 +115,8 @@ class PDFStructureElement { _addContentToParentTree(content) { content.refs.forEach(({ pageRef, mcid }) => { const pageStructParents = this.document - .getStructParentTree() - .get(pageRef.data.StructParents); + .getStructParentTree() + .get(pageRef.data.StructParents); pageStructParents[mcid] = this.dictionary; }); } @@ -165,8 +165,8 @@ class PDFStructureElement { } this._children - .filter((child) => child instanceof PDFStructureElement) - .forEach((child) => child.end()); + .filter((child) => child instanceof PDFStructureElement) + .forEach((child) => child.end()); this._ended = true; @@ -175,10 +175,10 @@ class PDFStructureElement { _isValidChild(child) { return ( - child instanceof PDFStructureElement || - child instanceof PDFStructureContent || - child instanceof PDFAnnotationReference || - typeof child === 'function' + child instanceof PDFStructureElement || + child instanceof PDFStructureContent || + child instanceof PDFAnnotationReference || + typeof child === 'function' ); } diff --git a/package.json b/package.json index 658eedf3..665cd9c6 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "document", "vector" ], - "version": "0.18.0", + "version": "0.18.1", "homepage": "http://pdfkit.org/", "author": { "name": "Devon Govett", diff --git a/tests/unit/structure_element.spec.js b/tests/unit/structure_element.spec.js index 530ae89a..e2df8e83 100644 --- a/tests/unit/structure_element.spec.js +++ b/tests/unit/structure_element.spec.js @@ -150,5 +150,33 @@ describe('PDFStructureElement', () => { `endobj`, ]); }); + test('should contain scope on TH tag', () => { + const docData = logData(document); + + const table = document.struct('Table'); + + const thead = document.struct('THead'); + + table.add(thead); + + const trHead = document.struct('TR'); + + thead.add(trHead); + + const th1 = document.struct('TH', { scope: 'Column' }); + + th1.add(document.struct('P', () => document.text('Test'))); + + trHead.add(th1); + + document.addStructure(table); + + document.end(); + + expect(docData).toContainChunk([ + '<<\n/S /TH\n/A <<\n/O /Table\n/Scope /Column\n>>\n/P 10 0 R\n/K [12 0 R]\n>>', + `endobj`, + ]); + }) }); });