% \iffalse meta-comment % % Copyright (C) 2004 by Maarten Sneep % ----------------------------------------------------- % % This work is licensed under the CC-GNU GPL, the human readable license % can be found here, with a link to the full text on this page. % http://creativecommons.org/licenses/GPL/2.0/ % % To process this file run the accompanying xmpincl.ins file through tex. % To get the documentation, run this file through pdfLaTeX. % % \fi % % \iffalse % %<*driver> \ProvidesFile{xmpincl.dtx} % %\NeedsTeXFormat{LaTeX2e}[1999/12/01] %\ProvidesPackage{xmpincl} %<*package> [2021/09/22 v2.4 Include XMP data in pdflatex] % % %<*driver> \documentclass{ltxdoc} \usepackage{hyperref} \usepackage{url} \usepackage{xmpincl} \hypersetup{colorlinks=true, pdftitle={Including XMP in pdflatex}, pdfauthor={Maarten Sneep}, pdfsubject={pdflatex and XMP inclusions.}, pdfkeywords={XMP, Creative Commons}, pdfview={FitH}, pdfstartview={FitH}, pdfstartpage={1}, plainpages=false} \includexmp{license} \DisableCrossrefs %\CodelineIndex %\RecordChanges %\OnlyDescription \begin{document} \DocInput{xmpincl.dtx} \end{document} % % \fi % % \CheckSum{121} % % \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}{2004/06/20}{Initial release} % \changes{v1.1}{2004/06/20}{Fixed some miscelaneous typos and removed support % for the package option} % \changes{v1.2}{2004/12/12}{Correctly detect pdftex usage -- rely on the ifpdf % package, not on whether the pdfoutput command is defined} % \changes{v1.3}{2005/02/14}{Clarified which parts are included in the % meta-information, and what isn't.} % \changes{v2.0}{2005/02/15}{Major release. Added code that will append % the xpacket bits, if they are not already there.} % \changes{v2.1}{2005/03/24}{Minor update: ifpdf and Memoir no longer bite each % other. When used with Memoir, version ``2005/03/23 v3.9 Patches for memoir % class v1.61'' of mempatch.sty is required.} % \changes{v2.2}{2008/05/10}{Minor update: made |~| and |&| normal characters % when writing the xmpi file. I still need to find a way to include |%| % characters in the xmpi file.} % \changes{v2.3}{2021/08/31}{Replaced \cs{if}\cs{par} with \cs{ifx}\cs{par} % because the former caused an error with the new definition of \cs{par}.} % \changes{v2.4}{2021/09/22}{Replaced \cs{ifx}\cs{par} with \cs{if}\cs{endline} % because the former caused pdf/a validation errors.} % % \GetFileInfo{xmpincl.dtx} % % \DoNotIndex{\newcommand,\newenvironment} % \DoNotIndex{\#,\$,\%,\&,\@,\\,\{,\},\^,\_,\~,\ } % \DoNotIndex{\@ne} % \DoNotIndex{\advance,\begingroup,\catcode,\closein} % \DoNotIndex{\closeout,\day,\def,\edef,\else,\empty,\endgroup} % % \title{The \textsf{XMP} inclusion package\thanks{This document % corresponds to \textsf{xmpincl.dtx}~\fileversion, dated \filedate.}} % \author{Maarten Sneep} % \date{\filedate} % % \maketitle % % \section{Introduction} % % The |XMP| (eXtensible Metadata Platform) is a framework to add metadata % to digital material to enhance the workflow in publication. References % are given below, but the essence is that the metadata is stored in an % |XML| file, and this XML stream is then embedded in the file to which it % applies. How you create this |XML| file is up to you, but I started % investigating this, because I wanted to embed some licensing information % in the files I create. The license I chose is one of the % \textsf{Creative Commons} licenses, and their web-site offers this % information in a valid |XML| file, suitable for direct inclusion. % % Note that this package is released under the % \href{http://creativecommons.org/licenses/GPL/2.0/}{CC-GNU GPL} license. % You can redistribute, but I kindly request that you update the version % number, add a description of what you added or changed -- if possible % with an explanation as to why -- and re-submit to CTAN, to keep it all % in a single location. You can also submit changes to me, I regularly % read |comp.text.tex| on usenet. % % Many thanks to James Howison for pushing me to put in the % || writing code, and suggesting to test whether they % are already there. % % Thanks to Martin Szummer for reporting that a |~| in an URL inside the % xmp file will not work. % % \subsection{Usage} % % This package defines a single command, |\includexmp{}|. The |xmp| file % is specified as an argument to this command. Although there is no real % specification as to where the xml-stream should be inserted into the % document, I would advise to put it at the start of the file, so call the % |\includexmp{}| command before |\begin{document}|. Note that the package % will add the extension |.xmp| to the base filename. To include the file % |metadata.xmp|, use the following: % %\begin{verbatim} %. . . %\usepackage{xmpincl} %\includexmp{metadata} %. . . %\begin{document} %. . . %\end{verbatim} % % The file |metadata.xmp| should exist in the same directory as the master % document. At the end of this documentation a sample file is included % that will yield a valid |XMP| enhanced pdf file. % % Previous versions of this package required the inclusion of the % || tags into the |XMP| file. This is against the standards, % and several users requested that this functionality be added to the % package. This new release (version 2.0) does add the || % tags, if they are \emph{not} present in the |xmp| file. % % \subsection{New in the release v2.1} % % There used to be a clash between the Memoir document class and the |ifpdf| package. % As of version 2005/03/23 v3.9 of |mempatch.sty|, this clash has been removed, and % glue code that was present here, has been removed in this update. Note that this % may mean that you'll need to update your distribution to include teh latest % |mempatch.sty|. % % \subsection{References} % % \begin{itemize} % \item \url{http://creativecommons.org/} % \item \url{http://creativecommons.org/technology/xmp-help} % \item \url{http://www.adobe.com/products/xmp} % \end{itemize} % % \PrintChanges % % \StopEventually{} % % \section{Implementation} % % First we determine if we run under pdf\LaTeX{}, in pdf-production mode. % This is best done with the |ifpdf| package. The Memoir documentclass also % defines the |\ifpdf| boolean, but didn't actually load the |ifpdf| package. % As of version ``2005/03/23 v3.9 Patches for memoir class v1.61'' of |mempatch.sty| % teh loading of the ifpdf package is properly faked, and we no longer need to % check for the existence of the |\ifpdf| boolean. % \begin{macrocode} %<*package> \RequirePackage{ifpdf} \ifpdf\else % \end{macrocode} % Apparently we do not run under pdflatex, or we are producing DVI. % Someone else may try to do this correcltly for PostScript output. Note % that a metacomment has to be added to the start of the |.ps| document, % and that is something for which I have no clue on how to accomplish that % from within \TeX{}. % % Right now I just skip non-pdflatex support and issue a warning. % \begin{macrocode} \PackageWarningNoLine{xmpincl}% {Only pdflatex is supported by the xmpincl package} % \end{macrocode} % \DescribeMacro{includexmp} % This is the latex (|DVI|) edition: just issue a warning, and stop % reading the rest of this file % \begin{macrocode} \newcommand{\includexmp}[1]{% \PackageError{xmpincl}% {latex is not supported by the \protect\includexmp\space package}% {You tried to include XMP metadata in DVI production.\MessageBreak That doesn't work, and I friendly tried to warn you.\MessageBreak Just continue and pretend nothing is wrong,\MessageBreak but please remove the package or switch to pdflatex.} } % \end{macrocode} % Stop reading this file, as the rest only works when generating |pdf| % directly. % \begin{macrocode} \relax\expandafter\endinput \fi % \end{macrocode} % The |ifthen| package is loaded, for the string comparisons later on. % \begin{macrocode} \RequirePackage{ifthen} % \end{macrocode} % \DescribeMacro{mcs@xmpincl@patchFile} % Based on popular feedback, we now add the || parts % ourselves. This can be a bit tricky, so bear with me. I basically create % a new file |.xmpi| which starts off with the || tag, copy % the whole |XMP| file to this new file, and add the || close % tag. Of course, this is new functionality, so we still have to take care % of our backward compatibility issues. So we check that what we've read is % not an || tag. I'm aware of the odd combination of \TeX{} % and \LaTeX{} coding here, but I didn't manage to get the string % comparison working in palin \TeX{} code, and this \LaTeX{} code is % maintained by others, something I really don't mind. % % The macro starts off by opening a few files, one for reading the user % supplied |XMP|, and another one for writing it back out again, but this % time with the || bits included. % \begin{macrocode} \newcommand*{\mcs@xmpincl@patchFile}[1]{ \begingroup \newwrite\xmpinclWrite \newread\xmpinclRead \immediate\openin\xmpinclRead #1.xmp \immediate\openout\xmpinclWrite #1.xmpi % \end{macrocode} % \DescribeMacro{mcs@xmpinclStart} % \DescribeMacro{mcs@xmpinclStartAlt} % \DescribeMacro{mcs@xmpinclEnd} % The begin and en || strings are put in some macros to % easier access. Yes, that start string was double checked against the % documentation provided by Adobe. The alternate starting string is there % because the |id| seems to be optional, if I understand the documentation % correctly. % \begin{macrocode} \newcommand{\mcs@xmpinclStart}% { } \newcommand{\mcs@xmpinclStartAlt}% { } \newcommand{\mcs@xmpinclEnd}% { } % \end{macrocode} % Next we change the catcode of |#| to `other'. This is just to prevent % misinterpretation of this character. Of course there are more special % characters, but as far as I can see, these aren't treated in any special % way (|#| is doubled by \TeX{} to |##|). % \begin{macrocode} \catcode`\#=12 % \end{macrocode} % We deactivate |~| and |&| as well. % \begin{macrocode} \catcode`\~=12 \catcode`\&=12 % \end{macrocode} % Read the first line of the input file, and compare it to the start tag, % and the alternate start tag. If they match, write out the standard start % tag (including the |id|). If they don't match, write out the start tag, % followed by the line we've just read. % \begin{macrocode} \immediate\read\xmpinclRead to\xmpinclReadln% \ifthenelse{% \equal{\mcs@xmpinclStart}{\xmpinclReadln}% \or% \equal{\mcs@xmpinclStartAlt}{\xmpinclReadln}% }% {% \immediate\write\xmpinclWrite{\mcs@xmpinclStart}% }% {% \immediate\write\xmpinclWrite{\mcs@xmpinclStart}% \immediate\write\xmpinclWrite{\xmpinclReadln}% }% % \end{macrocode} % Start the |\loop|, and read a line. Check if it is equal to the end tag % or to |\endline|, and if it isn't, write it out to the |.xmpi| file. The % check against |\endline| ensures that empty lines are skipped, and not % replaced by |\par|. % % The |\ifeof| test checks whether we've reached the end of the original % |.xmp| file, and |\repeat|s the |\loop| if we haven't. % \begin{macrocode} \loop% \immediate\read\xmpinclRead to\xmpinclReadln% \ifthenelse{% \equal{\mcs@xmpinclEnd}{\xmpinclReadln}% }{% Note: no if. }{% \if\endline\xmpinclReadln\else% \immediate\write\xmpinclWrite{\xmpinclReadln}% \fi% }% \ifeof\xmpinclRead\else% \repeat % \end{macrocode} % Since we skipped any end || tags, we write it here. After % that we close both files and end the current group (restoring the % meaning of |#|, |&|, and |~|). % \begin{macrocode} \immediate\write\xmpinclWrite{\mcs@xmpinclEnd} \immediate\closein\xmpinclRead \immediate\closeout\xmpinclWrite \endgroup } % \end{macrocode} % \DescribeMacro{includexmp} % The meat of the business. Actually pretty trivial, once you know % how\ldots % \begin{macrocode} \newcommand{\includexmp}[1]{% % \end{macrocode} % First check that the file can be found, and if we use the new methods, % convert it. % \begin{macrocode} \IfFileExists{#1.xmp}{ \mcs@xmpincl@patchFile{#1} % \end{macrocode} % Reset the |\pdfcompresslevel| to 0, do not compress the |XML| data. % This is recommended by Adobe, so that file utilities can grep the |.pdf| % file for metadata, without the full capability to actually parse the % |pdf| file. % Keep the change local. % \begin{macrocode} \begingroup \pdfcompresslevel=0 % \end{macrocode} % Write out the |pdf| object, with the specifications given in the % reference manual found at \url{http://www.adobe.com/products/xmp}. The % |file| attribute reads the specified file from disk, although it is not % clear to me if it uses the full \TeX{} search path. To be safe, specify % a local path relative to the master document. Depending on the % compatibility level, we use the original file, or the newly generated % version. % \begin{macrocode} \immediate\pdfobj stream attr {/Type /Metadata /Subtype /XML} file{#1.xmpi} % \end{macrocode} % Also add the newly created object to the catalog. % \begin{macrocode} \pdfcatalog{/Metadata \the\pdflastobj\space 0 R} % \end{macrocode} % end the group, which resets the compression to whatever it was before. % \begin{macrocode} \endgroup } % \end{macrocode} % The file does not exist, and we have to generate an error. Declare a % placeholder for the missing file-name, to prevent double execution of % the macro. % \begin{macrocode} {\newcommand{\mcs@xmpincl@filename}{#1.xmp} \PackageError{xmpincl}% {The file \mcs@xmpincl@filename\space was not found} {The file \mcs@xmpincl@filename\space The metadata file wasn't found.\MessageBreak Oops.} } } % % \end{macrocode} % % \section{A sample \texttt{.xmp} file} % Note that this is the license of this package, % \href{http://creativecommons.org/licenses/GPL/2.0/}{CC-GNU GPL}. % % \begin{macrocode} %<*license> xmpincl 2005 A LaTeX package to include XMP metadata in files generated through pdfLaTeX Maarten Sneep Maarten Sneep % % \end{macrocode} % \Finale \endinput