% \iffalse meta-comment % % Copyright (C) 2011-2023 by Scott Pakin % -------------------------------------------------------------- % % This file may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.3c % of this license or (at your option) any later version. % The latest version of this license is in: % % http://www.latex-project.org/lppl.txt % % and version 1.3c or later is part of all distributions of LaTeX % version 2008/05/04 or later. % % \fi % % \iffalse %<*driver> \ProvidesFile{hyperxmp.dtx} % %\NeedsTeXFormat{LaTeX2e}[1999/12/01] %\ProvidesPackage{hyperxmp} %<*package> [2024/03/17 v5.13 Store hyperref metadata in XMP format] % % %<*driver> \bgroup \catcode`\&=11 \gdef\levelchar{&} \egroup \documentclass{ltxdoc} \usepackage[T1]{fontenc} \usepackage[english]{babel} \usepackage{graphicx} \usepackage[cmyk]{xcolor} \usepackage{tocbibind} \usepackage{microtype} \usepackage{needspace} \usepackage{varioref} \usepackage{fancyvrb} \usepackage{multicol} \usepackage{makeidx} \usepackage{mmap} \usepackage{enumitem} \usepackage{listings} \usepackage[labelformat=simple]{subcaption} \renewcommand\thesubfigure{(\alph{subfigure})} \usepackage{array} \usepackage{booktabs} \usepackage{marginfix} \usepackage{ifmtarg} \usepackage{iftex} \input{hyperxmp-stds} \expandafter\ifx\csname wantpdfstandards\endcsname\relax \usepackage{hyperref} \else \usepackage[pdfa]{hyperref} \fi \usepackage{hyperxmp} \EnableCrossrefs \CodelineIndex \RecordChanges % Specify this document's metadata. \GetFileInfo{hyperxmp.dtx} \title{The \pkgname{hyperxmp} package\thanks{This document corresponds to \pkgname{hyperxmp}~\fileversion, dated \filedate.}} \author{Scott Pakin \\ \texttt{scott+hyxmp@pakin.org}} \makeatletter \edef\versionnumber{\expandafter\@gobble\fileversion} % Drop the "v" in the file version. \makeatother \hypersetup{% pdfauthor={Scott Pakin}, pdftitle={The hyperxmp package}, pdfsubject={LaTeX2e support for XMP metadata}, pdfkeywords={LaTeX, embedded metadata, XMP, PDF, copyright, license, comments}, pdfcopyright={Copyright (C) 2011-2023, Scott Pakin}, pdflicenseurl={http://www.latex-project.org/lppl/}, pdfcaptionwriter={Scott Pakin}, pdfcontactemail={scott+hyxmp@pakin.org}, pdfcontacturl={http://www.pakin.org/\xmptilde scott/}, pdfversionid={\versionnumber}, pdflang={en-US}, pdftrapped={False}, pdfstartpage={}, pdfsource={hyperxmp.dtx}, pdfurl={http://mirror.ctan.org/macros/latex/contrib/hyperxmp/hyperxmp.pdf}, baseurl={http://mirror.ctan.org/macros/latex/contrib/hyperxmp/} } % Specify some additional hyperref configuration. \hypersetup{% unicode, bookmarksopen, bookmarksopenlevel=2, bookmarksnumbered } % Redefine \changes to properly sort v5.10 *after* v5.9. \makeatletter \let\orig@changes=\changes \def\discard@suffix#1\relax{} \def\pad@minor@ver v#1.#2\relax{% \afterassignment\discard@suffix \@tempcnta=#2\relax \edef\new@change@ver{% v#1.% \ifnum\@tempcnta<10 0#2 \else #2 \fi }% } \renewcommand{\changes}[2]{% \pad@minor@ver#1\relax \orig@changes{\new@change@ver=#1}{#2}% } \makeatother \begin{document} \DocInput{hyperxmp.dtx} \Needspace{10\baselineskip} \renewcommand*{\glossaryname}{Change History} \PrintChanges \Needspace{12\baselineskip} \PrintIndex \end{document} % % \fi % % \CheckSum{2859} % % \CharacterTable % {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z % Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z % Digits \0\1\2\3\4\5\6\7\8\9 % Exclamation \! Double quote \" Hash (number) \# % Dollar \$ Percent \% Ampersand \& % Acute accent \' Left paren \( Right paren \) % Asterisk \* Plus \+ Comma \, % Minus \- Point \. Solidus \/ % Colon \: Semicolon \; Less than \< % Equals \= Greater than \> Question mark \? % Commercial at \@ Left bracket \[ Backslash \\ % Right bracket \] Circumflex \^ Underscore \_ % Grave accent \` Left brace \{ Vertical bar \| % Right brace \} Tilde \~} % % % \changes{v1.0}{2006/05/14}{Initial version} % \changes{v2.0}{2012/08/02}{Heiko Oberdiek's major rewrite of the code % to better support native-Unicode \string\TeX\ implementations % (\string\XeTeX\ and \string\LuaTeX)} % \changes{v2.0}{2012/08/26}{Added support for the \protect\acro{XMP} Basic % schema and miscellaneous other bits of metadata} % \changes{v1.2}{2010/06/04}{Added support for the \protect\XeTeX\ backend % (\texttt{xdvipdfmx})} % \changes{v1.2}{2010/06/07}{Added support for the Photoshop schema} % \changes{v2.2}{2010/12/06}{Added support for the \protect\acro{IPTC} Photo Metadata schema} % \changes{v2.4}{2013/12/21}{Added support for the \protect\acro{PDF/A} % Identification schema, as requested by Florian Breitwieser} % \changes{v2.5}{2014/06/19}{Enabled ``\texttt{\string\string\string\_}'' % to work within email addresses, as requested by Leonid Sinev} % \changes{v2.6}{2014/09/24}{Added support for a new \protect\optname{pdfdate} % key to explicitly specify the document date (and optionally time)} % \changes{v2.9}{2016/04/25}{Force inclusion of \protect\xmpprop{dc:creator}, % \protect\xmpprop{dc:title}, and \protect\xmpprop{dc:description}---even if % empty---when \protect\pkgname{hyperref} is loaded with the % \protect\optname{pdfa} option (suggested by Leonid Sinev)} % \changes{v2.9}{2016/04/26}{Introduced the \protect\optname{pdftype} % package option, which enables an author to specify the type of % document being produced} % \changes{v3.0}{2016/07/02}{Made the code compatible with \string\LuaTeX~0.85. % Thanks to Robert Schlicht, Leonid Sinev, and David Carlisle for bug % reports and to Leonid Sinev for helping test the new % \protect\pkgname{hyperxmp} code} % \changes{v3.4}{2017/11/04}{Use \protect\pkgname{ifmtarg} to test for % empty arguments, including non-empty but all spaces} % \changes{v4.0}{2019/03/14}{Include all metadata within a single % \protect\xmpterm{rdf:Description} block} % \changes{v4.1}{2019/04/05}{Updated the documentation to refer to % \protect\cs{pdfnumpages} by its correct name. Thanks to Volker RW Schaa % for catching the discrepancy} % \changes{v5.0}{2020/02/15}{Added support for \protect\acro{PDF/UA} % standards, as requested by Robin Schwab} % \changes{v5.0}{2020/02/26}{Added support for \protect\acro{PDF/X} % standards, as requested by Robin Schwab} % \changes{v5.0}{2020/03/17}{Don't set any document dates (creation, % modification, or metadata) from \string\optname{pdfdate}} % \changes{v5.2}{2020/04/29}{Introduced the \protect\optname{pdfidentifier} % package option, which enables an author to specify a unique identifier % for the document} % \changes{v5.5}{2020/07/23}{Introduced the \protect\optname{pdfpubstatus} % package option, which enables an author to specify the document's % publication status. Thanks to Robin Schwab for pointing me to the % Journal Article Versions recommendation~\protect\cite{NISO2008:jav}} % \changes{v5.5}{2020/07/25}{Automatically assign % \protect\optname{pdfnumpages} and \protect\optname{pdfbytes} under % \protect\pdfLaTeX\ and \protect\LuaLaTeX} % \changes{v5.5}{2020/09/23}{Defer \protect\cs{AtEndPreamble} execution % until the end of the document. This enables % \protect\pkgname{hyperxmp} itself to be loaded from % \protect\cs{AtEndPreamble}, as is done by % \protect\pkgname{doclicense}~v2.2.0. Thanks to Tommaso Pecorella % for the bug report and help testing} % % ^^A \GetFileInfo{hyperxmp.dtx} % % \DoNotIndex{\,,\&,\ ,\!,\",\#,\(,\),\*,\<,\>,\\,\^,\~,\^,\_} % \DoNotIndex{\@cons,\@empty,\@firstofone,\@firstoftwo,\@gobble,\@gobbletwo} % \DoNotIndex{\@ifpackageloaded,\@ifundefined,\@nil,\@secondoftwo} % \DoNotIndex{\@tempcnta,\@tempcntb,\MessageBreak,\advance,\afterassignment} % \DoNotIndex{\aftergroup,\begin,\begingroup,\bgroup,\catcode,\csname,\def} % \DoNotIndex{\divide,\do,\edef,\egroup,\else,\end,\endcsname,\endgroup} % \DoNotIndex{\expandafter,\fi,\futurelet,\g@addto@macro,\gdef,\global} % \DoNotIndex{\hbox,\if,\ifcase,\ifnum,\ifx,\immediate,\lccode,\let,\loop} % \DoNotIndex{\lowercase,\multiply,\newcommand,\noexpand,\or,\relax,\repeat} % \DoNotIndex{\space,\string,\the,\toks,\uccode,\uppercase,\usepackage} % \DoNotIndex{\xdef} % % ^^A Define a few logical styles. % \DeclareRobustCommand{\term}[1]{#1\SortIndex{#1}{#1}} % \DeclareRobustCommand{\pkgname}[1]{^^A % \mbox{\textsf{#1}}^^A % \SortIndex{#1}{\textsf{#1} (package)}^^A % \index{packages=\textsf{#1}}^^A % } % \DeclareRobustCommand{\clsname}[1]{^^A % \mbox{\textsf{#1}}^^A % \SortIndex{#1}{\textsf{#1} (class)}^^A % \index{classes=\textsf{#1}}^^A % } % \makeatletter % \DeclareRobustCommand{\xmpprop}[2][]{^^A XMP property % \def\xmppropopt{#1}^^A % \ifx\xmppropopt\@empty % \mbox{\textsf{#2}}^^A % \else % \mbox{\textsf{#2}}.\mbox{\textsf{#1}}^^A % \SortIndex{#1}{\textsf{#1}}^^A % \fi % \SortIndex{#2}{\textsf{#2}}^^A % \index{properties, \acrostyle{XMP}=\textsf{#2}}^^A % } % \DeclareRobustCommand{\xmpterm}[1]{^^A All other XMP terms % \mbox{\textsf{#1}}^^A % \SortIndex{#1}{\textsf{#1}}^^A % } % \makeatother % \index{XMP=\acrostyle {XMP}&properties|see{properties, \acrostyle{XMP}}} % \DeclareRobustCommand{\pdfterm}[1]{^^A % \mbox{\textsf{#1}}^^A % \SortIndex{#1}{\textsf{#1}}^^A % \index{PDF=\acrostyle{PDF}=\textsf{#1}}^^A % } % \DeclareRobustCommand{\cmdname}[1]{\mbox{\texttt{#1}}\SortIndex{#1}{\texttt{#1}}} % \DeclareRobustCommand{\optname}[1]{^^A % \mbox{\textsf{#1}}^^A % \SortIndex{#1}{\textsf{#1} (option)}^^A % \index{options=\textsf{#1}}^^A % } % ^^A \moptname is the same as \optname but additionally typesets the % ^^A option name in the margin. % \DeclareRobustCommand{\moptname}[1]{^^A % \optname{#1}^^A % \marginpar{\raggedleft\strut\mbox{\textsf{#1}}}^^A % } % \DeclareRobustCommand{\acrostyle}[1]{\textsc{\MakeLowercase{#1}}} % \DeclareRobustCommand{\acro}[1]{^^A % \mbox{\acrostyle{#1}}^^A % \SortIndex{#1}{\acrostyle{#1}}^^A % } % \newcounter{note} % \newcommand{\usagenote}[1]{^^A % \refstepcounter{note}^^A % \Needspace{\baselineskip}^^A % \belowpdfbookmark{Note \thenote: #1}{note.\thenote}^^A % \paragraph{Note~\thenote: #1}% % } % % ^^A Define some other shortcut macros. % \DeclareRobustCommand{\tex}{^^A % \texorpdfstring{\TeX\SortIndex{TeX}{\TeX}}{TeX}^^A % } % \DeclareRobustCommand{\XeTeXlogo}{^^A % X\lower0.5ex\hbox{\kern-.15em\reflectbox{E}}\kern-0.1667em\TeX % } % \DeclareRobustCommand{\XeTeX}{^^A % \texorpdfstring{\XeTeXlogo\SortIndex{XeTeX}{\XeTeXlogo}}{XeTeX}^^A % } % \DeclareRobustCommand{\XeLaTeXlogo}{^^A % X\lower0.5ex\hbox{\kern-.15em\reflectbox{E}}\kern-0.1667em\LaTeX % } % \DeclareRobustCommand{\XeLaTeX}{^^A % \texorpdfstring{\XeLaTeXlogo\SortIndex{XeLaTeX}{\XeLaTeXlogo}}{XeLaTeX}^^A % } % \DeclareRobustCommand{\LuaTeXlogo}{Lua\TeX} % \DeclareRobustCommand{\LuaTeX}{^^A % \texorpdfstring{\LuaTeXlogo\SortIndex{LuaTeX}{\LuaTeXlogo}}{LuaTeX}^^A % } % \DeclareRobustCommand{\LuaLaTeXlogo}{Lua\LaTeX} % \DeclareRobustCommand{\LuaLaTeX}{^^A % \texorpdfstring{\LuaLaTeXlogo\SortIndex{LuaLaTeX}{\LuaLaTeXlogo}}{LuaLaTeX}^^A % } % \DeclareRobustCommand{\pdfTeXlogo}{pdf\TeX} % \DeclareRobustCommand{\pdfTeX}{^^A % \texorpdfstring{\pdfTeXlogo\SortIndex{pdfTeX}{\pdfTeXlogo}}{pdfTeX}^^A % } % \DeclareRobustCommand{\pdfLaTeXlogo}{pdf\LaTeX} % \DeclareRobustCommand{\pdfLaTeX}{^^A % \texorpdfstring{\pdfLaTeXlogo\SortIndex{pdfLaTeX}{\pdfLaTeXlogo}}{pdfLaTeX}^^A % } % \DeclareRobustCommand{\Dvips}{^^A % \texorpdfstring{Dvips\SortIndex{dvips}{\texttt{dvips}}}{Dvips}^^A % } % \DeclareRobustCommand{\progname}[1]{^^A % \mbox{\texttt{#1}}\SortIndex{#1}{\texttt{#1}}^^A % } % \DeclareRobustCommand{\Lua}{^^A % Lua\index{Lua}^^A % } % \DeclareRobustCommand{\Koma}{^^A % Koma^^A % \SortIndex{Koma}{Koma (class)}^^A % \index{classes&Koma}^^A % } % \DeclareRobustCommand{\ACMclass}{^^A % \acro{ACM}^^A % \index{classes&ACM=\acrostyle{ACM}}^^A % } % % ^^A Define an environment just like macro but for Lua functions. % \makeatletter % \newenvironment{luafunc}{^^A % \begingroup % \catcode`\_=11 % \def\PrintMacroName##1{\strut\MacroFont\string##1\ }^^A % \def\SpecialIndex@##1##2{^^A % \@bsphack % \special@index{\string##1\actualchar % \string\verb\quotechar*\verbatimchar##1\verbatimchar##2}^^A % \@esphack % }^^A % \begin{macro}^^A % }{^^A % \end{macro}^^A % \endgroup % } % \makeatother % % ^^A Typeset a PDF standard name, indexing only the standard type but % ^^A not the subtype or year. % \makeatletter % \newcommand*{\PDFstd}[4]{^^A % \mbox{^^A % \acro{PDF/#1}-\oldstylenums{#2}^^A % #3^^A % \@ifnotmtarg{#4}{:\oldstylenums{#4}}^^A % }^^A % } % \makeatother % % ^^A Index schemata. % \DeleteShortVerb{\|} % \makeatletter % \newenvironment{schemadesc}[2][]{^^A % \@ifmtarg{#1}{^^A % \index{#2 schema|(}^^A % \index{schemata|(}^^A % \def\closeschemedesc{^^A % \index{schemata|)}^^A % \index{#2 schema|)}^^A % }^^A % }{^^A % \index{#1 schema=#2 schema|(}^^A % \index{schemata=#2|(}^^A % \def\closeschemedesc{^^A % \index{schemata=#2|)}^^A % \index{#1 schema=#2 schema|)}^^A % }^^A % }^^A % }{^^A % \closeschemedesc % } % \newcommand{\schema}[2][]{^^A % \@ifmtarg{#1}{^^A % \kern0pt^^A % \index{#2 schema}^^A % \index{schemata}^^A % #2^^A % }{^^A % \kern0pt^^A % \index{#1 schema=#2 schema}^^A % \index{schemata=#2}^^A % #2^^A % }^^A % } % \makeatother % \MakeShortVerb{\|} % % ^^A Pack figures a bit tighter onto the page. % \renewcommand{\floatpagefraction}{0.8} % % ^^A Help \pageref refer to arbitrary content. % \newcounter{pagelabel} % % \maketitle % \sloppy % % \begin{abstract} % \pkgname{hyperxmp} makes it easy for an author to include \acro{XMP} % metadata in a \acro{PDF} document produced by \LaTeX\@. \pkgname{hyperxmp} % integrates seamlessly with \pkgname{hyperref} and requires virtually % no modifications to a document that already specifies document % metadata through \pkgname{hyperref}'s mechanisms. % \end{abstract} % % \section{Introduction} % % Adobe Systems, Inc.\ has been promoting % \acro{XMP}~\cite{Adobe2012:XMP}---eXtensible Metadata Platform---as a % standard way to include metadata within a document. The idea behind % \acro{XMP} is that it is an \acro{XML}-based description of various % document attributes and is embedded as uncompressed, unencoded text % within the document it describes. By storing the metadata this way it % is independent of the document's file format. That is, regardless of % whether a document is in \acro{PDF}, \acrostyle{JPEG}, % \acrostyle{HTML}, or any other format, it is trivial for a program (or % human) to locate, extract, and---using any standard \acro{XML} % parser---process the embedded \acro{XMP} metadata. % % As of this writing there are few tools that actually do process % \acro{XMP}\@. However, it is easy to imagine future support existing % in file browsers for displaying not only a document's filename but % also its title, list of authors, description, and other metadata. % % \paragraph{This is too abstract! Give me an example.} % Consider a \LaTeX\ document with three authors---Jack Napier, Edward % Nigma, and Harvey Dent---named in the \LaTeX\ source in the usual way: % ``\verb|\author{|\texttt{Jack Napier \cs{and} Edward Nigma \cs{and} % Harvey Dent}\verb|}|''. With \pkgname{hyperxmp}, the generated % \acro{PDF} file will contain, among other information, the following % stanza of \acro{XMP} code embedded within it: % % \begin{verbatim} % % % Jack Napier % Edward Nigma % Harvey Dent % % % \end{verbatim} % % In the preceding code, the |dc| namespace refers to the % \href{http://purl.org/DC/}{\schema{Dublin Core} schema}, a collection % of metadata properties. The \xmpprop{dc:creator} property surrounds % the list of authors. The \textsf{rdf} namespace is the % \href{http://www.w3.org/RDF/}{Resource Description Framework}, which % defines \xmpterm{rdf:Seq} as an ordered list of values. Each author % is represented by an individual list item (\xmpterm{rdf:li}), making % it easy for an \acro{XML} parser to separate the authors' names. % % Remember that \acro{XMP} code is stored as \emph{metadata}. It does % not appear when viewing or printing the \acro{PDF} file. Rather, it % is intended to make it easy for computer applications to identify and % categorize the document. % % \subsection{Supported metadata} % % \pkgname{hyperxmp} knows how to embed all of the following types of % metadata within a document: % % \label{page:begin-metadata-list} % \begin{itemize} \raggedright % \item address of primary author % (\xmpprop[CiAdrExtadr]{Iptc4xmpCore:CreatorContactInfo}, % \xmpprop[CiAdrCity]{Iptc4xmpCore:CreatorContactInfo}, % \xmpprop[CiAdrRegion]{Iptc4xmpCore:CreatorContactInfo}, % \xmpprop[CiAdrPcode]{Iptc4xmpCore:CreatorContactInfo}, and % \xmpprop[CiAdrCtry]{Iptc4xmpCore:CreatorContactInfo}) % \item author(s) (\xmpprop{dc:creator}) % \item base \acro{URL} for relative references (\xmpprop{xmp:BaseURL}) % \item book edition (\xmpprop{prism:bookEdition}) % \item copyright (\xmpprop{dc:rights} and \xmpprop{xmpRights:Marked}) % \item date (\xmpprop{dc:date}, \xmpprop{xmp:CreateDate}, % \xmpprop{xmp:ModifyDate}, and \xmpprop{xmp:MetadataDate}) % \item \acro{DOI} (\xmpprop{prism:doi}) % \item email address(es) of primary author (\xmpprop[CiEmailWork]{Iptc4xmpCore:CreatorContactInfo}) % \item file format (\xmpprop{dc:format}) % \item file name of main \LaTeX\ source file (\xmpprop{dc:source}) % \item file size in bytes (\xmpprop{prism:byteCount}) % \item \acro{ISBN} (\xmpprop{prism:isbn}) % \item \acro{ISSN}---both print (\xmpprop{prism:issn}) and electronic (\xmpprop{prism:eIssn}) % \item issue number of parent publication (\xmpprop{prism:number}) % \item journal article version (\xmpprop{jav:journal\_article\_version}) % \item keywords (\xmpprop{pdf:Keywords} and \xmpprop{dc:subject}) % \item language used (\xmpprop{dc:language}) % \item license \acro{URL} (\xmpprop{xmpRights:WebStatement}) % \item metadata writer (\xmpprop{photoshop:CaptionWriter}) % \item page count (\xmpprop{prism:pageCount}) % \item page range(s) (\xmpprop{prism:pageRange}) % \item \acro{PDF} version (\xmpprop{pdf:PDFVersion}) % \item \acro{PDF}-generating tool (\xmpprop{pdf:Producer} and \xmpprop{xmp:CreatorTool}) % \item \acro{PDF/A} version and conformance level (\xmpprop{pdfaid:part} and \xmpprop{pdfaid:conformance}) % \item \acro{PDF/UA} version (\xmpprop{pdfuaid:part}) % \item \acro{PDF/X} standard compliance (\xmpprop{pdfxid:GTS\_PDFXVersion}) % \item position/title of primary author (\xmpprop{photoshop:AuthorsPosition}) % \item publication name of parent publication (\xmpprop{prism:publicationName}) % \item publisher of the document (\xmpprop{dc:publisher}) % \item rendition variation of the document (\xmpprop{xmpMM:RenditionClass}) % \item summary (\xmpprop{dc:description}) % \item subtitle (\xmpprop{prism:subtitle}) % \item telephone number(s) of primary author (\xmpprop[CiTelWork]{Iptc4xmpCore:CreatorContactInfo}) % \item title (\xmpprop{dc:title}) % \item trapping of colors (\xmpprop{pdf:trapped}) % \item type of document (\xmpprop{dc:type}) % \item type of parent publication (\xmpprop{prism:aggregationType}) % \item unique identifier for the document (\xmpprop{dc:identifier}) % \item \acro{URL} of the document (\xmpprop{prism:url}) % \item \acro{URL}(s) of the primary author (\xmpprop[CiUrlWork]{Iptc4xmpCore:CreatorContactInfo}) % \item \acro{UUID} for the document (\xmpprop{xmpMM:DocumentID}) % \item \acro{UUID} for the document instance (\xmpprop{xmpMM:InstanceID}) % \item version identifier for the document (\xmpprop{xmpMM:VersionID}) % \item volume number of parent publication (\xmpprop{prism:volume}) % \end{itemize} % \label{page:end-metadata-list} % % \noindent % More types of metadata may be added in a future release. % % \subsection{Comparisons with similar packages} % % \paragraph{\textsf{xmpincl}} % In short, \pkgname{xmpincl} is more flexible but \pkgname{hyperxmp} is % easier to use. With \pkgname{xmpincl}, the author manually constructs % a file of arbitrary \acro{XMP} data and the package merely embeds it % within the generated \acro{PDF} file. With \pkgname{hyperxmp}, the % author specifies values for various predefined metadata types and the % package formats those values as \acro{XMP} and embeds the result % within the generated \acro{PDF} file. % % \pkgname{xmpincl} can embed \acro{XMP} only when running under \pdfLaTeX\ and % only when in \acro{PDF}-generating mode. \pkgname{hyperxmp} additionally % works with a few other \acro{PDF}-producing \LaTeX\ backends. % % \pkgname{hyperxmp} and \pkgname{xmpincl} can complement each other. % An author may want to use \pkgname{hyperxmp} to produce a basic set of % \acro{XMP} code, then extract the \acro{XMP} code from the \acro{PDF} file with a text % editor, augment the \acro{XMP} code with any metadata not supported by % \pkgname{hyperxmp}, and use \pkgname{xmpincl} to include the modified % \acro{XMP} code in the \acro{PDF} file. % % \paragraph{\textsf{pdfx}} % The main difference between \pkgname{hyperxmp} and \pkgname{pdfx} is % that \pkgname{hyperxmp} tries to integrate as seamlessly as possible % into an existing document. It leverages \pkgname{hyperref}'s % \cs{hypersetup} command and many of \cs{hypersetup}'s options and % defines its own options in a compatible manner. In contrast, % \pkgname{pdfx} requires the user to create a separate % |\jobname.xmpdata| file containing \pkgname{pdfx}-defined commands for % each metadata element. % % \iffalse %<*listings> % \fi \newsavebox{\pdfxbox} \begin{lrbox}{\pdfxbox} \begin{lstlisting}[ language=tex, columns=fullflexible, linewidth=14pc, frame=single, basicstyle=\footnotesize, showlines, morekeywords={\Title,\Author,\Language,\Keywords,\Publisher,\sep} ] \Title{Baking through the ages} \Author{A. Baker\sep C. Kneader} \Language{en-GB} \Keywords{cookies\sep muffins\sep cakes} \Publisher{Baking International} \end{lstlisting} \end{lrbox} \newsavebox{\hyxmpbox} \begin{lrbox}{\hyxmpbox} \begin{lstlisting}[ language=tex, columns=fullflexible, linewidth=13pc, frame=single, basicstyle=\footnotesize, morekeywords={\hypersetup} ] \hypersetup{% pdftitle={Baking through the ages}, pdfauthor={A. Baker, C. Kneader}, pdflang={en-GB}, pdfkeywords={cookies, muffins, cakes}, pdfpublisher={Baking International} } \end{lstlisting} \end{lrbox} % \iffalse % % \fi % % Figure~\ref{fig:pdfx-hyxmp} adapts an example appearing in the % \pkgname{pdfx} manual to \pkgname{hyperxmp}. % \begin{figure} % \centering % \subcaptionbox{\pkgname{pdfx} (separate \texttt{.xmpdata} file) % \label{fig:ph-pdfx}}{% % \usebox{\pdfxbox}% % } % \hfil % \subcaptionbox{\pkgname{hyperxmp} (main document) % \label{fig:ph-hyxmp}}{% % \usebox{\hyxmpbox}} % \caption{Comparison of \pkgname{pdfx} and \pkgname{hyperxmp}} % \label{fig:pdfx-hyxmp} % \end{figure} % The two are comparable line-by-line in terms of how one specifies the % title, author, document language, keywords, and publisher. However, % \pkgname{hyperxmp} implicitly writes a wealth of additional metadata % into the \acro{XMP} packet such as the document date, creation date, % creator tool, file format, \acro{PDF} version, and unique document and % instance IDs. In fact, if a document omits all of the code shown in % Figure~\ref{fig:ph-hyxmp}, it will still store the \cs{title} and % \cs{author} data in the \acro{XMP} packet. % % One can therefore summarize the difference between \pkgname{hyperxmp} % and \pkgname{pdfx} as follows: \pkgname{pdfx} requires the author to % be fully explicit about the document's metadata while % \pkgname{hyperxmp} allows some metadata to be specified implicitly, % automatically inferring it when possible. In general, % \pkgname{hyperxmp} tries to simplify the author's task as much as % possible. % % % \section{Usage} % % \pkgname{hyperxmp} works by postprocessing some of the package options % honored by \pkgname{hyperref}. To use \pkgname{hyperxmp}, merely put % a |\usepackage{hyperxmp}| in your document's preamble. That line can % appear anywhere \emph{after} the |\usepackage{hyperref}| but % \emph{before} \pkgname{hyperref}'s \acro{PDF} options are specified % with |\hypersetup|. \pkgname{hyperxmp} will construct its \acro{XMP} % data using the following \pkgname{hyperref} options: % % \begin{multicols}{3} % \raggedcolumns % \begin{itemize} % \item \optname{baseurl} % \item \optname{pdfauthor} % \item \optname{pdfcreationdate} % \item \optname{pdfkeywords} % \item \optname{pdflang} % \item \optname{pdfmoddate} % \item \optname{pdfproducer} % \item \optname{pdfsubject} % \item \optname{pdftitle} % \item \optname{pdftrapped} % \end{itemize} % \end{multicols} % % \noindent % \mbox{}\label{page:begin-new-options} % \pkgname{hyperxmp} instructs \pkgname{hyperref} also to accept the % following options, which have meaning only to \pkgname{hyperxmp}: % % \begin{multicols}{3} % \raggedcolumns % \begin{itemize} % \item \optname{pdfaconformance} % \item \optname{pdfapart} % \item \optname{pdfauthortitle} % \item \optname{pdfbookedition} % \item \optname{pdfbytes} % \item \optname{pdfcaptionwriter} % \item \optname{pdfcontactaddress} % \item \optname{pdfcontactcity} % \item \optname{pdfcontactcountry} % \item \optname{pdfcontactemail} % \item \optname{pdfcontactphone} % \item \optname{pdfcontactpostcode} % \item \optname{pdfcontactregion} % \item \optname{pdfcontacturl} % \item \optname{pdfcopyright} % \item \optname{pdfdate} % \item \optname{pdfdocumentid} % \item \optname{pdfdoi} % \item \optname{pdfeissn} % \item \optname{pdfidentifier} % \item \optname{pdfinstanceid} % \item \optname{pdfisbn} % \item \optname{pdfissn} % \item \optname{pdfissuenum} % \item \optname{pdflicenseurl} % \item \optname{pdfmetadate} % \item \optname{pdfmetalang} % \item \optname{pdfnumpages} % \item \optname{pdfpagerange} % \item \optname{pdfpublication} % \item \optname{pdfpublisher} % \item \optname{pdfpubstatus} % \item \optname{pdfpubtype} % \item \optname{pdfrendition} % \item \optname{pdfsource} % \item \optname{pdfsubtitle} % \item \optname{pdftype} % \item \optname{pdfuapart} % \item \optname{pdfurl} % \item \optname{pdfversionid} % \item \optname{pdfvolumenum} % \item \optname{pdfxstandard} % \end{itemize} % \end{multicols} % \label{page:end-new-options} % % % \subsection{Option descriptions} % % The document title is specified as normal for \pkgname{hyperref} with % \moptname{pdftitle}, but see Note~\ref{note:multilingual} on % page~\pageref{note:multilingual} for instructions on how to specify a % title in multiple languages. If \optname{pdftitle} is not specified % it will inherit its value from the document's \cs{title}. % \pkgname{hyperxmp} introduces a complementary \moptname{pdfsubtitle} % option: % % \begin{verbatim} % pdftitle={Frankenstein}, % pdfsubtitle={The Modern Prometheus}, % \end{verbatim} % % Unfortunately, the subtitle can appear in only one language. It % assumed to be the same language as the document language % (\optname{pdflang}) but can be overridden by preceding the text with a % bracketed \acro{ISO} \mbox{639-1} two-letter language code and an % optional \acro{ISO} \mbox{3166-1} two-letter region code. See the % example below for \optname{pdfpublication}. % % \pkgname{hyperref}'s \moptname{pdfauthor} option specifies the % document's author(s). See Note~\ref{note:literal-commas} on % page~\pageref{note:literal-commas} for a discussion of the correct % syntax. If \optname{pdfauthor} is not specified it will inherit its % value from the document's \cs{author}. \moptname{pdfauthortitle} % indicates the primary author's position or title. % \moptname{pdfcaptionwriter} specifies the name of the person who added % the metadata to the document. % % The next eight items describe how to contact the person or institution % responsible for the document (the ``contact''). % \moptname{pdfcontactaddress} is the contact's street address and can % include the institution name if the contact is an institution; % \moptname{pdfcontactcity} is the contact's city; % \moptname{pdfcontactcountry} is the contact's country; % \moptname{pdfcontactemail} is the contact's email address (or % multiple, comma-separated email addresses); \moptname{pdfcontactphone} % is the contact's telephone number (or multiple, comma-separated % telephone numbers); \moptname{pdfcontactpostcode} is the contact's % postal code; \moptname{pdfcontactregion} is the contact's state or % province; and \moptname{pdfcontacturl} is the contact's \acro{URL} (or % multiple, comma-separated \acro{URL}s). % % \Needspace{2\baselineskip} % \moptname{pdfcopyright} defines the copyright text, and % \moptname{pdflicenseurl} identifies a \acro{URL} that points to the % document's license agreement. % % \moptname{pdfmetalang} indicates the natural language in which certain % metadata---specifically, the document's title, subject, and copyright % statement---are written. The language should be specified using an % \acro{IETF} language tag~\cite{IANA2011:lang-tags}, for example, % ``|en|'' for English, ``|en-US|'' for specifically United States % English, ``|de|'' for German, and so forth. If \optname{pdfmetalang} % is not specified, \pkgname{hyperxmp} assumes the metadata language is % the same as the document language (\pkgname{hyperref}'s % \moptname{pdflang} option). If neither \optname{pdfmetalang} nor % \optname{pdflang} is specified, \pkgname{hyperxmp} uses only % ``\xmpterm{x-default}'' as the metadata language. % % \acro{XMP} can include a universally unique identifier (\acro{UUID}) % for each document and for each instance of a given document. By % default, \pkgname{hyperxmp} assigns a version~4 (i.e.,~pseudorandom) % \acro{UUID}~\cite{Leach2005:uuid} for each of these. However, a % document can alternatively specify a particular document identifier % using \moptname{pdfdocumentid} and (not normally recommended) a % particular instance identifier using \moptname{pdfinstanceid}. These % should be of the form % \texttt{uuid:}\textit{xxxxxxxx}\texttt{-}\textit{xxxx}\texttt{-}\textit{xxxx}\texttt{-}\textit{xxxx}\texttt{-}\textit{xxxxxxxxxxxx}, % where ``\textit{x}'' is a lowercase hexadecimal number. For example, % \texttt{uuid:53ab7f19-a48c-5177-8bb2-403ad907f632} is a valid argument % to \optname{pdfdocumentid} (or \optname{pdfinstanceid}). See Leach, % Mealling, and Salz's \acro{UUID} specification document for details on % how to produce the various forms of % \acro{UUID}s~\cite{Leach2005:uuid}. A more freeform mechanism than % \optname{pdfinstanceid} for versioning documents is available via % \moptname{pdfversionid}. The version specified by % \optname{pdfversionid} can be incremented as~|1|, |2|, |3|,~\dots; % identified with a hierarchical numbering scheme (e.g.,~this document % is versioned \texttt{\versionnumber} to match the package version); or % labeled using any other approach. One possibility is to use a % revision number or commit hash from the version-control software % maintaining the document. For example, the |\gitVer| macro from the % \pkgname{gitver} package is an expandable (see % Note~\ref{note:expandable} on page~\pageref{note:expandable}) version % of the current \href{https://git-scm.com/}{Git} hash that can suitably % be passed to \optname{pdfversionid}. If not specified, % \optname{pdfversionid} defaults to~|1|. % % Already-published documents can be identified in a number of ways. % \moptname{pdfisbn} specifies the \acro{ISBN}. \moptname{pdfissn} % refers to the \acro{ISSN} of the \emph{print} version of the document % while \moptname{pdfeissn} refers to the \acro{ISSN} of the % \emph{electronic} version of the document. \moptname{pdfdoi} % specifies the \acro{DOI} and should include only the \acro{DOI} name % without any \acro{URL} prefix. For example, specify % |pdfdoi={10.1145/3149526.3149532}|, \emph{not} % |pdfdoi={https://doi.org/10.1145/3149526.3149532}|. % \moptname{pdfurl} points to the complete \acro{URL} for the document. % In contrast, \moptname{baseurl} points one level up and is used to % resolve relative \acro{URL}s. % % \moptname{pdfidentifier} provides an alternative mechanism to uniquely % identify a document. Its advantage relative to \optname{pdfisbn}, % \optname{pdfissn}, \optname{pdfdoi}, etc.\ is its flexibility; any of % a wide variety of identification types can be used.\footnote{See, for % example, % \url{https://www.iana.org/assignments/urn-namespaces/urn-namespaces.xhtml} % for the \texttt{urn:} \acro{URI} scheme and % \url{http://info-uri.info/registry/} for the \texttt{info:} % \acro{URI} scheme.} \optname{pdfidentifier}'s disadvantage is that % it allows only a single identifier per document. For example, a % document could use |pdfidentifier=urn:iso:std:32000:ed-1:v1:en| to % identify itself as version~1 of English-language \acro{ISO} standard % 32000-1, but then this same document could not also use % \optname{pdfidentifier} to identify itself by \acro{DOI} % (|info:doi/|\dots), \acro{ISBN} (|urn:ISSN:|\dots), etc. (It can % still use the options described in the previous paragraph, though.) If % \optname{pdfidentifier} is not specified explicitly, % \pkgname{hyperxmp} will use the first non-empty value out of the % \acro{DOI}, electronic \acro{ISSN}, print \acro{ISSN}, and \acro{ISBN} % or skip the identifier entirely if all of those are empty. % % Already-published documents can further be identified by the % publication in which they appear. \moptname{pdfpublication} specifies % the title of the journal, magazine, or other parent document. The % title language is assumed to be the same as the document language % (\optname{pdflang}) but can be overridden by preceding the text with a % bracketed \acro{ISO} \mbox{639-1} two-letter language code and an % optional \acro{ISO} \mbox{3166-1} two-letter region code. For % example, |pdfpublication={[fr]Charlie Hedbo}| indicates a % French-language title. Were the language or pronunciation differences % significant, |fr-FR| would indicate specifically the French spoken in % France, as opposed to that spoken in, say, Canada (|fr-CA|) or Belgium % (|fr-BE|). The publisher itself can be named using % \moptname{pdfpublisher}. % % \moptname{pdfpubtype} indicates the type of publication in which the % document was published. This should be one of the \acro{PRISM} % aggregation types~\cite{PRISM2012:cont-voc} such as |book|, |journal|, % |magazine|, |manual|, |report|, or |whitepaper|. % % For publications in journals, magazines, and similar periodicals, a % document can specify the volume number with \moptname{pdfvolumenum} % and the issue number within the volume with \moptname{pdfissuenum}. % \moptname{pdfpagerange} indicates the page numbers at which the % document appears within the publication. The intention is that this % be a comma-separated list of dash-separated ranges, as in % |pdfpagerange={1,4-5}|. See Note~\ref{note:page-counting} on % page~\pageref{note:page-counting} for advice on how to assign % \optname{pdfpagerange} semi-automatically. A journal article's % publication status can be indicated with \moptname{pdfpubstatus}. % This option expects to take one of the values listed in % Table~\ref{tbl:jav}. See the \acro{NISO}/\acro{ALPSP} Journal Article % Versions recommendation~\cite{NISO2008:jav} for an explanation of each % of those values and when to use them. % % \begin{table} % \centering % \caption{Valid arguments for \optname{pdfpubstatus}} % \label{tbl:jav} % \begin{tabular}{@{}>{\ttfamily}ll@{}} % \toprule % \multicolumn{1}{@{}l}{Value} & Meaning \\ % \midrule % AO & Author's Original \\ % SMUR & Submitted Manuscript Under Review \\ % AM & Accepted Manuscript \\ % P & Proof \\ % VoR & Version of Record \\ % CVoR & Corrected Version of Record \\ % EVoR & Enhanced Version of Record \\ % \bottomrule % \end{tabular} % \end{table} % % For books, \moptname{pdfbookedition} names the edition of the book. % This is specified as text, not a number. As with % \optname{pdfpublication} (above), \optname{pdfbookedition} accepts a % bracketed language code, as in |pdfbookedition={[en]Second| % |edition}|. % % \acro{XMP} metadata can include a number of dates (in fact, % timestamps, as they include both date and time components). % \moptname{pdfdate} specifies the document date. It is analogous to the % \LaTeX\ |\date| command, and, like |\date|, defaults to the date the % document was built. It must be specified in either \acro{XMP} % format~\cite{Adobe2012:XMP} or \acro{PDF} format~\cite{Adobe2008:PDF}. % \acro{XMP} dates are written in the form % \textsc{yyyy}|-|\textsc{mm}|-|\textsc{dd}|T|hh|:|mm|:|ss|+|\textsc{tt}|:|tt.\footnote{Although % allowed by \acro{XMP}, \pkgname{hyperxmp} does not currently accept % fractions of a second in timestamps.} A W3C % recommendation~\cite{Wolf1997:date-time} discusses this format in more % detail, but as an example, 14~hours, 15~minutes, 9~seconds past % midnight U.S. Mountain Daylight Time (UTC-6) on the 23rd day of % September in the year~2014 should be written as % \texttt{2014-09-23T14:15:09-06:00}. This can be truncated (with loss % of information) to \texttt{2014-09-23T14:15:09}, % \texttt{2014-09-23T14:15}, \texttt{2014-09-23}, \texttt{2014-09}, % or \texttt{2014} but no other subsets. \acro{PDF} dates are written % in the form |D:|\textsc{yyyymmdd}hhmmss|+|\textsc{tt}|'|tt|'|. The % same date in the preceding example would be written as % \texttt{D:20140923141509-06'00'} in \acro{PDF} format. % % The document's creation date, modification date, and metadata date are % normally set automatically, but \moptname{pdfcreationdate}, % \moptname{pdfmoddate}, and \moptname{pdfmetadate} can be used to % override the defaults. Like \optname{pdfdate}, \optname{pdfmetadate} % can be specified in either \acro{XMP} or \acro{PDF} format. However, % because \pkgname{hyperref} defines \optname{pdfcreationdate} and % \optname{pdfmoddate} and expects these to be written as \acro{PDF} % dates, \pkgname{hyperxmp} concomitantly accepts these two dates only % in \acro{PDF} format as well. Note that it's rare that a document % would need to specify any of \optname{pdfcreationdate}, % \optname{pdfmoddate}, or \optname{pdfmetadate}. % % \moptname{pdftype} describes the type of document being produced. % This refers to ``the nature or genre of the % resource''~\cite{Adobe2012:XMP} such as |poem|, |novel| or |working| % |paper|, as opposed to the file format (always |application/pdf| when % generated by \pkgname{hyperxmp}). Although \optname{pdftype} can be % assigned an arbitrary piece of text, the \acro{XMP} specification % recommends selecting types from a ``controlled vocabulary'' such as % the \acro{DCMI} Type Vocabulary~\cite{DCMI2012:meta-terms}. The % \acro{DCMI} Type Vocabulary currently consists of only |Collection|, % |Dataset|, |Event|, |Image|, |InteractiveResource|, |MovingImage|, % |PhysicalObject|, |Service|, |Software|, |Sound|, |StillImage|, and % |Text|. \optname{pdftype} defaults to |Text|, which refers to % ``books, letters, dissertations, poems, newspapers, articles, archives % of mailing lists,''~\cite{DCMI2012:meta-terms} and other forms of % text---all things \LaTeX\ is commonly used to typeset. % % Sometimes a base document is rendered in different forms. % \moptname{pdfrendition} indicates the particular rendition the current % document instance represents. The value should come from the % following controlled vocabulary~\cite{Adobe2012:XMP}: |default|, % |draft|, |low-res|, |proof|, |screen|, and |thumbnail|. % \pkgname{hyperxmp}'s default value is |default|, which indicates the % master document, unless the \optname{draft} option is passed to % |\documentclass|, in which case \pkgname{hyperxmp} defaults to % |draft|. % % \pkgname{hyperxmp} honors \pkgname{hyperref}'s \moptname{pdftrapped} % option. A document can indicate whether it employs % \href{https://en.wikipedia.org/wiki/Trap_(printing)}{color trapping} % by specifying \optname{pdftrapped}=|True| or % \optname{pdftrapped}=|False|. (\optname{pdftrapped}=|Unknown| is also % allowed.) % % \moptname{pdfapart} and \moptname{pdfaconformance}, are used in % conjunction with \pkgname{hyperref}'s \optname{pdfa} option to claim a % particular \acro{PDF/A} standard by which the document abides. They % default to \optname{pdfapart}=|1| and \optname{pdfaconformance}=|B|, % indicating the \PDFstd{A}{1}{b}{} standard. These can be changed % (with caution) to assert that the document abides by a different % standard (e.g.,~\PDFstd{A}{2}{u}{}). A document that conforms to the % \acro{PDF/UA} standard can use \moptname{pdfuapart} to indicate the % \acro{PDF/UA} conformance level. For example, \optname{pdfuapart}=|1| % asserts that the document respects \PDFstd{UA}{1}{}{}. % \moptname{pdfxstandard} indicates the particular \acro{PDF/X} standard % by which the document abides. Unlike \optname{pdfapart} and % \optname{pdfaconformance}, which accept a number and a letter, % respectively, \optname{pdfxstandard} expects a textual identification % of a standard name. The following are the acceptable \acro{PDF/X} % standard names as of at the time of this writing. % % ^^A This list needs to be kept up-to-date with the standards checked % ^^A by \@pdfxstandard. % \begin{multicols}{3} % \raggedcolumns % \begin{itemize}[noitemsep] % \item \PDFstd{X}{1}{a}{2001} % \item \PDFstd{X}{1}{a}{2003} % \item \PDFstd{X}{3}{}{2002} % \item \PDFstd{X}{3}{}{2003} % \item \PDFstd{X}{4}{}{} % \item \PDFstd{X}{4}{p}{} % \item \PDFstd{X}{5}{g}{} % \item \PDFstd{X}{5}{n}{} % \item \PDFstd{X}{5}{pg}{} % \end{itemize} % \end{multicols} % % For example, one can specify \optname{pdfxstandard}=|{PDF/X-4}| or % \optname{pdfxstandard}=|{PDF/X-3:2003}|, but specifying % \optname{pdfxstandard}=|{PDF/X-3}| will not pass \acro{PDF/X} % validation. Note that at the time of this writing the use of the % \PDFstd{X}{4}{p}{}, \PDFstd{X}{5}{n}{}, and \PDFstd{X}{5}{pg}{} % standards has not been tested. % % \subsubsection*{Rarely needed options} % % \moptname{pdfsource} overrides the name of the \LaTeX\ source file. % It defaults to |\jobname.tex| but can be replaced by any other string. % If \optname{pdfsource} is given an empty argument, no document source % will be specified at all. % % The number of pages in the published, print version of the document % can be expressed with \moptname{pdfnumpages}. This is computed % automatically when the document is built using either \pdfLaTeX\ or % \LuaLaTeX\@. % % The \moptname{pdfbytes} option expresses the document's file size in % bytes. The intention is for this to be used to display an estimate of % download time to a user or to serve as a quick check on whether a file % was transmitted correctly between systems. \optname{pdfbytes} is % computed automatically by both \pdfLaTeX\ and \LuaLaTeX, using the % file size from the previous build of the document. % % \bigskip % % It is usually more convenient to provide values for all of the options % presented in this section using \pkgname{hyperref}'s |\hypersetup| % command than on the |\usepackage| command line. See % \href{http://mirrors.ctan.org/macros/latex/contrib/hyperref/hyperref.pdf}{the % \pkgname{hyperref} manual} for more information. % % % \subsection{A complete example} % % The following is a sample \LaTeX\ document that provides values for % most of the metadata options that \pkgname{hyperxmp} recognizes: % % \Needspace{4\baselineskip} % \refstepcounter{pagelabel} % \label{page:begin-sample-doc} % \begin{verbatim} % \documentclass{article} % \usepackage[utf8]{inputenc} % \usepackage[unicode]{hyperref} % \usepackage{hyperxmp} % % \title{% % On a heuristic viewpoint concerning the production and % transformation of light} % \author{Albert Einstein} % \date{March 17, 1905} % % \hypersetup{% % pdftitle={% % On a heuristic viewpoint concerning the production and % transformation of light}, % pdfsubtitle={[en-US]Putting that bum Maxwell in his place}, % pdfauthor={Albert Einstein}, % pdfauthortitle={\xmpquote{Technical Assistant\xmpcomma\ Level III}}, % pdfdate={1905-03-17}, % pdfcopyright={Copyright (C) 1905, Albert Einstein}, % pdfsubject={photoelectric effect}, % pdfkeywords={energy quanta, Hertz effect, quantum physics}, % pdflicenseurl={http://creativecommons.org/licenses/by-nc-nd/3.0/}, % pdfcaptionwriter={Scott Pakin}, % pdfcontactaddress={Kramgasse 49}, % pdfcontactcity={Bern}, % pdfcontactpostcode={3011}, % pdfcontactcountry={Switzerland}, % pdfcontactphone={031 312 00 91}, % pdfcontactemail={aeinstein@ipi.ch}, % pdfcontacturl={% % http://einstein.biz/, % https://www.facebook.com/AlbertEinstein % }, % pdfdocumentid={uuid:6d1ac9ec-4ff2-515a-954b-648eeb4853b0}, % pdfversionid={2.998e8}, % pdfpublication={[de]Annalen der Physik}, % pdfpublisher={Wiley-VCH}, % pdfpubtype={journal}, % pdfvolumenum={322}, % pdfissuenum={6}, % pdfpagerange={132-148}, % pdfissn={0003-3804}, % pdfeissn={1521-3889}, % pdfpubstatus={VoR}, % pdflang={en}, % pdfmetalang={en}, % pdfurl={http://www.physik.uni-augsburg.de/annalen/history/einstein-papers/1905_17_132-148.pdf}, % pdfdoi={10.1002/andp.19053220607}, % pdfidentifier={info:lccn/50013519} % } % \XMPLangAlt{de}{pdftitle={Über einen die Erzeugung und Verwandlung des % Lichtes betreffenden heuristischen Gesichtspunkt}} % % \begin{document} % \maketitle % A profound formal difference exists between the theoretical % concepts that physicists have formed about gases and other % ponderable bodies, and Maxwell's theory of electromagnetic % processes in so-called empty space\dots % \end{document} % \end{verbatim} % \refstepcounter{pagelabel} % \label{page:end-sample-doc} % % Compile the document to \acro{PDF} using any of the following % approaches: % % \begin{itemize} % \item \pdfLaTeX % \item \LuaLaTeX % \item \XeLaTeX % \item \LaTeX~$+$ \term{Dvipdfm} % \item \LaTeX~$+$ \Dvips~$+$ \term{Ghostscript} % \item \LaTeX~$+$ \Dvips~$+$ Adobe Acrobat Distiller % \end{itemize} % % \noindent % The \LaTeX~$+$ \Dvips~$+$ \term{Ghostscript} path stores the % \acro{XMP} packet in a compressed stream, which implies that a % \acro{PDF} reader is needed to access it. Ideally, \acro{XMP} % metadata should be stored uncompressed so it can be extracted as % ordinary text. Unfortunately, as of 2022-10-07, Ghostscript has no % plans to support uncompressed metadata streams % (\href{https://bugs.ghostscript.com/show_bug.cgi?id=705962}{Ghostscript % bug report~\#705962}). It is possible to leave \emph{all} streams % uncompressed by passing |-dCompressStreams=false| to \term{Ghostscript} % (e.g.,~via the \progname{ps2pdf} wrapper script), but this leads to % larger file sizes. % % \bigskip % % Once the document is compiled, the resulting \acro{PDF} file will % contain an \acro{XMP} packet that looks something like that shown in % Appendix~\ref{sec:sample-packet}. Figure~\ref{fig:xmp-metadata-1} is % a screenshot of the \acro{XMP} metadata as it appears in Adobe % Acrobat's ``Advanced'' metadata dialog box. Further clicking on the % ``Advanced'' item within that dialog box displays all of the % document's metadata sorted by schema as shown in % Figure~\ref{fig:xmp-metadata-2}. % % \begin{figure}[htbp] % \includegraphics[width=\linewidth]{einstein1} % \caption{\acro{XMP} metadata as it appears in Adobe Acrobat} % \label{fig:xmp-metadata-1} % \end{figure} % % \begin{figure}[htbp] % \includegraphics[width=\linewidth]{einstein2} % \caption{Additional \acro{XMP} metadata as it appears in Adobe Acrobat} % \label{fig:xmp-metadata-2} % \end{figure} % % % \subsection{Usage notes} % % \usagenote{Conflicting metadata in PDF/A documents} % \label{note:meta-conflicts} % A \acro{PDF} file includes an \pdfterm{Info} dictionary containing % \pdfterm{Author}, \pdfterm{Title}, \pdfterm{Subject}, and % \pdfterm{Keywords} keys. The \pkgname{hyperref} package's % \optname{pdfauthor}, \optname{pdftitle}, \optname{pdfsubject}, and % \optname{pdfkeywords} options assign values to those keys. The % \pkgname{hyperxmp} package additionally uses those options to assign % values to various \acro{XMP} metadata: \xmpprop{dc:creator}, % \xmpprop{dc:title}, \xmpprop{dc:description}, and % \xmpprop{pdf:Keywords}. The \acro{PDF/A} specification indicates that % values that appear in both the \acro{PDF} \pdfterm{Info} dictionary % and \acro{XMP} packet must match. The problem is that in \acro{XMP}, % the author and keywords can be proper lists, as in % % \Needspace{7\baselineskip} % \begin{verbatim} % % % Curly Howard % Larry Fine % Moe Howard % % % \end{verbatim} % % \noindent % while in \acro{PDF}, the author and keywords are specified as flat % strings. Alas, there is no definition of how a list should be % collapsed to a flat string: ``\texttt{Curly Howard, Larry Fine, Moe % Howard}'' or ``\texttt{Curly Howard; Larry Fine; Moe Howard}'' or % something else. I have not yet found a form of flat string that % passes all \acro{PDF/A} validators. Furthermore, when Adobe % Acrobat---at least Adobe Acrobat DC (2019) and earlier % versions---converts a \acro{PDF} file to \acro{PDF/A} format, it does % so by discarding all but the first author, which is an unsatisfying % solution. % % Starting with version~4.0, \pkgname{hyperxmp}'s solution is to % suppress writing metadata to the \acro{PDF} \pdfterm{Info} dictionary % and write it only to the \acro{XMP} packet. (\pkgname{hyperxmp}~v5.0+ % is more sophisticated. It suppresses only the author and keyword % lists.) This appears to pacify \acro{PDF/A} validators yet retains % the author and keyword lists in their non-truncated form. If desired, % the \pdfterm{Info} dictionary can be retained by passing the % \moptname{keeppdfinfo}\label{page:keeppdfinfo} option to % \cs{hypersetup}. % % \usagenote{Acrobat multiline-field bug} % The \acro{IPTC} Photo Metadata schema states that ``the [contact] % address is a multiline field''~\cite{IPTC2010:photo-meta}. % \pkgname{hyperxmp} converts commas in \optname{pdfcontactaddress}'s % argument to line breaks in the generated \acro{XML}\@. Unfortunately, % A bug in Adobe Acrobat---at least in Adobe Acrobat DC (2019) and % earlier versions---causes that \acro{PDF} reader to discard line % breaks in the contact address. Interestingly, Adobe Illustrator CS5 % correctly displays the contact address. If you find Adobe Acrobat's % behavior bothersome, you can redefine the % \DescribeMacro{\xmplinesep}|\xmplinesep| macro as a string to use as % an address-line separator. For example, the following replaces all % commas appearing in \optname{pdfcontactaddress}'s argument with % semicolons: % % \begin{verbatim} % \renewcommand*{\xmlinesep}{;} % \end{verbatim} % % \usagenote{Object compression} % One intention of \acro{XMP} is that metadata embedded in a file be % readable even without knowledge of the file's format. That is, the % metadata are expected to appear as plain text. Although % \pkgname{hyperxmp} does its best to honor that intention, it faces % a few challenges: % % \begin{enumerate} % \item When run with versions of \LuaLaTeX\ earlier than 0.85, % \pkgname{hyperxmp} leaves all \acro{PDF} objects uncompressed. This % is due to \LuaLaTeX\ treating object compression as a global % parameter, unlike \pdfLaTeX, which treats it as a local parameter. % Hence, when \pkgname{hyperxmp} requests that the \acro{XMP} packet % be left uncompressed, \LuaLaTeX\ in fact leaves \emph{all} % \acro{PDF} streams uncompressed. Beginning with version~3.0, % \pkgname{hyperxmp} includes a workaround that correctly leaves only % the \acro{XMP} metadata uncompressed, but this workaround is % implemented only for \LuaLaTeX\ v0.85 onwards. % % \item \XeLaTeX\ (or, more precisely, the \cmdname{xdvipdfmx} back end) % exhibits the opposite problem. It compresses \emph{all} \acro{PDF} % objects, including the ones containing \acro{XMP} metadata. While % Adobe Acrobat can still detect and utilize the \acro{XMP} metadata, % non-\acro{PDF}-aware applications are unlikely to see the metadata. % Three options to consider are to (1)~use a different program % (e.g.,~\LuaLaTeX), (2)~pass the |--output-driver="xdvipdfmx -z0"| % option to \XeLaTeX\ to instruct \cmdname{xdvipdfmx} to turn off all % compression (which will of course make the \acro{PDF} file % substantially larger), or (3)~postprocess the generated \acro{PDF} % file by loading it into the commercial version of Adobe Acrobat and % re-saving it with the Save As\dots\ menu option. % \end{enumerate} % % \usagenote{Literal commas} % \label{note:literal-commas} % \pkgname{hyperxmp} splits the \optname{pdfauthor} and % \optname{pdfkeywords} lists at commas. Therefore, when specifying % \optname{pdfauthor} and \optname{pdfkeywords}, you should separate % items with commas. Also, omit ``|and|'' and other text that does not % belong to any list item. The following examples should serve as % clarification: % % \begin{description} % \item[Wrong:] |pdfauthor={Jack Napier, Edward Nigma,| % \textcolor{red}{\texttt{and}} |Harvey Dent}| % \item[Wrong:] |pdfauthor={Jack Napier|\textcolor{red}{\texttt{;}} % |Edward Nigma|\textcolor{red}{\texttt{;}} % |Harvey Dent}| % \item[Right:] |pdfauthor={Jack Napier, Edward Nigma, Harvey Dent}| % \end{description} % % \noindent % \DescribeMacro{\xmpcomma} % \DescribeMacro{\xmpquote} % If you need to include a literal comma within an author or keyword % list (where commas normally separate list items) or a street address % (where commas normally separate lines), use the |\xmpcomma| macro to % represent it, and wrap the entire entry containing the comma within % |\xmpquote{|\dots|}| as shown below: % % \begin{verbatim} % pdfauthor={\xmpquote{Jack Napier\xmpcomma\ Jr.}, % \xmpquote{Edward Nigma\xmpcomma\ PhD}, % \xmpquote{Harvey Dent\xmpcomma\ Esq.}} % % pdfcontactaddress={Office of the President, % \xmpquote{Wayne Enterprises\xmpcomma\ Inc.}, % One Wayne Blvd} % \end{verbatim} % % As of version~2.2 of \pkgname{hyperxmp}, it is acceptable to use % |\xmpcomma| and |\xmpquote| within any \pkgname{hyperxmp} option, not % just in those in which a comma normally serves as a separator % (i.e.,~lists and multiline fields). Outside of cases in which a comma % serves as a separator, |\xmpcomma| is treated as an ordinary comma, % and |\xmpquote| returns its argument unmodified. Hence, it is % legitimate to use |\xmpcomma| and |\xmpquote| in cases like the % following % % \begin{verbatim} % pdfauthortitle={\xmpquote{Psychiatrist\xmpcomma\ Arkham Asylum}} % \end{verbatim} % % \noindent % (Like most \pkgname{hyperxmp} options, \optname{pdfauthortitle} % inserts its argument unmodified in an \acro{XMP} tag.) When in % doubt, use |\xmpcomma| and |\xmpquote|; it should always be safe % to do so. % % \DescribeMacro{\xmptilde} % Version~2.4 of \pkgname{hyperxmp} introduces a convenience macro % called |\xmptilde|. |\xmptilde| expands to a literal tilde character % instead of the nonbreaking space that ``|~|'' normally represents. % Use it to represent \acro{URL}s such as % \url{http://www.pakin.org/~scott/} (``|http://www.pakin.org/|\linebreak[0]|\xmptilde| % |scott/|'') in options such as \optname{baseurl}, % \optname{pdfcontacturl} and \optname{pdflicenseurl}. % % \usagenote{Unicode support} % \term{Unicode} support is provided via the \pkgname{hyperref} package. % If you specify \optname{unicode}|=true| either as a \pkgname{hyperref} % option or as an argument to the |\hypersetup| command, the document % can include \term{Unicode} characters in its \acro{XMP} fields. % % \usagenote{Automatically specified metadata} % \pkgname{hyperxmp} attempts to identify certain metadata % automatically. The hope is that in many cases, an author can simply % include |\usepackage{hyperxmp}| in a document's preamble and benefit % from a modicum of \acro{XMP} metadata with no additional effort. % % Currently, \optname{pdftitle} defaults to the document's title as % specified by |\title{|\dots|}|. \optname{pdfauthor} defaults to the % document's author(s) as specified by |\author{|\dots|}|. % \optname{pdfdate} defaults to the current date and time. % \optname{pdfmetalang} defaults to the same value as \optname{pdflang} % if non-empty, ``\xmpterm{x-default}'' otherwise. \pkgname{hyperxmp} % recognizes some class-specific metadata as well, such as that provided % via the \Koma\ letter classes (e.g.,~\clsname{scrlttr2}) and the % \ACMclass\ article class (\clsname{acmart}). % % If a document uses either the \pkgname{babel} or \pkgname{polyglossia} % packages it is recommended that it \emph{not} explicitly set % \optname{pdflang}. \optname{pdflang} accepts only a single language % name while \pkgname{hyperxmp} can automatically query \pkgname{babel} % and \pkgname{polyglossia} for a list of all languages used in the % document and include this list in an \acro{XMP} \xmpprop{dc:language} % element. % % \usagenote{Multilingual metadata} % \label{note:multilingual} % The \optname{pdfmetalang} option specifies the language in which the % document's metadata is written. It defaults to the value of % \optname{pdflang}, which specifies the document language. % \DescribeMacro{\XMPLangAlt} As of version~3.3 of \pkgname{hyperxmp}, % it is possible to include certain metadata---specifically, the % document's title, subject, and copyright statement---in more than one % language. The |\XMPLangAlt| macro provides this functionality. Usage % is as follows: % % \bigskip % \indent % |\XMPLangAlt| \marg{language} |{| \meta{option}|=|\meta{text},~\dots\ |}| % \bigskip % % \noindent % where \meta{language} is an \acro{ISO} \mbox{639-1} two-letter country % code with an optional \acro{ISO} \mbox{3166-1} two-letter region code % (e.g.,~``|en|'' for English or ``|en-US|'' for specifically US % English); \meta{option} is one of ``|pdftitle|'', ``|pdfsubject|'', or % ``|pdfcopyright|''; and \meta{text} is the text as expressed in the % specified language. By way, of example, the following code provides % the document title in English then specifies an alternative title to % use in four other languages: % % \begin{verbatim} % \hypersetup{% % pdfmetalang={en}, % pdftitle={English title} % } % \XMPLangAlt{de}{pdftitle={Deutscher Titel}} % \XMPLangAlt{fr}{pdftitle={Titre fran\c{c}ais}} % \XMPLangAlt{it}{pdftitle={Titolo italiano}} % \XMPLangAlt{rm}{pdftitle={Titel rumantsch}} % \end{verbatim} % % \usagenote{Expandable arguments} % \label{note:expandable} % All arguments passed to \pkgname{hyperxmp} options must be expandable, % in \tex\ terminology. This implies that any macros that are used in % arguments are limited to a relatively small set of operations (such as % conditionals and macro expansion) and must produce a string of text. % Code (such as macro definitions and arithmetic operations) will be % written to \acro{XMP} as code, not as the result of executing the % code. % % By way of example, the macros provided by the \pkgname{texdate} % package for typesetting dates are not expandable (at least at the time % of this writing). Hence, the |\printfdate{Y}| in the following code % snippet is not replaced by the current year, as one might expect: % % \begin{verbatim} % \usepackage{texdate} % \initcurrdate % \hypersetup{% % pdfcopyright={Copyright \textcopyright\ \printfdate{Y}, Scott Pakin} % } % \end{verbatim} % % \noindent % Rather, it generates a \xmpprop{dc:rights} tag of the form % ``\texttt{Copyright \textcopyright\ =2=0=by-1by=0\the\year, Scott % Pakin}''. The garbage in that line corresponds to the remnants of % the |\printfdate| code after expanding all of the \tex\ primitives and % certain other control sequences it uses to the empty string. For % example, ``|\global\advance\texd@yr| |by-1|'' expands to ``|by-1|''. % % It is not possible to determine a~priori whether or not a macro is % expandable. The best advice is to carefully inspect the \acro{XMP} % package in the output file to ensure that any macros used in arguments % to \pkgname{hyperxmp} options produced the expected output. % % \usagenote{Semi-automatic page ranges} % \label{note:page-counting} % Although \optname{pdfpagerange} is intended to refer to pages in the % final, published version of a document, it would be convenient for % them to be generated automatically when producing a standalone % \acro{PDF} file that is not intended to be incorporated into a book, % journal, or other publication (or if it is known that the pages will % not be renumbered for publication). One approach is to use the % \pkgname{totpages} package help generate \optname{pdfpagerange}. For % documents numbered from~1 to~$n$, a simple % % \Needspace{3\baselineskip} % \begin{verbatim} % \hypersetup{% % pdfpagerange={1-\ref*{TotPages}} % } % \end{verbatim} % % \noindent % should suffice. A bit more effort is needed for documents that change % numbering schemes, such as using lowercase Roman numerals for the % front matter and Arabic numerals for the main matter and back matter. % One approach is to use \cs{label} to mark the first and last page of % each numbering scheme and specify \optname{pdfpagerange} as in the % following: % % \Needspace{6\baselineskip} % \begin{verbatim} % \hypersetup{% % pdfpagerange={% % \pageref*{page:begin-front}-\pageref*{page:end-front},% % 1-\pageref*{TotPages}% % } % } % \end{verbatim} % % I don't know how unnumbered pages (e.g.,~blank pages and the title % page) are supposed to be handled. I suppose blank pages can be % omitted from \optname{pdfpagerange}, and the title page can be either % omitted or listed as \texttt{title}, for example. % % It appears that at least with version~2.00 of \pkgname{totpages}, the % |TotPages| label is not defined until after the |\begin{document}|. % Consequently, using |TotPages| within a \cs{hypersetup} invocation in % the document's preamble will produce ``|??|'' as the page count in the % \acro{XMP} packet. The solution is either to assign % \optname{pdfpagerange} after the |\begin{document}| or to ask % \LaTeX\ to do that on your behalf: % % \begin{verbatim} % \AtBeginDocument{% % \hypersetup{% % pdfpagerange={1-\ref*{TotPages}} % }% % } % \end{verbatim} % % \usagenote{Automatic computation of the PDF byte count} % \label{note:auto-byte-count} % % The \schema[PRISM Basic Metadata]{\protect\acro{PRISM} Basic Metadata} % schema~\cite{PRISM2012:basic-meta} defines a \xmpprop{prism:byteCount} % property that indicates the \acro{PDF} file size in bytes. % \pkgname{hyperxmp} computes this value automatically when the document % is built using \LuaLaTeX\ but not when using any other \TeX\ engine. % Note that \pkgname{hyperxmp} uses the file size from the % \emph{previous} run of \LuaLaTeX\ because the new \acro{PDF} file is % not yet complete. Consequently, one extra compilation is needed for % the byte count to converge relative to the the number of compilations % that would otherwise be required. % % Starting with \pkgname{hyperxmp}~v5.9, the \pkgname{hyperxmp} % distribution includes a Perl\index{Perl} script called % \progname{hyperxmp-add-bytecount} that edits a \acro{PDF} file in % place, adding or replacing the \xmpprop{prism:byteCount} property with % one that specifies the final file size.\footnote{The script was in % fact introduced with \progname{hyperxmp}~v5.8 and was then called % \texttt{add\_byteCount}.} Run the script as % ``\progname{hyperxmp-add-bytecount} \meta{filename.pdf}''. % % The \progname{latexmk} build tool can be configured to run % \progname{hyperxmp-add-bytecount} automatically every time a \acro{PDF} file % is generated. Simply add the code shown in Figure~\ref{fig:latexmkrc} % to your \progname{latexmk} configuration file. See % \href{http://mirrors.ctan.org/support/latexmk/latexmk.pdf}{the % \progname{latexmk} manual} for information on configuration-file % naming on different operating systems and explanations of the hook % functions used in Figure~\ref{fig:latexmkrc}. % % \changes{v5.8}{2020/11/18}{Distribute an % \protect\progname{add\_byteCount} script and document some sample % \protect\progname{latexmk} configuration code that invokes it. % Thanks to John Collins for providing both of those} % \changes{v5.9}{2020/11/22}{At Karl Berry's request, rename % \protect\progname{add\_byteCount} to the less generic-sounding % \protect\progname{hyperxmp-add-bytecount}} % % \iffalse %<*listings> % \fi \newsavebox{\latexmkrcbox} \begin{lrbox}{\latexmkrcbox} \begin{lstlisting}[ language=perl, columns=fullflexible, linewidth=19pc, frame=single, basicstyle=\footnotesize, showstringspaces=false, upquote=true, literate={-}{-}{1} ] foreach my $cmd ( "latex", "lualatex", "pdflatex", "xelatex", "dvipdf", "xdvipdfmx", "ps2pdf" ) { ${$cmd} = "internal mycmd ${$cmd}"; } sub mycmd { my $retval = system @_; if ( $$Pdest =~ /\.pdf$/ ) { system 'hyperxmp-add-bytecount', $$Pdest; } return $retval; } \end{lstlisting} \end{lrbox} % \iffalse % % \fi % % \begin{figure} % \centering % \usebox{\latexmkrcbox} % \caption{ \progname{latexmk} configuration-file code for % automatically invoking \progname{hyperxmp-add-bytecount} every time a % \acro{PDF} file is generated} % \label{fig:latexmkrc} % \end{figure} % % Even though \pkgname{hyperxmp} can compute the byte count % automatically when run from \LuaLaTeX, users of \progname{latexmk} % need to use configuration-file code like that shown in % Figure~\ref{fig:latexmkrc}. Otherwise, \progname{latexmk} would % compile the document one time too few for the byte count to % converge. It is recommended that those who use both \progname{latexmk} % and \pkgname{hyperxmp} configure \progname{latexmk} to be % \pkgname{hyperxmp}-aware. % % % \StopEventually{^^A % \section{Help Wanted} % % \paragraph{Comma handling} % Ideally, \texttt{\string\xmpquote} should automatically replace all % commas with \texttt{\string\xmpcomma}. Unfortunately, my \tex\ skills % are insufficient to pull that off. If you know a way to make % \texttt{\string\xmpquote\string{Hello, world\string}} work with both % \term{Unicode} and non-\term{Unicode} encodings and with all % \tex\ engines (\pdfTeX, \LuaTeX, \XeTeX, etc.), please send me a code % patch. % % \appendix % % \section{Sample XMP Packet} % \label{sec:sample-packet} % % The following is an example of a complete \acro{XMP} packet as may be % produced by \pkgname{hyperxmp}. This packet corresponds to the % metadata included in the sample \LaTeX\ document presented % \vpagerefrange{page:begin-sample-doc}{page:end-sample-doc}. For % clarity, metadata values, either specified explicitly by the document % or introduced automatically by \pkgname{hyperxmp}, are colored blue. % % \input{einstein-xmp} % % \begin{thebibliography}{99} % \bibitem{NISO2008:jav} % Beverley Acreman, Claire Bird, Catherine Jones, Peter McCracken, Cliff Morgan, % John Ober, Evan Owens, T.~Scott Plutchak, Bernie Rous, and Andrew Wray. % \newblock {J}ournal {A}rticle {V}ersions ({JAV}): Recommendations of the % {NISO}/{ALPSP} {JAV} {T}echnical {W}orking {G}roup. % \newblock Recommended practice, National Information Standards Organization, % Baltimore, Maryland, USA, April 2008. % \newblock ISBN~\mbox{978-1-880124-79-6}. % \newblock Available from % \url{https://www.niso.org/sites/default/files/2017-08/RP-8-2008.pdf}. % % \bibitem{Adobe2010:pdfmark} % Adobe Systems, Inc., San Jose, California. % \newblock \emph{{A}dobe {A}crobat~{X} {SDK} Help, pdfmark Reference}. % \newblock Available from % \url{http://www.adobe.com/devnet/acrobat/documentation.html}. % % \bibitem{Adobe1996:postscript} % {Adobe Systems, Inc.} % \newblock \emph{{P}ost{S}cript Language Reference Manual}. % \newblock Addison-Wesley, 2nd edition, January 1996, ISBN: \mbox{0-201-18127-4}. % % \bibitem{Adobe2008:PDF} % Adobe Systems, Inc., San Jose, California. % \newblock \emph{Document Management---Portable Document Format---Part 1: % PDF~1.7}, July 2008. % \newblock ISO \mbox{32000-1} standard document. Available from % \url{http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/pdf/pdfs/PDF32000_2008.pdf}. % % \bibitem{Adobe2012:XMP} % Adobe Systems, Inc., San Jose, California. % \newblock \emph{{XMP} Specification Part~1: Data model, Serialization, and Core % Properties}, April 2012. % \newblock Available from % \url{http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/xmp/pdfs/cc-201306/XMPSpecificationPart1.pdf}. % % \bibitem{DCMI2012:meta-terms} % DCMI Usage Board % \newblock \emph{DCMI Metadata Terms}, June~14, 2012. % \newblock Available from \url{http://dublincore.org/documents/dcmi-terms/}. % % \bibitem{Downes1994:ATB15} % Michael Downes. % \newblock Around the bend~\#15, answers, 4th (last) installment. % \newblock \href{news:comp.text.tex}{\texttt{comp.text.tex}} newsgroup posting, % January~3, 1994. % \newblock Archived by Google at % \url{http://groups.google.com/group/comp.text.tex/msg/7da7643b9e8f3b48}. % % \bibitem{PRISM2012:basic-meta} % International Digital Enterprise Alliance, Inc. % \newblock \emph{Publishing Requirements for Industry Standard Metadata, % Version~3.0: {PRISM} Basic Metadata Specification}, October~12, 2012. % \newblock Available from % \url{http://www.prismstandard.org/specifications/3.0/PRISM_Basic_Metadata_3.0.htm}. % % \bibitem{PRISM2012:cont-voc} % International Digital Enterprise Alliance, Inc. % \newblock \emph{Publishing Requirements for Industry Standard Metadata, % Version~3.0: {PRISM} Controlled Vocabularies Specification}, October~4, 2012. % \newblock Available from % \url{http://www.prismstandard.org/specifications/3.0/PRISM_CV_Spec_3.0.pdf}. % % \bibitem{IPTC2010:photo-meta} % International Press Telecommunications Council. % \newblock \emph{{IPTC} Photo Metadata: Core 1.1/Extension 1.1}, July 2010. % \newblock Revision~1. Available from % \url{http://www.iptc.org/std/photometadata/specification/IPTC-PhotoMetadata-201007_1.pdf}. % % \bibitem{IANA2011:lang-tags} % {Internet Assigned Numbers Authority}. % \newblock Language subtag registry, January~11, 2011. % \newblock Available from % \url{http://www.iana.org/assignments/language-subtag-registry}. % % \bibitem{Leach2005:uuid} % Paul~J. Leach, Michael Mealling, and Rich Salz. % \newblock A {U}niversally {U}nique {ID}entifier ({UUID}) {URN} namespace. % \newblock Request for Comments 4122, Internet Engineering Task Force, Network % Working Group, July 2005. % \newblock Category: Standards Track. Available from % \url{http://www.ietf.org/rfc/rfc4122.txt}. % % \bibitem{PDFA2008:xmp-props} % PDF/A Competence Center, Berlin, Germany. % \newblock \emph{{T}ech{N}ote~0008: Predefined {XMP} Properties in {PDF/A-1}}, % March~20, 2008. % \newblock Available from % \url{http://www.pdfa.org/wp-content/uploads/2011/08/tn0008_predefined_xmp_properties_in_pdfa-1_2008-03-20.pdf}. % % \bibitem{PDFA2008:ext-schemas} % PDF/A Competence Center, Berlin, Germany. % \newblock \emph{{T}ech{N}ote~0009: {XMP} Extension Schemas in {PDF/A-1}}, % March~20, 2008. % \newblock Available from % \url{http://www.pdfa.org/wp-content/uploads/2011/08/tn0009_xmp_extension_schemas_in_pdfa-1_2008-03-20.pdf}. % % \bibitem{Wolf1997:date-time} % Misha Wolf and Charles Wicksteed. % \newblock Date and time formats. % \newblock Note NOTE-datetime, World Wide Web Consortium (W3C), September~15, % 1997. % \newblock Available from \url{http://www.w3.org/TR/NOTE-datetime}. % \end{thebibliography} % } % % % \section{Implementation} % % This section presents the commented \LaTeX\ source code for % \pkgname{hyperxmp}. Read this section only if you want to learn how % \pkgname{hyperxmp} is implemented. % % \bigskip % % One thing to bear in mind when reading the \pkgname{hyperxmp} source % code is that different actions occur at different times throughout % document processing: % % \begin{enumerate} % \item |\usepackage{hyperxmp}|: \pkgname{hyperxmp} parses package % options, defines a number of commands, loads various helper % packages, and assigns default values to most \acro{XMP} fields. % % \item |\begin{document}|: \pkgname{hyperxmp} loads certain packages % such as \pkgname{hyperref} and \pkgname{ifdraft} and queries % natural-language information from \pkgname{babel} and % \pkgname{polyglossia} that becomes available only at the end of % the preamble. % % \item |\end{document}|: \pkgname{hyperxmp} finalizes certain data % that are known only at the end of the document, such as the page % count, and writes the \acro{XMP} packet to the \acro{PDF} file. % \end{enumerate} % % \iffalse %<*package> % \fi % % \subsection{Initial preparation} % \label{sec:initial-prep} % % \changes{v5.11}{2022/10/02}{Disable \protect\pkgname{hyperxmp} if % \LaTeX3 document metadata is available. Document metadata implies % the presence of PDF management, which completely breaks % \protect\pkgname{hyperxmp}} % \begin{macrocode} \IfDocumentMetadataTF{% \PackageWarning {hyperxmp} {Disabling hyperxmp because it is incompatible with PDF management} }{} \IfDocumentMetadataTF{\endinput}{} % \end{macrocode} % % \changes{v1.2}{2011/04/17}{Made the package compatible with \pkgname{ngerman}. % Thanks to Tobias Mueller for the bug report.} % % \begin{macro}{\hyxmp@dq@code} % The \pkgname{ngerman} package redefines % ``\,{\fontencoding{T1}\selectfont\textquotedbl}\,'' as an active % character, which causes problems for \pkgname{hyperxmp} when it tries % to use that character. We therefore save the double-quote character's % current category code in |\hyxmp@dq@code| and mark the character as % category code~12 (``other''). The original category code is restored % at the end of the package code (Section~\ref{sec:clean-up}). % \begin{macrocode} \edef\hyxmp@dq@code{\the\catcode`\"} \catcode`\"=12 % \end{macrocode} % \end{macro} % % \changes{v1.5}{2012/03/10}{Made the \protect\acro{XMP} inclusion more robust. % Thanks to Heiko Oberdiek for the bug report and suggested modifications.} % % \begin{macro}{\hyxmp@at@end} % The |\hyxmp@at@end| macro includes code at the end of the document. % When available (as is the case in most modern \tex\ backends), % \cs{AtEndDocument} works well enough. Otherwise, we invoke % \cs{AtEndDvi} from the \pkgname{atenddvi} package, which is robust but % requires an addition \LaTeX\ run. % \changes{v5.3}{2020/05/29}{Use \protect\cs{AtEndDocument} in all % \protect\tex\ back ends that provide it. Thanks to Nelson Posse % Lago for pointing out why \protect\pkgname{atenddvi} is best avoided % if possible} % \changes{v5.11}{2022/10/16}{Use \protect\cs{AddToHook} when available. % This addresses a bug reported on \protect\TeX\ StackExchange by joHub % and solved by Ulrike Fischer} % \begin{macrocode} \@ifundefined{AddToHook}{% \@ifundefined{AtEndDocument}{% \RequirePackage{atenddvi} \let\hyxmp@at@end=\AtEndDvi }{% \let\hyxmp@at@end=\AtEndDocument } }{% \def\hyxmp@at@end{\AddToHook{shipout/lastpage}} } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@set@jobname} % Given an expanded \cs{jobname} followed by \cs{relax}, invoke the % \cs{hyxmp@set@jobname@dbl} macro if the job name is surrounded by % double quotes and the \cs{hyxmp@set@jobname@plain} macro otherwise. % \begin{macrocode} \def\hyxmp@set@jobname#1\relax{% \@ifnextchar"{\hyxmp@set@jobname@dbl}{\hyxmp@set@jobname@plain}#1\relax } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@set@jobname@dbl} % \begin{macro}{\hyxmp@jobname} % Set \cs{hyxmp@jobname} to to |#1|, discarding the surrounding double % quotes. % \begin{macrocode} \def\hyxmp@set@jobname@dbl"#1"\relax{\xdef\hyxmp@jobname{#1}} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\hyxmp@set@jobname@plain} % \begin{macro}{\hyxmp@jobname} % Set \cs{hyxmp@jobname} to to |#1|. % \begin{macrocode} \def\hyxmp@set@jobname@plain#1\relax{\xdef\hyxmp@jobname{#1}} % \end{macrocode} % \end{macro} % \end{macro} % % Define \cs{hyxmp@jobname} as a sanitized version of \cs{jobname}. The % problem with using \cs{jobname} directly is that it surrounds the % filename with double quotes if it contains a space character. For % example, a source file named \texttt{my-file.tex} results in a % \cs{jobname} of ``\texttt{my-file}'', but a source file named % \texttt{my file.tex} results in a \cs{jobname} of ``|"my file"|''. % Trying to access |"my file".log| (as is done on % page~\pageref{page:jobname-log}) will fail because the filename does % not in fact contain literal double quotes. % \changes{v5.5}{2020/07/28}{Correctly handle source files with spaces % in their name. Thanks to Peter Dyballa for the bug report} % \begin{macrocode} \expandafter\hyxmp@set@jobname\jobname\relax % \end{macrocode} % % \begin{macro}{\hyxmp@aep@toks} % In order for \pkgname{hyperxmp} to be loaded safely during % \cs{AtEndPreamble} we need to ensure that we perform no % \cs{AtEndPreamble} actions until all top-level macro definitions have % been made. The most straightforward approach would be to move all of % \pkgname{hyperxmp}'s \cs{AtEndPreamble} stanzas to the end of the % package. However, this degrades readability of the source code. For % instance, an \cs{AtEndPreamble} stanza related to integration with % \pkgname{hyperref} could no longer appear in the ``Integration with % \pkgname{hyperref}'' section (Section~\ref{sec:hyperref-int}). Hence, % we instead store in a token list, \cs{hyxmp@aep@toks}, each % \cs{AtEndPreamble} stanza as we encounter it. This token list is % evaluated as one of the package's final actions % (Section~\ref{sec:clean-up}). % \begin{macrocode} \newtoks{\hyxmp@aep@toks} % \end{macrocode} % \end{macro} % % % \subsection{Integration with \textsf{hyperref}} % \label{sec:hyperref-int} % % An important design decision underlying \pkgname{hyperxmp} is that the % package should integrate seamlessly with \pkgname{hyperref}. To that % end, \pkgname{hyperxmp} takes \acro{XMP} metadata from % \pkgname{hyperref}'s \optname{baseurl}, \optname{pdfauthor}, % \optname{pdfkeywords}, \optname{pdflang}, \optname{pdfproducer}, % \optname{pdfsubject}, \optname{pdftrapped}, and \optname{pdftitle} % options. It also introduces a number of new options, which are listed % \vpagerefrange[above]{page:begin-new-options}{page:end-new-options}. % For consistency with \pkgname{hyperref}'s document-metadata naming % conventions (which are in turn based on \LaTeX's document-metadata % naming conventions), we do not prefix metadata-related macro names % with our package-specific |\hyxmp@| prefix. That is, we use names % like |\@pdfcopyright| instead of |\hyxmp@pdfcopyright|. % % \bigskip % % We load a bunch of helper packages: \pkgname{kvoptions} for % package-option processing, \pkgname{pdfescape} and \pkgname{stringenc} % for re-encoding \term{Unicode} strings, \pkgname{intcalc} for % performing integer calculations (division and modulo), \pkgname{iftex} % for determining which \tex\ engine is being used, \pkgname{ifmtarg} % for testing if a macro argument is empty or all spaces, % \pkgname{etoolbox} for dynamically patching existing commands % (specifically, \pkgname{hyperref}'s |\PDF@FinishDoc|), and % \pkgname{ifthen} for convenient string comparisons. % \begin{macrocode} \RequirePackage{kvoptions} \RequirePackage{pdfescape} \RequirePackage{stringenc} \RequirePackage{intcalc} \RequirePackage{iftex} \RequirePackage{ifmtarg} \RequirePackage{etoolbox} \RequirePackage{ifthen} % \end{macrocode} % % There are a few places where \pkgname{hyperxmp} can take advantage of % \LuaTeX\ features. To simplify the use of \LuaTeX\ we load the % \pkgname{luacode} package. % \begin{macrocode} \ifLuaTeX \RequirePackage{luacode} \fi % \end{macrocode} % % \begin{macro}{\@ifmtargexp} % \begin{macro}{\@ifnotmtargexp} % |\@ifmtarg| and |\@ifnotmtarg| do not expand their first argument. % Define |\@ifmtargexp| and |\@ifnotmtargexp| as expanding versions of % those macros. % \begin{macrocode} \def\@ifmtargexp#1{\expandafter\@ifmtarg\expandafter{#1}} \def\@ifnotmtargexp#1{\expandafter\@ifnotmtarg\expandafter{#1}} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\@if@def@and@nonempty} % This macro combines \cs{@ifundefined} and \cs{@ifmtargexp}. If the % macro named |#1| is both defined and non-empty, evaluate~|#2|. % Otherwise, evaluate~|#3|. % \changes{v5.3}{2020/06/07}{Added this macro} % \begin{macrocode} \newcommand*{\@if@def@and@nonempty}[3]{% \@ifundefined{#1}{#3}{% \expandafter\@ifmtargexp\expandafter{\csname#1\endcsname}{#3}{#2}% }% } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@pdfstringdef} % \begin{macro}{\hyxmp@textunderscore} % Because \pkgname{hyperxmp} uses underscores to represent hard spaces, % we need ``|\_|'' to map initially to something other than an % underscore, in particular the \acro{ASCII} \acro{NAK}~(|^^U|) % character. To accomplish this, we wrap \pkgname{hyperref}'s % |\pdfstringdef| macro with our own version that temporarily does the % proper substitution. Later in the execution, after underscores have % been replaced with spaces, we replace \acro{NAK} characters with % underscores. % \changes{v2.5}{2014/06/19}{Added this macro} % \begin{macrocode} \newcommand{\hyxmp@pdfstringdef}[2]{% \let\hyxmp@textunderscore=\textunderscore \let\textunderscore=\hyxmp@uscore \pdfstringdef{#1}{#2}% \let\textunderscore=\hyxmp@textunderscore } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\@pdfdatetime} % Prepare to store the document's date and (optionally) time. Whether % specified by the author in \acro{XMP} format or \acro{PDF} format % (see Section~\ref{sec:date-manip}) we always store |\@pdfdatetime| as % an \acro{XMP}-format string. % \begin{macrocode} \def\@pdfdatetime{} \define@key{Hyp}{pdfdate}{% \begingroup \Hy@unicodefalse % \end{macrocode} % \begin{macro}{\next} % Expand \optname{pdfdate}'s argument and convert it to \acro{XMP} format. % \begin{macrocode} \edef\next{% \noexpand\hyxmp@pdfstringdef\noexpand\@pdfdatetime{% \noexpand\hyxmp@as@xmp@date{#1}}% }% \next \endgroup } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\@pdfmetadatetime} % Prepare to store the document's metadata date and (optionally) time. % Whether specified by the author in \acro{XMP} format or \acro{PDF} % format (see Section~\ref{sec:date-manip}) we always store % |\@pdfmetadatetime| as an \acro{XMP}-format string. % \begin{macrocode} \def\@pdfmetadatetime{} \define@key{Hyp}{pdfmetadate}{% \begingroup \Hy@unicodefalse % \end{macrocode} % \begin{macro}{\next} % Expand \optname{pdfmetadate}'s argument and convert it to \acro{XMP} format. % \begin{macrocode} \edef\next{% \noexpand\hyxmp@pdfstringdef\noexpand\@pdfmetadatetime{% \noexpand\hyxmp@as@xmp@date{#1}}% }% \next \endgroup } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\@pdfcopyright} % Prepare to store the document's copyright statement. % \begin{macrocode} \def\@pdfcopyright{} \define@key{Hyp}{pdfcopyright}{\hyxmp@pdfstringdef\@pdfcopyright{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\@pdftype} % Prepare to store the document's logical type, which defaults to ``|Text|''. % \begin{macrocode} \def\@pdftype{Text} \define@key{Hyp}{pdftype}{\hyxmp@pdfstringdef\@pdftype{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\@pdflicenseurl} % Prepare to store the \acro{URL} containing the document's license % agreement. % \begin{macrocode} \def\@pdflicenseurl{} \define@key{Hyp}{pdflicenseurl}{\hyxmp@pdfstringdef\@pdflicenseurl{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\@pdfauthortitle} % Prepare to store the author's position/title (e.g.,~Staff Writer). % \begin{macrocode} \def\@pdfauthortitle{} \define@key{Hyp}{pdfauthortitle}{\hyxmp@pdfstringdef\@pdfauthortitle{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\@pdfcaptionwriter} % Prepare to store the name of the person who inserted the % \pkgname{hyperxmp} metadata. % \begin{macrocode} \def\@pdfcaptionwriter{} \define@key{Hyp}{pdfcaptionwriter}{\hyxmp@pdfstringdef\@pdfcaptionwriter{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\@pdfmetalang} % Prepare to store the natural language of the document's metadata, % typically as an \acro{ISO}~\mbox{639-1} two-letter abbreviation. % \begin{macrocode} \def\@pdfmetalang{} \define@key{Hyp}{pdfmetalang}{\hyxmp@pdfstringdef\@pdfmetalang{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@no@bad@parts} % Complain about a bad \optname{pdfapart} or \optname{pdfuapart} if given % trailing non-digits after a part number. % \begin{macrocode} \def\hyxmp@no@bad@parts#1\relax{% \@ifnotmtarg{#1}{% \PackageWarning{hyperxmp}{pdfapart and pdfuapart must be numeric}% }% } % \end{macrocode} % \end{macro} % % \begin{macro}{\@hyxmp@count} % \changes{v5.11}{2022/10/02}{Added this macro to fix a bug with % \protect\optname{pdfapart}. Thanks to John H. Lienhard and % Kartik Singhal for their bug reports} % Define a temporary counter. The code previously used \cs{@tempcnta}, % but this is no longer safe within \cs{pdfstringdef} as of more recent % versions of \pkgname{hyperref}. % \begin{macrocode} \newcount\@hyxmp@count % \end{macrocode} % \end{macro} % % \begin{macro}{\@pdfapart} % Prepare to store the \acro{PDF/A} part ID, which defaults to~``1'' % if \optname{pdfa} is passed to \pkgname{hyperref}. % \begin{macrocode} \def\@pdfapart{} \define@key{Hyp}{pdfapart}{% \afterassignment\hyxmp@no@bad@parts\@hyxmp@count=0#1\relax \hyxmp@pdfstringdef\@pdfapart{\the\@hyxmp@count}% } % \end{macrocode} % \end{macro} % % \begin{macro}{\@pdfaconformance} % Prepare to store the \acro{PDF/A} conformance ID, which defaults to~``b'' % if \optname{pdfa} is passed to \pkgname{hyperref} and |\@pdfapart| is % empty. % \begin{macrocode} \def\@pdfaconformance{} \define@key{Hyp}{pdfaconformance}{% \uppercase{\hyxmp@pdfstringdef\@pdfaconformance{#1}}% } % \end{macrocode} % \end{macro} % % \begin{macro}{\@pdfuapart} % Prepare to store the \acro{PDF/UA} part ID. % \begin{macrocode} \def\@pdfuapart{} \define@key{Hyp}{pdfuapart}{% \afterassignment\hyxmp@no@bad@parts\@hyxmp@count=0#1\relax \hyxmp@pdfstringdef\@pdfuapart{\the\@hyxmp@count}% } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@set@pdfx@major} % Parse \optname{pdfxstandard} as ``|PDF/X-|\meta{major}\meta{other}'', % setting |\hyxmp@pdfx@major| to \meta{major}. % \begin{macrocode} \newcommand*{\hyxmp@set@pdfx@major}[1]{\hyxmp@set@pdfx@major@i#1!} % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@set@pdfx@major@i} % This is the first helper macro for |\hyxmp@set@pdfx@major|. It stores % the \acro{PDF/X} major version in |\@hyxmp@count|. % \begin{macrocode} \def\hyxmp@set@pdfx@major@i PDF/X-{% \afterassignment\hyxmp@set@pdfx@major@ii \@hyxmp@count=% } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@set@pdfx@major@ii} % \begin{macro}{\hyxmp@pdfx@major} % This is the second helper macro for |\hyxmp@set@pdfx@major|. It % copies the \acro{PDF/X} major version from |\@hyxmp@count| to % |\@hyxmp@pdfx@major| and discards the rest of the \acro{PDF/X} % standard string. % \begin{macrocode} \def\hyxmp@set@pdfx@major@ii#1!{% \edef\hyxmp@pdfx@major{\the\@hyxmp@count}% } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\hyxmp@check@std} % \changes{v5.0}{2020/03/10}{Added this macro} % Compare a user-provided string to a fixed string. (Assumption: Both % are names of \acro{PDF/X} standard versions.) If they match, undefine % |\next|, which we assume was previously defined to issue an % ``unrecognized standard'' warning message. % \begin{macrocode} \newcommand*\hyxmp@check@std[2]{% \ifthenelse{\equal{#1}{#2}}% {\global\let\next=\relax}% {}% }% % \end{macrocode} % \end{macro} % % \begin{macro}{\@pdfxstandard} % Prepare to store the \acro{PDF/X} standard. % \changes{v5.0}{2020/03/10}{Added this macro} % \begin{macrocode} \def\@pdfxstandard{} \def\hyxmp@pdfx@major{} \define@key{Hyp}{pdfxstandard}{% \hyxmp@pdfstringdef\@pdfxstandard{#1}% % \end{macrocode} % \begin{macro}{\next} % Issue a warning message if the \acro{PDF/X} standard named by the user % does not appear in a list of known \acro{PDF/X} standards. This is to % caution the user that \pkgname{hyperxmp} generates standard-specific % \acro{XMP} metadata and it can only guess at the correct format for % new standard versions. (See the comments on % page~\pageref{page:pdfx-id-schema} above the definition of % |\hyxmp@pdfx@id@schema|, for example.) % \begin{macrocode} \gdef\next{% \PackageWarning{hyperxmp}{Unrecognized PDF/X standard `#1'}% }% \hyxmp@check@std{#1}{PDF/X-1a:2001}% \hyxmp@check@std{#1}{PDF/X-1a:2003}% \hyxmp@check@std{#1}{PDF/X-3:2002}% \hyxmp@check@std{#1}{PDF/X-3:2003}% \hyxmp@check@std{#1}{PDF/X-4}% \hyxmp@check@std{#1}{PDF/X-4p}% \hyxmp@check@std{#1}{PDF/X-5g}% \hyxmp@check@std{#1}{PDF/X-5n}% \hyxmp@check@std{#1}{PDF/X-5pg}% \next % \end{macrocode} % \begin{macro}{\hyxmp@pdfx@major} % Parse the \acro{PDF/X} major version number from % \optname{pdfxstandard} and assign it to |\hyxmp@pdfx@major|. % \begin{macrocode} \hyxmp@set@pdfx@major{#1}% } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\@pdfsource} % Prepare to store the document's source, which defaults to the value of % |\jobname|. % \changes{v3.3}{2017/07/16}{Added this macro and the corresponding % \protect\optname{pdfsource} option, at Niklas Beisert's request} % \begin{macrocode} \edef\@pdfsource{\hyxmp@jobname.tex} \define@key{Hyp}{pdfsource}{\hyxmp@pdfstringdef\@pdfsource{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@DocumentID} % Prepare to store a \acro{UUID} that represents the document. % \changes{v3.5}{2018/11/27}{Added the \protect\optname{pdfdocumentid} % option, at Michael Osipov's request} % \begin{macrocode} \def\hyxmp@DocumentID{} \define@key{Hyp}{pdfdocumentid}{\hyxmp@pdfstringdef\hyxmp@DocumentID{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@InstanceID} % Prepare to store a \acro{UUID} that represents the current instance of % the document. % \changes{v3.5}{2018/11/27}{Added the \protect\optname{pdfinstanceid} % option, at Michael Osipov's request} % \begin{macrocode} \def\hyxmp@InstanceID{} \define@key{Hyp}{pdfinstanceid}{\hyxmp@pdfstringdef\hyxmp@InstanceID{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\@pdfversionid} % Prepare to store a string that represents the current version of % the document. It defaults to ``|1|''. % \begin{macrocode} \def\@pdfversionid{1} \define@key{Hyp}{pdfversionid}{\hyxmp@pdfstringdef\@pdfversionid{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\ifdraft} % \changes{v5.2}{2020/04/18}{Define \protect\cs{ifdraft} only locally, at % Niklas Beisert's request} % \changes{v5.6}{2020/10/05}{Make conditional the loading of the % \protect\pkgname{ifdraft} package. Thanks to Tobias Pape for % reporting the incompatibility between \protect\pkgname{hyperxmp} and % \protect\pkgname{ifdraft}} % \changes{v5.13}{2024/03/17}{Rewrite \protect\pkgname{ifdraft} handling % to avoid loading a package within a group, which \protect\LaTeX\ % soon will stop supporting. Thanks to Ulrike Fischer and Boris Veytsman % for bringing this to my attention} % \begin{macro}{\next} % Use the \pkgname{ifdraft} package to determine if this is a draft or % final document. The challenge here is that we want to use % \pkgname{ifdraft} if it's already loaded, load it if not, and not % break any incompatible, author-defined \cs{ifdraft} macros that may % occur either before or after the |\usepackage{hyperxmp}|. Our % solution works as follows: % % \begin{itemize} % \item If \pkgname{ifdraft} is already loaded, \cs{next} is defined % as a no-op. % \item If \pkgname{ifdraft} is not (yet) loaded, the code backs up % then undefines \cs{ifdraft}, which may be author-defined. It then % loads \pkgname{ifdraft} and defines \cs{next} to ``unload'' the % package by setting the package's author-visible commands to % \cs{relax}. % \item Below, after \cs{ifdraft} is used to define % \cs{@pdfrendition}, \cs{next} is invoked to unload a % \pkgname{hyperxmp}-loaded \pkgname{ifdraft}. Finally, \cs{ifdraft} % is restored to its original definition. % \end{itemize} % \begin{macrocode} \let\hyxmp@orig@ifdraft=\ifdraft \@ifpackageloaded{ifdraft}{% \let\next=\relax }{% \let\ifdraft=\relax \RequirePackage{ifdraft}% \def\next{% \expandafter\let\csname ver@ifdraft.sty\endcsname=\relax \let\ifdraft=\relax \let\ifoptiondraft=\relax \let\ifoptionfinal=\relax }% }% % \end{macrocode} % \begin{macro}{\@pdfrendition} % \changes{v5.0}{2020/02/27}{Added the \protect\optname{pdfrendition} % option} % Prepare to store a tag describing how this rendition of the document % differs from the master. The default value is |default|, which % indicates the master document, except in the case of % |\documentclass[draft]|, for which |\@pdfrendition| defaults to % |draft|. % \begin{macrocode} \ifdraft{% \def\@pdfrendition{draft}% }{% \def\@pdfrendition{default}% } \next \let\ifdraft=\hyxmp@orig@ifdraft \define@key{Hyp}{pdfrendition}{\hyxmp@pdfstringdef\@pdfrendition{#1}} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\@pdfpublication} % Prepare to store the name of the publication in which the % document was published. % \begin{macrocode} \def\@pdfpublication{} \define@key{Hyp}{pdfpublication}{\hyxmp@pdfstringdef\@pdfpublication{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\@pdfpubtype} % Prepare to store the type of the publication in which the % document was published. % \begin{macrocode} \def\@pdfpubtype{} \define@key{Hyp}{pdfpubtype}{\hyxmp@pdfstringdef\@pdfpubtype{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\@pdfbytes} % Prepare to store the size of the file in bytes. % \begin{macrocode} \def\@pdfbytes{} \define@key{Hyp}{pdfbytes}{\hyxmp@pdfstringdef\@pdfbytes{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\@pdfnumpages} % Prepare to store the number of pages in the file. % \begin{macrocode} \def\@pdfnumpages{} \define@key{Hyp}{pdfnumpages}{\hyxmp@pdfstringdef\@pdfnumpages{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\@pdfissn} % Prepare to store the \acro{ISSN} of the publication in which the % document was published. % \begin{macrocode} \def\@pdfissn{} \define@key{Hyp}{pdfissn}{\hyxmp@pdfstringdef\@pdfissn{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\@pdfeissn} % Prepare to store the \acro{ISSN} of the electronic version of the % publication in which the document was published. % \begin{macrocode} \def\@pdfeissn{} \define@key{Hyp}{pdfeissn}{\hyxmp@pdfstringdef\@pdfeissn{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\@pdfisbn} % Prepare to store the \acro{ISBN} of the publication in which the % document was published. % \begin{macrocode} \def\@pdfisbn{} \define@key{Hyp}{pdfisbn}{\hyxmp@pdfstringdef\@pdfisbn{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\@pdfbookedition} % Prepare to store the edition of the book in which the document % was published. % \begin{macrocode} \def\@pdfbookedition{} \define@key{Hyp}{pdfbookedition}{\hyxmp@pdfstringdef\@pdfbookedition{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\@pdfpublisher} % Prepare to store the name of the document's publisher. % \begin{macrocode} \def\@pdfpublisher{} \define@key{Hyp}{pdfpublisher}{\hyxmp@pdfstringdef\@pdfpublisher{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\@pdfvolumenum} % Prepare to store the volume identifier of the publication in which the % document was published. % \begin{macrocode} \def\@pdfvolumenum{} \define@key{Hyp}{pdfvolumenum}{\hyxmp@pdfstringdef\@pdfvolumenum{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\@pdfissuenum} % Prepare to store the identifier of the issue within a volume of the % publication in which the document was published. % \begin{macrocode} \def\@pdfissuenum{} \define@key{Hyp}{pdfissuenum}{\hyxmp@pdfstringdef\@pdfissuenum{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\@pdfpagerange} % Prepare to store the document's range of pages within the publication % in which the document was published. % \begin{macrocode} \def\@pdfpagerange{} \define@key{Hyp}{pdfpagerange}{\hyxmp@pdfstringdef\@pdfpagerange{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\@pdfdoi} % Prepare to store a \acro{DOI} that represents the current instance of % the document. % \begin{macrocode} \def\@pdfdoi{} \define@key{Hyp}{pdfdoi}{\hyxmp@pdfstringdef\@pdfdoi{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\@pdfurl} % Prepare to store a \acro{URL} that represents where the document % can be found. Note that we do not prepend \optname{baseurl} to % the value provided. % \begin{macrocode} \def\@pdfurl{} \define@key{Hyp}{pdfurl}{\hyxmp@pdfstringdef\@pdfurl{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\@pdfidentifier} % Prepare to store an identifier that uniquely represents the document. % \begin{macrocode} \def\@pdfidentifier{} \define@key{Hyp}{pdfidentifier}{\hyxmp@pdfstringdef\@pdfidentifier{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\@pdfsubtitle} % Prepare to store the document's subtitle. % \begin{macrocode} \def\@pdfsubtitle{} \define@key{Hyp}{pdfsubtitle}{\hyxmp@pdfstringdef\@pdfsubtitle{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\@pdfpubstatus} % Prepare to store the document's journal article version. % \begin{macrocode} \def\@pdfpubstatus{} \define@key{Hyp}{pdfpubstatus}{\hyxmp@pdfstringdef\@pdfpubstatus{#1}} % \end{macrocode} % \end{macro} % % The following eight macros---|\@pdfcontactaddress|, % |\@pdfcontactcity|, |\@pdfcontactregion|, |\@pdfcontactpostcode|, % |\@pdfcontactcountry|, |\@pdfcontactphone|, |\@pdfcontactemail|, and % |\@pdfcontacturl|---together specify how to contact the person or % institution responsible for the document. % % \begin{macro}{\@pdfcontactaddress} % Prepare to store a street address for the document's contact % person\slash institution. The \acro{IPTC} standard defines this as % follows: % % \begin{quote} % The contact information address part. Comprises an optional company % name and all required information to locate the building or postbox % to which mail should be sent. To that end, the address is a % multiline field. % \end{quote} % % For consistency with the rest of \pkgname{hyperxmp}, we use commas to % separate terms, in this case, lines of the address. The author can % use |\xmpquote| and |\xmpcomma| to include literal commas. % \begin{macrocode} \def\@pdfcontactaddress{} \define@key{Hyp}{pdfcontactaddress}{% \let\xmpcomma=\hyxmp@comma \def\xmpquote##1{##1}% \hyxmp@pdfstringdef\@pdfcontactaddress{#1}% \def\xmpcomma{,}% \let\xmpquote=\relax } % \end{macrocode} % \end{macro} % % \begin{macro}{\@pdfcontactcity} % Prepare to store the city of the document's contact person\slash % institution. % \begin{macrocode} \def\@pdfcontactcity{} \define@key{Hyp}{pdfcontactcity}{\hyxmp@pdfstringdef\@pdfcontactcity{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\@pdfcontactregion} % Prepare to store the state or province of the document's contact % person\slash institution. % \begin{macrocode} \def\@pdfcontactregion{} \define@key{Hyp}{pdfcontactregion}{\hyxmp@pdfstringdef\@pdfcontactregion{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\@pdfcontactpostcode} % Prepare to store the postal code of the document's contact % person\slash institution. % \begin{macrocode} \def\@pdfcontactpostcode{} \define@key{Hyp}{pdfcontactpostcode}{\hyxmp@pdfstringdef\@pdfcontactpostcode{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\@pdfcontactcountry} % Prepare to store the country of the document's contact person\slash % institution. % \begin{macrocode} \def\@pdfcontactcountry{} \define@key{Hyp}{pdfcontactcountry}{\hyxmp@pdfstringdef\@pdfcontactcountry{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\@pdfcontactphone} % Prepare to store the telephone number of the document's contact % person\slash institution. % \begin{macrocode} \def\@pdfcontactphone{} \define@key{Hyp}{pdfcontactphone}{\hyxmp@pdfstringdef\@pdfcontactphone{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\@pdfcontactemail} % Prepare to store the email address of the document's contact % person\slash institution. % \begin{macrocode} \def\@pdfcontactemail{} \define@key{Hyp}{pdfcontactemail}{\hyxmp@pdfstringdef\@pdfcontactemail{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\@pdfcontacturl} % Prepare to store the \acro{URL} of the document's contact person\slash % institution. % \begin{macrocode} \def\@pdfcontacturl{} \define@key{Hyp}{pdfcontacturl}{\hyxmp@pdfstringdef\@pdfcontacturl{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@no@info@lists} % Suppress \pkgname{hyperref} from writing \pdfterm{Author} and % \pdfterm{Keywords} into the \pdfterm{Info} dictionary. This prevents % conflicts between the \acro{PDF} metadata and the \acro{XMP} metadata % that cause \acro{PDF/A} validation to fail. The \acro{PDF} metadata % can be restored by passing the \optname{keeppdfinfo} option to % |\hypersetup|. % \changes{v4.0}{2019/03/31}{Added this macro} % \changes{v5.0}{2020/03/10}{Renamed this macros from % \protect\cs{hyxmp@suppress@pdf@metadata} and rewrote it to replace, % if possible, only \protect\pdfterm{Author} and \protect\pdfterm{Keywords}} % \begin{macrocode} \def\hyxmp@no@info@lists{% % \end{macrocode} % \begin{macro}{\hyxmp@suppress@pdf@info} % \begin{macro}{\next} % If |\patchcmd| fails for any reason---most likely, a modification to % the \pkgname{hyperref} package---our fallback is to prevent % \pkgname{hyperref} from writing \emph{any} data to the \acro{PDF} % \pdfterm{Info} dictionary. % \begin{macrocode} \def\hyxmp@suppress@pdf@info{% \global\let\PDF@FinishDoc=\@empty \PackageWarningNoLine{hyperxmp}{% Suppressing the _entire_ PDF Info dictionary.\MessageBreak Please notify the hyperxmp maintainer% }% }% \let\next=\relax \patchcmd {\PDF@FinishDoc}% {/Author(\@pdfauthor)}% {}% {}% {\let\next=\hyxmp@suppress@pdf@info}% \patchcmd {\PDF@FinishDoc}% {/Keywords(\@pdfkeywords)}% {}% {}% {\let\next=\hyxmp@suppress@pdf@info}% \next } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \begin{macrocode} \define@key{Hyp}{keeppdfinfo}[true]{% \gdef\hyxmp@no@info@lists{}% } % \end{macrocode} % % \changes{v2.1}{2012/09/16}{Enabled \protect\pkgname{hyperxmp} and % \protect\pkgname{hyperref} to be loaded in either order. This addresses % a bug report by Yury Donskoy} % % We need to capture list arguments (viz.~\optname{pdfauthor} and % \optname{pdfkeywords}) before \pkgname{hyperref} converts them to % \term{PDFDocEncoding}. Otherwise, |\xmpcomma| is permanently replaced % with a comma, and we lose our ability to change it to a % |\hyxmp@comma|. We therefore need to augment \pkgname{hyperref}'s % option processing with our own. Because \pkgname{hyperref} has not % yet been loaded we need to ensure that our augmentation gets loaded in % the future: after the |\usepackage{hyperref}| but before options are % passed to that package. % % For lack of a better approach, \pkgname{hyperxmp} redefines % |\ProcessKeyvalOptions| to alter the way \pkgname{hyperref} processes % \optname{pdfauthor} and \optname{pdfkeywords}. This is somewhat % heavy-handed as it gets executed for \emph{every} subsequently loaded % package that uses |\ProcessKeyvalOptions|, but at least it does what % we need. \pkgname{hyperxmp} also redefines |\hypersetup| to do the % same thing. This is required in case \pkgname{hyperref} is loaded % before \pkgname{hyperxmp}. % % \changes{v5.12}{2023/09/10}{Require that \pkgname{hyperref} be loaded % before \pkgname{hyperxmp}} % \begin{center} % \fbox{% % \begin{minipage}{0.75\linewidth} % \paragraph{New in v5.12} % \pkgname{hyperref} must be loaded \emph{before} \pkgname{hyperxmp}. % This is because recent changes in \pkgname{hyperref} and the % \LaTeX\ kernel prevent \pkgname{hyperxmp} from hooking into % \pkgname{hyperref}'s internals if \pkgname{hyperref} is loaded % first. % \end{minipage}% % } % \end{center} % % \begin{macrocode} \@ifpackageloaded{hyperref}{% }{% \PackageError{hyperxmp}% {hyperref must be loaded before hyperxmp}% {Recent versions of hyperref and the LaTeX kernel inhibit\MessageBreak hyperxmp's ability to hook into hyperref's internals unless\MessageBreak hyperref is loaded first.} } % \end{macrocode} % % \begin{macro}{\hyxmp@pdfauthor} % \begin{macro}{\hyxmp@pdfkeywords} % Prepare to store the name of the author and a list of keywords. % \begin{macrocode} \def\hyxmp@pdfauthor{} \def\hyxmp@pdfkeywords{} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\hyxmp@redefine@Hyp} % If not already redefined, redefine \pkgname{hyperref}'s % \optname{pdfauthor} and \optname{pdfkeywords} options to properly % handle |\xmpcomma| and |\xmpquote|. % \changes{v2.1}{2012/09/16}{Added this macro} % \begin{macrocode} \newcommand*{\hyxmp@redefine@Hyp}{% % \end{macrocode} % \begin{macro}{\hyxmp@Hyp@pdfauthor} % Store the old definition of |\KV@Hyp@pdfauthor| in % |\hyxmp@Hyp@pdfauthor|, but only if we see that |\KV@Hyp@pdfauthor| is % defined and |\hyxmp@Hyp@pdfauthor| isn't. Otherwise, we'd be defining % |\hyxmp@Hyp@pdfauthor| in terms of itself and creating an infinite % loop. % \begin{macrocode} \@ifundefined{KV@Hyp@pdfauthor}{}{% \@ifundefined{hyxmp@Hyp@pdfauthor}{% \expandafter\let\expandafter\hyxmp@Hyp@pdfauthor \csname KV@Hyp@pdfauthor\endcsname }{}% }% % \end{macrocode} % \Needspace{6\baselineskip} % \begin{macro}{\KV@Hyp@pdfauthor} % \begin{macro}{\xmpcomma} % \begin{macro}{\xmpquote} % \begin{macro}{\hyxmp@and} % \begin{macro}{\and} % \begin{macro}{\hyxmp@pdfauthor} % \begin{macro}{\@pdfauthor} % Redefine |\KV@Hyp@pdfauthor| to process its argument twice. The first % time, |\xmpcomma| is defined as a placeholder character % (|\hyxmp@comma|) and |\xmpquote| as the identity function. The result % is stored in |\hyxmp@pdfauthor| for use in structured lists (those % surrounding each entry with ||). The second time, |\xmpcomma| % is defined as an ordinary comma, and |\xmpquote| is defined as a macro % that puts its argument within double quotes. The result is stored in % |\@pdfauthor| for use in unstructured lists (those in which the entire % list appears within a single pair of tags). In case % \optname{pdfauthor} is left unspecified and we copy |\author|'s % argument to \optname{pdfauthor}, we temporarily redefine |\and| as the % list separator when producing a structured list and as ``|and|'' when % producing an unstructured list. % \begin{macrocode} \define@key{Hyp}{pdfauthor}{% \let\xmpcomma=\hyxmp@comma \def\xmpquote####1{####1}% \let\hyxmp@and=\and \def\and{,}% \hyxmp@Hyp@pdfauthor{##1}% \global\let\hyxmp@pdfauthor=\@pdfauthor \def\and{and\space}% \def\xmpcomma{,}% \def\xmpquote####1{"####1"}% \hyxmp@Hyp@pdfauthor{##1}% \def\xmpcomma{,}% \let\xmpquote=\relax \let\and=\hyxmp@and }% % \end{macrocode} % \begin{macro}{\hyxmp@Hyp@pdfkeywords} % The previous block of code now repeats for the keyword list, starting % by storing the old definition of |\KV@Hyp@pdfkeywords| in % |\hyxmp@Hyp@pdfkeywords|. % \begin{macrocode} \@ifundefined{KV@Hyp@pdfkeywords}{}{% \@ifundefined{hyxmp@Hyp@pdfkeywords}{% \expandafter\let\expandafter\hyxmp@Hyp@pdfkeywords \csname KV@Hyp@pdfkeywords\endcsname }{}% }% % \end{macrocode} % \begin{macro}{\KV@Hyp@pdfkeywords} % \begin{macro}{\xmpcomma} % \begin{macro}{\xmpquote} % \begin{macro}{\hyxmp@pdfkeywords} % \begin{macro}{\@pdfkeywords} % Redefine |\KV@Hyp@pdfkeywords| to process its argument twice. The % first time, |\xmpcomma| is defined as a placeholder character % (|\hyxmp@comma|) and |\xmpquote| as the identity function. The % result is stored in |\hyxmp@pdfkeywords| for use in structured lists % (those surrounding each entry with ||). The second time, % |\xmpcomma| is defined as an ordinary comma, and |\xmpquote| is % defined as a macro that puts its argument within double quotes. The % result is stored in |\@pdfkeywords| for use in unstructured lists % (those in which the entire list appears within a single pair of tags). % \begin{macrocode} \define@key{Hyp}{pdfkeywords}{% \let\xmpcomma=\hyxmp@comma \def\xmpquote####1{####1}% \hyxmp@Hyp@pdfkeywords{##1}% \global\let\hyxmp@pdfkeywords=\@pdfkeywords \def\xmpcomma{,}% \def\xmpquote####1{"####1"}% \hyxmp@Hyp@pdfkeywords{##1}% \def\xmpcomma{,}% \let\xmpquote=\relax }% } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\hyxmp@ProcessKeyvalOptions} % \changes{v2.0}{2012/09/05}{Added this macro} % \changes{v5.11}{2022/10/02}{Bug fix: Restore % \protect\cs{ProcessKeyvalOptions} after first use. Thanks to % Ulrike Fischer for the bug report} % \begin{macro}{\ProcessKeyvalOptions} % \changes{v2.0}{2012/09/05}{Added this macro} % Redefine \pkgname{kvoptions}'s |\ProcessOptions| command to invoke % |\hyxmp@redefine@Hyp| before performing its normal option processing. % \begin{macrocode} \let\hyxmp@ProcessKeyvalOptions=\ProcessKeyvalOptions \renewcommand*{\ProcessKeyvalOptions}{% \global\let\ProcessKeyvalOptions=\hyxmp@ProcessKeyvalOptions \hyxmp@redefine@Hyp \hyxmp@ProcessKeyvalOptions } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\hyxmp@hypersetup} % \changes{v2.1}{2012/09/16}{Added this macro} % \begin{macro}{\hypersetup} % \changes{v2.1}{2012/09/16}{Added this macro} % Redefine \pkgname{hyperref}'s |\hypersetup| command to invoke % |\hyxmp@redefine@Hyp| before performing its normal option processing. % \begin{macrocode} \let\hyxmp@hypersetup=\hypersetup \def\hypersetup{% \hyxmp@redefine@Hyp \hyxmp@hypersetup } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\hyxmp@concated@metadata} % \begin{macro}{\hyxmp@aep@toks} % Assume that if the document loaded either \pkgname{babel} or % \pkgname{polyglossia} it will eventually define one or more languages % that \pkgname{hyperxmp} can list within a \xmpprop{dc:language} % element. As explained in Section~\ref{sec:initial-prep}, we defer the % invocation of \cs{AtEndPreamble} to the end of the file. % \begin{macrocode} \edef\hyxmp@concated@metadata{} \expandafter\hyxmp@aep@toks\expandafter=\expandafter{% \the\hyxmp@aep@toks \AtEndPreamble{% \@ifpackageloaded{babel}{% \edef\hyxmp@concated@metadata{babel}% }{% \@ifpackageloaded{polyglossia}{% \edef\hyxmp@concated@metadata{polyglossia}% }{% }% }% }% } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\hyxmp@warn@if@no@metadata} % \begin{macro}{\hyxmp@concated@metadata} % Issue a warning message if the author failed to specify any metadata % at all. This excludes metadata that is included automatically such as % the current timestamp. Note that we don't consider |\@pdfmetalang| as % metadata as that value is meaningful only when used in conjunction % with other information. We also don't examine |\@pdfapart| or % |\@pdfaconformance| because those have nonempty default values. % \begin{macrocode} \newcommand*{\hyxmp@warn@if@no@metadata}{% \edef\hyxmp@concated@metadata{% \hyxmp@concated@metadata \@baseurl \@pdfauthor \@pdfauthortitle \@pdfbookedition \@pdfbytes \@pdfcaptionwriter \@pdfcontactaddress \@pdfcontactcity \@pdfcontactcountry \@pdfcontactemail \@pdfcontactphone \@pdfcontactpostcode \@pdfcontactregion \@pdfcontacturl \@pdfcopyright \@pdfcreationdate \@pdfdatetime \@pdfdoi \@pdfeissn \@pdfidentifier \@pdfisbn \@pdfissn \@pdfissuenum \@pdfkeywords \@pdflang \@pdflicenseurl \@pdfmetadatetime \@pdfmoddate \@pdfnumpages \@pdfpagerange \@pdfpublication \@pdfpubtype \@pdfsubject \@pdfsubtitle \@pdftitle \@pdfuapart \@pdfurl \@pdfvolumenum \@pdfxstandard }% \ifx\hyxmp@concated@metadata\@empty \PackageWarningNoLine{hyperxmp}{% \hyxmp@jobname.tex did not specify any metadata to\MessageBreak include in the XMP packet.\space\space Please see the\MessageBreak hyperxmp documentation for instructions on how to\MessageBreak provide metadata values to hyperxmp}% \fi } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\hyxmp@check@standards} % Most \acro{PDF} standards require that certain metadata be present. % If compliance with a \acro{PDF} standard is claimed but any of the % metadata it requires are absent, issue a warning message. % \changes{v5.0}{2020/03/11}{Added this macro} % \begin{macrocode} \newcommand*{\hyxmp@check@standards}{% % \end{macrocode} % If the \optname{pdfa} option was passed to \pkgname{hyperref} but % |\@pdfapart| is not set, set it to~|1| and |\@pdfaconformance| to~|B|. % \begin{macrocode} \ifHy@pdfa \@ifmtargexp{\@pdfapart}{% \PackageWarningNoLine{hyperxmp}{% `pdfa' was passed to hyperref, but `pdfapart' was\MessageBreak not specified.\space\space Setting pdfapart to `1' and\MessageBreak pdfaconformance to `B'% }% \gdef\@pdfapart{1}% \gdef\@pdfaconformance{B}% }% {}% \fi % \end{macrocode} % % \begin{macro}{\hyxmp@standards} % We define |\hyxmp@standards| to be non-empty if \emph{any} \acro{PDF} % standard is claimed (currently, \acro{PDF/A}, \acro{PDF/X}, or % \acro{PDF/UA}. % \begin{macrocode} \edef\hyxmp@standards{% \@pdfapart \@pdfxstandard \@pdfuapart }% % \end{macrocode} % Check that a document title was provided and is non-empty. % \begin{macrocode} \@ifnotmtargexp{\hyxmp@standards}{% \@ifmtargexp{\@pdftitle}{% \PackageWarningNoLine{hyperxmp}{% Missing pdftitle (required for PDF standards\MessageBreak compliance)% }% }% {}% }% } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\hyxmp@aep@toks} % Right before we reach the |\begin{document}| we check if % \pkgname{hyperref} was loaded. In normal usage, the document will % already have done a |\usepackage{hyperref}| because otherwise, % \cs{hypersetup} will not have been defined, and only a limited amount % of metadata will be included. However, in case the author is relying % exclusively on \pkgname{hyperxmp}'s automatically detected metadata, % we'll need to load \pkgname{hyperref} now. As explained in % Section~\ref{sec:initial-prep}, we defer the invocation of % \cs{AtEndPreamble} to the end of the file. % \changes{v5.5}{2020/06/24}{Load \protect\pkgname{hyperref} automatically % if the document does not do so explicitly, as requested by Robin Schwab} % \begin{macrocode} \expandafter\hyxmp@aep@toks\expandafter=\expandafter{% \the\hyxmp@aep@toks \AtEndPreamble{% \RequirePackage{hyperref}% % \end{macrocode} % Older versions of \pkgname{hyperref} write the \pdfterm{Info} % dictionary to the \acro{PDF} file at the end of the document. Newer % versions of \pkgname{hyperref} write the \pdfterm{Info} dictionary to % the \acro{PDF} file at the \emph{beginning} of the document. For % compatibility with both old and new \pkgname{hyperref} implementations % we suppress writing the \pdfterm{Info} dictionary here, at the % beginning of the document. % \changes{v4.1}{2019/04/02}{Invoke % \protect\cs{hyxmp@no@info@lists} at the beginning of the % document, for compatibility with both newer and older versions of % \protect\pkgname{hyperref}} % \begin{macrocode} \hyxmp@no@info@lists % \end{macrocode} % If \optname{pdftitle} is undefined but the author invoked \cs{title}, % we copy the latter to the former. This addresses two problems: % (1)~handling \LaTeX\ classes in which \cs{maketitle} clears \cs{title} % and (2)~ensuring that \pkgname{hyperref} writes the same title to the % \acro{PDF} \pdfterm{Info} dictionary that \pkgname{hyperxmp} writes to % the \acro{XMP} packet. We do likewise for \cs{author}~$\rightarrow$ % \optname{pdfauthor}. % % One tricky bit is that the standard \LaTeX\ classes do not define % \cs{@title} and \cs{@author} as empty strings but rather as calls to % \cs{@latex@warning@no@line} that complain about a missing % title/author. Hence, we can't simply test if the title and author are % empty because they're not. Instead, we first locally redefine % \cs{@latex@warning@no@line} to discard its argument then test if any % text remains. % \changes{v5.5}{2020/07/24}{Copy \protect\cs{title} to % \protect\optname{pdftitle} and \protect\cs{author} to % \protect\optname{pdfauthor} at the start of the document to improve % consistency between \protect\acro{XMP} and \protect\acro{PDF} metadata} % \begin{macrocode} \begingroup \let\@latex@warning@no@line=\@gobble \hyxmp@use@first@valid{pdftitle}{\@pdftitle}{% \scr@subject@var,% \@title }% \hyxmp@use@first@valid{pdfauthor}{\@pdfauthor}{% \scr@fromname@var,% \@author }% \endgroup }% } % \end{macrocode} % \end{macro} % % When we reach the |\end{document}| we need to gather up the metadata % specified explicitly by the user, infer additional metadata where % possible, and write the \acro{XMP} packet to the \acro{PDF} file. % \changes{v1.3}{2011/04/25}{Introduced the \protect\optname{pdfmetalang} % package option, which enables an author to specify the language in which he % wrote the document's metadata} % \changes{v2.0}{2012/08/02}{New \cs{AtBeginDocument} code from Heiko % Oberdiek to properly encode \cs{@pdfmetalang}} % \changes{v3.3}{2017/07/21}{Don't overwrite an existing % \protect\optname{pdfmetalang} with \protect\optname{pdflang} or % \protect\xmpterm{x-default}. This addresses a bug report by Niklas % Beisert} % \changes{v5.4}{2020/06/18}{Moved the automatic assignment of % \protect\cs{@pdflang} and \protect\cs{@pdfmetalang} from % \protect\cs{hyxmp@auto@assign@data} to within a call to % \protect\cs{hyxmp@at@end}} % \changes{v5.5}{2020/07/21}{Move most of the \protect\cs{AtEndPreamble} % code to \protect\cs{hyxmp@at@end}} % \begin{macrocode} \hyxmp@at@end{% % \end{macrocode} % Fill in any missing metadata we can using values provided by the author % via mechanisms other than the \cs{hypersetup} command. % \begin{macrocode} \hyxmp@auto@assign@data % \end{macrocode} % If the document claims to comply with one or more \acro{PDF} % standards, check that all of the requisite metadata are present. % \begin{macrocode} \hyxmp@check@standards % \end{macrocode} % We can finally construct the \acro{XMP} packet and write it to the % \acro{PDF} document catalog. % \begin{macrocode} \hyxmp@warn@if@no@metadata \hyxmp@embed@packet } % \end{macrocode} % % % \subsection{Advanced metadata detection} % % \pkgname{hyperxmp} strives to be as convenient and user-friendly as % possible. To that end, we try to automatically detect as much % metadata as possible. The author can of course augment or override % autodetected metadata by explicitly providing values to % \cs{hypersetup}, but the hope is that we can save the author some % effort in many cases. % % In this section, we identify additional metadata we can use. Most of % the functionality is class- or package-specific. For example, we % check for phone numbers provided to the \Koma\ letter classes via % |\setkomavar{fromphone}{|\dots|}| and/or % |\setkomavar{frommobilephone}{|\dots|}|, street addresses provided to % the \ACMclass\ article class via \cs{affiliation}, and languages % the \pkgname{polyglossia} package is instructed to load via % \cs{setdefaultlanguage} and \cs{setotherlanguage}. % % \begin{macro}{\hyxmp@set@koma@phones} % \changes{v5.3}{2020/06/07}{Added this macro} % \changes{v5.5}{2020/07/08}{Support hyperlinks and other markup in % \protect\texttt{frommobilephone} and \protect\texttt{fromphone}, % as requested by Robin Schwab} % \begin{macro}{\hyxmp@koma@phones} % Define \cs{hyxmp@koma@phones} as a comma-separated list of the phone % numbers provided to a \Koma\ letter class (mobile and landline). % \begin{macrocode} \newcommand*{\hyxmp@set@koma@phones}{% \begingroup \Hy@unicodefalse \@if@def@and@nonempty{scr@frommobilephone@var}{% \@if@def@and@nonempty{scr@fromphone@var}{% \hyxmp@pdfstringdef\hyxmp@koma@phones{\scr@frommobilephone@var,\scr@fromphone@var}% }{% \hyxmp@pdfstringdef\hyxmp@koma@phones{\scr@frommobilephone@var}% }% }{% \@if@def@and@nonempty{scr@fromphone@var}{% \hyxmp@pdfstringdef\hyxmp@koma@phones{\scr@fromphone@var}% }{% }% }% \endgroup } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\hyxmp@use@first@valid} % Given a \pkgname{hyperxmp} option~(|#1|), its current value~(|#2|), % and a comma-separated list of option names~(|#3|), if the current % value is empy, invoke \cs{hypersetup} to set the option to the first % non-empty item in the list. If all items in the list are empty, do % nothing. % \changes{v5.3}{2020/05/29}{Added this macro} % \begin{macrocode} \newcommand*{\hyxmp@use@first@valid}[3]{% \@ifmtargexp{#2}{% \hyxmp@use@first@valid@i{#1}#3,!,% }% {}% } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@use@first@valid@i} % This macro performs all the work for \cs{hyxmp@use@first@valid}. It % loops over a comma-separated list of macros~(|#2|), stopping when it % encounters an end-of-list marker~(``|!|''). The first list element % that is neither undefined nor empty is assigned to a given option % name~(|#1|) using \cs{hypersetup}. % \begin{macrocode} \def\hyxmp@use@first@valid@i#1#2,{% \def\next{\hyxmp@use@first@valid@i{#1}}% \ifx#2!% \let\next=\relax \else \ifx#2\undefined \else \@ifnotmtargexp{#2}{% \hypersetup{#1={#2}}% \def\next##1!,{}% }% \fi \fi \next } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@auto@assign@data} % If certain metadata are unspecified, try to specify meaningful values % using data provided by author via other means (e.g.,~\cs{title} for % the document's title). % \begin{macrocode} \newcommand*{\hyxmp@auto@assign@data}{% % \end{macrocode} % If \cs{@pdflang} is not set, see if we can detect the document % language via either the \pkgname{babel} or \pkgname{polyglossia} % packages. % \begin{macrocode} \@if@def@and@nonempty{@pdflang}{% \let\hyxmp@dc@lang=\@pdflang }{% \hyxmp@detect@langs }% % \end{macrocode} % Replace an empty \cs{@pdfmetalang}. If \cs{@pdflang} is defined, use % that as the metadata language. Otherwise, use \xmpterm{x-default}. % \begin{macrocode} \ifx\@pdfmetalang\@empty \ifx\@pdflang\@empty \let\@pdfmetalang=\hyxmp@x@default \else \edef\@pdfmetalang{\@pdflang}% \fi \fi % \end{macrocode} % Identify various author-provided information that can be co-opted % for use as \acro{XMP} metadata. % \changes{v2.7}{2016/02/01}{Automatically use \cs{title} and \cs{author} % if \protect\optname{pdftitle} and \protect\optname{pdfauthor} are left % unspecified. Thanks to Maciej Radziejewski for the suggestion} % \changes{v5.3}{2020/05/29}{Consider other author-provided sources of % metadata. Thanks to Robin Schwab for proposing that % \protect\pkgname{hyperxmp} use the \Koma\ letter classes's metadata} % \changes{v5.5}{2020/07/24}{Moved the language-detection and % \protect\XeTeX\ date-detection code here from the % \protect\cs{hyxmp@at@end} block} % \changes{v5.5}{2020/07/24}{Use \protect\LuaTeX\ mechanisms, when available, % to automatically compute the page count} % \changes{v5.5}{2020/07/24}{Moved title and author autodetection to the % \protect\cs{AtEndPreamble}} % \begin{macrocode} \hyxmp@use@first@valid{pdfcontactemail}{\@pdfcontactemail}{% \scr@fromemail@var }% \hyxmp@set@koma@phones \hyxmp@use@first@valid{pdfcontactphone}{\@pdfcontactphone}{% \hyxmp@koma@phones }% \hyxmp@use@first@valid{pdfcontacturl}{\@pdfcontacturl}{% \scr@fromurl@var }% \hyxmp@use@first@valid{pdfsubtitle}{\@pdfsubtitle}{% \@subtitle }% \hyxmp@use@first@valid{pdfpublisher}{\@pdfpublisher}{% \@publishers }% % \end{macrocode} % We handle the \clsname{acmart} class specially. \clsname{acmart} % stores author-provided contact information in a structured format that % we can process fairly easily. Note that if the author is not using % the \clsname{acmart} class, \cs{hyxmp@parse@acmart} will have been % redefined to do nothing. % \begin{macrocode} \hyxmp@parse@acmart % \end{macrocode} % Most \acro{PDF} standards dictate that if the same metadata appear in % both the \acro{XMP} packet and the \acro{PDF} \pdfterm{Info} % dictionary, the metadata must match. This requirement poses a problem % for a user-unspecified \optname{pdfcreationdate} in the context of % \XeLaTeX\@. In this case we explicitly define |\@pdfcreationdate| as % |\hyxmp@today@pdf| to prevent the \cmdname{xdvipdfmx} back-end % processor from detecting a missing \pdfterm{CreationDate} in the % \pdfterm{Info} dictionary and adding its own---typically a few seconds % after \pkgname{hyperxmp} has constructed an \xmpprop{xmp:CreateDate} % for the \acro{XMP} metadata and leading to a metadata mismatch. % \begin{macrocode} \@ifundefined{XeTeXversion}{}{% \@ifmtargexp{\@pdfcreationdate}{% \let\@pdfcreationdate=\hyxmp@today@pdf }% {}% }% % \end{macrocode} % Query the document currently being built for page and byte counts. % \begin{macrocode} \hyxmp@query@self } % \end{macrocode} % \end{macro} % % Determine the size of the output file from the \emph{previous} run of % \LuaLaTeX\@. This action has to be performed before the % |\begin{document}| because at that point the size of the output file % is reset to zero. We use |\jobname.pdf| as the name of the output % file because |status.output_file_name| is not defined at this point. % % It's possible to use \pdfLaTeX's \cs{pdffilesize} primitive to query % the size of |\jobname.pdf| under \pdfLaTeX\@. Unfortunately, doing so % has a side effect of making \progname{latexmk} view the % \acro{PDF} file as an input file, which puts \progname{latexmk} in an % infinite build loop. (This was the case for \pkgname{hyperxmp} v5.5 % and v5.6.) See the discussion at % \url{https://github.com/borisveytsman/acmart/issues/413} for more % information. % \changes{v5.7}{2020/11/01}{Do not automatically compute the % \protect\acro{PDF} file size under \protect\pdfLaTeX\ because this confuses % \protect\progname{latexmk}. Thanks to John Collins, Nelson Posse Lago, % Derek Dreyer, and the other contributors to % \protect\href{https://github.com/borisveytsman/acmart/issues/413}{\protect\pkgname{acmart} issue \#413}, % ``Latexmk goes into an infinite loop even on sample files from ACM''} % \changes{v5.8}{2020/11/05}{Take % \protect\mbox{\protect\texttt{-\kern0pt-output-directory}} into % consideration when querying the output file size. Thanks to John % Collins for pointing out that the user can change the output % directory} % \begin{macrocode} \ifLuaTeX % \end{macrocode} % Now that we know we're running \LuaLaTeX\ we define a Lua function, % |get_pdf_size|, that takes the base name of the output file and % returns the number of bytes in the corresponding \acro{PDF} file. One % difficulty is that, at the time of this writing, \LuaTeX\ lacks a % mechanism for querying the full name of the output file. Our % workaround is a tad kludgy but seems to work. We walk the list of % command-line arguments for % \mbox{``|-\kern0pt-output-directory=|\meta{dir}''}. (We in fact % accept either one or two initial dashes and abbreviations as terse as % \mbox{``|-output-d|''}.) Then, we concatenate the output directory % (or ``|.|'' if unspecified), a path separator, the given base name of % the job, and a ``|.pdf|'' extension. Alas, different operating % systems use different path separators so we have to query the % operating-system type to select an appropriate separator: ``|\|'' on % Windows/\acro{DOS} and ``|/|'' on everything else. % % |get_pdf_size| is called regardless of whether we're producing % \acro{PDF} or \acro{DVI} output. We assume that even if the user % specified |--output-format=dvi|, the user's intention is eventually to % convert the document to \acro{PDF}. % \begin{macrocode} \begin{luacode*} function get_pdf_size (bname) % \end{macrocode} % Search the list of command-line arguments for the output directory. % \begin{macrocode} local odir = "" for _, opt in ipairs(arg) do local m = string.match(opt, "%-output%-d.-=(.*)") if m then odir = m end end % \end{macrocode} % Set the path separator to either ``|/|'' or ``|\|'', depending on the % operating system. % \begin{macrocode} local sep = "/" if os.type == "windows" or os.type == "msdos" then sep = "\\\\" end % \end{macrocode} % Concatenate the output directory, path separator, base name, and % \texttt{.pdf} extension. Do not insert a path separator if either % (1)~no output directory was specified, (2)~the output directory % already ends with the path separator, or (3)~the output directory ends % in a colon (and is therefore a relative directory) on % Windows/\acro{DOS}. As a few examples, % % \bigskip % \noindent % \begingroup % \let\bs=\textbackslash % \begin{tabular}{@{\quad\textbullet~}l@{~+~}l@{~+~}l@{~+~``\texttt{.pdf}''~=~}l@{}} % ``'' & ``\texttt{/}'' & ``\texttt{myfile}'' % & ``\texttt{myfile.pdf}'' \\ % ``\texttt{/docs}'' & ``\texttt{/}'' & ``\texttt{myfile}'' % & ``\texttt{/docs/myfile.pdf}'' \\ % ``\texttt{/docs/}'' & ``\texttt{/}'' & ``\texttt{myfile}'' % & ``\texttt{/docs/myfile.pdf}'' \\ % ``\texttt{C:\bs docs}'' & ``\texttt{\bs}'' & ``\texttt{myfile}'' % & ``\texttt{C:\bs docs\bs myfile.pdf}'' \\ % ``\texttt{C:\bs docs\bs}'' & ``\texttt{\bs}'' & ``\texttt{myfile}'' % & ``\texttt{C:\bs docs\bs myfile.pdf}'' \\ % ``\texttt{C:\bs}'' & ``\texttt{\bs}'' & ``\texttt{myfile}'' % & ``\texttt{C:\bs myfile.pdf}'' \\ % ``\texttt{C:}'' & ``\texttt{\bs}'' & ``\texttt{myfile}'' % & ``\texttt{C:myfile.pdf}'' \\ % \end{tabular} % \endgroup % \bigskip % \begin{macrocode} local dlast = string.sub(odir, -1) if odir == "" or dlast == sep or (dlast == ":" and sep == "\\\\") then sep = "" end local fname = odir .. sep .. bname .. ".pdf" % \end{macrocode} % Query the file size and return it. % \begin{macrocode} local nbytes = lfs.attributes(fname, "size") return nbytes end \end{luacode*} % \end{macrocode} % Now that we've defined |get_pdf_size| we invoke it, passing it % \cs{hyxmp@jobname} as the base name of the job. (Recall that % \cs{hyxmp@jobname} is the same as \cs{jobname} but with any % surrounding double quotes removed.) We store |get_pdf_size|'s % output---which will be empty if the \acro{PDF} file doesn't yet % exist---in \cs{hyxmp@prev@pdf@size}. % \begin{macrocode} \xdef\hyxmp@prev@pdf@size{% \luadirect{ nbytes = get_pdf_size("\hyxmp@jobname") if nbytes then tex.write(nbytes) end }% }% \fi % \end{macrocode} % % \begin{macro}{\hyxmp@query@self} % Query the document currently being built to acquire page and byte counts. % \changes{v5.5}{2020/07/25}{Added this macro} % \begin{macrocode} \newcommand*{\hyxmp@query@self}{% % \end{macrocode} % \LaTeX's |totalpages| counter tracks the number of pages written. We % use this mechanism to assign \cs{@pdfnumpages}. % \changes{v5.11}{2022/10/16}{Use \protect\cs{thetotalpages} to compute % the page count in an engine-independent manner. Thanks to Ulrike % Fischer for recommending this mechanism} % \begin{macrocode} \@if@def@and@nonempty{@pdfnumpages}{% }{% \xdef\@pdfnumpages{\thetotalpages}% }% % \end{macrocode} % If \optname{pdfbytes} hasn't been set, set it to the output file's size % from the previous run. % \begin{macrocode} \hyxmp@use@first@valid{pdfbytes}{\@pdfbytes}{% \hyxmp@prev@pdf@size }% } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@parse@acmart} % The \clsname{acmart} class stores a rich set of author metadata in its % \cs{addresses} macro. \cs{hyxmp@parse@acmart} extracts the contact % information for the first author and converts that to \acro{XMP} % metadata. % \changes{v5.3}{2020/05/30}{Added this macro} % \begin{macrocode} \newcommand*{\hyxmp@parse@acmart}{% \begingroup % \end{macrocode} % \begin{macro}{\@author} % \clsname{acmart} has already invoked % |\hypersetup{pdfauthor=|\dots|}| to specify the complete list of % authors. At this point, |\@author| is defined to produce a warning % message. We locally redefine it to do nothing. % \begin{macrocode} \let\@author=\@gobble % \end{macrocode} % \end{macro} % \begin{macro}{\email} % \begin{macro}{\hyxmp@address@val} % Within \cs{addresses}, \cs{email} is defined to accept two arguments, % the second of which is the author's email address. % \begin{macrocode} \def\email##1##2{% \def\hyxmp@address@val{##2}% \hyxmp@use@first@valid{pdfcontactemail}{\@pdfcontactemail}{% \hyxmp@address@val }% }% % \end{macrocode} % \end{macro} % \end{macro} % \begin{macro}{\streetaddress} % \begin{macro}{\hyxmp@address@val} % \cs{streetaddress} wraps the author's street address. % \begin{macrocode} \def\streetaddress##1{% \def\hyxmp@address@val{##1}% \hyxmp@use@first@valid{pdfcontactaddress}{\@pdfcontactaddress}{% \hyxmp@address@val }% }% % \end{macrocode} % \end{macro} % \end{macro} % \begin{macro}{\city} % \begin{macro}{\hyxmp@address@val} % \cs{city} wraps the author's city name. % \begin{macrocode} \def\city##1{% \def\hyxmp@address@val{##1}% \hyxmp@use@first@valid{pdfcontactcity}{\@pdfcontactcity}{% \hyxmp@address@val }% }% % \end{macrocode} % \end{macro} % \end{macro} % \begin{macro}{\state} % \begin{macro}{\hyxmp@address@val} % \cs{state} wraps the author's state or region name. % \begin{macrocode} \def\state##1{% \def\hyxmp@address@val{##1}% \hyxmp@use@first@valid{pdfcontactregion}{\@pdfcontactregion}{% \hyxmp@address@val }% }% % \end{macrocode} % \end{macro} % \end{macro} % \begin{macro}{\country} % \begin{macro}{\hyxmp@address@val} % \cs{country} wraps the author's country name. % \begin{macrocode} \def\country##1{% \def\hyxmp@address@val{##1}% \hyxmp@use@first@valid{pdfcontactcountry}{\@pdfcontactcountry}{% \hyxmp@address@val }% }% % \end{macrocode} % \end{macro} % \end{macro} % \begin{macro}{\postcode} % \begin{macro}{\hyxmp@address@val} % \cs{postcode} wraps the author's postal code. % \begin{macrocode} \def\postcode##1{% \def\hyxmp@address@val{##1}% \hyxmp@use@first@valid{pdfcontactpostcode}{\@pdfcontactpostcode}{% \hyxmp@address@val }% }% % \end{macrocode} % \end{macro} % \end{macro} % \begin{macro}{\affiliation} % We want to produce \acro{XMP} metadata for only a single affiliation. % Although \cs{hyxmp@use@first@valid} will ensure that only the first % email, city, country, etc.\ encountered is considered, we run the % first of one affiliation defining, say, a city and state but no % country and a subsequent affiliation defining a country. In that % case, the \acro{XMP} would include the first author's city and state % and the subsequent author's country. Hence, we define % \cs{affiliation} to ``self destruct'' after its first use, discarding % all further affiliations. % \begin{macrocode} \def\affiliation##1##2{% ##2% \let\affiliation=\@gobbletwo }% % \end{macrocode} % \end{macro} % % We want to evaluate \cs{addresses} with the preceding local % definitions in effect, but we don't want to typeset any text appearing % in the string. Hence, we ``typeset'' \cs{addresses} within a box that % is subsequently discarded. % \begin{macrocode} \setbox0=\hbox{\addresses}% \endgroup % \end{macrocode} % % \clsname{acmart} supports other relevant metadata in addition to the % authors' mailing addresses. For instance, papers accepted for % publication indicate their \acro{DOI} number. However, papers under % review will contain either a placeholder \acro{DOI}, % ``10.1145/nnnnnnn.nnnnnnn'', or the example \acro{DOI} specified in % the \clsname{acmart} example document, ``10.1145/1122445.1122456''. % We ignore both of those \acro{DOI}s. % \changes{v5.4}{2020/06/16}{Bug fix: Correct a missing ``else'' argument % in two invocations of \protect\cs{@if@def@and@nonempty}} % \begin{macrocode} \@if@def@and@nonempty{@acmDOI}{% \IfSubStr{\@acmDOI}{10.1145/1122445.1122456}{}{% \IfSubStr{\@acmDOI}{10.1145/nnnnnnn.nnnnnnn}{}{% \hyxmp@use@first@valid{pdfdoi}{\@pdfdoi}{% \@acmDOI }% }% }% }% {}% % \end{macrocode} % \begin{macro}{\hyxmp@strip@isbn@date} % \begin{macro}{\hyxmp@acm@isbn} % Papers appearing in conference proceedings specify the proceedings' % \acro{ISBN}. As with \cs{@acmDOI} above, we ignore both the % placeholder \acro{ISBN}, ``978-x-xxxx-xxxx-x/YY/MM'', and the example % \acro{ISBN}, ``978-1-4503-XXXX-X/18/06''. We also strip off the % ``\texttt{/}\meta{year}\texttt{/}\meta{month}'' suffix so as to % include a true \acro{ISBN} in the \acro{XMP} metadata. % \begin{macrocode} \@if@def@and@nonempty{@acmISBN}{% \IfSubStr{\@acmISBN}{XXXX}{}{% \IfSubStr{\@acmISBN}{xxxx}{}{% \def\hyxmp@strip@isbn@date##1/##2!{##1}% \edef\hyxmp@acm@isbn{% \expandafter\hyxmp@strip@isbn@date\@acmISBN/!% }% \hyxmp@use@first@valid{pdfisbn}{\@pdfisbn}{% \hyxmp@acm@isbn }% }% }% }% {}% % \end{macrocode} % \end{macro} % \end{macro} % \begin{macro}{\hyxmp@acm@publisher} % The publisher is of course \acro{ACM}. % \begin{macrocode} \def\hyxmp@acm@publisher{Association for Computing Machinery}% \hyxmp@use@first@valid{pdfpublisher}{\@pdfpublisher}{% \hyxmp@acm@publisher }% % \end{macrocode} % Use the journal name if defined, otherwise the book name (for % conference proceedings). % \begin{macrocode} \hyxmp@use@first@valid{pdfpublication}{\@pdfpublication}{% \@journalName,% \@acmBooktitle,% \@acmConference }% % \end{macrocode} % \end{macro} % \begin{macro}{\hyxmp@acm@pubtype} % \clsname{acmart} makes clear whether it's typesetting a journal % article. If it's not a journal, we assume it's a book (conference % proceedings). % \begin{macrocode} \if@ACM@journal \def\hyxmp@acm@pubtype{journal}% \else \def\hyxmp@acm@pubtype{book}% \fi \hyxmp@use@first@valid{pdfpubtype}{\@pdfpubtype}{% \hyxmp@acm@pubtype }% % \end{macrocode} % \end{macro} % Journal articles have a volume and issue number. % \begin{macrocode} \hyxmp@use@first@valid{pdfvolumenum}{\@pdfvolumenum}{% \@acmVolume }% \hyxmp@use@first@valid{pdfissuenum}{\@pdfissuenum}{% \@acmNumber }% } % \end{macrocode} % \end{macro} % % Nullify \cs{hyxmp@parse@acmart} if the author is not using the % \clsname{acmart} class. % \begin{macrocode} \@ifclassloaded{acmart}{}{\let\hyxmp@parse@acmart=\relax} % \end{macrocode} % % \begin{macro}{\hyxmp@dc@lang} % \cs{hyxmp@dc@lang} is a comma-separated list of all languages used in % the document. % \begin{macrocode} \let\hyxmp@dc@lang=\@empty % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@detect@langs} % If \optname{pdflang} was not specified, try to determine the document % language(s) using either \pkgname{babel}'s or \pkgname{polyglossia}'s % definitions. % \changes{v5.3}{2020/06/08}{Acquire the default language from the % \protect\pkgname{polyglossia} package, if loaded. Thanks to % Robin Schwab for bringing that package to my attention} % \changes{v5.4}{2020/06/16}{Refactored language detection into a % separate command} % \changes{v5.5}{2020/07/21}{Set the language(s) immediately instead of % deferring them to \protect\cs{hyxmp@set@dc@lang}} % \begin{macrocode} \newcommand*{\hyxmp@detect@langs}{% \@ifundefined{mainbcp47id}{% \@ifundefined{LocaleForEach}{% % \end{macrocode} % The document doesn't appear to have loaded either \pkgname{babel} or % \pkgname{polyglossia}. In this case we have one small task to do. In % older versions of \pkgname{hyperref}, \cs{@pdflang} is set to % \cs{@empty} if \optname{pdflang} is not specified. In newer versions % of \pkgname{hyperref}, \cs{@pdflang} is set to \cs{relax} if % \optname{pdflang} is not specified. The latter is a bit problematic % for \pkgname{hyperxmp} because it makes \cs{@pdflang} non-expandable, % which causes a literal ``\cs{@pdflang}'' to be written as \acro{XMP} % metadata. To avoid that situation we explicitly set \cs{@pdflang} to % \cs{@empty} to avoid problems with non-expandable symbols. % \changes{v2.3a}{2013/04/16}{Bug fix: Redefine \cs{@pdflang} as % \cs{@empty} when \protect\pkgname{hyperref} has set % it to \cs{relax}} % \begin{macrocode} \let\@pdflang=\@empty }{% % \end{macrocode} % \changes{v5.4}{2020/06/17}{Added support for \protect\pkgname{babel}} % \changes{v5.5}{2020/07/16}{Store the main language in \protect\cs{@pdflang}. % Thanks to Javier Bezos for his help with the \protect\pkgname{hyperxmp} % code and for modifying \protect\pkgname{babel} for % \protect\pkgname{hyperxmp}'s benefit} % \begin{macro}{\hyxmp@dc@lang} % \begin{macro}{\hyxmp@lang@tag} % \begin{macro}{\hyxmp@lang@name} % \begin{macro}{\@pdflang} % Use \pkgname{babel}'s \cs{LocaleForEach} and \cs{getlocaleproperty} to % set \cs{@pdflang} to the document's main language and % \cs{hyxmp@dc@lang} to a comma-separated list of all languages used. % \begin{macrocode} \BabelEnsureInfo \LocaleForEach{% \getlocaleproperty\hyxmp@lang@tag{##1}{identification/tag.bcp47}% \ifx\hyxmp@dc@lang\@empty \xdef\hyxmp@dc@lang{\hyxmp@lang@tag}% \else \xdef\hyxmp@dc@lang{\hyxmp@dc@lang,\hyxmp@lang@tag}% \fi \def\hyxmp@lang@name{##1}% \ifx\hyxmp@lang@name\bbl@main@language \edef\@pdflang{\hyxmp@lang@tag}% \fi }% }% }{% % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % Use \pkgname{polyglossia}'s \cs{mainbcp47id} as the document's main % language and its \cs{xpg@bcp@loaded} as a comma-separated list of all % document languages. % \begin{macrocode} \xdef\@pdflang{\csname mainbcp47id\endcsname}% \edef\hyxmp@dc@lang{\xpg@bcp@loaded}% }% } % \end{macrocode} % \end{macro} % % % \subsection{Manipulating author-supplied data} % % The author provides metadata information to \pkgname{hyperxmp} via % package options to \pkgname{hyperref} or via \pkgname{hyperref}'s % |\hypersetup| command. The functions in this section convert % author-supplied lists (e.g.,~|pdfkeywords={foo, bar, baz}|) into % \LaTeX\ lists (e.g.,~|\@elt {foo}| |\@elt {bar}| |\@elt {baz}|) that % can be more easily manipulated (Section~\ref{sec:list-manip}); parse % dates in both \acro{PDF} and \acro{XMP} formats % (Section~\ref{sec:date-manip}; trim spaces off the ends of strings % (Section~\ref{sec:trim-spaces}); convert text to \acro{XML} % (e.g.,~from || to % |<scott+hyxmp@pakin.org>|) (Section~\ref{sec:text-xml}); % simplify the pretty-printing of a begin tag, \acro{XML} text, and end % tag (Section~\ref{sec:output-xml}; and provide metadata in multiple % languages (Section~\ref{sec:lang-alt}). % % \subsubsection{List manipulation} % \label{sec:list-manip} % % We define a macro for converting a list of comma-separated elements % (e.g.,~the list of \acro{PDF} keywords) to a list of \LaTeX\ % |\@elt|-separated elements. % % \begin{macro}{\hyxmp@commas@to@list} % Given a macro name~(|#1|) and a comma-separated list~(|#2|), define % the macro name as the elements of the list, each preceded by |\@elt|. % (Executing the macro therefore applies |\@elt| to each element in % turn.) % \begin{macrocode} \newcommand*{\hyxmp@commas@to@list}[2]{% \gdef#1{}% \expandafter\hyxmp@commas@to@list@i\expandafter#1#2,,% } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@commas@to@list@i} % \begin{macro}{\next} % Recursively construct macro~|#1| from comma-separated list~|#2|. Stop % if |#2| is empty. % \begin{macrocode} \def\hyxmp@commas@to@list@i#1#2,{% \gdef\hyxmp@sublist{#2}% \ifx\hyxmp@sublist\@empty \let\next=\relax \else \hyxmp@trimspaces\hyxmp@sublist \@cons{#1}{{\hyxmp@sublist}}% \def\next{\hyxmp@commas@to@list@i{#1}}% \fi \next } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\xmpcomma} % Because \pkgname{hyperxmp} splits lists at commas, a comma cannot % normally be used within a list. We there provide an |\xmpcomma| macro % that can expand to either a true comma or a placeholder character % depending on the situation. Here, we bind it to a comma so it can be % used in \emph{any} \pkgname{hyperxmp} option, not just those that treat % commas specially. % \changes{v2.0}{2012/08/25}{Added this macro} % \changes{v2.2}{2012/12/07}{Changed the default from % \texttt{\string\string\string\relax} to an ordinary comma} % \begin{macrocode} \def\xmpcomma{,}% % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@comma} % This is what |\xmpcomma| maps to during list construction. We assume % that documents will never otherwise use an \acro{ETX} (|^^C|) % character in their \acro{XMP} metadata. % \changes{v2.0}{2012/08/25}{Added this macro} % \begin{macrocode} \bgroup \catcode`\^^C=11 \gdef\hyxmp@comma{^^C} \egroup % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@uscore} % This is what |\_| temporarily maps to during packet construction. % Because underscores are replaced by spaces, we need a mechanism to % preserve user-specified underscores (e.g.,~in email addresses). We % assume that documents will never otherwise use an \acro{NAK} (|^^U|) % character in their \acro{XMP} metadata. % \changes{v2.5}{2014/06/19}{Added this macro} % \begin{macrocode} \bgroup \catcode`\^^U=11 \gdef\hyxmp@uscore{^^U} \egroup % \end{macrocode} % \end{macro} % % \begin{macro}{\xmpquote} % Adobe Acrobat likes to see double quotes around list elements that % contain commas when the entire list appears within a single \acro{XMP} % tag (e.g.,~||). However, it doesn't like to see double % quotes around list elements that contain commas when the list is % broken up into individual components (i.e.,~using || tags). % We therefore introduce an |\xmpquote| macro that quotes or doesn't % quote its argument based on context. Here, we bind |\xmpquote| to % |\relax| to prevent it from prematurely quoting or not quoting. % \changes{v2.0}{2012/09/10}{Added this macro} % \begin{macrocode} \let\xmpquote=\relax % \end{macrocode} % \end{macro} % % \begin{macro}{\xmptilde} % As a convenience for the user, we define |\xmptilde| as a category~12 % (other) ``|~|'' character. % \changes{v2.4}{2014/01/01}{Added this macro} % \begin{macrocode} \bgroup \catcode`\~=12% \gdef\xmptilde{~}% \egroup % \end{macrocode} % \end{macro} % % \begin{macro}{\XMPTruncateList} % \changes{v2.0}{2012/09/07}{Added this macro} % \changes{v2.3b}{2013/07/18}{Made all definitions local to avoid % spurious \texttt{Too many unprocessed floats} errors when running % with \string\pkgname{memoir}} % \changes{v4.0}{2019/03/31}{Deprecated this macro} % \begin{macro}{\hyxmp@temp@str} % \begin{macro}{\hyxmp@temp@list} % \begin{macro}{\@elt} % As a workaround for the inability of older Adobe Acrobat versions to % display author lists correctly we introduce a hack that replaces a % list with its first element. One can then write % ``|\XMPTruncateList{pdfauthor}|'' and have Adobe Acrobat display the % author list correctly. % \begin{macrocode} \newcommand{\XMPTruncateList}[1]{{% \PackageWarning{hyperxmp}{% \noexpand\XMPTruncateList has been deprecated since\MessageBreak hyperxmp 4.0 and may be removed in future\MessageBreak versions of the package. \noexpand\XMPTruncateList\MessageBreak was found}% \edef\hyxmp@temp@str{\csname hyxmp@#1\endcsname}% \hyxmp@commas@to@list{\hyxmp@temp@list}{\hyxmp@temp@str}% \def\@elt##1{% \expandafter\gdef\csname @#1\endcsname{##1}% \let\@elt=\@gobble } \hyxmp@temp@list }} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % % \subsubsection{Date manipulation} % \label{sec:date-manip} % % \pkgname{hyperxmp} needs to manipulate two types of date (really, % timestamp) formats: \acro{PDF} format and \acro{XMP} format. % \acro{PDF} timestamps are of the form % ``|D:|\textsc{yyyymmdd}hhmmss|+|\textsc{tt}|'|tt|'|'' % \makeatletter % \@ifundefined{pdffeedback}{^^A % \@ifundefined{pdfcreationdate}{^^A % }{^^A % (e.g.,~\texttt{\pdfcreationdate})^^A % }^^A % }{^^A % (e.g.,~\texttt{\pdffeedback creationdate})^^A % } % \makeatother % ~\cite{Adobe2008:PDF}, while \acro{XMP} timestamps are of the form % ``\textsc{yyyy}|-|\textsc{mm}|-|\textsc{dd}|T|hh|:|mm|:|ss|+|\textsc{tt}|:|tt'' % \makeatletter % \@ifundefined{pdffeedback}{^^A % \@ifundefined{pdfcreationdate}{^^A % \unskip % }{^^A % (e.g.,~\texttt{\expandafter\hyxmp@pdf@to@xmp@date\pdfcreationdate})^^A % }^^A % }{^^A % (e.g.,~\texttt{\expandafter\hyxmp@pdf@to@xmp@date\pdffeedback creationdate})^^A % }^^A % \makeatother % ~\cite{Adobe2012:XMP}. The |\hyxmp@as@pdf@date| and % |\hyxmp@as@xmp@date| macros defined in this section facilitate % timestamp conversions to \acro{PDF} and \acro{XMP} formats, % respectively. % % \begin{macro}{\hyxmp@first@char} % \begin{macro}{\hyxmp@first@char@i} % Return the first character of a string. This macro is fully expandable. % \begin{macrocode} \def\hyxmp@first@char#1{\hyxmp@first@char@i#1\relax} \def\hyxmp@first@char@i#1#2\relax{#1} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\hyxmp@as@xmp@date} % If necessary, convert a timestamp to \acro{XMP} format. That is, if % the timestamp is in \acro{PDF} format, convert it; otherwise, leave it % unmodified. This macro is fully expandable. % \changes{v3.2}{2017/02/20}{Added this macro} % \begin{macrocode} \def\hyxmp@as@xmp@date#1{% \expandafter\ifnum\expandafter`\hyxmp@first@char@i#1\relax=`D \hyxmp@pdf@to@xmp@date{#1}% \else #1% \fi } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@pdf@to@xmp@date} % Convert a timestamp from \acro{PDF} format to \acro{XMP} format. This % macro is fully expandable. % \changes{v2.4}{2013/12/24}{Added this macro} % \begin{macrocode} \def\hyxmp@pdf@to@xmp@date#1:#2#3#4#5#6#7#8#9{% #2#3#4#5-#6#7-#8#9% \hyxmp@parse@time } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@parse@time} % This is a helper function for |\hyxmp@pdf@to@xmp@date|. % |\hyxmp@pdf@to@xmp@date| proper parses only the year, month, and day % then calls |\hyxmp@parse@time|. |\hyxmp@parse@time| parses the % hours, minutes, and seconds then calls |\hyxmp@parse@tz@char|. % \changes{v2.4}{2013/12/24}{Added this macro} % \begin{macrocode} \def\hyxmp@parse@time#1#2#3#4#5#6{% T#1#2:#3#4:#5#6% \hyxmp@parse@tz@char } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@parse@tz@char} % This is another helper function for |\hyxmp@pdf@to@xmp@date|. So far, % the date and time have been parsed. |\hyxmp@parse@tz@char| parses the % first character of the timezone descriptor. This can be one of % ``|+|'' for eastern timezones (\mbox{UTC$+x$}, including Asia, % Oceania, and most of Europe), ``|-|'' for western timezones % (\mbox{UTC$-x$}, primarily the Americas), or ``|Z|'' for Zulu time % (\mbox{UTC$+0$}). Timezones beginning with ``|+|'' or ``|-|'' are % followed by an offset in hours and minutes (parsed by % |\hyxmp@parse@tz|; timezones beginning with ``|Z|'' are not. % \changes{v2.4}{2013/12/24}{Added this macro} % \begin{macrocode} \def\hyxmp@parse@tz@char#1{% #1% \ifx#1-% \expandafter\hyxmp@parse@tz \else \ifx#1+% \expandafter\hyxmp@parse@tz \fi \fi } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@parse@tz} % This is the final helper function for |\hyxmp@pdf@to@xmp@date|. It % parses the piece of the timezone comprising the offset from % Coordinated Universal Time, measured in hours and minutes. % \changes{v2.4}{2013/12/24}{Added this macro} % \begin{macrocode} \def\hyxmp@parse@tz#1'#2'{% #1:#2% } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@as@pdf@date} % If necessary, convert a timestamp to \acro{PDF} format. That is, if % the timestamp is in \acro{XMP} format, convert it; otherwise, leave it % unmodified. This macro is fully expandable. % \changes{v3.2}{2017/02/20}{Added this macro} % \begin{macrocode} \def\hyxmp@as@pdf@date#1{% \expandafter\ifx\hyxmp@first@char@i#1\relax D% #1% \else \hyxmp@xmp@to@pdf@date{#1}% \fi } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@xmp@to@pdf@date} % Convert a timestamp from \acro{XMP} format to \acro{PDF} format. This % macro is fully expandable. % \changes{v2.4}{2013/12/24}{Added this macro} % \begin{macrocode} \def\hyxmp@xmp@to@pdf@date#1{% D:\hyxmp@xmp@to@pdf@date@i#1\relax\relax } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@xmp@to@pdf@date@i} % Parse the year for |\hyxmp@xmp@to@pdf@date|. % \begin{macrocode} \def\hyxmp@xmp@to@pdf@date@i#1#2#3#4#5#6{% #1#2#3#4% \ifx#5-% \expandafter\hyxmp@xmp@to@pdf@date@ii\expandafter#6% \fi } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@xmp@to@pdf@date@ii} % Parse the month for |\hyxmp@xmp@to@pdf@date|. % \begin{macrocode} \def\hyxmp@xmp@to@pdf@date@ii#1#2#3#4{% #1#2% \ifx#3-% \expandafter\hyxmp@xmp@to@pdf@date@iii\expandafter#4% \fi } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@xmp@to@pdf@date@iii} % Parse the day for |\hyxmp@xmp@to@pdf@date|. % \begin{macrocode} \def\hyxmp@xmp@to@pdf@date@iii#1#2#3#4{% #1#2% \ifx#3T% \expandafter\hyxmp@xmp@to@pdf@date@iv\expandafter#4% \fi } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@xmp@to@pdf@date@iv} % Parse the hour for |\hyxmp@xmp@to@pdf@date|. % \begin{macrocode} \def\hyxmp@xmp@to@pdf@date@iv#1#2#3#4{% #1#2% \ifx#3:% \expandafter\hyxmp@xmp@to@pdf@date@v\expandafter#4% \fi } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@xmp@to@pdf@date@v} % Parse the minute for |\hyxmp@xmp@to@pdf@date|. % \begin{macrocode} \def\hyxmp@xmp@to@pdf@date@v#1#2#3#4{% #1#2% \ifx#3:% \expandafter\hyxmp@xmp@to@pdf@date@vi\expandafter#4% \fi } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@gobbletwo} % This is exactly the same as \LaTeXe's |\@gobbletwo| but needs to be a % different literal for |\hyxmp@xmp@to@pdf@date@vii|'s pattern-matching % to work. % \begin{macrocode} \let\hyxmp@gobbletwo=\@gobbletwo % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@xmp@to@pdf@date@vi} % Parse the second for |\hyxmp@xmp@to@pdf@date|. The challenge here is % that we need to handle four cases for the character following the % seconds---``|+|'', ``|-|'', ``|Z|'', and no character---without sacrificing % expandability. Our tricky solution is to insert a |\@gobbletwo| as a % sentinel and let |\hyxmp@xmp@to@pdf@date@vi| discard everything up to % that sentinel (i.e.,~all the other conditionals). % \begin{macrocode} \def\hyxmp@xmp@to@pdf@date@vi#1#2#3#4{% #1#2% \ifx#3+% +\expandafter\hyxmp@xmp@to@pdf@date@vii \fi \ifx#3-% -\expandafter\hyxmp@xmp@to@pdf@date@vii \fi \ifx#3Z% Z% \fi \ifx#3\relax \expandafter\hyxmp@gobbletwo \fi \@gobbletwo #4% } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@xmp@to@pdf@date@vii} % Parse the time-zone hours for |\hyxmp@xmp@to@pdf@date|. % \begin{macrocode} \def\hyxmp@xmp@to@pdf@date@vii#1\@gobbletwo#2#3#4#5{% #2#3% \ifx#4:% \expandafter\hyxmp@xmp@to@pdf@date@viii\expandafter#5% \fi } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@xmp@to@pdf@date@viii} % Parse the time-zone minutes for |\hyxmp@xmp@to@pdf@date|. % \begin{macrocode} \def\hyxmp@xmp@to@pdf@date@viii#1#2#3#4{% '#1#2'% } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@today@xmp@define} % Use \tex\ primitives to define a given macro as today's date in % \textsc{yyyy}-\textsc{mm}-\textsc{dd}|T|hh|:|mm|Z| format. % \changes{v2.4}{2013/12/21}{Added this macro} % \changes{v3.0}{2016/07/03}{Modified to accept the name of a macro % to define} % \changes{v3.2}{2017/02/21}{Modified to include hours and minutes} % \changes{v5.0}{2020/03/16}{Modified to specify UTC} % \begin{macrocode} \def\hyxmp@today@xmp@define#1{% % \end{macrocode} % The date is a straightforward representation of \tex's |\year|, % |\month|, and |\day| primitives, with the latter two zero-padded to % two digits apiece. % \begin{macrocode} \xdef#1{\the\year}% \ifnum\month<10 \xdef#1{#1-0\the\month}% \else \xdef#1{#1-\the\month}% \fi \ifnum\day<10 \xdef#1{#1-0\the\day}% \else \xdef#1{#1-\the\day}% \fi % \end{macrocode} % \tex\ does not provide the time in terms of separate hours and minutes % but rather as the total number of minutes since midnight (|\time|). % There's no mechanism in \tex\ to query the number of seconds since % midnight or the timezone so we omit those fields when defining % macro~|#1|. % \begin{macrocode} \@hyxmp@count=\time \divide\@hyxmp@count by 60 \ifnum\@hyxmp@count<10 \xdef#1{#1T0\the\@hyxmp@count}% \else \xdef#1{#1T\the\@hyxmp@count}% \fi \multiply\@hyxmp@count by -60 \advance\@hyxmp@count by \time \ifnum\@hyxmp@count<10 \xdef#1{#1:0\the\@hyxmp@count}% \else \xdef#1{#1:\the\@hyxmp@count}% \fi \xdef#1{#1Z}% } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@try@today} % If |\hyxmp@today@xmp| is still empty and |#1| is defined, evaluate |#2|. % Otherwise, do nothing. % \begin{macrocode} \def\hyxmp@try@today#1#2{% \@ifmtargexp{\hyxmp@today@xmp}{% \@ifundefined{#1}{}{#2}% }% {}% } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@today@xmp} % Define |\hyxmp@today@xmp| as the current date and (if available) time and % timezone in \acro{XMP} \xmpterm{Date} format~\cite{Adobe2012:XMP}. % \changes{v2.4}{2013/12/24}{Modified the code to parse the time and % timezone from \texttt{\string\string\string\pdfcreationdate}, as % proposed by Florian Breitwieser} % \changes{v5.0}{2020/03/15}{Support \string\XeTeX's \string\cs{filemoddate}} % \begin{macrocode} \def\hyxmp@today@xmp{} % \end{macrocode} % Case 1: |\pdfcreationdate| is defined (\pdfLaTeX\ and pre-0.85 \LuaLaTeX). % \begin{macrocode} \hyxmp@try@today{pdfcreationdate}{% \edef\hyxmp@today@xmp{\expandafter\hyxmp@pdf@to@xmp@date\pdfcreationdate}% } % \end{macrocode} % Case 2: |\pdffeedback| is defined (\LuaLaTeX~0.85+). % \begin{macrocode} \hyxmp@try@today{pdffeedback}{% \edef\hyxmp@today@xmp{\expandafter\hyxmp@pdf@to@xmp@date\pdffeedback creationdate}% } % \end{macrocode} % \begin{macro}{\hyxmp@timestamp} % Case 3: |\filemoddate| is defined (\XeLaTeX). % In this case, we treat the timestamp of the job's |.log| file as the % current date/time. % \label{page:jobname-log} % \changes{v5.1}{2020/04/08}{Don't rely on % \string\cs{jobname}\string\texttt{.aux} existing to query the % current time under \string\XeLaTeX\string\@. Instead, use % \string\cs{jobname}\string\texttt{.log}. Thanks to Ulrike Fischer % for the bug report and for her suggestion to use the log file.} % \begin{macrocode} \hyxmp@try@today{filemoddate}{% \edef\hyxmp@today@xmp{\filemoddate{\hyxmp@jobname.log}}% \edef\next{% \edef\noexpand\hyxmp@today@xmp{\noexpand\hyxmp@as@xmp@date{\hyxmp@today@xmp}}% }% \next }% % \end{macrocode} % Case 4: None of the above. % Do the best we can using the available \tex\ primitives (|\year|, % |\month|, |\day|, and |\time|. % \begin{macrocode} \hyxmp@try@today{year}{% \hyxmp@today@xmp@define\hyxmp@today@xmp } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\hyxmp@today@pdf} % Define |\hyxmp@today@pdf| as the current date and (if available) time % and timezone in \acro{PDF} date format~\cite{Adobe2008:PDF}. To do so % we simply convert |\hyxmp@today@xmp|, defined above, from \acro{XMP} % to \acro{PDF} using |\hyxmp@xmp@to@pdf@date|. % \changes{v5.0}{2020/03/16}{Added this macro} % \begin{macrocode} \expandafter\edef\expandafter\hyxmp@today@pdf\expandafter{% \expandafter\hyxmp@xmp@to@pdf@date\expandafter{\hyxmp@today@xmp}% } % \end{macrocode} % \end{macro} % % % \subsubsection{Trimming leading and trailing spaces} % \label{sec:trim-spaces} % % To make it easier for \acro{XMP} processors to manipulate our output we % define a |\hyxmp@trimspaces| macro to strip leading and trailing % spaces from various data fields. % % \begin{macro}{\hyxmp@trimspaces} % Redefine a macro as its previous value but without leading or trailing % spaces. This code---as well as that for its helper macros, % |\hyxmp@trimb| and |\hyxmp@trimc|---was taken almost verbatim from a % solution to an \emph{Around the Bend} puzzle~\cite{Downes1994:ATB15}. % Inline comments are also taken from the solution text. % \begin{macrocode} \catcode`\Q=3 % \end{macrocode} % |\hyxmp@trimspaces\x| redefines |\x| to have the same replacement text % sans leading and trailing space tokens. % \begin{macrocode} \newcommand{\hyxmp@trimspaces}[1]{% % \end{macrocode} % Use grouping to emulate a multi-token |afterassignment| queue. % \begin{macrocode} \begingroup % \end{macrocode} % Put ``|\toks 0 {|'' into the |afterassignment| queue. % \begin{macrocode} \aftergroup\toks\aftergroup0\aftergroup{% % \end{macrocode} % Apply |\hyxmp@trimb| to the replacement text of |#1|, adding a leading % |\noexpand| to prevent brace stripping and to serve another purpose % later. % \begin{macrocode} \expandafter\hyxmp@trimb\expandafter\noexpand#1Q Q}% % \end{macrocode} % Transfer the trimmed text back into |#1|. % \begin{macrocode} \edef#1{\the\toks0}% } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@trimb} % |\hyxmp@trimb| removes a trailing space if present, then calls % |\hyxmp@trimc| to clean up any leftover bizarre |Q|s, and trim a % leading space. In order for |\hyxmp@trimc| to work properly we need to % put back a |Q| first. % \begin{macrocode} \def\hyxmp@trimb#1 Q{\hyxmp@trimc#1Q} % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@trimc} % Execute |\vfuzz| assignment to remove leading space; the |\noexpand| % will now prevent unwanted expansion of a macro or other expandable % token at the beginning of the trimmed text. The |\endgroup| will feed % in the |\aftergroup| tokens after the |\vfuzz| assignment is % completed. % \begin{macrocode} \def\hyxmp@trimc#1Q#2{\afterassignment\endgroup \vfuzz\the\vfuzz#1} \catcode`\Q=11 % \end{macrocode} % \end{macro} % % % \subsubsection{Converting text to XML} % \label{sec:text-xml} % % The ``|<|'', ``|>|'', and ``|&|'' characters are significant to \acro{XML}. % We therefore need to escape them in any author-supplied text. % % \begin{macro}{\ifhyxmp@unicodetex} % \changes{v2.0}{2012/08/02}{Added by Heiko Oberdiek} % \begin{macro}{\hyxmp@unicodetextrue} % \begin{macro}{\hyxmp@unicodetexfalse} % \XeTeX\ and \LuaTeX\ natively support \term{Unicode}. We define the % conditional |\ifhyxmp@unicodetex| to check for these so we can % properly handle encoding conversions. The trick here is that % \term{Unicode} \tex\ implementations compare decimal~64 to % hexadecimal~40 (decimal~64), specified with four carets, and take the % \textsc{true} branch; non-\term{Unicode} \tex\ implementations compare % decimal~64 to character~``|^|'' (decimal~94), ignore the ``|^^0040|'' % and the rest of the \textsc{true} branch, and take the \textsc{false} % branch. % \begin{macrocode} \newif\ifhyxmp@unicodetex \ifnum64=`\^^^^0040\relax \hyxmp@unicodetextrue \else \hyxmp@unicodetexfalse \fi % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\SE->pdfdoc@03} % Preserve \acro{ETX} (|^^C|), which is normally an invalid character in % \term{PDFDocEncoding}. We use it in \pkgname{hyperxmp} (and % specifically in |\hyxmp@xmlify| below) as a list-element separator. % \begin{macrocode} \expandafter\def\csname SE->pdfdoc@03\endcsname{0003} % \end{macrocode} % \end{macro} % % \begin{macro}{\SE->pdfdoc@15} % Preserve \acro{NAK} (|^^U|), which is normally an invalid character in % \term{PDFDocEncoding}. We use it in \pkgname{hyperxmp} (and % specifically in |\hyxmp@xmlify| below) as a placeholder for an % underscore character. % \begin{macrocode} \expandafter\def\csname SE->pdfdoc@15\endcsname{0015} % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@xmlify} % \changes{v2.0}{2012/08/02}{Completely rewritten by Heiko Oberdiek to % better support Unicode-enabled \TeX\ programs} % \begin{macro}{\hyxmp@xmlified} % \begin{macro}{\hyxmp@text} % Given a piece of text defined using |\pdfstringdef| (i.e.,~with many % special characters redefined to have category code~11), set % |\hyxmp@xmlified| to the same text but with all occurrences of~``|<|'' % replaced with~|<|, all occurrences of~``|>|'' replaced with~|>|, % and all occurrences of~``|&|'' replaced with~|&|. % \begin{macrocode} \newcommand*{\hyxmp@xmlify}[1]{% \gdef\hyxmp@xmlified{}% % \end{macrocode} % Escaped \acro{PDF} string~$\rightarrow$ \term{PDFDocEncoding}/\term{Unicode} % \begin{macrocode} \EdefUnescapeString\hyxmp@text{#1}% \ifhyxmp@unicodetex % \end{macrocode} % \term{PDFDocEncoding}/\term{Unicode}~$\rightarrow$ \acro{UTF-32BE} % \begin{macrocode} \hyxmp@is@unicode\hyxmp@text{% \StringEncodingConvert \hyxmp@text\hyxmp@text{utf16be}{utf32be}% }{% \ifXeTeX \hyxmp@xetex@crap \else \StringEncodingConvert \hyxmp@text\hyxmp@text{pdfdoc}{utf32be}% \fi }% % \end{macrocode} % \acro{UTF-32BE}~$\rightarrow$ \acro{UTF-32BE} as hex string % \begin{macrocode} \EdefEscapeHex\hyxmp@text{\hyxmp@text}% % \end{macrocode} % \acro{UTF-32BE}~$\rightarrow$ \acro{XML} in \acro{ASCII} % \begin{macrocode} \edef\hyxmp@text{% \expandafter }\expandafter\hyxmp@toxml@unicodetex\hyxmp@text \relax\relax\relax\relax\relax\relax\relax\relax \else % \end{macrocode} % \term{PDFDocEncoding}/\term{Unicode}~$\rightarrow$ \acro{UTF-8} % \begin{macrocode} \hyxmp@is@unicode\hyxmp@text{% \StringEncodingConvert \hyxmp@text\hyxmp@text{utf16be}{utf8}% }{% \StringEncodingConvert \hyxmp@text\hyxmp@text{pdfdoc}{utf8}% }% % \end{macrocode} % \acro{UTF-8}~$\rightarrow$ \acro{UTF-8} as hex string % \begin{macrocode} \EdefEscapeHex\hyxmp@text{\hyxmp@text}% % \end{macrocode} % \acro{UTF-8} as hex string~$\rightarrow$ \acro{XML} in \acro{UTF-8} % as hex string % \begin{macrocode} \edef\hyxmp@text{% \expandafter\hyxmp@toxml\hyxmp@text\@empty\@empty }% % \end{macrocode} % \acro{XML} in \acro{UTF-8} as hex string~$\rightarrow$ \acro{XML} % in \acro{UTF-8} % \begin{macrocode} \EdefUnescapeHex\hyxmp@text{\hyxmp@text}% \fi \global\let\hyxmp@xmlified\hyxmp@text } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\hyxmp@is@unicode} % \changes{v2.0}{2012/08/02}{Added by Heiko Oberdiek} % \begin{macro}{\hyxmp@@is@unicode} % Given a string and two expressions, evaluate the first expression if % the string is \acro{UTF-16BE}-encoded and the second expression if not. % \begin{macrocode} \begingroup \lccode`\<=254 % \lccode`\>=255 % \catcode254=12 % \catcode255=12 % \lowercase{\endgroup \def\hyxmp@is@unicode#1{% \expandafter\hyxmp@@is@unicode#1<>\@nil }% \def\hyxmp@@is@unicode#1<>#2\@nil{% \ifx\\#1\\% \expandafter\@firstoftwo \else \expandafter\@secondoftwo \fi }% } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\hyxmp@toxml} % \changes{v2.0}{2012/08/02}{Added by Heiko Oberdiek} % Replace the characters ``\textless'', ``\&'', and ``\textgreater'' with % \acro{XML} entities when using a non-native-\term{Unicode} % \tex\ (\tex\ or \pdfTeX). % \begin{macrocode} \def\hyxmp@toxml#1#2{% \ifx#1\@empty \else \ifnum"#1#2=`\& % 26616D703B% & \else\ifnum"#1#2=`\< % 266C743B% < \else\ifnum"#1#2=`\> % 2667743B% > \else % \end{macrocode} % \cmdname{dvips} wraps text when generating most PostScript code but % preserves line breaks within strings. Unfortunately, \cmdname{dvips} % fails to observe the special case in the PostScript specification that % ``[b]alanced pairs of parentheses in the string require no special % treatment''~\cite{Adobe1996:postscript}. Consequently, \acro{XMP} % data containing parentheses (e.g.,~``\texttt{Copyright (C) 1605 Miguel % de Cervantes}'') confuse \cmdname{dvips} into thinking that the % string has ended after the closing parenthesis and that line breaks % can subsequently be injected safely into the document at arbitrary % points for formatting purposes. This leads to erroneous display by % \acro{PDF} viewers, which honor line breaks within \acro{XMP} tags. % The solution is to insert a backslash before all parentheses when in % \texttt{pdfmark}-generating mode to convince \cmdname{dvips} that the % entire \acro{XMP} packet must be treated as a single, % not-to-be-modified string. % \changes{v2.0}{2012/08/22}{Escaped parentheses written with % \texttt{pdfmark}s to prevent \cmdname{dvips} from line-wrapping the % \protect\acro{XMP} packet} % \begin{macrocode} \@ifundefined{pdfmark}{% #1#2% }{% \ifnum"#1#2=`\( % 5C28% \( \else\ifnum"#1#2=`\) % 5C29% \) \else #1#2% \fi\fi }% \fi\fi\fi \expandafter\hyxmp@toxml \fi } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@toxml@unicodetex} % \changes{v2.0}{2012/08/02}{Added by Heiko Oberdiek} % \begin{macro}{\hyxmp@text} % Replace the characters ``\textless'', ``\&'', and ``\textgreater'' with % \acro{XML} entities when using a native-\term{Unicode} % \tex\ (\XeTeX\ or \LuaTeX). % \begin{macrocode} \def\hyxmp@toxml@unicodetex#1#2#3#4#5#6#7#8{% \ifx#1\relax \else \ifnum"#1#2#3#4#5#6#7#8>127 % \uccode`\*="#1#2#3#4#5#6#7#8\relax \uppercase{% \edef\hyxmp@text{\hyxmp@text *}% }% \else\ifnum"#7#8=`\< % \edef\hyxmp@text{\hyxmp@text <}% \else\ifnum"#7#8=`\& % \edef\hyxmp@text{\hyxmp@text &}% \else\ifnum"#7#8=`\> % \edef\hyxmp@text{\hyxmp@text >}% \else\ifnum"#7#8=`\ % \edef\hyxmp@text{\hyxmp@text\space}% \else \uccode`\*="#7#8\relax \uppercase{% \edef\hyxmp@text{\hyxmp@text *}% }% \fi\fi\fi\fi\fi \expandafter\hyxmp@toxml@unicodetex \fi } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\hyxmp@skipzeros} % \changes{v2.0}{2012/08/02}{Added by Heiko Oberdiek} % Skip over leading zeroes in the input argument. % \begin{macrocode} \def\hyxmp@skipzeros#1{% \ifx#10% \expandafter\hyxmp@skipzeros \fi } % \end{macrocode} % \end{macro} % % \begin{macro}{\x} % \begin{macro}{\hyxmp@xetex@crap} % \changes{v2.0}{2012/08/02}{Added by Heiko Oberdiek} % \begin{macro}{\hyxmp@try} % \begin{macro}{\hyxmp@crap@result} % \begin{macro}{\hyxmp@text} % In the case of \XeTeX, the strings defined by |\pdfstringdef| can % contain big characters. In this case, the string is treated as % \term{Unicode}. % \begin{macrocode} \begingroup \def\x#1{\endgroup \def\hyxmp@xetex@crap{% \edef\hyxmp@try{% \expandafter\hyxmp@SpaceOther\hyxmp@text#1\@nil }% \let\hyxmp@crap@result=N% \expandafter\hyxmp@crap@test\hyxmp@try\relax \ifx\hyxmp@crap@result Y% \let\hyxmp@text\@empty \expandafter\hyxmp@crap@convert\hyxmp@try\relax \else \StringEncodingConvert\hyxmp@text\hyxmp@text{pdfdoc}{utf32be}% \fi }% } \x{ } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\hyxmp@SpaceOther} % Re-encode all spaces in a string with category code~12 (``other''). % \changes{v2.0}{2012/08/02}{Added by Heiko Oberdiek} % \begin{macrocode} \begingroup \catcode`\~=12 % \lccode`\~=`\ % \lowercase{\endgroup \def\hyxmp@SpaceOther#1 #2\@nil{% #1% \ifx\relax#2\relax \expandafter\@gobble \else ~% \expandafter\@firstofone \fi {\hyxmp@SpaceOther#2\@nil}% }% } % \end{macrocode} % \end{macro} % % % \begin{macro}{\hyxmp@crap@test} % Determine if we need to treat a string as \term{Unicode}. % \changes{v2.0}{2012/08/02}{Added by Heiko Oberdiek} % \begin{macrocode} \def\hyxmp@crap@test#1{% \ifx#1\relax \else \ifnum`#1>127 % \let\hyxmp@crap@result=Y% \expandafter\expandafter\expandafter\hyxmp@skiptorelax \else \expandafter\expandafter\expandafter\hyxmp@crap@test \fi \fi } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@skiptorelax} % Discard all tokens up to and including the first |\relax|. % \changes{v2.0}{2012/08/02}{Added by Heiko Oberdiek} % \begin{macrocode} \def\hyxmp@skiptorelax#1\relax{} % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@crap@convert} % \changes{v2.0}{2012/08/02}{Added by Heiko Oberdiek} % \begin{macro}{\hyxmp@num} % \begin{macro}{\hyxmp@text} % Convert a hexadecimal string to a number. % \begin{macrocode} \def\hyxmp@crap@convert#1{% \ifx#1\relax \else \edef\hyxmp@num{\number`#1}% \ifnum\hyxmp@num>"FFFFFF % \lccode`\!=\intcalcDiv{\hyxmp@num}{\number"1000000}\relax \lowercase{\edef\hyxmp@text{\hyxmp@text!}}% \edef\hyxmp@num{\intcalcMod{\hyxmp@num}{\number"1000000}}% \else \edef\hyxmp@text{\hyxmp@text\hyxmp@zero}% \fi \ifnum\hyxmp@num>"FFFF % \lccode`\!=\intcalcDiv{\hyxmp@num}{\number"10000}\relax \lowercase{\edef\hyxmp@text{\hyxmp@text!}}% \edef\hyxmp@num{\intcalcMod{\hyxmp@num}{\number"10000}}% \else \edef\hyxmp@text{\hyxmp@text\hyxmp@zero}% \fi \ifnum\hyxmp@num>"FF % \lccode`\!=\intcalcDiv{\hyxmp@num}{\number"100}\relax \lowercase{\edef\hyxmp@text{\hyxmp@text!}}% \edef\hyxmp@num{\intcalcMod{\hyxmp@num}{\number"100}}% \else \edef\hyxmp@text{\hyxmp@text\hyxmp@zero}% \fi \ifnum\hyxmp@num>0 % \lccode`\!=\hyxmp@num\relax \lowercase{\edef\hyxmp@text{\hyxmp@text!}}% \else \edef\hyxmp@text{\hyxmp@text\hyxmp@zero}% \fi \expandafter\hyxmp@crap@convert \fi } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\hyxmp@zero} % Define a null character with category code~12 (``other''). % \changes{v2.0}{2012/08/02}{Added by Heiko Oberdiek} % \begin{macrocode} \begingroup \catcode0=12 % \gdef\hyxmp@zero{^^00}% \endgroup % \end{macrocode} % \end{macro} % % % \subsubsection{Outputting structured XML} % \label{sec:output-xml} % % An \acro{XMP} packet consists of structured \acro{XML} data. We % define some helper routines to handle the repetitive tasks of % indenting a consistent number of spaces, inserting begin and end tags, % and escaping arbitrary text as necessary for \acro{XML} compatibility. % % \begin{macro}{\hyxmp@extra@indent} % This macro is used internally to increase the amount of indentation % when writing certain \acro{XML} data. It is normally defined as empty % but can temporarily be redefined to a sequence of |\space| characters. % \begin{macrocode} \newcommand*{\hyxmp@extra@indent}{} % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@add@simple} % Given an \acro{XMP} tag~(|#1|) and a string~(|#2|), if the string is % nonempty, add a begin tag, the string, and an end tag to the packet. % The ``|simple|'' in the macro name indicates that the string is output % without variations for different languages. % \changes{v2.0}{2012/08/25}{Added this macro} % \changes{v5.0}{2020/02/21}{Insert the tag name (\string\texttt{\#1}) % verbatim} % \begin{macrocode} \newcommand*{\hyxmp@add@simple}[2]{% \@ifnotmtargexp{#2}{% \hyxmp@xmlify{#2}% \hyxmp@add@to@xml{\hyxmp@extra@indent______<}% \xdef\hyxmp@xml{\hyxmp@xml#1}% \hyxmp@add@to@xml{>\hyxmp@xmlified^^J}% }% } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@add@simple@var} % Given an \acro{XMP} tag~(|#1|) and a variable name~(|#2|), if the % string is defined, add a begin tag, the string, and an end tag to the % packet. The ``|simple|'' in the macro name indicates that the string % is output without variations for different languages. % |\hyxmp@add@simple@var| differs from |\hyxmp@add@simple| in that the % former includes defined but empty values in the \acro{XMP} packet % while the latter excludes both undefined and defined but empty values. % \changes{v2.4}{2013/12/21}{Added this macro} % \begin{macrocode} \newcommand*{\hyxmp@add@simple@var}[2]{% \expandafter\ifx\csname#2\endcsname\relax \else \hyxmp@xmlify{\csname#2\endcsname}% \hyxmp@add@to@xml{% \hyxmp@extra@indent______<#1>\hyxmp@xmlified^^J% }% \fi } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@add@simple@lang} % Given an \acro{XMP} tag~(|#1|) and a string~(|#2|), if the string is % nonempty, add a begin tag, the string, and an end tag to the packet. % The ``|simple|'' in the macro name indicates that the string is output % without variations for different languages. However, if the string % begins with a language code in square brackets, specify that as the % (sole) language for the tag. % \changes{v4.0}{2019/03/12}{Added this macro} % \begin{macrocode} \newcommand*{\hyxmp@add@simple@lang}[2]{% \@ifnotmtarg{#2}{% \hyxmp@xmlify{#2}% \expandafter\hyxmp@add@simple@lang@i\hyxmp@xmlified\relax{#1}% }% } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@add@simple@lang@i} % This is a helper macro for |\hyxmp@add@simple@lang|. It takes an % optional language code (in brackets), text up to |\relax|, and a tag, % and typesets the text within the \acro{XML} tag. % \begin{macrocode} \newcommand*{\hyxmp@add@simple@lang@i}{% \@ifnextchar[\hyxmp@add@simple@lang@ii{\hyxmp@add@simple@lang@ii[\@pdfmetalang]}% } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@add@simple@lang@ii} % This is another helper macro for |\hyxmp@add@simple@lang|. It takes % an mandatory language code (in brackets; can be empty), text up to % |\relax|, and a tag, and typesets the text within the \acro{XML} tag. % \begin{macrocode} \def\hyxmp@add@simple@lang@ii[#1]#2\relax#3{% \@ifnotmtarg{#2}{% \hyxmp@xmlify{#2}% \@ifmtarg{#1}{% \hyxmp@add@to@xml{% ______<#3>\hyxmp@xmlified^^J% }% }{% \hyxmp@add@to@xml{% ______<#3 xml:lang="#1">\hyxmp@xmlified^^J% }% }% }% } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@add@simple@pfx} % Given an \acro{XMP} tag~(|#1|), a---typically hard-wired---prefix % string~(|#2|), and a main string~(|#2|), if the main string is % nonempty, add a begin tag, both strings, and an end tag to the packet. % The ``|simple|'' in the macro name indicates that the string is output % without variations for different languages. % \changes{v5.2}{2020/04/29}{Added this macro} % \begin{macrocode} \newcommand*{\hyxmp@add@simple@pfx}[3]{% \@ifnotmtargexp{#3}{% \hyxmp@add@to@xml{\hyxmp@extra@indent______<}% \xdef\hyxmp@xml{\hyxmp@xml#1}% \hyxmp@pdfstringdef\hyxmp@iprefix{#2}% \hyxmp@xmlify{\hyxmp@iprefix}% \hyxmp@add@to@xml{>\hyxmp@xmlified}% \hyxmp@xmlify{#3}% \hyxmp@add@to@xml{\hyxmp@xmlified^^J}% }% } % \end{macrocode} % \end{macro} % % % \subsubsection{Providing metadata in multiple languages} % \label{sec:lang-alt} % % Certain \acro{XMP} tags---\xmpprop{dc:title}, % \xmpprop{dc:description}, and \xmpprop{dc:rights} (and others? Let me % know.)---can be expressed in multiple languages. The same text is % used for both language \optname{pdfmetalang} (default: % \optname{pdflang}) and language ``\xmpterm{x-default}''. To express % the same metadata in multiple languages, we provide an |\XMPLangAlt| % macro to construct a list of alternative forms for a piece of % metadata. % % \begin{macro}{\hyxmp@alt@title} % \begin{macro}{\hyxmp@alt@description} % \begin{macro}{\hyxmp@alt@rights} % Each of these macros is a list in which each element is of the form % ``|\do| \meta{language} \meta{text}'' in which \meta{language} is an % \acro{ISO} \mbox{639-1} two-letter country code with an optional % \acro{ISO} \mbox{3166-1} two-letter region code. For example, % |\hyxmp@alt@title| may contain an element, ``|\do| |{es-MX}| % |{Este| |es| |mi| |documento}|''. % \begin{macrocode} \def\hyxmp@alt@title{} \def\hyxmp@alt@description{} \def\hyxmp@alt@rights{} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\hyxmp@LA@accept} % This macro wraps |\define@key| to make the option ``|#1|=\meta{value}'' % append \meta{value} to list~|#2|. % \begin{macrocode} \newcommand{\hyxmp@LA@accept}[2]{% \define@key{hyxmp@LA}{#1}{% % \end{macrocode} % \begin{macro}{\hyxmp@value} % As Niklas Beisert observed, if the option passed to the current key % contains \LaTeX\ code, this code will be included in the \acro{XMP} % packet, which is undesirable. Hence, we first clean up the string % using |\hyxmp@pdfstringdef|. % \begin{macrocode} \hyxmp@pdfstringdef\hyxmp@value{##1}% \xdef#2{#2\noexpand\do {\hyxmp@cur@lang} {\hyxmp@value}}% } } % \end{macrocode} % \end{macro} % \end{macro} % % Define \meta{key}=\meta{value} options for appending to each of the % |\hyxmp@alt|\meta{tag} lists. % \begin{macrocode} \hyxmp@LA@accept{pdftitle}{\hyxmp@alt@title} \hyxmp@LA@accept{pdfsubject}{\hyxmp@alt@description} \hyxmp@LA@accept{pdfcopyright}{\hyxmp@alt@rights} % \end{macrocode} % % \begin{macro}{\XMPLangAlt} % Argument~|#1| is a language expressed as a two-letter country code and % optional two-letter region code. Argument~|#2| is a list of % \meta{key}=\meta{value} pairs. Keys correspond to |\hypersetup| % options such as ``|pdftitle|'', ``|pdfsubject|'', and % ``|pdfcopyright|''. Values are the alternative-language form of the % text provided for the corresponding option. % \changes{v3.3}{2017/07/22}{Added this macro based on a request---and % some code---by Niklas Beisert to support metadata expressed in multiple % languages} % \begin{macrocode} \newcommand{\XMPLangAlt}[2]{% \let\do=\relax % \end{macrocode} % \begin{macro}{\hyxmp@cur@lang} % Store the provided language, which will be used during option processing. % \begin{macrocode} \edef\hyxmp@cur@lang{#1}% \setkeys{hyxmp@LA}{#2}% } % \end{macrocode} % \end{macro} % \end{macro} % % % \subsection{UUID generation} % \label{sec:uuid-gen} % % We use a linear congruential generator to produce pseudorandom % version~4 \acro{UUID}s~\cite{Leach2005:uuid}. True, this method has % its flaws but it's simple to implement in \tex\ and is good enough for % producing the \acro{XMP} \xmpprop{xmpMM:DocumentID} and % \xmpprop{xmpMM:InstanceID} fields. % % \begin{macro}{\hyxmp@modulo@a} % Replace the contents of |\@hyxmp@count| with the contents modulo~|#1|. % Note that |\@tempcntb| is overwritten in the process. % \begin{macrocode} \def\hyxmp@modulo@a#1{% \@tempcntb=\@hyxmp@count \divide\@tempcntb by #1 \multiply\@tempcntb by #1 \advance\@hyxmp@count by -\@tempcntb } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@big@prime} % \begin{macro}{\hyxmp@big@prime@ii} % Define a couple of large prime numbers that can still be stored in a % \tex\ counter. % \begin{macrocode} \def\hyxmp@big@prime{536870923} \def\hyxmp@big@prime@ii{536870027} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\hyxmp@seed@rng} % \begin{macro}{\hyxmp@one@token} % Seed \pkgname{hyperxmp}'s random-number generator from a given piece % of text. % \begin{macrocode} \def\hyxmp@seed@rng#1{% \@hyxmp@count=\hyxmp@big@prime \futurelet\hyxmp@one@token\hyxmp@seed@rng@i#1\@empty } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\hyxmp@seed@rng@i} % \begin{macro}{\hyxmp@one@token} % \begin{macro}{\next} % Do all of the work for |\hyxmp@seed@rng|. For each character code $c$ % of the input text, assign $\mathtt{\string\@hyxmp@count} \leftarrow 3 % \cdot \mathtt{\string\@hyxmp@count} + c % \pmod{\mathtt{\string\hyxmp@big@prime}}$. % \begin{macrocode} \def\hyxmp@seed@rng@i{% \ifx\hyxmp@one@token\@empty \let\next=\relax \else \def\next##1{% \multiply\@hyxmp@count by 3 \advance\@hyxmp@count by `##1 \hyxmp@modulo@a{\hyxmp@big@prime}% \futurelet\hyxmp@one@token\hyxmp@seed@rng@i }% \fi \next } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\hyxmp@set@rand@num} % \begin{macro}{\hyxmp@rand@num} % Advance |\hyxmp@rand@num| to the next pseudorandom number in the % sequence. Specifically, we assign $\mathtt{\string\hyxmp@rand@num} % \leftarrow 3 \cdot \mathtt{\string\hyxmp@rand@num} + % \mathtt{\string\hyxmp@big@prime@ii} % \pmod{\mathtt{\string\hyxmp@big@prime}}$. Note that both |\@hyxmp@count| % and |\@tempcntb| are overwritten in the process. % \begin{macrocode} \def\hyxmp@set@rand@num{% \@hyxmp@count=\hyxmp@rand@num \multiply\@hyxmp@count by 3 \advance\@hyxmp@count by \hyxmp@big@prime@ii \hyxmp@modulo@a{\hyxmp@big@prime}% \xdef\hyxmp@rand@num{\the\@hyxmp@count}% } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\hyxmp@append@hex} % Append a randomly selected hexadecimal digit to macro~|#1|. Note that % both |\@hyxmp@count| and |\@tempcntb| are overwritten in the process. % \begin{macrocode} \def\hyxmp@append@hex#1{% \hyxmp@set@rand@num \@hyxmp@count=\hyxmp@rand@num \hyxmp@modulo@a{16}% \ifnum\@hyxmp@count<10 \xdef#1{#1\the\@hyxmp@count}% \else % \end{macrocode} % There \emph{must} be a better way to handle the numbers~10--15 than % with |\ifcase|. % \begin{macrocode} \advance\@hyxmp@count by -10 \ifcase\@hyxmp@count \xdef#1{#1a}% \or\xdef#1{#1b}% \or\xdef#1{#1c}% \or\xdef#1{#1d}% \or\xdef#1{#1e}% \or\xdef#1{#1f}% \fi \fi } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@append@hex@iii} % Invoke |\hyxmp@append@hex| three times. % \begin{macrocode} \def\hyxmp@append@hex@iii#1{% \hyxmp@append@hex#1% \hyxmp@append@hex#1% \hyxmp@append@hex#1% } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@append@hex@iv} % Invoke |\hyxmp@append@hex| four times. % \begin{macrocode} \def\hyxmp@append@hex@iv#1{% \hyxmp@append@hex@iii#1% \hyxmp@append@hex#1% } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@create@uuid} % As per the definition of a version~4 % \acro{UUID}~\cite{Leach2005:uuid}, define macro~|#1| as a \acro{UUID} % of the form % ``|uuid:|\textit{xxxxxxxx}|-|\linebreak[0]\textit{xxxx}|-|\linebreak[0]\textit{4xxx}|-|\linebreak[0]\textit{yxxx}|-|\linebreak[0]\textit{xxxxxxxxxxxx}'' % in which each ``\textit{x}'' is a lowercase hexadecimal digit and % ``\textit{y}'' is one of ``|8|'', ``|9|'', ``|a|'', or~``|b|''. We % assume that the random-number generator is already seeded. Note that % |\hyxmp@create@uuid| overwrites both |\@hyxmp@count| and |\@tempcntb|. % \changes{v2.4}{2014/01/02}{Modified this macro to produce a proper % version~4 (random or pseudorandom) \protect\acro{UUID}} % \begin{macrocode} \def\hyxmp@create@uuid#1{% \def#1{uuid:}% \hyxmp@append@hex@iv#1% \hyxmp@append@hex@iv#1% \g@addto@macro#1{-}% \hyxmp@append@hex@iv#1% \g@addto@macro#1{-4}% \hyxmp@append@hex@iii#1% \g@addto@macro#1{-}% % \end{macrocode} % Randomly select one of ``|8|'', ``|9|'', ``|a|'', or~``|b|''. % \begin{macrocode} \hyxmp@set@rand@num \@hyxmp@count=\hyxmp@rand@num \hyxmp@modulo@a{4}% \ifcase\@hyxmp@count \g@addto@macro#1{8}% \or\g@addto@macro#1{9}% \or\g@addto@macro#1{a}% \or\g@addto@macro#1{b}% \fi \hyxmp@append@hex@iii#1% \g@addto@macro#1{-}% \hyxmp@append@hex@iv#1% \hyxmp@append@hex@iv#1% \hyxmp@append@hex@iv#1% } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@def@DocumentID} % \begin{macro}{\hyxmp@DocumentID} % \begin{macro}{\hyxmp@seed@string} % Seed the random-number generator with a function of the current % filename, \acro{PDF} document title, and \acro{PDF} author, then invoke % |\hyxmp@create@uuid| to define |\hyxmp@DocumentID| as a random \acro{UUID}. % \changes{v3.4}{2017/11/04}{Correctly handle an author field of all spaces. % Bug reported by Ga\"etan Leurent} % \begin{macrocode} \newcommand*{\hyxmp@def@DocumentID}{% \edef\hyxmp@seed@string{\hyxmp@jobname:\@pdftitle:\@pdfauthor:}% \expandafter\hyxmp@seed@rng\expandafter{\hyxmp@seed@string}% \edef\hyxmp@rand@num{\the\@hyxmp@count}% \hyxmp@create@uuid\hyxmp@DocumentID } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\hyxmp@def@InstanceID} % \begin{macro}{\hyxmp@InstanceID} % \begin{macro}{\hyxmp@seed@string} % Seed the random-number generator with a function of the current % filename, \acro{PDF} document title, \acro{PDF} author, and the % current timestamp, then invoke |\hyxmp@create@uuid| to define % |\hyxmp@InstanceID| as a random \acro{UUID}. For the current % timestamp, we use both the document-specified timestamp from % \optname{pdfdate} and the \tex\ time. The former can be more precise % (to sub-seconds) but may be less random (as it depends on manual % document modifications) while the latter is typically less precise (to % minutes) but may be more random (as it is updated automatically). % \changes{v3.5}{2018/11/27}{Seed with the \protect\TeX\ timestamp in % addition to the document-specified timestamp} % \begin{macrocode} \newcommand*{\hyxmp@def@InstanceID}{% \hyxmp@today@xmp@define{\hyxmp@seed@string}% \edef\hyxmp@seed@string{% \hyxmp@jobname:\@pdftitle:\@pdfauthor:\hyxmp@today@xmp:\hyxmp@seed@string }% \expandafter\hyxmp@seed@rng\expandafter{\hyxmp@seed@string}% \edef\hyxmp@rand@num{\the\@hyxmp@count}% \hyxmp@create@uuid\hyxmp@InstanceID } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % % \subsection{Constructing the XMP packet} % % An \acro{XMP} packet ``shall consist of the following, in order: a % header \acro{PI}, the serialized \acro{XMP} data model (the \acro{XMP} % packet) with optional white-space padding, and a trailer % \acro{PI}''~\cite{Adobe2012:XMP}. (``\acro{PI}'' is an abbreviation for % ``processing instructions''). The serialized \acro{XMP} includes blocks % of \acro{XML} for various \acro{XMP} schemata: % ^^A % \schema[Adobe PDF]{Adobe \protect\acro{PDF}} (Section~\ref{sec:adobe-pdf}), % \schema{Dublin Core} (Section~\ref{sec:dublin-core}), % \schema[XMP Rights Management]{\protect\acro{XMP} Rights Management} (Section~\ref{sec:xmp-rights}), % \schema[XMP Media Management]{\protect\acro{XMP} Media Management} (Section~\ref{sec:xmp-media}), % \schema[XMP Basic]{\protect\acro{XMP} Basic} (Section~\ref{sec:xmp-basic}), % \schema{Photoshop} (Section~\ref{sec:photoshop}), % \index{PDF/A Identification schema=\acro {PDF/A} Identification schema} % \index{PDF/X Identification schema=\acro {PDF/X} Identification schema} % \index{PDF/UA Identification schema=\acro {PDF/UA} Identification schema} % \index{schemata&PDF/A Identification=\acro {PDF/A} Identification} % \index{schemata&PDF/X Identification=\acro {PDF/X} Identification} % \index{schemata&PDF/UA Identification=\acro {PDF/UA} Identification} % \acro{PDF}\textsc{/*} Identification (Section~\ref{sec:pdfX-id}), % \schema[IPTC Photo Metadata]{\protect\acro{IPTC} Photo Metadata} (Section~\ref{sec:photo-meta}), % \schema[PRISM Basic Metadata]{\protect\acro{PRISM} Basic Metadata} (Section~\ref{sec:prism-meta}), % \schema{Journal Article Versions} (Section~\ref{sec:niso-jav-meta}), and % \schema[XMP Paged-Text]{\protect\acro{XMP} Paged-Text} (Section~\ref{sec:xmp-paged-text}). % ^^A % The |\hyxmp@construct@packet| macro % (Section~\ref{sec:combining-schemata}) constructs the \acro{XMP} packet % into |\hyxmp@xml|. It first writes the appropriate \acro{XML} header, % then calls the various schema-writing macros, then injects % |\hyxmp@padding| as padding, and finally writes the appropriate % \acro{XML} trailer. % % \subsubsection{XMP utility functions} % % \begin{macro}{\hyxmp@add@to@xml} % Given a piece of text, replace all underscores with category-code~11 % (``other'') spaces and all |^C| characters with commas, then append % the result to the |\hyxmp@xml| macro. % \changes{v2.0}{2012/08/24}{Updated also to replace commas} % \changes{v2.5}{2014/06/19}{Updated also to replace underscores and to % modify only the text being added, not the already-modified text} % \changes{v2.8}{2014/04/05}{Corrected inadvertent lowercasing of non-Latin % characters when run under \XeLaTeX\ or \LuaLaTeX\ (bug reported by % Leonid Sinev)} % \begin{macrocode} \newcommand*{\hyxmp@add@to@xml}[1]{% \bgroup \@hyxmp@count=0 \ifhyxmp@unicodetex \@tempcntb=65536% \else \@tempcntb=256% \fi \loop \lccode\@hyxmp@count=\@hyxmp@count \advance\@hyxmp@count by 1 \ifnum\@hyxmp@count<\@tempcntb \repeat \lccode`\_=`\ \relax \lccode`\^^C=`\,\relax \lccode`\^^U=`\_\relax \lowercase{\xdef\hyxmp@new@xml{#1}}% \xdef\hyxmp@xml{\hyxmp@xml\hyxmp@new@xml}% \egroup } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@hash} % Define a category-code~11 (``other'') version of the ``|#|'' character. % \begin{macrocode} \bgroup \catcode`\#=11 \gdef\hyxmp@hash{#} \egroup % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@padding} % \begin{macro}{\hyxmp@xml} % The \acro{XMP} specification recommends leaving approximately % 2000~bytes of whitespace at the end of each \acro{XMP} packet to % facilitate editing the packet in place~\cite{Adobe2012:XMP}. % |\hyxmp@padding| is defined to contain 32~lines of 63~spaces and a % newline apiece for a total of 2048 characters of whitespace. % \begin{macrocode} \bgroup \xdef\hyxmp@xml{}% \hyxmp@add@to@xml{% _______________________________________________________________^^J% } \xdef\hyxmp@padding{\hyxmp@xml}% \egroup \xdef\hyxmp@padding{\hyxmp@padding\hyxmp@padding} \xdef\hyxmp@padding{\hyxmp@padding\hyxmp@padding} \xdef\hyxmp@padding{\hyxmp@padding\hyxmp@padding} \xdef\hyxmp@padding{\hyxmp@padding\hyxmp@padding} \xdef\hyxmp@padding{\hyxmp@padding\hyxmp@padding} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\hyxmp@x@default} % Define an \xmpterm{x-default} string that we can use in comparisons % with |\@pdfmetalang|. % \begin{macrocode} \newcommand*{\hyxmp@x@default}{x-default} % \end{macrocode} % \end{macro} % % % \subsubsection{The Adobe PDF schema} % \label{sec:adobe-pdf} % % \begin{schemadesc}[Adobe PDF]{Adobe \protect\acro{PDF}} % % Older versions of \pkgname{hyperref} defined a default producer; newer % versions do not. Instead, they let the \tex\ engine define the % producer itself. This poses a problem for \acro{PDF/A} compliance % because \pkgname{hyperxmp} sees an empty producer and therefore omits % writing a \xmpprop{pdf:Producer} to the \acro{XMP} packet, causing a % mismatch between the data in the \acro{XMP} packet and the data in the % \acro{PDF} \pdfterm{Info} dictionary. To ensure consistency between % \acro{XMP} and \pdfterm{Info}, we explicitly define our own default % |\@pdfproducer| here. % % \begin{macro}{\@pdfproducer} % \begin{macro}{\hyxmp@define@pdfproducer} % Define |\@pdfproducer| using the banner string if available or the % \tex\ engine's version number if not. % \changes{v5.0}{2020/03/01}{Added this macro} % \changes{v5.1}{2020/04/06}{Check for \string\LuaTeX\ before checking for % \string\pdfTeX\ to work around \string\pkgname{luatex85}'s confusing % \string\pkgname{iftex} by defining \string\cs{pdftexversion}. Thanks % to Robin Schwab for the bug report} % \begin{macrocode} \newcommand*{\hyxmp@define@pdfproducer}{% \gdef\@pdfproducer{TeX} \ifLuaTeX \expandafter\hyxmp@banner@to@producer\expandafter{\luatexbanner}% \else \ifPDFTeX \expandafter\hyxmp@banner@to@producer\expandafter{\pdftexbanner}% \else \ifXeTeX \edef\@pdfproducer{XeTeX version \the\XeTeXversion\XeTeXrevision}% \fi \fi \fi } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\@pdfproducer} % \begin{macro}{\hyxmp@banner@to@producer} % Define |\@pdfproducer| as the \tex\ engine's banner string % \ifPDFTeX % (e.g.,~``\texttt{\pdftexbanner}''), % \else % \ifLuaTeX % (e.g.,~``\texttt{\luatexbanner}''), % \else % (e.g.,~``\texttt{This is pdfTeX, Version 3.14159265-2.6-1.40.20 % (TeX Live 2019/Debian) kpathsea version 6.3.1}''), % \fi % \fi % removing the initial ``\texttt{This is}'' if possible (specifically, % when $\varepsilon$-\TeX's\index{e-TeX=$\varepsilon$-\TeX} % |\scantokens| primitive is available). % \changes{v5.1}{2020/04/03}{Prevent the category code of ``@'' from % propagating past the \cs{begin}\string\texttt{\{document\}}. % Thanks to Robert Schlicht for noticing this catcode ``leak'' and % providing a correction} % \begin{macrocode} \def\hyxmp@banner@to@producer#1{% \ifx\scantokens\relax \gdef\@pdfproducer{#1}% \else {\scantokens{\makeatletter\hyxmp@remove@this#1\relax}}% \fi } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\@pdfproducer} % \begin{macro}{\hyxmp@remove@this} % Define |\@pdfproducer| as a given banner string with the initial % ``\texttt{This is}'' stripped off the beginning. % \begin{macrocode} \def\hyxmp@remove@this This is #1\relax{\gdef\@pdfproducer{#1}} % \end{macrocode} % \end{macro} % \end{macro} % % If \optname{pdfproducer} wasn't specified and \pkgname{hyperref} % didn't already define |\@pdfproducer|---old versions of % \pkgname{hyperref} did; newer ones don't---try to assign a meaningful % producer string and use that. % \changes{v5.0}{2020/03/02}{Define a default producer} % \begin{macrocode} \AtBeginDocument{% \ifx\@pdfproducer\relax \hyxmp@define@pdfproducer \fi } % \end{macrocode} % % \begin{macro}{\hyxmp@assign@major@minor} % Assign |\hyxmp@major@minor| to be the \acro{PDF} version targeted by % the running \TeX\ engine. % \changes{v5.2}{2020/05/10}{Added this macro. \string\pkgname{hyperxmp} % now correctly specifies \string\xmpprop{pdf:PDFVersion} when % generating \string\acro{PDF}~2.0+. Thanks to Ulrike Fischer for % alerting me to \string\acro{PDF}~2.0's availability in the % \string\TeX\ ecosystem and informing me how to activate it} % \begin{macro}{\hyxmp@major@minor} % \begin{macrocode} \newcommand*{\hyxmp@assign@major@minor}{% \@ifundefined{pdfvariable}{% \@ifundefined{pdfminorversion}{% % \end{macrocode} % Case 1: Neither |\pdfvariable| nor |\pdfminorversion| is defined % (\XeLaTeX\ and regular \LaTeX). % \begin{macrocode} }{% % \end{macrocode} % Case 2: |\pdfminorversion| is defined (\pdfLaTeX\ and pre-0.85 \LuaLaTeX). % \begin{macrocode} \xdef\hyxmp@major@minor{\the\pdfminorversion}% \@ifundefined{pdfmajorversion}{% % \end{macrocode} % Case 2(a): |\pdfmajorversion| is not defined (older versions of % \pdfLaTeX\ and \LuaLaTeX). % \begin{macrocode} \xdef\hyxmp@major@minor{1.\hyxmp@major@minor}% }{% % \end{macrocode} % Case 2(b): |\pdfmajorversion| is defined (\pdfLaTeX~1.40.21+). % \begin{macrocode} \xdef\hyxmp@major@minor{\the\pdfmajorversion.\hyxmp@major@minor}% }% }% }{% % \end{macrocode} % Case 3: |\pdfvariable| is defined (\LuaLaTeX~0.85+). % \begin{macrocode} \xdef\hyxmp@major@minor{\the\pdfvariable majorversion.\the\pdfvariable minorversion}% }% } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\hyxmp@pdf@schema} % Add properties defined by the Adobe \acro{PDF} schema to the |\hyxmp@xml| % macro. % \begin{macrocode} \newcommand*{\hyxmp@pdf@schema}{% % \end{macrocode} % Add a block of \acro{XML} to |\hyxmp@xml| that lists the document's % keywords (the \xmpprop{pdf:Keywords} property), the tools used to % produce the \acro{PDF} file (the \xmpprop{pdf:Producer} property), and % the version of the \acro{PDF} standard adhered to (the % \xmpprop{pdf:PDFVersion} property). Unlike most of the other schemata % that \pkgname{hyperxmp} supports, the Adobe \acro{PDF} schema is % \emph{always} included in the document, even if all of its keys are % empty. This is because \PDFstd{A}{1}{b}{} requires the keywords and % producer to be the same in the \acro{XMP} metadata and the \acro{PDF} % metadata. Because \pkgname{hyperref} always specifies the % \pdfterm{Keywords} and \pdfterm{Producer} fields, even when they're % empty, \pkgname{hyperxmp} has to follow suit and define % \xmpprop{pdf:Keywords} and \xmpprop{pdf:Producer} in the \acro{XMP} % packet. % \changes{v2.4}{2013/12/21}{Made % \texttt{\string\string\string\hyxmp@pdf@schema} % \protect\emph{always} include the Adobe \protect\acro{PDF} schema, % even when empty. Florian Breitwieser noted that this is necessary % for \protect\PDFstd{A}{1}{b}{} compliance} % \changes{v5.0}{2020/02/28}{Honor \protect\optname{pdftrapped}} % \begin{macrocode} \hyxmp@add@simple@var{pdf:Producer}{@pdfproducer}% \hyxmp@add@simple@var{pdf:Keywords}{@pdfkeywords}% \hyxmp@add@simple{pdf:Trapped}{\@pdftrapped}% \hyxmp@assign@major@minor \hyxmp@add@simple@var{pdf:PDFVersion}{hyxmp@major@minor}% } % \end{macrocode} % \end{macro} % % \end{schemadesc} % % % \subsubsection{The Dublin Core schema} % \label{sec:dublin-core} % % \begin{schemadesc}{Dublin Core} % % \begin{macro}{\ifhyxmp@multi@langs} % \begin{macro}{\hyxmp@multi@langstrue} % \begin{macro}{\hyxmp@multi@langsfalse} % These macros are used locally to \cs{hyxmp@rdf@dc}. If the property % being processed has values in different languages, % \cs{ifhyxmp@multi@langs} evaluates to \textsc{true}. If it has a % value in only a single language, \cs{ifhyxmp@multi@langs} evaluates to % \textsc{false}. % \begin{macrocode} \newif\ifhyxmp@multi@langs % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\hyxmp@rdf@dc} % Given an optional |\if|\meta{something} statement (|#1|), a Dublin Core % property~(|#2|) and a macro containing some |\pdfstringdef|-defined % text~(|#3|), append the appropriate block of \acro{XML} to the |\hyxmp@xml| % macro. % \changes{v1.4}{2011/06/12}{Included metadata in the \xmpterm{x-default} % language regardless of the specified metadata language} % \changes{v3.3}{2017/07/22}{Bug fix: Output the metadata language as % correct \noexpand\acro{XML} even when \noexpand\pkgname{hyperref} is % loaded with the \noexpand\optname{unicode} option} % \changes{v5.5}{2020/07/17}{List \protect\xmpterm{x-default} alternatives % before language-specific alternatives, as dictated by the % \protect\acro{XMP} specification~\protect\cite{Adobe2012:XMP}} % \changes{v5.5}{2020/07/21}{Rewrite the core part of this macro to % divide it into four, cleanly defined cases} % \begin{macrocode} \newcommand*{\hyxmp@rdf@dc}[3][\iffalse]{% % \end{macrocode} % Set |\@tempswatrue| only if the given text is nonempty or the provided % conditional evaluates to \textsc{true}. % \begin{macrocode} \@ifmtargexp{#3}{\@tempswafalse}{\@tempswatrue}% #1 \@tempswatrue \fi % \end{macrocode} % Append the corresponding \acro{XML} only if |\@tempswatrue|. % \begin{macrocode} \if@tempswa \hyxmp@xmlify{#3}% % \end{macrocode} % \begin{macro}{\hyxmp@value} % Store the \acro{XML}-ified version of |#3| in |\hyxmp@value| so we can % reuse |\hyxmp@xmlifiied| if necessary. % \begin{macrocode} \let\hyxmp@value=\hyxmp@xmlified \hyxmp@add@to@xml{% ______^^J% ________^^J% }% % \end{macrocode} % Record whether property~|#2| has definitions in multiple languages. % \begin{macrocode} \@if@def@and@nonempty{hyxmp@alt@#2}{% \hyxmp@multi@langstrue }{% \hyxmp@multi@langsfalse }% % \end{macrocode} % There are now four cases to consider: the cross product of % \{\optname{pdfmetalang}~$=$ ``\xmpterm{x-default}'', % \optname{pdfmetalang}~$\neq$ ``\xmpterm{x-default}''\} and % \{\cs{XMPLangAlt} was specified, \cs{XMPLangAlt} was not specified\}. % We handle each of these in turn. % \begin{macrocode} \ifx\@pdfmetalang\hyxmp@x@default \ifhyxmp@multi@langs % \end{macrocode} % \textbf{Case~1}: No \optname{pdfmetalang} but \cs{XMPLangAlt}. % We consider this an error because the \xmpterm{x-default} language will % not have a matching non-default language, in violation of the % \acro{XMP} specification's guidance~\cite[p.~23]{Adobe2012:XMP}: % % \begin{quote} % \sffamily % % An \textbf{xml:lang} value of ``x-default'' may be used to % explicitly denote a default item. If used, the ``x-default'' item % shall be first in the array and its simple text value should be % repeated in another item in which \textbf{xml:lang} specifies its % actual language. However, an ``x-default'' item may be the only % item, in which case there is only a default value in no defined % language. % \end{quote} % \begin{macrocode} \PackageError{hyperxmp}% {\string\XMPLangAlt\space was used without specifying pdfmetalang\MessageBreak or pdflang}% {Be sure to assign a language code to the pdfmetalang key and/or a document\MessageBreak language to the pdflang key (e.g., \string\hypersetup{pdfmetalang={en}}).}% \else % \end{macrocode} % \textbf{Case~2}: No \optname{pdfmetalang} and no \cs{XMPLangAlt}. % Here we specify only \xmpterm{x-default} as the language, as per the % guidance quoted above. % \begin{macrocode} \hyxmp@add@to@xml{% __________\hyxmp@value^^J% }% \fi \else \ifhyxmp@multi@langs % \end{macrocode} % \textbf{Case~3}: Both \optname{pdfmetalang} and \cs{XMPLangAlt}. In % this case, we include an \xmpterm{x-default} followed by the % \optname{pdfmetalang} language, followed by all of the language % alternatives. % \begin{macrocode} \hyxmp@xmlify{\@pdfmetalang}% \hyxmp@add@to@xml{% __________\hyxmp@value^^J% __________\hyxmp@value^^J% }% \def\do##1##2{ \hyxmp@xmlify{##2}% \hyxmp@add@to@xml{% __________\hyxmp@xmlified^^J% }% }% \csname hyxmp@alt@#2\endcsname \else % \end{macrocode} % \textbf{Case~4}: \optname{pdfmetalang} but no \cs{XMPLangAlt}. To % reduce redundancy we omit the \xmpterm{x-default} and include the % single language in which the text appears. % \begin{macrocode} \hyxmp@xmlify{\@pdfmetalang}% \hyxmp@add@to@xml{% __________\hyxmp@value^^J% }% \fi \fi % \end{macrocode} % Complete this \acro{XMP} element. % \begin{macrocode} \hyxmp@add@to@xml{% ________^^J% ______^^J% }% \fi }% % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\hyxmp@list@to@xml} % Given an optional |\if|\meta{something} statement (|#1|), a Dublin Core % property~(|#2|), an \acro{RDF} array~(|#3|), and a macro containing a % comma-separated list~(|#4|), append the appropriate block of \acro{XML} to % the |\hyxmp@xml| macro. % \changes{v2.0}{2012/08/02}{Modified by Heiko Oberdiek to use the new % \term{Unicode}-processing macros} % \begin{macrocode} \newcommand*{\hyxmp@list@to@xml}[4][\iffalse]{% % \end{macrocode} % Set |\@tempswatrue| only if the given list is nonempty or the provided % conditional evaluates to \textsc{true}. % \begin{macrocode} \@ifmtargexp{#4}{\@tempswafalse}{\@tempswatrue}% #1 \@tempswatrue \fi % \end{macrocode} % Append the corresponding \acro{XML} only if |\@tempswatrue|. % \begin{macrocode} \if@tempswa \hyxmp@add@to@xml{% ______^^J% ________^^J% }% \bgroup % \end{macrocode} % \begin{macro}{\@elt} % Re-encode the text from \term{Unicode} if necessary. Then redefine % |\@elt| to \acro{XML}-ify each element of the list and append it to % |\hyxmp@xmlified|. % \begin{macrocode} \hyxmp@xmlify{#4}% \hyxmp@commas@to@list\hyxmp@list{\hyxmp@xmlified}% \def\@elt##1{% \hyxmp@add@to@xml{% __________##1^^J% }% }% \hyxmp@list \egroup \hyxmp@add@to@xml{% ________^^J% ______^^J% }% \fi } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\hyxmp@singleton@dc} % Given an optional list type (|Seq| or |Bag|), a Dublin Core property, % and a string, append a block of \acro{XML} representing a one-element % list consisting of the given string. % \changes{v4.1}{2019/04/05}{Added this macro} % \begin{macrocode} \newcommand{\hyxmp@singleton@dc}[3][Bag]{% \@ifnotmtargexp{#3}{% \hyxmp@xmlify{#3}% \hyxmp@add@to@xml{% ______^^J% ________^^J% __________\hyxmp@xmlified^^J% ________^^J% ______^^J% }% } } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@cond@dc@identifier} % Conditionally add a \xmpprop{dc:identifier} tag. Given a prefix % string~(|#1|) and a main string~(|#2|), wrap these in a % \xmpprop{dc:identifier} if the main string is nonempty and % |\hyxmp@xmlified| \emph{is} empty (implying the % \xmpprop{dc:identifier} has not yet been written). % \changes{v5.2}{2020/04/29}{Added this macro} % \begin{macrocode} \newcommand*{\hyxmp@cond@dc@identifier}[2]{% \ifx\hyxmp@xmlified\@empty \@ifnotmtargexp{#2}{% \hyxmp@add@simple@pfx{dc:identifier}{#1}{#2}% }% \fi } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@dc@schema} % Add properties defined by the Dublin Core schema to the |\hyxmp@xml| % macro. Specifically, we add entries for the \xmpprop{dc:title} % property if the author specified a \optname{pdftitle}, the % \xmpprop{dc:description} property if the author specified a % \optname{pdfsubject}, the \xmpprop{dc:rights} property if the author % specified a \optname{pdfcopyright}, the \xmpprop{dc:creator} property % if the author specified a \optname{pdfauthor}, the % \xmpprop{dc:subject} property if the author specified % \optname{pdfkeywords}, the \xmpprop{dc:language} property if the % author specified \optname{pdflang}, the \xmpprop{dc:type} property if % the author specified \optname{pdftype}, and the % \xmpprop{dc:identifier} if the author specified % \optname{pdfidentifier} or if we can derive it from other options. We % also specify the \xmpprop{dc:source} property using the base name of % the source file with |.tex| appended and the \xmpprop{dc:date} % property using the date the document was run through \LaTeX---unless % the author specified \optname{pdfdate}, in which case we use that. % \changes{v2.0}{2012/08/26}{Added support for \xmpprop{dc:language} % and \xmpprop{dc:source}} % \changes{v2.4}{2013/12/21}{Made \xmpprop{dc:language} a \xmpterm{Bag} % instead of an individual item so as to conform to the latest % \acro{XMP} specifications, a detail identified by Florian Breitwieser} % \changes{v5.3}{2020/06/13}{Include all languages used in the document % in \protect\xmpprop{dc:language}} % \changes{v5.4}{2020/06/18}{Bug fix: Use \protect\cs{hyxmp@today@xmp} % as the date only if \protect\cs{@pdfdatetime} is undefined} % \begin{macrocode} \newcommand*{\hyxmp@dc@schema}{% \hyxmp@add@simple{dc:format}{application/pdf}% \hyxmp@rdf@dc[\ifHy@pdfa]{title}{\@pdftitle}% \hyxmp@rdf@dc[\ifHy@pdfa]{description}{\@pdfsubject}% \hyxmp@rdf@dc{rights}{\@pdfcopyright}% \hyxmp@singleton@dc{publisher}{\@pdfpublisher}% \@ifmtargexp{\@pdfdatetime}{% \hyxmp@singleton@dc[Seq]{date}{\hyxmp@today@xmp}% }{% \hyxmp@singleton@dc[Seq]{date}{\@pdfdatetime}% }% \hyxmp@singleton@dc{type}{\@pdftype}% \hyxmp@list@to@xml[\ifHy@pdfa]{creator}{Seq}{\hyxmp@pdfauthor}% \hyxmp@list@to@xml{subject}{Bag}{\hyxmp@pdfkeywords}% \ifx\@pdfsource\@empty \else \hyxmp@add@simple{dc:source}{\@pdfsource}% \fi \hyxmp@list@to@xml{language}{Bag}{\hyxmp@dc@lang}% % If |\@pdfidentifier| is empty, try setting it to each of |\@pdfdoi|, % |\@pdfeissn|, |\@pdfissn|, and |\@pdfisbn|, in turn, with proper % syntactic adjustments. % \begin{macrocode} \@ifmtargexp{\@pdfidentifier}{% \let\hyxmp@xmlified=\@empty \hyxmp@cond@dc@identifier{info:doi/}{\@pdfdoi}% \hyxmp@cond@dc@identifier{urn:ISSN:}{\@pdfeissn}% \hyxmp@cond@dc@identifier{urn:ISSN:}{\@pdfissn}% \hyxmp@cond@dc@identifier{urn:ISBN:}{\@pdfisbn}% }{% \hyxmp@add@simple{dc:identifier}{\@pdfidentifier}% }% } % \end{macrocode} % \end{macro} % % \end{schemadesc} % % % \subsubsection{The XMP Rights Management schema} % \label{sec:xmp-rights} % % \begin{schemadesc}[XMP Rights Management]{\protect\acro{XMP} Rights Management} % % \begin{macro}{\hyxmp@xmpRights@schema} % Add properties defined by the \acro{XMP} Rights Management schema to the % |\hyxmp@xml| macro. Currently, these are only the % \xmpprop{xmpRights:Marked} property and the % \xmpprop{xmpRights:WebStatement} property. If the author specified a % copyright statement we mark the document as copyrighted. If the % author specified a license statement we include the \acro{URL} in the % metadata. % \changes{v1.4}{2011/05/29}{Renamed the \texttt{xapRights} namespace % prefix to \texttt{xmpRights}} % \changes{v2.0}{2012/08/25}{Modified to include % \xmpprop{xmpRights:Marked} only when \optname{pdfcopyright} is % specified and \xmpprop{xmpRights:WebStatement} only when % \optname{pdflicenseurl} is specified} % \begin{macrocode} \newcommand*{\hyxmp@xmpRights@schema}{% % \end{macrocode} % \begin{macro}{\hyxmp@legal} % Set |\hyxmp@rights| to |YES| if either \optname{pdfcopyright} or % \optname{pdflicenseurl} was specified. % \begin{macrocode} \let\hyxmp@rights=\@empty \ifx\@pdflicenseurl\@empty \else \def\hyxmp@rights{YES}% \fi \ifx\@pdfcopyright\@empty \else \def\hyxmp@rights{YES}% \fi % \end{macrocode} % Include the license-statement \acro{URL} and/or the copyright % indication. The copyright statement itself is included by % |\hyxmp@dc@schema| in Section~\ref{sec:dublin-core}. % \begin{macrocode} \ifx\hyxmp@rights\@empty \else \ifx\@pdfcopyright\@empty \else \hyxmp@add@simple{xmpRights:Marked}{True}% \fi \hyxmp@add@simple{xmpRights:WebStatement}{\@pdflicenseurl}% \fi } % \end{macrocode} % \end{macro} % \end{macro} % % \end{schemadesc} % % % \subsubsection{The XMP Media Management schema} % \label{sec:xmp-media} % % \begin{schemadesc}[XMP Media Management]{\protect\acro{XMP} Media Management} % % \begin{macro}{\hyxmp@aep@toks} % Once we reach the end of the preamble and know that \cs{@pdftitle} and % \cs{@pdfauthor} are no longer expected to change we use those macros % (and others) to define one \acro{UUID} for the document % (\cs{hyxmp@DocumentID}) and one for the document instance % (\cs{hyxmp@InstanceID}). As explained in % Section~\ref{sec:initial-prep}, we defer the invocation of % \cs{AtEndPreamble} to the end of the file. % \changes{v5.7}{2020/10/13}{As requested by Moritz Heckscher, define % \protect\cs{hyxmp@DocumentID} and \protect\cs{hyxmp@InstanceID} at % the end of the preamble instead of at the end of the document} % \begin{macrocode} \expandafter\hyxmp@aep@toks\expandafter=\expandafter{% \the\hyxmp@aep@toks \AtEndPreamble{% \@ifmtargexp{\hyxmp@DocumentID}{\hyxmp@def@DocumentID}{}% \@ifmtargexp{\hyxmp@InstanceID}{\hyxmp@def@InstanceID}{}% }% } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@mm@schema} % Add properties defined by the \acro{XMP} Media Management schema to % the |\hyxmp@xml| macro. According to the \acro{XMP} specification, % the \xmpprop{xmpMM:DocumentID} property is supposed to uniquely % identify a document, and the \xmpprop{xmpMM:InstanceID} property is % supposed to change with each save operation~\cite{Adobe2012:XMP}. As % seen in Section~\ref{sec:uuid-gen}, we do what we can to honor this % intention from within a \tex-based workflow. We additionally support % the \xmpprop{xmpMM:VersionID} property, whose value is supplied by % the author using \optname{pdfversionid}. % \changes{v1.4}{2011/05/29}{Renamed the \texttt{xapMM} namespace % prefix to \texttt{xmpMM}} % \changes{v3.5}{2018/11/27}{Generate \protect\cs{hyxmp@DocumentID} and % \protect\cs{hyxmp@InstanceID} only if the document does not already % define these using the \protect\optname{pdfdocumentid} and % \protect\optname{pdfinstanceid} options} % \changes{v4.0}{2019/03/09}{Include \protect\xmpprop{xmpMM:VersionID} in % the \protect\acro{XMP} packet} % \begin{macrocode} \gdef\hyxmp@mm@schema{% \hyxmp@add@simple{xmpMM:DocumentID}{\hyxmp@DocumentID}% \hyxmp@add@simple{xmpMM:InstanceID}{\hyxmp@InstanceID}% \hyxmp@add@simple{xmpMM:VersionID}{\@pdfversionid}% \hyxmp@add@simple{xmpMM:RenditionClass}{\@pdfrendition}% } % \end{macrocode} % \end{macro} % % \end{schemadesc} % % % \subsubsection{The XMP Basic schema} % \label{sec:xmp-basic} % % \begin{schemadesc}[XMP Basic]{\protect\acro{XMP} Basic} % \begin{macro}{\hyxmp@xmp@basic@schema} % Add properties defined by the \acro{XMP} Basic schema to the % |\hyxmp@xml| macro. These include a bunch of dates (all set to the % same value) and the base \acro{URL} for the document if specified with % \optname{baseurl}. % \changes{v2.0}{2012/08/26}{Added this macro} % \changes{v3.0}{2016/07/04}{Made the \protect\acro{XMP} % \protect\xmpprop{xmp:CreateDate}, \protect\xmpprop{xmp:ModifyDate}, % and \protect\xmpprop{xmp:MetadataDate} match the \protect\acro{PDF} % \protect\pdfterm{CreationDate}} % \changes{v3.2}{2017/01/22}{Honor \string\pkgname{hyperref}'s % \string\optname{pdfcreationdate} and \string\optname{pdfmoddate} % options plus a new \string\optname{pdfmetadate} option. Leonid % Sinev requested this additional control and helped test the resulting % \protect\pkgname{hyperxmp} code} % \begin{macrocode} \newcommand*{\hyxmp@xmp@basic@schema}{% % \end{macrocode} % For the document's creation date, use the user-specified % |\@pdfcreationdate| if defined and non-empty. Otherwise use our % fabricated |\hyxmp@today@xmp|. % \begin{macrocode} \@ifmtargexp{\@pdfcreationdate}{% \hyxmp@add@simple{xmp:CreateDate}{\hyxmp@today@xmp}% }{% \hyxmp@add@simple{xmp:CreateDate}{% \expandafter\hyxmp@as@xmp@date\expandafter{\@pdfcreationdate}}% }% % \end{macrocode} % For the document's modification date, use the user-specified % |\@pdfmoddate| if defined and non-empty. Otherwise use our % fabricated |\hyxmp@today@xmp|. % \begin{macrocode} \@ifmtargexp{\@pdfmoddate}{% \hyxmp@add@simple{xmp:ModifyDate}{\hyxmp@today@xmp}% }{% \hyxmp@add@simple{xmp:ModifyDate}{% \expandafter\hyxmp@as@xmp@date\expandafter{\@pdfmoddate}}% }% % \end{macrocode} % For the document's metadata date, use the user-specified % |\@pdfmetadatetime| if defined and non-empty. Otherwise use our % fabricated |\hyxmp@today@xmp|. % \begin{macrocode} \@ifmtargexp{\@pdfmetadatetime}{% \hyxmp@add@simple{xmp:MetadataDate}{\hyxmp@today@xmp}% }{% \hyxmp@add@simple{xmp:MetadataDate}{\@pdfmetadatetime}% }% % \end{macrocode} % Define the creation tool and the base \acro{URL}. % \begin{macrocode} \hyxmp@add@simple{xmp:CreatorTool}{\@pdfcreator}% \hyxmp@add@simple{xmp:BaseURL}{\@baseurl}% } % \end{macrocode} % \end{macro} % % \end{schemadesc} % % % \subsubsection{The Photoshop schema} % \label{sec:photoshop} % % \begin{schemadesc}{Photoshop} % % \begin{macro}{\hyxmp@photoshop@schema} % \changes{v2.0}{2012/08/26}{Simplified using % \texttt{\string\string\string\hyxmp@add@simple}} % \begin{macro}{\hyxmp@photoshop@data} % Add properties defined by the Photoshop schema to the |\hyxmp@xml| % macro. We currently support only the % \xmpprop{photoshop:AuthorsPosition} and % \xmpprop{photoshop:CaptionWriter} properties. % \begin{macrocode} \gdef\hyxmp@photoshop@schema{% \edef\hyxmp@photoshop@data{\@pdfauthortitle\@pdfcaptionwriter}% \hyxmp@add@simple{photoshop:AuthorsPosition}{\@pdfauthortitle}% \hyxmp@add@simple{photoshop:CaptionWriter}{\@pdfcaptionwriter}% } % \end{macrocode} % \end{macro} % \end{macro} % % \end{schemadesc} % % % \subsubsection{PDF/* Identification schemata} % \label{sec:pdfX-id} % % \begin{schemadesc}[PDF/A Identification]{\protect\acro{PDF/A} Identification} % \begin{schemadesc}[PDF/X Identification]{\protect\acro{PDF/X} Identification} % \begin{schemadesc}[PDF/UA Identification]{\protect\acro{PDF/UA} Identification} % % \begin{macro}{\hyxmp@pdfa@id@schema} % Add properties defined by the \acro{PDF/A} Identification % schema~\cite{PDFA2008:xmp-props} to the |\hyxmp@xml| macro. These % properties identify a document as conforming to a particular % \acro{PDF/A} standard. We default to \PDFstd{A}{1}{b}{} if any % \acro{PDF/A} compliance is detected but let the author override the % ``1'' with \optname{pdfapart} and the ``b'' with % \optname{pdfaconformance}. % \changes{v2.4}{2013/12/21}{Added this macro} % \changes{v2.9}{2016/04/12}{Let the author specify the \protect\acro{PDF/A} % part and conformance IDs, as requested by Leonid Sinev} % \begin{macrocode} \newcommand*{\hyxmp@pdfa@id@schema}{% \ifHy@pdfa \hyxmp@add@simple{pdfaid:part}{\@pdfapart}% \hyxmp@add@simple{pdfaid:conformance}{\@pdfaconformance}% \fi } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@pdfua@id@schema} % If the document conforms to a \acro{PDF/UA} standard, the author can % indicate the standard version with \optname{pdfuapart}. % \changes{v5.0}{2020/02/16}{Added this macro} % \begin{macrocode} \newcommand*{\hyxmp@pdfua@id@schema}{% \hyxmp@add@simple{pdfuaid:part}{\@pdfuapart}% } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@pdfx@id@schema} % \label{page:pdfx-id-schema} % If the document conforms to a \acro{PDF/X} standard, the author can % indicate the standard version with \optname{pdfxstandard}. We % separately handle \PDFstd{X}{1}{}{}, \PDFstd{X}{2}{}{} and % \PDFstd{X}{3}{}{}, and \PDFstd{X}{4}{}{} onwards. % \changes{v5.0}{2020/02/26}{Added this macro} % \begin{macrocode} \newcommand*{\hyxmp@pdfx@id@schema}{% \@hyxmp@count=0\hyxmp@pdfx@major\relax \ifnum\@hyxmp@count=0 \else \ifnum\@hyxmp@count=1 \hyxmp@add@simple{pdfx:GTS_PDFXVersion}{PDF/X-1:2001}% \hyxmp@add@simple{pdfx:GTS_PDFXConformance}{\@pdfxstandard}% \else \ifnum\@hyxmp@count<4 \hyxmp@add@simple{pdfx:GTS_PDFXVersion}{\@pdfxstandard}% \else \hyxmp@add@simple{pdfxid:GTS_PDFXVersion}{\@pdfxstandard}% \fi \fi \fi } % \end{macrocode} % \end{macro} % % \end{schemadesc} % \end{schemadesc} % \end{schemadesc} % % % \subsubsection{The IPTC Photo Metadata schema} % \label{sec:photo-meta} % % \begin{schemadesc}[IPTC Photo Metadata]{\protect\acro{IPTC} Photo Metadata} % % \begin{macro}{\xmplinesep} % Lines in multiline fields are separated by |\xmplinesep| in the % generated \acro{XML}. This defaults to an \acro{LF} (|^^J|) character % but written as an \acro{XML} character entity for consistency across % operating systems. % \changes{v2.2}{2012/12/07}{Added this macro} % \begin{macrocode} \begingroup \catcode`\&=12 \catcode`\#=12 \gdef\xmplinesep{ } \endgroup % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@list@to@lines} % Given a property~(|#1|) and a macro containing a comma-separated % list~(|#2|), replace commas with |\xmplinesep|. Do nothing if the % list is empty. % \changes{v2.2}{2012/12/07}{Added this macro} % \begin{macrocode} \newcommand*{\hyxmp@list@to@lines}[2]{% \@ifnotmtargexp{#2}{% \bgroup \hyxmp@add@to@xml{% \hyxmp@extra@indent______<#1>% }% % \end{macrocode} % \begin{macro}{\@elt@first} % The first element of the list is output as is. % \begin{macrocode} \def\@elt@first##1{% \hyxmp@add@to@xml{##1}% \let\@elt=\@elt@rest }% % \end{macrocode} % \begin{macro}{\@elt@rest} % The remaining elements of the list are output with a preceding line % separator (|\xmplinesep|). % \begin{macrocode} \def\@elt@rest##1{% \hyxmp@add@to@xml{\xmplinesep##1}% }% % \end{macrocode} % \begin{macro}{\@elt} % Re-encode the text from \term{Unicode} if necessary. Then redefine % |\@elt| to insert a line separator between terms. % \begin{macrocode} \let\@elt=\@elt@first \hyxmp@xmlify{#2}% \hyxmp@commas@to@list\hyxmp@list{\hyxmp@xmlified}% \hyxmp@list \hyxmp@add@to@xml{^^J}% \egroup }% } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\hyxmp@iptc@schema} % Add properties defined by the \acro{IPTC} Photo Metadata % schema~\cite{IPTC2010:photo-meta} to the |\hyxmp@xml| macro. We % currently support only the \xmpprop{Iptc4xmpCore:CreatorContactInfo} % property, although this is a structure containing multiple fields. % \changes{v2.2}{2012/12/07}{Added this macro} % \changes{v2.9}{2016/04/23}{Use \textsf{Iptc4xmpCore} instead of % \textsf{Iptc4ContInfo} as the contact-information metadata prefix. % Leonid Sinev reports that Acrobat's \acro{PDF/A} validator seems to % prefer \textsf{Iptc4xmpCore}} % \changes{v4.0}{2019/03/09}{Moved the definition of % \protect\cs{hyxmp@iptc@data} from here into % \protect\cs{hyxmp@check@iptc@data}} % \changes{v4.0}{2019/03/16}{Renamed this macro to % \protect\cs{hyxmp@iptc@schema} from % \protect\cs{hyxmp@photometa@schema}} % \changes{v4.0}{2019/03/16}{Rewrote this macro entirely to correct % the use of fields within a structure} % \begin{macrocode} \gdef\hyxmp@iptc@schema{% % \end{macrocode} % Because we currently support only % \xmpprop{Iptc4xmpCore:CreatorContactInfo} it suffices to check if we % have any relevant data. If so, we instantiate a % \xmpprop{Iptc4xmpCore:ContactInfo} structure with all available % fields. % \begin{macrocode} \ifx\hyxmp@iptc@data\@empty \else \hyxmp@add@to@xml{% ______^^J% }% % \end{macrocode} % We locally redefine |\hyxmp@extra@indent| to increase the indentation % of the assignments to \xmpprop{Iptc4xmpCore:CreatorContactInfo}'s % fields. % \begin{macrocode} \bgroup \edef\hyxmp@extra@indent{\hyxmp@extra@indent\space\space}% \hyxmp@list@to@lines{Iptc4xmpCore:CiAdrExtadr}{\@pdfcontactaddress}% \hyxmp@add@simple{Iptc4xmpCore:CiAdrCity}{\@pdfcontactcity}% \hyxmp@add@simple{Iptc4xmpCore:CiAdrRegion}{\@pdfcontactregion}% \hyxmp@add@simple{Iptc4xmpCore:CiAdrPcode}{\@pdfcontactpostcode}% \hyxmp@add@simple{Iptc4xmpCore:CiAdrCtry}{\@pdfcontactcountry}% % \end{macrocode} % \begin{macro}{\xmplinesep} % The \acro{IPTC} standard states that sets of telephone numbers, email % addresses, and \acro{URL}s for the contact person or institution, % ``[m]ay have to be separated by a comma in the user % interface''~\cite{IPTC2010:photo-meta}. This is rather ambiguous: % Does the comma appear \emph{only} in the user interface or also in the % generated \acro{XML}\@? Here we assume the latter interpretation and % temporarily redefine |\xmplinesep| as a comma and use % |\hyxmp@list@to@lines| to insert the data. Unlike % |\hyxmp@add@simple|, this approach trims all spaces surrounding commas. % \begin{macrocode} \def\xmplinesep{,}% \hyxmp@list@to@lines{Iptc4xmpCore:CiTelWork}{\@pdfcontactphone}% \hyxmp@list@to@lines{Iptc4xmpCore:CiEmailWork}{\@pdfcontactemail}% \hyxmp@list@to@lines{Iptc4xmpCore:CiUrlWork}{\@pdfcontacturl}% \egroup \hyxmp@add@to@xml{% ______^^J% }% \fi } % \end{macrocode} % \end{macro} % \end{macro} % % \end{schemadesc} % % % \subsubsection{The PRISM Basic Metadata schema} % \label{sec:prism-meta} % % \begin{schemadesc}[PRISM Basic Metadata]{\protect\acro{PRISM} Basic Metadata} % % \begin{macro}{\hyxmp@prism@schema} % \changes{v4.0}{2019/03/10}{Added this macro} % Add properties defined by the \acro{PRISM} Basic Metadata % schema~\cite{PRISM2012:basic-meta}. % \begin{macrocode} \newcommand*{\hyxmp@prism@schema}{% \ifx\hyxmp@prism@data\@empty \else \hyxmp@add@simple{prism:complianceProfile}{three}% \fi \hyxmp@add@simple@lang{prism:subtitle}{\@pdfsubtitle}% \hyxmp@add@simple@lang{prism:publicationName}{\@pdfpublication}% \hyxmp@add@simple{prism:aggregationType}{\@pdfpubtype}% \hyxmp@add@simple@lang{prism:bookEdition}{\@pdfbookedition}% \hyxmp@add@simple{prism:volume}{\@pdfvolumenum}% \hyxmp@add@simple{prism:number}{\@pdfissuenum}% \hyxmp@add@simple{prism:pageRange}{\@pdfpagerange}% \hyxmp@add@simple{prism:isbn}{\@pdfisbn}% \hyxmp@add@simple{prism:issn}{\@pdfissn}% \hyxmp@add@simple{prism:eIssn}{\@pdfeissn}% \hyxmp@add@simple{prism:doi}{\@pdfdoi}% \hyxmp@add@simple{prism:url}{\@pdfurl}% \hyxmp@add@simple{prism:byteCount}{\@pdfbytes}% \hyxmp@add@simple{prism:pageCount}{\@pdfnumpages}% } % \end{macrocode} % \end{macro} % % \end{schemadesc} % % % \subsubsection{The Journal Article Versions (JAV) schema} % \label{sec:niso-jav-meta} % % \begin{schemadesc}{Journal Article Versions} % % \begin{macro}{\hyxmp@jav@schema} % \changes{v5.5}{2020/07/23}{Added this macro} % Add properties defined by the \acro{NISO}/\acro{ALPSP} Journal Article % Versions schema~\cite{NISO2008:jav}. % \begin{macrocode} \newcommand*{\hyxmp@jav@schema}{% \hyxmp@add@simple{jav:journal_article_version}{\@pdfpubstatus}% } % \end{macrocode} % \end{macro} % % \end{schemadesc} % % \subsubsection{The XMP Paged-Text schema} % \label{sec:xmp-paged-text} % % \begin{schemadesc}[XMP Paged-Text]{\protect\acro{XMP} Paged-Text} % % \begin{macro}{\hyxmp@xmptpg@schema} % The \acro{XMP} Paged-Text schema~\cite{Adobe2012:XMP} includes % properties related to the construction of the \acro{PDF} file itself. % We acquire most of this information through \LuaTeX\ mechanisms and % therefore include much less information when run from other \TeX\ engines. % \changes{v5.5}{2020/07/25}{Added this macro} % \begin{macrocode} \newcommand*{\hyxmp@xmptpg@schema}{% \ifLuaTeX \luadirect{write_xmp_font_list(\the\hyxmp@cct)}% \fi \hyxmp@add@simple{xmpTPg:NPages}{\@pdfnumpages}% } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@cct} % We store the current category-code table to ensure that % |write_xmp_font_list|'s output uses our redefined category codes. % \begin{macrocode} \ifLuaTeX \newcatcodetable\hyxmp@cct \savecatcodetable\hyxmp@cct \fi % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@prot@us} % Define an underscore character that's protected from being converted % into a space when passed to \cs{hyxmp@add@to@xml}. \cs{hyxmp@prot@us} % is used within |write_xmp_font_list| (below) in particular to typeset % filenames that may contain underscores. % \begin{macrocode} \bgroup \catcode`\_=11 \gdef\hyxmp@prot@us{_}% \egroup % \end{macrocode} % \end{macro} % % Here we define a Lua\index{Lua} function, |write_xmp_font_list|, that % writes font information to the \acro{XMP} packet. % \changes{v5.6}{2020/10/02}{Make \protect\texttt{write\_xmp\_font\_list} % robust to fonts loaded using % \protect\href{https://en.wikipedia.org/wiki/HarfBuzz}{HarfBuzz}. % Thanks to John Lienhard for the bug report} % \changes{v5.6}{2020/10/02}{Don't inadvertently replace underscores in % filenames when writing font-related metadata} % \begin{macrocode} \ifLuaTeX \begin{luacode*} function write_xmp_font_list (cct) local function show_field(name, ...) for i = 1, select("#", ...) do local val = select(i, ...) if val then local xml = string.gsub(val, "&", "&") xml = string.gsub(xml, "<", "<") xml = string.gsub(xml, ">", ">") xml = string.gsub(xml, "_", "\\hyxmp@prot@us ") tex.print(cct, "____________" .. xml .. "^^J%") return end end end tex.print(cct, "\\hyxmp@add@to@xml{%") tex.print(cct, "______^^J%") tex.print(cct, "________^^J%") for i, f in font.each() do tex.print(cct, "__________^^J%") if f.filename then local fname = string.gsub(f.filename, "^harfloaded:(.*)", "%1") local info = fontloader.info(fname) if info then show_field("fontFace", info.fullname) show_field("fontFamily", info.familyname) show_field("fontName", info.fontname) show_field("versionString", info.version) end local baseName = string.gsub(f.filename, ".*[/\\](.*)", "%1") show_field("fontFileName", baseName) else show_field("fontName", f.psname, f.fullname, f.name) end if f.format and f.format ~= "unknown" then show_field("fontType", f.format) end tex.print(cct, "__________^^J%") end tex.print(cct, "________^^J%") tex.print(cct, "______^^J%") tex.print(cct, "}") end \end{luacode*} \fi % \end{macrocode} % % \end{schemadesc} % % % \subsubsection{XMP extension schemata} % \label{sec:extension-schemata} % % Not all of the schemata supported by \pkgname{hyperxmp} are predefined % by \acro{XMP}. \acro{PDF/A} conversion would normally fail for % documents that employ ``custom'' schemata. However, this problem can % be circumvented by declaring non-standard schemata in the \acro{XMP} % packet itself, following a technique described in a PDF Association % technical note~\cite{PDFA2008:ext-schemas}. In this section, we % declare only those schemata we actually use. % % \begin{macro}{\hyxmp@check@iptc@data} % \begin{macro}{\hyxmp@iptc@data} % Define |\hyxmp@iptc@data| as the concatenation of all \acro{IPTC} % photo metadata supplied by the document. % \begin{macrocode} \newcommand*{\hyxmp@check@iptc@data}{% \edef\hyxmp@iptc@data{% \@pdfcontactaddress \@pdfcontactcity \@pdfcontactregion \@pdfcontactpostcode \@pdfcontactcountry \@pdfcontactphone \@pdfcontactemail \@pdfcontacturl }% }% % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\hyxmp@check@prism@data} % \begin{macro}{\hyxmp@prism@data} % Define |\hyxmp@prism@data| as the concatenation of all \acro{PRISM} % metadata supplied by the document. % \begin{macrocode} \newcommand*{\hyxmp@check@prism@data}{% \edef\hyxmp@prism@data{% \@pdfbookedition \@pdfbytes \@pdfdoi \@pdfeissn \@pdfisbn \@pdfissn \@pdfissuenum \@pdfnumpages \@pdfpagerange \@pdfpublication \@pdfpubtype \@pdfsubtitle \@pdfurl \@pdfvolumenum }% }% % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\hyxmp@check@jav@data} % \begin{macro}{\hyxmp@jav@data} % Define |\hyxmp@jav@data| as the concatenation of all \acro{JAV} % metadata supplied by the document. % \begin{macrocode} \newcommand*{\hyxmp@check@jav@data}{% \edef\hyxmp@jav@data{% \@pdfpubstatus }% } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\hyxmp@begin@extension@decls} % Begin a block of \acro{XML} tags that indicates we're declaring one or % more extension schemata. % \begin{macrocode} \newcommand*{\hyxmp@begin@extension@decls}{% \hyxmp@add@to@xml{% ______^^J% ________^^J% }% } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@end@extension@decls} % End the block of \acro{XML} tags begun by |\hyxmp@begin@extension@decls|. % \begin{macrocode} \newcommand*{\hyxmp@end@extension@decls}{% \hyxmp@add@to@xml{% ________^^J% ______^^J% }% } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@begin@ext@decl} % Begin the declaration of a single extension schema. % |\hyxmp@begin@ext@decl| accepts the schema's name, prefix, and % namespace URI. % \changes{v4.0}{2019/03/15}{Added this macro} % \begin{macrocode} \newcommand*{\hyxmp@begin@ext@decl}[3]{% \hyxmp@add@to@xml{% __________^^J% ____________#1^^J% ____________#2^^J% ____________#3^^J% ____________^^J% ______________^^J% }% }% % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@end@ext@decl} % End the declaration of a single extension schema. % \changes{v4.0}{2019/03/15}{Added this macro} % \begin{macrocode} \newcommand*{\hyxmp@end@ext@decl}{% \hyxmp@add@to@xml{% ______________^^J% ____________^^J% __________^^J% }% }% % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@declare@property} % Declare a single extension-schema property. |\hyxmp@declare@property| % takes as input an optional type (defaults to \xmpterm{Text}) and a % mandatory name, category, and description. % \changes{v4.0}{2019/03/15}{Added this macro} % \changes{v5.0}{2020/02/21}{Insert the property name (\string\texttt{\#2}) % verbatim} % \begin{macrocode} \newcommand{\hyxmp@declare@property}[4][Text]{% \hyxmp@add@to@xml{% ________________^^J% __________________}% \xdef\hyxmp@xml{\hyxmp@xml#2}% \hyxmp@add@to@xml{^^J% __________________#1^^J% __________________#3^^J% __________________#4^^J% ________________^^J% }% }% % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@declare@field} % Declare a single field in a custom datatype required by an extension % schema. |\hyxmp@declare@field| takes as input an optional type % (defaults to \xmpterm{Text}) and a mandatory name and description. % \changes{v4.0}{2019/03/16}{Replaced % \protect\cs{hyxmp@declare@resource} with this macro} % \begin{macrocode} \newcommand{\hyxmp@declare@field}[3][Text]{% \hyxmp@add@to@xml{% ______________________^^J% ________________________#2^^J% ________________________#1^^J% ________________________#3^^J% ______________________^^J% }% } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@pdf@extensions} % Declare the Adobe \acro{PDF} schema. % \changes{v5.0}{2020/02/27}{Added this macro} % \begin{macrocode} \newcommand*{\hyxmp@pdf@extensions}{% \hyxmp@begin@ext@decl {Adobe PDF Schema}% {pdf}% {http://ns.adobe.com/pdf/1.3/}% \hyxmp@declare@property {Trapped}% {internal}% {Indication if the document has been modified to include trapping information}% \hyxmp@end@ext@decl }% % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@mm@extensions} % Declare the \acro{XMP} Media Management schema. % \changes{v4.0}{2019/03/15}{Added this macro} % \changes{v5.5}{2020/07/23}{Corrected the type of % \protect\xmpprop{xmpMM:RenditionClass}. Thanks to Thorsten Wi{\ss}mann % for the bug report and patch} % \begin{macrocode} \newcommand*{\hyxmp@mm@extensions}{% \hyxmp@begin@ext@decl {XMP Media Management Schema}% {xmpMM}% {http://ns.adobe.com/xap/1.0/mm/}% \hyxmp@declare@property [URI] {DocumentID}% {internal}% {UUID based identifier for all versions and renditions of a document}% \hyxmp@declare@property [URI] {InstanceID}% {internal}% {UUID based identifier for specific incarnation of a document}% \hyxmp@declare@property {VersionID}% {internal}% {Document version identifier}% \hyxmp@declare@property [RenditionClass]% {RenditionClass}% {internal}% {The manner in which a document is rendered}% \hyxmp@end@ext@decl }% % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@pdfa@id@extensions} % Declare the \acro{PDF/A} Identification schema~\cite{PDFA2008:xmp-props}. % \changes{v4.0}{2019/03/15}{Added this macro} % \begin{macrocode} \newcommand*{\hyxmp@pdfa@id@extensions}{% \hyxmp@begin@ext@decl {PDF/A Identification Schema}% {pdfaid}% {http://www.aiim.org/pdfa/ns/id/}% \hyxmp@declare@property [Integer]% {part}% {internal}% {Part of PDF/A standard}% \hyxmp@declare@property {conformance}% {internal}% {Conformance level of PDF/A standard}% \hyxmp@end@ext@decl }% % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@pdfua@id@extensions} % Declare the \acro{PDF/UA} Universal Accessibility schema. % \changes{v5.0}{2020/02/15}{Added this macro} % \begin{macrocode} \newcommand*{\hyxmp@pdfua@id@extensions}{% \hyxmp@begin@ext@decl {PDF/UA Universal Accessibility Schema}% {pdfuaid}% {http://www.aiim.org/pdfua/ns/id/}% \hyxmp@declare@property [Integer]% {part}% {internal}% {Part of ISO 14289 standard}% \hyxmp@end@ext@decl }% % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@pdfx@id@extensions} % Declare the schema used pre-\PDFstd{X}{4}{}{}. Because Adobe Acrobat DC % (at least) defines this even for \PDFstd{X}{4}{}{} and later, we follow % suit. % \changes{v5.0}{2020/02/26}{Added this macro} % \begin{macrocode} \newcommand*{\hyxmp@pdfx@id@extensions}{% \ifx\hyxmp@pdfx@major\empty \else \hyxmp@begin@ext@decl {Adobe Document Info PDF/X eXtension Schema}% {pdfx}% {http://ns.adobe.com/pdfx/1.3/}% \hyxmp@declare@property {GTS_PDFXVersion}% {internal}% {ID of PDF/X standard}% \hyxmp@declare@property {GTS_PDFXConformance}% {internal}% {Conformance level of PDF/X standard}% \hyxmp@end@ext@decl \fi % \end{macrocode} % Declare the schema used in \PDFstd{X}{4}{}{} and later versions. % \begin{macrocode} \@hyxmp@count=0\hyxmp@pdfx@major\relax \ifnum\@hyxmp@count>3 \hyxmp@begin@ext@decl {PDF/X ID Schema}% {pdfxid}% {http://www.npes.org/pdfx/ns/id/}% \hyxmp@declare@property {GTS_PDFXVersion}% {internal}% {ID of PDF/X standard}% \hyxmp@end@ext@decl \fi }% % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@iptc@extensions} % \changes{v2.2}{2012/12/13}{Added this macro to support % \acro{PDF/A} generation} % \changes{v2.3}{2013/01/08}{Gave the % \xmpprop{Iptc4xmpCore:CreatorContactInfo} fields a unique % \xmpprop{pdfaType:prefix} to better support conversion of the % document to \acro{PDF/A}} % \changes{v4.0}{2019/03/09}{Moved the header code from here into % \protect\cs{hyxmp@begin@extension@decls} and the trailer code % from here into \protect\cs{hyxmp@end@extension@decls}} % \changes{v4.0}{2019/03/16}{Rewrote to more closely honor the % \acro{XMP} specification} % Because \acro{IPTC} metadata are not recognized by the \acro{PDF/A} % standard, \acro{PDF/A} conversion would normally fail for documents % that utilize \acro{IPTC} metadata. Declaring the \acro{IPTC} % metadata we support enables the document to be converted to % \acro{PDF/A} format. % \begin{macrocode} \newcommand*{\hyxmp@iptc@extensions}{% \hyxmp@begin@ext@decl {IPTC Core Schema}% {Iptc4xmpCore}% {http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/}% \hyxmp@declare@property [ContactInfo] {CreatorContactInfo} {external} {Document creator's contact information} % \end{macrocode} % We can't call |\hyxmp@end@ext@decl| because we need first need to % define the \xmpprop{Iptc4xmpCore:ContactInfo} structure. % \begin{macrocode} \hyxmp@add@to@xml{% ______________^^J% ____________^^J% ____________^^J% ______________^^J% ________________^^J% __________________ContactInfo^^J% __________________http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/^^J% __________________Iptc4xmpCore^^J% __________________% Basic set of information to get in contact with a person% ^^J% __________________^^J% ____________________^^J% }% \hyxmp@declare@field {CiAdrCity}% {Contact information city}% \hyxmp@declare@field {CiAdrCtry}% {Contact information country}% \hyxmp@declare@field {CiAdrExtadr}% {Contact information address}% \hyxmp@declare@field {CiAdrPcode}% {Contact information local postal code}% \hyxmp@declare@field {CiAdrRegion}% {Contact information regional information such as state or province}% \hyxmp@declare@field {CiEmailWork}% {Contact information email address(es)}% \hyxmp@declare@field {CiTelWork}% {Contact information telephone number(s)}% \hyxmp@declare@field {CiUrlWork}% {Contact information Web URL(s)}% \hyxmp@add@to@xml{% ____________________^^J% __________________^^J% ________________^^J% ______________^^J% ____________^^J% __________^^J% }% } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@prism@extensions} % \changes{v4.0}{2019/03/15}{Added this macro} % Because \acro{PRISM} metadata are not recognized by the \acro{PDF/A} % standard, \acro{PDF/A} conversion would normally fail for documents % that utilize \acro{PRISM} metadata. Declaring the \acro{PRISM} % metadata we support enables the document to be converted to % \acro{PDF/A} format. % \begin{macrocode} \newcommand*{\hyxmp@prism@extensions}{% \hyxmp@begin@ext@decl {PRISM Basic Metadata}% {prism}% {http://prismstandard.org/namespaces/basic/3.0/}% \hyxmp@declare@property {complianceProfile}% {internal}% {PRISM specification compliance profile to which this document adheres}% \hyxmp@declare@property {publicationName}% {external}% {Publication name}% \hyxmp@declare@property {aggregationType}% {external}% {Publication type}% \hyxmp@declare@property {bookEdition}% {external}% {Edition of the book in which the document was published}% \hyxmp@declare@property {volume}% {external}% {Publication volume number}% \hyxmp@declare@property {number}% {external}% {Publication issue number within a volume}% \hyxmp@declare@property {pageRange}% {external}% {Page range for the document within the print version of its publication}% \hyxmp@declare@property {issn}% {external}% {ISSN for the printed publication in which the document was published}% \hyxmp@declare@property {eIssn}% {external}% {ISSN for the electronic publication in which the document was published}% \hyxmp@declare@property {isbn}% {external}% {ISBN for the publication in which the document was published}% \hyxmp@declare@property {doi}% {external}% {Digital Object Identifier for the document}% \hyxmp@declare@property [URL] {url}% {external}% {URL at which the document can be found}% \hyxmp@declare@property [Integer] {byteCount}% {internal}% {Approximate file size in octets}% \hyxmp@declare@property [Integer] {pageCount}% {internal}% {Number of pages in the print version of the document}% \hyxmp@declare@property {subtitle}% {external}% {Document's subtitle}% \hyxmp@end@ext@decl }% % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@jav@extensions} % \changes{v5.5}{2020/07/23}{Added this macro} % Because \acro{JAV} metadata are not recognized by the \acro{PDF/A} % standard, \acro{PDF/A} conversion would normally fail for documents % that utilize \acro{JAV} metadata. Declaring the \acro{JAV} metadata % we support enables the document to be converted to \acro{PDF/A} % format. % \begin{macrocode} \newcommand*{\hyxmp@jav@extensions}{% \hyxmp@begin@ext@decl {NISO/ALPSP Journal Article Versions}% {jav}% {http://www.niso.org/schemas/jav/1.0/}% \hyxmp@declare@property [Closed Choice of Text]% {journal_article_version}% {external}% {Article status, one of "AO", "SMUR", "AM", "P", "VoR", "CVoR", or "EVoR"}% \hyxmp@end@ext@decl }% % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@declare@extensions} % Declare all \acro{XMP} extension schemata. We'll always have at least % one, the \acro{XMP} Media Management extensions, because we % automatically generate \xmpprop{xmpMM:DocumentID} and % \xmpprop{xmpMM:InstanceID} % values. % \begin{macrocode} \newcommand*{\hyxmp@declare@extensions}{% \hyxmp@begin@extension@decls % \end{macrocode} % Declare the Adobe \acro{PDF} schema (always present). % \begin{macrocode} \hyxmp@pdf@extensions % \end{macrocode} % Declare the \acro{XMP} Media Management extensions (always present). % \begin{macrocode} \hyxmp@mm@extensions % \end{macrocode} % Declare the \acro{PDF/A} Identification extensions, but only when % generating a \acro{PDF/A} document. % \begin{macrocode} \ifHy@pdfa \hyxmp@pdfa@id@extensions \fi % \end{macrocode} % Conditionally declare the \acro{PDF/UA} Universal Accessibility % extensions. % \begin{macrocode} \ifx\@pdfuapart\@empty \else \hyxmp@pdfua@id@extensions \fi % \end{macrocode} % \begin{macro}{\next} % Conditionally declare the \acro{PDF/X} extensions. % \begin{macrocode} \ifx\@pdfxversion\@empty \else \hyxmp@pdfx@id@extensions \fi % \end{macrocode} % \end{macro} % Conditionally declare \acro{IPTC} photo metadata extensions. % \begin{macrocode} \ifx\hyxmp@iptc@data\@empty \else \hyxmp@iptc@extensions \fi % \end{macrocode} % Conditionally declare \acro{PRISM} basic metadata extensions. % \begin{macrocode} \ifx\hyxmp@prism@data\@empty \else \hyxmp@prism@extensions \fi % \end{macrocode} % Conditionally declare \acro{JAV} metadata. % \begin{macrocode} \ifx\hyxmp@jav@data\@empty \else \hyxmp@jav@extensions \fi % \end{macrocode} % \begin{macrocode} \hyxmp@end@extension@decls } % \end{macrocode} % \end{macro} % % \subsubsection{Combining schemata into an XMP packet} % \label{sec:combining-schemata} % % \begin{macro}{\hyxmp@bom} % Define a macro for the \term{Unicode} byte-order marker (\acro{BOM}). % \changes{v2.0}{2012/08/02}{Added by Heiko Oberdiek} % \begin{macrocode} \begingroup \ifhyxmp@unicodetex \lccode`\!="FEFF % \lowercase{% \gdef\hyxmp@bom{!} }% \else \catcode`\^^ef=12 \catcode`\^^bb=12 \catcode`\^^bf=12 \gdef\hyxmp@bom{^^ef^^bb^^bf}% \fi \endgroup % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@construct@packet} % \changes{v1.1}{2006/05/21}{Explicitly set the category codes of % characters \string\meta{EF}, \string\meta{BB}, and % \string\meta{BF} to ``letter''. Thanks to Daniel Sch\"omer for % the bug report} % \changes{v2.0}{2012/08/02}{Modified by Heiko Oberdiek to use an % appropriate \acro{BOM} representation via % \texttt{\string\string\string\hyxmp@bom}} % \begin{macro}{\hyxmp@xml} % Successively add \acro{XML} data to |\hyxmp@xml| until we have % something we can insert into the document's \acro{PDF} catalog. % \begin{macrocode} \def\hyxmp@construct@packet{% \gdef\hyxmp@xml{}% \hyxmp@add@to@xml{^^J% ^^J% __^^J% ____3 \hyxmp@add@to@xml{% _____________________xmlns:pdfxid="http://www.npes.org/pdfx/ns/id/"^^J% }% \fi % \end{macrocode} % Revert to ``include every namespace'' mode. % \begin{macrocode} \hyxmp@add@to@xml{% _____________________xmlns:prism="http://prismstandard.org/namespaces/basic/3.0/"^^J% _____________________xmlns:jav="http://www.niso.org/schemas/jav/1.0/"^^J% _____________________xmlns:xmpTPg="http://ns.adobe.com/xap/1.0/t/pg/"^^J% _____________________xmlns:stFnt="http://ns.adobe.com/xap/1.0/sType/Font\hyxmp@hash"^^J% _____________________xmlns:Iptc4xmpCore="http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/"^^J% _____________________xmlns:pdfaExtension="http://www.aiim.org/pdfa/ns/extension/"^^J% _____________________xmlns:pdfaSchema="http://www.aiim.org/pdfa/ns/schema\hyxmp@hash"^^J% _____________________xmlns:pdfaProperty="http://www.aiim.org/pdfa/ns/property\hyxmp@hash"^^J% _____________________xmlns:pdfaType="http://www.aiim.org/pdfa/ns/type\hyxmp@hash"^^J% _____________________xmlns:pdfaField="http://www.aiim.org/pdfa/ns/field\hyxmp@hash">^^J% }% % \end{macrocode} % Declare non-standard schemata. % \begin{macrocode} \hyxmp@check@iptc@data \hyxmp@check@prism@data \hyxmp@check@jav@data \hyxmp@declare@extensions % \end{macrocode} % Insert all the metadata we know how to insert. % \begin{macrocode} \hyxmp@pdf@schema \hyxmp@xmpRights@schema \hyxmp@dc@schema \hyxmp@photoshop@schema \hyxmp@xmp@basic@schema \hyxmp@pdfa@id@schema \hyxmp@pdfua@id@schema \hyxmp@pdfx@id@schema \hyxmp@mm@schema \hyxmp@iptc@schema \hyxmp@prism@schema \hyxmp@jav@schema \hyxmp@xmptpg@schema \hyxmp@add@to@xml{% ____^^J% __^^J% ^^J% \hyxmp@padding ^^J% }% } % \end{macrocode} % \end{macro} % \end{macro} % % % \subsection{Embedding the XMP packet} % % The \acro{PDF} specification says that ``a metadata stream may be % attached to a document through the \pdfterm{Metadata} entry in the % document catalogue''~\cite{Adobe2008:PDF} so that's what we do here. % % \begin{macro}{\hyxmp@embed@packet} % \begin{macro}{\hyxmp@driver} % Determine which \pkgname{hyperref} driver is in use and invoke the % appropriate embedding function. % \begin{macrocode} \newcommand*{\hyxmp@embed@packet}{% \hyxmp@construct@packet \def\hyxmp@driver{hpdftex}% \ifx\hyxmp@driver\Hy@driver \hyxmp@embed@packet@pdftex \else \def\hyxmp@driver{hluatex}% \ifx\hyxmp@driver\Hy@driver \hyxmp@embed@packet@luatex \else \def\hyxmp@driver{hdvipdfm}% \ifx\hyxmp@driver\Hy@driver \hyxmp@embed@packet@dvipdfm \else \def\hyxmp@driver{hxetex}% \ifx\hyxmp@driver\Hy@driver \hyxmp@embed@packet@xetex \else \@ifundefined{pdfmark}{% \PackageWarningNoLine{hyperxmp}{% Unrecognized hyperref driver `\Hy@driver'.\MessageBreak \hyxmp@jobname.tex's XMP metadata will *not* be\MessageBreak embedded in the resulting file}% }{% \hyxmp@embed@packet@pdfmark }% \fi \fi \fi \fi } % \end{macrocode} % \end{macro} % \end{macro} % % \subsubsection{Embedding using \pdfTeX} % % Up to version~0.85, \LuaTeX\ supported the \pdfTeX\ primitives, and % \pkgname{hyperref} didn't distinguish the two backends. However, from % \pkgname{hyperxmp}'s perspective there is one key difference: the % effect of |\pdfcompresslevel| is local to a group in \pdfTeX\ but is % global in \LuaTeX\@. % % The \acro{PDF} object representing the \acro{XMP} packet is supposed % to include an uncompressed stream so it can be read by % non-\acro{PDF}-aware tools. However, we don't want to unnecessarily % uncompress \emph{every} \acro{PDF} stream. The solution, provided by % Hans Hagen on the |luatex| mailing list (thread: % \href{http://tug.org/pipermail/luatex/2016-July/006077.html}{``Leaving % a single \acro{PDF} object uncompressed''}, 6\,\textsc{Jul}\,2016), % is to provide the |uncompressed| flag to |\pdfobj|. Our definition of % |\hyxmp@embed@packet@pdftex| uses the \pkgname{ifluatex} package to % distinguish the \pdfTeX\ case from the pre-0.85 \LuaTeX\ case. % % \begin{macrocode} \RequirePackage{ifluatex} % \end{macrocode} % % \begin{macro}{\hyxmp@embed@packet@pdftex} % Embed the \acro{XMP} packet using \pdfTeX\ primitives, which are % supported by both \pdfTeX\ and pre-0.85 \LuaTeX. The only difference % is that in the former case we locally specify |\pdfcompresslevel=0| to % leave the \acro{PDF} object uncompressed while in the latter case we % pass the |uncompressed| flag to |\pdfobj| to achieve the same effect. % \changes{v3.1}{2016/07/06}{Leave the \protect\acro{XMP} packet---and % only the \protect\acro{XMP} packet---uncompressed in both % \protect\pdfTeX\ and pre-0.85 \protect\LuaTeX} % \begin{macrocode} \newcommand*{\hyxmp@embed@packet@pdftex}{% \bgroup \ifluatex \else \pdfcompresslevel=0 \fi \immediate\pdfobj \ifluatex uncompressed\fi stream attr {% /Type /Metadata /Subtype /XML }{\hyxmp@xml}% \pdfcatalog {/Metadata \the\pdflastobj\space 0 R}% \egroup } % \end{macrocode} % \end{macro} % % \subsubsection{Embedding using \LuaTeX~0.85+} % % \begin{macro}{\hyxmp@embed@packet@luatex} % Embed the \acro{XMP} packet using \LuaTeX~0.85+ primitives. % \changes{v3.0}{2016/07/02}{Added this macro} % \changes{v3.1}{2016/07/06}{Updated to use % \protect\texttt{\string\string\string\pdfextension\ obj uncompressed} % as suggested by Hans Hagen} % \begin{macrocode} \newcommand*{\hyxmp@embed@packet@luatex}{% \immediate\pdfextension obj uncompressed stream attr {% /Type /Metadata /Subtype /XML }{\hyxmp@xml}% \pdfextension catalog {/Metadata \the\numexpr\pdffeedback lastobj\relax\space 0 R}% } % \end{macrocode} % \end{macro} % % \subsubsection{Embedding using any \texttt{pdfmark}-based backend} % % \begin{macro}{\hyxmp@embed@packet@pdfmark} % Embed the \acro{XMP} packet using \pkgname{hyperref}'s |\pdfmark| % command. I believe |\pdfmark| is used by the \optname{dvipdf}, % \optname{dvipsone}, \optname{dvips}, \optname{dviwindo}, % \optname{nativepdf}, \optname{pdfmark}, \optname{ps2pdf}, % \optname{textures}, and \optname{vtexpdfmark} options to % \pkgname{hyperref}, but I've tested only a few of those. % \begin{macrocode} \newcommand*{\hyxmp@embed@packet@pdfmark}{% \pdfmark{% pdfmark=/NamespacePush }% \pdfmark{% pdfmark=/OBJ, Raw={/_objdef \string{hyxmp@Metadata\string} /type /stream}% }% \pdfmark{% pdfmark=/PUT, Raw={\string{hyxmp@Metadata\string} 2 dict begin /Type /Metadata def /Subtype /XML def currentdict end }% }% \pdfmark{% pdfmark=/PUT, Raw={\string{hyxmp@Metadata\string} (\hyxmp@xml)}% }% \pdfmark{% pdfmark=/Metadata, Raw={\string{Catalog\string} \string{hyxmp@Metadata\string}}% }% \pdfmark{% pdfmark=/NamespacePop }% } % \end{macrocode} % \end{macro} % % \subsubsection{Embedding using \texttt{dvipdfm}} % % \begin{macro}{\hyxmp@embed@packet@dvipdfm} % Embed the \acro{XMP} packet using \cmdname{dvipdfm}-specific % |\special| commands. Note that \cmdname{dvipdfm} rather irritatingly % requires us to count the number of characters in the |\hyxmp@xml| % stream ourselves. % \begin{macrocode} \newcommand*{\hyxmp@embed@packet@dvipdfm}{% \hyxmp@string@len{\hyxmp@xml}% \special{pdf: object @hyxmp@Metadata << /Type /Metadata /Subtype /XML /Length \the\@hyxmp@count >> stream^^J\hyxmp@xml endstream% }% \special{pdf: docview << /Metadata @hyxmp@Metadata >> }% } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@string@len} % Set |\@hyxmp@count| to the number of characters in a given string~(|#1|). % The approach is first to tally the number of space characters then to % tally the number of non-space characters. While this is rather % sloppy I haven't found a better way to achieve the same effect, % especially given that all of the characters in |#1| have already been % assigned their category codes. % \begin{macrocode} \newcommand*{\hyxmp@string@len}[1]{% \@hyxmp@count=0 \expandafter\hyxmp@count@spaces#1 {} % \expandafter\hyxmp@count@non@spaces#1{}% } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@count@spaces} % Count the number of spaces in a given string. We rely on the built-in % pattern matching of \tex's |\def| primitive to pry one word at a time % off the head of the input string. % \begin{macrocode} \def\hyxmp@count@spaces#1 {% \def\hyxmp@one@token{#1}% \ifx\hyxmp@one@token\@empty \advance\@hyxmp@count by -1 \else \advance\@hyxmp@count by 1 \expandafter\hyxmp@count@spaces \fi } % \end{macrocode} % \end{macro} % % \begin{macro}{\hyxmp@count@non@spaces} % Count the number of non-spaces in a given string. Ideally, we'd count % both spaces and non-spaces but \tex\ won't bind |#1| to a space % character (category code~10). Hence, in each iteration, |#1| is bound % to the next non-space character only. % \begin{macrocode} \newcommand*{\hyxmp@count@non@spaces}[1]{% \def\hyxmp@one@token{#1}% \ifx\hyxmp@one@token\@empty \else \advance\@hyxmp@count by 1 \expandafter\hyxmp@count@non@spaces \fi } % \end{macrocode} % \end{macro} % % \subsubsection{Embedding using \XeTeX} % % \begin{macro}{\hyxmp@embed@packet@xetex} % Embed the \acro{XMP} packet using \cmdname{xdvipdfmx}-specific % |\special| commands. I don't know how to tell \cmdname{xdvipdfmx} % always to leave the \pdfterm{Metadata} stream uncompressed, so the % \acro{XMP} metadata is likely to be missed by non-\acro{PDF}-aware % \acro{XMP} viewers. % \begin{macrocode} \newcommand*{\hyxmp@embed@packet@xetex}{% \special{pdf:stream @hyxmp@Metadata (\hyxmp@xml) << /Type /Metadata /Subtype /XML >> }% \special{pdf:put @catalog << /Metadata @hyxmp@Metadata >> }% } % \end{macrocode} % \end{macro} % % % \subsection{Final clean-up} % \label{sec:clean-up} % % As explained in Section~\ref{sec:initial-prep}, all invocations of % \cs{AtEndPreamble} have been stored in \cs{hyxmp@aep@toks} rather than % executed. Now that \pkgname{hyperxmp} has been initialized % completely, it is finally safe to execute the accumulated % \cs{AtEndPreamble} stanzas. % \begin{macrocode} \the\hyxmp@aep@toks % \end{macrocode} % % Having saved the category code of % ``\,{\fontencoding{T1}\selectfont\textquotedbl}\,'' at the start of % the package code (Section~\ref{sec:initial-prep}), we now restore that % character's original category code. % % \begin{macrocode} \catcode`\"=\hyxmp@dq@code % \end{macrocode} % % \iffalse % % \fi % % \iffalse %<*doc-helper> % \fi % % ^^A There's not much point including the documentation helper code % ^^A in the documentation itself, but feel free to remove the % ^^A following |\iffalse| and matching |\fi| if you'd like to include % ^^A it. % \iffalse % % \section{Documentation helper code} % % The following code is used to make |hyperxmp.pdf| compliant with the % \PDFstd{A}{1}{b}{} standard, at least when built from \pdfLaTeX\ or % \LuaLaTeX, but not currently \XeLaTeX\@. We include this code in a % separate file because (a)~it is less distracting squirreled away here % than placed at the top of the |.dtx| file, and (b)~putting it in a % separate file makes it easy to disable. One simply needs to comment % out the |\input{hyperxmp-stds}| line to produce an ordinary \acro{PDF} % file, which offers the benefit of live hyperlinks in almost all % \acro{PDF} readers. % % % \subsection{Ensuring proper support} % % \begin{macro}{\next} % We can't proceed without a color profile. For this document we use a % \acro{CMYK} profile, specifically uncoated FOGRA29L, as a small and % thus safe color space. As long as |FOGRA29L_uncoated.icc| lies in the % \tex\ search path (which normally includes the current directory), % we'll be able to find it. % \begin{macrocode} \let\next=\endinput \IfFileExists{FOGRA29L_uncoated.icc} {\let\next=\relax} {} \next % \end{macrocode} % \end{macro} % % \begin{macro}{\next} % We can't proceed unless we're running either \pdfLaTeX\ or % \LuaLaTeX\@. \XeLaTeX\ doesn't appear to support all of the % mechanisms required below to support \PDFstd{A}{1}{b}{} compliance. % If you know how to adapt the following code to \XeLaTeX, please % contact the \pkgname{hyperxmp} maintainer. % \begin{macrocode} \let\next=\endinput \ifPDFTeX \let\next=\relax \else \ifLuaTeX \usepackage{luatex85} \let\next=\relax \fi \fi \next % \end{macrocode} % \end{macro} % % If we're here, we should be able to make |hyperxmp.pdf| % \PDFstd{A}{1}{b}{}-compliant. % \begin{macrocode} \def\wantpdfstandards{} \typeout{Generating PDF/A-1b compliant hyperxmp documentation.} % \end{macrocode} % % % \subsection{Complying with the PDF/A-1b standard} % % We can't specify \PDFstd{A}{1}{b}{} compliance until after both % \pkgname{hyperref} and \pkgname{hyperxmp} are loaded so we do so at % the beginning of the document. % \begin{macrocode} \AtBeginDocument{% \hypersetup{% pdfapart=1, pdfaconformance=b }% } % \end{macrocode} % % \PDFstd{A}{1}{b}{} forbids object compression. This is normally the % default for \pdfLaTeX, but the \TeX\ Live distribution changes the % default to compression level~2. Here we explicitly change it back % to~0. % \begin{macrocode} \pdfobjcompresslevel=0 % \end{macrocode} % % We specify an uncoated FOGRA29 output intent for both % \PDFstd{A}{1}{b}{} and \acro{PDF/X} (all versions). % \begin{macrocode} \immediate\pdfobj stream attr {/N 4} file {FOGRA29L_uncoated.icc} \edef\iccobj{\the\pdflastobj} \pdfcatalog{% /OutputIntents [ << /Type /OutputIntent /S /GTS_PDFA1 /DestOutputProfile \iccobj\space 0 R /OutputConditionIdentifier (Uncoated FOGRA29) /Info (FOGRA29L) >> << /Type /OutputIntent /S /GTS_PDFX /DestOutputProfile \iccobj\space 0 R /OutputConditionIdentifier (Uncoated FOGRA29) /Info (FOGRA29L) >> ] } % \end{macrocode} % % \begin{macro}{\HyColor@HyperrefBorderColor} % We just specified a \acro{CMYK} color profile, but \pkgname{hyperref} % normally produces \acro{RGB} link borders. The following code % instructs \pkgname{hyperref} to accept \acro{CMYK} colors. % \begin{macrocode} \makeatletter \AtBeginDocument{% \let\HyColor@HyperrefBorderColor\HyColor@XZeroOneThreeFour } \makeatother % \end{macrocode} % \end{macro} % % \pkgname{hyperref}'s default colors are specified as \acro{RGB}\@. We % need to reassign them so they take on \acro{CMYK} values. (Note that % the main document already loaded the \pkgname{xcolor} package with the % \optname{cmyk} option.) Annoyingly, very few \acro{PDF} readers % correctly color hyperlinks defined with \acro{CMYK} link borders. At % the time of this writing (March 2020), Adobe Acrobat DC displays the % \emph{reverse} of the specified color, presumably because it always % interprets the first three color channels as red, green, and blue. % Other browsers display no border or a black border. This is not a % huge problem in practice because (a)~it's more important to be able to % distinguish hyperlinks from regular text than to render with correct % border colors and (b)~\acro{PDF} readers may suppress hyperlink % borders anyway for \PDFstd{A}{1}{b}{} documents. % \begin{macrocode} \AtBeginDocument{% \hypersetup{% citebordercolor=green, linkbordercolor=red, urlbordercolor=cyan }% } % \end{macrocode} % % \begin{macro}{\@tempdima} % \begin{macro}{\boxwd} % \begin{macro}{\boxht} % \begin{macro}{\next} % Explicitly specify the \pdfterm{BleedBox} and \pdfterm{TrimBox} to use % for every page of the documentation. % \begin{macrocode} \makeatletter \@tempdima=0.996264\paperwidth \edef\boxwd{\strip@pt\@tempdima} \@tempdima=0.996264\paperheight \edef\boxht{\strip@pt\@tempdima} \makeatother \edef\next{% \protect\pdfpageattr{ /BleedBox [0.0 0.0 \boxwd\space \boxht] /TrimBox [0.0 0.0 \boxwd\space \boxht] /StructParents 0 /Tabs /S }% } \next % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \fi % % \iffalse % % \fi % % \Finale \endinput