From a1f11c0b253215e29345a70060ea16c46dd8536e Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Fri, 14 Sep 2012 00:35:00 +0000 Subject: hyperxmp (13sep12) git-svn-id: svn://tug.org/texlive/trunk@27663 c570f23f-e606-0410-a88d-b1316a301751 --- .../texmf-dist/source/latex/hyperxmp/einstein.png | Bin 0 -> 36422 bytes .../texmf-dist/source/latex/hyperxmp/hyperxmp.dtx | 1461 +++++++++++++------- 2 files changed, 977 insertions(+), 484 deletions(-) create mode 100644 Master/texmf-dist/source/latex/hyperxmp/einstein.png (limited to 'Master/texmf-dist/source/latex/hyperxmp') diff --git a/Master/texmf-dist/source/latex/hyperxmp/einstein.png b/Master/texmf-dist/source/latex/hyperxmp/einstein.png new file mode 100644 index 00000000000..661c3c6dfa0 Binary files /dev/null and b/Master/texmf-dist/source/latex/hyperxmp/einstein.png differ diff --git a/Master/texmf-dist/source/latex/hyperxmp/hyperxmp.dtx b/Master/texmf-dist/source/latex/hyperxmp/hyperxmp.dtx index 78dedace992..f1aa01b724e 100644 --- a/Master/texmf-dist/source/latex/hyperxmp/hyperxmp.dtx +++ b/Master/texmf-dist/source/latex/hyperxmp/hyperxmp.dtx @@ -22,13 +22,19 @@ %\NeedsTeXFormat{LaTeX2e}[1999/12/01] %\ProvidesPackage{hyperxmp} %<*package> - [2012/03/10 v1.5 Store hyperref metadata in XMP format] + [2012/09/10 v2.0 Store hyperref metadata in XMP format] % % %<*driver> +\bgroup + \catcode`\&=11 + \gdef\levelchar{&} +\egroup \documentclass{ltxdoc} \usepackage{graphicx} +\usepackage{color} \usepackage{tocbibind} +\usepackage{microtype} \usepackage{hyperxmp} \usepackage[bookmarksopen,bookmarksopenlevel=2,pdflang=en]{hyperref} \EnableCrossrefs @@ -36,13 +42,21 @@ \RecordChanges \begin{document} \DocInput{hyperxmp.dtx} + \phantomsection\addcontentsline{toc}{section}{Change History} \PrintChanges + \makeatletter + \let\orig@index@prologue=\index@prologue + \def\index@prologue{% + \phantomsection\addcontentsline{toc}{section}{Index} + \orig@index@prologue + }% + \makeatother \PrintIndex \end{document} % % \fi % -% \CheckSum{898} +% \CheckSum{1200} % % \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 @@ -62,6 +76,11 @@ % % % \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} % % \GetFileInfo{hyperxmp.dtx} % @@ -91,6 +110,7 @@ % \DeclareRobustCommand{\xmpterm}[1]{\mbox{\textsf{#1}}\SortIndex{#1}{\textsf{#1}}} % \DeclareRobustCommand{\pdfterm}[1]{\mbox{\textsf{#1}}\SortIndex{#1}{\textsf{#1}}} % \DeclareRobustCommand{\cmdname}[1]{\mbox{\texttt{#1}}\SortIndex{#1}{\texttt{#1}}} +% \DeclareRobustCommand{\optname}[1]{\mbox{\texttt{#1}}\SortIndex{#1}{\textsf{#1} (option)}} % \DeclareRobustCommand{\acrostyle}[1]{\textsc{\MakeLowercase{#1}}} % \DeclareRobustCommand{\acro}[1]{^^A % \mbox{\acrostyle{#1}}^^A @@ -98,6 +118,9 @@ % } % % ^^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 % } @@ -110,6 +133,28 @@ % \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 +% } +% +% ^^A Pack figures a bit tighter onto the page. +% \renewcommand{\floatpagefraction}{0.8} % % ^^A Specify this document's metadata. % \title{The \pkgname{hyperxmp} package\thanks{This document @@ -151,16 +196,16 @@ % 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. +% 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: +% 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} % @@ -181,10 +226,10 @@ % 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 applications to identify and categorize the -% document. +% 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 all of the following types of @@ -192,15 +237,21 @@ % % \begin{itemize} % \item authors (\xmpterm{dc:creator}) -% \item copyright (\xmpterm{dc:rights}) -% \item date (\xmpterm{dc:date}) +% \item base \acro{URL} (\xmpterm{xmp:BaseURL}) +% \item copyright (\xmpterm{dc:rights} and \xmpterm{xmpRights:Marked}) +% \item date (\xmpterm{dc:date}, \xmpterm{xmp:CreateDate}, +% \xmpterm{xmp:ModifyDate}, and \xmpterm{xmp:MetadataDate}) % \item document identifier (\xmpterm{xmpMM:DocumentID}) % \item document instance identifier (\xmpterm{xmpMM:InstanceID}) -% \item format (\xmpterm{dc:format}) -% \item keywords (\xmpterm{pdf:Keyword} and \xmpterm{dc:subject}) +% \item file format (\xmpterm{dc:format}) +% \item keywords (\xmpterm{pdf:Keywords} and \xmpterm{dc:subject}) +% \item language (\xmpterm{dc:language}) +% \item \LaTeX\ file name (\xmpterm{dc:source}) % \item license \acro{URL} (\xmpterm{xmpRights:WebStatement}) % \item metadata writer (\xmpterm{photoshop:CaptionWriter}) -% \item \acro{PDF}-generating tool (\xmpterm{pdf:Producer}) +% \item \acro{PDF}-generating tool (\xmpterm{pdf:Producer} and +% \xmpterm{xmp:CreatorTool}) +% \item \acro{PDF} version (\xmpterm{pdf:PDFVersion}) % \item primary author's position/title (\xmpterm{photoshop:AuthorsPosition}) % \item summary (\xmpterm{dc:description}) % \item title (\xmpterm{dc:title}) @@ -219,7 +270,7 @@ % 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 +% \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. % @@ -232,19 +283,20 @@ % % \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: +% \pkgname{hyperxmp} works by postprocessing 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 |pdflang| -% \item |pdfproducer| -% \item |pdfsubject| -% \item |pdftitle| +% \item \optname{baseurl} +% \item \optname{pdfauthor} +% \item \optname{pdfkeywords} +% \item \optname{pdflang} +% \item \optname{pdfproducer} +% \item \optname{pdfsubject} +% \item \optname{pdftitle} % \end{itemize} % % \noindent @@ -252,30 +304,31 @@ % following options, which have meaning only to \pkgname{hyperxmp}: % % \begin{itemize} -% \item |pdfauthortitle| -% \item |pdfcaptionwriter| -% \item |pdfcopyright| -% \item |pdflicenseurl| -% \item |pdfmetalang| +% \item \optname{pdfauthortitle} +% \item \optname{pdfcaptionwriter} +% \item \optname{pdfcopyright} +% \item \optname{pdflicenseurl} +% \item \optname{pdfmetalang} % \end{itemize} % % \noindent -% |pdfauthortitle| indicates the primary author's position or title. -% |pdfcaptionwriter| specifies the name of the person who added -% the metadata to the document. |pdfcopyright| defines the copyright -% text. |pdflicenseurl| identifies a \acro{URL} that points to the -% document's license agreement. |pdfmetalang| indicates the natural -% language in which the metadata is written, typically as 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 |pdfmetalang| is not specified, +% \optname{pdfauthortitle} indicates the primary author's position or +% title. \optname{pdfcaptionwriter} specifies the name of the person +% who added the metadata to the document. \optname{pdfcopyright} +% defines the copyright text. \optname{pdflicenseurl} identifies a +% \acro{URL} that points to the document's license agreement. +% \optname{pdfmetalang} indicates the natural language in which the +% metadata is written, typically as 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 |pdflang| option). If neither -% |pdfmetalang| nor |pdflang| is specified, \pkgname{hyperxmp} uses only -% ``|x-default|'' as the metadata language. Note that ``|x-default|'' -% metadata is always included in addition to the specified metadata -% language, as the user reading the document may not have specified a -% language preference. +% document language (\pkgname{hyperref}'s \optname{pdflang} option). If +% neither \optname{pdfmetalang} nor \optname{pdflang} is specified, +% \pkgname{hyperxmp} uses only ``|x-default|'' as the metadata language. +% Note that ``|x-default|'' metadata is always included in addition to +% the specified metadata language, as the user reading the document may +% not have specified a language preference. % % It is usually more convenient to provide values for those options using % \pkgname{hyperref}'s |\hypersetup| command than on the |\usepackage| @@ -298,10 +351,14 @@ % On a heuristic viewpoint concerning the production and % transformation of light}, % pdfauthor={Albert Einstein}, +% pdfauthortitle={Technical Assistant, Level III}, % pdfcopyright={Copyright (C) 1905, Albert Einstein}, % pdfsubject={photoelectric effect}, % pdfkeywords={energy quanta, Hertz effect, quantum physics}, -% pdflang={en} +% pdflicenseurl={http://creativecommons.org/licenses/by-nc-nd/3.0/}, +% pdfcaptionwriter={Scott Pakin}, +% pdflang={en}, +% baseurl={http://www.ctan.org/tex-archive/macros/latex/contrib/hyperxmp/} % } % \begin{document} % \maketitle @@ -312,51 +369,65 @@ % \end{document} % \end{verbatim} % -% Compile the document to \acro{PDF} using any of the following approaches: +% Compile the document to \acro{PDF} using any of the following +% approaches: % % \begin{itemize} -% \item pdf\LaTeX -% \item Lua\LaTeX +% \item \pdfLaTeX +% \item \LuaLaTeX % \item \LaTeX~$+$ Dvipdfm -% \item \LaTeX~$+$ Dvips~$+$ Ghostscript -% \item \LaTeX~$+$ Dvips~$+$ Adobe Acrobat Distiller +% \item \LaTeX~$+$ \Dvips~$+$ Adobe Acrobat Distiller % \item \XeLaTeX % \end{itemize} % -% Besides the approaches listed above, other approaches may work as well -% but have not been tested. Note that in many \TeX\ distributions -% \cmdname{ps2pdf} is a convenience script that calls Ghostscript with -% the appropriate options for converting PostScript to \acro{PDF} and -% \cmdname{dvipdf} is a convenience script that calls \cmdname{dvips} -% and \cmdname{ps2pdf}; both \cmdname{ps2pdf} and \cmdname{dvipdf} -% should be compatible with \pkgname{hyperxmp}. +% \noindent +% Unfortunately, the \LaTeX~$+$ \Dvips~$+$ \term{Ghostscript} path +% doesn't work. +% \href{http://bugs.ghostscript.com/show_bug.cgi?id=690066}{Ghostscript +% bug report~\#690066}, closed with ``\textsc{wontfix}'' status on +% 2012-05-28, explains that \term{Ghostscript} doesn't honor the +% \pdfterm{Metadata} tag needed to inject a custom \acro{XMP} packet. +% Instead, \term{Ghostscript} fabricates an \acro{XMP} packet of its own +% based on the metadata it finds in the \acro{PDF} file's \pdfterm{Info} +% dictionary (\pdfterm{Author}, \pdfterm{Title}, \pdfterm{Subject}, and +% \pdfterm{Keywords}). % % \bigskip % -% The resulting \acro{PDF} file will contain an \acro{XMP} packet that -% looks something like this: +% Once the document is compiled, the resulting \acro{PDF} file +% will contain an \acro{XMP} packet that looks something like this: % % \begin{verbatim} -% +% % % % -% energy quanta, Hertz effect, -% quantum physics -% pdfeTeX-1.10b +% +% energy quanta, Hertz effect, quantum physics +% +% pdfTeX-1.40.10 +% +% +% True +% +% http://creativecommons.org/licenses/by-nc-nd/3.0/ +% % % % application/pdf % % -% On a heuristic viewpoint -% concerning the production and transformation of -% light -% On a heuristic viewpoint -% concerning the production and transformation of -% light +% +% On a heuristic viewpoint concerning the production and +% transformation of light +% +% +% On a heuristic viewpoint concerning the production and +% transformation of light +% % % % @@ -367,10 +438,12 @@ % % % -% Copyright (C) 1905, -% Albert Einstein -% Copyright (C) 1905, -% Albert Einstein +% +% Copyright (C) 1905, Albert Einstein +% +% +% Copyright (C) 1905, Albert Einstein +% % % % @@ -387,21 +460,51 @@ % % % -% 2006-04-19 +% 2012-08-26 % % +% en +% einstein.tex +% +% +% +% Technical Assistant, Level III +% +% Scott Pakin +% +% +% 2012-08-26 +% 2012-08-26 +% 2012-08-26 +% LaTeX with hyperref package +% +% http://www.ctan.org/tex-archive/macros/latex/contrib/hyperxmp/ +% % % -% uuid:c4188820-aef2-0a82-626ce4182b62 -% uuid:9b62b67f-d754-626c-4c959595fd75 +% uuid:0595fdce-41dc-e4c4-6c418dc4ce46 +% uuid:efd754c4-1d7f-200a-ef754ce413ea % % % % % \end{verbatim} % +% \noindent +% Figure~\ref{fig:xmp-metadata} is a screenshot of the preceding packet +% as it appears in Adobe Acrobat's ``Advanced'' metadata dialog box. +% +% \begin{figure}[htbp] +% \includegraphics[width=\linewidth]{einstein} +% \caption{\acro{XMP} metadata as it appears in Adobe Acrobat} +% \label{fig:xmp-metadata} +% \end{figure} +% % \paragraph{Note~1: Acrobat \pdfterm{Author} bug} +% \label{page:author-bug} % A bug in Adobe Acrobat---at least in versions~10.0.1 and % earlier---causes that \acro{PDF} reader to confuse the \acro{XMP} and % non-\acro{XMP} author lists when displaying the document's metadata. @@ -415,22 +518,21 @@ % leaves ``Edward Nigma'' and ``Harvey Dent'' as the second and third % authors, respectively. % -% A workaround, independent of \TeX, is to modify the \acro{PDF} file to -% remove all but the first author from the non-\acro{XMP} author list -% while retaining all of the authors in the \acro{XMP} author list. -% Doing so will cause Adobe Acrobat to properly display all of the -% authors but at the cost of other \acro{PDF} readers likely displaying -% only the first author. The following Perl command (which should be -% entered as a single line) automates this modification: +% \DescribeMacro{\XMPTruncateList} +% The \pkgname{hyperxmp} package provides a workaround for this bug in +% the form of the |\XMPTruncateList| macro. |\XMPTruncateList| takes +% the name of a list (a \pkgname{hyperref} option name) and replaces the +% list with the value of its first element. Currently, the only +% meaningful usage is to put % % \begin{verbatim} -% perl -i -ne 's,(/Author\s*\([^\,\)]+)(.*?)\),"$1)" . " " x length($2),ge; -% print' myfile.pdf +% \XMPTruncateList{pdfauthor} % \end{verbatim} % % \noindent -% (Systems with different quoting conventions from Linux/Unix may need -% to adapt the preceding commands as appropriate.) +% in your document's preamble. This will cause Adobe Acrobat to +% properly display all of the authors but at the cost of other +% \acro{PDF} readers likely displaying only the first author. % % % \paragraph{Note~2: \XeLaTeX\ object compression} @@ -438,47 +540,58 @@ % 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. Either use a different program -% (e.g.,~Lua\LaTeX) or use \XeLaTeX\ to produce a \acro{DVI} or -% \acro{XDV} file and run \cmdname{xdvipdfmx} manually on that file -% using the |-z0| option to turn off all compression (which will of -% course make the \acro{PDF} file substantially larger). +% 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. % % % \paragraph{Note~3: Literal commas} -% \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: +% \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, and Harvey Dent}| -% \item[Wrong:] |pdfauthor={Jack Napier; Edward Nigma; Harvey Dent}| +% \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} % -% 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: +% \DescribeMacro{\xmpcomma} +% If you need to include a comma within an author or keyword list, use +% the |\xmpcomma| macro to represent it, and wrap the entire entry +% containing the comma within |\xmpquote{|\dots|}| as shown below: % % \begin{verbatim} -% pdfauthor={Napier\mycomma\ Jack, -% Nigma\mycomma\ Edward, -% Dent\mycomma\ Harvey} +% pdfauthor={\xmpquote{Jack Napier\xmpcomma\ Jr.}, +% \xmpquote{Edward Nigma\xmpcomma\ PhD}, +% \xmpquote{Harvey Dent\xmpcomma\ Esq.}} % \end{verbatim} % % % \StopEventually{^^A +% \section{Future Work} +% \label{sec:future-work} +% +% \paragraph{Help wanted} +% 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. +% % \begin{thebibliography}{1} % \bibitem{Adobe2010:pdfmark} % Adobe Systems, Inc., San Jose, California. @@ -486,6 +599,11 @@ % \newblock Available from % \url{http://www.adobe.com/devnet/acrobat/documentation.html}. % +% \bibitem{Adobe1996:postscript} +% {Adobe Systems, Inc.} +% \newblock {\em {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 {\em Document Management---Portable Document Format---Part 1: @@ -550,7 +668,7 @@ % \begin{macro}{\hyxmp@at@end} % \begin{macro}{\hyxmp@driver} % The |\hyxmp@at@end| macro includes code at the end of the document. -% For pdf\TeX, the standard |\AtEndDocument| works well enough. For all +% For \pdfTeX, the standard |\AtEndDocument| works well enough. For all % the other backends we use |\AtEndDvi| from the \pkgname{atenddvi} % package, which is more robust but requires an addition \LaTeX\ run. % \begin{macrocode} @@ -571,26 +689,31 @@ % 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 -% \pkgname{hyperref}'s |pdftitle|, |pdfauthor|, |pdfsubject|, -% |pdfkeywords|, and |pdflang| options. It also introduces five new -% options: |pdfcopyright|, |pdflicenseurl|, |pdfauthortitle|, -% |pdfcaptionwriter|, and |pdfmetalang|. 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|. +% \pkgname{hyperref}'s \optname{pdftitle}, \optname{pdfauthor}, +% \optname{pdfsubject}, \optname{pdfkeywords}, and \optname{pdflang} +% options. It also introduces five new options: \optname{pdfcopyright}, +% \optname{pdflicenseurl}, \optname{pdfauthortitle}, +% \optname{pdfcaptionwriter}, and \optname{pdfmetalang}. 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 three helper packages: \pkgname{keyval} for package-option -% processing and \pkgname{pdfescape} and \pkgname{stringenc} for -% re-encoding Unicode strings. +% 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), and +% \pkgname{ifxetex} for detecting \XeTeX. % % \begin{macrocode} -\RequirePackage{keyval} +\RequirePackage{kvoptions} \RequirePackage{pdfescape} \RequirePackage{stringenc} +\RequirePackage{intcalc} +\RequirePackage{ifxetex} % \end{macrocode} % % \begin{macro}{\@pdfcopyright} @@ -636,20 +759,147 @@ % \end{macrocode} % \end{macro} % +% \begin{macro}{\hyxmp@ProcessKeyvalOptions} +% \changes{v2.0}{2012/09/05}{Added this macro} +% \begin{macro}{\ProcessKeyvalOptions} +% \changes{v2.0}{2012/09/05}{Added this macro} +% 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. +% \begin{macrocode} +\let\hyxmp@ProcessKeyvalOptions=\ProcessKeyvalOptions +\renewcommand*{\ProcessKeyvalOptions}{% +% \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} +% \begin{macro}{\KV@Hyp@pdfauthor} +% \begin{macro}{\xmpcomma} +% \begin{macro}{\xmpquote} +% \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). +% \begin{macrocode} + \define@key{Hyp}{pdfauthor}{% + \let\xmpcomma=\hyxmp@comma + \def\xmpquote####1{####1}% + \hyxmp@Hyp@pdfauthor{##1}% + \global\let\hyxmp@pdfauthor=\@pdfauthor + \def\xmpcomma{,}% + \def\xmpquote####1{"####1"}% + \hyxmp@Hyp@pdfauthor{##1}% + \let\xmpcomma=\relax + \let\xmpquote=\relax + }% +% \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}% + \let\xmpcomma=\relax + \let\xmpquote=\relax + }% +% \end{macrocode} +% Process the calling package's options as normal but with the preceding +% substitutions. +% \begin{macrocode} + \hyxmp@ProcessKeyvalOptions +} +% \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} +% % \begin{macro}{\hyxmp@find@metadata} % \begin{macro}{\hyxmp@concated@metadata} % Issue a warning message if the author failed to include any metadata -% at all. Note that we don't consider |\@pdflang| or |\@pdfmetalang| as -% metadata, as they're meaningful only when used in conjunction with -% other information. +% at all. Note that we don't consider |\@pdfmetalang| as metadata as +% that value is meaningful only when used in conjunction with other +% information. % \begin{macrocode} \newcommand*{\hyxmp@find@metadata}{% \edef\hyxmp@concated@metadata{% + \@baseurl \@pdfauthor \@pdfauthortitle \@pdfcaptionwriter \@pdfcopyright \@pdfkeywords + \@pdflang \@pdflicenseurl \@pdfsubject \@pdftitle @@ -673,28 +923,26 @@ metadata values to hyperxmp}% % preamble, not just before \pkgname{hyperxmp} is loaded. % \begin{macrocode} \AtBeginDocument{% - \@ifpackageloaded{hyperref}% - {% + \@ifpackageloaded{hyperref}{% % \end{macrocode} % If the user explicitly specified the language to use for the % document's metadata, we use that. If not, we use the document -% language, specified to \pkgname{hyperref} with the |pdflang| option. -% If the author did not specify a language, we use |x-default| as the -% metadata language. +% language, specified to \pkgname{hyperref} with the \optname{pdflang} +% option. If the author did not specify a language, we use |x-default| +% as the metadata language. % \changes{v1.3}{2011/04/25}{Introduced the \texttt{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 +% \texttt{\string\string\string\AtBeginDocument} code from Heiko +% Oberdiek to properly encode \texttt{\string\string\string\@pdfmetalang}} % \begin{macrocode} - \ifx\@pdfmetalang\@empty - \ifx\@pdflang\@empty - \let\@pdfmetalang=\hyxmp@x@default - \else - \edef\@pdfmetalang{\@pdflang}% - \fi - \fi - \ifHy@unicode - \hyxmp@reencode\@pdfmetalang - \fi + \ifx\@pdflang\@empty + \let\@pdfmetalang=\hyxmp@x@default + \else + \edef\@pdfmetalang{\@pdflang}% + \fi + \hyxmp@xmlify\@pdfmetalang % \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 @@ -724,12 +972,10 @@ disabled}% % |\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}); 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 || to -% |<scott+hyxmp@pakin.org>|). +% can be more easily manipulated (Section~\ref{sec:list-manip}); 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 +% || to |<scott+hyxmp@pakin.org>|). % % \subsubsection{List manipulation} % \label{sec:list-manip} @@ -771,75 +1017,73 @@ disabled}% % \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{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 |\relax| to prevent +% it from expanding to either prematurely. +% \changes{v2.0}{2012/08/25}{Added this macro} % \begin{macrocode} -\bgroup -\catcode`\&=11 -\gdef\hyxmp@xml@amp{&} -\global\let\hyxmp@other@amp=& -\gdef\hyxmp@amp{&} +\let\xmpcomma=\relax % \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{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} -\catcode`\<=11 -\gdef\hyxmp@xml@lt{<} -\global\let\hyxmp@other@lt=< +\bgroup +\catcode`\^^C=11 +\gdef\hyxmp@comma{^^C} +\egroup % \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{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} -\catcode`\>=11 -\gdef\hyxmp@xml@gt{>} -\global\let\hyxmp@other@gt=> +\let\xmpquote=\relax % \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= } % +% \begin{macro}{\XMPTruncateList} +% \changes{v2.0}{2012/09/07}{Added this macro} +% \begin{macro}{\hyxmp@temp@str} +% \begin{macro}{\hyxmp@temp@list} +% \begin{macro}{\@elt} +% As a workaround for Adobe Acrobat's inability to display author lists +% correctly (cf.~``Acrobat \pdfterm{Author} bug'' on +% page~\pageref{page:author-bug}) 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. It's sad that this is necessary, though. +% \begin{macrocode} +\newcommand{\XMPTruncateList}[1]{% + \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} -% -% \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} +% \end{macro} +% % % \subsubsection{Trimming leading and trailing spaces} % \label{sec:trim-spaces} @@ -912,33 +1156,55 @@ disabled}% % 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}{\hyxmp@reencode} +% This is now a placeholder macro needed only for |\@pdfmetalang| in +% the |\begin{document}|. % \changes{v1.3}{2011/04/25}{Introduced this macro to re-encode Unicode % strings as 8-bit strings before manipulating them into \acro{XMP} % schema. This change addresses a bug reported by Martin M\"unch} -% \begin{macro}{\hyxmp@reencoded} -% Given a control word that expands to a Unicode (|utf16be|) string, -% re-encode it in a more basic (|pdfdoc|) 8-bit encoding so we don't -% wind up escaping each octet of what should be a single 16-bit -% character. The bulk of the work is left to |\EdefUnescapeString| from -% the \pkgname{pdfescape} package and |\StringEncodingConvert| and to -% |\StringEncodingSuccessFailure| from the \pkgname{stringenc} package. -% \begin{macrocode} -\newcommand*{\hyxmp@reencode}[1]{% - \EdefUnescapeString\hyxmp@reencoded{#1}% - \StringEncodingConvert\hyxmp@reencoded\hyxmp@reencoded{utf16be}{pdfdoc}% - \StringEncodingSuccessFailure{% - \global\let\hyxmp@reencoded=\hyxmp@reencoded - }{% - \gdef\hyxmp@reencoded{#1}% - }% - \edef#1{\hyxmp@reencoded}% -} +% \changes{v2.0}{2012/08/02}{Replaced with an empty macro by Heiko Oberdiek} +% \begin{macrocode} +\newcommand*{\hyxmp@reencode}[1]{} % \end{macrocode} % \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}{\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 @@ -946,201 +1212,349 @@ disabled}% % |\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 -% \cmdname{dvips} on the resulting \acro{DVI} file and \cmdname{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{}% - \edef\hyxmp@text{#1}% - \ifHy@unicode - \hyxmp@reencode\hyxmp@text - \fi - \expandafter\hyxmp@xmlify@i\hyxmp@text\@empty - \@ifundefined{pdfmark}{}{% - \expandafter\hyxmp@obscure@spaces\expandafter{\hyxmp@xmlified}% - }% -} % \end{macrocode} -% \end{macro} -% \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|. +% Escaped PDF string~$\rightarrow$ \term{PDFDocEncoding}/\term{Unicode} % \begin{macrocode} -\def\hyxmp@xmlify@i{\futurelet\hyxmp@one@token\hyxmp@xmlify@ii} + \EdefUnescapeString\hyxmp@text{#1}% + \ifhyxmp@unicodetex % \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. +% \term{PDFDocEncoding}/\term{Unicode}~$\rightarrow$ \acro{UTF-32BE} % \begin{macrocode} -\def\hyxmp@xmlify@ii{% - \if\hyxmp@one@token\hyxmp@other@lt + \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} -% Replace ``|<|'' with |<|. +% \acro{UTF-32BE}~$\rightarrow$ \acro{UTF-32BE} as hex string % \begin{macrocode} - \def\next##1{% - \xdef\hyxmp@xmlified{\hyxmp@xmlified\hyxmp@xml@lt}% - \hyxmp@xmlify@i - }% - \else - \if\hyxmp@one@token\hyxmp@other@gt + \EdefEscapeHex\hyxmp@text{\hyxmp@text}% % \end{macrocode} -% Replace ``|>|'' with |>|. +% \acro{UTF-32BE}~$\rightarrow$ \acro{XML} in \acro{ASCII} % \begin{macrocode} - \def\next##1{% - \xdef\hyxmp@xmlified{\hyxmp@xmlified\hyxmp@xml@gt}% - \hyxmp@xmlify@i - }% - \else - \if\hyxmp@one@token\hyxmp@other@amp + \edef\hyxmp@text{% + \expandafter + }\expandafter\hyxmp@toxml@unicodetex\hyxmp@text + \relax\relax\relax\relax\relax\relax\relax\relax + \else % \end{macrocode} -% Replace ``|&|'' with |&|. +% \term{PDFDocEncoding}/\term{Unicode}~$\rightarrow$ \acro{UTF-8} % \begin{macrocode} - \def\next##1{% - \xdef\hyxmp@xmlified{\hyxmp@xmlified\hyxmp@xml@amp}% - \hyxmp@xmlify@i - }% - \else - \ifx\hyxmp@one@token\hyxmp@other@space + \hyxmp@is@unicode\hyxmp@text{% + \StringEncodingConvert + \hyxmp@text\hyxmp@text{utf16be}{utf8}% + }{% + \StringEncodingConvert + \hyxmp@text\hyxmp@text{pdfdoc}{utf8}% + }% % \end{macrocode} -% Store spaces. We need a special case for this to avoid inadvertently -% discarding spaces. +% \acro{UTF-8}~$\rightarrow$ \acro{UTF-8} as hex string % \begin{macrocode} - \def\next##1{% - \g@addto@macro\hyxmp@xmlified{ }% - \hyxmp@xmlify@i##1% - }% - \else - \if\hyxmp@one@token\hyxmp@other@bs + \EdefEscapeHex\hyxmp@text{\hyxmp@text}% % \end{macrocode} -% Replace |\|\meta{ooo} with |&#|\meta{ddd}|;|. For example, |\100|, -% the octal code for ``|@|'', is represented in \acro{XML} as~|@|. +% \acro{UTF-8} as hex string~$\rightarrow$ \acro{XML} in \acro{UTF-8} +% as hex string % \begin{macrocode} - \def\next##1{\futurelet\hyxmp@one@token\hyxmp@xmlify@iii} - \else - \ifx\hyxmp@one@token\@empty + \edef\hyxmp@text{% + \expandafter\hyxmp@toxml\hyxmp@text\@empty\@empty + }% % \end{macrocode} -% End the recursion upon encountering |\@empty|. +% \acro{XML} in \acro{UTF-8} as hex string~$\rightarrow$ \acro{XML} +% in \acro{UTF-8} % \begin{macrocode} - \def\next##1{}% - \else + \EdefUnescapeHex\hyxmp@text{\hyxmp@text}% + \fi + \global\let\hyxmp@xmlified\hyxmp@text +} % \end{macrocode} -% In most cases we merely append the next character in the input to -% |\hyxmp@xmlified| without any special processing. +% \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} - \def\next##1{% - \g@addto@macro\hyxmp@xmlified{##1}% - \hyxmp@xmlify@i - }% - \fi - \fi - \fi - \fi +\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 +% \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} -% Recursively process the next character in the input stream. +% \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} - \next +\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@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;% +% \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 }% - \hyxmp@xmlify@i - }% - \if\hyxmp@one@token( - \let\next=\hyxmp@xmlify@i - \else - \if\hyxmp@one@token) - \let\next=\hyxmp@xmlify@i + \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 - \fi - \next + }% } +\x{ } % \end{macrocode} % \end{macro} % \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} % -% \begin{macro}{\hyxmp@obscure@spaces} -% The \cmdname{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 \xmpterm{dc:rights} -% (copyright notice) within a single-line field. By introducing an -% extra line break in the middle of the copyright notice, -% \cmdname{dvips} implicitly causes it to be truncated when displayed. +% \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} % -% To thwart \cmdname{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{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} -\newcommand*{\hyxmp@obscure@spaces}[1]{% - \gdef\hyxmp@xmlified{}% - \expandafter\hyxmp@obscure@spaces@i#1 {} % +\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@obscure@spaces@i} -% \begin{macro}{\hyxmp@one@token} -% \begin{macro}{\next} -% Do all of the work for |\hyxmp@obscure@spaces|. +% \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@obscure@spaces@i #1 #2 {% - \def\hyxmp@one@token{#2}% - \ifx\hyxmp@one@token\@empty - \xdef\hyxmp@xmlified{\hyxmp@xmlified#1}% - \let\next=\relax +\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 - \xdef\hyxmp@xmlified{\hyxmp@xmlified#1\hyxmp@amp\hyxmp@hash32;}% - \def\next{\expandafter\hyxmp@obscure@spaces@i\expandafter#2 }% + \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 - \next } % \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} +% % % \subsection{UUID generation} % \label{sec:uuid-gen} % % 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} +% implement in \tex\ and is good enough for producing the \acro{XMP} % \xmpterm{xmpMM:DocumentID} and \xmpterm{xmpMM:InstanceID} fields. % % \begin{macro}{\hyxmp@modulo@a} @@ -1159,7 +1573,7 @@ disabled}% % \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. +% \tex\ counter. % \begin{macrocode} \def\hyxmp@big@prime{536870923} \def\hyxmp@big@prime@ii{536870027} @@ -1350,7 +1764,9 @@ disabled}% % % \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. +% (``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} % \begin{macrocode} \newcommand*{\hyxmp@add@to@xml}[1]{% \bgroup @@ -1361,6 +1777,7 @@ disabled}% \ifnum\@tempcnta<256 \repeat \lccode`\_=`\ \relax + \lccode`\^^C=`\,\relax \lowercase{\xdef\hyxmp@xml{\hyxmp@xml#1}}% \egroup } @@ -1457,20 +1874,11 @@ __________________________________________________^^J% ______^^J% }% - \ifx\@pdfkeywords\@empty - \else - \hyxmp@xmlify{\@pdfkeywords}% - \hyxmp@add@to@xml{% -___________\hyxmp@xmlified^^J% - }% - \fi - \ifx\@pdfproducer\@empty - \else - \hyxmp@xmlify{\@pdfproducer}% - \hyxmp@add@to@xml{% -___________\hyxmp@xmlified^^J% - }% - \fi + \hyxmp@add@simple{pdf:Keywords}{\@pdfkeywords}% + \hyxmp@add@simple{pdf:Producer}{\@pdfproducer}% + \@ifundefined{pdfminorversion}{}{% + \hyxmp@add@simple{pdf:PDFVersion}{1.\the\pdfminorversion}% + }% \hyxmp@add@to@xml{% ______^^J% }% @@ -1480,6 +1888,29 @@ ______^^J% % \end{macro} % \end{macro} % +% \begin{macro}{\hyxmp@add@simple} +% \begin{macro}{\hyxmp@string} +% 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} +% \begin{macrocode} +\newcommand*{\hyxmp@add@simple}[2]{% + \edef\hyxmp@string{#2}% + \ifx\hyxmp@string\@empty + \else + \hyxmp@xmlify{\hyxmp@string}% + \hyxmp@add@to@xml{% +_________<#1>\hyxmp@xmlified^^J% + }% + \fi +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% % \subsubsection{The Dublin Core schema} % \label{sec:dublin-core} % @@ -1518,6 +1949,8 @@ _________^^J% % 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. +% \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}[3]{% \ifx#3\@empty @@ -1528,22 +1961,16 @@ ____________^^J% }% \bgroup % \end{macrocode} -% \begin{macro}{\hyxmp@text} % \begin{macro}{\@elt} -% We store the comma-separated list in |\hyxmp@text| so we can re-encode -% it from Unicode if necessary. We then redefine |\@elt| to -% \acro{XML}-ify each element of the list and append it to +% 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} - \edef\hyxmp@text{#3}% - \ifHy@unicode - \hyxmp@reencode\hyxmp@text - \fi - \hyxmp@commas@to@list\hyxmp@list{\hyxmp@text}% + \hyxmp@xmlify{#3}% + \hyxmp@commas@to@list\hyxmp@list{\hyxmp@xmlified}% \def\@elt##1{% - \hyxmp@xmlify{##1}% \hyxmp@add@to@xml{% -_______________\hyxmp@xmlified^^J% +_______________##1^^J% }% }% \hyxmp@list @@ -1557,18 +1984,23 @@ _________^^J% % \end{macrocode} % \end{macro} % \end{macro} -% \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{dc:title} property -% if the author specified a |pdftitle|, the \xmpterm{dc:description} -% property if the author specified a |pdfsubject|, the \xmpterm{dc:rights} -% property if the author specified a |pdfcopyright|, the -% \xmpterm{dc:creator} property if the author specified a |pdfauthor|, and -% the \xmpterm{dc:subject} property if the author specified |pdfkeywords|. -% We also specify the \xmpterm{dc:date} property using the date the -% document was run through \LaTeX. +% macro. Specifically, we add entries for the \xmpterm{dc:title} +% property if the author specified a \optname{pdftitle}, the +% \xmpterm{dc:description} property if the author specified a +% \optname{pdfsubject}, the \xmpterm{dc:rights} property if the author +% specified a \optname{pdfcopyright}, the \xmpterm{dc:creator} property +% if the author specified a \optname{pdfauthor}, the +% \xmpterm{dc:subject} property if the author specified +% \optname{pdfkeywords}, and the \xmpterm{dc:language} property if the +% author specified \optname{pdflang}. We also specify the +% \xmpterm{dc:date} property using the date the document was run through +% \LaTeX\ and the \xmpterm{dc:source} property using the base name of +% the source file with |.tex| appended. +% \changes{v2.0}{2012/08/26}{Added support for \xmpterm{dc:language} +% and \xmpterm{dc:source}} % \begin{macrocode} \newcommand*{\hyxmp@dc@schema}{% \hyxmp@add@to@xml{% @@ -1579,9 +2011,11 @@ _________application/pdf^^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{creator}{Seq}{\hyxmp@pdfauthor}% + \hyxmp@list@to@xml{subject}{Bag}{\hyxmp@pdfkeywords}% \hyxmp@list@to@xml{date}{Seq}{\hyxmp@today}% + \hyxmp@add@simple{dc:language}{\@pdflang}% + \hyxmp@add@simple{dc:source}{\jobname.tex}% \hyxmp@add@to@xml{% ______^^J% }% @@ -1596,26 +2030,71 @@ ______^^J% % Add properties defined by the XMP Rights Management schema to the % |\hyxmp@xml| macro. Currently, these are only the % \xmpterm{xmpRights:Marked} property and the -% \xmpterm{xmpRights:WebStatement} property and only if the author -% defined a |pdflicenseurl|. +% \xmpterm{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 +% \xmpterm{xmpRights:Marked} only when \optname{pdfcopyright} is +% specified and \xmpterm{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 - \hyxmp@xmlify{\@pdflicenseurl}% + \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 +% \end{macrocode} +% Header +% \begin{macrocode} \hyxmp@add@to@xml{% ______^^J% + }% +% \end{macrocode} +% Copyright indication +% \begin{macrocode} + \ifx\@pdfcopyright\@empty + \else + \hyxmp@add@to@xml{% _________True^^J% -_________\hyxmp@xmlified^^J% + }% + \fi +% \end{macrocode} +% License \acro{URL} +% \begin{macrocode} + \hyxmp@add@simple{xmpRights:WebStatement}{\@pdflicenseurl}% +% \end{macrocode} +% Trailer +% \begin{macrocode} + \hyxmp@add@to@xml{% ______^^J% }% \fi } % \end{macrocode} % \end{macro} +% \end{macro} +% % % \subsubsection{The XMP Media Management schema} % \label{sec:xmp-media} @@ -1627,7 +2106,7 @@ ______^^J% % document, and the \xmpterm{xmpMM:InstanceID} property is supposed to % change with each save operation~\cite{Adobe2010:XMP}. As seen in % Section~\ref{sec:uuid-gen}, we do what we can to honor this intention -% from within a \TeX-based workflow. +% from within a \tex-based workflow. % \changes{v1.4}{2011/05/29}{Renamed the \texttt{xapMM} namespace % prefix to \texttt{xmpMM}} % \begin{macrocode} @@ -1645,16 +2124,47 @@ ______^^J% % \end{macrocode} % \end{macro} % +% +% \subsubsection{The XMP Basic schema} +% \label{sec: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} +% \begin{macrocode} +\newcommand*{\hyxmp@xmp@basic@schema}{% + \hyxmp@add@to@xml{% +______^^J% + }% + \hyxmp@add@simple{xmp:CreateDate}{\hyxmp@today}% + \hyxmp@add@simple{xmp:ModifyDate}{\hyxmp@today}% + \hyxmp@add@simple{xmp:MetadataDate}{\hyxmp@today}% + \hyxmp@add@simple{xmp:CreatorTool}{\@pdfcreator}% + \hyxmp@add@simple{xmp:BaseURL}{\@baseurl}% + \hyxmp@add@to@xml{% +______^^J% + }% +} +% \end{macrocode} +% \end{macro} +% +% % \subsubsection{The Photoshop schema} % \label{sec:photoshop} % % \begin{macro}{\hyxmp@photoshop@schema} % \begin{macro}{\hyxmp@photoshop@data} % Add properties defined by the Photoshop schema to the |\hyxmp@xml| -% macro. We support only the \xmpterm{photoshop:AuthorsPosition} and -% \xmpterm{photoshop:CaptionWriter} properties, as that's all that Adobe -% Acrobat currently displays. +% macro. We currently support only the +% \xmpterm{photoshop:AuthorsPosition} and +% \xmpterm{photoshop:CaptionWriter} properties. % \changes{v1.2}{2010/06/07}{Added support for the Photoshop schema} +% \changes{v2.0}{2012/08/26}{Simplified using +% \texttt{\string\string\string\hyxmp@add@simple}} % \begin{macrocode} \gdef\hyxmp@photoshop@schema{% \edef\hyxmp@photoshop@data{\@pdfauthortitle\@pdfcaptionwriter}% @@ -1665,26 +2175,8 @@ ______^^J% }% \fi -% \end{macrocode} -% \begin{macrocode} - \ifx\@pdfauthortitle\@empty - \else - \hyxmp@xmlify{\@pdfauthortitle}% - \hyxmp@add@to@xml{% -_________\hyxmp@xmlified^^J% - }% - \fi -% \end{macrocode} -% \begin{macrocode} - \ifx\@pdfcaptionwriter\@empty - \else - \hyxmp@xmlify{\@pdfcaptionwriter}% - \hyxmp@add@to@xml{% -_________\hyxmp@xmlified^^J% - }% - \fi -% \end{macrocode} -% \begin{macrocode} + \hyxmp@add@simple{photoshop:AuthorsPosition}{\@pdfauthortitle}% + \hyxmp@add@simple{photoshop:CaptionWriter}{\@pdfcaptionwriter}% \ifx\hyxmp@photoshop@data\@empty \else \hyxmp@add@to@xml{% @@ -1696,41 +2188,54 @@ ______^^J% % \end{macro} % \end{macro} % +% % \subsubsection{Constructing the XMP packet} % +% \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} -% \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 states that the argument to the -% \xmpterm{begin} attribute is supposed to be ``the Unicode character -% U+FEFF used as a byte-order marker''~\cite{Adobe2010:XMP}, so that's -% what we use, although inserted as the 8-bit character sequence -% \meta{EF}\meta{BB}\meta{BF}. We explicitly mark those characters 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} +% \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} -\bgroup -\catcode`\^^ef=12 -\catcode`\^^bb=12 -\catcode`\^^bf=12 -\gdef\hyxmp@construct@packet{% +\def\hyxmp@construct@packet{% \gdef\hyxmp@xml{}% - \hyxmp@add@to@xml{% -^^J% + \hyxmp@add@to@xml{^^J% ^^J% -___^^J% +___^^J% }% \hyxmp@pdf@schema \hyxmp@xmpRights@schema \hyxmp@dc@schema \hyxmp@photoshop@schema + \hyxmp@xmp@basic@schema \hyxmp@mm@schema \hyxmp@add@to@xml{% ___^^J% @@ -1739,7 +2244,6 @@ ___^^J% ^^J% }% } -\egroup % \end{macrocode} % \end{macro} % \end{macro} @@ -1786,10 +2290,10 @@ ___^^J% % \end{macro} % \end{macro} % -% \subsubsection{Embedding using pdf\TeX} +% \subsubsection{Embedding using \pdfTeX} % % \begin{macro}{\hyxmp@embed@packet@pdftex} -% Embed the \acro{XMP} packet using pdf\TeX\ primitives. +% Embed the \acro{XMP} packet using \pdfTeX\ primitives. % \begin{macrocode} \newcommand*{\hyxmp@embed@packet@pdftex}{% \bgroup @@ -1808,23 +2312,28 @@ ___^^J% % % \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. +% 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}% - << - /Type /Metadata - /Subtype /XML - >> + Raw={\string{hyxmp@Metadata\string} + 2 dict begin + /Type /Metadata def + /Subtype /XML def + currentdict + end }% }% \pdfmark{% @@ -1832,27 +2341,11 @@ ___^^J% Raw={\string{hyxmp@Metadata\string} (\hyxmp@xml)}% }% \pdfmark{% - pdfmark=/CLOSE, - Raw={\string{hyxmp@Metadata\string}}% + pdfmark=/Metadata, + Raw={\string{Catalog\string} \string{hyxmp@Metadata\string}}% }% -% \end{macrocode} -% Adobe's |pdfmark| reference indicates that a metadata stream should be -% added to the document catalog by specifying the \pdfterm{Metadata} -% |pdfmark|~\cite{Adobe2010:pdfmark}. However, earlier versions of -% Adobe Acrobat Distiller (pre-6.0) and Ghostscript ignored -% \pdfterm{Metadata} but honored \pdfterm{PUT} so that's what versions -% of \pkgname{hyperxmp} prior to~1.3 used. As all current -% PostScript-to-\acro{PDF} generators seem to honor the -% \pdfterm{Metadata} |pdfmark|, \pkgname{hyperxmp} now uses that -% mechanism to point the document catalog to our metadata stream. -% \begin{macrocode} \pdfmark{% - pdfmark=/Metadata, - Raw={\string{Catalog\string}% - << - /Metadata \string{hyxmp@Metadata\string}% - >> - }% + pdfmark=/NamespacePop }% } % \end{macrocode} @@ -1903,7 +2396,7 @@ ___^^J% % % \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 +% 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 {% @@ -1920,7 +2413,7 @@ ___^^J% % % \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 +% 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} -- cgit v1.2.3