% \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