diff options
Diffstat (limited to 'macros/latex/required/latex-lab/latex-lab-graphic.dtx')
-rw-r--r-- | macros/latex/required/latex-lab/latex-lab-graphic.dtx | 1073 |
1 files changed, 1073 insertions, 0 deletions
diff --git a/macros/latex/required/latex-lab/latex-lab-graphic.dtx b/macros/latex/required/latex-lab/latex-lab-graphic.dtx new file mode 100644 index 0000000000..f9457e0524 --- /dev/null +++ b/macros/latex/required/latex-lab/latex-lab-graphic.dtx @@ -0,0 +1,1073 @@ +% \iffalse meta-comment +% +%% File: latex-lab-graphic.dtx (C) Copyright 2022-2023 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. +% +%<*driver> +\documentclass{l3doc} +\EnableCrossrefs +\CodelineIndex +\begin{document} + \DocInput{latex-lab-graphic.dtx} +\end{document} +%</driver> +% +% \fi +% +% +% \title{The \textsf{latex-lab-graphic} package\\ +% Tagging of included graphics } +% \author{\LaTeX{} Project\thanks{Initial implementation done by Ulrike Fischer}} +% \date{v0.8 2023-04-07} +% +% \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}} +% \begin{documentation} +% \begin{abstract} +% The following code implements a first draft for the tagging of graphics +% included with \cs{includegraphics}. +% \end{abstract} +% +% +% \section{Introduction} +% +% The code here handle the tagging of pictures included with \cs{includegraphics} +% and the picture environment. Pictures drawn with \texttt{l3draw} or \texttt{tikz} +% or similar packages aren't handled yet. +% +% Tagging of graphics included with \cs{includegraphics} is at a first glance trivial: +% They are either only decorations, in which case they should be in a \texttt{artifact} +% MC-chunk or (in pdf 2.0) tagged as an \texttt{Artifact} structure, +% or they are meaningful and then they should be tagged as a \texttt{Figure}. +% Such a graphic is a simple box and no other content can interfere so adding the +% structure commands shouldn't pose much problems. +% +% But things are actually not so easy. +% +% At first there are two ways to add a graphic +% 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 but should be tested. +% Currently the first method is used as the second require changes in the backend files. +% +% +% At second---and this is actually a \emph{much} larger problem---a +% \texttt{Figure} structure should have an attribute with an \texttt{BBox} entry. +% The value of a \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. That is the rectangle that completely encloses +% its \emph{visible} content so not necessarly the TeX bounding box: +% if \texttt{viewport} or \texttt{trim} is used and the +% graphic is not clipped, the visible content can be larger. +% +% Getting the \texttt{BBox} is quite straightforward for a graphic that is +% used once as is. But graphics can be trimmed, scaled, reflected, rotated and reused +% in various ways. This transformations typically involve a mix of \TeX{} commands +% like shifting a box or changing the bounding box and backend commands like +% inserting a pdfliteral with a transformation matrix and +% and not in all cases getting the \texttt{BBox} is possible +% without rewriting large parts of the graphics/x packages. Problematic are +% \begin{itemize} +% \item manipulations through external box commands +% (\cs{rotatebox}, \cs{reflectbox}, \cs{scalebox}). The current implementation +% in the graphics/x packages do not pass the transformation matrix in 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} +% +% +% +% \section{Restrictions and Todos} +% Correct tagging is currently +% implemented only for simple \cs{includegraphics} and the keys +% \texttt{viewport}, \texttt{trim}, +% \texttt{scale} and \texttt{angle} (used at most once). +% +% Not supported +% \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} +% +% +% \section{Additional keys} +% The code defines additional keys for \cs{includegraphics}: +% +% \begin{description} +% \item[\texttt{tag}] with the values +% \begin{description} +% \item[\texttt{artifact}] When used the graphic will be tagged as artifact. This doesn't +% require a \texttt{BBox} and so works also in some of the not yet supported cases described +% above. +% \item[\texttt{false}] When used tagging will be stopped completly. It is then the +% responsability of the surrounding code to add appropriate tagging commands. +% \item[\meta{name}] Other values will be used as tag names in the structure. If the tag is not +% known as a structure tag you will get an warning from tagpdf. The default name is currently +% \texttt{Figure} +% \end{description} +% \item[\texttt{actualtext}] This allows to add an /ActualText to the structure. +% 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. +% This in accordance with (the draft of) PDF/UA-2 but violates perhaps PDF/UA-1. +% \item[\texttt{correct-BBox}] If the calculated \texttt{/BBox} values are wrong +% they can be correct with this key. It expects four dimensions that are added to the +% \texttt{/BBox} values. +% \item[\texttt{debug}] The value \texttt{BBox} will show the calculated \texttt{/BBox} +% as a half transparent red rectangle. +% \end{description} +% +% The code also redefines the \texttt{alt} key to actually add its values +% as an alternative text. If no \texttt{alt} value is given, a warning is issued +% and the file name of the graphic is used. +% +% \begin{macrocode} +%<@@=tag> +%<*package> +% \end{macrocode} +% \end{documentation} +% \begin{implementation} +% \section{Implementation} +% \begin{macrocode} +\ProvidesExplPackage {latex-lab-testphase-graphic} {2023-04-07} {0.8} + {Code related to the tagging of graphics} +% \end{macrocode} +% We load l3opacity for the debug code +% \begin{macrocode} +\RequirePackage{l3opacity} +% \end{macrocode} +% +%\subsection{Saving the position} +% We need a replacement for zref-savepos. This uses l3ref which loaded +% by the pdfmanagement/tagpdf. +% +% TODO: this is perhaps needed in other places too and should be moved to +% l3ref!! +% \begin{macrocode} +\ref_attribute_gset:nnnn{xpos}{0}{shipout}{\int_use:N\tex_lastxpos:D} +\ref_attribute_gset:nnnn{ypos}{0}{shipout}{\int_use:N\tex_lastypos:D} +% \end{macrocode} + +% \begin{macro}{\@@_graphic_savepos:n} +% this is the command which stores the position. It uses +% two savepos in case bidi needs it (see zref-savepos). +% \begin{macrocode} +\cs_new_protected:Npn\@@_graphic_savepos:n #1 + { + \tex_savepos:D + \ref_label: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_debug_bool} +% A boolean for debug code +% \begin{macrocode} +\bool_new:N \l_@@_graphic_debug_bool +\keys_define:nn { document / metadata } + { + debug / BBox .code:n = { \bool_set_true:N \l_@@_graphic_debug_bool } + } +% \end{macrocode} +% \end{variable} +% \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_alt_tl, +% \l_@@_graphic_alt_dft_tl, +% \l_@@_graphic_actual_tl, +% \l_@@_graphic_struct_tl, +% \l_@@_graphic_artifact_bool, +% \l_@@_graphic_BBox_bool +% } +% Variables for the alt text, the actualtext and the structure tag. +% \begin{macrocode} +\tl_new:N \l_@@_graphic_alt_tl +\tl_new:N \l_@@_graphic_alt_dflt_tl +\tl_set:Nn \l_@@_graphic_alt_dflt_tl {\Gin@base\Gin@ext} +\tl_new:N \l_@@_graphic_actual_tl +\tl_new:N \l_@@_graphic_struct_tl +\tl_set:Nn\l_@@_graphic_struct_tl {Figure} +\bool_new:N\l_@@_graphic_artifact_bool +\bool_new:N\l_@@_graphic_BBox_bool +\bool_set_true:N\l_@@_graphic_BBox_bool +% \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 everwhere) +% \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. Currently this only the one from +% \cs{Gin@scalex} +% \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 commands} +% +% \begin{macro}{\Gin@tag@struct@begin} +% The command to start the tagging. +% \begin{macrocode} +\msg_new:nnn {tag}{alt-text-missing} + { + Alternative~text~for~graphic~is~missing.\\ + Using~'#1'~instead + } +\cs_new_protected:Npn\Gin@tag@struct@begin + { + \tag_if_active:T + { + \tag_mc_end_push: +% \end{macrocode} +% we don't open a structure for artifacts to make it easier to use +% graphics in saveboxes. +% \begin{macrocode} + \bool_if:NTF\l_@@_graphic_artifact_bool + { + \tag_mc_begin:n{artifact} + } + { + \tl_if_empty:NTF\l_@@_graphic_actual_tl + { + \tl_if_empty:NT\l_@@_graphic_alt_tl + { + \msg_warning:nnx{tag}{alt-text-missing}{\l_@@_graphic_alt_dflt_tl} + \tl_set:Nx\l_@@_graphic_alt_tl {\l_@@_graphic_alt_dflt_tl} + } + \tag_struct_begin:n + { + tag=\l_@@_graphic_struct_tl, + alt=\l_@@_graphic_alt_tl, + } + } + { + \tag_struct_begin:n + { + tag=Span, + actualtext=\l_@@_graphic_actual_tl, + } + \bool_set_false:N\l_@@_graphic_BBox_bool + } + \tag_mc_begin:n{} + } + } + } +% \end{macrocode} +% \end{macro} + +% \begin{macro}{\Gin@tag@struct@end} +% \begin{macrocode} +\cs_new_protected:Npn\Gin@tag@struct@end + { + \tag_if_active:T + { + \tag_mc_end: + \bool_if:NF\l_@@_graphic_artifact_bool + { + \tag_struct_end: + } + \tag_mc_begin_pop:n{} + } + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Patching graphics commands} +% All changes are currently done in \cs{Gin@setfile}. +% \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} + \Gin@tag@struct@begin %NEW + \ifGin@draft + \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 +% \end{macrocode} +% This the main command to calculate the BBox values. +% \begin{macrocode} + \Gin@tag@bbox@attribute %new + \box\z@ +% \end{macrocode} +% and here the tagging stops. +% \begin{macrocode} + \Gin@tag@struct@end %new + \fi} + } +% \end{macrocode} +% +% \subsection{Additional keys for the graphics command} +% TODO: this is a bit temporary and will perhaps need more refinement. +% we also ensure that graphicx is loaded for the keyval support. +% \begin{macrocode} +\AddToHook{package/graphicx/after}[latex-lab] + { + \define@key{Gin}{alt} {\tl_set:Nx\l_@@_graphic_alt_tl{\text_purify:n{#1}}} + \define@key{Gin}{artifact}[] + { + \bool_set_true:N \l_@@_graphic_artifact_bool + \bool_set_false:N \l_@@_graphic_BBox_bool + } + \define@key{Gin}{actualtext} + { + \tl_set:Nx\l_@@_graphic_actual_tl{\text_purify:n{#1}} + \bool_set_false:N \l_@@_graphic_BBox_bool + } + \define@key{Gin}{correct-BBox} + { + \bool_set_true:N \l_@@_graphic_bboxcorr_bool + \seq_set_split:Nnn\l_@@_graphic_bboxcorr_seq{~}{#1~0pt~0pt~0pt~0pt} + } + \define@key{Gin}{tag} + { + \str_case:nnF {#1} + { + {artifact} + { + \bool_set_true:N \l_@@_graphic_artifact_bool + \bool_set_false:N \l_@@_graphic_BBox_bool + } + {false}{\tag_stop:} + } + {\tl_set:Nn\l_@@_graphic_struct_tl{#1}} + } + } +\AddToHook{package/graphics/after}[latex-lab] + {\RequirePackage{graphicx}} +% \end{macrocode} +% For picture and other environments we need a similar set of keys. +% TODO: redefine \cs{includegraphics} to make use of these here?? +% \begin{macrocode} +\keys_define:nn{tag/picture} + { + ,alt .code:n = + {\tl_set:Nx\l_@@_graphic_alt_tl{\text_purify:n{#1}}} + ,artifact .code:n = + { + \bool_set_true:N \l_@@_graphic_artifact_bool + \bool_set_false:N \l_@@_graphic_BBox_bool + } + ,actualtext .code:n = + { + \tl_set:Nx\l_@@_graphic_actual_tl{\text_purify:n{#1}} + \bool_set_false:N \l_@@_graphic_BBox_bool + } + ,correct-BBox .code:n = + { + \bool_set_true:N \l_@@_graphic_bboxcorr_bool + \seq_set_split:Nnn\l_@@_graphic_bboxcorr_seq{~}{#1~0pt~0pt~0pt~0pt} + } + ,tag .code:n = + { + \str_case:nnF {#1} + { + {artifact} + { + \bool_set_true:N \l_@@_graphic_artifact_bool + \bool_set_false:N \l_@@_graphic_BBox_bool + } + {false}{\tag_stop:} + } + {\tl_set:Nn\l_@@_graphic_struct_tl{#1}} + } + } +% \end{macrocode} +% +% \subsection{Calculating the BBox} +% +% \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 { \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:Nx\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:Nx\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:Nx\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:Nx\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:Nx #1 + { + \fp_eval:n + { + #1 + + + \dim_to_decimal_in_bp:n {\seq_item:Nn \l_@@_graphic_bboxcorr_seq {1} } + } + } + \tl_set:Nx #2 + { + \fp_eval:n + { + #2 + + + \dim_to_decimal_in_bp:n {\seq_item:Nn \l_@@_graphic_bboxcorr_seq {2} } + } + } + \tl_set:Nx #3 + { + \fp_eval:n + { + #3 + + + \dim_to_decimal_in_bp:n {\seq_item:Nn \l_@@_graphic_bboxcorr_seq {3} } + } + } + \tl_set:Nx #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 +% \begin{macrocode} +\cs_new_protected:Npn \Gin@tag@bbox@attribute + { +% \end{macrocode} +% the attribute is only needed if tagging is active and there is not artifact. +% \begin{macrocode} + \bool_lazy_all:nT + { + {\tag_if_active_p:} + {!\l_@@_graphic_artifact_bool} + {\l_@@_graphic_BBox_bool} + } + { + \fp_set:Nn \l_@@_graphic_scale_fp { \Gin@scalex } + \@@_graphic_get_trim: + \int_gincr:N\g_@@_graphic_int + \tl_set:Nx\l_@@_graphic_currentlabel_tl {_@@_graphic_\int_use:N \g_@@_graphic_int} + \@@_graphic_savepos:e { \l_@@_graphic_currentlabel_tl } + \tl_gset:Nx\g_@@_graphic_lx_tl + { + \dim_to_decimal_in_bp:n + { \@@_ref_value:enn {\l_@@_graphic_currentlabel_tl}{xpos}{0}sp } + } + \tl_gset:Nx\g_@@_graphic_ly_tl + { + \dim_to_decimal_in_bp:n + { \@@_ref_value:enn {\l_@@_graphic_currentlabel_tl}{ypos}{0}sp } + } + \tl_gset:Nx\g_@@_graphic_ux_tl + { + \fp_eval:n + { + \g_@@_graphic_lx_tl + + + \dim_to_decimal_in_bp:n { \Gin@req@width } + } + } + \tl_gset:Nx\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:Nx\g_@@_graphic_ux_tl + { + \fp_eval:n + { + \g_@@_graphic_ux_tl + + + \l_@@_graphic_trim_ux_fp + } + } + \tl_gset:Nx\g_@@_graphic_lx_tl + { + \fp_eval:n + { + \g_@@_graphic_lx_tl + - + \l_@@_graphic_trim_lx_fp + } + } + \tl_gset:Nx\g_@@_graphic_uy_tl + { + \fp_eval:n + { + \g_@@_graphic_uy_tl + + + \l_@@_graphic_trim_uy_fp + } + } + \tl_gset:Nx\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} + {\int_use:N\g_@@_graphic_int} + } +% \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). TODO: think about interface if more attributes are needed. +% \begin{macrocode} + \@@_prop_gput:cnx + { g_@@_struct_\int_eval:n {\c@g_@@_struct_abs_int}_prop } + { A } + { + << + /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} +% +% \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 + { + \bool_lazy_all:nT + { + {\tag_if_active_p:} + {!\l_@@_graphic_artifact_bool} + {\l_@@_graphic_BBox_bool} + } + { + \int_gincr:N\g_@@_graphic_int + \tl_set:Nx\l_@@_graphic_currentlabel_tl {_@@_graphic_\int_use:N \g_@@_graphic_int} + \@@_graphic_savepos:e { \l_@@_graphic_currentlabel_tl } + \tl_gset:Nx \g_@@_graphic_lx_tl + { + \dim_to_decimal_in_bp:n + { \@@_ref_value:enn {\l_@@_graphic_currentlabel_tl}{xpos}{0}sp } + } + \tl_gset:Nx \g_@@_graphic_ly_tl + { + \dim_to_decimal_in_bp:n + { \@@_ref_value:enn {\l_@@_graphic_currentlabel_tl}{ypos}{0}sp - \dp\@picbox } + } + \tl_gset:Nx \g_@@_graphic_ux_tl + { + \dim_to_decimal_in_bp:n + { + \g_@@_graphic_lx_tl bp + \wd\@picbox + } + } + \tl_gset:Nx \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} + {\int_use:N\g_@@_graphic_int} + } + \@@_prop_gput:cnx + { g_@@_struct_\int_eval:n {\c@g_@@_struct_abs_int}_prop } + { A } + { + << + /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} +% We redefine \cs{picture} to accept an optional argument and +% change the default alt text. We also ensure that we are in +% hmode, so that stopping tagging doesn't confuse the paratags. +% \begin{macrocode} +\RenewDocumentCommand\picture{O{}m} + { + \leavevmode + \keys_set:nn{tag/picture}{#1} % + \tl_set:Nn\l_@@_graphic_alt_dflt_tl {picture~environment} + \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 + \Gin@tag@struct@begin + \setbox\@picbox\hb@xt@\@tempdimc\bgroup + \tag_stop: %do not tag inside the picture box + \@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@ + \picture@tag@bbox@attribute + \mbox{\box\@picbox} + \Gin@tag@struct@end} +% \end{macrocode} +% +% \subsection{Debugging code} +% +% \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 graphic + { + \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} + = + {\@@_ref_value:enn{_@@_graphic_#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} +% \end{macrocode} +% \end{macro} + +% \begin{macrocode} +%</package> +% \end{macrocode} + +% \begin{macrocode} +%<*latex-lab> +\ProvidesFile{graphic-latex-lab-testphase.ltx} + [2023-04-07 v0.8 code related to the tagging included graphics] +\RequirePackage{latex-lab-testphase-graphic} +%</latex-lab> +% \end{macrocode} +% \end{implementation} |