summaryrefslogtreecommitdiff
path: root/macros/luatex/generic/minim-pdf
diff options
context:
space:
mode:
Diffstat (limited to 'macros/luatex/generic/minim-pdf')
-rw-r--r--macros/luatex/generic/minim-pdf/README16
-rw-r--r--macros/luatex/generic/minim-pdf/minim-pdf.doc99
-rw-r--r--macros/luatex/generic/minim-pdf/minim-pdf.lua135
-rw-r--r--macros/luatex/generic/minim-pdf/minim-pdf.pdfbin116670 -> 126824 bytes
-rw-r--r--macros/luatex/generic/minim-pdf/minim-pdf.tex53
5 files changed, 244 insertions, 59 deletions
diff --git a/macros/luatex/generic/minim-pdf/README b/macros/luatex/generic/minim-pdf/README
index eb9a1bd114..0626208f2f 100644
--- a/macros/luatex/generic/minim-pdf/README
+++ b/macros/luatex/generic/minim-pdf/README
@@ -1,4 +1,4 @@
-Version: 2023/1.3
+Version: 2024/1.4
SUMMARY
@@ -27,6 +27,20 @@ In order to obtain the typeset manual of this package, simply say:
HISTORY
+2024/1.4 (5/1/2024)
+
+ Breaking changes:
+
+ * Table cells and headers now connect automatically in \automarktable
+
+ New features:
+
+ * Add support for pdf/ua
+ * Re-write \hyperlink, adding many options
+ * Add ref and title options to structure elements
+ * New helper macros for footnotes
+ * Add \withpdfresource
+
2023/1.3 (20/10/2023)
New features:
diff --git a/macros/luatex/generic/minim-pdf/minim-pdf.doc b/macros/luatex/generic/minim-pdf/minim-pdf.doc
index e04deb31ab..111d8c1423 100644
--- a/macros/luatex/generic/minim-pdf/minim-pdf.doc
+++ b/macros/luatex/generic/minim-pdf/minim-pdf.doc
@@ -3,7 +3,7 @@
\manual{minim-pdf}
-\ifchapter \chapter Hypertext
+\ifchapter \chapter Advanced PDF features
This chapter and the next document the support of the modern pdf features
provided by the minim-pdf package.
@@ -14,8 +14,8 @@ all other features of the package are described here.
\else \startmetadata
author {Esger Renkema}
title {minim-pdf}
- date {2023-10-20}
- version {2023/1.3}
+ date {2024-01-05}
+ version {2024/1.4}
keywords {LuaTeX; Plain TeX; PDF/A; Tagged PDF; accessibility; a11y;
hypertext; bookmarks; document outline; associated files}
stopmetadata
@@ -33,10 +33,16 @@ all other features will be covered first.
\section Hyperlinks % 1
-For most simple cases, you can use
-⟦*\hyperlink [name {...} | url {...}] ... \endlink⟧ for linking to a named
-destination in your own document or to an external hyperlink respectively.
-There is no support for nonsimple cases.
+Hyperlinks can be made with
+⟦*\hyperlink [alt {...}] [attr {...}] <action> ... \endlink⟧, where the
+⟦<action>⟧ must be one of
+⟦name {...} | url {...} | name {...} | next | prev | first | last⟧
+With the ⟦name⟧ action, a named destination must be used (see below), while the
+⟦user⟧ action will be passed directly to the back-end (as with the pdftex
+primitive).
+The ⟦*\hyperlinkstyle⟧ token list can be used so set common (pdf) link
+attributes; it defaults to ⟦/Border [0 0 0]⟧. The contents of the optional
+⟦attr⟧ parameter will be appended to these.
A named destination can be created with ⟦*\nameddestination {...}⟧ (also in
horizontal mode, unlike the backend primitive) and if you cannot think of
@@ -47,9 +53,10 @@ generated name.
\section Bookmarks % 1
-Bookmarks can be added with ⟦*\outline [open|closed] [dest {name}] {title}⟧.
-Add ⟦open⟧ or ⟦closed⟧ to have the bookmark appear initially open or
-closed (default), and
+Bookmarks (also known as outlines) can be added with ⟦*\outline [open|closed]
+[dest {name}] {title}⟧.
+Add ⟦open⟧ or ⟦closed⟧ to have the bookmark appear initially open or closed
+(default), and
say ⟦dest {name}⟧ for having it refer to a specific named destination
(otherwise, a new one will be created where the ⟦\outline⟧ command appears).
@@ -101,6 +108,48 @@ are enabled by default.
You can disable them by setting ⟦*\writehyphensandspaces⟧ to a nonpositive value.
+\section PDF/UA % 1
+
+You can claim pdf/ua conformance with ⟦*\pdfualevel 1⟧.
+By itself, this will do very little:
+
+\startlist
+\tagattribute List ListNumbering /Decimal
+\item 1. The ⟦pdfuaid:part⟧ metadata key will be set.
+\item 2. A conforming ⟦ViewerPreferences⟧ dictionary will be added to the document catalog.
+\item 3. The ⟦/Suspects⟧ key of the ⟦MarkInfo⟧ dictionary will be set to ⟦false⟧.
+\item 4. ⟦/Tab /S⟧ will be added to the page attributes.
+\stoplist
+
+Also making your document pdf/a-compliant, however, will relieve you of a few
+additional worries:
+
+\startlist
+\tagattribute List ListNumbering /Decimal
+\tagattribute List ContinuedList true
+\item 5. Fonts will be included properly.
+\item 6. The (natural) language of every element will be known.
+\item 7. Headings will be strongly-structured.
+\item 8. Table headers will have their ⟦Scope⟧ set properly.
+\item 9. A document outline will be generated automatically.
+\stoplist
+
+This leaves the following for you to provide before your document can be
+pdf/ua-compliant:
+
+\startlist
+\tagattribute List ListNumbering /Decimal
+\tagattribute List ContinuedList true
+\item 10. Figure and Formula structure elements must have alt texts.
+\item 11. Hyperlinks must have alternate descriptions.
+\item 12. Lists must have the ⟦ListNumbering⟧ attribute set.
+\item 13. Tables must have headers that are tagged as such.
+\item 14. Page headers and footers must be marked as header or footer artifacts.
+\item 15. Document section structure elements should have their ⟦title⟧ set.
+\item 16. All embedded files must have a description.
+\stoplist
+
+
\section Embedded files % 1
You can attach (associate) files with ⟦*\embedfile <options>⟧.
@@ -110,7 +159,9 @@ document catalog.
Arguments consisting of a single word can be given without braces and
exactly one of the options ⟦file⟧ or ⟦string⟧ must be present.
-\smallskip\marktableaslist \halign{#\quad\hfil&#\hfil\cr
+\smallskip\marktableaslist
+\tagattribute List ListNumbering /Description
+\halign{#\quad\hfil&#\hfil\cr
⟦file ⟧\hfill⟦{...}⟧ & The file to embed.\cr
⟦string ⟧\hfill⟦{...}⟧ & The string to embed.\cr
⟦global⟧ & Attach to the document catalog.\cr
@@ -166,6 +217,7 @@ You should always check the result in an external application.
This is the full list of limitations, pitfalls and shortcomings:
\startlist
+\tagattribute List ListNumbering /Decimal
\item1. Document content must be seen by tex in its logical order (although you
can mark out-of-order content explicitly if you know what you are doing; see
below).
@@ -342,9 +394,16 @@ Note that for the ⟦owner⟧ and ⟦key⟧ the initial slash must be omitted; t
⟦value⟧ on the other hand will be written to the pdf verbatim.
Any number of attributes can be added.
-An identifier can be set with the ⟦id⟧ option, or after the fact with
+An identifier can be set with the ⟦id {...}⟧ option, or after the fact with
⟦*\settagid {...}⟧. This identifier will be added to the ⟦IDTree⟧ and is
entirely optional; you will probably already know when you need it.
+The ⟦ref {...}⟧ option lets a structure element refer to another (the ⟦/Ref⟧
+option in the structure element dictionary). Its argument should be the ⟦id⟧ of
+the other structure element.
+
+The title of the structure element (corresponding to the ⟦/T⟧ entry in the
+structure element dictionary) can be set with the ⟦title {...}⟧ option. The
+pdf/ua standard requires this key for all document sections.
Finally, structure element classes can be given with the
⟦class <classname>⟧ keyword, which can be repeated.
@@ -450,12 +509,13 @@ sort (and indeed, no general logic can be given in the latter case). Always proc
with caution when using cells spanning multiple rows, and inspect the resulting
structure carefully.
-Marking a table header (either manually or with ⟦\automarktable⟧) will not
-connect normal cells with their headers; you will have to connect these
-manually by including ⟦*\markcolumnhead⟧ or ⟦*\markrowhead⟧ in the appropriate
-header cells. This must be done \emph{after} ⟦\markcolumnspan⟧ if the latter
-appplies. If properly setup like this, other cells of the table (including
-header cells) will be assigned to matching row or column headers automatically.
+Marking up a table header (except if done through ⟦\automarktable⟧)
+will not connect normal table cells with their headers; you will have to
+connect these manually by including ⟦*\markcolumnhead⟧ or ⟦*\markrowhead⟧ in
+the appropriate header cells. This must be done \emph{after} ⟦\markcolumnspan⟧
+if the latter appplies. If properly setup like this, other cells of the table
+(including header cells) will be assigned to matching row or column headers
+automatically.
\section Other helper macros % 1
@@ -465,6 +525,9 @@ For marking up an entry in a table of contents, you can use the macro
tags in the correct way. (The ⟦dest⟧ is a link destination and can be empty;
the ⟦lbl⟧ is a section number and can also be empty.)
+For tagging (foot)notes, ⟦*\marknoteref{*}⟧ and ⟦*\marknotelbl{*}⟧, when placed
+around the footnote markers, will insert the proper ⟦Ref⟧, ⟦Note⟧ and ⟦Lbl⟧
+tags.
% 
diff --git a/macros/luatex/generic/minim-pdf/minim-pdf.lua b/macros/luatex/generic/minim-pdf/minim-pdf.lua
index 74d56eeaac..875fd89659 100644
--- a/macros/luatex/generic/minim-pdf/minim-pdf.lua
+++ b/macros/luatex/generic/minim-pdf/minim-pdf.lua
@@ -7,9 +7,11 @@ alloc.remember('minim-pdf')
-- 1 helper functions
+local HLIST_NODE = node.id 'hlist'
local GLUE_NODE = node.id 'glue'
local GLYPH_NODE = node.id 'glyph'
local RULE_NODE = node.id 'rule'
+local DISC_NODE = node.id 'disc'
local WHATSIT_NODE = node.id 'whatsit'
local USER_DEFINED = node.subtype 'user_defined'
local START_LINK = node.subtype 'pdf_start_link'
@@ -51,9 +53,8 @@ local function singleton(t)
return one
end
--- in-depth node list traversal
--- returns current and parent node
--- only dives into hbox, vbox and ins nodes
+-- in-depth node list traversal; returns current and parent node
+-- only dives into hbox, vbox and ins nodes, and in disc no-break text
-- returns node and enclosing box
local function full_traverse(head)
return function(stack, last)
@@ -178,7 +179,7 @@ local structure_types = alloc.saved_table('structure types', {
-- inline structure elements ILSE
Span = { type = 'inline' },
Quote = { type = 'inline' },
- Note = { type = 'inline' },
+ Note = { type = 'extern' },
Reference = { type = 'inline' },
BibEntry = { type = 'inline' },
Code = { type = 'inline', attributes = { ['CSS-2.00'] = { ['white-space'] = '(pre)' } } },
@@ -198,9 +199,10 @@ local structure_type_compatibility = {
none = { none=1, section=1, group=1, block=1, inline=1, contain=1 },
section = { none=1, section=1, group=1, block=1 },
group = { none=1, group=1, block=1 },
- block = { none=1, inline=1 },
- inline = { none=1, inline=1 },
- contain = { none=1, inline=1, block=1, group=1 },
+ extern = { none=1, group=1, block=1 },
+ block = { none=1, inline=1, extern=1 },
+ inline = { none=1, inline=1, extern=1 },
+ contain = { none=1, inline=1, block=1, group=1, extern=1 },
}
local function check_structure_compatibility(parent, child, childtype)
@@ -354,10 +356,19 @@ local function write_structure()
local id_tree, id_tree_obj = { }, pdf.reserveobj()
structure[1].parent = { objnum = root_obj }
for _, se in ipairs(structure) do
- if not se.hidden then se.objnum = pdf.reserveobj() end
+ if not se.hidden then
+ se.objnum = pdf.reserveobj()
+ if se.id then
+ id_tree[se.id] = se.objnum
+ end
+ end
end
-- update the document catalog
- add_to_catalog('/MarkInfo << /Marked true >>')
+ if tex.count['pdfuaconformancelevel'] > 0 then
+ add_to_catalog('/MarkInfo << /Marked true /Suspects false >>')
+ else
+ add_to_catalog('/MarkInfo << /Marked true >>')
+ end
add_to_catalog('/StructTreeRoot %s 0 R', root_obj)
-- write the structure tree root
pdf.immediateobj(root_obj, string.format(
@@ -368,10 +379,11 @@ local function write_structure()
if not se.hidden then
local res = { '<<' }
insert_formatted(res, '/Type/StructElem /S%s /P %d 0 R', pdf_name(se.struct), se.parent.objnum)
- if se.id then id_tree[se.id] = se.objnum; insert_formatted(res, '/ID %s', pdf_string(se.id)) end
- if se.lang and se.lang ~= se.parent.lang then insert_formatted(res, '/Lang (%s)', se.lang) end
+ if se.id then insert_formatted(res, '/ID %s', pdf_string(se.id)) end
+ if se.lang and se.lang ~= se.parent.lang then insert_formatted(res, '/Lang %s', pdf_string(se.lang)) end
if se.alt then insert_formatted(res, '/Alt %s', pdf_string(se.alt)) end
if se.actual then insert_formatted(res, '/ActualText %s', pdf_string(se.actual)) end
+ if se.title then insert_formatted(res, '/T %s', pdf_string(se.title)) end
if #se.children > 0 then insert_formatted(res, '\n/K %s', format_K_array(se)) end
if se.mainpage then insert_formatted(res, '/Pg %d 0 R', se.mainpage) end
if se.class then
@@ -382,6 +394,19 @@ local function write_structure()
end
if #se.class > 1 then table.insert(res, ']') end
end
+ if se.ref then
+ table.insert(res, '/Ref')
+ table.insert(res, '[')
+ for _, c in ipairs(se.ref) do
+ local onum = id_tree[c]
+ if onum then
+ insert_formatted(res, '%d 0 R', onum)
+ else
+ alloc.err('Invalid structure element ID: %s', c)
+ end
+ end
+ table.insert(res, ']')
+ end
if not is_empty(se.attributes) then
table.insert(res, '/A')
make_attributes(res, se.attributes)
@@ -481,7 +506,7 @@ cb.register('uselanguage', function(name)
end)
local function write_language()
- add_to_catalog('/Lang (%s)', structure[1].lang or 'und')
+ add_to_catalog('/Lang %s', pdf_string(structure[1].lang or 'und'))
end
-- 1 marking structure elements
@@ -559,9 +584,11 @@ end
alloc.luadef('tagging:startelement', function()
local s = options_scanner()
:string('id')
+ :string('ref', true)
:string('type') -- 'section', 'group', 'block' etc.
:argument('alt')
:argument('actual')
+ :argument('title')
:string('lang')
:subtable('attr')
:string('class', true)
@@ -736,7 +763,7 @@ function M.mark_content_items(box)
elseif marker and marker.what == 'mci_stop' then
end_node = end_node and n; insert_tags(b)
-- finally, see if we need to intervene between content nodes
- elseif n.id == RULE_NODE or n.id == GLYPH_NODE
+ elseif n.id == RULE_NODE or n.id == GLYPH_NODE or n.id == DISC_NODE
or marker and marker.what == 'content' then
local _se, _order = n[current_struct], n[current_order]
if n.id == RULE_NODE and (n.width == 0 or n.height == 0 and n.depth == 0) then
@@ -768,7 +795,7 @@ cb.register('pre_shipout', function(nr)
end
end)
--- 1 destinations
+-- 1 links and destinations
local dest_count = alloc.new_count('link dest count')
local function new_dest_name()
@@ -791,7 +818,41 @@ end
alloc.luadef('newdestinationname', function() tex.sprint(new_dest_name()) end)
alloc.luadef('lastdestinationname', function() tex.sprint(last_dest_name()) end)
--- 1 bookmarks
+-- provide the arguments to \pdfextension startlink
+local link_types = { }
+alloc.luadef('hyper:makelink', function()
+ local s = options_scanner()
+ :argument('alt'):argument('contents') -- same thing
+ :argument('attr')
+ :scan()
+ local type = token.scan_word()
+ local userf = link_types[type]
+ if not userf then
+ alloc.err('Unknown hyperlink type: %s', type)
+ userf = link_types.first
+ end
+ local user = userf()
+ attr = { 'attr {\\csname minim:linkattr\\endcsname' }
+ if s.attr then table.insert(attr, s.attr) end
+ if s.alt or s.contents then insert_formatted(attr, '/Contents %s', pdf_string(s.alt or s.contents)) end
+ insert_formatted(attr, '} user {%s}', user)
+ tex.sprint(table.concat(attr, ' '))
+end)
+
+function link_types.dest()
+ return string.format('/Subtype/Link /A <</S/GoTo /D %s>>', pdf_string(token.scan_argument()))
+end
+function link_types.url()
+ return string.format('/Subtype/Link /A <</S/URI /URI %s>>', pdf_string(token.scan_argument()))
+end
+
+function link_types.user() return token.scan_argument() end
+function link_types.next() return '/Subtype/Link /A <</S/Named /N/NextPage>>' end
+function link_types.prev() return '/Subtype/Link /A <</S/Named /N/PrevPage>>' end
+function link_types.first() return '/Subtype/Link /A <</S/Named /N/FirstPage>>' end
+function link_types.last() return '/Subtype/Link /A <</S/Named /N/LastPage>>' end
+
+-- 1 bookmarks (outlines)
-- start with a dummy top-level bookmark
local bookmarks = { { count = 0 } }
@@ -811,8 +872,8 @@ local function write_bookmarks()
-- write bookmark objects
for i=2, #bookmarks do
local bm, res = bookmarks[i], { }
- insert_formatted(res, '<< /Title %s\n/Parent %s 0 R /Dest (%s)', pdf_string(bm.title),
- bm.parent and bm.parent.outline_obj or bookmarks[1].outline_obj, bm.dest)
+ insert_formatted(res, '<< /Title %s\n/Parent %s 0 R /Dest %s', pdf_string(bm.title),
+ bm.parent and bm.parent.outline_obj or bookmarks[1].outline_obj, pdf_string(bm.dest))
if bm.next then insert_formatted(res, '/Next %s 0 R', bm.next.outline_obj) end
if bm.prev then insert_formatted(res, '/Prev %s 0 R', bm.prev.outline_obj) end
if bm.struct and bm.struct.objnum then
@@ -945,13 +1006,13 @@ end, 'protected')
function M.mark_discretionaries(head, gc)
if not spaces_enabled() then return end
- for disc in node.traverse_id(7, head) do
+ for disc in node.traverse_id(DISC_NODE, head) do
if disc.subtype ~= 2 then -- ‘automatic’ (exclude explicit hyphens)
local pre, post, replace = disc.pre, disc.post, disc.replace
local se, order = disc[current_struct], disc[current_order]
-- get the replacement text
local actual = { }
- for c in node.traverse_id(29, replace) do
+ for c in node.traverse_id(GLYPH_NODE, replace) do
table.insert(actual, c.char)
end
-- special case: a single hyphen
@@ -982,7 +1043,7 @@ local space_attr = alloc.new_attribute('space insertion marker')
function M.mark_spaces(head, gc)
if not spaces_enabled() then return end
- for g in node.traverse_id(12, head) do -- glue
+ for g in node.traverse_id(GLUE_NODE, head) do
if g.prev and g.subtype == 13 or g.subtype == 14 then -- (x)spaceskip
local p = g.prev
p[space_attr] = p.id == GLYPH_NODE and p.font
@@ -1011,7 +1072,7 @@ end
function M.insert_spaces(head, gc)
if not spaces_enabled() then return end
- for line in node.traverse_id(0, head) do
+ for line in node.traverse_id(HLIST_NODE, head) do
insert_spaces(line.head)
end
return true
@@ -1085,10 +1146,10 @@ local function write_output_intents()
attr = string.format('/N %d', oi.N),
immediate = true }
insert_formatted(res, '<< /Type/OutputIntent /DestOutputProfile %d 0 R', p)
- insert_formatted(res, '/S/%s /OutputConditionIdentifier (%s)', oi.subtype, oi.id)
- if oi.info then insert_formatted(res, '/Info (%s)', oi.info) end
- if oi.condition then insert_formatted(res, '/OutputCondition (%s)', oi.condition) end
- if oi.registry then insert_formatted(res, '/RegistryName (%s)', oi.registry) end
+ insert_formatted(res, '/S/%s /OutputConditionIdentifier %s', oi.subtype, pdf_string(oi.id))
+ if oi.info then insert_formatted(res, '/Info %s', pdf_string(oi.info)) end
+ if oi.condition then insert_formatted(res, '/OutputCondition %s', pdf_string(oi.condition)) end
+ if oi.registry then insert_formatted(res, '/RegistryName %s', pdf_string(oi.registry)) end
table.insert(res, '>>')
end
table.insert(res, ']')
@@ -1121,9 +1182,31 @@ end
alloc.luadef('minim:default:rgb:profile', function() M.add_default_rgb_output_intent() end)
alloc.luadef('minim:default:cmyk:profile', function() M.add_default_cmyk_output_intent() end)
+-- 1 pdf/ua
+
+alloc.luadef('tagging:enablepdfua', function()
+ add_to_catalog('/ViewerPreferences << /DisplayDocTitle true >>')
+ local pageattr = pdf.getpageattributes()
+ if pageattr then
+ pdf.setpageattributes(pageattr .. ' /Tabs /S')
+ else
+ pdf.setpageattributes('/Tabs /S')
+ end
+end)
+
+local function perform_pdfua_checks()
+ local xmp = require 'minim-xmp'
+ if xmp.get_metadata('dc:title') == '' then
+ alloc.err('PDF/UA error: no dc:title metadata')
+ end
+end
+
--
-cb.register ('finish_pdffile', function()
+cb.register('finish_pdffile', function()
+ if tex.count['pdfuaconformancelevel'] > 0 then
+ perform_pdfua_checks()
+ end
if tagging_enabled() then
write_language()
write_structure()
diff --git a/macros/luatex/generic/minim-pdf/minim-pdf.pdf b/macros/luatex/generic/minim-pdf/minim-pdf.pdf
index a6e22ee194..2b2ea69c42 100644
--- a/macros/luatex/generic/minim-pdf/minim-pdf.pdf
+++ b/macros/luatex/generic/minim-pdf/minim-pdf.pdf
Binary files differ
diff --git a/macros/luatex/generic/minim-pdf/minim-pdf.tex b/macros/luatex/generic/minim-pdf/minim-pdf.tex
index d8b06255ba..8a5f738063 100644
--- a/macros/luatex/generic/minim-pdf/minim-pdf.tex
+++ b/macros/luatex/generic/minim-pdf/minim-pdf.tex
@@ -167,8 +167,8 @@
\newcount\tagging:tablecolspan \tagging:tablecolspan 1
\newcount\tagging:tablerowspan \tagging:tablerowspan 1
\newcount\tagging:i
-\def\tagging:TH{TH}
-\def\tagging:TD{TD}
+\def\tagging:TH{{TH}\markcolumnhead}
+\def\tagging:TD{{TD}}
% initialising variables
\def\marktable{\startelement{Table}%
\global\advance\tagging:tablec1
@@ -205,7 +205,7 @@
\def\marktablecell{%
\global\advance\tagging:tablecol1
\continueelementfrom\tagging:row
- \startelement{\tagging:cell}%
+ \expandafter\startelement\tagging:cell%
\tagging:assignheaders}
% spans
@@ -301,13 +301,27 @@
\def\marktocentry#1#2#3#4#5{%
\ifx\marktocentry#1\marktocentry
\def\marktocentry:link##1{##1}\else
- \def\marktocentry:link##1{\hyperlink dest{#1}##1\endlink}\fi
+ \def\marktocentry:link##1{\hyperlink
+ alt{\csname minim:str:page\endcsname#5}
+ dest{#1}##1\endlink}\fi
\markelement{TOCI}{\nextpartag{}\quitvmode
\ifx\marktocentry#2\marktocentry\else
\markelement{Lbl}{\marktocentry:link{#2}}\fi
\markelement{Reference}{\marktocentry:link{#3%
\ifx\marktocentry#4\marktocentry\else
\markartifact{Layout}{#4}\fi#5}}}}
+\def\minim:str:page{Page }
+
+% \marknoteref {*}
+\def\marknoteref#1{%
+ \startelement ref{\newdestinationname}{Reference}%
+ {\stopformulatagging#1}\stopelement{Reference}}
+% \marknotelbl {*}
+\def\marknotelbl#1{%
+ \startelement id{\lastdestinationname}{Note}%
+ \aftergroup\tagging:ensurestopNote
+ \markelement{Lbl}{{\stopformulatagging#1}}}
+\def\tagging:ensurestopNote{\ensurestopelement{Note}}
% 1 tagging formulas
@@ -351,7 +365,7 @@
\def\formulasource:set#1{%
\begingroup
% strip \setalttext, \setactualtext
- \def\setalttext#1{}\def\setactualtext#1{}%
+ \def\setalttext##1{}\def\setactualtext##1{}%
\xdef\formulasource:thesource{#1}%
\endgroup
\expandafter\splitcommalist
@@ -370,6 +384,7 @@
relation Source desc {Equation source}
name {\formulafilename.tex}
string {\tagging:formulasource{#1}}\fi}
+\def\formulasource:none#1{}
\newtoks\includeformulasources
\includeformulasources{actualtext,attachment}
@@ -390,17 +405,18 @@
\def\linkdest:h#1{\vadjust pre{\linkdest:v{#1}}}
\def\linkdest:v#1{\pdfextension dest name {#1} xyz\nobreak}
-% \hyperlink dest {name} ... \endlink
-% \hyperlink url {url} ... \endlink
+% \hyperlink <args> ... \endlink
+% args: alt {...} attr {...} <type>
+% type: dest {name} | url {url} | next | prev | first | last
\protected\def\endlink{\pdfextension endlink\stopelement{Link}\relax}
\protected\def\startlink{\startelement{Link}\pdfextension startlink}
-\def\hyperlink#1#{\quitvmode\hyperlink:rmspace#1 \hyperlink:rmspace}
-\def\hyperlink:rmspace#1 #2\hyperlink:rmspace{%
- \startlink attr {\minim:linkattr}%
- \csname hyperlink:#1\endcsname}
-\def\hyperlink:dest#1{user {/Subtype/Link /F 4 /A <</S/GoTo /D (#1)>>}}
-\def\hyperlink:url#1{user {/Subtype/Link /F 4 /A <</S/URI /URI (#1)>>}}
-\def\minim:linkattr{/Border [0 0 0]}
+\protected\def\hyperlink{\quitvmode\startlink\hyper:makelink}
+
+% \hyperlinkstyle { ... }
+\def\minim:linkattr{\the\hyperlinkstyle\the\minim:pdfalinkattr}
+\newtoks\hyperlinkstyle
+\newtoks\minim:pdfalinkattr
+\hyperlinkstyle{/Border [0 0 0]}
% 1 languages
@@ -449,9 +465,12 @@
\newcount \pdfaconformancelevel
\pdfaconformancelevel = 0
+\newcount \pdfuaconformancelevel
+\pdfuaconformancelevel = 0
% \pdfalevel 2b
\def\pdfalevel#1#2{%
+ \minim:pdfalinkattr{ /F 4}% hyperlinks must be printed
\global\pdfaconformancelevel=#1\relax
\ifcsname minim:pdfa:#1#2\endcsname \lastnamedcs\else
\errmessage{Unknown pdf/a standard pdf/a-#1}\fi}
@@ -474,6 +493,12 @@
\expandafter\def\csname minim:pdfa:3b\endcsname{\minim:pdfasettings 7B3}
\expandafter\def\csname minim:pdfa:3u\endcsname{\minim:pdfasettings 7U3}
+% \pdfualavel 1
+\def\pdfualevel{\input minim-xmp
+ \setmetadata pdfuaid:part {1}
+ \tagging:enablepdfua
+ \global\pdfuaconformancelevel= }
+
% 
\catcode`\: = \minimpdfloaded