diff options
author | Karl Berry <karl@freefriends.org> | 2006-05-24 00:51:38 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2006-05-24 00:51:38 +0000 |
commit | ae0bea40b27f392a9597f584308def4060a4bd4d (patch) | |
tree | 52c8a1ff3ada3e56586b43c4aa69686bc2ea348e /Master/texmf-dist/source/latex | |
parent | 42cb90508c7d60d9183533b23d65ac36e35ea4c0 (diff) |
hyperxmp install
git-svn-id: svn://tug.org/texlive/trunk@1587 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex')
-rw-r--r-- | Master/texmf-dist/source/latex/hyperxmp/hyperxmp.dtx | 1624 | ||||
-rw-r--r-- | Master/texmf-dist/source/latex/hyperxmp/hyperxmp.ins | 55 |
2 files changed, 1679 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/hyperxmp/hyperxmp.dtx b/Master/texmf-dist/source/latex/hyperxmp/hyperxmp.dtx new file mode 100644 index 00000000000..264e78496f7 --- /dev/null +++ b/Master/texmf-dist/source/latex/hyperxmp/hyperxmp.dtx @@ -0,0 +1,1624 @@ +% \iffalse meta-comment +% +% Copyright (C) 2006 by Scott Pakin <scott+hyxmp@pakin.org> +% ------------------------------------------------------- +% +% This file may be distributed and/or modified under the +% conditions of the LaTeX Project Public License, either version 1.3b +% 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.3b or later is part of all distributions of LaTeX +% version 2006/01/07 or later. +% +% \fi +% +% \iffalse +%<*driver> +\ProvidesFile{hyperxmp.dtx} +%</driver> +%<package>\NeedsTeXFormat{LaTeX2e}[1999/12/01] +%<package>\ProvidesPackage{hyperxmp} +%<*package> + [2006/05/21 v1.1 Store hyperref metadata in XMP format] +%</package> +% +%<*driver> +\documentclass{ltxdoc} +\usepackage{tocbibind} +\usepackage{hyperxmp} +\usepackage[bookmarksopen]{hyperref} +\EnableCrossrefs +\CodelineIndex +\RecordChanges +\begin{document} + \DocInput{hyperxmp.dtx} + \PrintChanges + \PrintIndex +\end{document} +%</driver> +% \fi +% +% \CheckSum{756} +% +% \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} +% +% \GetFileInfo{hyperxmp.dtx} +% +% \DoNotIndex{\#,\&,\<,\>,\\,\_,\|,\ } +% \DoNotIndex{\@cons,\@elt,\@empty,\@ifpackageloaded,\@ifundefined} +% \DoNotIndex{\@tempcnta,\@tempcntb} +% \DoNotIndex{\advance,\afterassignment,\aftergroup} +% \DoNotIndex{\begingroup,\bgroup} +% \DoNotIndex{\catcode} +% \DoNotIndex{\def,\divide} +% \DoNotIndex{\edef,\egroup,\else,\endgroup,\expandafter} +% \DoNotIndex{\fi,\futurelet} +% \DoNotIndex{\gdef,\global} +% \DoNotIndex{\if,\ifcase,\ifnum,\ifx,\immediate} +% \DoNotIndex{\let,\loop} +% \DoNotIndex{\MessageBreak,\multiply} +% \DoNotIndex{\newcommand,\noexpand} +% \DoNotIndex{\or} +% \DoNotIndex{\relax,\repeat} +% \DoNotIndex{\space,\string} +% \DoNotIndex{\the,\toks} +% \DoNotIndex{\xdef} +% +% ^^A Define a few logical styles. +% \DeclareRobustCommand{\term}[1]{#1\SortIndex{#1}{#1}} +% \DeclareRobustCommand{\pkgname}[1]{\textsf{#1}\SortIndex{#1}{\textsf{#1}}} +% \DeclareRobustCommand{\xmpterm}[1]{\textsf{#1}\SortIndex{#1}{\textsf{#1}}} +% \DeclareRobustCommand{\pdfterm}[1]{\textsf{#1}\SortIndex{#1}{\textsf{#1}}} +% \DeclareRobustCommand{\acrostyle}[1]{\textsc{\MakeLowercase{#1}}} +% \DeclareRobustCommand{\acro}[1]{^^A +% \acrostyle{#1}^^A +% \SortIndex{#1}{\acrostyle{#1}}^^A +% } +% +% ^^A Specify this document's metadata. +% \title{The \pkgname{hyperxmp} package\thanks{This document +% corresponds to \pkgname{hyperxmp}~\fileversion, dated \filedate.}} +% \author{Scott Pakin \\ \texttt{scott+hyxmp@pakin.org}} +% \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) 2006, Scott Pakin}, +% pdflicenseurl={http://www.latex-project.org/lppl/} +% } +% +% \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 recently been promoting +% \acro{XMP}~\cite{Adobe2005: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 of \acro{PDF}, \acrostyle{JPEG}, +% \acrostyle{HTML}, or any other type, 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. The generated \acro{PDF} file will contain, among +% other information, the following stanza of \acro{XMP} code embedded within +% it: +% +% \begin{verbatim} +% <dc:creator> +% <rdf:Seq> +% <rdf:li>Jack Napier</rdf:li> +% <rdf:li>Edward Nigma</rdf:li> +% <rdf:li>Harvey Dent</rdf:li> +% </rdf:Seq> +% </dc:creator> +% \end{verbatim} +% +% In the preceding code, the |dc| namespace refers to the +% \href{http://purl.org/DC/}{Dublin Core schema}, a collection of +% metadata properties. The |dc:creator| property surrounds the list of +% authors. The |rdf| namespace is the +% \href{http://www.w3.org/RDF/}{Resource Description Framework}, which +% defines |rdf:Seq| as an ordered list of values. Each author is +% represented by an individual list item (|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 applications to identify and categorize the +% document. +% +% \paragraph{What metadata does \textsf{hyperxmp} process?} +% \pkgname{hyperxmp} knows how to embed each of the following types of +% metadata within a document: +% +% \begin{itemize} +% \item authors (|dc:creator|) +% \item copyright (|dc:rights|) +% \item date (|dc:date|) +% \item document identifier (|xapMM:DocumentID|) +% \item document instance identifier (|xapMM:InstanceID|) +% \item format (|dc:format|) +% \item keywords (|pdf:Keyword| and |dc:subject|) +% \item license \acro{URL} (|xapRights:WebStatement|) +% \item \acro{PDF}-generating tool (|pdf:Producer|) +% \item summary (|dc:description|) +% \item title (|dc:title|) +% \end{itemize} +% +% \noindent +% More types of metadata may be added in a future release. +% +% \paragraph{How does \textsf{hyperxmp} compare with the \textsf{xmpincl} +% package?} +% The short answer is that \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 pdf\LaTeX\ 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. +% +% \section{Usage} +% +% \pkgname{hyperxmp} provides no commands of its own. Rather, it +% processes some of the package options honored by \pkgname{hyperref}. +% To use \pkgname{hyperxmp}, merely put a |\usepackage{hyperxmp}| +% somewhere in your document's preamble. \pkgname{hyperxmp} will +% construct its \acro{XMP} data using the following \pkgname{hyperref} options: +% +% \begin{itemize} +% \item |pdfauthor|, +% \item |pdfkeywords|, +% \item |pdfproducer|, +% \item |pdfsubject|, and +% \item |pdftitle|. +% \end{itemize} +% +% \noindent +% \pkgname{hyperxmp} instructs \pkgname{hyperref} also to accept the +% following options, which have meaning only to \pkgname{hyperxmp}: +% +% \begin{itemize} +% \item |pdfcopyright| and +% \item |pdflicenseurl|. +% \end{itemize} +% +% \noindent +% |\pdfcopyright| defines the copyright text. |pdflicenseurl| defines a +% \acro{URL} that points to the document's license agreement. +% +% It's usually more convenient to provide values for those options using +% \pkgname{hyperref}'s |\hypersetup| command than on the |\usepackage| +% command line. See +% \href{ftp://tug.ctan.org/pub/tex-archive/macros/latex/contrib/hyperref/doc/manual.pdf}{the +% \pkgname{hyperref} manual} for more information. The following is a +% sample \LaTeX\ document that provides values for most of the metadata +% options that \pkgname{hyperxmp} recognizes: +% +% \begin{verbatim} +% \documentclass{article} +% \usepackage{hyperxmp} +% \usepackage{hyperref} +% \title{% +% On a heuristic viewpoint concerning the production and +% transformation of light} +% \author{Albert Einstein} +% \hypersetup{% +% pdftitle={% +% On a heuristic viewpoint concerning the production and +% transformation of light}, +% pdfauthor={Albert Einstein}, +% pdfcopyright={Copyright (C) 1905, Albert Einstein}, +% pdfsubject={photoelectric effect}, +% pdfkeywords={energy quanta, Hertz effect, quantum physics} +% } +% \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} +% +% Compile the document to \acro{PDF} using any of the following approaches: +% +% \begin{itemize} +% \item pdf\LaTeX +% \item \LaTeX~$+$ Dvipdfm +% \item \LaTeX~$+$ Dvips~$+$ Ghostscript +% \end{itemize} +% +% The combination \LaTeX~$+$ Dvips~$+$ Adobe Acrobat Distiller +% \emph{almost} works but is hampered by a Distiller bug (at least in +% version~7.0.5) that incorrectly replaces the first author with the +% complete list of authors in the generated \acro{PDF} file. That is, +% if a document's authors are Jack Napier, Edward Nigma, and Harvey +% Dent, Distiller replaces ``Jack Napier'' with a single author named +% ``Jack Napier, Edward Nigma, Harvey Dent'' and leaves ``Edward Nigma'' +% and ``Harvey Dent'' as the second and third authors, respectively. +% Until Adobe fixes this bug, Adobe Acrobat Distiller is not recommended +% for use with \pkgname{hyperxmp}. +% +% Besides the approaches listed above, other approaches may work as well +% but have not been tested. Note that in many \TeX\ distributions +% |ps2pdf| is a convenience script that calls Ghostscript with the +% appropriate options for converting PostScript to \acro{PDF} and +% |dvipdf| is a convenience script that calls |dvips| and |ps2pdf|; both +% |ps2pdf| and |dvipdf| should be compatible with \pkgname{hyperxmp}. +% +% \bigskip +% +% The resulting \acro{PDF} file will contain an \acro{XMP} packet that +% looks something like this: +% +% \begin{verbatim} +% <?xpacket begin="???" id="W5M0MpCehiHzreSzNTczkc9d"?> +% <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="3.1-702"> +% <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> +% <rdf:Description rdf:about="" +% xmlns:pdf="http://ns.adobe.com/pdf/1.3/"> +% <pdf:Keywords>energy quanta, Hertz effect, +% quantum physics</pdf:Keywords> +% <pdf:Producer>pdfeTeX-1.10b</pdf:Producer> +% </rdf:Description> +% <rdf:Description rdf:about="" +% xmlns:dc="http://purl.org/dc/elements/1.1/"> +% <dc:format>application/pdf</dc:format> +% <dc:title> +% <rdf:Alt> +% <rdf:li xml:lang="x-default">On a heuristic viewpoint +% concerning the production and transformation of +% light</rdf:li> +% </rdf:Alt> +% </dc:title> +% <dc:description> +% <rdf:Alt> +% <rdf:li xml:lang="x-default">photoelectric effect</rdf:li> +% </rdf:Alt> +% </dc:description> +% <dc:rights> +% <rdf:Alt> +% <rdf:li xml:lang="x-default">Copyright (C) 1905, +% Albert Einstein</rdf:li> +% </rdf:Alt> +% </dc:rights> +% <dc:creator> +% <rdf:Seq> +% <rdf:li>Albert Einstein</rdf:li> +% </rdf:Seq> +% </dc:creator> +% <dc:subject> +% <rdf:Bag> +% <rdf:li>energy quanta</rdf:li> +% <rdf:li>Hertz effect</rdf:li> +% <rdf:li>quantum physics</rdf:li> +% </rdf:Bag> +% </dc:subject> +% <dc:date> +% <rdf:Seq> +% <rdf:li>2006-04-19</rdf:li> +% </rdf:Seq> +% </dc:date> +% </rdf:Description> +% <rdf:Description rdf:about="" +% xmlns:xapMM="http://ns.adobe.com/xap/1.0/mm/"> +% <xapMM:DocumentID>uuid:c4188820-aef2-0a82-626ce4182b62</xapMM:DocumentID> +% <xapMM:InstanceID>uuid:9b62b67f-d754-626c-4c959595fd75</xapMM:InstanceID> +% </rdf:Description> +% </rdf:RDF> +% </x:xmpmeta> +% <?xpacket end="w"?> +% \end{verbatim} +% +% \pkgname{hyperxmp} splits the |pdfauthor| and |pdfkeywords| lists at +% commas. Therefore, when specifying |pdfauthor| and |pdfkeywords|, you +% should separate items with commas. Also, omit ``|and|'' and other +% text that does not belong to any list item. The following example +% should serve as clarification: +% +% \begin{description} +% \item[Wrong:] |pdfauthor={Jack Napier, Edward Nigma, and Harvey Dent}| +% \item[Wrong:] |pdfauthor={Jack Napier; Edward Nigma; Harvey Dent}| +% \item[Right:] |pdfauthor={Jack Napier, Edward Nigma, Harvey Dent}| +% \end{description} +% +% If you desperately need to include a comma within an author or keyword +% list you can define your own comma macro as follows: +% +% \begin{verbatim} +% \bgroup +% \catcode`,=11 +% \gdef\mycomma{,} +% \egroup +% \end{verbatim} +% +% \noindent +% Thereafter, you can use |\mycomma| as a literal comma: +% +% \begin{verbatim} +% pdfauthor={Napier\mycomma\ Jack, +% Nigma\mycomma\ Edward, +% Dent\mycomma\ Harvey} +% \end{verbatim} +% +% +% \StopEventually{^^A +% \begin{thebibliography}{1} +% \bibitem{Adobe2004:PDF} +% Adobe Systems, Inc., San Jose, California. +% \newblock {\em {PDF} Reference, Fifth Edition: {A}dobe Portable Document Format +% Version~1.6}, November 2004. +% \newblock Available from +% \url{http://partners.adobe.com/public/developer/en/pdf/PDFReference16.pdf}. +% +% \bibitem{Adobe2005:pdfmark} +% Adobe Systems, Inc., San Jose, California. +% \newblock {\em {A}dobe {A}crobat~7.0.5 pdfmark Reference Manual}, October~2, +% 2005. +% \newblock Available from +% \url{http://partners.adobe.com/public/developer/en/acrobat/sdk/pdf/pdf_creation_apis_and_specs/pdfmarkReference.pdf}. +% +% \bibitem{Adobe2005:XMP} +% Adobe Systems, Inc., San Jose, California. +% \newblock {\em {XMP} Specification}, June 2005. +% \newblock Available from +% \url{http://partners.adobe.com/public/developer/en/xmp/sdk/xmpspecification.pdf}. +% +% \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}. +% \end{thebibliography} +% } +% +% +% \section{Implementation} +% +% This section presents the commented \LaTeXe\ source code for +% \pkgname{hyperxmp}. Read this section only if you want to learn how +% \pkgname{hyperxmp} is implemented. +% +% +% \subsection{Integration with \textsf{hyperref}} +% +% An important design decision underlying \pkgname{hyperxmp} is that the +% package should integrate seamlessly with \pkgname{hyperref}. To that +% end, \pkgname{hyperxmp} takes its \acro{XMP} metadata from the +% \pkgname{hyperref} |pdftitle|, |pdfauthor|, |pdfsubject|, and +% |pdfkeywords| options plus two new options, |pdfcopyright| and +% |pdflicenseurl|, introduced by \pkgname{hyperxmp}. +% +% \begin{macrocode} +\RequirePackage{keyval} +% \end{macrocode} +% +% \begin{macro}{\@pdfcopyright} +% Prepare to store the document's copyright statement. For consistency +% with \pkgname{hyperref}'s document-metadata naming conventions (which +% are in turn based on \LaTeXe's document-metadata naming conventions), +% we do not prefix the macro name with our package-specific |\hyxmp@| +% prefix. +% \begin{macrocode} +\def\@pdfcopyright{} +\define@key{Hyp}{pdfcopyright}{\pdfstringdef\@pdfcopyright{#1}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@pdflicenseurl} +% Prepare to store the \acro{URL} containing the document's license +% agreement. For consistency with \pkgname{hyperref}'s +% document-metadata naming conventions (which are in turn based on +% \LaTeXe's document-metadata naming conventions), we do not prefix the +% macro name with our package-specific |\hyxmp@| prefix. +% \begin{macrocode} +\def\@pdflicenseurl{} +\define@key{Hyp}{pdflicenseurl}{\pdfstringdef\@pdflicenseurl{#1}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\hyxmp@find@metadata} +% Issue a warning message if the author failed to include any metadata +% at all. +% \begin{macrocode} +\newcommand*{\hyxmp@find@metadata}{% + \ifx\@pdfauthor\@empty + \ifx\@pdfcopyright\@empty + \ifx\@pdfkeywords\@empty + \ifx\@pdflicenseurl\@empty + \ifx\@pdfsubject\@empty + \ifx\@pdftitle\@empty + \PackageWarningNoLine{hyperxmp}{% +\jobname.tex did not specify any metadata to\MessageBreak +include in the XMP packet.\space\space Please see the hyperxmp\MessageBreak +documentation for instructions on how to provide\MessageBreak +metadata values to hyperxmp% + }% + \fi + \fi + \fi + \fi + \fi + \fi +} +% \end{macrocode} +% \end{macro} +% +% Rather than load \pkgname{hyperref} ourself we let the author do it +% then verify he actually did. This approach gives the author the +% flexibility to load \pkgname{hyperxmp} and \pkgname{hyperref} in +% either order and to call |\hypersetup| anywhere in the document's +% preamble, not just before \pkgname{hyperxmp} is loaded. +% \begin{macrocode} +\AtBeginDocument{% + \@ifpackageloaded{hyperref}% + {% +% \end{macrocode} +% We wait until the end of the document to construct the \acro{XMP} +% packet and write it to the \acro{PDF} document catalog. This gives +% the author ample opportunity to provide metadata to \pkgname{hyperref} +% and thereby \pkgname{hyperxmp}. +% \begin{macrocode} + \AtEndDocument{% + \hyxmp@find@metadata + \hyxmp@embed@packet + }% + }% + {\PackageWarningNoLine{hyperxmp}{% +\jobname.tex failed to include a\MessageBreak +\string\usepackage\string{hyperref\string} +in the preamble.\MessageBreak +Consequently, all hyperxmp functionality will be\MessageBreak +disabled}% + }% +} +% \end{macrocode} +% +% +% \subsection{Manipulating author-supplied data} +% +% The author provides metadata information to \pkgname{hyperxmp} via +% package options to \pkgname{hyperref} or via the \pkgname{hyperref} +% |\hypersetup| command. The functions in this section convert +% author-supplied lists (e.g.,~|pdfkeywords={foo, bar, baz}|) into +% \LaTeXe\ lists (e.g.,~|\@elt {foo}| |\@elt {bar}| |\@elt {baz}|) that +% can be more easily manipulated (Section~\ref{sec:list-manip}); define +% macros for the \acro{XML} entites |<|, |>|, and |&| +% (Section~\ref{sec:xml-entities}); trim spaces off the ends of strings +% (Section~\ref{sec:trim-spaces}); and, in Section~\ref{sec:text-xml}, +% convert text to \acro{XML} (e.g.,~from |<scott+hyxmp@pakin.org>| to +% |<scott+hyxmp@pakin.org>|). +% +% \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 \LaTeXe\ +% |\@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} +% +% \subsubsection{Character-code and XML entity definitions} +% \label{sec:xml-entities} +% +% The \pkgname{hyperref} package invokes |\pdfstringdef| on its metadata +% parameters, setting every character to \TeX\ category code~11 +% (``other''). To match against these, we have to define a few category +% code~11 characters of our own. Furthermore, because \acro{XMP} is an +% \acro{XML} format, we have to replace the characters ``|&|'', ``|<|'', +% and ``|>|'' with equivalent \acro{XML} entities. +% +% \begin{macro}{\hyxmp@xml@amp} +% \begin{macro}{\hyxmp@other@amp} +% \begin{macro}{\hyxmp@amp} +% Define category code~11 (``other'') versions of the character~``|&|'' +% and map |\hyxmp@other@amp| to its \acro{XML} entity, |&|. +% \begin{macrocode} +\bgroup +\catcode`\&=11 +\gdef\hyxmp@xml@amp{&} +\global\let\hyxmp@other@amp=& +\gdef\hyxmp@amp{&} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\hyxmp@xml@lt} +% \begin{macro}{\hyxmp@other@lt} +% Define a category code~11 (``other'') version of the character~``|<|'' +% and map |\hyxmp@other@lt| to its \acro{XML} entity, |<|. +% \begin{macrocode} +\catcode`\<=11 +\gdef\hyxmp@xml@lt{<} +\global\let\hyxmp@other@lt=< +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\hyxmp@xml@gt} +% \begin{macro}{\hyxmp@other@gt} +% Define a category code~11 (``other'') version of the character~``|>|'' +% and map |\hyxmp@other@gt| to its \acro{XML} entity, |>|. +% \begin{macrocode} +\catcode`\>=11 +\gdef\hyxmp@xml@gt{>} +\global\let\hyxmp@other@gt=> +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\hyxmp@other@space} +% \begin{macro}{\next} +% Define a category code~11 (``other'') version of the space character. +% \begin{macrocode} +\def\next#1{#1} +\next{\global\let\hyxmp@other@space= } % +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\hyxmp@other@bs} +% Define a category code~11 (``other'') version of the character~``|\|''. +% \begin{macrocode} +\catcode`\|=0 +\catcode`\\=11 +|global|let|hyxmp@other@bs=\ +|egroup +% \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}{\hyxmp@xmlify} +% \begin{macro}{\hyxmp@xmlified} +% 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~|&|. +% +% If |\pdfmark| is defined then there's a chance the user will run +% |dvips| on the resulting \acro{DVI} file and |dvips| may convert some +% of the spaces to newlines, which is problematic for the proper display +% of an \acro{XMP} packet. We therefore conditionally invoke +% |\hyxmp@obscure@spaces| to replace all spaces with | |. +% \begin{macrocode} +\newcommand*{\hyxmp@xmlify}[1]{% + \gdef\hyxmp@xmlified{}% + \expandafter\hyxmp@xmlify@i#1\@empty + \@ifundefined{pdfmark}{}{% + \expandafter\hyxmp@obscure@spaces\expandafter{\hyxmp@xmlified}% + }% +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\hyxmp@xmlify@i} +% \begin{macro}{\hyxmp@one@token} +% Bind the next token in the input stream to |\hyxmp@one@token| and +% invoke |\hyxmp@xmlify@ii|. |\hyxmp@xmlify@i| (and therefore +% |\hyxmp@xmlify@ii|) is invoked on each character in the text supplied +% to |\hyxmp@xmlify|. +% \begin{macrocode} +\def\hyxmp@xmlify@i{\futurelet\hyxmp@one@token\hyxmp@xmlify@ii} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\hyxmp@xmlify@ii} +% \begin{macro}{\next} +% Given a token in |\hyxmp@one@token|, define |\next| to consume the +% token, append the corresponding text to |\hyxmp@xmlified|, and +% recursively invoke |\hyxmp@xmlify@i| to consume subsequent tokens. +% \begin{macrocode} +\def\hyxmp@xmlify@ii{% + \if\hyxmp@one@token\hyxmp@other@lt +% \end{macrocode} +% Replace ``|<|'' with |<|. +% \begin{macrocode} + \def\next##1{% + \xdef\hyxmp@xmlified{\hyxmp@xmlified\hyxmp@xml@lt}% + \hyxmp@xmlify@i + }% + \else + \if\hyxmp@one@token\hyxmp@other@gt +% \end{macrocode} +% Replace ``|>|'' with |>|. +% \begin{macrocode} + \def\next##1{% + \xdef\hyxmp@xmlified{\hyxmp@xmlified\hyxmp@xml@gt}% + \hyxmp@xmlify@i + }% + \else + \if\hyxmp@one@token\hyxmp@other@amp +% \end{macrocode} +% Replace ``|&|'' with |&|. +% \begin{macrocode} + \def\next##1{% + \xdef\hyxmp@xmlified{\hyxmp@xmlified\hyxmp@xml@amp}% + \hyxmp@xmlify@i + }% + \else + \ifx\hyxmp@one@token\hyxmp@other@space +% \end{macrocode} +% Store spaces. We need a special case for this to avoid inadvertently +% discarding spaces. +% \begin{macrocode} + \def\next##1{% + \g@addto@macro\hyxmp@xmlified{ }% + \hyxmp@xmlify@i##1% + }% + \else + \if\hyxmp@one@token\hyxmp@other@bs +% \end{macrocode} +% Replace |\|\meta{ooo} with |&#|\meta{ddd}|;|. For example, |\100|, +% the octal code for ``|@|'', is represented in \acro{XML} as~|@|. +% \begin{macrocode} + \def\next##1{\futurelet\hyxmp@one@token\hyxmp@xmlify@iii} + \else + \ifx\hyxmp@one@token\@empty +% \end{macrocode} +% End the recursion upon encountering |\@empty|. +% \begin{macrocode} + \def\next##1{}% + \else +% \end{macrocode} +% In most cases we merely append the next character in the input to +% |\hyxmp@xmlified| without any special processing. +% \begin{macrocode} + \def\next##1{% + \g@addto@macro\hyxmp@xmlified{##1}% + \hyxmp@xmlify@i + }% + \fi + \fi + \fi + \fi + \fi + \fi +% \end{macrocode} +% Recursively process the next character in the input stream. +% \begin{macrocode} + \next +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\hyxmp@xmlify@iii} +% \begin{macro}{\next} +% \pkgname{hyperref}'s |\pdfstringdef| macro converts certain special +% characters to a backslash followed by a three-digit octal number. +% However, it also replaces ``|(|'' and ``|)|'' with ``|\(|'' and +% ``|\)|''. The |\hyxmp@xmlify@iii| macro is called after encountering +% (and removing) a backslash. If the next character in the input stream +% (|\hyxmp@one@token|) is a parenthesis, |\hyxmp@xmlify@iii| leaves it +% alone. Otherwise, |\hyxmp@xmlify@iii| assumes it's an octal number +% and replaces it with its \acro{XML} equivalent. +% \begin{macrocode} +\def\hyxmp@xmlify@iii{% + \def\next##1##2##3{% + \@tempcnta='##1##2##3 + \xdef\hyxmp@xmlified{\hyxmp@xmlified + \hyxmp@amp\hyxmp@hash\the\@tempcnta;% + }% + \hyxmp@xmlify@i + }% + \if\hyxmp@one@token( + \let\next=\hyxmp@xmlify@i + \else + \if\hyxmp@one@token) + \let\next=\hyxmp@xmlify@i + \fi + \fi + \next +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\hyxmp@obscure@spaces} +% The |dvips| backend rather obnoxiously word-wraps text. Doing so can +% cause \acro{XMP} metadata to be displayed incorrectly. For example, +% Adobe Acrobat displays the document's |dc:rights| (copyright notice) +% within a single-line field. By introducing an extra line break in the +% middle of the copyright notice, |dvips| implicitly causes it to be +% truncated when displayed. +% +% To thwart |dvips|'s word-wrapping, we define |\hyxmp@obscure@spaces| +% to replace each space in a given piece of text with an \acro{XML} | | +% (space) entity. +% \begin{macrocode} +\newcommand*{\hyxmp@obscure@spaces}[1]{% + \gdef\hyxmp@xmlified{}% + \expandafter\hyxmp@obscure@spaces@i#1 {} % +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\hyxmp@obscure@spaces@i} +% \begin{macro}{\hyxmp@one@token} +% \begin{macro}{\next} +% Do all of the work for |\hyxmp@obscure@spaces|. +% \begin{macrocode} +\def\hyxmp@obscure@spaces@i #1 #2 {% + \def\hyxmp@one@token{#2}% + \ifx\hyxmp@one@token\@empty + \xdef\hyxmp@xmlified{\hyxmp@xmlified#1}% + \let\next=\relax + \else + \xdef\hyxmp@xmlified{\hyxmp@xmlified#1\hyxmp@amp\hyxmp@hash32;}% + \def\next{\expandafter\hyxmp@obscure@spaces@i\expandafter#2 }% + \fi + \next +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \subsection{UUID generation} +% +% We use a linear congruential generator to produce pseudorandom +% \acro{UUID}s. True, this method has its flaws but it's simple to +% implement in \TeX\ and is good enough for producing the \acro{XMP} +% \xmpterm{DocumentID} and \xmpterm{InstanceID} fields. +% +% \begin{macro}{\hyxmp@modulo@a} +% Replace the contents of |\@tempcnta| with the contents modulo~|#1|. +% Note that |\@tempcntb| is overwritten in the process. +% \begin{macrocode} +\def\hyxmp@modulo@a#1{% + \@tempcntb=\@tempcnta + \divide\@tempcntb by #1 + \multiply\@tempcntb by #1 + \advance\@tempcnta 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{% + \@tempcnta=\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\@tempcnta} \leftarrow 3 +% \cdot \mathtt{\string\@tempcnta} + 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\@tempcnta by 3 + \advance\@tempcnta 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 |\@tempcnta| +% and |\@tempcntb| are overwritten in the process. +% \begin{macrocode} +\def\hyxmp@set@rand@num{% + \@tempcnta=\hyxmp@rand@num + \multiply\@tempcnta by 3 + \advance\@tempcnta by \hyxmp@big@prime@ii + \hyxmp@modulo@a{\hyxmp@big@prime}% + \xdef\hyxmp@rand@num{\the\@tempcnta}% +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\hyxmp@append@hex} +% Append a randomly selected hexadecimal digit to macro~|#1|. Note that +% both |\@tempcnta| and |\@tempcntb| are overwritten in the process. +% \begin{macrocode} +\def\hyxmp@append@hex#1{% + \hyxmp@set@rand@num + \@tempcnta=\hyxmp@rand@num + \hyxmp@modulo@a{16}% + \ifnum\@tempcnta<10 + \xdef#1{#1\the\@tempcnta}% + \else +% \end{macrocode} +% There \emph{must} be a better way to handle the numbers~10--15 than +% with |\ifcase|. +% \begin{macrocode} + \advance\@tempcnta by -10 + \ifcase\@tempcnta + \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@iv} +% Invoke |\hyxmp@append@hex| four times. +% \begin{macrocode} +\def\hyxmp@append@hex@iv#1{% + \hyxmp@append@hex#1% + \hyxmp@append@hex#1% + \hyxmp@append@hex#1% + \hyxmp@append@hex#1% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\hyxmp@create@uuid} +% Define macro~|#1| as a \acro{UUID} of the form +% ``|uuid:|\textit{xxxxxxxx}|-|\textit{xxxx}|-|\textit{xxxx}|-|\textit{xxxxxxxxxxxx}'' +% in which each ``\textit{x}'' is a lowercase hexadecimal digit. We +% assume that the random-number generator is already seeded. Note that +% |\hyxmp@create@uuid| overwrites both |\@tempcnta| and |\@tempcntb|. +% \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{-}% + \hyxmp@append@hex@iv#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} +% 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}. +% \begin{macrocode} +\newcommand*{\hyxmp@def@DocumentID}{% + \edef\hyxmp@seed@string{\jobname:\@pdftitle:\@pdfauthor}% + \expandafter\hyxmp@seed@rng\expandafter{\hyxmp@seed@string}% + \edef\hyxmp@rand@num{\the\@tempcnta}% + \hyxmp@create@uuid\hyxmp@DocumentID +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\hyxmp@def@InstanceID} +% \begin{macro}{\hyxmp@InstanceID} +% Seed the random-number generator with a function of the current +% filename, \acro{PDF} document title, \acro{PDF} author, and the +% current day, month, year, and minutes since midnight, then invoke +% |\hyxmp@create@uuid| to define |\hyxmp@InstanceID| as a random +% \acro{UUID}. +% \begin{macrocode} +\newcommand*{\hyxmp@def@InstanceID}{% + \edef\hyxmp@seed@string{% + \jobname:\@pdftitle:\@pdfauthor:% + \the\year/\the\month/\the\day:% + \the\time + }% + \expandafter\hyxmp@seed@rng\expandafter{\hyxmp@seed@string}% + \edef\hyxmp@rand@num{\the\@tempcnta}% + \hyxmp@create@uuid\hyxmp@InstanceID +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% \subsection{Constructing the XMP packet} +% +% An \acro{XMP} packet comprises a header, ``serialized \acro{XMP}'', +% padding, and a trailer~\cite{Adobe2005:XMP}. The serialized +% \acro{XMP} includes blocks of \acro{XML} for various \acro{XMP} +% schemata: Adobe \acro{PDF} (Section~\ref{sec:adobe-pdf}), Dublin Core +% (Section~\ref{sec:dublin-core}), \acro{XMP} Rights Management +% (Section~\ref{sec:xmp-rights}), and \acro{XMP} Media Management +% (Section~\ref{sec:xmp-media}). The |\hyxmp@construct@packet| macro +% 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 append the result to the |\hyxmp@xml| macro. +% \begin{macrocode} +\newcommand*{\hyxmp@add@to@xml}[1]{% + \bgroup + \@tempcnta=0 + \loop + \lccode\@tempcnta=\@tempcnta + \advance\@tempcnta by 1 + \ifnum\@tempcnta<256 + \repeat + \lccode`\_=`\ \relax + \lowercase{\xdef\hyxmp@xml{\hyxmp@xml#1}}% + \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~\cite{Adobe2005:XMP} recommends leaving a +% few kilobytes of whitespace at the end of each \acro{XMP} packet to +% facilitate editing the packet in place. |\hyxmp@padding| is defined +% to contain 32~lines of 50~spaces and a newline apiece for a total of +% 1632 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@today} +% Define today's date in \textit{YYYY}-\textit{MM}-\textit{DD} format. +% \begin{macrocode} +\xdef\hyxmp@today{\the\year}% +\ifnum\month<10 + \xdef\hyxmp@today{\hyxmp@today-0\the\month}% +\else + \xdef\hyxmp@today{\hyxmp@today-\the\month}% +\fi +\ifnum\day<10 + \xdef\hyxmp@today{\hyxmp@today-0\the\day}% +\else + \xdef\hyxmp@today{\hyxmp@today-\the\day}% +\fi +% \end{macrocode} +% \end{macro} +% +% \subsubsection{The Adobe PDF schema} +% \label{sec:adobe-pdf} +% +% \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} +% \begin{macro}{\hyxmp@have@any} +% Include an Adobe \acro{PDF} schema block if at least one of +% |\@pdfkeywords| and |\@pdfproducer| is defined. +% \begin{macrocode} + \let\hyxmp@have@any=!% + \ifx\@pdfkeywords\@empty + \ifx\@pdfproducer\@empty + \let\hyxmp@have@any=\@empty + \fi + \fi + \ifx\hyxmp@have@any\@empty + \else +% \end{macrocode} +% Add a block of \acro{XML} to |\hyxmp@xml| that lists the document's keywords +% (the \xmpterm{Keywords} property) and the tools used to produce the +% \acro{PDF} file (the \xmpterm{Producer} property). +% \begin{macrocode} + \hyxmp@add@to@xml{% +______<rdf:Description rdf:about=""^^J% +___________xmlns:pdf="http://ns.adobe.com/pdf/1.3/">^^J% + }% + \ifx\@pdfkeywords\@empty + \else + \hyxmp@xmlify{\@pdfkeywords}% + \hyxmp@add@to@xml{% +___________<pdf:Keywords>\hyxmp@xmlified</pdf:Keywords>^^J% + }% + \fi + \ifx\@pdfproducer\@empty + \else + \hyxmp@xmlify{\@pdfproducer}% + \hyxmp@add@to@xml{% +___________<pdf:Producer>\hyxmp@xmlified</pdf:Producer>^^J% + }% + \fi + \hyxmp@add@to@xml{% +______</rdf:Description>^^J% + }% + \fi +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsubsection{The Dublin Core schema} +% \label{sec:dublin-core} +% +% \begin{macro}{\hyxmp@rdf@dc} +% Given a Dublin Core property~(|#1|) and a macro containing some +% |\pdfstringdef|-defined text~(|#2|), append the appropriate block of +% \acro{XML} to the |\hyxmp@xml| macro but only if |#2| is non-empty. +% \begin{macrocode} +\newcommand*{\hyxmp@rdf@dc}[2]{% + \ifx#2\@empty + \else + \hyxmp@xmlify{#2}% + \hyxmp@add@to@xml{% +_________<dc:#1>^^J% +____________<rdf:Alt>^^J% +_______________<rdf:li xml:lang="x-default">\hyxmp@xmlified</rdf:li>^^J% +____________</rdf:Alt>^^J% +_________</dc:#1>^^J% + }% + \fi% +}% +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\hyxmp@list@to@xml} +% Given a Dublin Core property~(|#1|), an RDF array~(|#2|), and a macro +% containing a comma-separated list~(|#3|), append the appropriate block +% of \acro{XML} to the |\hyxmp@xml| macro but only if |#3| is non-empty. +% \begin{macrocode} +\newcommand*{\hyxmp@list@to@xml}[3]{% + \ifx#3\@empty + \else + \hyxmp@add@to@xml{% +_________<dc:#1>^^J% +____________<rdf:#2>^^J% + }% + \bgroup + \hyxmp@commas@to@list\hyxmp@list{#3}% + \def\@elt##1{% + \hyxmp@xmlify{##1}% + \hyxmp@add@to@xml{% +_______________<rdf:li>\hyxmp@xmlified</rdf:li>^^J% + }% + }% + \hyxmp@list + \egroup + \hyxmp@add@to@xml{% +____________</rdf:#2>^^J% +_________</dc:#1>^^J% + }% + \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 \xmpterm{title} property +% if the author specified a |pdftitle|, the \xmpterm{description} +% property if the author specified a |pdfsubject|, the \xmpterm{rights} +% property if the author specified a |pdfcopyright|, the +% \xmpterm{creator} property if the author specified a |pdfauthor|, and +% the \xmpterm{subject} property if the author specified |pdfkeywords|. +% We also specify the \xmpterm{date} property using the date the +% document was run through \LaTeX. +% \begin{macrocode} +\newcommand*{\hyxmp@dc@schema}{% + \hyxmp@add@to@xml{% +______<rdf:Description rdf:about=""^^J% +____________xmlns:dc="http://purl.org/dc/elements/1.1/">^^J% +_________<dc:format>application/pdf</dc:format>^^J% + }% + \hyxmp@rdf@dc{title}{\@pdftitle}% + \hyxmp@rdf@dc{description}{\@pdfsubject}% + \hyxmp@rdf@dc{rights}{\@pdfcopyright}% + \hyxmp@list@to@xml{creator}{Seq}{\@pdfauthor}% + \hyxmp@list@to@xml{subject}{Bag}{\@pdfkeywords}% + \hyxmp@list@to@xml{date}{Seq}{\hyxmp@today}% + \hyxmp@add@to@xml{% +______</rdf:Description>^^J% + }% +} +% \end{macrocode} +% \end{macro} +% +% \subsubsection{The XMP Rights Management schema} +% \label{sec:xmp-rights} +% +% \begin{macro}{\hyxmp@xapRights@schema} +% Add properties defined by the XMP Rights Management schema to the +% |\hyxmp@xml| macro. Currently, these are only the \xmpterm{Marked} +% property and the \xmpterm{WebStatement} property and only if the +% author defined a |pdflicenseurl|. +% \begin{macrocode} +\newcommand*{\hyxmp@xapRights@schema}{% + \ifx\@pdflicenseurl\@empty + \else + \hyxmp@xmlify{\@pdflicenseurl}% + \hyxmp@add@to@xml{% +______<rdf:Description rdf:about=""^^J% +___________xmlns:xapRights="http://ns.adobe.com/xap/1.0/rights/">^^J% +_________<xapRights:Marked>True</xapRights:Marked>^^J% +_________<xapRights:WebStatement>\hyxmp@xmlified</xapRights:WebStatement>^^J% +______</rdf:Description>^^J% + }% + \fi +} +% \end{macrocode} +% \end{macro} +% +% \subsubsection{The XMP Media Management schema} +% \label{sec:xmp-media} +% +% \begin{macro}{\hyxmp@mm@schema} +% Add properties defined by the XMP Media Management schema to the +% |\hyxmp@xml| macro. Although the \xmpterm{DocumentID} property is +% defined in the \acro{XMP} specification~\cite{Adobe2005:XMP}, the +% \xmpterm{InstanceID} property is not. However, an +% \xmpterm{InstanceID} field is produced by Adobe Acrobat~7.0 (the +% latest version at the time of this writing) so it's probably worth +% including here. +% \begin{macrocode} +\gdef\hyxmp@mm@schema{% + \hyxmp@def@DocumentID + \hyxmp@def@InstanceID + \hyxmp@add@to@xml{% +______<rdf:Description rdf:about=""^^J% +____________xmlns:xapMM="http://ns.adobe.com/xap/1.0/mm/">^^J% +_________<xapMM:DocumentID>\hyxmp@DocumentID</xapMM:DocumentID>^^J% +_________<xapMM:InstanceID>\hyxmp@InstanceID</xapMM:InstanceID>^^J% +______</rdf:Description>^^J% + }% +} +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Constructing the XMP packet} +% +% \begin{macro}{\hyxmp@construct@packet} +% \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. The \acro{XMP} +% specification~\cite{Adobe2005:XMP} states that the argument to the +% \xmpterm{begin} attribute must be ``the Unicode `zero-width +% non-breaking space character'~(U+FEFF)''. However, Adobe Acrobat~7.0 +% (the latest version at the time of this writing) inserts the sequence +% \meta{EF}\meta{BB}\meta{BF} so that's what we use here. +% +% We explicitly mark characters \meta{EF}, \meta{BB}, \meta{BF} as +% character code~12 (``letter'') because the \pkgname{inputenc} package +% re-encodes them as character code~13 (``active''), which causes +% \LaTeX\ to abort with an ``\texttt{Undefined control sequence}'' error +% upon invoking |\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} +% \begin{macrocode} +\bgroup +\catcode`\^^ef=12 +\catcode`\^^bb=12 +\catcode`\^^bf=12 +\gdef\hyxmp@construct@packet{% + \gdef\hyxmp@xml{}% + \hyxmp@add@to@xml{% +<?xpacket begin="^^ef^^bb^^bf" id="W5M0MpCehiHzreSzNTczkc9d"?>^^J% +<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="3.1-702">^^J% +___<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns\hyxmp@hash">^^J% + }% + \hyxmp@pdf@schema + \hyxmp@xapRights@schema + \hyxmp@dc@schema + \hyxmp@mm@schema + \hyxmp@add@to@xml{% +___</rdf:RDF>^^J% +</x:xmpmeta>^^J% +\hyxmp@padding +<?xpacket end="w"?>^^J% + }% +} +\egroup +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% \subsection{Embedding the XMP packet} +% +% The \acro{PDF} specification~\cite{Adobe2004:PDF} says that ``a +% metadata stream can be attached to a document through the +% \pdfterm{Metadata} entry in the document catalog'' so that's what we +% do here. \pkgname{hyperxmp} does not currently support the embedding +% of \acro{XMP} in any format other than \acro{PDF}. +% +% \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{hdvipdfm}% + \ifx\hyxmp@driver\Hy@driver + \hyxmp@embed@packet@dvipdfm + \else + \@ifundefined{pdfmark}{% + \PackageWarningNoLine{hyperxmp}{% + Unrecognized hyperref driver `\Hy@driver'.\MessageBreak + \jobname.tex's XMP metadata will *not* be\MessageBreak + embedded in the resulting file}% + }{% + \hyxmp@embed@packet@pdfmark + }% + \fi + \fi +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsubsection{Embedding using pdf\TeX} +% +% \begin{macro}{\hyxmp@embed@packet@pdftex} +% Embed the \acro{XMP} packet using pdf\TeX\ primitives. +% \begin{macrocode} +\newcommand*{\hyxmp@embed@packet@pdftex}{% + \bgroup + \pdfcompresslevel=0 + \immediate\pdfobj stream attr {% + /Type /Metadata + /Subtype /XML + }{\hyxmp@xml}% + \pdfcatalog {/Metadata \the\pdflastobj\space 0 R}% + \egroup +} +% \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 |dvipdf|, |dvipsone|, +% |dvips|, |dviwindo|, |nativepdf|, |pdfmark|, |ps2pdf| |textures|, and +% |vtexpdfmark| options to \pkgname{hyperref} but I've tested only a few +% of those. +% \begin{macrocode} +\newcommand*{\hyxmp@embed@packet@pdfmark}{% + \pdfmark{% + pdfmark=/OBJ, + Raw={/_objdef \string{hyxmp@Metadata\string} /type /stream}% + }% + \pdfmark{% + pdfmark=/PUT, + Raw={\string{hyxmp@Metadata\string}% + << + /Type /Metadata + /Subtype /XML + >> + }% + }% + \pdfmark{% + pdfmark=/PUT, + Raw={\string{hyxmp@Metadata\string} (\hyxmp@xml)}% + }% + \pdfmark{% + pdfmark=/CLOSE, + Raw={\string{hyxmp@Metadata\string}}% + }% +% \end{macrocode} +% Adobe's |pdfmark| reference~\cite{Adobe2005:pdfmark} indicates that a +% metadata stream can be added to the document catalog by specifying the +% \pdfterm{Metadata} |pdfmark| instead of the \pdfterm{PUT} |pdfmark|. +% I see no advantage to this alternative mechanism and, furthermore, it +% works only with Adobe Acrobat Distiller and only with versions~6.0 +% onwards. Consequently, \pkgname{hyperxmp} uses the traditional +% \pdfterm{PUT} mechanism to point the document catalog to our metadata +% stream. +% \begin{macrocode} + \pdfmark{% + pdfmark=/PUT, + Raw={\string{Catalog\string}% + << + /Metadata \string{hyxmp@Metadata\string}% + >> + }% + }% +} +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Embedding using \texttt{dvipdfm}} +% +% \begin{macro}{\hyxmp@embed@packet@dvipdfm} +% Embed the \acro{XMP} packet using a |dvipdfm|-specific |\special| command. +% Note that |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\@tempcnta + >> + stream^^J\hyxmp@xml endstream% + }% + \special{pdf: docview + << + /Metadata @hyxmp@Metadata + >> + }% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\hyxmp@string@len} +% Set |\@tempcnta| 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]{% + \@tempcnta=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\@tempcnta by -1 + \else + \advance\@tempcnta 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\@tempcnta by 1 + \expandafter\hyxmp@count@non@spaces + \fi +} +% \end{macrocode} +% \end{macro} +% +% \Finale +\endinput diff --git a/Master/texmf-dist/source/latex/hyperxmp/hyperxmp.ins b/Master/texmf-dist/source/latex/hyperxmp/hyperxmp.ins new file mode 100644 index 00000000000..82008a84a5f --- /dev/null +++ b/Master/texmf-dist/source/latex/hyperxmp/hyperxmp.ins @@ -0,0 +1,55 @@ +%% +%% Copyright (C) 2006 by Scott Pakin <scott+dtx@pakin.org> +%% +%% This file may be distributed and/or modified under the conditions of +%% the LaTeX Project Public License, either version 1.3b 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.3b or later is part of all distributions of LaTeX version +%% 2006/01/07 or later. +%% + +\input docstrip.tex +\keepsilent + +\usedir{tex/latex/hyperxmp} + +\preamble + +This is a generated file. + +Copyright (C) 2006 by Scott Pakin <scott+dtx@pakin.org> + +This file may be distributed and/or modified under the conditions of +the LaTeX Project Public License, either version 1.3b 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.3b or later is part of all distributions of LaTeX +version 2006/01/07 or later. + +\endpreamble + +\generate{\file{hyperxmp.sty}{\from{hyperxmp.dtx}{package}}} + +\obeyspaces +\Msg{*************************************************************} +\Msg{* *} +\Msg{* To finish the installation you have to move the following *} +\Msg{* file into a directory searched by TeX: *} +\Msg{* *} +\Msg{* hyperxmp.sty *} +\Msg{* *} +\Msg{* To produce the documentation run the file hyperxmp.dtx *} +\Msg{* through LaTeX. *} +\Msg{* *} +\Msg{* Happy TeXing! *} +\Msg{* *} +\Msg{*************************************************************} + +\endbatchfile |