% pdfextra package % Michal Vlasák % https://github.com/vlasakm/pdfextra % Zero-Clause BSD license \_def\_pdfextra_version{0.3} \_codedecl \RM {Extra PDF features (v\_pdfextra_version)} \_namespace{pdfextra} \_doc \sec Package initialization We ensure that hyperlinking is active. Our fallback \`\_linkcolor` must exist. We also use it for `\hyperlinks` if the user didn't enable `\hyperlinks` yet (we don't want to override user setting). \_cod \_ifdefined\_ilinkcolor\_else \_ifdefined\_linkcolor \_ea\_let\_ea\_linkcolor \_ifdefined\Blue\Blue\_else\_empty\_fi \_else \_let\_linkcolor\linkcolor \_fi \_fi \_ifx\_dest\_destactive\_else \_hyperlinks\_linkcolor\_linkcolor \_fi \_doc We are in the \OpTeX/ package namespace. A couple of shortcuts are defined here: \`\.isdefined`, \`\.trycs`, \`\.cs` \`\.slet`, \`\.slet`, \`\.sdef` and \`\.sxdef`. They all hard code the package name, because we already have too many levels of indirection. \_cod \_def\.isdefined#1{\_isdefined{_pdfextra_#1}} \_def\.trycs#1{\_trycs{_pdfextra_#1}} \_def\.cs#1{\_cs{_pdfextra_#1}} \_def\.slet#1#2{\_slet{_pdfextra_#1}{_pdfextra_#2}} \_def\.sdef#1{\_sdef{_pdfextra_#1}} \_def\.sxdef#1{\_sxdef{_pdfextra_#1}} \_doc \sec Helper macros The macros here are just helpers for the macros to follow. They are not useful generally, but proved useful in the expandable context of writing to PDF files. Already the first one limits the use to \LuaTeX/ (but who needs other engines anyways :). \`\.emptyor` checks whether the first argument is empty, if not it expands the second argument which can use the text from the first argument with \`\.nonempty`. \`\.attrorempty` builds upon the first one and is really useful for PDF dictionaries, when we don't want to write an attribute without a value (a default specified by standard will be used instead). \_cod \_def\.emptyor#1#2{% \_immediateassignment\_edef\.nonempty{#1}% \_ifx\.nonempty\_empty\_else #2\_fi } \_def\.attrorempty#1#2{\.emptyor{#2}{/#1 \.nonempty}} \_doc There is a dillema for handling colors. While typesetting it is possible to use greyscale, CMYK or RGB colors. But there are contexts where it is possible to only use RGB colors. We want to provide the user with two possibilities of specifying colors: \begitems * RGB color using PDF triplet (e.g. `1 0 0`), * \OpTeX/ color using control sequence (e.g. `\Blue`) \enditems Both are handled by \`\.colortorgbdef`, which defines to the corresponding PDF RGB triplet. The indirection with defining a macro is because we want to use the processed color within expansion only contexts where grouping is not possible. \_cod \_def\.colortorgbdef#1#2{\_bgroup \_def\_setrgbcolor##1{##1}% \_def\_setcmykcolor##1{\_cmyktorgb ##1 ;}% \_def\_setgreycolor##1{##1 ##1 ##1}% \_xdef#1{#2}% \_egroup } \_doc \`\.xaddto``\macro`{} is a natural extension of \OpTeX's `\addto` that expands and is global.\nl \`\.tmp` is used throught the package for temporary values. \_cod \_def\.xaddto#1#2{\_edef\.tmp{#2}% \_global\_ea\_addto\_ea#1\_ea{\.tmp}% } \_doc This package defines a few commands in the form `\macro[][]{}`. To make it possible to omit the `[]` \`\.secondoptdef` is defined. `\.secondoptdef\{}` defines `\macro` with first mandatory argument in brackets (saved to \`\.name`). Second optional argument in brackets is scanned using helper macro defined with `\optdef` and is saved to `\_opt` token list). Additional can be specified as with `\optdef` (numbered from `#1`). \_cod \_def\.secondoptdef#1{% \_def#1[##1]{\_def\.name{##1}\.cs{sopt:\_string#1}}% \_ea\_optdef\_csname _pdfextra_sopt:\_string#1\_endcsname[]% } \_doc When processing comma separated lists sometimes it is needed to ignore the remaining text. For this we use \`\.untilend` macro which ignores everything up to dummy \`\.end`. This is analogous to \OpTeX/'s `\_finbody` used for the same purpose. Sometimes `\.end` is used as sentinel and compared in `\ifx` tests, hence we define it to a unique value. \_cod \_def\.untilend#1\.end{} \_def\.end{_pdfextra_end} \_doc For various uses it is necessary to know the number of page where something happens. This has to be handled asynchronously with `\write`. Here we use \OpTeX/ specific `.ref` file and associated macros, but this could be replaced as long as the same interface is exposed. \`\.setpageof` writes \`\.Xpageof` to the `.ref` file. In the next \TeX/ run `\.Xpageof` finds out the page number (`\gpageno`) from \OpTeX/'s `\_currpage` and saves it so that \`\.pageof` can retrieve it. In the first run we can't be sure of the page where the content will end up. As a rough estimate we take the current page~-- this actually works well for slides where page breaks are manual. When `.ref` file is read along with the defintion of `\.Xpageof` this package has not been loaded yet. Hence we can't use namespaced variants of `\.isdefined`, etc. \_cod \_refdecl{% \_def\.Xpageof#1{\_isdefined{_pdfextra_pageof:#1}\_iffalse \_sxdef{_pdfextra_pageof:#1}{\_ea\_ignoresecond\_currpage}\_fi }% } \_def\.setpageof#1{\_openref \_ewref\.Xpageof{{#1}}} \_def\.pageof#1{% \.trycs{pageof:#1}{% \_the\_numexpr\_gpageno+1\_relax % best effort = current page num }% } \_doc \label[files] \sec Handling of files Handling of files is a big topic of this package. Files are everywhere~-- files containing multimedia, JavaScript script files, attachments, externally referred files\dots Therefore a more sophisticated mechanism for handling files is needed. The mechanism introduced in this section handles all three cases of a {\em file specification}: \begitems * files embedded in the PDF (\"e", embedded file), * files determined by path (\"x", external file), * files determined by URL (\"u", url file). \enditems Although ideally all three would be interchangible this is not always the case, because e.g. some media files must be embedded and linking to external resources does not work with embedded files. In most cases there are two many names and other associated values involved: \begitems * Some kind of a \"friendly" name. This one is sometimes shown by PDF viewers. * The real name of the file. Also shown but in different contexts. * The path or URL used to determine the file. * MIME type of the file. \enditems For example when talking about \OpTeX/'s documentation we might have a friendly name of \"opdoc", file name of \"`optex-doc.pdf`", URL of \"\url{http://petr.olsak.net/ftp/olsak/optex/optex-doc.pdf}" and MIME type of \"application/pdf". Different subset of them is required in different contexts, but the user should only have to specify the friendly name (by which they will refer to the file) and the path/URL of the file. The rest will be deduced. The friendly name is used as a handle and {\em is usable} in all places where file specification is required (although it may not produce conforming output, see above). In this two step process~-- definition and (re)use~-- we introduce a command for defining files: \`\filedef``/ []{}`. The macro itself does general definitions and dispatches the type dependant work to other macros in the form `_filedef:`. \_cod \_def\.filedef/#1#2[#3]#4{% \.sxdef{filename:#3}{(\.filename{#4})}% \_edef\.tmp{\.exttomime{\.fileext{#4}}}% \_ifx\.tmp\_empty \_opwarning{MIME type of '#4' unknown, using '\.defaultmimetype'}% \_edef\.tmp{\.defaultmimetype}% \_fi \.sxdef{filemime:#3}{\.tmp}% \.cs{filedef:#1}{#3}{#4}% } \_nspublic \filedef ; \_doc Types \"e", \"x", \"u" are predefined, anything else would essentialy be a variant of these. External file (\"x") is determined only by path. \_cod \.sdef{filedef:x}#1#2{% \.slet{filespec:#1}{filename:#1}% } \_doc URL file (\"u") is determined by URL. Using all sorts of characters is allowed by using `\_detokenize`. This time it is necessary to create full {\em file specification}~-- a dictionary, where the \"file system" is URL. \_cod \.sdef{filedef:u}#1#2{% \.sdef{filespec:#1}{<>}% } \_doc Embedded files (\"e") are the most interesting ones. For further use (e.g. for displaying the embedded files as attachments) MIME type is required. It is saved in the stream as a `\Subtype`, encoded as a PDF name (e.g. `/video#2Fmp4`). The embedded file stream must be wrapped in a full {\em file specification}, which has the `/EF` (\"embedded file") entry. Also the friendly name is used for some purpose by PDF viewers, so it set in `/Desc` (description). \_cod \.sdef{filedef:e}#1#2{% \_edef\.tmp{\.cs{filemime:#1}}% \_isfile{#2}\_iffalse \_opwarning{file '#2' not found}% \_fi \_pdfobj stream attr{/Type /EmbeddedFile /Subtype \_ea\.mimetoname\_ea[\.tmp]} file {#2}% \_pdfrefobj\_pdflastobj \.sxdef{filestream:#1}{\_the\_pdflastobj\_space 0 R}% \_pdfobj {<>% >>}% \_pdfrefobj\_pdflastobj \.sxdef{filespec:#1}{\_the\_pdflastobj\_space 0 R}% } \_doc Now the less interesting part~-- determining the file names from paths and determining MIME types. The file name is the part after the last \"`/`" (if any). The file extension is the part after last \"`.`" (if any). \_cod \_def\.filename#1{\_ea\.filenameA#1/\.end} \_def\.filenameA#1/#2{\_ifx\.end#2#1\_else\_afterfi{\.filenameA#2}\_fi} \_def\.fileext#1{\_ea\.fileextA#1.\.end} \_def\.fileextA#1.#2{\_ifx\.end#2#1\_else\_afterfi{\.fileextA#2}\_fi} \_doc MIME type is determined from file extension (e.g. `mp4` is \"video/mp4"). For mapping of file extensions to MIME types we abuse \TeX/'s hash table which gets populated with \"known MIME types". This necessarily means that the database is incomplete. Users can define their own additional mappings, or they can contribute generally useful ones to this package. The default MIME type (used for unknown file extensions) is \"application/octet-stream"~-- binary data. The uninteresting MIME type database itself is at the very end (\ref[mime]). \_cod \_def\.mimetoname[#1/#2]{/#1\_csstring\#2F#2} \_def\.defaultmimetype{application/octet-stream} \_def\.exttomime#1{\.trycs{mimetype:#1}{}} \_doc Here we define an \OpTeX/ style \"is-macro" that checks whether the file has already been defined~-- \`\.isfiledefined``{}\iftrue` (or `\iffalse`). The case where the file has not been defined using `\filedef` can be handled in a lot of ways. As a default we interpret as path and try to embed it. Because the path from is used as the \"friendly name" the file will be embedded only once even when requested more times. \_cod \_def\.isfiledefined#1#2{\.isdefined{filespec:#1}\_iftrue\_else \_afterfi{\.fileundefined{#1}}\_fi#2% } \_def\.fileundefined#1{\_isfile{#1}\_iftrue\.filedef/e[#1]{#1}\_else \_opwarning{file '#1' not found, ignored}\_ea\_unless\_fi } % strict requirement of preceeding `\filedef` can be set like this: %\_def\.fileundefined#1{\_opwarning{file '#1' is not defined, ignored}\_unless} \_doc \label[actions] \sec PDF actions The core of interactivity in PDF are actions. They are all initialy handled by \`\pdfaction``[]`. is a comma separated list of `:`. Leading spaces in the elements of the list are ignored using undelimited-delimited argument pair trick. An invocation could look like this: \begtt \pdfaction[ js:{app.alert("Yay JavaScript, going to page 5");}, ilink:pg:5, transition:Wipe, ] \endtt This is why we have to be very careful when loading the contents between `[]` to arguments. In particular, we can't split immediatly using `[#1:#2]`, because this would discard the braces guarding the comma in the JavaScript code. However we also need to find out the {\em type} of action which is taken as a type of the first action (`js` in this case). \`\.pdfactiontype``[]` does this~-- we don't mind that there the braces are lost. `\pdfaction` processes the list, to create a chain of actions using `/Next` field. The handling of each action type is up to macro `\_pdfextra_action`, which receives `[:]`. Because of this a single type handler can handle multiple different actions, as is the case with `\.ilinkaction` which is the fallback for unknown action types. \_cod \_def\.pdfaction[#1#2]{\.pdfactionA#1#2,\.stop\.end} \_def\.pdfactionA#1,#2#3\.end{% <<% \.pdfactionB[#1]% % next action \_ifx\.stop#3\_else\_space /Next \_afterfi{\.pdfactionA#2#3\.end} % intentional space \_fi >> } \_def\.pdfactionB[#1:#2]{\.trycs{#1action}{\_ea\.ilinkaction}[#1:#2]} \_nspublic \pdfaction ; \_def\.pdfactiontype[#1:#2]{#1} \_doc \label[actions-additional] \secc Additional actions Some PDF objects, like pages and some annotations, can also have \"additional actions". These are actions which will be executed when an event happens~-- like page getting opened for `/O` action in page's additonal actions or `/PO` in annotation's additional actions. For constructing these additional actions we define a helper macro \`\.pdfaactions`. The use is as something follows: \begtt \catcode`<=13 \adef|{\csstring<} /AA || \.pdfaactions{ {O} {} {C} {} } >> \endtt To produce something this: \begtt \catcode`<=13 \adef|{\csstring<} /AA || /O ||>> /C ||>> >> \endtt \_cod \_def\.pdfaactions#1{<<\.pdfaactionsA #1\.end\.end>>} \_def\.pdfaactionsA#1#2{\_ifx\.end#1\_else /#1 \_ea\.pdfaction\_ea[#2]\_ea\.pdfaactionsA\_fi} \_doc \label[actions-link] \secc Link annotations The main use of actions~-- annotations of `/Subtype /Link`. Annotation of this type creates an active rectangular area on the page that executes a PDF action (or chain of them in the general case). \`\hlink``[]` is macro that typesets and makes area occupied by it active according to . All action types are supported, the mechanism is completely generic. The `\pdfstartlink`/`\pdfendlink` primitives are used to denote the part of the page where appears as active. \LuaTeX/ will then handle even the situations where gets broken across multiple lines (by creating multiple rectangular annotations to cover all `\hbox`es). \_cod \_def\.hlink[#1]#2{\_bgroup\_def\#{\_csstring\#}% \_edef\.type{\.pdfactiontype[#1]}% \_quitvmode\_pdfstartlink \.linkdimens attr{\_pdfborder{\.type}}% user{/Subtype /Link /A \.pdfaction[#1]}\_relax \_localcolor\.linkcolor{\.type}#2\_pdfendlink\_egroup } \_nspublic \hlink ; \_doc Use `\hlink` as the backing command for OpTeX's \"higher level" linking commands (`\ilink` and `\ulink`). The lower level ones (`\xlink` and its predecessor `\link` actually have completely different semantics with regards to color, so we keep them as they are. \_cod \_protected\_def\_ilink[#1]#2{\.hlink[#1]{#2}} \_protected\_def\_ulink[#1]#2{{\_escapechar=-1 \_ea}\_expanded {\_noexpand\.hlink[url:\_detokenize{#1}]}{#2}} \_public \link \ilink \ulink ; %\_protected\_def\_link[#1]#2#3{\_hlink[#1]{#3}} %\_protected\_def\_xlink#1#2#3#4{\_hlink[#1:#2]{#4}} \_doc Two customizations of `\hlinks` are possible: \begitems * Dimensions of rectangular areas created by `\pdfstartlink`/`\pdfendlink`. This is done using \`\.linkdimens` (analogous to \OpTeX's `\linkdimens`). Dimensions that are unset are taken from the respective `\hbox`es. \`\lininglinks` sets the dimensions for running text~-- it covers all space of a line using `\baselineskip`. \`\nolininglinks` sets no dimensions, this is useful for buttons, that may have larger height/depth than a line. * The color is determined from the type of link (that is, the first action in ) by checking `\_linkcolor` (compatible with \OpTeX/). As a fallback `\_ilinkcolor` is used (set by \OpTeX's `\hyperlinks`) for all links except for URLs, where `\_elinkcolor` is used instead. If even these fallback colors are not defined (`\hyperlinks` isn't used), then the most generic `\_linkcolor` will be taken or no color will be set. \enditems \_cod \_def\.lininglinks{% \_def\.linkdimens{height.75\_baselineskip depth.25\_baselineskip}% } \_def\.nolininglinks{\_def\.linkdimens{}} \.lininglinks \_nspublic \lininglinks \nolininglinks ; \_def\.linkcolor#1{\_trycs{_#1linkcolor}{\_trycs{_ilinkcolor}{\_trycs{_linkcolor}{}}}} % \_urllinkcolor = \_elinkcolor with fallbacks \_def\_urllinkcolor{\.linkcolor{e}} \_doc \secc Open action The document itself has one action defined in the document catalog. It is called `/OpenAction`. We allow the user to set it using the familiar syntax with the command \`\openaction``[]`. Internally we could directly set it by appending to the catalog using the primitive `\pdfcatalog`, but \LuaTeX/ (pdf\TeX/ really) allows setting the action with special syntax. This has the benefit that it is not allowed to set the action more than once. \_cod \_def\.openaction[#1]{\_pdfcatalog{} openaction user{\.pdfaction[#1]}\_relax} \_nspublic \openaction ; \_doc \label[actions-jump] \secc Jump actions These are the most typical actions. Even \LuaTeX/ itself handles them, although we don't use the possibility for maintaining generality. There are a few types of jump actions: \begitems * `/GoTo` actions are the classic internal links to named destinations in the PDF file (created by `\pdfdest` primitive or \OpTeX/'s `\dest`). The destination names include also the type of internal link (e.g. `ref:section1`). They are handled by \`\.ilinkaction``[:]`. * `/URI` actions which are in most cases used as \"goto URL" actions. These are not that useful directly, because special characters should be handled before this actions is used (like with `\url`). The low level use is \`\.urlaction``[url:]`. * \"Goto remote" actions, which can jump to a destination in another PDF file~-- either determined by name, or by page number. The external files are expected to be defined by `\filedef` (but not the embedded variant). The use is either \`\.extrefaction``[extref::]` for links to named destination or \`\.extpgrefaction``[extpgref::]` for page destinations. Customization is possible with \`\.extrefextra`, by default opening in a new windows is requested. \enditems \_cod \_def\.ilinkaction[#1:#2]{/S /GoTo /D (#1:#2)} \_def\.urlaction[#1:#2]{/S /URI /URI (#2)} \_def\.extrefaction[#1:#2:#3]{/S /GoToR /F \.cs{filespec:#2} /D (#3) \.extrefextra } \_def\.extpgrefaction[#1:#2:#3]{/S /GoToR /F \.cs{filespec:#2} /D [\_the\_numexpr#3-1\_relax\_space /Fit] \.extrefextra } \_def\.extrefextra{/NewWindow true} \_doc Transition action is not really a jump action in of itself, but is only useful when chained after jump actions, so we define it here. Transitions (as page attributes) are handled more thoroughly in section~\ref[transitions]. The use would look something like:\nl \`\.transitionaction`% `[transition:::]`, where all fields omitted from right take the default values. \_cod \_def\.transitionaction[#1:#2]{/S /Trans \.attrorempty{Trans}{\.maketrans[#2]}} \_doc \secc Named actions User can request arbitrary \"named" action with \`\.namedaction``[named:]`. See user documentation for details. \_cod \_def\.namedaction[#1:#2]{/S /Named /N /#2} \_doc \secc JavaScript actions JavaScript actions have two forms, either \`\.jsaction``[js:]` or `\.jsaction``[js: