%D \module %D [ file=spec-fdf, %D version=1998.05.18, %D title=\CONTEXT\ \PDF\ Macros, %D subtitle=Support Macros, %D author=Hans Hagen, %D date=\currentdate, %D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] %C %C This module is part of the \CONTEXT\ macro||package and is %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. %D The name of this module is a bit strange but it started with fields %D so we keep the name. %D When dealing with resources, we share the resource dictionaries %D between all xforms. This is inefficent in the sense that when no %D resources are used, redundant entries take space, but on the other %D hand we save redundant dictionaries so it's a nice compromise. Maybe %D that in \LUATEX\ I will reimplement most of the code here anyway. %D We need to check if we can use \type {\driverreferenced} %D object in more places. %D Initialization of fields is tricky. If a field has no %D value, it is kind of not there. If ResetForm is used, the %D default is assigned, but pushbuttons are spoiled. Adding a %D \type {/MK} dictionary helps, but gives ugly down %D appearances (displaced with background). What a mess. %D Also, in order to get at least something, the \type {/AS} %D key should be provided. % to do : /IF << /SW /N >> == no scaling / clipping of widget \unprotect %D \macros %D {PDFobjref} %D %D Just a shortcut. % Watch out, \def\PDFobjref#1{\purenumber#1 0 R} also works, but not when % #1 == \the\whatever \def\PDFobjref#1{\purenumber{#1} 0 R} %D \macros %D {PDFswapdir} \let\PDFswapdir\empty \def\PDFswapdir{\ifcase\inlinedirection\or\or-\fi} % the pdf spec changed cq. viewers started behaving differently / 5+ \chardef\overcomePDFpage\plusone % page numbers/ beware: optimizers remove this one \chardef\overcomePDFpage\plustwo % page:number %chardef\overcomePDFpage\plusthree % pdftex page ref feature \ifx\pdfpageref\undefined \else \chardef\overcomePDFpage\plusthree \fi %D \macros %D {setPDFdestination} %D %D \PDF\ destinations should obey the specifications laid down %D in the \PDF\ reference manual. The next macro strips illegal %D characters from the destination name. %D %D The \ACROBAT\ programs are not bug free. By setting the next %D switches, we will at least try to prevent problems. \newif\ifovercomePDFbugs \overcomePDFbugsfalse % dest sort problem / 3- \newif\ifovercomePDFspace \overcomePDFspacetrue % dest sort problem / 3- \let\setPDFdestination\gobbleoneargument % a MK specific definition %D \macros %D {sanitizePDFstring} %D %D This macro at least tries to convert a arbitrary string %D into a sequence of characters valid for \PDF\ bookmarks and %D alike. \def\sanitizePDFstring#1\to#2{} %D \macros %D {doPDFdestination, %D doPDFaction, %D doPDFannotation, %D doPDFannotationobject, %D doPDFdictionaryobject, %D doPDFarrayobject, %D doPDFaddtocatalog, %D doPDFaddtoinfo, %D doPDFpageattribute, %D doPDFpageresource, %D doPDFpagesattribute, %D doPDFbookmark, %D defaultobjectreference, %D doPDFgetobjectreference} %D %D This module deals with \PDF\ support, including fill||in %D forms. Before we present the largely unreadable bunch of %D macros, we introduce the here||not||defined low level %D interface macros. These must be provided by the special %D drivers \type{pdf} (\ACROBAT) and \type{tpd} (\PDFTEX). %D %D \starttyping %D \doPDFdestination #1 name %D \doPDFaction #1#2#3 width height action %D \doPDFannotation #1#2#3 width height data %D \doPDFannotationobject #1#2#3#4#5 class name width height data %D \doPDFdictionaryobject #1#2#3 class name data %D \doPDFarrayobject #1#2#3 class name data %D \doPDFaddtocatalog #1 %D \doPDFaddtoinfo #1 %D \doPDFpageattribute #1 %D \doPDFpageresource #1 %D \doPDFpagesattribute #1 %D \doPDFbookmark #1#2#3#4#5 level n text page open %D %D \defaultobjectreference #1#2 class name %D \doPDFgetobjectreference #1#2#3 class name \PDFobjectreference %D \doPDFgetobjectpagereference #1#2#3 class name \PDFobjectreference %D \stoptyping %D %D The keywords reflect their use. For the moment we stick to %D keywords, because that way at we get an indication of what %D we're doing. \startspecials[fdf] %D Common: % \def\doPDFgetobjectreference#1#2#3% % {\def#3{..}} \def\doPDFgetobjectpage#1#2#3% {\dogetobjectreferencepage{#1}{#2}#3% \ifx#3\empty\def#3{\realfolio}\fi} \def\doPDFgetobjectpagereference#1#2#3% {\dogetobjectreferencepage{#1}{#2}#3% \ifx#3\empty \doPDFgetpagereference\realfolio#3% \else \doPDFgetpagereference#3#3% we assume that #3 gets expanded \fi} % \def\doPDFgetpagereference#1#2%%%%%%%%%%%%%%% % {\def#2{...}} %D Due to the fact that \PDFTEX\ has a different concept of %D page attributes, we need: \let\doPDFresetpageattributes\relax \let\doPDFresetpageresources \relax \appendtoksonce \doPDFresetpageattributes \doPDFresetpageresources \to \everyaftershipout \ifx\PDFcode\undefined \ifx\pdfliteral\undefined \def\PDFcode#1{\message{[ignored pdfliteral: #1]}} \else \let\PDFcode\pdfliteral \fi \fi %D For special (\METAPOST) effects, we need to build %D resource dictionaries. Here is the framework. \let\docuPDFextgstates\empty %let\pagePDFextgstates\empty \def\checkPDFextgstates {\ifx\docuPDFextgstates\empty \else \ifnum\realpageno=\lastpage\relax %\doPDFreserveddictionaryobject{FDF}{docuextgstates}{\docuPDFextgstates}% \doPDFdictionaryobject{FDF}{docuextgstates}{\docuPDFextgstates}% \fi \doPDFgetobjectreference{FDF}{docuextgstates}\PDFobjectreference \doPDFpageresource{/ExtGState \PDFobjectreference}% \fi} \appendtoksonce \checkPDFextgstates \to \everyshipout \def\appendtoPDFdocumentextgstates#1% {\xdef\docuPDFextgstates{\docuPDFextgstates\space#1}} %D Patterns (for tikz) \let\docuPDFpatterns\empty \def\checkPDFpatterns {\ifx\docuPDFpatterns\empty \else \ifnum\realpageno=\lastpage\relax \doPDFdictionaryobject{FDF}{docupatterns}{\docuPDFpatterns}% \fi \doPDFgetobjectreference{FDF}{docupatterns}\PDFobjectreference \doPDFpageresource{/Pattern \PDFobjectreference}% \fi} \appendtoksonce \checkPDFpatterns \to \everyshipout \def\appendtoPDFdocumentpatterns#1% {\xdef\docuPDFpatterns{\docuPDFpatterns\space#1}} %D Another special mechanism (needed for color separation): \let\docuPDFcolorspaces\empty \def\checkPDFcolorspaces {\ifx\docuPDFcolorspaces\empty \else \ifnum\realpageno=\lastpage\relax %\doPDFreserveddictionaryobject{FDF}{colorspaces}{\docuPDFcolorspaces}% \doPDFdictionaryobject{FDF}{colorspaces}{\docuPDFcolorspaces}% \fi \doPDFgetobjectreference{FDF}{colorspaces}\PDFobjectreference \doPDFpageresource{/ColorSpace \PDFobjectreference}% \fi} \appendtoksonce \checkPDFcolorspaces \to \everyshipout \def\appendtoPDFdocumentcolorspaces#1% {\xdef\docuPDFcolorspaces{\docuPDFcolorspaces\space#1}} %D And another one (used to be in spec-pdf) \let\docuPDFshades\empty \def\checkPDFshades {\ifx\docuPDFshades\empty \else \ifnum\realpageno=\lastpage\relax %\doPDFreserveddictionaryobject{FDF}{docushades}{\docuPDFshades}% \doPDFdictionaryobject{FDF}{docushades}{\docuPDFshades}% \fi \doPDFgetobjectreference{FDF}{docushades}\PDFobjectreference \doPDFpageresource{/Shading \PDFobjectreference}% \fi} \appendtoksonce \checkPDFshades \to \everyshipout \def\appendtoPDFdocumentshades#1% {\xdef\docuPDFshades{\docuPDFshades\space#1}} %D \macros %D {doPDFsetupscreen,doPDFsetupidentity} %D %D Opposite to \DVI\ drivers, \PDF\ ones must know which what %D page dimensions they are dealing. We also use the %D opportunity to launch full screen (1) or show bookmarks (2). \let\currentPDFpagemode \empty % document catalog \let\currentPDFviewerprefs\empty % document catalog \let\currentPDFcropbox \empty % page attributes \let\currentPDFbleedbox \empty % page attributes \let\currentPDFartbox \empty % page attributes \let\currentPDFtrimbox \empty % page attributes \def\doPDFsetupscreen#1#2#3#4#5#6% watch the extra argument {\bgroup % \!!widtha#4% % \advance\!!widtha#2% % \!!heighta-#5% % \!!heightb#1% extra argument % \advance\!!heightb -#3% % \advance\!!heighta \!!heightb % % sometimes whole values give better results % % \PointsToWholeBigPoints{#2}\left % % \PointsToWholeBigPoints\!!heighta\bottom % % \PointsToWholeBigPoints\!!widtha \width % % \PointsToWholeBigPoints\!!heightb\height % % but since pdf/x does not round when checking if % % the boxes fit inside the media box ... % \PointsToBigPoints{#2}\left % \PointsToBigPoints\!!heighta\bottom % \PointsToBigPoints\!!widtha \width % \PointsToBigPoints\!!heightb\height % \xdef\currentPDFcropboxspec % {[\left\space\bottom\space\width\space\height]}% % \global\let\currentPDFtrimboxspec\currentPDFcropboxspec % % \xdef\currentPDFpagemode % {/PageMode \ifcase#6 % /UseNone\or/FullScreen\or/UseOutlines\else/UseNone\fi}% % \xdef\currentPDFpagemode {\ifnum#6=4 /PageLayout /TwoColumnRight \else /PageMode \ifcase#6 /UseNone\or/FullScreen\or/UseOutlines\else/UseNone\fi \fi}% \xdef\currentPDFviewerprefs % space after #6 needed, else \relax {\ifcase#6 \or\or\else /ViewerPreferences << /FitWindow true >>\fi}% \egroup} % not that good if we switch drivers \def\addPDFdocumentinfo {\doPDFaddtocatalog{\currentPDFpagemode\currentPDFviewerprefs}% \doPDFaddtocatalog{/Version /\PDFversion}% \doPDFaddtoinfo{/Trapped /False}% \doPDFaddtoinfo{/ConTeXt.Version (\contextversion)}% \doPDFaddtoinfo{/ConTeXt.Time (\number\normalyear.\twodigits\normalmonth.\twodigits\normalday\space \twodigits\currenthour:\twodigits\currentminute)}% \doPDFaddtoinfo{/ConTeXt.Jobname (\jobname)}% \doPDFaddtoinfo{/ConTeXt.Url (www.pragma-ade.com)}} \appendtoksonce % hack to prevent duplicates \addPDFdocumentinfo \to \everyfirstshipout \ifx\pdfminorversion\undefined \ifx\pdfoptionpdfminorversion\undefined \newcount\pdfminorversion \else \let\pdfminorversion\pdfoptionpdfminorversion \fi \fi \pdfminorversion=5 \def\PDFversion{1.\number\pdfminorversion} \appendtoksonce \def\PDFversion{1.\the\pdfminorversion}% \let\addPDFdocumentinfo\relax \to \everyresetspecials \def\doPDFsetupwhateverbox#1#2#3#4#5#6% watch the extra arguments {\bgroup \!!widtha \dimexpr#5+#3\relax \!!heightb\dimexpr#2-#4\relax \!!heighta\dimexpr\!!heightb-#6\relax % sometimes whole values give better results % \PointsToWholeBigPoints{#3}\left % \PointsToWholeBigPoints\!!heighta\bottom % \PointsToWholeBigPoints\!!widtha \width % \PointsToWholeBigPoints\!!heightb\height % but since pdf/x does not round when checking if % the boxes fit inside the media box ... \PointsToBigPoints{#3}\left \PointsToBigPoints\!!heighta\bottom \PointsToBigPoints\!!widtha \width \PointsToBigPoints\!!heightb\height \xdef#1{[\left\space\bottom\space\width\space\height]}% \egroup} \def\doPDFsetupartbox {\doPDFsetupwhateverbox\currentPDFartbox } \def\doPDFsetupcropbox {\doPDFsetupwhateverbox\currentPDFcropbox } \def\doPDFsetupbleedbox{\doPDFsetupwhateverbox\currentPDFbleedbox} \def\doPDFsetuptrimbox {\doPDFsetupwhateverbox\currentPDFtrimbox } \gdef\currentPDFtrimbox{\currentPDFcropbox} % default, needed for pdf/x \def\flushPDFwhateverbox#1#2% {\doifsomething{#1}{\doPDFpageattribute{/#2Box #1}}} \def\flushPDFpageboxes {\flushPDFwhateverbox\currentPDFartbox {Art}% \flushPDFwhateverbox\currentPDFcropbox {Crop}% \flushPDFwhateverbox\currentPDFbleedbox{Bleed}% \flushPDFwhateverbox\currentPDFtrimbox {Trim}} \appendtoksonce \flushPDFpageboxes \to \everyshipout % \def\doPDFsetupidentity#1#2#3#4#5#6% % {\bgroup % \enablePDFdocencoding % \edef\!!stringa{#5}% % \ifx\!!stringa\empty \ifx\pdfdate\undefined\else % \edef\!!stringa{D:\pdfdate}% % \fi \fi % \expanded{\doPDFaddtoinfo % {/Title (#1) % /Subject (#2) % /Author (#3) % /Creator (#4) % /ModDate (\!!stringa) % /ID (\jobname.\!!stringa) % needed for pdf/x % /Keywords (#6)}}% % \egroup} \def\doPDFsetupidentity#1#2#3#4#5#6% {\bgroup \enablePDFdocencoding \sanitizePDFencoding#1\to\idtitle \stripstring\idtitle \sanitizePDFencoding#2\to\idsubject\stripstring\idsubject \sanitizePDFencoding#3\to\idauthor \stripstring\idauthor \sanitizePDFencoding#4\to\idcreator\stripstring\idcreator \sanitizePDFencoding#6\to\idkeyword\stripstring\idkeyword \expanded{\doPDFaddtoinfo {/Title \ifPDFunicode<\idtitle >\else(\idtitle )\fi /Subject \ifPDFunicode<\idsubject>\else(\idsubject)\fi /Author \ifPDFunicode<\idauthor >\else(\idauthor )\fi /Creator \ifPDFunicode<\idcreator>\else(\idcreator)\fi /ModDate (#4) /ID (\jobname.#5) % needed for pdf/x /Keywords \ifPDFunicode<\idkeyword>\else(\idkeyword)\fi}}% \egroup} %D \macros %D {doPDFsetupopenaction,doPDFsetupcloseaction, %D doPDFsetupopenpageaction,doPDFsetupclosepageaction} %D %D Setting the open and close actions is kind of fuzzy %D because action chains are derived from the reference %D mechanism. %D Starting with version~5 viewers, when the open actions %D started yto give problems, for testing purposes we %D decided use indirect actions. % \definespecial\dosetupopenaction {\doPDFsetupopenaction} % \definespecial\dosetupcloseaction {\doPDFsetupcloseaction} % \definespecial\dosetupopenpageaction {\doPDFsetupopenpageaction} % \definespecial\dosetupclosepageaction{\doPDFsetupclosepageaction} \let\lastPDFaction\empty %D We can safe a couple of references by moving this code %D to the specific drivers. %D %D The following code used to work okay, but as with any %D update of Acrobat Viewers, upward compatibility was %D just a dream. \definespecial\dosetupopenaction {\doPDFaddtocatalog{/OpenAction <<\lastPDFaction>>}} \definespecial\dosetupcloseaction{\doPDFaddtocatalog{/CloseAction <<\lastPDFaction>>}} % todo: /AA << dictionary in catalog >> % \globalletempty\PDFdocumentclose % \globalletempty\PDFwillsave % \globalletempty\PDFdidsave % \globalletempty\PDFwillprint % \globalletempty\PDFdidprint % \definespecial\dosetupdocumentcloseaction {\global\let\PDFdocumentclose\lastPDFaction} % \definespecial\dosetupwillsaveaction {\global\let\PDFwillsave \lastPDFaction} % \definespecial\dosetupdidsaveaction {\global\let\PDFdidsave \lastPDFaction} % \definespecial\dosetupwillprintaction {\global\let\PDFwillprint \lastPDFaction} % \definespecial\dosetupdidprintaction {\global\let\PDFdidprint \lastPDFaction} % \def\checkPDFdocumentactions % {\iflocation % \doPDFpageattribute % {/AA <<\ifx\PDFdocumentclose\empty \else /DC <<\PDFdocumentclose>> \fi % \ifx\PDFwillsave \empty \else /WS <<\PDFwillsave >> \fi % \ifx\PDFdidsave \empty \else /DS <<\PDFdidsave >> \fi % \ifx\PDFwillprint \empty \else /WP <<\PDFwillprint >> \fi % \ifx\PDFdidprint \empty \else /DP <<\PDFdidprint >> \fi>>}% % % \globalletempty\PDFdocumentclose % % \globalletempty\PDFwillsave % % \globalletempty\PDFdidsave % % \globalletempty\PDFwillprint % % \globalletempty\PDFdidprint % \global\let\checkPDFdocumentactions\relax % \fi} % \appendtoksonce % \checkPDFdocumentactions % \to \everylastshipout %\def\doPDFsetupopenaction% % {\doPDFdictionaryobject{FDF}{local:openaction}\lastPDFaction % \doPDFgetobjectreference{FDF}{local:openaction}\PDFobjectreference % \doPDFaddtocatalog{/OpenAction \PDFobjectreference}} % %\def\doPDFsetupcloseaction% % {\doPDFdictionaryobject{FDF}{local:closeaction}\lastPDFaction % \doPDFgetobjectreference{FDF}{local:closeaction}\PDFobjectreference % \doPDFaddtocatalog{/CloseAction \PDFobjectreference}} \let\PDFopenpageaction \empty \let\PDFclosepageaction\empty \definespecial\dosetupopenpageaction {\global\let\PDFopenpageaction \lastPDFaction} \definespecial\dosetupclosepageaction{\global\let\PDFclosepageaction\lastPDFaction} \def\checkPDFpageactions {\iflocation % important since direct -) \donefalse \ifx\PDFopenpageaction \empty\!!doneafalse\else\donetrue\!!doneatrue\fi \ifx\PDFclosepageaction\empty\!!donebfalse\else\donetrue\!!donebtrue\fi \ifdone \doPDFpageattribute {/AA <<\if!!donea/O <<\PDFopenpageaction >> \fi \if!!doneb/C <<\PDFclosepageaction>> \fi>>}% \fi \global\let\PDFopenpageaction \empty \global\let\PDFclosepageaction\empty \fi} \appendtoksonce \checkPDFpageactions \to \everyshipout %D \macros %D {doPDFstartthisislocation} %D %D Next we define the macros that deal with hyperreferencing, %D graphic inclusion and general document features. These are %D the olderst ones. I won't comment much because one needs %D knowledge of \PDF\ itself, and explaning \PDF\ is beyond %D this documentation. \def\doPDFstartthisislocation#1% {\bgroup \setPDFdestination{#1}% \ifx\PDFdestination\empty \else \doPDFdestination{\PDFdestination}% \fi \egroup} %D \macros %D {doPDFstartgotolocation, %D doPDFstartgotorealpage, %D doPDFstartgotoJS} %D %D The goto macros use the switch \type{\ifsecondaryreference} %D to determine if actions should be linked. \def\locationfilesuffix{pdf} % \def\preparePDFlocationfile#1#2% % {\setreferencefilename#1\to#2% % \expanded{\doifnotinstring{.\locationfilesuffix}{#2}} % {\edef#2{#2.\locationfilesuffix}}} % % \def\preparePDFlocationfile#1\to#2% % {\setreferencefilename#1\to#2% % \expanded{\doifnotinstring{.pdf}{#2}}{\edef#2{#2.pdf}}} \def\doPDFstartgotolocation#1#2#3#4#5#6% {\bgroup \doifelsenothing{#3} {\setPDFdestination{#5}% \doifelsenothing\PDFdestination {\let\action\empty} {\doifelsenothing{#4} {\let\PDFfile\empty} {\expanded{\beforesplitstring#4}\at.\to\PDFfile \doifparentfileelse\PDFfile % {#4} {\let\PDFfile\empty} %{\setreferencefilename#4.\locationfilesuffix\to\PDFfile {\@EA\setreferencefilename\PDFfile.\locationfilesuffix\to\PDFfile \edef\PDFfile {R /F (\PDFfile)\ifgotonewwindow\space/NewWindow true \fi}}}% \edef\action% {/S /GoTo\PDFfile\space /D (\PDFdestination)}}} {\doifelsenothing{#4} {\let\PDFfile\empty \let\PDFdestination\empty} {\setreferencefilename/#4\to\PDFfile \setPDFdestination{#5}% \doifsomething\PDFdestination {\edef\PDFdestination{\URLhash\PDFdestination}}}% \edef\action{/S /URI /URI (#3\PDFfile\PDFdestination)}}% \ifx\action\empty\else \ifsecondaryreference \savesecondaryPDFreference\action \else \getsecondaryPDFreferences \doPDFaction{\PDFswapdir#1}{#2}{\action \secondaryPDFreferences}% \fi \fi \egroup} \def\PDFgotonewwindow{\ifgotonewwindow\space/NewWindow true \fi} % optimization in tpd driver % % \edef\PDFdestination{(page:\the\scratchcounter)}% % % ==> % % \advance\scratchcounter 1 % \edef\PDFdestination{[\pdfpageref \PDFobjref\scratchcounter\PDFpageviewwrd]}% % % \doPDFgetpagedestination#1#2% pagenumber macro % % fuzzy hack \def\doPDFstartgotorealpage#1#2#3#4#5% watch the R append trick {\bgroup \doifelsenothing{#3}% #1 = url {\scratchcounter0#5\relax \ifnum\scratchcounter>0 \doifelsenothing{#4} {\let\PDFfile\empty} {\expanded{\beforesplitstring#4}\at.\to\PDFfile \doifparentfileelse\PDFfile % {#4} {\let\PDFfile\empty} %{\setreferencefilename#4.\locationfilesuffix\to\PDFfile {\@EA\setreferencefilename\PDFfile.\locationfilesuffix\to\PDFfile \edef\PDFfile{R /F (\PDFfile)\PDFgotonewwindow}}}% \ifx\PDFfile\empty \ifcase\overcomePDFpage \or % pdf starts numbering at zero \advance\scratchcounter \minusone \edef\PDFdestination{[\the\scratchcounter\space\PDFpageviewwrd]}% \or % pdf starts numbering at zero \advance\scratchcounter \minusone \edef\PDFdestination{(page:\the\scratchcounter)}% \or % pdftex starts numbering at one \edef\PDFdestination{[\pdfpageref\scratchcounter\space0 R \PDFpageviewwrd]}% \fi \else % across files it's a page number / pdf starts numbering at zero \advance\scratchcounter \minusone \edef\PDFdestination{[\the\scratchcounter\space\PDFpageviewwrd]}% \fi \edef\action{/S /GoTo\PDFfile\space /D \PDFdestination}% \else \let\action\empty \fi} {\doifelsenothing{#4} {\let\PDFfile\empty} {\setreferencefilename/#4\to\PDFfile}% \edef\action{/S /URI /URI (#3\PDFfile)}}% \ifx\action\empty\else \ifsecondaryreference \savesecondaryPDFreference\action \else \getsecondaryPDFreferences \doPDFaction{\PDFswapdir#1}{#2}{\action \secondaryPDFreferences}% \fi \fi \egroup} \let\lastfakedPDFpage\!!zerocount \def\fakePDFpagedestination % as in pdf, we start numbering at zero {\iflocation \ifarrangingpages \else \ifnum\overcomePDFpage=\plustwo \ifnum\lastfakedPDFpage<\realpageno \bgroup \xdef\lastfakedPDFpage{\realfolio}% \advance\realpageno \minusone % is \expanded needed ? \expanded{\doPDFdestination{page:\realfolio}}% \egroup \fi \fi \fi \fi} \appendtoksonce \fakePDFpagedestination \to \everyshipout \def\doPDFstartgotoJS#1#2#3% {\bgroup \doPSsanitizeJScode#3\to\sanitizedJScode \edef\action {/S /JavaScript /JS (\sanitizedJScode)}% \ifsecondaryreference \savesecondaryPDFreference\action \else \getsecondaryPDFreferences \doPDFaction{\PDFswapdir#1}{#2}{\action \secondaryPDFreferences}% \fi \egroup} %D \macros %D {doPDFstartexecutecommand} %D %D At the cost of much auxiliary placeholders, we can pretty %D fast convert the command asked for. This is how the \PDF\ %D code looks like. \def\PDFmoviecode#1#2#3% {/Movie /T (\ifcase#1movie \else sound \fi\ifx\argumentA\empty#2\else\argumentA\fi) /Operation /\ifcase#3Play\or Stop\or Pause\or Resume\fi\space} \def\PDFexecutestartmovie {\PDFmoviecode0\currentmovie0} \def\PDFexecutestopmovie {\PDFmoviecode0\currentmovie1} \def\PDFexecutepausemovie {\PDFmoviecode0\currentmovie2} \def\PDFexecuteresumemovie {\PDFmoviecode0\currentmovie3} \def\PDFexecutestartsound {\PDFmoviecode1\currentsound0} \def\PDFexecutestopsound {\PDFmoviecode1\currentsound1} \def\PDFexecutepausesound {\PDFmoviecode1\currentsound2} \def\PDFexecuteresumesound {\PDFmoviecode1\currentsound3} \def\PDFformcode#1% {\doFDFiffieldset{#1}{/Field [\doFDFgetfieldset{#1}]}} % bit 3 = html % bit 6 = xml % bit 4 = get \ifx\PDFsubmitfiller\undefined \let\PDFsubmitfiller\empty \fi \chardef\PDFformmethod=1 % 0=GET 1=POST \def\PDFformflag#1#2{\ifcase\PDFformmethod#1\else#2\fi} \def\PDFexecuteimportform {/Named /N /AcroForm:ImportFDF} \def\PDFexecuteexportform {/Named /N /AcroForm:ExportFDF} \def\PDFexecuteresetform {/ResetForm \PDFformcode\argumentA} \def\PDFexecutesubmitform {/SubmitForm \PDFformcode\argumentB /Flags \ifcase\submitoutputformat\space \PDFformflag{12} {4} % 0=unknown \or \PDFformflag{12} {4} % 1=HTML \or \PDFformflag {8} {0} % 2=FDF \or \PDFformflag{40}{32} % 3=XML \else \PDFformflag{12} {4} % ?=unknown \fi /F (\argumentA)\PDFsubmitfiller} % urifill permits url substitution \def\PDFexecutehide {/Hide /T (\argumentA) /H true} \def\PDFexecuteshow {/Hide /T (\argumentA) /H false} \def\PDFexecutefirst {/Named /N /FirstPage} \def\PDFexecuteprevious {/Named /N /PrevPage} \def\PDFexecutenext {/Named /N /NextPage} \def\PDFexecutelast {/Named /N /LastPage} \def\PDFexecutebackward {/Named /N /GoBack} \def\PDFexecuteforward {/Named /N /GoForward} \def\PDFexecuteprint {/Named /N /Print} \def\PDFexecuteexit {/Named /N /Quit} \def\PDFexecuteclose {/Named /N /Close} \def\PDFexecutesave {/Named /N /Save} \def\PDFexecutesavenamed {/Named /N /SaveAs} \def\PDFexecuteopennamed {/Named /N /Open} \def\PDFexecutehelp {/Named /N /HelpUserGuide} \def\PDFexecutetoggle {/Named /N /FullScreen} \def\PDFexecutesearch {/Named /N /Find} \def\PDFexecutesearchagain {/Named /N /FindAgain} \def\PDFexecutegotopage {/Named /N /GoToPage} \def\PDFexecutequery {/Named /N /AcroSrch:Query} \def\PDFexecutequeryagain {/Named /N /AcroSrch:NextHit} \def\PDFexecutefitwidth {/Named /N /FitWidth} \def\PDFexecutefitheight {/Named /N /FitHeight} \let\PDFobjectclass\empty \let\PDFobjectname \empty \def\doPDFstartexecutecommand#1#2#3#4% {\doifdefined{PDFexecute#3} {\bgroup \edef\argument{#4}% \ifx\argument\empty \let\argumentA\empty \let\argumentB\empty \else \@EA\dogetcommalistelement\@EA1\@EA\from#4\to\argumentA \@EA\dogetcommalistelement\@EA2\@EA\from#4\to\argumentB \fi \edef\action% {/S \getvalue{PDFexecute#3}}% \ifsecondaryreference \savesecondaryPDFreference\action \else \getsecondaryPDFreferences % \ifx\PDFobjectclass\empty % \let\next\doPDFaction % \else % \edef\next{\doPDFactionobject{\PDFobjectclass}{\PDFobjectname}}% % \globalletempty\PDFobjectclass % \globalletempty\PDFobjectname % \fi % \next \doPDFaction{\PDFswapdir#1}{#2}{\action \secondaryPDFreferences}% \fi \egroup}} %D \macros %D {doPDFstartrunprogram} %D %D Running programs is possible, but is non that portable, and %D therefore dangerous. \def\doPDFstartrunprogram#1#2#3#4% new: #3 => #3#4 {\bgroup %\edef\string{#3}% %\@EA\beforesplitstring\string\at{ }\to\program %\@EA\aftersplitstring \string\at{ }\to\parameters %\edef\action% % {/S /Launch /F (\program) /P (\parameters) /D (.)}% \edef\action {/S /Launch /F (#3) /P (#4) /D (.)}% \ifsecondaryreference \savesecondaryPDFreference\action \else \getsecondaryPDFreferences \doPDFaction{\PDFswapdir#1}{#2}{\action \secondaryPDFreferences}% \fi \egroup} %D \macros %D {doPDFstartgotoprofile} %D %D Far from perfect, but nevertheless present, is the profile %D handler. We want to misuse article threads for reder %D profiles. \def\doPDFstartgotoprofile#1#2#3% to be done: file {\bgroup \setPDFdestination{#3}% \doifsomething\PDFdestination {\edef\action {/S /Thread /D (\PDFdestination)}% \ifsecondaryreference \savesecondaryPDFreference\action \else \getsecondaryPDFreferences \doPDFaction{\PDFswapdir#1}{#2}{\action \secondaryPDFreferences}% \fi}% \egroup} %D \macros %D {doPDFsetpagetransition} %D %D This array holds a reasonable selection of transitions %D (watch out: \type{replace} is not in this list). Most of %D the transitions look awful anyway. By the way, \CONTEXT\ is %D able to select transitions randomly. % some day, when 1.5 is on linux and apple, we will add: % % \def\pagetransitions % {{split,in,vertical},{split,in,horizontal}, % {split,out,vertical},{split,out,horizontal}, % {blinds,horizontal},{blinds,vertical}, % {box,in},{box,out}, % {wipe,east},{wipe,west},{wipe,north},{wipe,south}, % dissolve, % {glitter,east},{glitter,south}, % {fly,in,east},{fly,in,west},{fly,in,north},{fly,in,south}, % {fly,out,east},{fly,out,west},{fly,out,north},{fly,out,south}, % {push,east},{push,west},{push,north},{push,south}, % {cover,east},{cover,west},{cover,north},{cover,south}, % {uncover,east},{uncover,west},{uncover,north},{uncover,south}, % fade} \def\pagetransitions {{split,in,vertical},{split,in,horizontal}, {split,out,vertical},{split,out,horizontal}, {blinds,horizontal},{blinds,vertical}, {box,in},{box,out}, {wipe,east},{wipe,west},{wipe,north},{wipe,south}, dissolve, {glitter,east},{glitter,south}} %D Again, we use macros as placeholders for \PDF\ key||value %D pairs. \def\PDFpagesplit {/S /Split } \def\PDFpageblinds {/S /Blinds } \def\PDFpagebox {/S /Box } \def\PDFpagewipe {/S /Wipe } \def\PDFpagedissolve {/S /Dissolve } \def\PDFpageglitter {/S /Glitter } \def\PDFpagereplace {/S /R } \def\PDFpagefly {/S /Fly } % 1.5 \def\PDFpagepush {/S /Push } % 1.5 \def\PDFpagecover {/S /Cover } % 1.5 \def\PDFpageuncover {/S /Uncover } % 1.5 \def\PDFpagefade {/S /Fade } % 1.5 \def\PDFpagehorizontal {/Dm /H } \def\PDFpagevertical {/Dm /V } \def\PDFpagein {/M /I } \def\PDFpageout {/M /O } \def\PDFpageeast {/Di 0 } \def\PDFpagenorth {/Di 90 } \def\PDFpagewest {/Di 180 } \def\PDFpagesouth {/Di 270 } \def\dodoPDFsetpagetransition#1% {\doifdefined{PDFpage#1} {\edef\PDFpagetransitions{\PDFpagetransitions\getvalue{PDFpage#1}}}} \def\doPDFsetpagetransition#1#2% {\let\PDFpagetransitions\empty \processcommalist[#1]\dodoPDFsetpagetransition \doPDFpageattribute %{\ifnum#2>0 /Dur #2 \fi {\ifnum0<0#2 /Dur #2 \fi \ifx\PDFpagetransitions\empty\else/Trans <<\PDFpagetransitions>>\fi}} % \ifx\PDFpagetransitions\empty\else/Trans <>\fi}} %D \macros %D {doPDFinsertmov} %D %D Most of the annotations we use here are of type {\em %D link}, but here is another one: the {\em movie} annotation. %D The driver module must implement \type {setcurrentmovie}. %D Great: this will become an obsolete pdf feature; why did we have to %D keep up with the bugs ... and by the time acrobat gets better in %D handling it have to drop it. \let\currentmovie\s!unknown \def\doPDFinsertmov {\bgroup \xdef\currentmovie{\@@DriverImageLabel}% \PointsToBigPoints\@@DriverImageWidth \width \PointsToBigPoints\@@DriverImageHeight\height \let\pdf@@options\empty \let\pdf@@actions\empty \donefalse \expanded{\processallactionsinset[\@@DriverImageOptions]} [\v!controls=>\donetrue, \v!repeat=>\edef\pdf@@actions{\pdf@@actions /Mode /Repeat }, \v!preview=>\edef\pdf@@options{\pdf@@options /Poster true }]% \edef\pdf@@actions{\pdf@@actions /ShowControls \ifdone true\else false\fi}% \doPDFannotation\@@DriverImageWidth\@@DriverImageHeight {/Subtype /Movie /Border [0 0 0] /T (movie \currentmovie) /Movie << /F (\@@DriverImageFile) /Aspect [\width\space\height] \pdf@@options >> /A << \pdf@@actions >>}% \egroup} %D \macros %D {doPDFinsertsoundtrack} %D %D In \PDF\ sounds can be embedded like movies. \ifx\everygoto\undefined \newtoks\everygoto \fi \let\currentsound\s!unknown \def\doPDFinsertsoundtrack#1#2#3% {\bgroup \xdef\currentsound{#2}% \let\pdf@@actions\empty \@EA\processallactionsinset\@EA [#3] [\v!repeat=>\edef\pdf@@actions{\pdf@@actions /Mode /Repeat }]% \collectdriverresource %\flushatshipout % since it can be buried in a chained box {\doPDFannotation{0pt}{0pt} {/Subtype /Movie /Border [0 0 0] /T (sound \currentsound) /Movie <>% \ifx\pdf@@actions\empty\else/A << \pdf@@actions >>\fi}}% \egroup} %D \macros %D {doPDFattachfile} \def\doPDFfilestreamobject#1#2#3#4% {} \def\doPDFfilestreamidentifier#1% {0} \def\doPDFgetfilestreamreference#1#2% {0 0 R} \def\doPDFattachfile#1#2#3#4#5#6#7#8% {\bgroup % title width height color symbol file \edefconvertedargument\PDFfile{#8}% % beware: the symbol may (indirectly) use the file % reference when typesetting the object number; \presetPDFsymbolappearance{#5}{#6}{#2}{#3}{#4}% sets width/height \startPDFsymbolappearance \doPDFembedfile\PDFfile{#7}{#8}% \doPDFgetembeddedfilereference\PDFfile\PDFobjectreference \setFDFlayer\@@DriverAttachmentLayer \doPDFannotation{\width}{\totalheight} {/Subtype /FileAttachment /FS \PDFobjectreference\space /Contents (#1) \PDFsymbol \FDFlayer \PDFattributes}% \stopPDFsymbolappearance \egroup} % semi-public \def\doPDFembedfile#1#2#3% symbolic name | filename | user name {\edefconvertedargument\PDFfile{#1}% \doifnotflagged{a:\PDFfile}% {\doPDFfilestreamobject{PDFEF}{\PDFfile}{#2}{#3}% \doglobal\setflag{a:\PDFfile}}} \def\doPDFgetembeddedfilereference#1#2% {\edefconvertedargument\PDFfile{#1}% \doPDFgetobjectreference{PDFEF}\PDFfile#2} \def\doPDFgetembeddedfilestreamreference#1#2% {\edefconvertedargument\PDFfile{#1}% \doPDFgetfilestreamreference\PDFfile#2} % == \doPDFgetobjectreference{PDFFS}\PDFfile#2 \definespecial \doattachfile {\doPDFattachfile} % requested by Jens-Uwe Morawski: permits usage of pdftosrc % in viewers that don't support attachments: % % \definesymbol % [ObjectNumber] % % [object number {\PDFattachmentnumber[xx]}] % named % [object number \PDFattachmentnumber] % current % % \useattachment[test][xx][test.tex] % \setupattachments[symbol=ObjectNumber] % \attachment[test] \def\PDFattachmentnumber {\dosingleargument\doPDFattachmentnumber} \def\doPDFattachmentnumber[#1]% {\iffirstargument \doPDFfilestreamidentifier{#1}% \else \doPDFfilestreamidentifier\PDFfile \fi} %D \macros %D {...} %D %D Rather preliminary. We have to wait till the complete specs %D show up. As usual, we cannot really check it (Acrobat 6.0 %D has a bug that inhibits us to make a test file). Half a day %D of testing made clear that trying to control the plugin fails %D in most cases (we need plugin specs -). We also miss a feature %D to let acrobat wait with proceeding (action processing) till %D the media clip is ready. % aiff audio/aiff % au audio/basic % avi video/avi % mid audio/midi % mov video/quicktime % mp3 audio/x-mp3 (mpeg) % mp4 audio/mp4 % mp4 video/mp4 % mpeg video/mpeg % smil application/smil % swf application/x-shockwave-flash % beware, this is preliminary code, should be improved \def\PDFrenderingspecs#1{\executeifdefined{PDFMR:#1}\empty} \def\PDFexecutestartrendering {/Rendition /OP 0 \PDFrenderingspecs\argumentA} \def\PDFexecutestoprendering {/Rendition /OP 1 \PDFrenderingspecs\argumentA} \def\PDFexecutepauserendering {/Rendition /OP 2 \PDFrenderingspecs\argumentA} \def\PDFexecuteresumerendering {/Rendition /OP 3 \PDFrenderingspecs\argumentA} % todo : sub files % % \doPDFembedfile{pier-39.png}{pier-39.png}{pier-39.png}% % \doPDFgetembeddedfilestreamreference{pier-39.png}\xPDFobjectreference % \edef\xxxx{/RF [(pier-39.png) \xPDFobjectreference]}% % todo: alternative renderings % % object_1 -> <> >> % object_2 -> <> >> % % rendering -> <> % todo: embedded files (too buggy) % % \let\PDFattribute\empty % % /D \PDFobjectreference % % test one, no error, but ignored % \doifinset\v!file{#4} % {\doPDFembedfile{#3}{#3}{#3}% % \doPDFgetembeddedfilestreamreference{#3}\PDFobjectreference % \edef\PDFattribute{/EF \PDFobjectreference}}% % % official, does not work either % \doifinset\v!file{#4} % {\doPDFembedfile{#3}{#3}{#3}% % \doPDFgetembeddedfilereference{#3}\PDFobjectreference} % % do we play the game as follows \definespecial\doinsertrendering#1#2#3#4% tag mime file options {\ifundefined{PDFMR:#1}% \doifinstringelse{://}{#3}\donetrue\donefalse % evt url as keyword \doPDFdictionaryobject{PDFMF}{#1} {/Type /Rendition /S /MR % does not work: /SP << /Type /MediaScreenParam /BE << /B [1 0 0] /O 0.5 >> >> /C << /Type /MediaClip /S /MCD /N (#1) /Alt [() (file not found)] % language id + message /D << /Type /Filespec /F (#3) \ifdone/FS /URL\fi >> /CT (#2) >>}% % common code \doifobjectreferencefoundelse{PDFMS}{#1} {\doPDFgetobjectreference{PDFMS}{#1}\PDFobjectreferenceB} {\doPDFgetobjectreference{PDFMU}{#1}\PDFobjectreferenceB}% \doPDFgetobjectreference{PDFMF}{#1}\PDFobjectreferenceA \setxvalue{PDFMR:#1}% needed /AA actions in /Screen {/R \PDFobjectreferenceA /AN \PDFobjectreferenceB}% \doifobjectreferencefoundelse{PDFMS}{#1}\donothing {\dodoinsertrenderingwindow{PDFMU}{#1}\zeropoint\zeropoint{#4}}% \fi} \definespecial\doinsertrenderingobject#1#2#3#4% tag class objectname options {\ifundefined{PDFMR:#1}% \doPDFgetobjectreference{#2}{#3}\PDFobjectreference \doPDFdictionaryobject{PDFMF}{#1} {/Type /Rendition /S /MR /C << /Type /MediaClip /S /MCD /N (#1) /D \PDFobjectreference>>}% % common code \doifobjectreferencefoundelse{PDFMS}{#1} {\doPDFgetobjectreference{PDFMS}{#1}\PDFobjectreferenceB} {\doPDFgetobjectreference{PDFMU}{#1}\PDFobjectreferenceB}% \doPDFgetobjectreference{PDFMF}{#1}\PDFobjectreferenceA \setxvalue{PDFMR:#1}% needed /AA actions in /Screen {/R \PDFobjectreferenceA /AN \PDFobjectreferenceB}% \doifobjectreferencefoundelse{PDFMS}{#1}\donothing {\dodoinsertrenderingwindow{PDFMU}{#1}\zeropoint\zeropoint{#4}}% \fi} \definespecial\doinsertrenderingwindow {\dodoinsertrenderingwindow{PDFMS}} \def\dodoinsertrenderingwindow#1#2#3#4#5% {\vbox to #4 \bgroup \checkPDFscreenactions{#2}{#5}% \doPDFgetobjectpagereference{PDFMF}{#2}\PDFobjectreferenceA \doPDFgetobjectreference {PDFMF}{#2}\PDFobjectreferenceB \vss \hbox to #3 \bgroup \doPDFannotationobject{#1}{#2}{#3}{#4} {/Subtype /Screen /P \PDFobjectreferenceA /A \PDFobjectreferenceB \PDFattributes /Border [0 0 0]}% \hss \egroup \egroup} \global\let\PDFrenderingopenpageaction \empty \global\let\PDFrenderingclosepageaction\empty \def\checkPDFscreenactions#1#2% {\let\PDFattributes\empty \iflocation % important since direct -) % the action can either (already) be set by the window handler % or (normally when no window [i.e a zero dimensions one] is present) by keyword \doifinset\v!auto{#2} {% brrr, here instead of in navigation module, must move and become special % now two sided dependency \let\checkrendering\gobbleoneargument \ifx\PDFrenderingopenpageaction \empty \handlereferenceactions{\v!StartRendering{#1}}\dosetuprenderingopenpageaction \fi \ifx\PDFrenderingclosepageaction\empty \handlereferenceactions{\v!StopRendering {#1}}\dosetuprenderingclosepageaction \fi }% \donefalse \ifx\PDFrenderingopenpageaction \empty\!!doneafalse\else\donetrue\!!doneatrue\fi \ifx\PDFrenderingclosepageaction\empty\!!donebfalse\else\donetrue\!!donebtrue\fi \ifdone \edef\PDFattributes {/AA <<\if!!donea/PO <<\PDFrenderingopenpageaction >> \fi \if!!doneb/PC <<\PDFrenderingclosepageaction>> \fi>>}% \fi \global\let\PDFrenderingopenpageaction \empty \global\let\PDFrenderingclosepageaction\empty \fi} \definespecial\dosetuprenderingopenpageaction {\global\let\PDFrenderingopenpageaction \lastPDFaction} \definespecial\dosetuprenderingclosepageaction{\global\let\PDFrenderingclosepageaction\lastPDFaction} %D \macros %D {doPDFinsertbookmark} %D %D Well, here is the dreadfull bookmark, rather useless because %D only standard encoding is possible, no typography is done, %D and a maximum of 32~characters is advized. \def\doPDFinsertbookmark#1#2#3#4#5% level sublevels text page open=1 {\bgroup \sanitizePDFencoding#3\to\bookmarktext % uses scratchcounter \stripstring\bookmarktext \doPDFbookmark{#1}{#2}{\bookmarktext}{#4}{#5}% \egroup} %D The next section of this module is dedicated to form %D support. These macros are complicated by the fact that %D cloning is possible. %D \macros %D {FDFflag...,FDFplus...} %D %D The \type{/FT} key determines the type of field: text, %D button or choice. The latter two come in several disguises, %D which are set by flipping bits in the \type{/Ff}. Other bits %D are used to set states. Personally I hate this bitty way of %D doing things. The next six bit determine the field sub type: \def\FDFflagMultiLine {4096} % 13 \def\FDFflagNoToggleToOff {16384} % 15 \def\FDFflagRadio {32768} % 16 (not used as such) \def\FDFflagPushButton {65536} % 17 \def\FDFflagPopUp {131072} % 18 \def\FDFflagEdit {262144} % 19 % bugged anyway, so we need to drop it: \def\FDFflagRadiosInUnison {33554432} % 26 %D A few more (pdf 1.4) flags, what the spell check one: for %D obscure reasons for Adobe downward compatibility means %D enabling features that harm old applications like testing. \def\FDFflagDoNotSpellCheck {4194304} % 23 \def\FDFflagDoNotScroll {8388608} % 24 %D The next bits (watch how strange the bits are organized) %D take care of the states: \def\FDFflagReadOnly {1} % 1 \def\FDFflagRequired {2} % 2 \def\FDFflagNoExport {4} % 3 \def\FDFflagPassword {8192} % 14 \def\FDFflagSort {524288} % 20 \def\FDFflagFileSelect {1048576} % 21 %D There is a second, again bitset oriented, \type{/F} flag: \def\FDFplusInvisible {1} % 1 \def\FDFplusHidden {2} % 2 \def\FDFplusPrintable {4} % 3 %def\FDFplusNoView {32} % 6 %def\FDFplusToggleNoView {256} % 9 \def\FDFplusAutoView {256} % {288} % 6+9 %D \macros %D {setFDFswitches} %D %D The non||type bits are mapped onto user||interface %D swithes, to be used later on: \def\@@FDFflag{FDFflag} \def\@@FDFplus{FDFplus} \letvalue {\@@FDFflag\v!readonly}=\FDFflagReadOnly \letvalue {\@@FDFflag\v!required}=\FDFflagRequired \letvalue {\@@FDFflag\v!protected}=\FDFflagPassword \letvalue {\@@FDFflag\v!sorted}=\FDFflagSort \letvalue {\@@FDFflag\v!unavailable}=\FDFflagNoExport \letvalue {\@@FDFflag\v!nocheck}=\FDFflagDoNotSpellCheck \letvalue {\@@FDFflag\v!fixed}=\FDFflagDoNotScroll \letvalue {\@@FDFflag\v!file}=\FDFflagFileSelect \letvalue {\@@FDFplus\v!hidden}=\FDFplusHidden \letvalue {\@@FDFplus\v!printable}=\FDFplusPrintable \letvalue {\@@FDFplus\v!auto}=\FDFplusAutoView %D A set of switches is collected into the flags we mentioned %D before by the next macro (we don't handle negations yet, %D but do take care of redundancy): \def\FDFflag{0} \def\FDFplus{0} \def\setFDFswitches[#1]% {\bgroup \!!counta\zerocount \!!countb\zerocount \def\docommand##1% {\doifsomething{##1} {\advance\!!counta 0\getvalue{\@@FDFflag##1}% \setvalue{\@@FDFflag##1}{0}% \advance\!!countb 0\getvalue{\@@FDFplus##1}% \setvalue{\@@FDFplus##1}{0}}}% \processcommacommand[#1]\docommand \xdef\FDFflag{\the\!!counta}% \xdef\FDFplus{\the\!!countb}% \egroup} %D \macros %D {setFDFvalues} %D %D Menu items are passed as an array of \type{(string)}'s and %D the content of this array is build with: \let\FDFvalues \empty \let\FDFfirstvalues \empty \let\FDFsecondvalues\empty \let\FDFkidlist \empty \let\FDFdefaultindex\!!zerocount \let\FDFdefaultvalue\empty % Why do we need to tweak this mechanism each time acrobat updates ... % it would make sense to have version specific sections in pdf files % since my guess is that it never will be done right since each year % new programmers have new ideas about what is supposed to happen with % kids. So .. best is not to trust this feature esp not for radio % widgets. (new flags, different interpretation of AS etc etc) \def\setFDFvalues[#1][#2]% #1 = list (item=>value) #2 = default {\let\FDFvalues \empty %when radio opt works ok %\let\FDFfirstvalues \empty %\let\FDFsecondvalues\empty \let\FDFkidlist \empty %\let\FDFdefaultindex\!!zerocount %\let\FDFdefaultvalue\empty %\scratchcounter\zerocount \def\dodocommand##1=>##2=>##3\end {\addtocommalist{##1}\FDFkidlist %\edef\FDFfirstvalues{\FDFfirstvalues(##1)}% %\doif{##1}{#2}{\edef\FDFdefaultindex{\the\scratchcounter}}% %\advance\scratchcounter\plusone \doifelsenothing{##2} {\doif{##1}{#2}{\edef\FDFdefaultvalue{##1}}% %\edef\FDFsecondvalues{\FDFsecondvalues(##1)}% \edef\FDFvalues{\FDFvalues [(##1)(##1)] }} {\doif{##1}{#2}{\edef\FDFdefaultvalue{##2}}% %\edef\FDFsecondvalues{\FDFsecondvalues(##2)}% \edef\FDFvalues{\FDFvalues [(##2)(##1)] }}}% ! ##1 is shown \def\docommand##1% {\dodocommand##1=>=>\end}% \expanded{\processcommalist[#1]}\docommand} %D This macro accepts comma separated \type{visual=>result} %D pairs. %D \macros %D {setFDFalignment} %D %D Text and line fields can be entered and showed in three %D alternative alingments, indicated by a digit: \def\FDFalign{0} \def\setFDFalignment[#1]% {\processaction [#1] [ \v!left=>\edef\FDFalign{2}, % raggedleft \v!middle=>\edef\FDFalign{1}, % raggedcenter \v!right=>\edef\FDFalign{0}]} % raggedright %D \macros %D {setFDFattributes} %D %D The weak part of (at least version 2.1 \PDF) is that only %D default fonts are handled well. Another restriction is that %D the encoding vector must be the standard \PDF\ document one. %D Although the \PDF\ reference explictly states that one could %D use the normal text operators, leading is not yet handled. %D %D For the moment the current \CONTEXT\ font is mapped onto %D one best suitable default font. The color attribute is %D less problematic and is directly derived from the \CONTEXT\ %D color. \def\FDFattributes{/Helv 12 Tf 0 g 14.4 TL} \def\FDFrm {TiRo} \def\FDFss {Helv} \def\FDFtt {Cour} \def\FDFrmtf{TiRo} \def\FDFsstf{Helv} \def\FDFtttf{Cour} \def\FDFrmbf{TiBo} \def\FDFssbf{HeBo} \def\FDFttbf{CoBo} \def\FDFrmit{TiIt} \def\FDFssit{HeOb} \def\FDFttit{CoOb} \def\FDFrmsl{TiIt} \def\FDFsssl{HeOb} \def\FDFttsl{CoOb} \def\FDFrmbi{TiBI} \def\FDFssbi{HeBO} \def\FDFttbi{CoBO} \def\FDFrmbs{TiBI} \def\FDFssbs{HeBO} \def\FDFttbs{CoBO} \let\FDFusedfonts=\FDFsstf \def\setFDFattributes[#1,#2,#3,#4]% style, color, backgroundcolor, framecolor {\bgroup % nog interlinie: n TL \setbox\scratchbox\hbox \bgroup \doconvertfont{#1}{}% \PointsToBigPoints\bodyfontsize\size % x/xx, so better the actual size \doifdefinedelse{FDF\fontstyle\fontalternative} {\xdef\FDFattributes{\getvalue{FDF\fontstyle\fontalternative}}} {\doifdefinedelse{FDF\fontstyle} {\xdef\FDFattributes{\getvalue{FDF\fontstyle}}} {\xdef\FDFattributes{\FDFrm}}}% \doglobal\addtocommalist\FDFattributes\FDFusedfonts \xdef\FDFattributes% move up with "x.y Ts" {/\FDFattributes\space\size\space Tf\space\PDFcolor{#2}}% \doifelsenothing{#3} {\global\let\FDFsurroundings\empty} {\xdef\FDFsurroundings{/BG \FDFcolor{#3}}}% \doifsomething{#4} {\xdef\FDFsurroundings{\FDFsurroundings\space /BC \FDFcolor{#4}}}% \ifx\FDFsurroundings\empty \else \xdef\FDFsurroundings{/MK << \FDFsurroundings\space>>}% \fi \egroup \egroup} %D \macros %D {setFDFactions} %D %D Depending on the type of the field, one can assign %D \JAVASCRIPT\ code to a mouse event or keystroke. The next %D preparation macro shows what events are handled. \let\FDFactions\empty \def\setFDFactions[#1,#2,#3,#4,#5,#6,#7,#8,% {\global\let\FDFactions\empty \setFDFaction D#1\relax% mousedown \setFDFaction U#2\relax% mouseup \setFDFaction E#3\relax% enterregion \setFDFaction X#4\relax% exitregion \setFDFaction K#5\relax% afterkeystroke \setFDFaction F#6\relax% formatresult \setFDFaction V#7\relax% validateresult \setFDFaction C#8\relax% calculatewhatever \setFDFactionsmore} \def\setFDFactionsmore#1,#2]% {\setFDFaction{Fo}#1\relax% focusin \setFDFaction{Bl}#2\relax% focusout % was I (now pdf ref manual explicitly talks about lowercase l) \ifx\FDFactions\empty\else \xdef\FDFactions{/AA << \FDFactions >>}% since 1.3 no longer inherited \fi} % todo, when new var scheme is implemented % % \setFDFaction{PO}\@@DriverFieldPageOpen\relax % \setFDFaction{PC}\@@DriverFieldPageClose\relax % \setFDFaction{PV}\@@DriverFieldPageVisible\relax % \setFDFaction{PI}\@@DriverFieldPageInVisible\relax %D The event handler becomes something: %D %D \starttyping %D /AA << /D << /S ... >> ... /C << /S ... >> %D /A << /S /JavaScript /JS (...) >> %D \stoptyping % \def\setFDFaction#1#2\relax% % {\bgroup % \global\let\sanitizedJScode\empty % \def\setFDFaction##1% % {\doifreferencefoundelse{##1} % {\doifelse{\currentreferencespecial}{JS} % filter non-js % {\presetJScode % \currentreferenceoperation % \currentreferencearguments % \doPSsanitizeJScode\JScode\to\JScode % \xdef\sanitizedJScode{\sanitizedJScode\space\JScode}} % {\illegalreference{##1}}} % {\unknownreference{##1}}}% % \@EA\processcommalist\@EA[#2]\setFDFaction % one level expansion % \ifx\sanitizedJScode\empty \else % \xdef\FDFactions% % {\FDFactions /#1 << /S /JavaScript /JS (\sanitizedJScode) >> }% % \fi % \egroup} % % acrobat 5 supports other that JS actions too \def\setFDFaction#1#2\relax% {\bgroup \def\docommand{\xdef\FDFactions{\FDFactions /#1 << \lastPDFaction >> }}% \@EA\handlereferenceactions\@EA{#2}\docommand % one level expansion \egroup} %D \macros %D {testFDFactions} %D %D This rather confusion prone series of script can be tested %D with: %D %D \starttyping %D \testFDFactions %D \stoptyping %D %D which simply redefined the previous macro to one that prints %D a message to the console. \def\testFDFactions {\def\setFDFaction##1##2\relax% {\doPSsanitizeJScode console.show();console.println("executing:##1"); \to\sanitizedJScode \edef\FDFactions{\FDFactions /##1 << /S /JavaScript /JS (\sanitizedJScode) >> }}} %D \macros %D {doFDFregistercalculationset} %D %D There is at most one calculation order list, which defines %D the order in which fields are calculated. \let\PDFcalculationset\empty \def\doFDFregistercalculationset#1% {\def\PDFcalculationset{#1}} %D \macros %D {registerFDFobject,everylastshipout} %D %D Officially one needs to embed some general datastructures %D that tell the viewer what fields are present in the file, as %D well as what resources they use. The next mechanism does that %D job automatically when one registers the field. \def\flushFDFnames {\ifbuildFDFdictionary \ifx\FDFcollection\empty\else \ifbuildFDFencodingvector \doPDFdictionaryobject{FDF}{local:encodingvector}{\FDFencodingvector}% \fi \defineFDFfonts \doPDFarrayobject{FDF}{local:fields}{\FDFcollection}% \doPDFgetobjectreference{FDF}{local:fields}\PDFobjectreference % The /NeedAppearances is pretty important because % otherwise Acrobat 5 blows up on cloned radio widgets \doPDFdictionaryobject{FDF}{local:acroform} {/Fields \PDFobjectreference\space /NeedAppearances true \doFDFiffieldset\PDFcalculationset{/CO [\doFDFgetfieldset\PDFcalculationset]} /DR << /Font << \FDFfonts >> >> /DA (/Helv 10 Tf 0 g)}% \doPDFgetobjectreference{FDF}{local:acroform}\PDFobjectreference \doPDFaddtocatalog {/AcroForm \PDFobjectreference}% \global\let\FDFcollection\empty \global\let\flushFDFnames\relax \fi \fi} \let\FDFcollection\empty \def\registerFDFobject#1% {\ifbuildFDFdictionary \ifx\flushFDFnames\relax \writestatus{FDF}{second run needed for field list (#1)}% \fi \doPDFgetobjectreference{FDF}{#1}\PDFobjectreference \xdef\FDFcollection{\FDFcollection\space\PDFobjectreference}% \fi} \appendtoksonce \flushFDFnames \to \everylastshipout % test \everybye / was \prependtoksonce %D \macros %D {defineFDFfonts, %D ifbuildFDFdictionary, %D ifbuildFDFencodingvector} %D %D Another datastruture concerns the fonts used. We only %D define the fonts we use. \newif\ifbuildFDFdictionary \buildFDFdictionarytrue \newif\ifbuildFDFencodingvector \buildFDFencodingvectortrue \def\defineFDFfonts {\let\FDFfonts\empty \processcommacommand[\FDFusedfonts]\defineFDFfont} \def\defineFDFfont#1% {\ifbuildFDFencodingvector \doPDFgetobjectreference{FDF}{local:encodingvector}\PDFobjectreference \fi \doPDFdictionaryobject{FDF}{local:#1} {/Type /Font /Subtype /Type1 /Name /#1 \ifbuildFDFencodingvector /Encoding \PDFobjectreference\space\fi /BaseFont /\getvalue{FDFname#1}}% \doPDFgetobjectreference{FDF}{local:#1}\PDFobjectreference \edef\FDFfonts{\FDFfonts \space/#1 \PDFobjectreference}} %D Another list of constants: \def\FDFnameTiRo {Times-Roman} \def\FDFnameTiBo {Times-Bold} \def\FDFnameTiIt {Times-Italic} \def\FDFnameTiBI {Times-BoldItalic} \def\FDFnameHelv {Helvetica} \def\FDFnameHeBo {Helvetica-Bold} \def\FDFnameHeOb {Helvetica-Oblique} \def\FDFnameHeBO {Helvetica-BoldOblique} \def\FDFnameCour {Courier} \def\FDFnameCoBo {Courier-Bold} \def\FDFnameCoOb {Courier-Oblique} \def\FDFnameCoBO {Courier-BoldOblique} %D And a big one: (should be run time loaded (spec-run or %D so)). \def\FDFencodingvector {/Type /Encoding /Differences [ 24 /breve /caron /circumflex /dotaccent /hungarumlaut /ogonek /ring /tilde 39 /quotesingle 96 /grave 128 /bullet /dagger /daggerdbl /ellipsis /emdash /endash /florin /fraction /guilsinglleft /guilsinglright /minus /perthousand /quotedblbase /quotedblleft /quotedblright /quoteleft /quoteright /quotesinglbase /trademark /fi /fl /Lslash /OE /Scaron /Ydieresis /Zcaron /dotlessi /lslash /oe /scaron /zcaron 164 /currency 166 /brokenbar 168 /dieresis /copyright /ordfeminine 172 /logicalnot /.notdef /registered /macron /degree /plusminus /twosuperior /threesuperior /acute /mu 183 /periodcentered /cedilla /onesuperior /ordmasculine 188 /onequarter /onehalf /threequarters 192 /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis ]} %D \macros %D {currentFDFmode,currentFDFparent,currentFDFkids,currenrFDFroot} %D %D There are three more quasi global interfacing variables %D that need to be set. \let\currentFDFmode =\fieldlonermode \let\currentFDFkids =\empty \let\currentFDFparent=\empty \let\currentFDFroot =\empty %D \macros %D {dosetfieldstatus} %D %D And here comes the special that deals with them. \definespecial\dosetfieldstatus#1#2#3#4% {\chardef\currentFDFmode #1% \edef\currentFDFparent {#2}% \edef\currentFDFkids {#3}% \edef\currentFDFroot {#4}} %D \macros %D {dosetuppageview} %D %D Because this command will seldom be called, we can permit %D slow action processing. We need three settings, one for %D direct \PDF\ inclusion, the other as \PDFTEX\ keyword, an %D a last one for form. All determine in what way the %D screen is adapted when going to a destination. Watch the %D space. \def\PDFpageviewkey{fit} \def\PDFpageviewwrd{/Fit} \def\PDFpageview {/View [\PDFpageviewwrd] } \let\PDFpagexyzspec\relax % 0 0 0 hack, pdftex does handle this, for dvipdfmx we need height \def\dosetuppageview#1% watch the v-h swapping here {\processaction [#1] [ \v!fit=>\def\PDFpageviewkey {fit}\def\PDFpageviewwrd{/Fit}, \v!width=>\def\PDFpageviewkey {fith}\def\PDFpageviewwrd{/FitH}, \v!height=>\def\PDFpageviewkey {fitv}\def\PDFpageviewwrd{/FitV}, \v!minwidth=>\def\PDFpageviewkey{fitbh}\def\PDFpageviewwrd{/FitBH}, \v!minheight=>\def\PDFpageviewkey{fitbv}\def\PDFpageviewwrd{/FitBV}, \v!standard=>\ifx\PDFpagexyzspec\relax % empty does not work too wel with dpx \def\PDFpageviewkey{fit}% \def\PDFpageviewwrd{/Fit}% \else \edef\PDFpageviewkey{xyz \PDFpagexyzspec}% \edef\PDFpageviewwrd{/XYZ \PDFpagexyzspec}% \fi, \s!unknown=>\def\PDFpageviewkey {fit}\def\PDFpageviewwrd{/Fit}]% \edef\PDFpageview{\ifx\PDFpageviewwrd\empty\else/View [\PDFpageviewwrd]\fi}} %D \macros %D {setFDFkids} %D %D Clones as well as radiofields (which themselves can have %D cloned components) need a list of kids. The next macro %D builds one. \def\setFDFkids[#1][#2]% tag commalist {\let\FDFkids\empty \def\docommand##1% {\doPDFgetobjectreference{FDF}{#1##1}\PDFobjectreference \edef\FDFkids{\FDFkids\PDFobjectreference\space}}% \@EA\processcommalist\@EA[#2]\docommand \ifx\FDFkids\empty\else\edef\FDFkids{/Kids [\FDFkids]}\fi % \edef\FDFkids{/Kids [\FDFkids]}% } %D \macros %D {doFDFpresetlinefield,doFDFpresettextfield, %D doFDFpresetchoicefield,doFDFpresetpopupfield,doFDFpresetcombofield, %D doFDFpresetpushfield,doFDFpresetcheckfield, %D doFDFpresetfield,doFDFpresetradiorecord} %D %D I would say: read the \PDF\ reference manual first and see %D what happens here next. Lucky us that they have so much in %D common. \def\doFDFpresetlinefield#1#2#3#4#5#6#7#8#9% {\bgroup \setFDFlayer\@@DriverFieldLayer \setFDFswitches[#7]% \setFDFattributes[#6]% \setFDFalignment[#8]% \setFDFactions[#9]% \expanded{\escapePSstring#4}\to\FDFtext \ifcase\currentFDFmode \doPDFannotationobject{FDF}{#1}{#2}{#3} {/Subtype /Widget /T (#1) /FT /Tx /MaxLen \ifcase0#5 1000 \else#5 \fi %/DV (#4) /V (#4) % value added /DV (\FDFtext) /V (\FDFtext) % value added /Ff \FDFflag\space /F \FDFplus\space /DA (\FDFattributes) \FDFlayer\space \FDFsurroundings\space /Q \FDFalign\space \FDFactions}% \registerFDFobject{#1}% \or \setFDFkids[kids:][\currentFDFkids]% \doPDFdictionaryobject{FDF}{#1} {/T (#1) /FT /Tx /MaxLen \ifcase0#5 1000 \else#5 \fi \FDFkids\space %/DV (#4) /V (#4) % value added /DV (\FDFtext) /V (\FDFtext) % value added /Ff \FDFflag\space /F \FDFplus\space /DA (\FDFattributes) \FDFlayer\space \FDFsurroundings\space /Q \FDFalign\space \FDFactions}% \registerFDFobject{#1}% \or \doPDFgetobjectreference{FDF}\currentFDFparent\PDFobjectreference %\global\objectreferencingtrue \doPDFannotationobject{FDF}{kids:#1}{#2}{#3} {/Subtype /Widget /Parent \PDFobjectreference /Ff \FDFflag\space /F \FDFplus\space /DA (\FDFattributes) \FDFlayer\space \FDFsurroundings\space /Q \FDFalign\space \FDFactions}% \or \doPDFgetobjectreference{FDF}\currentFDFparent\PDFobjectreference %\global\objectreferencingtrue \doPDFannotationobject{FDF}{kids:#1}{#2}{#3} {/Subtype /Widget /Parent \PDFobjectreference /F \FDFplus \FDFactions}% \fi \egroup} \def\doFDFpresettextfield#1#2#3#4#5#6#7#8#9% {\doFDFpresetlinefield{#1}{#2}{#3}{#4}{#5}{#6}{MultiLine,#7}{#8}{#9}} \def\doFDFpresetchoicefield#1#2#3#4#5#6#7#8% {\bgroup \setFDFlayer\@@DriverFieldLayer \setFDFswitches[#6]% \setFDFattributes[#5]% \setFDFvalues[#7][#4]% \setFDFactions[#8]% \ifcase\currentFDFmode \doPDFannotationobject{FDF}{#1}{#2}{#3} {/Subtype /Widget /T (#1) /FT /Ch /DV (#4) /V (#4) /Ff \FDFflag\space /F \FDFplus\space /DA (\FDFattributes) \FDFlayer\space \FDFsurroundings\space /Opt [\FDFvalues] \FDFactions}% \registerFDFobject{#1}% \or \setFDFkids[kids:][\currentFDFkids]% \doPDFdictionaryobject{FDF}{#1} {/T (#1) /FT /Ch \FDFkids\space /DV (#4) /V (#4) /Ff \FDFflag\space /F \FDFplus\space /DA (\FDFattributes) \FDFlayer\space \FDFsurroundings\space /Opt [\FDFvalues] \FDFactions}% \registerFDFobject{#1}% \or \doPDFgetobjectreference{FDF}\currentFDFparent\PDFobjectreference %\global\objectreferencingtrue \doPDFannotationobject{FDF}{kids:#1}{#2}{#3} {/Subtype /Widget /Parent \PDFobjectreference /Ff \FDFflag\space /F \FDFplus\space /DA (\FDFattributes) \FDFlayer\space \FDFsurroundings\space \FDFactions}% \or \doPDFgetobjectreference{FDF}\currentFDFparent\PDFobjectreference %\global\objectreferencingtrue \doPDFannotationobject{FDF}{kids:#1}{#2}{#3} {/Subtype /Widget /Parent \PDFobjectreference /F \FDFplus \FDFactions}% \fi \egroup} \def\doFDFpresetpopupfield#1#2#3#4#5#6#7#8% {\doFDFpresetchoicefield{#1}{#2}{#3}{#4}{#5}{PopUp,#6}{#7}{#8}} \def\doFDFpresetcombofield#1#2#3#4#5#6#7#8% {\doFDFpresetchoicefield{#1}{#2}{#3}{#4}{#5}{PopUp,Edit,#6}{#7}{#8}} \newif\ifFDFvalues \def\doFDFpresetpushcheckfield#1#2#3#4#5#6#7#8% in acro<5 (\FDFdefault) {\bgroup % in acro>5 /\FDFdefault \setFDFlayer\@@DriverFieldLayer \ifcase#8\relax\FDFvaluesfalse\else\FDFvaluestrue\fi \setFDFswitches[#5]% \setFDFactions[#7]% \doifelse{#4}{1} {\def\FDFdefault{On}} {\def\FDFdefault{Off}}% \ifcase\currentFDFmode \doFDFappearance{On}{#6}{#8}% \doPDFannotationobject{FDF}{#1}{#2}{#3} {/Subtype /Widget /T (#1) /FT /Btn \ifFDFvalues /DV /\FDFdefault\space /V /\FDFdefault\space /AS /\FDFdefault\space \fi \FDFlayer /Ff \FDFflag\space /F \FDFplus\space \FDFlayer\space \FDFappearance\space % /IF << /SW /N >> % strange, only works for stupid buttons \FDFactions}% \registerFDFobject{#1}% \or % no appearance and layer ? \setFDFkids[kids:][\currentFDFkids]% \doPDFdictionaryobject{FDF}{#1} {/T (#1) /FT /Btn \FDFkids\space \ifFDFvalues /DV /\FDFdefault\space /V /\FDFdefault\space /AS /\FDFdefault\space \fi /Ff \FDFflag\space /F \FDFplus\space \FDFactions}% \registerFDFobject{#1}% \or \doFDFappearance{On}{#6}{#8}% \doPDFgetobjectreference{FDF}\currentFDFparent\PDFobjectreference %\global\objectreferencingtrue \doPDFannotationobject{FDF}{kids:#1}{#2}{#3} {/Subtype /Widget /Parent \PDFobjectreference\space \ifFDFvalues /DV /\FDFdefault\space /V /\FDFdefault\space /AS /\FDFdefault\space \fi /Ff \FDFflag\space /F \FDFplus\space \FDFlayer\space \FDFappearance\space \FDFactions}% \or \doFDFappearance{On}{#6}{#8}% \doPDFgetobjectreference{FDF}\currentFDFparent\PDFobjectreference %\global\objectreferencingtrue \doPDFannotationobject{FDF}{kids:#1}{#2}{#3} {/Subtype /Widget /Parent \PDFobjectreference\space /F \FDFplus\space \ifFDFvalues /DV /\FDFdefault\space /V /\FDFdefault\space /AS /\FDFdefault\space \fi \FDFlayer\space \FDFappearance \FDFactions}% \fi \egroup} \def\doFDFpresetpushfield#1#2#3#4#5#6#7% {\doFDFpresetpushcheckfield{#1}{#2}{#3}{#4}{PushButton,#5}{#6}{#7}{0}} \def\doFDFpresetcheckfield#1#2#3#4#5#6#7% {\doFDFpresetpushcheckfield{#1}{#2}{#3}{#4}{#5}{#6}{#7}{1}} % As pdf widgets are rather consistently upward incompatible % especially with regards to inheritance, the following code is not % quite okay. I've decided no longer to bother about in it in MkII % and use a flat model in MkIV which somehow seems to work better. \def\doFDFpresetradiofield#1#2#3#4#5#6#7#8% {\bgroup \setFDFlayer\@@DriverFieldLayer \FDFvaluestrue \setFDFswitches[#5]% \setFDFactions[#8]% \doifelsenothing{#4} {\def\FDFdefault{Off}} {\def\FDFdefault{#4}}% \@EA\aftersplitstring\FDFdefault\at=>\to\FDFdefaultvalue \ifx\FDFdefaultvalue\empty\else\let\FDFdefault\FDFdefaultvalue\fi \ifcase\currentFDFmode \doFDFappearance{#1}{#7}{1}% \doPDFgetobjectreference{FDF}{#6}\PDFobjectreference \doPDFannotationobject{FDF}{#1}{#2}{#3} {/Subtype /Widget /Parent \PDFobjectreference\space /F \FDFplus\space /AS /\FDFdefault\space \FDFlayer\space \FDFappearance\space \FDFactions}% \registerFDFobject{#1}% \or \setFDFkids[kids:][\currentFDFkids]% \doPDFgetobjectreference{FDF}{#6}\PDFobjectreference \doPDFdictionaryobject{FDF}{#1} {/Parent \PDFobjectreference\space \FDFkids\space /F \FDFplus\space \FDFactions}% \registerFDFobject{#1}% \or %\doFDFappearance{#1}{#7}{1}% \doFDFappearance{\currentFDFparent}{#7}{1}% \doPDFgetobjectreference{FDF}\currentFDFparent\PDFobjectreference %\global\objectreferencingtrue % nb \doPDFannotationobject{FDF}{kids:#1}{#2}{#3} {/Subtype /Widget /Parent \PDFobjectreference\space /AS /\FDFdefault\space /F \FDFplus\space \FDFlayer\space \FDFappearance\space \FDFactions}% \or %\doFDFappearance{#1}{#7}{1}% \doFDFappearance{\currentFDFparent}{#7}{1}% \doPDFgetobjectreference{FDF}\currentFDFparent\PDFobjectreference %\global\objectreferencingtrue \doPDFannotationobject{FDF}{kids:#1}{#2}{#3} {/Subtype /Widget /Parent \PDFobjectreference\space /AS /\FDFdefault\space /F \FDFplus\space \FDFlayer\space \FDFappearance\space \FDFactions}% \fi \egroup} %D \macros %D {setFDFstrings} %D %D This one creates a string array. %\def\setFDFstrings[#1]% % {\let\FDFstrings\empty % \def\docommand##1{\edef\FDFstrings{\FDFstrings(##1)}}% % \processcommacommand[#1]\docommand} % Beware, RadiosInUnison is really needed in the pre 1.5/6 time this % was the default but out of a sudden it's no longer the case. Also % the NoToggleToOff interferes with kids of kids and both it will % break older documents, i.e. so much for pdf as standard. With % features like widgets we can probably best wait till adobe tools % themselves support it because that's probably the moment that % functionality gets frozen/becomes definitive. Actually, acrobat % flattens the kids tree, so that's yet another situation. The % interesting thing is that it worked ok in acrobat 2/3 but got bugged % in later versions. [The rationale is in html compatibility, which % seems to be more important than compatibility of documents, which in % turn renders acrobat useless for forms.] Anyway, synchronization is % broken or not depending on the combination pdfversion/acrobatversion. % % Hm, nowadays Radio will overload RadiosInUnison so we need to use only one % of them. \def\doFDFpresetradiorecord#1#2#3#4#5% {\bgroup % < pdf 1.5 (1.5 was broken) % \setFDFswitches[Radio,NoToggleToOff,RadiosInUnison,#3]% % > pdf 1.5 % \setFDFswitches[Radio,RadiosInUnison,#3]% % > pdf 1.6 \setFDFswitches[RadiosInUnison,#3]% %setFDFswitches[PushButton,RadiosInUnison,#3]% this is what acrobat itself does % older, else fatal error % \setFDFkids[#4][]% % newer \setFDFvalues[#4][#2]% inits kidlist \expanded{\setFDFkids[][\FDFkidlist]}% % \setFDFactions[#5]% \doPDFdictionaryobject{FDF}{#1} {%/Subtype /Widget /FT /Btn /T (#1) /Rect [0 0 0 0] % used to be this % /V (#2) % then this % /DV (#2) % since this bomded in 5 % /V (#2) % and now finally this works /H /N % /opt is buggy in 5.05, only works once, sigh %\ifx\FDFfirstvalues\FDFsecondvalues /V /#2 %\else % /V /\FDFdefaultindex\space % /Opt [\FDFsecondvalues] %\fi /Ff \FDFflag\space /F \FDFplus\space \FDFkids\space \FDFactions}% \egroup} %D At the cost of some more references, we can save bytes, %D by sharing appearance dictionaries. This code needs more %D documentation. Surprise: \def\dodoFDFappearance#1#2% {\ifx#2\empty\else \dogetcommacommandelement1\from#2\to\commalistelement \ifx\commalistelement\empty\else \doPDFgetobjectreference{SYM}\commalistelement\PDFobjectreference \edef\N{\ifFDFvalues\N /#1 \fi\PDFobjectreference\space}% \fi \dogetcommacommandelement2\from#2\to\commalistelement \ifx\commalistelement\empty\else \doPDFgetobjectreference{SYM}\commalistelement\PDFobjectreference \edef\R{\ifFDFvalues\R /#1 \fi\PDFobjectreference\space}% \fi \dogetcommacommandelement3\from#2\to\commalistelement \ifx\commalistelement\empty\else \doPDFgetobjectreference{SYM}\commalistelement\PDFobjectreference \edef\D{\ifFDFvalues\D /#1 \fi\PDFobjectreference\space}% \def\FDFappearance{/H /P }% \fi \fi} \def\redoFDFappearance#1% {\ifx#1\empty\else \dogetcommacommandelement3\from#1\to\commalistelement \ifx\commalistelement\empty\else \def\FDFappearance{/H /P }% \fi \fi} \def\doFDFappearance#1#2#3% {\ifcase#3\relax % push only field \edef\yes{#2}% \let\no\empty \else % on / off field \dogetcommacommandelement1\from#2,\to\yes \dogetcommacommandelement2\from#2,\to\no \fi \def\FDFappearance{/H /N}% \doifobjectfoundelse{FDF}{ap:#1:\yes:\no} {\redoFDFappearance\yes \redoFDFappearance\no} {\presetobject{FDF}{ap:#1:\yes:\no}% funny hack \let\N\empty\let\R\empty\let\D\empty \dodoFDFappearance{#1}\yes \dodoFDFappearance{Off}\no \doPDFdictionaryobject{FDF}{ap:#1:\yes:\no} {\ifx\N\empty\else/N \ifFDFvalues<<\N>>\else\N\fi\fi \ifx\R\empty\else/R \ifFDFvalues<<\R>>\else\R\fi\fi \ifx\D\empty\else/D \ifFDFvalues<<\D>>\else\D\fi\fi}}% \doPDFgetobjectreference{FDF}{ap:#1:\yes:\no}\PDFobjectreference \edef\FDFappearance{\FDFappearance /AP \PDFobjectreference}} %\def\doFDFdefault#1#2% % {\dogetcommacommandelement1\from#1,\to\commalistelement % \dogetcommacommandelement1\from\commalistelement\to\commalistelement % \doifelse{\commalistelement}{#2} % kan ook met \ifx % {\def\FDFdefault{On}}{\def\FDFdefault{Off}}} \def\doFDFdefault#1#2% {\doifelse{#2}{1}{\def\FDFdefault{On}}{\def\FDFdefault{Off}}} %D Layer support: \def\setFDFlayer#1% todo : \ifx\PDFobjectreference\noPDFobjectreference ipv found {\letempty\FDFlayer \doifsomething{#1}% {\checkproperty[#1]% == \dodocheckproperty\@@DriverFieldLayer \doifobjectreferencefoundelse{PDLN}{#1} {\doPDFgetobjectreference{PDLN}{#1}\!!stringa % we need to avoid a clash with other macros \edef\FDFlayer{/OC \!!stringa}}% \donothing}} %D The three appearances {\em normal}, \type{roll over} and %D \type{push down} are passed as comma separated triplets, %D that is, the second argument can look like: %D %D \starttyping %D {yes,ok,fine},{no,rubish,awful} %D \stoptyping %D \macros %D {doFDFdefinefieldset,doFDFgetfieldset,doFDFiffieldset} %D %D Field sets, the ones we use in submitting and resetting %D fields, are implemented using the next low level specials: %D %D \starttyping %D \doFDFdefinefieldset{TAG}{name,name,...} %D \doFDFgetfieldset{TAG} %D \doFDFiffieldset{TAG}{sequence} %D \stoptyping \def\doFDFdefinefieldset#1#2% tag commalist {\let\FDFfieldset\empty \def\docommand##1% {\doPDFgetobjectreference{FDF}{##1}\PDFobjectreference \edef\FDFfieldset{\FDFfieldset\PDFobjectreference\space}}% \processcommacommand[#2]\docommand % nb: command \setevalue{FDF:set:#1}{\FDFfieldset}} \def\doFDFgetfieldset#1% {\getvalue{FDF:set:#1}} \def\doFDFiffieldset#1#2% {\ifundefined{FDF:set:#1}\else#2\fi} %D In the goto specials we took care of secondary references. %D Here we define the macros used. \def\doPDFresetgotowhereever {\global\let\secondaryPDFreferences\empty} \doPDFresetgotowhereever % just to be sure % we can (in etex) share more by testing on this \def\savesecondaryPDFreference#1% {\@EA\xdef\csname PDF-SR:\the\nofsecondaryreferences\endcsname{#1}} \def\savesecondaryPDFreference % #1 == \action {\global\@EA\let\csname PDF-SR:\the\nofsecondaryreferences\endcsname} %\def\getsecondaryPDFreferences% % {\ifcase\nofsecondaryreferences\else % %\doifdefined{PDF-SR:\the\nofsecondaryreferences} % \xdef\secondaryPDFreferences% % {/Next << \csname PDF-SR:\the\nofsecondaryreferences\endcsname\space % \secondaryPDFreferences >>}% % \global\advance\nofsecondaryreferences \minusone % \expandafter\getsecondaryPDFreferences % \fi} % test should happen in core-ref \def\getsecondaryPDFreferences {\ifcase\nofsecondaryreferences\else \ifcsname PDF-SR:\the\nofsecondaryreferences\endcsname \xdef\secondaryPDFreferences {/Next << \csname PDF-SR:\the\nofsecondaryreferences\endcsname\space \secondaryPDFreferences >>}% \fi \global\advance\nofsecondaryreferences \minusone \expandafter\getsecondaryPDFreferences \fi} %D \macros %D {loadFDFfields, showFDFfields, %D getFDFfield, setFDFfield} %D %D Once filled in, we can export or submit the field in the %D \FDF\ file format. Such a file can be loaded by %D %D \starttyping %D \loadFDFfields{fiel-ini} %D \stoptyping %D %D or inspected by %D %D \starttyping %D \showFDFfields{fiel-ini} %D \stoptyping %D %D After both commands, one can use %D %D \starttyping %D \getFDFfield{name} %D \setFDFfield{name}{value} %D \stoptyping %D %D to inspect and overrule the data. %D %D By default \CONTEXT\ calls the perl script \type{fdf2tex}. %D This script reads the \type{fdf} file and produces a file %D named \type{filename.fdt}. If one disables the call to this %D script, by saying: %D %D \starttyping %D \runFDFconverterfalse %D \stoptyping %D %D or when \CONTEXT\ cannot find the \type{fdt} file, it tries %D to interpret the \type{fdf} file directly. Both mechanisms %D are rather crude. \newif\ifrunFDFconverter \runFDFconvertertrue %D The \PERL\ script produces a file formatted as: %D %D \starttyping %D \beginFDFobject %D \beginFDFdata %D \beginFDFfields %D \FDFfield[name=,value=] %D \endFDFfields %D \endFDFdata %D \endFDFobject %D \stoptyping %D %D One reason for using key value pairs is that we cannot be %D sure or the order in which the name and value are given %D (actually the reverse). \def\PERLloadFDFfields#1% will become obsolete soon {\bgroup \global\let\allFDFfields\empty \ifrunFDFconverter \executesystemcommand{fdf2tex #1}% \let\beginFDFobject\relax \let\endFDFobject\relax \let\beginFDFdata \relax \let\endFDFdata \relax \let\beginFDFfields\relax \let\endFDFfields\relax \def\FDFfield[##1]% {\getparameters[FDF][##1]% \doglobal\addtocommalist\FDFname\allFDFfields \global\setFDFfield{\FDFname}{\FDFvalue}}% \ReadFile{#1.fdt}% \fi \egroup} %D The next macro does the same job, but now in the \TEX\ way %D of doing things. Easy eh? Will become obsolete! \bgroup \catcode`\/=\@@other \global\let\normalslash=/ \catcode`\/=\@@escape \gdef\TEXloadFDFfields#1% will become obsolete due to XFDF {\bgroup \setbox0=\hbox {\global\let\allFDFfields\empty \scratchcounter=0 \escapechar=-1 \catcode`\/=\@@escape \catcode`\(=\@@begingroup \catcode`\)=\@@endgroup \catcode`\%=\@@letter \let/A =\relax \let/AS =\relax \let/Kids=\relax \let/Fields=\relax \let/F =\relax \let/ID =\relax \let/SetF=\relax \let/setFf =\relax \let/Ff=\relax \let/Opt=\relax \let/ClrF=\relax \let/ClrFf =\relax \let/AP=\relax \let/FDF=\relax \let/Root=\relax \def/T##1{\check\Title{##1}} \def/V{\bgroup\catcode`\/=\@@other\futurelet\next/doV} \def/doV{\ifx\next\normalslash\@EA/doVb\else\@EA/doVa\fi} \def/doVa##1{\egroup\check\Value{##1}} \def/doVb##1##2 {\egroup\check\Value{##2}} % watch the space \def\check##1##2% {\def##1{##2} \advance\scratchcounter\plusone\relax \ifodd\scratchcounter \else \defconvertedcommand\asciia\Title \global\setFDFfield{\asciia}{\Value} \doglobal\addtocommalist\Title\allFDFfields \fi} \ReadFile{#1.fdf}}% \egroup} \egroup %D Whatever mechanism is used, the next macros can be used to %D fetch the values. \def\getFDFfield #1{\getvalue {FDFfield::#1}} \def\setFDFfield#1#2{\setevalue{FDFfield::#1}{#2}} %D Of course the fields are only present when the file is %D loaded. \def\loadFDFfields#1% {\PERLloadFDFfields{#1}% \ifx\allFDFfields\empty \TEXloadFDFfields{#1}% \fi} \def\showFDFfields#1% {\bgroup \loadFDFfields{#1} \def\docommand##1{\par##1 = \getFDFfield{##1}\par}% \processcommacommand[\allFDFfields]\docommand \egroup} %D \macros %D {sanitizePDFencoding,sanitizePDFdocencoding} %D %D We already dealt with the encoding vector. Conversion from %D \TEX\ \ASCII\ encoding to the other one, is accomplished by %D the next few macros. Wach out: we don't group here. %D This will be reimplemented using the mapping mechanism. % \def\enablePDFdocencoding % {\reducetocoding[pdfdoc]\simplifycommands} \def\enablePDFdocencoding {\enablecoding[pdfdoc]% \enablelanguagespecifics[\currentlanguage]% redundant ? \simplifycommands} \long\def\sanitizePDFdocencoding#1\to#2% {\enablePDFcrlf \enablePDFdocencoding %\honorunexpanded % otherwise problems with "e etc in de \edef#2{#1}} \bgroup \catcode`\^^M=\@@active \gdef\enablePDFcrlf% {\def\\{\string\r}% \def\par{\\\\}% \def\endgraf{\\\\}% \catcode`\^^M=\@@active% \let^^M=\\} \egroup % \let\sanitizePDFencoding\sanitizePDFdocencoding %D The conversions comes down to (for the sake of speed the %D implementation combines steps): %D %D \startitemize %D \item we expand the \UTF\ sequences into \type {\unicodechar}'s %D \item spaces become character 255's (so that they are not %D gobbled in argument fetching %D \item normal \ASCII\ chars are unchanged %D \item \par's and alike are converted to \type {\unicodechar}'s %D \stopitemize %D %D This happens by expansion; next we convert the resulting %D sequence by interpreting the stream. \long\def\sanitizePDFuniencoding#1\to#2% {\enablePDFunicrlf \simplifycommands % added due to Dohyun Kim \let\unicodechar\relax % prevent further expansion \retainlccodes\lccode32=255 % slooow \lowercasestring\PDFunicodetrigger#1\to#2% \edef#2{\expandafter\doPDFuni#2\empty\empty}} % slooow %D Handling of empty lines: \bgroup \catcode`\^^M=\@@active \gdef\enablePDFunicrlf% {\def\\{\unicodechar{13}}% \def\par{\\\\}% \catcode`\^^M=\@@active% \let^^M=\\} \egroup %D Conversion to 16 bit \UNICODE: \def\PDFunicodechar#1% {\@EA\lchexnumbers\@EA{\number\utfdiv{#1}}% \@EA\lchexnumbers\@EA{\number\utfmod{#1}}} \def\PDFunicodetrigger {\unicodechar{65279}} %D The postprocessor: \def\doPDFuni#1% {\ifx#1\relax \@EA\dodoPDFuni \else\ifx#1\empty % quit \else \@EAEAEA\nodoPDFuni \fi\fi#1} \def\nodoPDFuni#1% {\PDFunicodechar{\ifnum`#1=255 32\else`#1\fi}\doPDFuni} \def\dodoPDFuni#1#2% {\PDFunicodechar{#2}\doPDFuni} \def\sanitizePDFencoding {\doifelse\currentregime{utf}{\PDFunicodetrue\sanitizePDFuniencoding}\sanitizePDFdocencoding} %D A bit out of place, but useful: \ifdefined\everysetfield \else \newtoks\everysetfield \fi \appendtoksonce \enablePDFdocencoding \enablePDFcrlf \to \everysetfield %D \macros %D {doPDFinsertcomment} %D %D An example its use is the next special, one that deals with %D text annotations. % starting point (keep this) % % \long\def\doPDFinsertcomment#1#2#3#4#5#6#7#8% % {\bgroup % title width height color open symbol collect data % \doifelsenothing{#1} % {\let\PDFidentifier\empty} % {\def\PDFidentifier{/T (#1)}}% % \doifelsenothing{#4} % {\let\PDFattributes\empty} % {\def\PDFattributes{/C \FDFcolor{#4}}}% % \doifundefinedelse{PDFsymbol#6} % {\let\PDFsymbol\empty} % {\def\PDFsymbol{/Name \getvalue{PDFsymbol#6} }}% % \sanitizePDFencoding#8\to\PDFdata % \setbox\scratchbox\vbox to #3 % {\vfill % \doPDFannotation{#2}{#3} % {/Subtype /Text % \ifcase#5 \else/Open true\fi % /Contents \ifPDFunicode <\PDFdata> \else(\PDFdata) \fi % \PDFsymbol % \PDFidentifier % \PDFattributes}}% % \wd\scratchbox\zeropoint % \ht\scratchbox\zeropoint % \dp\scratchbox\zeropoint % \box\scratchbox % \egroup} \newcounter\nofFDFcomments \newif\ifPDFpopupcomments \PDFpopupcommentstrue \def\doPDFflushcomments {\box\PDFsymbolbox} \long\def\doPDFinsertcomment#1#2#3#4#5#6#7#8% % \@@DriverCommentLayer set otherwise {\bgroup % title width height color open symbol collect data \presetPDFsymbolappearance{#4}{#6}{#2}{#3}\!!zeropoint% sets width/height % \doifelsenothing{#1} % {\let\PDFidentifier\empty} % {\def\PDFidentifier{/T (#1)}}% \doifelsenothing{#1} {\let\PDFidentifier\empty} {\sanitizePDFencoding#1\to\PDFcommenttitle \def\PDFidentifier{/T \ifPDFunicode <\PDFcommenttitle>\else (\PDFcommenttitle)\fi}}% \sanitizePDFencoding#8\to\PDFdata \setFDFlayer\@@DriverCommentLayer \startPDFsymbolappearance \ifPDFpopupcomments \doglobal\increment\nofFDFcomments \doifobjectreferencefoundelse{FDF}{c:\nofFDFcomments} {\doPDFgetobjectreference{FDF}{c:\nofFDFcomments}\PDFobjectreference \donetrue} \donefalse \ifdone \setbox\scratchbox\hbox {\doPDFannotationobject{FDF}{c::\nofFDFcomments}{#2}{#3}% text window, size does not work {/Subtype /Popup /Parent \PDFobjectreference}}% \ifcase#7\relax \vbox to \height{\forgetall\vskip#3\box\scratchbox\vss}% \else % incredible trial and error hack % it's quite a mess, the annot width cannot be set, well, it can % but the appearance and text sizes get mixed up % \setbox\scratchbox\vbox to \height{\forgetall\vskip#3\box\scratchbox\vss}% % \global\setbox\PDFsymbolbox\vbox % {\hsize#2% % \forgetall % \vsmash{\box\PDFsymbolbox} % \box\scratchbox}% % this may change when acrobat gets less bugged \setbox\scratchbox\vbox to #3{\forgetall\vss\box\scratchbox}% \wd\scratchbox#2% \global\setbox\PDFsymbolbox\vbox {\startoverlay{\box\PDFsymbolbox}{\box\scratchbox}\stopoverlay}% \fi \fi % generic \doifobjectreferencefoundelse{FDF}{c::\nofFDFcomments} {\doPDFgetobjectreference{FDF}{c::\nofFDFcomments}\PDFobjectreference \donetrue} \donefalse \doPDFannotationobject{FDF}{c:\nofFDFcomments}{\width}{\height} {/Subtype /Text \ifcase#5 \else/Open true\fi % pdftex (efficient) % \ifdone /Popup \PDFobjref\pdflastannot\fi % generic (less efficient) \ifdone /Popup \PDFobjectreference\fi /Contents \ifPDFunicode <\PDFdata> \else(\PDFdata) \fi \PDFidentifier \FDFlayer \PDFsymbol \PDFattributes}% \else \doPDFannotation{#2}{#3} {/Subtype /Text \ifcase#5 \else/Open true\fi /Contents \ifPDFunicode <\PDFdata> \else(\PDFdata) \fi \FDFlayer \PDFsymbol \PDFidentifier \PDFattributes}% \fi \stopPDFsymbolappearance \egroup} % symbols with a reasonable default of 18/24 pt \newbox\PDFsymbolbox \def\PDFsymbolNew {/Insert} \def\PDFsymbolBalloon {/Comment} \def\PDFsymbolAddition {/NewParagraph} \def\PDFsymbolHelp {/Help} \def\PDFsymbolParagraph {/Paragraph} \def\PDFsymbolKey {/Key } \def\PDFsymbolGraph {/Graph} \def\PDFsymbolPaperclip {/Paperclip} \def\PDFsymbolAttachment{/Attachment} \def\PDFsymbolTag {/Tag} \def\startPDFsymbolappearance {\setbox\scratchbox\vbox to \totalheight \bgroup \vfill} \def\stopPDFsymbolappearance {\egroup \setbox\scratchbox\hbox{\lower\depth\box\scratchbox}% \wd\scratchbox\width \ht\scratchbox\height \dp\scratchbox\depth \box\scratchbox} \def\presetPDFsymbolappearance#1#2#3#4#5% symbol color width height depth {\doifelsenothing{#1} {\let\PDFattributes\empty} {\def\PDFattributes{/C \FDFcolor{#1}}}% \scratchdimen#3\edef\width {\the\scratchdimen}% \scratchdimen#4\edef\height{\the\scratchdimen}% \scratchdimen#5\edef\depth {\the\scratchdimen}% \advance\scratchdimen\height\edef\totalheight{\the\scratchdimen}% \doifelsenothing{#2} {\let\PDFsymbol\empty} {\ifundefined{PDFsymbol#2}% \getfromcommacommand[#2][1]\let\PDFsymbolnormalsymbol\commalistelement \getfromcommacommand[#2][2]\let\PDFsymboldownsymbol \commalistelement \doifsymboldefinedelse\PDFsymbolnormalsymbol {\doifsymboldefinedelse\PDFsymboldownsymbol {\dopresetPDFsymbolappearance \PDFsymbolnormalsymbol\PDFsymboldownsymbol} {\dopresetPDFsymbolappearance \PDFsymbolnormalsymbol\PDFsymbolnormalsymbol}} {\doifsymboldefinedelse\PDFsymboldownsymbol {\dopresetPDFsymbolappearance \PDFsymboldownsymbol\PDFsymboldownsymbol} {\let\PDFsymbol\empty}}% \else \def\PDFsymbol{/Name \getvalue{PDFsymbol#2} }% \fi}} \def\dopresetPDFsymbolappearance#1#2% {\dopresetfieldsymbol{#1}% \dopresetfieldsymbol{#2}% \setbox\scratchbox\hbox{\symbol[#1]}% \edef\width {\the\wd\scratchbox}% \edef\height{\the\ht\scratchbox}% \edef\depth {\the\dp\scratchbox}% \scratchdimen\height \advance\scratchdimen\depth \edef\totalheight{\the\scratchdimen}% \doPDFgetobjectreference{SYM}{#1}\FDFsymbolNappearance \doPDFgetobjectreference{SYM}{#2}\FDFsymbolDappearance \edef\PDFsymbol {/AP <>}} %D Hooked into \CONTEXT, this special supports %D %D \starttyping %D \startcomment %D hello beautiful\\world %D \stopcomment %D %D \startcomment[hello] %D de \'e\'erste keer %D the f\'irst time %D \stopcommen %D %D \startcommentaar[hallo][color=green,width=4cm,height=3cm] %D first %D %D second %D \stopcommentaar %D \stoptyping %D %D So, special characters, forced linebreaks using \type{\\} %D and \type{\par} are handled in the appropriate way. %D \macros %D {doPDFovalbox} %D %D For drawing ovals we use quite raw \PDF\ code. The next %D implementation does not differ that much from the one %D implemented in the \POSTSCRIPT\ driver. \def\doPDFovalcalc#1#2#3% {\dimen2=#1% \advance\dimen2 #2\relax \PointsToBigPoints{\dimen2}#3} \def\doPDFovalbox#1#2#3#4#5#6#7#8% todo: \scratchdimen/\scatchbox {\forcecolorhack \bgroup \dimen0=#4\divide\dimen0 \plustwo \doPDFovalcalc{0pt}{+\dimen0}\xmin \doPDFovalcalc{#1}{-\dimen0}\xmax \doPDFovalcalc{#2}{-\dimen0}\ymax \doPDFovalcalc{-#3}{+\dimen0}\ymin \advance\dimen0 by #5% \doPDFovalcalc{0pt}{+\dimen0}\xxmin \doPDFovalcalc{#1}{-\dimen0}\xxmax \doPDFovalcalc{#2}{-\dimen0}\yymax \doPDFovalcalc{-#3}{+\dimen0}\yymin \doPDFovalcalc{#4}{\zeropoint}\stroke \doPDFovalcalc{#5}{\zeropoint}\radius \edef\dostroke{#6}% \edef\dofill{#7}% \edef\mode{\number#8 \space}% % no \ifcase, else \relax in pdfcode \setbox\scratchbox\hbox {\ifnum\dostroke\dofill>\zerocount \ifPDFstrokecolor\else\ifnum\dostroke=\plusone \writestatus\m!colors{pdf stroke color will fail}\wait \fi\fi \PDFcode {q \stroke\space w \ifcase\mode \xxmin\space \ymin \space m \xxmax\space \ymin \space l \xmax \space \ymin \space \xmax \space \yymin\space y \xmax \space \yymax\space l \xmax \space \ymax \space \xxmax\space \ymax \space y \xxmin\space \ymax \space l \xmin \space \ymax \space \xmin \space \yymax\space y \xmin \space \yymin\space l \xmin \space \ymin \space \xxmin\space \ymin \space y h \or % 1 \xxmin\space \ymin \space m \xxmax\space \ymin \space l \xmax \space \ymin \space \xmax \space \yymin\space y \xmax \space \ymax \space l \xmin \space \ymax \space l \xmin \space \yymin\space l \xmin \space \ymin \space \xxmin\space \ymin \space y h \or % 2 \xxmin\space \ymin \space m \xmax \space \ymin \space l \xmax \space \ymax \space l \xxmin\space \ymax \space l \xmin \space \ymax \space \xmin \space \yymax\space y \xmin \space \yymin\space l \xmin \space \ymin \space \xxmin\space \ymin \space y h \or % 3 \xmin \space \ymin \space m \xmax \space \ymin \space l \xmax \space \yymax\space l \xmax \space \ymax \space \xxmax\space \ymax \space y \xxmin\space \ymax \space l \xmin \space \ymax \space \xmin \space \yymax\space y \xmin \space \ymin \space l h \or % 4 \xmin \space \ymin \space m \xxmax\space \ymin \space l \xmax \space \ymin \space \xmax \space \yymin\space y \xmax \space \yymax\space l \xmax \space \ymax \space \xxmax\space \ymax \space y \xmin \space \ymax \space l \xmin \space \ymin\space l h \or % 5 \xmin \space \ymin \space m \xmax \space \ymin \space l \xmax \space \yymax\space l \xmax \space \ymax \space \xxmax\space \ymax \space y \xmin \space \ymax \space l \xmin \space \ymin \space l h \or % 6 \xmin \space \ymin \space m \xxmax\space \ymin \space l \xmax \space \ymin \space \xmax \space \yymin\space y \xmax \space \ymax \space l \xmin \space \ymax \space l \xmin \space \ymin \space l h \or \xxmin\space \ymin \space m \xmax \space \ymin \space l \xmax \space \ymax \space l \xmin \space \ymax \space l \xmin \space \yymin\space l \xmin \space \ymin \space \xxmin\space \ymin \space y h \or \xmin \space \ymin \space m \xmax \space \ymin \space l \xmax \space \ymax \space l \xxmin\space \ymax \space l \xmin \space \ymax \space \xmin \space \yymax\space y \xmin \space \ymin \space l h \or % 9 top open \xmin \space \ymax \space m \xmin \space \yymin\space l \xmin \space \ymin \space \xxmin\space \ymin \space y \xxmax\space \ymin \space l \xmax \space \ymin \space \xmax \space \yymin\space y \xmax \space \ymax \space l \or % 10 right open \xmax \space \ymax \space m \xxmin\space \ymax \space l \xmin \space \ymax \space \xmin \space \yymax\space y \xmin \space \yymin\space l \xmin \space \ymin \space \xxmin\space \ymin \space y \xmax\space \ymin \space l \or % 11 bottom open \xmax \space \ymin \space m \xmax \space \yymax\space l \xmax \space \ymax \space \xxmax \space \ymax\space y \xxmin\space \ymax \space l \xmin \space \ymax \space \xmin \space \yymax\space y \xmin \space \ymin \space l \or % 12 left open \xmin \space \ymax \space m \xxmax\space \ymax \space l \xmax \space \ymax \space \xmax \space \yymax\space y \xmax \space \yymin\space l \xmax \space \ymin \space \xxmax\space \ymin \space y \xmin \space \ymin \space l \or % 13 \xmin \space \ymax \space m \xxmax\space \ymax \space l \xmax \space \ymax \space \xmax \space \yymax\space y \xmax\space \ymin \space l \or % 14 \xmax \space \ymax \space m \xmax \space \yymin\space l \xmax \space \ymin \space \xxmax\space \ymin \space y \xmin \space \ymin \space l \or % 15 \xmax \space \ymin \space m \xxmin\space \ymin \space l \xmin \space \ymin \space \xmin \space \yymin\space y \xmin \space \ymax \space l \or % 16 \xmin \space \ymin \space m \xmin \space \yymax\space l \xmin \space \ymax \space \xxmin\space \ymax \space y \xmax \space \ymax \space l \or % 17 \xxmax\space \ymax \space m \xmax \space \ymax \space \xmax \space \yymax\space y \or % 18 \xmax \space \yymin\space m \xmax \space \ymin \space \xxmax\space \ymin \space y \or % 19 \xxmin\space \ymin \space m \xmin \space \ymin \space \xmin \space \yymin\space y \or % 20 \xmin \space \yymax\space m \xmin \space \ymax \space \xxmin\space \ymax \space y \or % 21 \xxmax\space \ymax \space m \xmax \space \ymax \space \xmax \space \yymax\space y \xmin \space \yymax\space m \xmin \space \ymax \space \xxmin\space \ymax \space y \or % 22 \xxmax\space \ymax \space m \xmax \space \ymax \space \xmax \space \yymax\space y \xmax \space \yymin\space m \xmax \space \ymin \space \xxmax\space \ymin \space y \or % 23 \xmax \space \yymin\space m \xmax \space \ymin \space \xxmax\space \ymin \space y \xxmin\space \ymin \space m \xmin \space \ymin \space \xmin \space \yymin\space y \or % 24 \xxmin\space \ymin \space m \xmin \space \ymin \space \xmin \space \yymin\space y \xmin \space \yymax\space m \xmin \space \ymax \space \xxmin\space \ymax \space y \or % 25 \xxmax\space \ymax \space m \xmax \space \ymax \space \xmax \space \yymax\space y \xmax \space \yymin\space m \xmax \space \ymin \space \xxmax\space \ymin \space y \xxmin\space \ymin \space m \xmin \space \ymin \space \xmin \space \yymin\space y \xmin \space \yymax\space m \xmin \space \ymax \space \xxmin\space \ymax \space y \or % 26 \xmax \space \yymin\space m \xmax \space \ymin \space \xxmax\space \ymin \space y \xmin \space \yymax\space m \xmin \space \ymax \space \xxmin\space \ymax \space y \or % 27 \xxmax\space \ymax \space m \xmax \space \ymax \space \xmax \space \yymax\space y \xxmin\space \ymin \space m \xmin \space \ymin \space \xmin \space \yymin\space y \or % 28 \fi \ifnum\mode>8 S \else \ifnum\dostroke=\plusone S \fi \ifnum\dofill =\plusone f \fi \fi Q}% \fi}% \wd\scratchbox#1\ht\scratchbox#2\dp\scratchbox#3\box\scratchbox \egroup} %D \macros %D {doPDFstartgraymode,doPDFstopgraymode, %D doPDFstartrgbcolormode,doPDFstartcmykcolormode,doPDFstartgraycolormode, %D doPDFstopcolormode} %D %D In \PDF\ there are two color states, one for strokes and one %D for fills. This means that we have to set the color in a %D rather redundant looking way. Unfortunately this makes the %D \PDF\ file much larger than needed. We can save few bytes %D by not setting the stroke color. Due to zip compression we %D only save a few percent. % \newif\ifPDFstrokecolor \PDFstrokecolortrue \def\doPDFstartgraymode#1% % {\PDFdirectcode{#1 g\ifPDFstrokecolor\space#1 G\fi}} {\PDFcode{#1 g\ifPDFstrokecolor\space#1 G\fi}} \def\doPDFstopgraymode % {\PDFdirectcode{0 g\ifPDFstrokecolor\space0 G\fi}} {\PDFcode{0 g\ifPDFstrokecolor\space0 G\fi}} \def\doPDFstartrgbcolormode#1#2#3% % {\PDFdirectcode{#1 #2 #3 rg\ifPDFstrokecolor\space#1 #2 #3 RG\fi}} {\PDFcode{#1 #2 #3 rg\ifPDFstrokecolor\space#1 #2 #3 RG\fi}} \def\doPDFstartcmykcolormode#1#2#3#4% % {\PDFdirectcode{#1 #2 #3 #4 k\ifPDFstrokecolor\space#1 #2 #3 #4 K\fi}} {\PDFcode{#1 #2 #3 #4 k\ifPDFstrokecolor\space#1 #2 #3 #4 K\fi}} \def\doPDFstartgraycolormode#1% % {\PDFdirectcode{#1 g\ifPDFstrokecolor\space#1 G\fi}} {\PDFcode{#1 g\ifPDFstrokecolor\space#1 G\fi}} \def\doPDFstartspotcolormode#1#2% redefining spotcolors is not possible anyway {\ifundefined{pdf:scs:#2}% \bgroup \getcommacommandsize[#2]% \ifcase\commalistsize\or \setxvalue{pdf:scs:#2}{#2 SCN #2 scn}% \setxvalue{pdf:scs:#2}{#2 SC #2 sc}% \else \let\PDFspotcolorspecs\empty \def\dospotcolorcommand##1{\edef\PDFspotcolorspecs{\PDFspotcolorspecs##1\space}}% \processcommacommand[#2]\dospotcolorcommand \setxvalue{pdf:scs:#2}{\PDFspotcolorspecs SCN \PDFspotcolorspecs scn}% \fi \egroup \fi % \PDFdirectcode{/#1 cs /#1 CS \PDFgetspotcolorspec{#2}}} \PDFcode{/#1 cs /#1 CS \PDFgetspotcolorspec{#2}}} \def\PDFgetspotcolorspec#1% {\executeifdefined{pdf:scs:#1}\empty} % better no default than one with too less args \def\doPDFstartnonecolormode % {\PDFdirectcode{/None CS 1 SC /None cs 1 sc}} {\PDFcode{/None CS 1 SC /None cs 1 sc}} \def\doPDFstopcolormode % {\PDFdirectcode{0 g\ifPDFstrokecolor\space0 G\fi}} {\PDFcode{0 g\ifPDFstrokecolor\space0 G\fi}} %D We need to register the spot colors and their fallbacks. % we cannot use /DeviceN since GS <=7.21 breaks on it % and Jaws does not handle it at all {[/DeviceN [/All|/None] % /Device#2 \PDFobjref\pdflastobj]} so we use separation % colors that work and print ok \def\doPDFregistersomespotcolor#1#2#3#4% implemented in the driver {\writestatus\m!systems{missing spot color definition}\wait} \def\doPDFregisternonecolor % internal command {\doPDFregistergrayspotcolor{None}{1}% \globallet\doPDFregisternonecolor\relax} \def\doPDFregisterspotcolorname#1#2% implemented in the driver {} \definespecial\doregisterspotcolorname{\doPDFregisterspotcolorname} \def\dodoPDFregisterrgbspotcolor#1#2#3#4#5#6#7% name noffractions names p's r g b {\doPDFregistersomespotcolor{#1}{#2}{#3}{#4}{RGB}{0.0 1.0 0.0 1.0 0.0 1.0}% {\ifcase#2\or dup #5 mul exch dup #6 mul exch #7 mul\else#5 #6 #7\fi}} \def\dodoPDFregistercmykspotcolor#1#2#3#4#5#6#7#8% name noffractions names p's c m y k {\doPDFregistersomespotcolor{#1}{#2}{#3}{#4}{CMYK}{0.0 1.0 0.0 1.0 0.0 1.0 0.0 1.0}% {\ifcase#2\or dup #5 mul exch dup #6 mul exch dup #7 mul exch #8 mul\else #5 #6 #7 #8\fi}} \def\dodoPDFregistergrayspotcolor#1#2#3#4#5% name noffractions names p's s {\doPDFregistersomespotcolor{#1}{#2}{#3}{#4}{Gray}{0.0 1.0}% {\ifcase#2\or #5 mul\else #5\fi}} % \let\doPDFregisterrgbspotcolor \dodoPDFregisterrgbspotcolor % \let\doPDFregistercmykspotcolor\dodoPDFregistercmykspotcolor % \let\doPDFregistergrayspotcolor\dodoPDFregistergrayspotcolor \def\doPDFregisterrgbspotcolor#1#2#3#4#5#6#7% name noffractions names p's r g b {\ifRGBsupported \dodoPDFregisterrgbspotcolor{#1}{#2}{#3}{#4}{#5}{#6}{#7}% \else \edef\@@cl@@r{#5}\edef\@@cl@@g{#6}\edef\@@cl@@b{#7}% \ifCMYKsupported \convertRGBtoCMYK\@@cl@@r\@@cl@@g\@@cl@@b \dodoPDFregistercmykspotcolor{#1}{#2}{#3}{#4}\@@cl@@c\@@cl@@m\@@cl@@y\@@cl@@k \else \convertRGBtoGRAY\@@cl@@r\@@cl@@g\@@cl@@b \dodoPDFregistergrayspotcolor{#1}{#2}{#3}{#4}\@@cl@@s \fi \fi} \def\doPDFregistercmykspotcolor#1#2#3#4#5#6#7#8% name noffractions names p's c m y k {\ifCMYKsupported \dodoPDFregistercmykspotcolor{#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}% \else \edef\@@cl@@c{#5}\edef\@@cl@@m{#6}\edef\@@cl@@y{#7}\edef\@@cl@@k{#8}% \ifRGBsupported \convertCMYKtoRGB\@@cl@@c\@@cl@@m\@@cl@@y\@@cl@@k \dodoPDFregisterrgbspotcolor{#1}{#2}{#3}{#4}\@@cl@@r\@@cl@@g\@@cl@@b \else \convertCMYKtoGRAY\@@cl@@c\@@cl@@m\@@cl@@y\@@cl@@k \dodoPDFregistergrayspotcolor{#1}{#2}{#3}{#4}\@@cl@@s \fi \fi} \def\doPDFregistergrayspotcolor{\dodoPDFregistergrayspotcolor} %D New and very experimental. \def\doPDFregistercmykindexcolor#1#2#3#4#5#6#7#8% name noffractions names p's c m y k {\doPDFregistersomeindexcolor{#1}{#2}{#3}{#4}{CMYK}{0.0 1.0 0.0 1.0 0.0 1.0 0.0 1.0}% {dup #5 mul exch dup #6 mul exch dup #7 mul exch #8 mul}} \def\doPDFregisterrgbindexcolor#1#2#3#4#5#6#7% name noffractions names p's r g b {\doPDFregistersomeindexcolor{#1}{#2}{#3}{#4}{RGB}{0.0 1.0 0.0 1.0 0.0 1.0}% {dup #5 mul exch dup #6 mul exch #7 mul}} \def\doPDFregistergrayindexcolor#1#2#3#4#5% name noffractions names p's s {\doPDFregistersomeindexcolor{#1}{#2}{#3}{#4}{Gray}{0.0 1.0}% {pop}} \let\checkpredefinedcolor\predefineindexcolor % we need an index in order to negate bitmaps \def\doPDFregisterfigurecolor#1% always an index color {\dogetobjectreference {PDFIX} {\internalspotcolorname{#1}} \PDFimagecolorreference} %D \macros %D {doPDFstartrotation,doPDFstoprotation} %D %D Rotating some text can be accomplished by setting the first %D four elements of the transform matrix. We only support some %D fixed angles. The \type{q}'s take care of grouping. % The original: % % \def\doPDFstartrotation#1% % {\PDFcode{q}% % \processaction % [#1] % [ 90=>\PDFcode{ 0 1 -1 0 0 0 cm}, % 180=>\PDFcode{-1 0 0 -1 0 0 cm}, % 270=>\PDFcode{ 0 -1 1 0 0 0 cm}, % 360=>\PDFcode{ 1 0 0 1 0 0 cm}]} % % We cannot directly pass an angle, but have to calculate % factors (rx and ry). As in the \METAPOST\ to \PDF\ % converter module we need to compensate the deformation % by setting (sx and sy). % % Optimized but bigger: % % \def\doPDFstartrotation#1% % {\PDFcode{q}% % \processaction % [#1] % [ 0=>\PDFcode{ 1 0 0 1 0 0 cm}, % 90=>\PDFcode{ 0 1 -1 0 0 0 cm}, % 180=>\PDFcode{-1 0 0 -1 0 0 cm}, % 270=>\PDFcode{ 0 -1 1 0 0 0 cm}, % 360=>\PDFcode{ 1 0 0 1 0 0 cm}, % #1=>\setcalculatedcos\cos{#1}% % \setcalculatedsin\sin{#1}% % \PDFcode{\cos \space % cos % \sin \space % sin % \negated\sin\space % -sin % \cos \space % cos % 0 0 cm}]} % % Since the sine and cosine values are preset and rounded we % can use the next alternative without running into inaccuracies. \def\doPDFstartrotation#1% grouped {\setcalculatedcos\cos{#1}% \setcalculatedsin\sin{#1}% \forcecolorhack \PDFcode{q \cos\space\sin\space\negated\sin\space\cos\space0 0 cm}} \def\doPDFstoprotation {\PDFcode{Q}} %D \macros %D {doPDFstartscaling,doPDFstopscaling} %D %D Scaling is rather straightforward: \def\@@PDFzeroscale{.0001} \def\doPDFstartscaling#1#2% the test is needed because acrobat is bugged! {\forcecolorhack \PDFcode{q \ifdim#1\points=\zeropoint\@@PDFzeroscale\else#1\fi\space 0 0 \ifdim#2\points=\zeropoint\@@PDFzeroscale\else#2\fi\space 0 0 cm}} % \def\doPDFstartscaling#1#2% the test is needed because acrobat is bugged! % {\PDFcode{q\ifdim#1\points=\zeropoint\else\ifdim#2\points=\zeropoint\else % \space#1\space 0 0 #2\space 0 0 cm\fi\fi}} \def\doPDFstopscaling {\PDFcode{Q}} %D \macros %D {doPDFstartmirroring,doPDFstopmirroring} %D %D Mirroring is implemented in a similar way: \def\doPDFstartmirroring {\PDFcode{-1 0 0 1 0 0 cm}} \def\doPDFstopmirroring {\PDFcode{-1 0 0 1 0 0 cm}} %D \macros %D {doPDFstartnegative,doPDFstopnegative} %D %D When producing output for an image setter, sometimes negative %D output is needed. \def\doPDFstartnegative {\ifx\initializePDFnegative\undefined\else \initializePDFnegative % \PDFdirectcode{/GSnegative gs}% \PDFcode{/GSnegative gs}% \fi} \def\doPDFstopnegative {\ifx\initializePDFnegative\undefined\else \initializePDFnegative % \PDFdirectcode{/GSpositive gs}% \PDFcode{/GSpositive gs}% \fi} %D \macros %D {doPDFstartoverprint,doPDFstopoverprint} %D %D Some printers like overprint more than knockout. \def\doPDFstartoverprint {\ifx\initializePDFoverprint\undefined\else \initializePDFoverprint % \PDFdirectcode{/GSoverprint gs}% \PDFcode{/GSoverprint gs}% \fi} \def\doPDFstopoverprint {\ifx\initializePDFoverprint\undefined\else \initializePDFoverprint % \PDFdirectcode{/GSknockout gs}% \PDFcode{/GSknockout gs}% wrong \fi} %D Transparency support: \newif\ifPDFtransparencysupported \def\PDFtransparancydictionary#1#2#3% type fraction extras {<>} \def\dodoPDFstarttransparency#1#2% {\presetPDFtransparency{#1}{#2}% \PDFcode{\PDFtransparencyidentifier\space gs }} \def\dodoPDFstoptransparency {\PDFcode{/Tr0 gs }} \def\doPDFstarttransparency {\ifPDFtransparencysupported \global\let\doPDFstarttransparency\dodoPDFstarttransparency \global\let\doPDFstoptransparency \dodoPDFstoptransparency \initializetransparency \expandafter\doPDFstarttransparency \else \expandafter\gobbletwoarguments \fi} % \let\doPDFstoptransparency\relax % % This is tricky: because a text stream is handled before % the page body is built, we can run into stops that will % match an outer start; however, the stop is needed in case % of a text color: [text color text] [other color text] on a % first page combined with color splitting will go wrong if % we stick to the relaxing method. \def\doPDFstoptransparency {\ifPDFtransparencysupported \initializetransparency \dodoPDFstoptransparency \fi} %D These use: \let\PDFtransparencyresetreference \empty \let\PDFtransparencyresetidentifier\empty \let\PDFtransparencyreference \empty \let\PDFtransparencyidentifier\empty \let\presetPDFtransparency \gobbletwoarguments \let\initializetransparency\relax %D New trickery: \definespecial\dostartgraphicgroup{\PDFcode{q}} \definespecial\dostopgraphicgroup {\PDFcode{Q}} %D Even newer trickery: \definespecial\dostartviewerlayer {\doPDFstartlayer} \definespecial\dostopviewerlayer {\doPDFstoplayer} \definespecial\dodefineviewerlayer{\doPDFdefinelayer} \let\PDFtextlayers\empty \let\PDFpagelayers\empty \let\PDFhidelayers\empty \let\PDFvidelayers\empty % \def\doPDFstartlayer#1{\PDFdirectcode{/OC /#1 BDC}} % \def\doPDFstoplayer {\PDFdirectcode {EMC}} \def\doPDFstartlayer#1{\PDFcode{/OC /#1 BDC}} \def\doPDFstoplayer {\PDFcode {EMC}} % resource -> prop -> mc's -> OCG|OCMD (nested) % ocg: % /Intent/Design % ocmd % /P /AllOn % kan zelf ocmd bevatten \def\doPDFdefinelayer#1#2#3#4#5% tag title visible type printable {\doPDFdictionaryobject{PDLN}{#1} {/Type /OCG \ifcase#4 \or /Intent /Design % disable layer hiding by user \fi \ifnum#5=\zerocount /Usage << /Print << /PrintState /OFF >> >> % printable or not \fi /Name (#2)}% \doPDFgetobjectreference{PDLN}{#1}\PDFobjectreference \xdef\PDFtextlayers{\PDFtextlayers\space\PDFobjectreference}% \doifelse{#3}\v!start {\xdef\PDFvidelayers{\PDFvidelayers\space\PDFobjectreference}}% {\xdef\PDFhidelayers{\PDFhidelayers\space\PDFobjectreference}}% \doPDFdictionaryobject{PDLD}{#1} {/Type /OCMD /OCGs [\PDFobjectreference]}% \doPDFgetobjectreference{PDLD}{#1}\PDFobjectreference \xdef\PDFpagelayers{\PDFpagelayers\space /#1 \PDFobjectreference}} \def\flushPDFtextlayers {\ifx\PDFtextlayers\empty \else \driverreferenced \doPDFarrayobject{PDF}{textlayers}{\PDFtextlayers}% \doPDFgetobjectreference{PDF}{textlayers}\!!stringa \ifx\PDFvidelayers\empty \def\!!stringb{[null]}% \else \driverreferenced \doPDFarrayobject{PDF}{videlayers}{\PDFvidelayers}% \doPDFgetobjectreference{PDF}{videlayers}\!!stringb \fi \ifx\PDFhidelayers\empty \def\!!stringc{[null]}% \else \driverreferenced \doPDFarrayobject{PDF}{hidelayers}{\PDFhidelayers}% \doPDFgetobjectreference{PDF}{hidelayers}\!!stringc \fi \doPDFaddtocatalog {/OCProperties << % display in menu /D << /Order \!!stringa /ON \!!stringb /OFF \!!stringc >> % used properties /OCGs \!!stringa >>}% \globallet\flushPDFtextlayers\relax \fi} \def\flushPDFpagelayers {\ifx\PDFpagelayers\empty \else \doPDFpageresource{/Properties <<\PDFpagelayers>>}% \fi} \prependtoksonce \flushPDFpagelayers \to \everyshipout \prependtoksonce \flushPDFtextlayers \to \everylastshipout \def\PDFlayeractionlist{null} \def\PDFexecutehidelayer {/SetOCGState /State [/OFF \PDFlayeractionlist]} \def\PDFexecutevidelayer {/SetOCGState /State [/ON \PDFlayeractionlist]} \def\PDFexecutetogglelayer {/SetOCGState /State [/Toggle \PDFlayeractionlist]} \def\domakeviewerlayerlist#1% {\bgroup \globallet\PDFlayeractionlist\empty \def\docommand##1% {\doPDFgetobjectreference{PDLN}{##1}\PDFobjectreference \xdef\PDFlayeractionlist{\PDFlayeractionlist\space\PDFobjectreference}}% \processcommalist[#1]\docommand \egroup} %D Something rather pdf dependent: % #1 => 1=fill 2=stroke 3=strokedfill 4=invisible % #2 => linewidth % #3 => spacing (beware, one needs to set the hsize as well) \def\doPDFstartfonteffect#1#2#3% {\ifdim#2>\zeropoint \PointsToBigPoints{#2}\ascii % \PDFdirectcode{\ascii\space w}% \PDFcode{\ascii\space w}% \fi \ifdim#3\points=\onepoint\else \scratchdimen#3\points % \PDFdirectcode{\withoutpt{\the\scratchdimen}\space Tc}% \PDFcode{\withoutpt{\the\scratchdimen}\space Tc}% \fi % \PDFdirectcode{\purenumber#1 Tr}} \PDFcode{\purenumber#1 Tr}} \def\doPDFstopfonteffect % {\PDFdirectcode{1 w 0 Tc 0 Tr}} {\PDFcode{1 w 0 Tc 0 Tr}} %D Handy for the \METAPOST\ to \PDF\ converter: \ifdefined\everyPDFximage \else \newtoks\everyPDFximage \fi \ifdefined\everyPDFxform \else \newtoks\everyPDFxform \fi \appendtoksonce \collectPDFresources \global\let\currentPDFresources\collectedPDFresources \to \everyPDFxform \let\collectedPDFresources\empty \def\collectPDFresources % suboptimal {\doifobjectreferencefoundelse{FDF}{docushades} % redundant, we have an reserved object now {\doPDFgetobjectreference{FDF}{docushades}\PDFobjectreference \xdef\collectedPDFresources{\collectedPDFresources/Shading \PDFobjectreference}}\donothing \doifobjectreferencefoundelse{FDF}{docuextgstates} {\doPDFgetobjectreference{FDF}{docuextgstates}\PDFobjectreference \xdef\collectedPDFresources{\collectedPDFresources/ExtGState \PDFobjectreference}}\donothing \doifobjectreferencefoundelse{FDF}{docupatterns} {\doPDFgetobjectreference{FDF}{docupatterns}\PDFobjectreference \xdef\collectedPDFresources{\collectedPDFresources/Pattern \PDFobjectreference}}\donothing \doifobjectreferencefoundelse{FDF}{colorspaces} {\doPDFgetobjectreference{FDF}{colorspaces}\PDFobjectreference \xdef\collectedPDFresources{\collectedPDFresources/ColorSpace \PDFobjectreference}}\donothing \global\let\collectPDFresources\relax} %D And that was about all. \stopspecials \ifx\fullytransparentcolor\undefined \else \def\fullytransparentcolor {\doPDFregisternonecolor \doPDFstartnonecolormode} \let\doPDFstarttransparency\gobbletwoarguments \let\doPDFstoptransparency\relax \fi %D Temporary hack: \def\TransparencyHack % png: /CS /DeviceRGB /I true {\appendtoks \doPDFpageattribute{/Group << /S /Transparency /I true /K true>>}% \to \everyPDFxform \appendtoks \doPDFpageattribute{/Group << /S /Transparency /I true /K true>>}% \to \everyshipout} %D We still need to implement a few helpers: \chardef\safePDFcode=`- \def\setPDFdestination#1% {\bgroup \retainlccodes \lccode`\/\safePDFcode \lccode`\#\safePDFcode \lccode`\<\safePDFcode \lccode`\>\safePDFcode \lccode`\[\safePDFcode \lccode`\]\safePDFcode \lccode`\(\safePDFcode \lccode`\)\safePDFcode \ifovercomePDFspace \lccode`\ \safePDFcode \fi \ifovercomePDFbugs \xdef\PDFdestination{'#1'}% \else \xdef\PDFdestination{#1}% \fi % nicer \xdef\PDFdestination{\ifovercomePDFbugs'\fi#1\ifovercomePDFbugs'\fi}% \lowercase\@EA{\@EA\xdef\@EA\PDFdestination\@EA{\PDFdestination}}% \egroup} %D This is much faster since we don't have to set the full %D range of lc-codes; about 5 sec on a 1000mhz PIII for %D 20K named destinations "x(x) x"). Of course when you use %D page destinations, the saving is nil. % \doifnotmode{atpragma}{\let\next\setPDFdestination} % experimental % % \catcode`\/=\@@active \catcode`\#=\@@active % \catcode`\<=\@@active \catcode`\>=\@@active % \catcode`\[=\@@active \catcode`\]=\@@active % \catcode`\(=\@@active \catcode`\)=\@@active % % \gdef\PDFrepchar{-} % % \gdef\setPDFdcharacters % {\catcode`\/=\@@active \let/\PDFrepchar % \catcode`\#=\@@active \let#\PDFrepchar % \catcode`\<=\@@active \let<\PDFrepchar % \catcode`\>=\@@active \let>\PDFrepchar % \catcode`\[=\@@active \let[\PDFrepchar % \catcode`\]=\@@active \let]\PDFrepchar % \catcode`\(=\@@active \let(\PDFrepchar % \catcode`\)=\@@active \let)\PDFrepchar} % % \egroup % % \def\setPDFdestination#1% expansion is needed, otherwise embedded % {\bgroup % macros will not expand under the new % \setPDFdcharacters % catcode regime % \ifovercomePDFspace % \catcode32=\@@ignore % \fi % \xdef\PDFdestination{\ifovercomePDFbugs'\fi#1\ifovercomePDFbugs'\fi}% % \scantokens\@EA{\@EA\xdef\@EA\PDFdestination\@EA{\PDFdestination}}% % \egroup} % % \doifnotmode{atpragma}{\let\setPDFdestination\next} % experimental %D This is a slow one, that uses \type{\lccode}'s to %D change the glyph as well as converts sensisitve ones into a %D \PDF\ command sequence, so \type{(} becomes \type{\(}. In %D fact we translate the string to lowercase inactive and non %D special characters, limit their number and finaly convert %D some of the characters to save ones. \chardef\maxPDFstringsize=60 \def\sanitizePDFstring#1\to#2% bugged {\bgroup \retainlccodes \lccode`( \zerocount \lccode`) \zerocount \lccode`< \zerocount \lccode`> \zerocount \lccode`[ \zerocount \lccode`] \zerocount \lccode`\\\zerocount \lccode`/ \zerocount \lowercase{\defconvertedargument\ascii{#1}}% % by integrating the split in the loop below % \splitofftokens\maxPDFstringsize\from\ascii\to\ascii % we diminish the processing time considerably \scratchcounter\maxPDFstringsize \def\docommand##1% {\ifcase\scratchcounter\else \advance\scratchcounter \minusone \ifcase\lccode`##1\relax \xdef#2{#2\expandafter\string\csname##1\endcsname}% \else \xdef#2{#2##1}% \fi \fi}% %\global\let#2=\empty % or to permit #2 to be \ascii too: \global\@EA\let\@EA#2\@EA\empty \@EA\handletokens\ascii\with\docommand \egroup} % \doifnotmode{atpragma}{\let\next\sanitizePDFstring} % experimental % % \bgroup % % \catcode`\.=\@@escape % % .catcode`./=.@@active % .catcode`.<=.@@active .catcode`.>=.@@active % .catcode`.[=.@@active .catcode`.]=.@@active % .catcode`.(=.@@active .catcode`.)=.@@active % % .gdef.setPDFscharacters% % {.catcode`.\=.@@other % .catcode`./=.@@active .def/{.noexpand./}% % .catcode`.<=.@@active .def<{.noexpand.<}% % .catcode`.>=.@@active .def>{.noexpand.>}% % .catcode`.[=.@@active .def[{.noexpand.[}% % .catcode`.]=.@@active .def]{.noexpand.]}% % .catcode`.(=.@@active .def({.noexpand.(}% % .catcode`.)=.@@active .def){.noexpand.)}} % % .gdef.sanitizePDFstring#1.to#2% % {.bgroup % .setPDFscharacters % .catcode`=.@@escape % .edef.next{.strippedcsname#2}% % .scantokens{setxvalue{next}{#1}}% % .egroup} % % .egroup % % \doifnotmode{atpragma}{\let\sanitizePDFstring\next} % experimental % % There is an unicode variant in spec-tst! \protect \endinput