%\iffalse % makeindex -s gglo.ist -o web.gls web.glo %<*copyright> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% aebxmp.sty package, 2012-01-10 %% %% Copyright (C) 2006--2012 D. P. Story %% %% dpstory@uakron.edu %% %% %% %% This program can redistributed and/or modified under %% %% the terms of the LaTeX Project Public License %% %% Distributed from CTAN archives in directory %% %% macros/latex/base/lppl.txt; either version 1 of the %% %% License, or (at your option) any later version. %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % %\NeedsTeXFormat{LaTeX2e}[1997/12/01] %\ProvidesPackage{aebxmp} % [2012/01/10 v2.3 Populate advanced metadata (dps)] %<*driver> \documentclass{ltxdoc} \usepackage[colorlinks,hyperindex]{hyperref} %\pdfstringdefDisableCommands{\let\\\textbackslash} %\EnableCrossrefs \CodelineIndex \RecordChanges \begin{document} \def\CMD#1{\textbackslash#1} \GetFileInfo{aebxmp.sty} \title{AeBXMP: Updating XMP using E4X and {\LaTeX}} \author{D. P. Story\\ Email: \texttt{dpstory@uakron.edu}} \date{processed \today} \maketitle \tableofcontents \let\Email\texttt \renewenvironment{theglossary}{% \let\efill\relax \begin{itemize}}{\end{itemize}} \value{GlossaryColumns}=1 \DocInput{aebxmp.dtx} \PrintIndex \end{document} % % \fi % \MakeShortVerb{|} % \StopEventually{} % % \DoNotIndex{\def,\edef,\gdef,\xdef,\global,\long,\let} % \DoNotIndex{\expandafter,\string,\the,\ifx,\else,\fi} % \DoNotIndex{\csname,\endcsname,\relax,\begingroup,\endgroup} % \DoNotIndex{\DeclareTextCommand,\DeclareTextCompositeCommand} % \DoNotIndex{\space,\@empty,\special} % % \begin{macrocode} %<*package> % \end{macrocode} % \textbf{Changes} % \begin{itemize} % \item v2.3 (2012/01/09) All XMP elements now is inserted by E4X. % \item v2.2 (2012/01/04) Added the \cs{Keywords} command for creating an array % of keywords that can be accessed individually using the JavaScript function % \texttt{aKeyWords}, also defined in this package. % \item v2.1a (2011/12/30) More code efficiencies % \item v2.1 (2011/12/30) Cleaned up the code, fixed a bug. % \item v2.0 (2011/12/30) Defined commands to producing custom document properties, % defined the \cs{Authors} command. % \item v1.0 (2011/12/29) Made a proper DTX file for this package; added % \cs{authortitle} and \cs{descriptionwriter}; support for \texttt{xmp:CreateDate}. % \item v0.2 (2007/03/13) Added support for unicode escape sequences in the % \cs{copyrightNotice} and \cs{copyrightInfoURL} fields. % \item v0.1 Original distribution % \end{itemize} % \begin{macrocode} \RequirePackage{xkeyval} \ProcessOptionsX \@ifpackageloaded{insdljs}{\let\execjs=y} {\RequirePackage[execJS]{insdljs}} % \end{macrocode} % \section{Top-level Interface to Metadata} % Through this package, the author can specify certain ``Advance Metadata'' % items: copyright notice; copyright notice; copyright url; author title; % and writer description.\par\medskip\noindent % The basic user interface is a series of commands listed below. % Each of the commands takes one argument. % \begin{macro}{\copyrightStatus} %If \texttt{\#1} is \texttt{True}, the \textsf{Copyright Status} is set to %\texttt{Copyrighted}; if \texttt{False}, \textsf{Copyright Status} is set %to \textsf{Public Domain}. If left empty, the status is set to %\textsf{Unknown}. % \begin{macro}{\copyrightNotice} % The argument \texttt{\#1} is the text of the \textsf{Copyright Notice}. % \begin{macro}{\copyrightInfoURL} % The argument \texttt{\#1} is the \textsf{URL} to the copyright information % \begin{macro}{\authortitle} % The \texttt{} (argument \texttt{\#1}) appears in the % \textsf{Author Title} line on the \textsf{Advanced Metadata} dialog box. % This is a \textbf{Photoshop} property. (See the Advanced category in the left % panel.) % \begin{macro}{\descriptionwriter} % The \texttt{} (argument \texttt{\#1}) appears in the %\textsf{Description Writer} line on the \textsf{Advanced Metadata} dialog box. %This is a \textbf{Photoshop} property. (See the Advanced category in the left %panel.) % \begin{macrocode} \newcommand{\copyrightStatus}[1]{\def\xmpcopyrightStatus{#1}} \let\xmpcopyrightStatus\@empty \newcommand{\copyrightNotice}[1]{\def\xmpcopyrightNotice{#1}} \let\xmpcopyrightNotice\@empty \newcommand{\copyrightInfoURL}[1]{\def\xmpcopyrightInfoURL{#1}} \let\xmpcopyrightInfoURL\@empty \newcommand{\authortitle}[1]{\def\xmpauthortitle{#1}} \let\xmpauthortitle\@empty \newcommand{\descriptionwriter}[1]{\def\xmpdescriptionwriter{#1}} \let\xmpdescriptionwriter\@empty % \end{macrocode} % \begin{macro}{\Authors} % Enter multiple authors using a token list %\begin{verbatim} %\Authors %{% % {D. P. Story} % {A. P. Story} % ... %} %\end{verbatim} % We use \cs{@tfor} to build an array of authors, and use the simple mechanism % of \texttt{this.info.Authors} to set the multiple authors. % \begin{macrocode} \let\arrayOfAuthors\@empty \let\xmpAuthors\@empty \newcommand{\Authors}[1]{\def\xmpAuthors{#1}% \begingroup\let\u\relax \ifx\xmpAuthors\@empty\else \let\arrayOfAuthors\@gobble \@tfor\xmpAuthor:=#1\do{% \xdef\arrayOfAuthors{\arrayOfAuthors,"\xmpAuthor"}% }% % \end{macrocode} % We build a JavaScript array of authors. % \begin{macrocode} \xdef\arrayOfAuthors{[\arrayOfAuthors];}% \fi \endgroup } % \end{macrocode} % \cs{insertAuthors} does what the other ``insert'' commands do, insert the % code, only if there are multiple authors. % \begin{macrocode} \def\insertAuthors{\ifx\arrayOfAuthors\@empty\else this.info.Authors=\arrayOfAuthors^^J\fi} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \begin{macrocode} \def\insertCopyrightNotice{\ifx\xmpcopyrightNotice\@empty\else ^^Jp.aebdc::rights.aebrdf::Alt.aebrdf::li[0]="\xmpcopyrightNotice"; ^^Jp.aebdc::rights.aebrdf::Alt.aebrdf::li[0].@xml::lang="en";\fi} % \end{macrocode} % \begin{macro}{\Keywords} % We try to implement keywords in a manner similar to \cs{Authors}; that is, % we want to reference each key word. The individual keywords are listed in % \texttt{dc:subject}, in a \texttt{Bag}, an unordered array. % \begin{macrocode} \let\arrayOfKeywords\@empty \let\aKeywords\@empty \let\xmpKeywords\@empty \newcommand{\Keywords}[1]{\def\xmpKeywords{#1}% \begingroup\let\u\relax\count0=0 \def\insBagItem{% p.aebdc::subject.aebrdf::Bag.aebrdf::li}% \ifx\xmpKeywords\@empty\else \let\arrayOfKeywords\@gobble \let\aKeywords\@gobbletwo \@for\xmpKeyword:=#1\do{% \xdef\arrayOfKeywords{\arrayOfKeywords^^J% \insBagItem[\the\count0]="\xmpKeyword";}% \xdef\aKeywords{\aKeywords;\space\xmpKeyword}% \advance\count0by1 }% \xdef\aKeywords{"\aKeywords"}% \fi \endgroup } % \end{macrocode} % \cs{insertKeywords} does what the other ``insert'' commands do, insert the % code, we use the \texttt{dc:subject} tag, which corresponds to keywords. % \begin{macrocode} \def\insertKeywords{\ifx\arrayOfKeywords\@empty\else \arrayOfKeywords\fi} % \end{macrocode} % We set the keywords using the JavaScript property \texttt{Doc.in}, rather % than a pdfmark. % \begin{macrocode} \def\insertaKeywords{\ifx\aKeywords\@empty\else % this.info.Keywords=\aKeywords.toString();^^J% this.info.Keywords=\aKeywords;^^J% this.addScript("Array of Keywords", '\akeywordsJS');^^J\fi} % \end{macrocode} % This is the definition of the function \texttt{aKeywords}, it is imported % using the JavaScript method \texttt{Doc.addScript}, see above. % \begin{macrocode} \begin{defineJS}[\catcode`\@=0\relax]{\akeywordsJS} function aKeywords(i) { var uriRdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"; var uriDc="http://purl.org/dc/elements/1.1/"; var meta=this.metadata; var aebXMPData=new XML(meta); var aebrdf=@xNNS(uriRdf); var aebdc=@xNNS(uriDc); var p=aebXMPData.aebrdf::RDF.aebrdf::Description; return p.aebdc::subject.aebrdf::Bag.aebrdf::li[i]; } aKeywords.doc=this; % \end{macrocode} % \texttt{aKeywords.toString()} displays a sting listing of the keywords; % the string it displays \texttt{this.info.Keywords}. % \begin{macrocode} aKeywords.toString=function() {return aKeywords.doc.info.Keywords;} \end{defineJS} % \end{macrocode} % \end{macro} % \begin{macro}{\customProperties} %\begin{verbatim} %\customProperties %{ % {name=dps,value=5} % {name=jg,value=good} % ... %} %\end{verbatim} % \begin{macrocode} \let\insertCusProps\@empty \newcommand\customProperties[1]{\def\pdfx@cusProps{#1}% \begingroup\let\u\relax \@tfor\thisproperty:=#1\do{% \edef\tmp@exp{\noexpand \setkeys{pdfx@cusPropKV}{name,value,\thisproperty}}\tmp@exp \xdef\insertCusProps{\insertCusProps^^J% % \end{macrocode} % We permit the use of \cs{u} the the value of the custom property, % the name of the custom property should be a restricted XML name, basically % \texttt{A-Z},\texttt{a-z}, and \texttt{0-9}. % \begin{macrocode} p.aebpdfx::\pdfx@KName="\pdfx@VValue";} }% \endgroup } % \end{macrocode} % The \texttt{pdfx@cusPropKV} family has two keys, \texttt{name} and \texttt{value}. % These keys are used in the command \cs{customProperties} defined above. % \begin{macrocode} \define@key{pdfx@cusPropKV}{name}[]{\def\pdfx@KName{#1}} \define@key{pdfx@cusPropKV}{value}[]{\def\pdfx@VValue{#1}} % \end{macrocode} % \end{macro} % We define a simple tabbing command \cs{tabiv} to use within the JavaScript. % \begin{macrocode} \bgroup\obeyspaces \gdef\tabiv{ }% \egroup % \end{macrocode} % These are some helper macros that conditionally fill in metadata when it exists. % All these commands are using internally; the document author has no reason to use them. % \begin{macrocode} \def\insertMarked{\ifx\xmpcopyrightStatus\@empty \else^^Jp.aebxapRights::Marked="\xmpcopyrightStatus";\fi} \def\insertWebStatement{\ifx\xmpcopyrightInfoURL\@empty \else^^Jp.aebxapRights::WebStatement="\xmpcopyrightInfoURL";\fi} \def\insertAuthorTitle{\ifx\xmpauthortitle\@empty \else^^Jp.aebphotoshop::AuthorsPosition="\xmpauthortitle";\fi} \def\insertDescriptionWriter{\ifx\xmpdescriptionwriter\@empty \else^^Jp.aebphotoshop::CaptionWriter="\xmpdescriptionwriter";\fi} \def\insertCreateDate{^^Jp.aebxap::CreateDate=createDateStr;} \def\xmpnEOL{\string\n\string\^^J} % \end{macrocode} % \section{Disposable JavaScript} % Most of this package consists of a few new commands to populate the ``disposable'' % JavaScript that is input as an \textsf{FDF} when the PDF file is first opened after distilling. % This code does all the work. % \begin{macrocode} \def\xNNS{new Namespace} \def\xAdbNS{http://ns.adobe.com} \def\xWiiiNS{http://www.w3.org} \begin{execJS}{execXMP} var meta=this.metadata; var aebXMPData=new XML(meta); var aebx=\xNNS("x","adobe:ns:meta/"); var xmlns=\xNNS("xmlns","\xWiiiNS/2000/xmlns/"); var xml=\xNNS("xml", "\xWiiiNS/XML/1998/namespace"); var aebrdf=\xNNS("rdf","\xWiiiNS/1999/02/22-rdf-syntax-ns#"); var aebdc=\xNNS("dc","http://purl.org/dc/elements/1.1/"); var aebpdf=\xNNS("pdf","\xAdbNS/pdf/1.3/"); var aebxap=\xNNS("xmp","\xAdbNS/xap/1.0/"); var aebxapRights=\xNNS("xmpRights","\xAdbNS/xap/1.0/rights/"); var aebphotoshop=\xNNS("photoshop","\xAdbNS/photoshop/1.0/"); var aebpdfx=\xNNS("pdfx","\xAdbNS/pdfx/1.3/"); % \end{macrocode} % \begin{macrocode} var p=aebXMPData.aebrdf::RDF.aebrdf::Description; % \end{macrocode} % \begin{macrocode} p.@xmlns::pdfx=aebpdfx.uri; p.@xmlns::photoshop=aebphotoshop.uri; p.@xmlns::xmpRights=aebxapRights.uri; % \end{macrocode} % The creation date shall be the time this \textsf{FDF} is imported into the document. % \begin{macrocode} var d=new Date(); var createDateStr=util.printd("yyyy-mm-ddTHH:MM:ss",d); % \end{macrocode} % We delete the element, in case it already has a value (unlikely), the we % assign it our value. % \begin{macrocode} delete p.@aebdc::rights.aebrdf::Alt.aebrdf::li; % \end{macrocode} % \paragraph*{Dublin Core Properties % (\texttt{dc}, \begin{NoHyper}\url{http://purl.org/dc/elements/1.1/}\end{NoHyper})}\strut\\ % Core properties include \texttt{dc:format}, \texttt{dc:title}, % \texttt{dc:rights}, \texttt{dc:creator}, and \texttt{dc:subject} (aka, keywords). % Here, we set \texttt{dc:rights}, called \textsf{Copyright Notice} in the user interface. % \begin{macrocode} \insertKeywords% \insertCopyrightNotice % \end{macrocode} % We delete all old values of \texttt{xapRights:Marked} and \texttt{xap:WebStatement}, % and replace them with the new values. % \begin{macrocode} delete p.@aebxapRights::Marked; delete p.@aebxapRights::WebStatement; % \end{macrocode} % Ditto for \texttt{photoshop:AuthorsPosition} and % \texttt{photoshop:CaptionWriter}. % \begin{macrocode} delete p.@aebphotoshop::AuthorsPosition; delete p.@aebphotoshop::CaptionWriter; delete p.@aebxap::CreateDate;% % \end{macrocode} % Now we insert additional properties, if there are any % \begin{macrocode} % \end{macrocode} % \paragraph*{XMP Rights Management}\strut\\(\texttt{xmpRights}, % \begin{NoHyper}\url{http://ns.adobe.com/xap/1.0/rights/}\end{NoHyper})\\ % These include \texttt{xmpRights:Marked} and \texttt{xmpRights:WebStatement}, both of which % are set. % \begin{macrocode} \insertMarked% \insertWebStatement% % \end{macrocode} % \paragraph*{Adobe Photoshop Properties}\strut\\(\texttt{photoshop}, % \begin{NoHyper}\url{http://ns.adobe.com/photoshop/1.0/}\end{NoHyper})\\ % These include \texttt{photoshop:AuthorsPosition} and \texttt{photoshop:CaptionWriter}, both of which % are set. % \begin{macrocode} \insertAuthorTitle% \insertDescriptionWriter% % \end{macrocode} % \paragraph*{Acrobat Custom Properties} (\texttt{pdfx}, % \begin{NoHyper}\url{http://ns.adobe.com/pdfx/1.3/}\end{NoHyper})\\ % Adobe allows the creation of custom properties that are accessible % through the \texttt{Doc.info} object. % \begin{macrocode} \insertCusProps% % \end{macrocode} % \paragraph*{XMP Core Properties} (\texttt{xmp}, % \begin{NoHyper}\url{http://ns.adobe.com/xap/1.0/}\end{NoHyper})\\ % These properties include \texttt{xmp:CreatorTool}, % \texttt{xmp:ModifyDate}, \texttt{xmp:CreateDate}, and \texttt{xmp:MetadataDate}. % Here we set only \texttt{CreateDate}. % \begin{macrocode} \insertCreateDate %% % \end{macrocode} % Convert \texttt{aebXMPData} into a string % \begin{macrocode} var aebNewXMPStr=aebXMPData.toXMLString(); % \end{macrocode} % and assign it to the document metadata % \begin{macrocode} this.metadata=aebNewXMPStr; % \end{macrocode} % Now, we update the metadata by inserting the \texttt{info.Authors} % \begin{macrocode} \insertAuthors% % \end{macrocode} % This next command uses \texttt{this.info.Keywords} to insert the keywords % into the \textbf{Info} dictionary and into \texttt{pdf:Keywords}. It also % inserts the document-level JavaScript function \texttt{aKeywords()}. % \begin{macrocode} \insertaKeywords% \end{execJS} % \end{macrocode} % \begin{macrocode} % % \end{macrocode} \endinput