% \iffalse meta-comment % %% File: l3pdfpdffield-textfield.dtx % % Copyright (C) 2021-2024 The LaTeX Project % % It may be distributed and/or modified under the conditions of the % LaTeX Project Public License (LPPL), either version 1.3c of this % license or (at your option) any later version. The latest version % of this license is in the file % % http://www.latex-project.org/lppl.txt % % This file is part of the "LaTeX PDF management testphase bundle" (The Work in LPPL) % and all files in that bundle must be distributed together. % % ----------------------------------------------------------------------- % % The development version of the bundle can be found at % % https://github.com/latex3/pdfresources % % for those people who are interested. % %<*driver> \DocumentMetadata{} \documentclass[full]{l3doc} \usepackage{array,booktabs} \usepackage{l3pdffield-testphase} \hypersetup{pdfauthor=The LaTeX Project, pdftitle=l3pdffield (LaTeX PDF management testphase bundle)} \begin{document} \DocInput{\jobname.dtx} \end{document} % % \fi % \providecommand\hook[1]{\texttt{#1}} % \title{^^A % The \pkg{l3pdffield-textfield} module\\ Commands to create textfield form fields ^^A % \\ \LaTeX{} PDF management testphase bundle % } % % \author{^^A % The \LaTeX{} Project\thanks % {^^A % E-mail: % \href{mailto:latex-team@latex-project.org} % {latex-team@latex-project.org}^^A % }^^A % } % % \date{Version 0.96n, released 2024-10-27} % % \maketitle % \begin{documentation} % \section{\pkg{l3pdffield-textfield} Introduction} % \ExplSyntaxOn % Enter~your~name:\quad \pdffield_textfield:n{name=name,fontcolor=[RGB]{00,33,99},width=5cm} % \ExplSyntaxOff % % This is the documentation for textfield fields, for general information about form fields % check the documentation l3pdffield. % % Textfields allows the user to input text which is then rendered by the PDF viewer and % often can also be saved together with the PDF. % % Currently the package doesn't initialize the font |/Helv| % used by default in the fields (It works also without it, but this isn't fully compliant.) % I don't want to setup the same font twice and haven't yet decided how % to organize the collaboration with hyperref. So for now you should load hyperref % and issue the \cs{Form} command. % % Please keep in mind % \begin{itemize} % \item Not every PDF viewer supports textfields. % \item The font and the exact position of the chars depends on the PDF viewer. % \item The handling can depend on settings in the PDF viewer. In adobe reader for % example I had to disable an option to avoid that it tries to create an appearance % itself % \item Standards like pdf/A disable features of form fields too % (as you typically can't change the PDF). % \end{itemize} % % \subsection{About fonts} % % The font color and font size can be changed with the keys |fontcolor| and % |fontsize| described below. This works quite reliably (but e.g. % the PDF viewer of my browser insists to show the font in blue while editing). % % Much more difficult is the font family: % a typical wish for textfields is that a font matching the document font is used % in the fields. But how can that be done? % Obviously it is not possible like with a checkbox to prepare and include appearances % with the right look, the PDF reader has to render the text dynamically. % The PDF reference mentions only one way to pass a font setting to the text field: % The |DA| key can contain a font operator and the fontname used should be added % along with a object reference of the font to the form resources % in the |AcroForm/DR/Font| dictionary. The question is: what does a PDF renderer % make with this data? Clearly the main resources to render % the text can not be to rely on an embedded font and a PDF font operator as both % is not enough % to guarantee a sensible text support: a font operator is normally used in % the page stream along with glyph indices and positioning instructions, not % with unicode input, and typically a font is only partially embedded. % This means the PDF viewers and editors actually have to use external % resources--system fonts, or fonts that come along with the viewer and libraries % to handle font shaping. % % Hyperref may add a reference the type1 font helvetica to the DA key, but % PDF viewers use actually Arial. And if one doesn't add a font with % |DA| and |DR/Font| the text field works nevertheless. % % This doesn't mean that the DA/DR info is ignored altogether. % Adobe Reader and Pro seems to use it to choose a fitting fallback font: % \begin{itemize} % \item One can change the font by simply using the font name (the examples use % the |font| key of this module). One get courier with |font=courier|, % times with |font=times|, % comic sans with |font=ComicSansMS|, DejaVu with |font=DejaVuSans|. The fonts % don't need to be used in the document or added as resources in the DR/Font dictionary. % Some fonts work better than other: comic sans is quite unproblematic, % but DejaVu seems to trigger a font search first and so is slower (perhaps the. % \item If one fill and then save such a PDF at least adobe adds % the missing font resources to the PDF. % \end{itemize} % % This lazy font setting doesn't work with other PDF viewers. % In other test I had better results by actually embedding a few glyphs % of the font and then adding the font % as resource to the DR/Font dictionary. Sadly this requires lualatex, only there is % possible to retrieve the internal font name and font object number for a larger set % of fonts---with pdflatex it works only for fonts not using a virtual font, and xelatex % has no access at all. The code for lualatex looked like this (the font one wants % to use should be active) % \begin{verbatim} % \pdffield_textfield:n {name=text,font=F\pdffeedback~fontname\font} % \pdfmanagement_add:nee{Catalog/AcroForm/DR/Font} % {F\pdffeedback~fontname\font} % {\pdffeedback~fontobjnum\font \c_space_tl 0 \c_space_tl R} % \end{verbatim} % % \subsection{Vertical alignment} % There is no way to set a reference point for the baseline. % Alignment must achieved by % fiddling with the height and depth of the field. The defaults (which uses as % height the fontsize, and a bit depth) works okay in adobe reader with arial. % If the font is set to courier, the text jumps up and one has to decrease the height % by around 30\%. For a multiline field which should be top aligned you should % increase the depth by the wanted amount \emph{and} the height by around 2pt. % % The geometry of the fields is seen by TeX, and so can influence the line spacing. % If needed you should hide the height with \cs{raisebox} or \cs{smash}. % % \section{Textfields} % Input a value: % \ExplSyntaxOn % \pdffield_textfield:n{name=test,width=4cm,height=0.7\baselineskip,depth=0.3\baselineskip} % \ExplSyntaxOff % % \bigskip % \subsection{Commands} % \begin{function}{\pdffield_textfield:n} % \begin{syntax} % \cs{pdffield_textfield:n}\Arg{key val list} % \end{syntax} % This creates a textfield. The list of allowed keys is described below. % The \meta{key val list} should at least set the name, without it the default name % |textfield| is used. Textfields with the same % name belong to the same field and are filled together. The default appearance % is a light gray background. % The default appearance is setup at the first use. % \end{function} % % % \subsection{Keys} % % The new textfield command accept all field and annot keys from l3pdffield, % please check the documentation there. The list here mentions only a few % central keys, and the keys which are either specific for textfields, or have % changed functionality. % % Disabled keys are % \begin{itemize} % \item |FT| is overwritten. % \item |AS| is cleared. % \item |DA| is overwritten. % Locally use |fontcolor|, |fontsize| and |font| instead. % Globally you can set the |DA| key in the catalog with for example % \begin{verbatim} % \pdfmanagement_add:nnn{Catalog/AcroForm}{DA}{(/Helv~10~Tf~1~1~0~rg)} % \end{verbatim} % \item For textfields only the field flags |ReadOnly|, |Required| |NoExport| % |Multiline|, |Password|, |FileSelect|, |DoNotSpellCheck|, |DoNotScroll| and |Comb| % make sense. % If |Comb| is set, |Multiline|, |Password| and |FileSelect| are unset, |MaxLen| is % set to 10 if it hasn't been set previously. % \end{itemize} % % The keys |value| and |default| are mapped to |V| and |DV| for this field type, see % below. % % % \begin{function}{preset-textfield} % \begin{syntax} % |preset-textfield| = \Arg{key-val-list} % \end{syntax} % This allows to set default keys for a textfield. % \end{function} % % \begin{function}{name,T} % \begin{syntax} % |name| = \meta{partial name}\\ % |T| = \meta{partial name} % \end{syntax} % This sets like the |T| key for fields the partial name of the field. The value % shouldn't contain a period, be not empty and sensibly consist of simple chars. % Additionally the value is used to create the field ID. % This means that textfield with the same partial name are annotations % with the same field as parent and are filled together---this % what is typically expected. % The field ID is then internal and can not be used to % attach another annotation. % For explicit control of the field ID use the |fieldID| key. % \end{function} % % \begin{function}{fieldID} % \begin{syntax} % |fieldID| = \meta{field ID}\\ % \end{syntax} % \emph{For experts only!} % This allows to give the textfield a specific ID. This is only useful % in the context of a larger fieldset or if you want to attach another annotation % to the field with \cs{pdffield_annot:n}. If used wrongly you can % easily create an invalid fieldset. It allows you to create to fields with the % same partial name, but if you want to see both % you need to ensure that their full names are % different---for example by adding some parent fields. % \end{function} % % \begin{function}{parent} % \begin{syntax} % |parent| = \meta{field ID}\\ % \end{syntax} % This is only needed if the field should be part % of a larger fieldset. The value should be a field ID of a field created previously % with \cs{pdffield_field:nn}. % \end{function} % % % \begin{function}{altname,TU} % \begin{syntax} % |altname| = \meta{string}\\ % |TU| = \meta{string}\\ % \end{syntax} % This is sets an alternative name for user interaction. % This name can only be set at the first textfield instance, when the field is initialized. % \end{function} % % \begin{function}{mappingname,TM} % \begin{syntax} % |mappingname| = \meta{string}\\ % |TM| = \meta{string}\\ % \end{syntax} % This is sets an alternative name for export. % This name can only be set at the first textfield instance, when the field is initialized. % \end{function} % % \begin{function}{width,height,depth} % \begin{syntax} % |width| = \meta{dim expression}\\ % |height| = \meta{dim expression}\\ % |depth| = \meta{dim expression} % \end{syntax} % These keys allow to set the dimensions of textfield instance. % The value should be a dimension expression. By default % |width| is 3cm, the |height| uses the fontsize (\cs{f@size} in pt), % the |depth| is 0.3\cs{f@size}. % \end{function} % % \begin{function}{appearance,rollover-appearance,down-appearance} % \begin{syntax} % |appearance| = \meta{name}\\ % |rollover-appearance| = \meta{name}\\ % |down-appearance| = \meta{name} % \end{syntax} % This keys sets the normal appearance, the rollover appearance (when the % mouse hovers over the textfield) and the down appearance (when the % mouse clicks). They expect the name of an existing form Xobject as value. % The initial value is |pdffield/textfield/default| % for the normal appearance and shows a light gray background. % The other appearance are not set by default (and it is quite unclear if they % make sense for a textfield). % \end{function} % % \begin{function}{V,value} % \begin{syntax} % |V| = \meta{text}\\ % |value| = \meta{text} % \end{syntax} % This sets the start text in the field. The keys have an effect only at the first % instance of the textfield, when the field is initialized. % \end{function} % % \begin{function}{DV,default} % \begin{syntax} % |DV| = \meta{text}\\ % |default| = \meta{text} % \end{syntax} % This sets the text which is shown if the form is reset. % The keys have an effect only at the first % instance of the textfield, when the field is initialized. % \end{function} % % \begin{function}{fontcolor} % \begin{syntax} % |fontcolor| = \meta{color expression} \verb"|" [\meta{model}]\Arg{values}\\ % \end{syntax} % This is sets the color of font in the textfield. Internally currently RGB is used. % The colors used in % \meta{color expression} must be known to the \pkg{l3color} commands. % The initial color is black. It is a \emph{field} setting, that means instances % share the color. % \end{function} % % \begin{function}{fontsize} % \begin{syntax} % |fontsize| = \meta{dim expression} % \end{syntax} % This is sets the size of the font in the textfield. % The default value is the current font size (\cs{f@size} in pt). % It is a \emph{field} setting, that means instances % share the size. % \end{function} % % \begin{function}{font} % \begin{syntax} % |font| = \meta{symbolic font name} % \end{syntax} % This is sets the font in the textfield. See the discussion at the begin of % the documentation about some background. The default value is |Helv| and this % name is setup if you load hyperref and issue the \cs{Form} command. % The default value is the current font size (\cs{f@size} in pt). % It is a \emph{field} setting, that means instances % share the font. % \end{function} % % \subsection{Using with hyperref} % The \cs{TextField} command from hyperref also prints a label, something that the % command here doesn't do. A redefinition like the following should allow \cs{TextField} % to use the commands of this module. Be aware that the behaviour will not be identical! % Not every setting and key from \pkg{hyperref} has been copied. % % \begin{verbatim} % \ExplSyntaxOn\makeatletter % \def\@TextField[#1]#2{\LayoutTextField{#2}{\pdffield_textfield:n {name=#2,#1}}} % \ExplSyntaxOff\makeatother % \end{verbatim} % % % \end{documentation} % % \begin{implementation} % \DoNotIndex % {\\ % ,\bitset_clear:N % ,\bitset_new:Nn % ,\bitset_set_false:Nn % ,\bitset_set_true:Nn % ,\bitset_to_arabic:N % ,\bitset_item:Nn % ,\bool_new:N % ,\box_dp:N % ,\box_ht:N % ,\clist_map_inline:nn % ,\color_export:nnN % ,\color_set:nn % ,\color_set:nnn % ,\color_select:n % ,\cs_new_protected:Npn % ,\cs_new_protected:cpn % ,\cs_set_eq:NN % ,\cs_gset_eq:cN % ,\cs_set_protected:Npn % ,\cs_generate_variant:Nn % ,\cs_gset_eq:NN % ,\c_space_tl % ,\csname % ,\dim_eval:n % ,\dim_new:N % ,\dim_to_decimal_in_bp:n % ,\endcsname % ,\exp_args:Ne % ,\fboxsep % ,\fp_eval:n % ,\f@size % ,\group_begin: % ,\group_end: % ,\hbox_to_wd:nn % ,\hfill % ,\hook_gput_code:nnn % ,\int_eval:n % ,\int_compare:nNnT % ,\l_keys_choice_int % ,\keys_define:nn % ,\keys_set:nn % ,\mode_leave_vertical: % ,\msg_error:nnn % ,\msg_error:nnnn % ,\msg_new:nnn % ,\msg_warning:nn % ,\msg_warning:nnn % ,\msg_warning:nnnnn % ,\NeedsTeXFormat % ,\normalsize % ,\paperheight % ,\paperwidth % ,\pdf_name_from_unicode_e:n % ,\pdf_object_if_exist:nTF % ,\pdf_object_if_exist:nF % ,\pdf_object_new:n % ,\pdf_object_ref:n % ,\pdf_object_ref_last: % ,\pdf_object_unnamed_write:nn % ,\pdf_object_write:nnn % ,\pdf_string_from_unicode:nnN % ,\pdfannot_box_ref_last: % ,\pdfannot_dict_put:nnn % ,\pdfannot_dict_remove:nn % ,\pdfannot_widget_box:nnn % ,\pdfdict_if_empty:nTF % ,\pdfdict_get:nnN % ,\pdfdict_new:n % ,\pdfdict_put:nnn % ,\pdfdict_remove:nn % ,\pdfdict_use:n % ,\pdfmanagement_add:nnn % ,\pdfmeta_standard_verify:nTF % ,\pdfxform_if_exist:nTF % ,\pdfxform_new:nnn % ,\pdfxform_ref:n % ,\phantom % ,\prg_do_nothing: % ,\ProvidesExplPackage % ,\quark_if_no_value:NT % ,\raisebox % ,\rule % ,\seq_gput_right:Nn % ,\seq_if_exist:NTF % ,\seq_new:N % ,\seq_use:Nn % ,\smash % ,\str_if_empty:NTF % ,\str_if_in:NnTF % ,\str_new:N % ,\strut % ,\strutbox % ,\tl_put_right:Nn % ,\tl_if_empty:NTF % ,\tl_if_empty:NT % ,\tl_if_empty:NF % ,\tl_put_left:Nn % ,\tl_if_empty:nTF % ,\tl_if_head_eq_charcode:nNTF % ,\tl_new:N % ,\tl_set:Nn % ,\tl_to_str:n % ,\use:c % } % \section{\pkg{l3pdffield-textfield} Implementation} % \begin{macrocode} %<*package> %<@@=pdffield> % \end{macrocode} % \subsection{Variables} % \begin{variable} % { % \l_@@_DA_fontcolor_tl, \l_@@_DA_fontsize_dim, \l_@@_DA_fontname_tl % } % Variables for the font setup in the DA key. % \begin{macrocode} \tl_new:N \l_@@_DA_fontcolor_tl \dim_new:N \l_@@_DA_fontsize_dim \tl_new:N \l_@@_DA_fontname_tl % \end{macrocode} % \end{variable} % % \subsection{Appearances} % The default appearance is a light gray background. % % \begin{macro}{\@@_textfield_default_appearance:} % This defines the standard appearance. It is setup at the first % use of a textfield. % \begin{macrocode} \cs_new_protected:Npn {\@@_textfield_default_appearance:} { \pdffield_appearance:nn {pdffield/textfield/default} { { \color_select:n{black!5!white}\rule{\paperwidth}{\paperheight} } } \cs_gset_eq:NN \@@_textfield_default_appearance: \prg_do_nothing: } % \end{macrocode} % \end{macro} % %\subsection{Creating the field} % \begin{macro}{\@@_textfield_field:n} % A field should be created only if the name doesn't exist % \begin{macrocode} \cs_new_protected:Npn \@@_textfield_field:n #1 %name { \pdf_object_if_exist:nF {@@/field/@@/textfield/#1} { \@@_field:n { @@/textfield/#1 } } \keys_set:nn {pdffield}{parent=@@/textfield/#1} } \cs_generate_variant:Nn \@@_textfield_field:n {V} % \end{macrocode} % \end{macro} % % \subsection{Assembling the textfield} % % \begin{macro}{\@@_textfield:n} % At first we map the handler and setup the appearance. % \begin{macrocode} \cs_new_protected:Npn \@@_textfield:n #1 { \group_begin: \cs_set_eq:NN\@@_V_handler:nN \@@_textfield_V_handler:nN \cs_set_eq:NN\@@_value_handler:n \@@_textfield_value_handler:n \cs_set_eq:NN\@@_default_handler:n \@@_textfield_default_handler:n \@@_textfield_default_appearance: % \end{macrocode} % Setting up the defaults and processing the keys. % \begin{macrocode} \keys_set:nn {pdffield} { ,fieldID= ,name=textfield ,appearance = pdffield/textfield/default ,width = 3cm ,fontsize= \f@size pt ,height = \f@size pt, depth = \fp_eval:n {0.3*\f@size} pt, % font defaults!! } \keys_set:nn { pdffield }{@@/preset/textfield,#1} % \end{macrocode} % We need to check if Comb is used and setup some flags in this case. % \begin{macrocode} \int_compare:nNnT {\bitset_item:Nn \l_@@_Ff_bitset {Comb}}={1} { % warning if set? \keys_set:nn { pdffield } { ,unsetFf={FileSelect,Multiline,Password} } \pdfdict_get:nnN {l_@@/field}{MaxLen}\l_@@_tmpa_tl \quark_if_no_value:NT \l_@@_tmpa_tl { \keys_set:nn { pdffield} { MaxLen = 10 %variable } % warning } } % \end{macrocode} % Now the postprocessing. % \begin{macrocode} \keys_set:nn { pdffield } { ,FT= Tx ,AS= ,DA= { \pdf_name_from_unicode_e:n{\l_@@_DA_fontname_tl} \c_space_tl \dim_to_decimal_in_bp:n{\l_@@_DA_fontsize_dim} \c_space_tl Tf \c_space_tl \l_@@_DA_fontcolor_tl \c_space_tl %\l_@@_text_DAextra_tl } } % \end{macrocode} % If no field ID exists, we get it from the T key. % \begin{macrocode} \tl_if_empty:NT\l_@@_fieldID_tl { \pdfdict_get:nnN {l_@@/field}{T}\l_@@_fieldID_tl \tl_put_left:Nn \l_@@_fieldID_tl {@@/textfield/} } \@@_textfield_field:V\l_@@_fieldID_tl \@@_annot: \group_end: } % \end{macrocode} % \end{macro} % % \subsection{Keys} % Most keys are inherited simply the ones from the generic field and annot keys. % A key to decide if the box is initially checked or not. % We stay in the same family so that we can build a style. % \begin{macro}{fontcolor,fontsize,font} % \begin{macrocode} \keys_define:nn {pdffield} { ,fontcolor .code:n = { \@@_color_set:nn {@@/tmp}{#1} \color_export:nnN{@@/tmp}{space-sep-rgb}\l_@@_DA_fontcolor_tl \tl_put_right:Nn \l_@@_DA_fontcolor_tl{~rg} } ,fontcolor .initial:n = black, ,fontcolor .groups:n = {textfield} ,font .tl_set:N = \l_@@_DA_fontname_tl ,font .initial:n = {Helv} ,font .groups:n = {textfield} ,fontsize .dim_set:N = \l_@@_DA_fontsize_dim ,fontsize .initial:n = {10bp} ,fontsize .groups:n = {textfield} } % \end{macrocode} % \end{macro} % % \subsection{Handler} % \begin{macro}{\@@_textfield_V_handler:nN} % The handler for V/DV, it creates a string. % \begin{macrocode} \cs_new_protected:Npn \@@_textfield_V_handler:nN #1#2 { \pdf_string_from_unicode:nnN {utf16/hex}{#1}#2 } % \end{macrocode} % \end{macro} % \begin{macro}{\@@_textfield_value_handler:n,\@@_textfield_default_handler:n} % The handler for value and default. They simply map to V,DV here. % \begin{macrocode} \cs_new_protected:Npn \@@_textfield_value_handler:n #1 { \keys_set:nn{pdffield}{V={#1}} } \cs_new_protected:Npn \@@_textfield_default_handler:n #1 { \keys_set:nn{pdffield}{DV={#1}} } % \end{macrocode} % \end{macro} % \subsection{User command} % \begin{macro}{\pdffield_textfield:n} % \begin{macrocode} \cs_set_eq:NN \pdffield_textfield:n \@@_textfield:n % % \end{macrocode} % \end{macro} %\end{implementation} %\PrintIndex