% \iffalse meta-comment % %% File: latex-lab-graphic.dtx (C) Copyright 2022-2025 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 % % https://www.latex-project.org/lppl.txt % % % The development version of the bundle can be found below % % https://github.com/latex3/latex2e/required/latex-lab % % for those people who are interested or want to report an issue. \def\ltlabgraphicdate{2025-04-08} \def\ltlabgraphicversion{0.80f} % %<*driver> \documentclass{l3doc} \EnableCrossrefs \CodelineIndex \begin{document} \DocInput{latex-lab-graphic.dtx} \end{document} % % % \fi % % % \title{The \textsf{latex-lab-graphic} package\\ % Tagging of included graphics } % \author{\LaTeX{} Project\thanks{Initial implementation done by Ulrike Fischer}} % \date{v\ltlabgraphicversion\ \ltlabgraphicdate} % % \maketitle % % \newcommand{\xt}[1]{\textsl{\textsf{#1}}} % \newcommand{\TODO}[1]{\textbf{[TODO:} #1\textbf{]}} % \newcommand{\docclass}{document class \marginpar{\raggedright document class % customizations}} % % \providecommand\hook[1]{\texttt{#1}} % \NewDocElement[printtype=\textit{plug},idxtype=plug,idxgroup=Plugs]{Plug}{plugdecl} % \NewDocElement[printtype=\textit{socket},idxtype=socket,idxgroup=Sockets]{Socket}{socketdecl} % % \newcommand\tikzname{ti\textit{k}Z} % \begin{documentation} % \begin{abstract} % The following code implements a first draft for the tagging of graphics % included with \cs{includegraphics} and the \env{picture} environment. % \end{abstract} % % % \section{Introduction} % % Tagging of pictures is non trivial. % % \begin{enumerate} % \item Pictures generally can have various purposes and so different \emph{tagging modes} must % be provided: % \begin{itemize} % \item The pictures can be purely \emph{ornamental} and \emph{decorative}, % e.g., (always/usually) some page border. % This should normally be tagged as \emph{artifact}, either in a \texttt{artifact} % MC-chunk or as an \texttt{Artifact} structure\footnote{The second option exists only in PDF 2.0}. % % \item The pictures can be \emph{illustrative figures}. % This should normally be tagged as a \texttt{Figure} structure with \emph{alternative text}. % % \item The pictures can represent a symbol. This should be tagged as a \texttt{Span} structure element % with an \texttt{/ActualText} mapping to some Unicode Codepoint(s) % (or perhaps even directly in the stream with a Span BDC with an \texttt{/ActualText}). % % \item The pictures can also be intended for consumption as normal \emph{text} % For example the todonotes package uses a % \tikzname{} picture to surround the text in a node with some colored frame and % background. % In this case the text (which can contain more elements like lists) % should be tagged as usual and put in an \texttt{Aside} structure while the decorative % elements should be marked up as artifacts. % % \item There are also case where no tagging is wanted, e.g. because the tagging % is done by surrounding commands, in this case the begin/end sockets should be transparent and % do nothing. % % \item And naturally there can be more complicated scenarios with % mixtures of these elements, e.g., some text % in nodes in a \tikzname{} picture can be meaningful % while other nodes still should be tagged as artifact. % \end{itemize} % % \item The various packages that allow to draw pictures uses lots of boxes and % moves them around and that makes is not easy to get the tagging right -- % especially with pdflatex where one has to insert the literals at the right time. % % \item When the picture is tagged as \texttt{Figure}, the PDF-UA standards require % an attribute with a \texttt{BBox} key in the structure. That BBox describes % the placement of the picture on the page, % and this typically require some low-level hacking into the picture code to calculate % the values. % \end{enumerate} % % The code here handles directly only the tagging of pictures included with \cs{includegraphics} % and the \env{picture} environment. But the used method and the documentation tries % to stay as general as possible, to make it easy to adapt the code to pictures drawn % with other packages like \pkg{l3draw}, \pkg{tikz}, \pkg{pstricks}, \pkg{luamplibs} or similar packages. % % \section{General implementation needs and ideas} % % \subsection{User interfaces} % % The tagging of pictures can not be done fully automatically: user % have to add alternative text or mark up a picture as an artifact. % It is important that the relevant user interfaces are similar across % all picture/graphic packages to make it % easy for authors to adapt their documents. % % We therefore recommend package authors to implement an interface % a key-value interface like the following. % % \subsubsection{Tagging mode of individual graphics} % To change the tagging mode of an individual graphic, the keys % \texttt{artifact} (decorations), \texttt{alt} (illustrative), % and \texttt{actualtext} (symbol) should be used. The keys \texttt{alt} % (and also \texttt{actualtext}) take a text as argument. % % \begin{verbatim} % \includegraphics[artifact]{example-image} % \begin{tikzpicture}[artifact] ... \end{tikzpicture} % \tikz[artifact]{...} % \begin{picture}[artifact]...\end{picture} % % \includegraphics[alt=example image]{example-image} % \begin{tikzpicture}[alt=\myalttext] ... \end{tikzpicture} % \tikz[alt=example image]{...} % \begin{picture}[alt=example image]...\end{picture} % % \includegraphics[actualtext=A]{example-image-A} % \begin{tikzpicture}[actualtext=A] ... \end{tikzpicture} % \tikz[actualtext=A]{...} % \begin{picture}[actualtext=A]...\end{picture} % \end{verbatim} % % Additionally, a key \texttt{tagging-setup} can be % provided that allows to handle more complicated cases, e.g., % % \begin{verbatim} % \includegraphics[tagging-setup={false}]{example-image} %no tagging at all % \begin{tikzpicture}[tagging-setup={artifact}] ... \end{tikzpicture} % \begin{tikzpicture}[tagging-setup={text}] ... \end{tikzpicture} % \begin{tikzpicture}[tagging-setup={alt=Water (H20),tag=Formula}] ... \end{tikzpicture} % \end{verbatim} % % This key is fully implemented for \cs{includegraphics} and \env{picture} but only % partially in the \tikzname{} module. % % \subsubsection{Setting the tagging mode for a scope}\label{sec:scope} % % Packages can also provide interfaces to change the tagging mode for all pictures or % nodes in a scope. % % If this is done side-effects on the tagging of other picture % types must be considered: % If the generic sockets declared below are used % (which are then used also by \cs{includegraphics}, \env{picture} % and perhaps more environments) a change of the tagging mode can % affect all pictures types using these sockets in the same scope. % % This means that packages that want to offer \enquote{scope support} % but restrict it to their own picture type should either use % their own sockets modelled after the generic sockets, % or use some specific variable to control the change of the tagging mode. % % With \tikzname{} \enquote{scope support} could be implemented rather easily as it has a setup command anyway. % So with the implementation in latex-lab-tikz, all these work as expected % \begin{verbatim} % \tikzset{artifact} % \tikzset{alt=a text} % \tikzset{actualtext=A} % \tikzset{tagging-setup=text} % \end{verbatim} % % With \cs{includegraphics} the standard \cs{setkeys} can be used: % \begin{verbatim} % \setkeys{Gin}{alt=a text} % \setkeys{Gin}{artifact} % \setkeys{Gin}{actualtext=A} % \end{verbatim} % This will then also affect \env{picture} environments in the scope. % % \subsection{Default tagging mode} % % If none of the keys are used, the picture code must chose a default tagging mode. % The best one depends on the graphic type and % should be chosen as needed and then documented. % % With \cs{includegraphics} we use as default the illustrative mode, % tag it as \texttt{Figure} structure, use the file name as alternative text % and issue a warning that a real alternative text is missing. % % With the \env{picture} enviroment we use as default the illustrative mode % to, but use a fix text as alternative text and issue a warning too. % % With \tikzname{} (a first implementation is currently in latex-lab-tikz), % the default is the text mode, which means that a screen reader will read % the text in the nodes in the order they appear in the code. With this default, % e.g. \cs{todo}'s from the \env{todonotes} are correctly tagged. % % % In this implementation the \texttt{artifact} % key can also be applied on nodes and will remove them from the tagging. % \begin{verbatim} % \begin{tikzpicture} % \node[draw=red](x){Important!}; % \node[artifact,fill=blue,anchor=west] at (x.east){\phantom{Ip}}; % \end{tikzpicture} % \end{verbatim} % \subsection{Sockets, plugs and commands} % % \begin{description} % \item[sockets] % The example implementations make use of up-to five \emph{tagging sockets}. % The sockets are all used by the various graphic codes inside a group: % \begin{itemize} % \item An initialization (\texttt{init}) socket that handles % the key-val argument and setups the tagging mode by switching % the plugs of the other tagging sockets. % \item Two sockets that are used at the \texttt{begin} and \texttt{end} of % the picture and setup the main structure element. % The \texttt{end} socket typically also executes if needed the code to calculate the BBox % attribute and add it to the structure. % After the \texttt{begin} socket tagging is suspended, and before the % \texttt{end} socket resumed. % \item Two sockets for the text mode that are used around places where a % picture contains text. Tagging must be resumed before this sockets % if they should do anything at all. % \end{itemize} % % The sockets take arguments that allows some configuration (e.g. to use % a special command for the BBox calculation) and the plugs are coded so that % they can be used in more than one picture type (they are shared here % between \cs{includegraphics} and \env{picture}) but there is no obligation % to use them in every graphic code. % A package can declare its own sockets and plugs. See \ref{sec:scope} for some discussion % why this can be a good idea. % % \item[plugs] % The main \texttt{begin} and \texttt{end} sockets should normally have % four \emph{plugs} % for the different modes: % \texttt{alt}, \texttt{actualtext}, \texttt{artifact} and \texttt{text}. % To disable tagging, \cs{SuspendTagging} can be used, % alternatively for sockets with zero or one argument, % the predefined \texttt{noop} plug can be assigned, % and for sockets with two arguments (if the socket has been declared with % \cs{NewTaggingSocket} the \texttt{transparent} % socket which lets pass through the % second argument. % % The initialization socket and the texts sockets typically have only one % additional \emph{plug} that is used when tagging is active. % % \item[commands] A command to store the position of a reference % point on the page and a command to calculate the BBox from this reference % point and the size of the picture are needed. The second command must also add the % attribute to the main structure element (how to do this can be seen in the implementation). % These commands are typically specific for a picture type. % %\end{description} % % We now describe how this general principles have be implemented % in the concrete examples of the \cs{includegraphics} command, the \env{picture} environment, % TODO! and a simple environment for l3draw commands. % % \section{Sockets, plugs, commands} % % The code defines the following generic sockets and commands. % % \begin{itemize} % \item \texttt{graphic/init} with the plug \texttt{default} % \item \texttt{graphic/begin} (one argument) with the plugs \texttt{alt}, % \texttt{actualtext}, \texttt{artifact}, \texttt{text}, \texttt{off}. The argument % allows to set a default alternative text. % \item \texttt{graphic/end} (two arguments) with the plugs \texttt{alt}, % \texttt{actualtext}, \texttt{artifact}, \texttt{text}, \texttt{off}. The first argument % of the socket typically receives the command to calculate the BBox. This command % often contains a savepos command and so has to go before the graphic box. The second % argument allows to insert the box between this command and the tagging commands.% % \item \texttt{graphic/text/begin} no argument, with the plug \texttt{default} % \item \texttt{graphic/text/end} no argument with the plug \texttt{default} % \end{itemize} % % \begin{macro}{\l_tag_graphic_mode_tl} % This variable holds the current active graphic mode. It is e.g. used % to test if text should resume tagging. % \end{macro} % % \section{Make \cs{includegraphics} tagging aware} % % Tagging of graphics included with \cs{includegraphics} is at a first glance % easier to handle than, e.g., a \tikzname{} graphic, as there is only a simple % box with a picture and no text content to consider. % One would think that adding some structure commands around a box shouldn't pose much problems. % % But things are actually not so easy. % % At first such graphics are inserted into the PDF as XObjects and % there are two ways to add an such an XObject to a structure: % similar to text as a marked content item (by surrounding % it with \cs{tagmcbegin} and \cs{tagmcend}) or by referencing the XObject % with an OBJR object (similar to a link annotation). Which method is more sensible % (and if it actually matters) is unknown. % Currently the first method is used as the second would changes in the backend files. % % At second---and this is actually a \emph{much} bigger problem\footnote{Which shows % also in the amount of code dedicated here only to this problem.}---if the graphic % is tagged as an illustrative picture the % \texttt{Figure} structure element should have an attribute with an \texttt{BBox} entry. % The value of this \texttt{BBox} is an array of four numbers that gives the % coordinates of the left, bottom, right, and top edges % of the structure element’s bounding box on the page. % That is the rectangle that completely encloses % its \emph{visible} content and so has not necessarily the same size as the TeX bounding box: % if \texttt{viewport} or \texttt{trim} is used and the % graphic is not clipped, the visible content can be larger. % It turned out to be extremely tricky to get a sensible result, and there are still % open problems and restrictions. % % % \subsection{The BBox calculation} % The reference point on the page is retrieved with \verb+\tex_savepos:D+ and a property % just before the graphic. % % Getting from this the \texttt{BBox} can be quite straightforward for a graphic that is % used once as is. But graphics can be trimmed, scaled, reflected, rotated and reused % in various ways. These transformations typically involve a mix of \TeX{} commands % that shift a box or change the bounding box and backend commands that insert % a pdfliteral with a transformation matrix. Calculating % the correct \texttt{BBox} in all cases is not possible % without rewriting large parts of the graphics and graphicx packages. Problematic are % \begin{itemize} % \item manipulations through external box commands % (\cs{rotatebox}, \cs{reflectbox}, \cs{scalebox}). Their implementation % do not pass the transformation matrix in a way % that allows to track the changes for the \texttt{BBox} % of an included graphic: sometimes % the values are set to late (after the box is already stored), and often the % values are not grouped and can leak out from earlier uses of the commands. % % \item some combination of keys in the optional argument of \cs{includegraphics}. % Examples are \texttt{origin} and multiple calls to \texttt{scale} % and \texttt{angle}) as they internally call the box commands. % Examples of failing combinations can be found in the test file % \texttt{graphic-faults}. % % \item graphics that are stored in a box and reused: to get the \texttt{BBox} % one has to set a label that stores the position with \cs{pdfsavepos}, % and if a box is reused one gets multiply defined labels. % One possible solution here is to make % use of the new delayed \cs{pdfliteral}. It allows to change the label names % in the shipout, but this requires careful tracking the box usages % and so various kernel changes. % \end{itemize} % % % Therefore a correct BBox is currently % implemented only for simple \cs{includegraphics} and the keys % \texttt{viewport}, \texttt{trim}, % \texttt{scale} and \texttt{angle} (used at most once). % % Currently not supported are % \begin{itemize} % \item graphics inside \cs{rotatebox}, \cs{reflectbox}, \cs{scalebox}. % % TODO: A new implementation with \texttt{l3graphics} and \texttt{l3box} is % probably needed here. % % \item multiple uses of the \texttt{scale} and \texttt{angle} keys % % \item multiple use of graphics stored in boxes. For such graphics automated tagging % should be probably deactivated when storing the content % and tagging should be added around the \cs{usebox}. (How to % proceed when content is saved in boxes needs generally more testing). % \end{itemize} % % % \subsection{User interface} % As suggested above the code (re)defines keys for \cs{includegraphics} % to add the recommanded interfaces \texttt{alt}, \texttt{artifact} and \texttt{actualtext}. % It also offers some keys specific to \cs{includegraphics}: % \begin{description} % \item[\texttt{alt}] This key is already defined in the graphicx package % but redefined here to switch to the illustrative mode and to add its value % as alternative text. % \item[\texttt{actualtext}] This switches to the actualtext mode. % This is useful for small graphics that represent single chars or a short word like a % logo. If \texttt{actualtext} is used, the graphics is not enclosed in \texttt{Figure} % structure but in a \texttt{Span} structure and no \texttt{/BBox} attribute is added.% % \footnote{This in accordance with (the draft of) PDF/UA-2 but violates perhaps PDF/UA-1.} % \item[\texttt{artifact}] This tags the graphic as an artifact. % \item[\texttt{tagging-setup}] This key takes as argument a key-list, % which can contain the following keys: % \begin{description} % \item[\texttt{alt=\meta{text}}] This a second way to tag the graphic as figure with % alternative text. \texttt{alt} without value will tag as figure but not change % the text variable, \texttt{alt=} will empty the text variable (and typically trigger % a warning). % \item[\texttt{actualtext=\meta{text}}] This a second way to tag the graphic as a % symbol with actualtext. % \item[\texttt{artifact}] This a second way to tag the graphic as artifact. % \item[\texttt{text}] This switches to text mode. % \item[\texttt{off}] When used tagging will be stopped completely. It is then the % responsibility of the surrounding code to add appropriate tagging commands. % \item[\texttt{tag=\meta{name}}] This switches to the illustrative mode but uses % \meta{name} as tag name in the structure instead of the default \texttt{Figure}. % This can for example be used to tag an image of a formula with \texttt{Formula}. % \end{description} % \item[\texttt{adjust-BBox}] If the calculated \texttt{/BBox} values are wrong % they can be corrected with this key. It expects four dimensions that are added to the % \texttt{/BBox} values. % \end{description} % % The code also add to the \texttt{debug} key of \cs{DocumentMetadata} % the value \texttt{BBox}. % This adds a half transparent red layer showing the calculated BBox. % \begin{verbatim} % \DocumentMetadata{tagging=on,debug=BBox} % \end{verbatim} % % \section{Make \env{picture} tagging aware} % % \subsection{User interface} % The \env{picture} environment doesn't have a optional argument with key-value value processing. % So the code changes that and then provides the keys already discussed for \cs{includegraphics}. % % \subsection{BBox calculation} % % The BBox calculation is much simpler than for \cs{includegraphics} as the code simply takes % the declared size from the \env{picture} arguments. % % \subsection{Tagging in text mode} % % A \env{picture} can contain \cs{put} commands with text content, tagging this in % text mode could make sense in some cases. But it is not quite clear if one can/should % redefine the \cs{put} command. If text tagging is wanted we suggest to % define a dedicated command along these lines: % \begin{verbatim} % \NewDocumentCommand\picturenode{O{}r()m} % { % \group_begin: % \keys_set:nn{tag/graphic}{#1} % \str_if_eq:VnT\l_tag_graphic_mode_tl {text} % {\tag_resume:n{\picturenode}} % \tag_socket_use:n{graphic/text/begin} % \put(#2){#3} % \tag_socket_use:n{graphic/text/end} % \group_end: % } % % \end{verbatim} % % \section{Make an l3draw environment tagging aware} % The newest l3draw version (in the latex3 github) % has all needed data to define a command to retrieve the BBox % and to build a tagging aware environment. l3draw currently has % no dedicated function to add text, instead one has to store the text % in a box and then reuse it, so similar to the \env{picture} environment % a dedicated command with tagging awareness is suggested. % % A command to calculate the BBox can for example be defined like this % \begin{verbatim} % \cs_new:Npn\draw_tag_bbox_attribute: % { % \tl_set:Ne \g__tag_graphic_lx_tl % { % \dim_to_decimal_in_bp:n % { % \property_ref:een {draw.\int_use:N\g_draw_id_int}{xpos}{0}sp % + % \g_draw_bb_xmin_dim % } % } % \tl_set:Ne \g__tag_graphic_ly_tl % { % \dim_to_decimal_in_bp:n % { % \property_ref:een {draw.\int_use:N\g_draw_id_int}{ypos}{0}sp % + % \g_draw_bb_ymin_dim % } % } % \tl_set:Ne \g__tag_graphic_ux_tl % { % \dim_to_decimal_in_bp:n % { % \property_ref:een {draw.\int_use:N\g_draw_id_int}{xpos}{0}sp % + % \g_draw_bb_xmax_dim % } % } % \tl_set:Ne \g__tag_graphic_uy_tl % { % \dim_to_decimal_in_bp:n % { % \property_ref:een {draw.\int_use:N\g_draw_id_int}{ypos}{0}sp % + % \g_draw_bb_ymax_dim % } % } % \bool_if:NT\l__tag_graphic_debug_bool % { % \__tag_graphic_show_bbox:VVVVne % \g__tag_graphic_lx_tl % \g__tag_graphic_ly_tl % \g__tag_graphic_ux_tl % \g__tag_graphic_uy_tl % {red} % {draw.\int_use:N\g_draw_id_int} % } % \tag_struct_gput:ene % {\tag_get:n{struct_num}} % {attribute} % { % /O /Layout /BBox~ % [ % \dim_to_decimal_in_bp:n % { % \property_ref:een {draw.\int_use:N\g_draw_id_int}{xpos}{0}sp % + % \g_draw_bb_xmin_dim % } % \c_space_tl % \dim_to_decimal_in_bp:n % { % \property_ref:een {draw.\int_use:N\g_draw_id_int}{ypos}{0}sp % + % \g_draw_bb_ymin_dim % } % \c_space_tl % \dim_to_decimal_in_bp:n % { % \property_ref:een {draw.\int_use:N\g_draw_id_int}{xpos}{0}sp % + % \g_draw_bb_xmax_dim % } % \c_space_tl % \dim_to_decimal_in_bp:n % { % \property_ref:een {draw.\int_use:N\g_draw_id_int}{ypos}{0}sp % + % \g_draw_bb_ymax_dim % } % ] % } % } % \end{verbatim} % % A tagging aware environment can then be defined like this % \begin{verbatim} % \NewDocumentEnvironment{tagged-draw}{O{}} % {\leavevmode % \ExplSyntaxOn % \tag_socket_use:nn{graphic/init}{#1} % \tag_socket_use:nn{graphic/begin}{tagged-draw~environment} % \tag_suspend:n{\draw} % % \draw_begin:\ignorespaces % } % { % \draw_end: % \tag_resume:n{\draw} % \tag_socket_use:nnn{graphic/end}{\draw_tag_bbox_attribute:}{} % } % \end{verbatim} % % And a command for tagged text nodes could look like this % \begin{verbatim} % \cs_new_protected:Npn \draw_text_node:nnn #1#2#3 %#1 keyval, #2 point, #3 text % { % \group_begin: % \keys_set:nn{tag/graphic}{#1} % \str_if_eq:VnT\l_tag_graphic_mode_tl {text} % {\tag_resume:n{\draw_node:nn}} % \tag_socket_use:n{graphic/text/begin} % \hbox_set:Nn \l_tmpa_box{#3} % \draw_box_use:Nn\l_tmpa_box {#2} % \tag_socket_use:n{graphic/text/end} % \group_end: % } % \end{verbatim} % \begin{macrocode} %<@@=tag> %<*package> % \end{macrocode} % \end{documentation} % \begin{implementation} % \section{Implementation} % \begin{macrocode} \ProvidesExplPackage {latex-lab-testphase-graphic} {\ltlabgraphicdate} {\ltlabgraphicversion} {Code related to the tagging of graphics} % \end{macrocode} % a variant % \begin{macrocode} \cs_generate_variant:Nn \tag_socket_use:nn {ne} % \end{macrocode} % We load l3opacity for the debug code if opacity is not already defined in the kernel: % \begin{macrocode} \cs_if_exist:NF \opacity_select:n { \RequirePackage{l3opacity} } % \end{macrocode} % % \begin{macro}{\@@_graphic_savepos:n} % this is the command which stores the position. Similar to % zref-savepos it uses two savepos commands % for the case that bidi changes the processing order. % \begin{macrocode} \cs_new_protected:Npn\@@_graphic_savepos:n #1 { \tex_savepos:D \property_record:nn{#1}{xpos,ypos,abspage} \tex_savepos:D } \cs_generate_variant:Nn \@@_graphic_savepos:n {e} % \end{macrocode} % \end{macro} % % \subsection{Variables} % \begin{variable} % { % \l_@@_graphic_alt_tl, % \l_@@_graphic_actual_tl, % \l_@@_graphic_struct_tl, % \l_tag_graphic_mode_tl, % } % % These variables are related to the tagging. % Variables for the alt text, the actualtext and the structure tag. % The variable that holds the tagging mode is public, % so that commands can test for it, and e.g. restart % tagging in text mode. % % \begin{macrocode} \tl_new:N \l_@@_graphic_alt_tl \tl_new:N \l_@@_graphic_actual_tl \tl_new:N \l_@@_graphic_struct_tl \tl_set:Nn\l_@@_graphic_struct_tl {Figure} % \end{macrocode} % \end{variable} % % \begin{variable}{\l_@@_graphic_debug_bool} % A boolean for debug code % \begin{macrocode} \bool_new:N \l_@@_graphic_debug_bool % \end{macrocode} % \end{variable} % % The rest of the variables are related to the BBox calculation in \cs{includegraphics}. % \begin{variable}{\g_@@_graphic_int} % This is used to get unique labels in the savepos code. % \begin{macrocode} \int_new:N\g_@@_graphic_int % \end{macrocode} % \end{variable} % \begin{variable} % { % \g_@@_graphic_lx_tl, % \g_@@_graphic_ly_tl, % \g_@@_graphic_ux_tl, % \g_@@_graphic_uy_tl, % \l_@@_graphic_bboxcorr_seq % \l_@@_graphic_bboxcorr_bool % } % This commands will hold the calculated BBox values. Local variables % would probably work too, but global variables can be easier retrieved % in tests and debugging code ... % \begin{macrocode} \tl_new:N \g_@@_graphic_lx_tl \tl_new:N \g_@@_graphic_ly_tl \tl_new:N \g_@@_graphic_ux_tl \tl_new:N \g_@@_graphic_uy_tl \seq_new:N\l_@@_graphic_bboxcorr_seq \bool_new:N\l_@@_graphic_bboxcorr_bool % \end{macrocode} % \end{variable} % \begin{variable}{\l_@@_graphic_currentlabel_tl} % This holds the label name of the savepos. % \begin{macrocode} \tl_new:N \l_@@_graphic_currentlabel_tl % \end{macrocode} % \end{variable} % % % \begin{variable} % { % \l_@@_graphic_sin_fp % ,\l_@@_graphic_cos_fp % ,\l_@@_graphic_scale_fp % ,\l_@@_graphic_lxly_fp % ,\l_@@_graphic_lxuy_fp % ,\l_@@_graphic_uxly_fp % ,\l_@@_graphic_uxuy_fp % ,\l_@@_graphic_ux_fp % ,\l_@@_graphic_ly_fp % ,\l_@@_graphic_lx_fp % ,\l_@@_graphic_uy_fp % ,\l_@@_graphic_trim_ux_fp % ,\l_@@_graphic_trim_ly_fp % ,\l_@@_graphic_trim_lx_fp % ,\l_@@_graphic_trim_uy_fp % } % A bunch of fp-variables (we don't use tl-vars, % to avoid to have to take care about minus signs everywhere) % \begin{macrocode} \fp_new:N\l_@@_graphic_sin_fp \fp_new:N\l_@@_graphic_cos_fp \fp_new:N\l_@@_graphic_lxly_fp \fp_new:N\l_@@_graphic_lxuy_fp \fp_new:N\l_@@_graphic_uxly_fp \fp_new:N\l_@@_graphic_uxuy_fp \fp_new:N\l_@@_graphic_ux_fp \fp_new:N\l_@@_graphic_ly_fp \fp_new:N\l_@@_graphic_lx_fp \fp_new:N\l_@@_graphic_uy_fp % \end{macrocode} % this holds the scale value. Either \cs{Gin@scalex} or (if that is !) \cs{Gin@scaley} % \begin{macrocode} \fp_new:N\l_@@_graphic_scale_fp % \end{macrocode} % the follow variables hold the four trim values (or the equivalent calculated % values if viewport is used. % \begin{macrocode} \fp_new:N\l_@@_graphic_trim_ux_fp \fp_new:N\l_@@_graphic_trim_ly_fp \fp_new:N\l_@@_graphic_trim_lx_fp \fp_new:N\l_@@_graphic_trim_uy_fp % \end{macrocode} % \end{variable} % % \subsection{Tagging sockets} % The sockets can perhaps not be shared between \cs{includegraphics} and \env{picture} % but for now we try to do it, with the exception of the init socket. % % The begin socket takes an argument to allow to pass some configuration. % The end socket takes two argument to allow to calculate the BBox % before outputting the box. % \begin{socketdecl}{tagsupport/graphic/init,tagsupport/graphic/begin, % tagsupport/graphic/end,tagsupport/graphic/text/begin,tagsupport/graphic/graphic/text/end} % \begin{macrocode} \NewTaggingSocket{graphic/init}{1} \NewTaggingSocket{graphic/begin}{1} \NewTaggingSocket{graphic/end}{2} \NewTaggingSocket{graphic/text/begin}{0} \NewTaggingSocket{graphic/text/end}{0} % \end{macrocode} %\end{socketdecl} % % \subsection{Tagging plugs} % % \subsubsection{Initialization of the tagging mode} % \begin{plugdecl}{default (tagsupport/graphic/init),default (tagsupport/graphic/init)} % \begin{macrocode} \NewTaggingSocketPlug{graphic/init}{default} { \keys_set:nn{tag/graphic}{#1} \ExpandArgs{no}\AssignTaggingSocketPlug{graphic/begin}{\l_tag_graphic_mode_tl} \ExpandArgs{no}\AssignTaggingSocketPlug{graphic/end}{\l_tag_graphic_mode_tl} } \AssignTaggingSocketPlug{graphic/init}{default} % \end{macrocode} % \end{plugdecl} % % \subsubsection{Main begin and end sockets} % \begin{plugdecl}{figure (tagsupport/graphic/begin),figure (tagsupport/graphic/end)} % These plugs handle the graphic as a figure. % Around the graphic is a \texttt{Figure} environment which will % use an alt text given in the optional argument and internally tagging is suspended. % The Bbox will be set (after the second compilation) to the size of the declared size % \begin{macrocode} \msg_new:nnn { tag } { alt-text-missing } { Alternative~text~for~graphic~is~missing.\\ Using~'#1'~instead. } \NewTaggingSocketPlug{graphic/begin}{alt} { \tag_mc_end_push: \tl_if_empty:NT\l_@@_graphic_alt_tl { \msg_warning:nne{tag}{alt-text-missing}{#1} \tl_set:Ne\l_@@_graphic_alt_tl {\text_purify:n{#1}} } \tag_struct_begin:n { tag=\l_@@_graphic_struct_tl, alt=\l_@@_graphic_alt_tl, } \tag_mc_begin:n{} } \NewTaggingSocketPlug{graphic/end}{alt} { #1 #2 \tag_mc_end: \tag_struct_end: \tag_mc_begin_pop:n{} } % \end{macrocode} % \end{plugdecl} % % \begin{plugdecl}{actualtext (tagsupport/graphic/begin),actualtext (tagsupport/graphic/end)} % This plug handles the picture as a symbol with an actualtext. % It tags the content as a Span and expects an actualtext. % Internally tagging is suspended. % \begin{macrocode} \NewTaggingSocketPlug{graphic/begin}{actualtext} { \tag_mc_end_push: \tag_struct_begin:n{tag=Span,actualtext=\l_@@_graphic_actual_tl } \tag_mc_begin:n{} } \NewTaggingSocketPlug{graphic/end}{actualtext} { #2 \tag_mc_end: \tag_struct_end: \tag_mc_begin_pop:n{} } % \end{macrocode} % \end{plugdecl} % % \begin{plugdecl}{artifact (tagsupport/graphic/begin),artifact (tagsupport/graphic/end)} % This plug handles the picture as an artifact, as decoration. % So it is surrounded by an artifact MC and internal text does not restart tagging. % \begin{macrocode} \NewTaggingSocketPlug{graphic/begin}{artifact} { \tag_mc_end_push: \tag_mc_begin:n{artifact} } \NewTaggingSocketPlug{graphic/end}{artifact} { #2 \tag_mc_end: \tag_mc_begin_pop:n{} } % \end{macrocode} % \end{plugdecl} % % \begin{plugdecl}{text (tagsupport/graphic/begin),text (tagsupport/graphic/end)} % This plug can be used for text tagging. % It basically does the same as the artifact plug. The main reason that it % exist is that it looks more consistend and % that we can test for the plug name and so restart tagging % in places where this is wanted. (tagging can not be resumed inside a tagging hook, % so has to use some external method). % \begin{macrocode} \NewTaggingSocketPlug{graphic/begin}{text} { \tag_mc_end_push: \tag_mc_begin:n{artifact} } \NewTaggingSocketPlug{graphic/end}{text} { #2 \tag_mc_end: \tag_mc_begin_pop:n{} } % \end{macrocode} % \end{plugdecl} % % \begin{plugdecl}{off (tagsupport/graphic/begin),off (tagsupport/graphic/end)} % This plug can be used for text tagging. % It basically does the same as the artifact plug. The main reason that it % exist is that it looks more consistend and % that we can test for the plug name and so restart tagging % in places where this is wanted. (tagging can not be resumed inside a tagging hook, % so has to use some external method). % \begin{macrocode} \NewTaggingSocketPlug{graphic/begin}{off}{} \NewTaggingSocketPlug{graphic/end}{off}{#2} % \end{macrocode} % \end{plugdecl} % % By default we use the alt plugs % \begin{macrocode} \AssignTaggingSocketPlug{graphic/begin}{alt} \AssignTaggingSocketPlug{graphic/end}{alt} % \end{macrocode} % % \begin{plugdecl}{default (tagsupport/graphic/text/begin), % default (tagsupport/picture/text/end)} % These sockets are used inside the text % plugs and ends the previous mc and restarts it after the text. % Not used by \cs{includegraphics}. Unclear if they can be used by % the \env{picture} environment. % \begin{macrocode} \NewTaggingSocketPlug{graphic/text/begin}{default} { \tag_mc_end: \tag_mc_begin:n{} } \NewTaggingSocketPlug{graphic/text/end}{default} { \tag_mc_end: \tag_mc_begin:n{artifact} } \AssignTaggingSocketPlug{graphic/text/begin}{default} \AssignTaggingSocketPlug{graphic/text/end}{default} % \end{macrocode} % \end{plugdecl} % % \subsection{Generic keys} % The keys are used by picture and \cs{includegraphics} (through the % \texttt{tagging-setup} key % \begin{macrocode} \keys_define:nn{tag/graphic} { ,alt .code:n = { \tl_if_empty:nF{#1} { \tl_set:Ne\l_@@_graphic_alt_tl{\text_purify:n{#1}}} \tl_set:Nn\l_tag_graphic_mode_tl{alt} } ,artifact .code:n = { \tl_set:Nn\l_tag_graphic_mode_tl{artifact} } ,actualtext .code:n = { \tl_if_empty:nF{#1} { \tl_set:Ne\l_@@_graphic_actual_tl{\text_purify:n{#1}} } \tl_set:Nn\l_tag_graphic_mode_tl{actualtext} } ,text .code:n = { \tl_set:Nn\l_tag_graphic_mode_tl{text} } ,off .code:n = { \tl_set:Nn\l_tag_graphic_mode_tl{off} } ,adjust-BBox .code:n = { \bool_set_true:N \l_@@_graphic_bboxcorr_bool \seq_set_split:Nnn\l_@@_graphic_bboxcorr_seq{~}{#1~0pt~0pt~0pt~0pt} } , tagging-setup .code:n= { \keys_set:nn { tag/graphic }{#1} } % \end{macrocode} % only for legacy. Should perhaps be removed? % \begin{macrocode} ,tag .code:n = { \str_case:nnF {#1} { {artifact} { \tl_set:Nn\l_tag_graphic_mode_tl{artifact} } {false}{\tag_suspend:n{picture}} } { \tl_set:Nn\l_@@_graphic_struct_tl{#1} \tl_set:Nn\l_tag_graphic_mode_tl{alt} } } } % \end{macrocode} % % \subsection{Tagging support for \cs{includegraphics}} % % \subsubsection{User interface: Additional keys.} % % We also ensure that graphicx is loaded for the keyval support. % At first a command to hold the tagging mode. % \begin{macrocode} \tl_new:N \l_tag_graphic_mode_tl \tl_set:Nn \l_tag_graphic_mode_tl {alt} %TODO think about the right default. \AddToHook{package/graphicx/after}[latex-lab] { \define@key{Gin}{alt} { \tl_if_empty:nF{#1} { \tl_set:Ne\l_@@_graphic_alt_tl{\text_purify:n{#1}}} \tl_set:Nn\l_tag_graphic_mode_tl {alt} } \define@key{Gin}{artifact}[] { \tl_set:Nn\l_tag_graphic_mode_tl{artifact} } \define@key{Gin}{actualtext} { \tl_if_empty:nF{#1} { \tl_set:Ne\l_@@_graphic_actual_tl{\text_purify:n{#1}} } \tl_set:Nn\l_tag_graphic_mode_tl{actualtext} } \define@key{Gin}{tagging-setup} { \keys_set:nn { tag/graphic}{#1} } \define@key{Gin}{adjust-BBox} { \bool_set_true:N \l_@@_graphic_bboxcorr_bool \seq_set_split:Nnn\l_@@_graphic_bboxcorr_seq{~}{#1~0pt~0pt~0pt~0pt} } % \end{macrocode} % only for legacy, no longer documented % \begin{macrocode} \define@key{Gin}{tag} { \str_case:nnF {#1} { {artifact} { \tl_set:Nn\l_tag_graphic_mode_tl{artifact} } {false}{\tag_suspend:n{Gin}} } { \tl_set:Nn\l_@@_graphic_struct_tl{#1} \tl_set:Nn\l_tag_graphic_mode_tl{alt} } } } \AddToHook{package/graphics/after}[latex-lab] {\RequirePackage{graphicx}} % \end{macrocode} % % % \subsubsection{Patching graphics commands} % All changes are currently done in \cs{Gin@setfile}. % We mainly have to add the sockets in the right place and % to rearrange a bit the \cs{ifGin@draft} test. % % \begin{macrocode} \AddToHook{package/graphics/after} { \def\Gin@setfile#1#2#3{% \ifx\\#2\\\Gread@false\fi \ifGin@bbox\else \ifGread@ \csname Gread@% \expandafter\ifx\csname Gread@#1\endcsname\relax eps% \else #1% \fi \endcsname{\Gin@base#2}% \else \Gin@nosize{#3}% \fi \fi \Gin@viewport@code \Gin@nat@height\Gin@ury bp% \advance\Gin@nat@height-\Gin@lly bp% \Gin@nat@width\Gin@urx bp% \advance\Gin@nat@width-\Gin@llx bp% \Gin@req@sizes \expandafter\ifx\csname Ginclude@#1\endcsname\relax \Gin@drafttrue \expandafter\ifx\csname Gread@#1\endcsname\relax \@latex@error{Can not include graphics of type: #1}\@ehc \global\expandafter\let\csname Gread@#1\endcsname\@empty \fi \fi \leavevmode % \end{macrocode} % Here the tagging begins. We want to catch also the draft box, % and for luatex tagging must be started before the \cs{setbox}. % \begin{macrocode} \tag_socket_use:ne {graphic/init} {tagging-setup=\l_tag_graphic_mode_tl} \tag_socket_use:nn {graphic/begin} {\Gin@base\Gin@ext} % \end{macrocode} % We store also the draft box in a box and do not output it directly % so that we can calculate its BBox too. % \begin{macrocode} \ifGin@draft \setbox\z@ \hb@xt@\Gin@req@width{% \vrule\hss \vbox to \Gin@req@height{% \hrule \@width \Gin@req@width \vss \edef\@tempa{#3}% \rlap{ \ttfamily\expandafter\strip@prefix\meaning\@tempa}% \vss \hrule}% \hss\vrule}% \else \@addtofilelist{#3}% \ProvidesFile{#3}[Graphic file (type #1)]% \setbox\z@\hbox{\csname Ginclude@#1\endcsname{#3}}% \dp\z@\z@ \ht\z@\Gin@req@height \wd\z@\Gin@req@width \fi % \end{macrocode} % This ends the tagging. % \begin{macrocode} \tag_socket_use:nnn{graphic/end} { \Gin@tag@bbox@attribute } { \box\z@ } } } % \end{macrocode} % % % \subsubsection{Calculating the BBox} % % This is the large code part. % % \begin{macro}{\@@_graphic_get_trim:} % Graphics can be trimmed with the trim and the viewport key. % If the graphic is not clipped the values must be taken into % account when rotating. % If viewport is used we have to calculate the trim. % % \begin{macrocode} \cs_new_protected:Npn \@@_graphic_get_trim: { \legacy_if:nTF {Gin@clip} % \end{macrocode} % Setting to 0 is not strictly needed but looks cleaner. % \begin{macrocode} { \fp_zero:N\l_@@_graphic_trim_lx_fp \fp_zero:N\l_@@_graphic_trim_ly_fp \fp_zero:N\l_@@_graphic_trim_ux_fp \fp_zero:N\l_@@_graphic_trim_uy_fp } { \fp_set:Nn \l_@@_graphic_trim_lx_fp {\l_@@_graphic_scale_fp*\Gin@vllx} \fp_set:Nn \l_@@_graphic_trim_ly_fp {\l_@@_graphic_scale_fp*\Gin@vlly} \fp_set:Nn \l_@@_graphic_trim_ux_fp {\l_@@_graphic_scale_fp*\Gin@vurx} \fp_set:Nn \l_@@_graphic_trim_uy_fp {\l_@@_graphic_scale_fp*\Gin@vury} \cs_if_exist:NT \Gin@ollx { \fp_set:Nn \l_@@_graphic_trim_ux_fp {\l_@@_graphic_scale_fp* (\Gin@ourx-(\Gin@urx)) } \fp_set:Nn \l_@@_graphic_trim_uy_fp {\l_@@_graphic_scale_fp* (\Gin@oury-(\Gin@ury)) } } } } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_graphic_get_scale:} % \begin{macrocode} \cs_new_protected:Npn \@@_graphic_get_scale: { \fp_set:Nn \l_@@_graphic_scale_fp { \str_if_eq:eeTF {\Gin@scalex} { ! } { \Gin@scaley } { \Gin@scalex } } } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_graphic_applyangle:nnnn} % This takes the current BBox and rotates it according to the use angle. % This is the most laborious code, as we have to take also the trim values into % account. We have to compare the values after the rotation to find the right corners % for the BBox. Not sure, if this is the most effective code, % the l3draw package has similar code to calculate a rotation, % this can perhaps be reused ... % \begin{macrocode} \cs_new_protected:Npn \@@_graphic_applyangle:nnnn #1#2#3#4 %lx,ly,ux,uy { \bool_lazy_and:nnT {\cs_if_exist_p:N \Grot@angle } {! \int_compare_p:nNn { \Grot@angle }={0}} { \fp_set:Nn \l_@@_graphic_sin_fp { sind(\Grot@angle) } \fp_set:Nn \l_@@_graphic_cos_fp { cosd(\Grot@angle) } \fp_set:Nn \l_@@_graphic_lx_fp {#1} \fp_set:Nn \l_@@_graphic_ly_fp {#2} \fp_set:Nn \l_@@_graphic_ux_fp {#3} \fp_set:Nn \l_@@_graphic_uy_fp {#4} % \end{macrocode} % get the x coordinates (cos,-sin) % \begin{macrocode} \fp_set:Nn\l_@@_graphic_lxly_fp { -\l_@@_graphic_trim_lx_fp * \l_@@_graphic_cos_fp +\l_@@_graphic_trim_ly_fp * \l_@@_graphic_sin_fp } \fp_set:Nn\l_@@_graphic_lxuy_fp { (-\l_@@_graphic_trim_lx_fp) * \l_@@_graphic_cos_fp + (\l_@@_graphic_uy_fp-\l_@@_graphic_ly_fp-\l_@@_graphic_trim_ly_fp) * (-\l_@@_graphic_sin_fp) } \fp_set:Nn\l_@@_graphic_uxly_fp { (\l_@@_graphic_ux_fp-\l_@@_graphic_lx_fp-\l_@@_graphic_trim_lx_fp) * \l_@@_graphic_cos_fp + (\l_@@_graphic_trim_ly_fp) * (\l_@@_graphic_sin_fp) } \fp_set:Nn\l_@@_graphic_uxuy_fp { (\l_@@_graphic_ux_fp-\l_@@_graphic_lx_fp-\l_@@_graphic_trim_lx_fp) * \l_@@_graphic_cos_fp + (\l_@@_graphic_uy_fp-\l_@@_graphic_ly_fp-\l_@@_graphic_trim_ly_fp) * (-\l_@@_graphic_sin_fp) } \tl_gset:Ne\g_@@_graphic_lx_tl { \fp_eval:n { min ( \l_@@_graphic_lxly_fp, \l_@@_graphic_lxuy_fp, \l_@@_graphic_uxly_fp, \l_@@_graphic_uxuy_fp, ) +\l_@@_graphic_lx_fp +\l_@@_graphic_trim_lx_fp } } \tl_gset:Ne\g_@@_graphic_ux_tl { \fp_eval:n { max ( \l_@@_graphic_lxly_fp, \l_@@_graphic_lxuy_fp, \l_@@_graphic_uxly_fp, \l_@@_graphic_uxuy_fp ) +\l_@@_graphic_lx_fp +\l_@@_graphic_trim_lx_fp } } % \end{macrocode} % get the y coordinates (sin,cos) % \begin{macrocode} \fp_set:Nn\l_@@_graphic_lxly_fp { -\l_@@_graphic_trim_lx_fp * \l_@@_graphic_sin_fp -\l_@@_graphic_trim_ly_fp * \l_@@_graphic_cos_fp } \fp_set:Nn\l_@@_graphic_lxuy_fp { - \l_@@_graphic_trim_lx_fp * \l_@@_graphic_sin_fp + (\l_@@_graphic_uy_fp-\l_@@_graphic_ly_fp-\l_@@_graphic_trim_ly_fp) * \l_@@_graphic_cos_fp } \fp_set:Nn\l_@@_graphic_uxly_fp { (\l_@@_graphic_ux_fp-\l_@@_graphic_lx_fp-\l_@@_graphic_trim_lx_fp) * \l_@@_graphic_sin_fp - \l_@@_graphic_trim_ly_fp * \l_@@_graphic_cos_fp } \fp_set:Nn\l_@@_graphic_uxuy_fp { (\l_@@_graphic_ux_fp-\l_@@_graphic_lx_fp-\l_@@_graphic_trim_lx_fp) * \l_@@_graphic_sin_fp + (\l_@@_graphic_uy_fp-\l_@@_graphic_ly_fp-\l_@@_graphic_trim_ly_fp) * \l_@@_graphic_cos_fp } \tl_gset:Ne\g_@@_graphic_ly_tl { \fp_eval:n { min ( \l_@@_graphic_lxly_fp, \l_@@_graphic_lxuy_fp, \l_@@_graphic_uxly_fp, \l_@@_graphic_uxuy_fp ) + \l_@@_graphic_ly_fp + \l_@@_graphic_trim_ly_fp } } \tl_gset:Ne\g_@@_graphic_uy_tl { \fp_eval:n { max ( \l_@@_graphic_lxly_fp, \l_@@_graphic_lxuy_fp, \l_@@_graphic_uxly_fp, \l_@@_graphic_uxuy_fp, ) + \l_@@_graphic_ly_fp + \l_@@_graphic_trim_ly_fp } } } } \cs_generate_variant:Nn\@@_graphic_applyangle:nnnn {VVVV} % \end{macrocode} % \end{macro} % \begin{macro}{\@@_graphic_applycorr:NNNN} % This command is used to add at the end the correction values. Quite dump ... % \begin{macrocode} \cs_new_protected:Npn \@@_graphic_applycorr:NNNN #1 #2 #3 #4 { \bool_if:NT\l_@@_graphic_bboxcorr_bool { \tl_set:Ne #1 { \fp_eval:n { #1 + \dim_to_decimal_in_bp:n {\seq_item:Nn \l_@@_graphic_bboxcorr_seq {1} } } } \tl_set:Ne #2 { \fp_eval:n { #2 + \dim_to_decimal_in_bp:n {\seq_item:Nn \l_@@_graphic_bboxcorr_seq {2} } } } \tl_set:Ne #3 { \fp_eval:n { #3 + \dim_to_decimal_in_bp:n {\seq_item:Nn \l_@@_graphic_bboxcorr_seq {3} } } } \tl_set:Ne #4 { \fp_eval:n { #4 + \dim_to_decimal_in_bp:n {\seq_item:Nn \l_@@_graphic_bboxcorr_seq {4} } } } } } % \end{macrocode} % \end{macro} % % \begin{macro}{\Gin@tag@bbox@attribute} % This is the main command to calculate and set the Bbox attribute of the % \cs{includegraphics} command. It also sets the reference point on the page. % % \begin{macrocode} \cs_new_protected:Npn \Gin@tag@bbox@attribute { \__tag_graphic_get_scale: \@@_graphic_get_trim: \int_gincr:N\g_@@_graphic_int \tl_set:Ne\l_@@_graphic_currentlabel_tl {_@@_graphic.\int_use:N \g_@@_graphic_int} \@@_graphic_savepos:e { \l_@@_graphic_currentlabel_tl } \tl_gset:Ne\g_@@_graphic_lx_tl { \dim_to_decimal_in_bp:n { \property_ref:een {\l_@@_graphic_currentlabel_tl}{xpos}{0}sp } } \tl_gset:Ne\g_@@_graphic_ly_tl { \dim_to_decimal_in_bp:n { \property_ref:een {\l_@@_graphic_currentlabel_tl}{ypos}{0}sp } } \tl_gset:Ne\g_@@_graphic_ux_tl { \fp_eval:n { \g_@@_graphic_lx_tl + \dim_to_decimal_in_bp:n { \Gin@req@width } } } \tl_gset:Ne\g_@@_graphic_uy_tl { \fp_eval:n { \g_@@_graphic_ly_tl + \dim_to_decimal_in_bp:n { \Gin@req@height } } } % \end{macrocode} % If the graphics is not clipped we must add the trim values. % \begin{macrocode} \legacy_if:nF {Gin@clip} { \tl_gset:Ne\g_@@_graphic_ux_tl { \fp_eval:n { \g_@@_graphic_ux_tl + \l_@@_graphic_trim_ux_fp } } \tl_gset:Ne\g_@@_graphic_lx_tl { \fp_eval:n { \g_@@_graphic_lx_tl - \l_@@_graphic_trim_lx_fp } } \tl_gset:Ne\g_@@_graphic_uy_tl { \fp_eval:n { \g_@@_graphic_uy_tl + \l_@@_graphic_trim_uy_fp } } \tl_gset:Ne\g_@@_graphic_ly_tl { \fp_eval:n { \g_@@_graphic_ly_tl - \l_@@_graphic_trim_ly_fp } } } % \end{macrocode} % If there is an angle we now rotate the values. % \begin{macrocode} \@@_graphic_applyangle:VVVV \g_@@_graphic_lx_tl \g_@@_graphic_ly_tl \g_@@_graphic_ux_tl \g_@@_graphic_uy_tl % \end{macrocode} % At last we have to add the correction values % \begin{macrocode} \@@_graphic_applycorr:NNNN \g_@@_graphic_lx_tl \g_@@_graphic_ly_tl \g_@@_graphic_ux_tl \g_@@_graphic_uy_tl % \end{macrocode} % \begin{macrocode} \bool_if:NT\l_@@_graphic_debug_bool { \@@_graphic_show_bbox:VVVVne \g_@@_graphic_lx_tl \g_@@_graphic_ly_tl \g_@@_graphic_ux_tl \g_@@_graphic_uy_tl {red} {\l_@@_graphic_currentlabel_tl} } % \end{macrocode} % Now we add the attribute. We do it manually as it had to be delayed until now. % The structure and the mc must be open earlier, before the \cs{setbox} (at least % for luatex it has to). % \begin{macrocode} \tag_struct_gput:ene{\tag_get:n{struct_num}}{attribute} { /O /Layout /BBox~ [ \g_@@_graphic_lx_tl\c_space_tl \g_@@_graphic_ly_tl\c_space_tl \g_@@_graphic_ux_tl\c_space_tl \g_@@_graphic_uy_tl ] } } % \end{macrocode} % \end{macro} % % \subsection{Support for the picture environment} % % \subsubsection{User interface} % % The original picture has no key-val argument yet. In the new optional % argument uses the generic tag/graphic keys. % We could perhaps use the \texttt{Gin} keys instead, but there could % be side-effects if some uses other \texttt{Gin} keys like % \texttt{angle}, so better stay on the safe side. % % % \subsubsection{Calculation of the BBox} % % \begin{macro}{\picture@tag@bbox@attribute} % Picture needs a similar command to calculate the BBox. But here we stay simple % and use simply the size of the picbox. % % \begin{macrocode} \newcommand\picture@tag@bbox@attribute { \int_gincr:N\g_@@_graphic_int \tl_set:Ne\l_@@_graphic_currentlabel_tl {_@@_graphic.\int_use:N \g_@@_graphic_int} \@@_graphic_savepos:e { \l_@@_graphic_currentlabel_tl } \tl_gset:Ne \g_@@_graphic_lx_tl { \dim_to_decimal_in_bp:n { \property_ref:een {\l_@@_graphic_currentlabel_tl}{xpos}{0}sp } } \tl_gset:Ne \g_@@_graphic_ly_tl { \dim_to_decimal_in_bp:n { \property_ref:een {\l_@@_graphic_currentlabel_tl}{ypos}{0}sp - \dp\@picbox } } \tl_gset:Ne \g_@@_graphic_ux_tl { \dim_to_decimal_in_bp:n { \g_@@_graphic_lx_tl bp + \wd\@picbox } } \tl_gset:Ne \g_@@_graphic_uy_tl { \dim_to_decimal_in_bp:n { \g_@@_graphic_ly_tl bp + \ht\@picbox + \dp\@picbox } } \@@_graphic_applycorr:NNNN \g_@@_graphic_lx_tl \g_@@_graphic_ly_tl \g_@@_graphic_ux_tl \g_@@_graphic_uy_tl \bool_if:NT\l_@@_graphic_debug_bool { \@@_graphic_show_bbox:VVVVne \g_@@_graphic_lx_tl \g_@@_graphic_ly_tl \g_@@_graphic_ux_tl \g_@@_graphic_uy_tl {red} {\l_@@_graphic_currentlabel_tl} } % \end{macrocode} % this stores the attribute in the structure. % \begin{macrocode} \tag_struct_gput:ene{\tag_get:n{struct_num}}{attribute} { /O /Layout /BBox~ [ \g_@@_graphic_lx_tl\c_space_tl \g_@@_graphic_ly_tl\c_space_tl \g_@@_graphic_ux_tl\c_space_tl \g_@@_graphic_uy_tl ] } } % \end{macrocode} % \end{macro} % % \subsubsection{Patching the commands} % We redefine \cs{picture} to accept an optional argument. % We also ensure that we are in % hmode, so that stopping tagging doesn't confuse the paratags. % \begin{macrocode} \RenewDocumentCommand\picture{O{}m} { \leavevmode \tag_socket_use:nn{graphic/init}{#1} \pictur@#2 } % \end{macrocode} % inside the picture box we stop tagging. % \begin{macrocode} \def\@picture(#1,#2)(#3,#4){% \@defaultunitsset\@picht{#2}\unitlength \@defaultunitsset\@tempdimc{#1}\unitlength \tag_socket_use:nn{graphic/begin}{picture~environment} \tag_suspend:n{\@picture} %do not tag inside the picture box \setbox\@picbox\hb@xt@\@tempdimc\bgroup \@defaultunitsset\@tempdimc{#3}\unitlength \hskip -\@tempdimc \@defaultunitsset\@tempdimc{#4}\unitlength \lower\@tempdimc\hbox\bgroup \ignorespaces} % \end{macrocode} % % \begin{macrocode} \def\endpicture{% \egroup\hss\egroup \ht\@picbox\@picht\dp\@picbox\z@ \tag_resume:n{\@picture} \tag_socket_use:nnn{graphic/end} {\picture@tag@bbox@attribute} {\mbox{\box\@picbox}}} % \end{macrocode} % % % \subsection{Debugging code} % This command puts a transparent layer in the size of the BBox over an graphic. % \begin{macro}{\@@_graphic_show_bbox:nnnnnn} % \begin{macrocode} \cs_new_protected:Npn \@@_graphic_show_bbox:nnnnnn #1#2#3#4#5#6%#5 color, #6 label name { \iow_log:n {tag/graphic~debug:~BBox~of~graphics~#6~is~#1~#2~#3~#4} \hook_gput_code:nnn {shipout/foreground} {tag/graphic} { \int_compare:nNnT {\g_shipout_readonly_int} = {\property_ref:een{#6}{abspage}{0}} { \put (#1 bp,\dim_eval:n{-\paperheight + \dim_eval:n{#2 bp}}) { \opacity_select:n{0.5}\color_select:n{#5} \rule {\dim_eval:n {#3 bp-\dim_eval:n{#1 bp}}} {\dim_eval:n {#4 bp-\dim_eval:n{#2 bp}}} } } } } \cs_generate_variant:Nn \@@_graphic_show_bbox:nnnnnn {VVVVne,nnnnne} % \end{macrocode} % \end{macro} % \begin{macrocode} % % \end{macrocode} % \begin{macrocode} %<*latex-lab> \ProvidesFile{graphic-latex-lab-testphase.ltx} [\ltlabgraphicdate\space v\ltlabgraphicversion\space latex-lab wrapper graphic] \RequirePackage{latex-lab-testphase-graphic} % % \end{macrocode} % \end{implementation}