diff options
Diffstat (limited to 'macros/latex/required/l3backend/l3backend-graphics.dtx')
-rw-r--r-- | macros/latex/required/l3backend/l3backend-graphics.dtx | 931 |
1 files changed, 931 insertions, 0 deletions
diff --git a/macros/latex/required/l3backend/l3backend-graphics.dtx b/macros/latex/required/l3backend/l3backend-graphics.dtx new file mode 100644 index 0000000000..e20457368d --- /dev/null +++ b/macros/latex/required/l3backend/l3backend-graphics.dtx @@ -0,0 +1,931 @@ +% \iffalse meta-comment +% +%% File: l3backend-graphics.dtx +% +% Copyright (C) 2019-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 +% +% https://www.latex-project.org/lppl.txt +% +% This file is part of the "l3backend 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/latex3 +% +% for those people who are interested. +% +%<*driver> +\documentclass[full,kernel]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \pkg{l3backend-graphics} module\\ Backend graphics support^^A +% } +% +% \author{^^A +% The \LaTeX{} Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released 2024-04-11} +% +% \maketitle +% +% \begin{documentation} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3backend-graphics} implementation} +% +% \begin{macrocode} +%<*package> +%<@@=graphics> +% \end{macrocode} +% +% \begin{macro}{\@@_backend_loaded:n} +% To deal with file load ordering. Plain users are on their own. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_loaded:n #1 + { + \cs_if_exist:NTF \hook_gput_code:nnn + { + \hook_gput_code:nnn + { package / l3graphics / after } + { backend } + {#1} + } + {#1} + } +% \end{macrocode} +% \end{macro} +% +% \subsection{\texttt{dvips} backend} +% +% \begin{macrocode} +%<*dvips> +% \end{macrocode} +% +% \begin{variable}[no-user-doc]{\l_graphics_search_ext_seq} +% \begin{macrocode} +\@@_backend_loaded:n + { \seq_set_from_clist:Nn \l_graphics_search_ext_seq { .eps , .ps } } +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\@@_backend_getbb_eps:n, \@@_backend_getbb_ps:n} +% Simply use the generic function. +% \begin{macrocode} +\@@_backend_loaded:n + { + \cs_new_eq:NN \@@_backend_getbb_eps:n \@@_read_bb:n + \cs_new_eq:NN \@@_backend_getbb_ps:n \@@_read_bb:n + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_backend_include_eps:n, \@@_backend_include_ps:n} +% The special syntax is relatively clear here: remember we need PostScript +% sizes here. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_include_eps:n #1 + { + \__kernel_backend_literal:e + { + PSfile = #1 \c_space_tl + llx = \dim_to_decimal_in_bp:n \l_@@_llx_dim \c_space_tl + lly = \dim_to_decimal_in_bp:n \l_@@_lly_dim \c_space_tl + urx = \dim_to_decimal_in_bp:n \l_@@_urx_dim \c_space_tl + ury = \dim_to_decimal_in_bp:n \l_@@_ury_dim + } + } +\cs_new_eq:NN \@@_backend_include_ps:n \@@_backend_include_eps:n +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_backend_get_pagecount:n} +% \begin{macrocode} +\@@_backend_loaded:n + { \cs_new_eq:NN \@@_backend_get_pagecount:n \@@_get_pagecount:n } +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</dvips> +% \end{macrocode} +% +% \subsection{\LuaTeX{} and \pdfTeX{} backends} +% +% \begin{macrocode} +%<*luatex|pdftex> +% \end{macrocode} +% +% \begin{variable}[no-user-doc]{\l_graphics_search_ext_seq} +% \begin{macrocode} +\@@_backend_loaded:n + { + \seq_set_from_clist:Nn + \l_graphics_search_ext_seq + { .pdf , .eps , .ps , .png , .jpg , .jpeg } + } +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_@@_attr_tl} +% In PDF mode, additional attributes of an graphic (such as page number) are +% needed both to obtain the bounding box and when inserting the graphic: this +% occurs as the graphic dictionary approach means they are read as part of +% the bounding box operation. As such, it is easier to track additional +% attributes using a dedicated |tl| rather than build up the same data +% twice. +% \begin{macrocode} +\tl_new:N \l_@@_attr_tl +% \end{macrocode} +% \end{variable} +% +% \begin{macro} +% { +% \@@_backend_getbb_jpg:n , +% \@@_backend_getbb_jpeg:n , +% \@@_backend_getbb_pdf:n , +% \@@_backend_getbb_png:n +% } +% \begin{macro} +% { +% \@@_backend_getbb_auxi:n , +% \@@_backend_getbb_auxii:n , +% \@@_backend_getbb_auxiii:n +% } +% \begin{macro}[EXP]{\@@_backend_dequote:w} +% Getting the bounding box here requires us to box up the graphic and +% measure it. To deal with the difference in feature support in bitmap +% and vector graphics but keeping the common parts, there is a little work +% to do in terms of auxiliaries. The key here is to notice that we need +% two forms of the attributes: a \enquote{short} set to allow us to +% track for caching, and the full form to pass to the primitive. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_getbb_jpg:n #1 + { + \int_zero:N \l_@@_page_int + \tl_clear:N \l_@@_pagebox_tl + \tl_set:Ne \l_@@_attr_tl + { + \tl_if_empty:NF \l_@@_decodearray_str + { :D \l_@@_decodearray_str } + \bool_if:NT \l_@@_interpolate_bool + { :I } + \str_if_empty:NF \l_@@_pdf_str + { :X \l_@@_pdf_str } + } + \@@_backend_getbb_auxi:n {#1} + } +\cs_new_eq:NN \@@_backend_getbb_jpeg:n \@@_backend_getbb_jpg:n +\cs_new_eq:NN \@@_backend_getbb_png:n \@@_backend_getbb_jpg:n +\cs_new_protected:Npn \@@_backend_getbb_pdf:n #1 + { + \tl_clear:N \l_@@_decodearray_str + \bool_set_false:N \l_@@_interpolate_bool + \tl_set:Ne \l_@@_attr_tl + { + : \l_@@_pagebox_tl + \int_compare:nNnT \l_@@_page_int > 1 + { :P \int_use:N \l_@@_page_int } + \str_if_empty:NF \l_@@_pdf_str + { :X \l_@@_pdf_str } + } + \@@_backend_getbb_auxi:n {#1} + } +\cs_new_protected:Npn \@@_backend_getbb_auxi:n #1 + { + \@@_bb_restore:eF { #1 \l_@@_attr_tl } + { \@@_backend_getbb_auxii:n {#1} } + } +% \end{macrocode} +% Measuring the graphic is done by boxing up: for PDF graphics we could +% use |\tex_pdfximagebbox:D|, but if doesn't work for other types. +% As the box always starts at $(0,0)$ there is no need to worry about +% the lower-left position. Quotes need to be \emph{removed} as \LuaTeX{} +% does not like them here. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_getbb_auxii:n #1 + { + \exp_args:Ne \@@_backend_getbb_auxiii:n + { \@@_backend_dequote:w #1 " #1 " \s_@@_stop } + \int_const:cn { c_@@_ #1 \l_@@_attr_tl _int } + { \tex_the:D \tex_pdflastximage:D } + \@@_bb_save:e { #1 \l_@@_attr_tl } + } +\cs_new_protected:Npn \@@_backend_getbb_auxiii:n #1 + { + \tex_immediate:D \tex_pdfximage:D + \bool_lazy_any:nT + { + { \l_@@_interpolate_bool } + { ! \tl_if_empty_p:N \l_@@_decodearray_str } + { ! \str_if_empty_p:N \l_@@_pdf_str } + } + { + attr ~ + { + \tl_if_empty:NF \l_@@_decodearray_str + { /Decode~[ \l_@@_decodearray_str ] } + \bool_if:NT \l_@@_interpolate_bool + { /Interpolate~true } + \l_@@_pdf_str + } + } + \int_compare:nNnT \l_@@_page_int > 0 + { page ~ \int_use:N \l_@@_page_int } + \tl_if_empty:NF \l_@@_pagebox_tl + { \l_@@_pagebox_tl } + {#1} + \hbox_set:Nn \l_@@_internal_box + { \tex_pdfrefximage:D \tex_pdflastximage:D } + \dim_set:Nn \l_@@_urx_dim { \box_wd:N \l_@@_internal_box } + \dim_set:Nn \l_@@_ury_dim { \box_ht:N \l_@@_internal_box } + } +\cs_new:Npn \@@_backend_dequote:w #1 " #2 " #3 \s_@@_stop {#2} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% { +% \@@_backend_include_jpg:n , +% \@@_backend_include_jpeg:n , +% \@@_backend_include_pdf:n , +% \@@_backend_include_png:n +% } +% Images are already loaded for the measurement part of the code, so +% inclusion is straight-forward, with only any attributes to worry about. The +% latter carry through from determination of the bounding box. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_include_jpg:n #1 + { + \tex_pdfrefximage:D + \int_use:c { c_@@_ #1 \l_@@_attr_tl _int } + } +\cs_new_eq:NN \@@_backend_include_jpeg:n \@@_backend_include_jpg:n +\cs_new_eq:NN \@@_backend_include_pdf:n \@@_backend_include_jpg:n +\cs_new_eq:NN \@@_backend_include_png:n \@@_backend_include_jpg:n +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_backend_getbb_eps:n, \@@_backend_getbb_ps:n} +% \begin{macro}{\@@_backend_getbb_eps:nm} +% \begin{macro}{\@@_backend_include_eps:n, \@@_backend_include_ps:n} +% \begin{variable} +% {\l_@@_backend_dir_str, \l_@@_backend_name_str, \l_@@_backend_ext_str} +% EPS graphics may be included in \LuaTeX{}/pdfTeX{} by conversion to +% PDF: this requires restricted shell escape. Modelled on the \pkg{epstopdf} +% \LaTeXe{} package, but simplified, conversion takes place here if we have +% shell access. +% \begin{macrocode} +\sys_if_shell:T + { + \str_new:N \l_@@_backend_dir_str + \str_new:N \l_@@_backend_name_str + \str_new:N \l_@@_backend_ext_str + \cs_new_protected:Npn \@@_backend_getbb_eps:n #1 + { + \file_parse_full_name:nNNN {#1} + \l_@@_backend_dir_str + \l_@@_backend_name_str + \l_@@_backend_ext_str + \exp_args:Ne \@@_backend_getbb_eps:nn + { + \exp_args:Ne \__kernel_file_name_quote:n + { + \l_@@_backend_name_str + - \str_tail:N \l_@@_backend_ext_str + -converted-to.pdf + } + } + {#1} + } + \cs_new_eq:NN \@@_backend_getbb_ps:n \@@_backend_getbb_eps:n + \cs_new_protected:Npn \@@_backend_getbb_eps:nn #1#2 + { + \file_compare_timestamp:nNnT {#2} > {#1} + { + \sys_shell_now:n + { repstopdf ~ #2 ~ #1 } + } + \tl_set:Nn \l_@@_final_name_str {#1} + \@@_backend_getbb_pdf:n {#1} + } + \cs_new_protected:Npn \@@_backend_include_eps:n #1 + { + \file_parse_full_name:nNNN {#1} + \l_@@_backend_dir_str \l_@@_backend_name_str \l_@@_backend_ext_str + \exp_args:Ne \@@_backend_include_pdf:n + { + \exp_args:Ne \__kernel_file_name_quote:n + { + \l_@@_backend_name_str + - \str_tail:N \l_@@_backend_ext_str + -converted-to.pdf + } + } + } + \cs_new_eq:NN \@@_backend_include_ps:n \@@_backend_include_eps:n + } +% \end{macrocode} +% \end{variable} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_backend_get_pagecount:n} +% Simply load and store. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_get_pagecount:n #1 + { + \tex_pdfximage:D {#1} + \int_const:cn { c_@@_ #1 _pages_int } + { \int_use:N \tex_pdflastximagepages:D } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</luatex|pdftex> +% \end{macrocode} +% +% \subsection{\texttt{dvipdfmx} backend} +% +% \begin{macrocode} +%<*dvipdfmx|xetex> +% \end{macrocode} +% +% \begin{variable}[no-user-doc]{\l_graphics_search_ext_seq} +% \begin{macrocode} +\@@_backend_loaded:n + { + \seq_set_from_clist:Nn \l_graphics_search_ext_seq + { .pdf , .eps , .ps , .png , .jpg , .jpeg , .bmp } + } +% \end{macrocode} +% \end{variable} +% +% \begin{macro} +% { +% \@@_backend_getbb_eps:n , \@@_backend_getbb_ps:n , +% \@@_backend_getbb_jpg:n , \@@_backend_getbb_jpeg:n , +% \@@_backend_getbb_pdf:n , \@@_backend_getbb_png:n , +% \@@_backend_getbb_bmp:n +% } +% Simply use the generic functions: only for \texttt{dvipdfmx} in the +% extraction cases. +% \begin{macrocode} +\@@_backend_loaded:n + { + \cs_new_eq:NN \@@_backend_getbb_eps:n \@@_read_bb:n + \cs_new_eq:NN \@@_backend_getbb_ps:n \@@_read_bb:n + } +%<*dvipdfmx> +\cs_new_protected:Npn \@@_backend_getbb_jpg:n #1 + { + \int_zero:N \l_@@_page_int + \tl_clear:N \l_@@_pagebox_tl + \@@_extract_bb:n {#1} + } +\cs_new_eq:NN \@@_backend_getbb_jpeg:n \@@_backend_getbb_jpg:n +\cs_new_eq:NN \@@_backend_getbb_png:n \@@_backend_getbb_jpg:n +\cs_new_eq:NN \@@_backend_getbb_bmp:n \@@_backend_getbb_jpg:n +\cs_new_protected:Npn \@@_backend_getbb_pdf:n #1 + { + \tl_clear:N \l_@@_decodearray_str + \bool_set_false:N \l_@@_interpolate_bool + \@@_extract_bb:n {#1} + } +%</dvipdfmx> +% \end{macrocode} +% \end{macro} +% +% \begin{variable}{\g_@@_track_int} +% Used to track the object number associated with each graphic. +% \begin{macrocode} +\int_new:N \g_@@_track_int +% \end{macrocode} +% \end{variable} +% +% \begin{macro} +% { +% \@@_backend_include_eps:n , \@@_backend_include_ps:n , +% \@@_backend_include_jpg:n , \@@_backend_include_jpseg:n , +% \@@_backend_include_pdf:n , \@@_backend_include_png:n , +% \@@_backend_include_bmp:n , +% } +% \begin{macro}{\@@_backend_include_auxi:nn} +% \begin{macro}{\@@_backend_include_auxii:nnn, \@@_backend_include_auxii:enn} +% \begin{macro}{\@@_backend_include_auxiii:nnn} +% The special syntax depends on the file type. There is a difference in +% how PDF graphics are best handled between |dvipdfmx| and \XeTeX{}: for +% the latter it is better to use the primitive route. The relevant code for +% that is included later in this file. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_include_eps:n #1 + { + \__kernel_backend_literal:e + { + PSfile = #1 \c_space_tl + llx = \dim_to_decimal_in_bp:n \l_@@_llx_dim \c_space_tl + lly = \dim_to_decimal_in_bp:n \l_@@_lly_dim \c_space_tl + urx = \dim_to_decimal_in_bp:n \l_@@_urx_dim \c_space_tl + ury = \dim_to_decimal_in_bp:n \l_@@_ury_dim + } + } +\cs_new_eq:NN \@@_backend_include_ps:n \@@_backend_include_eps:n +\cs_new_protected:Npn \@@_backend_include_jpg:n #1 + { \@@_backend_include_auxi:nn {#1} { image } } +\cs_new_eq:NN \@@_backend_include_jpeg:n \@@_backend_include_jpg:n +\cs_new_eq:NN \@@_backend_include_png:n \@@_backend_include_jpg:n +\cs_new_eq:NN \@@_backend_include_bmp:n \@@_backend_include_jpg:n +%<*dvipdfmx> +\cs_new_protected:Npn \@@_backend_include_pdf:n #1 + { \@@_backend_include_auxi:nn {#1} { epdf } } +%</dvipdfmx> +% \end{macrocode} +% Graphic inclusion is set up to use the fact that each image is stored in +% the PDF as an XObject. This means that we can include repeated images +% only once and refer to them. To allow that, track the nature of each +% image: much the same as for the direct PDF mode case. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_include_auxi:nn #1#2 + { + \@@_backend_include_auxii:enn + { + \tl_if_empty:NF \l_@@_pagebox_tl + { : \l_@@_pagebox_tl } + \int_compare:nNnT \l_@@_page_int > 1 + { :P \int_use:N \l_@@_page_int } + \tl_if_empty:NF \l_@@_decodearray_str + { :D \l_@@_decodearray_str } + \bool_if:NT \l_@@_interpolate_bool + { :I } + } + {#1} {#2} + } +\cs_new_protected:Npn \@@_backend_include_auxii:nnn #1#2#3 + { + \int_if_exist:cTF { c_@@_ #2#1 _int } + { + \__kernel_backend_literal:e + { pdf:usexobj~@graphic \int_use:c { c_@@_ #2#1 _int } } + } + { \@@_backend_include_auxiii:nnn {#2} {#1} {#3} } + } +\cs_generate_variant:Nn \@@_backend_include_auxii:nnn { e } +% \end{macrocode} +% Inclusion using the specials is relatively straight-forward, but there +% is one wrinkle. To get the |pagebox| correct for PDF graphics in all cases, +% it is necessary to provide both that information and the |bbox| argument: +% odd things happen otherwise! +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_include_auxiii:nnn #1#2#3 + { + \int_gincr:N \g_@@_track_int + \int_const:cn { c_@@_ #1#2 _int } { \g_@@_track_int } + \__kernel_backend_literal:e + { + pdf:#3~ + @graphic \int_use:c { c_@@_ #1#2 _int } ~ + \int_compare:nNnT \l_@@_page_int > 1 + { page ~ \int_use:N \l_@@_page_int \c_space_tl } + \tl_if_empty:NF \l_@@_pagebox_tl + { + pagebox ~ \l_@@_pagebox_tl \c_space_tl + bbox ~ + \dim_to_decimal_in_bp:n \l_@@_llx_dim \c_space_tl + \dim_to_decimal_in_bp:n \l_@@_lly_dim \c_space_tl + \dim_to_decimal_in_bp:n \l_@@_urx_dim \c_space_tl + \dim_to_decimal_in_bp:n \l_@@_ury_dim \c_space_tl + } + (#1) + \bool_lazy_or:nnT + { \l_@@_interpolate_bool } + { ! \tl_if_empty_p:N \l_@@_decodearray_str } + { + << + \tl_if_empty:NF \l_@@_decodearray_str + { /Decode~[ \l_@@_decodearray_str ] } + \bool_if:NT \l_@@_interpolate_bool + { /Interpolate~true } + >> + } + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_backend_get_pagecount:n} +% \begin{macrocode} +%<*dvipdfmx> +\@@_backend_loaded:n + { \cs_new_eq:NN \@@_backend_get_pagecount:n \@@_get_pagecount:n } +%</dvipdfmx> +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</dvipdfmx|xetex> +% \end{macrocode} +% +% \subsection{\XeTeX{} backend} +% +% \begin{macrocode} +%<*xetex> +% \end{macrocode} +% +% \begin{macro} +% { +% \@@_backend_getbb_jpg:n , +% \@@_backend_getbb_jpeg:n , +% \@@_backend_getbb_pdf:n , +% \@@_backend_getbb_png:n , +% \@@_backend_getbb_bmp:n +% } +% \begin{macro}{\@@_backend_getbb_auxi:nN} +% \begin{macro}{\@@_backend_getbb_auxii:nnN, \@@_backend_getbb_auxii:VnN} +% \begin{macro}{\@@_backend_getbb_auxiii:nNnn} +% \begin{macro}{\@@_backend_getbb_auxiv:nnNnn, \@@_backend_getbb_auxiv:VnNnn} +% \begin{macro}{\@@_backend_getbb_auxv:nNnn, \@@_backend_getbb_auxv:nNnn} +% \begin{macro}[EXP]{\@@_backend_getbb_pagebox:w} +% For \XeTeX{}, there are two primitives that allow us to obtain +% the bounding box without needing \texttt{extractbb}. The only complexity +% is passing the various minor variations to a common core process. The +% \XeTeX{} primitive omits the text |box| from the page box specification, +% so there is also some \enquote{trimming} to do here. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_getbb_jpg:n #1 + { + \int_zero:N \l_@@_page_int + \tl_clear:N \l_@@_pagebox_tl + \@@_backend_getbb_auxi:nN {#1} \tex_XeTeXpicfile:D + } +\cs_new_eq:NN \@@_backend_getbb_jpeg:n \@@_backend_getbb_jpg:n +\cs_new_eq:NN \@@_backend_getbb_png:n \@@_backend_getbb_jpg:n +\cs_new_eq:NN \@@_backend_getbb_bmp:n \@@_backend_getbb_jpg:n +\cs_new_protected:Npn \@@_backend_getbb_pdf:n #1 + { + \tl_clear:N \l_@@_decodearray_str + \bool_set_false:N \l_@@_interpolate_bool + \@@_backend_getbb_auxi:nN {#1} \tex_XeTeXpdffile:D + } +\cs_new_protected:Npn \@@_backend_getbb_auxi:nN #1#2 + { + \int_compare:nNnTF \l_@@_page_int > 1 + { \@@_backend_getbb_auxii:VnN \l_@@_page_int {#1} #2 } + { \@@_backend_getbb_auxiii:nNnn {#1} #2 { :P 1 } { page 1 } } + } +\cs_new_protected:Npn \@@_backend_getbb_auxii:nnN #1#2#3 + { \@@_backend_getbb_auxiii:nNnn {#2} #3 { :P #1 } { page #1 } } +\cs_generate_variant:Nn \@@_backend_getbb_auxii:nnN { V } +\cs_new_protected:Npn \@@_backend_getbb_auxiii:nNnn #1#2#3#4 + { + \tl_if_empty:NTF \l_@@_pagebox_tl + { \@@_backend_getbb_auxiv:VnNnn \l_@@_pagebox_tl } + { \@@_backend_getbb_auxv:nNnn } + {#1} #2 {#3} {#4} + } +\cs_new_protected:Npn \@@_backend_getbb_auxiv:nnNnn #1#2#3#4#5 + { + \use:e + { + \@@_backend_getbb_auxv:nNnn {#2} #3 { : #1 #4 } + { + #5 + \tl_if_blank:nF {#1} + { \c_space_tl \@@_backend_getbb_pagebox:w #1 } + } + } + } +\cs_generate_variant:Nn \@@_backend_getbb_auxiv:nnNnn { V } +\cs_new_protected:Npn \@@_backend_getbb_auxv:nNnn #1#2#3#4 + { + \@@_bb_restore:nF {#1#3} + { \@@_backend_getbb_auxvi:nNnn {#1} #2 {#3} {#4} } + } +\cs_new_protected:Npn \@@_backend_getbb_auxvi:nNnn #1#2#3#4 + { + \hbox_set:Nn \l_@@_internal_box { #2 #1 ~ #4 } + \dim_set:Nn \l_@@_urx_dim { \box_wd:N \l_@@_internal_box } + \dim_set:Nn \l_@@_ury_dim { \box_ht:N \l_@@_internal_box } + \@@_bb_save:n {#1#3} + } +\cs_new:Npn \@@_backend_getbb_pagebox:w #1 box {#1} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_backend_include_pdf:n} +% For PDF graphics, properly supporting the |pagebox| concept in \XeTeX{} +% is best done using the |\tex_XeTeXpdffile:D| primitive. The syntax here +% is the same as for the graphic measurement part, although we know at this +% stage that there must be some valid setting for \cs{l_@@_pagebox_tl}. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_include_pdf:n #1 + { + \tex_XeTeXpdffile:D #1 ~ + \int_compare:nNnT \l_@@_page_int > 0 + { page ~ \int_use:N \l_@@_page_int \c_space_tl } + \exp_after:wN \@@_backend_getbb_pagebox:w \l_@@_pagebox_tl + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_backend_get_pagecount:n} +% Very little to do here other than cover the case of a non-PDF file. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_get_pagecount:n #1 + { + \int_const:cn { c_@@_ #1 _pages_int } + { + \int_max:nn + { \int_use:N \tex_XeTeXpdfpagecount:D #1 ~ } + { 1 } + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</xetex> +% \end{macrocode} +% +% \subsection{\texttt{dvisvgm} backend} +% +% \begin{macrocode} +%<*dvisvgm> +% \end{macrocode} +% +% \begin{variable}[no-user-doc]{\l_graphics_search_ext_seq} +% \begin{macrocode} +\@@_backend_loaded:n + { + \seq_set_from_clist:Nn + \l_graphics_search_ext_seq + { .svg , .pdf , .eps , .ps , .png , .jpg , .jpeg } + } +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\@@_backend_getbb_svg:n} +% \begin{macro}{\@@_backend_getbb_svg_auxi:nNn} +% \begin{macro}{\@@_backend_getbb_svg_auxii:w} +% \begin{macro} +% { +% \@@_backend_getbb_svg_auxiii:Nw , +% \@@_backend_getbb_svg_auxiv:Nw , +% \@@_backend_getbb_svg_auxv:Nw +% } +% \begin{macro}{\@@_backend_getbb_svg_auxvi:Nn} +% \begin{macro}{\@@_backend_getbb_svg_auxvii:w} +% This is relatively similar to reading bounding boxes for |.eps| files. Life +% is though made more tricky as we cannot pick a single line for the data. So +% we have to loop until we collect up both height and width. To do that, we +% can use a marker value. We also have to allow for the default units of the +% lengths: they are big points and may be omitted. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_getbb_svg:n #1 + { + \@@_bb_restore:nF {#1} + { + \ior_open:Nn \l_@@_internal_ior {#1} + \ior_if_eof:NTF \l_@@_internal_ior + { \msg_error:nnn { graphics } { graphic-not-found } {#1} } + { + \dim_zero:N \l_@@_llx_dim + \dim_zero:N \l_@@_lly_dim + \dim_set:Nn \l_@@_urx_dim { -\c_max_dim } + \dim_set:Nn \l_@@_ury_dim { -\c_max_dim } + \ior_str_map_inline:Nn \l_@@_internal_ior + { + \dim_compare:nNnT \l_@@_urx_dim = { -\c_max_dim } + { + \@@_backend_getbb_svg_auxi:nNn + { width } \l_@@_urx_dim {##1} + } + \dim_compare:nNnT \l_@@_ury_dim = { -\c_max_dim } + { + \@@_backend_getbb_svg_auxi:nNn + { height } \l_@@_ury_dim {##1} + } + \bool_lazy_and:nnF + { \dim_compare_p:nNn \l_@@_urx_dim = { -\c_max_dim } } + { \dim_compare_p:nNn \l_@@_ury_dim = { -\c_max_dim } } + { \ior_map_break: } + } + \@@_bb_save:n {#1} + } + \ior_close:N \l_@@_internal_ior + } + } +\cs_new_protected:Npn \@@_backend_getbb_svg_auxi:nNn #1#2#3 + { + \use:e + { + \cs_set_protected:Npn \@@_backend_getbb_svg_auxii:w + ##1 \tl_to_str:n {#1} = ##2 \tl_to_str:n {#1} = ##3 + \s_@@_stop + } + { + \tl_if_blank:nF {##2} + { + \peek_remove_spaces:n + { + \peek_meaning:NTF ' % ' + { \@@_backend_getbb_svg_auxiii:Nw #2 } + { + \peek_meaning:NTF " % " + { \@@_backend_getbb_svg_auxiv:Nw #2 } + { \@@_backend_getbb_svg_auxv:Nw #2 } + } + } + ##2 \s_@@_stop + } + } + \use:e + { + \@@_backend_getbb_svg_auxii:w #3 + \tl_to_str:n {#1} = \tl_to_str:n {#1} = + \s_@@_stop + } + } +\cs_new_protected:Npn \@@_backend_getbb_svg_auxii:w { } +\cs_new_protected:Npn \@@_backend_getbb_svg_auxiii:Nw #1 ' #2 ' #3 \s_@@_stop + { \@@_backend_getbb_svg_auxvi:Nn #1 {#2} } +\cs_new_protected:Npn \@@_backend_getbb_svg_auxiv:Nw #1 " #2 " #3 \s_@@_stop + { \@@_backend_getbb_svg_auxvi:Nn #1 {#2} } +\cs_new_protected:Npn \@@_backend_getbb_svg_auxv:Nw #1 #2 ~ #3 \s_@@_stop + { \@@_backend_getbb_svg_auxvi:Nn #1 {#2} } +\cs_new_protected:Npn \@@_backend_getbb_svg_auxvi:Nn #1#2 + { + \tex_afterassignment:D \@@_backend_getbb_svg_auxvii:w + \l_@@_internal_dim #2 bp \scan_stop: + \dim_set_eq:NN #1 \l_@@_internal_dim + } +\cs_new_protected:Npn \@@_backend_getbb_svg_auxvii:w #1 \scan_stop: { } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_backend_getbb_eps:n, \@@_backend_getbb_ps:n} +% Simply use the generic function. +% \begin{macrocode} +\@@_backend_loaded:n + { + \cs_new_eq:NN \@@_backend_getbb_eps:n \@@_read_bb:n + \cs_new_eq:NN \@@_backend_getbb_ps:n \@@_read_bb:n + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_backend_getbb_png:n, \@@_backend_getbb_jpg:n, \@@_backend_getbb_jpeg:n} +% These can be included by extracting the bounding box data. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_getbb_jpg:n #1 + { + \int_zero:N \l_@@_page_int + \tl_clear:N \l_@@_pagebox_tl + \@@_extract_bb:n {#1} + } +\cs_new_eq:NN \@@_backend_getbb_jpeg:n \@@_backend_getbb_jpg:n +\cs_new_eq:NN \@@_backend_getbb_png:n \@@_backend_getbb_jpg:n +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_backend_getbb_pdf:n} +% Same as for \texttt{dvipdfmx}: use the generic function +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_getbb_pdf:n #1 + { + \tl_clear:N \l_@@_decodearray_str + \bool_set_false:N \l_@@_interpolate_bool + \@@_extract_bb:n {#1} + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro} +% { +% \@@_backend_include_eps:n , +% \@@_backend_include_ps:n , +% \@@_backend_include_pdf:n +% } +% \begin{macro}{\@@_backend_include:nn} +% The special syntax is relatively clear here: remember we need PostScript +% sizes here. (This is the same as the \texttt{dvips} code.) +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_include_eps:n #1 + { \@@_backend_include:nn { PSfile } {#1} } +\cs_new_eq:NN \@@_backend_include_ps:n \@@_backend_include_eps:n +\cs_new_protected:Npn \@@_backend_include_pdf:n #1 + { \@@_backend_include:nn { pdffile } {#1} } +\cs_new_protected:Npn \@@_backend_include:nn #1#2 + { + \__kernel_backend_literal:e + { + #1 = #2 \c_space_tl + llx = \dim_to_decimal_in_bp:n \l_@@_llx_dim \c_space_tl + lly = \dim_to_decimal_in_bp:n \l_@@_lly_dim \c_space_tl + urx = \dim_to_decimal_in_bp:n \l_@@_urx_dim \c_space_tl + ury = \dim_to_decimal_in_bp:n \l_@@_ury_dim + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% { +% \@@_backend_include_svg:n , +% \@@_backend_include_png:n , +% \@@_backend_include_jpg:n , +% \@@_backend_include_jpeg:n +% } +% \begin{macro}{\@@_backend_include_dequote:w} +% The backend here has built-in support for basic graphic inclusion (see +% \texttt{dvisvgm.def} for a more complex approach, needed if clipping, +% \emph{etc.}, is covered at the graphic backend level). We have to deal +% with the fact that the image reference point is at the \emph{top}, so +% there is a need for a vertical shift to put it in the right place. +% The other issue is that |#1| must be quote-corrected. The +% \texttt{dvisvgm:img} operation quotes the file name, but if it is already +% quoted (contains spaces) then we have an issue: we simply strip off any +% quotes as a result. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_include_svg:n #1 + { + \box_move_up:nn { \l_@@_ury_dim } + { + \hbox:n + { + \__kernel_backend_literal:e + { + dvisvgm:img~ + \dim_to_decimal:n { \l_@@_urx_dim } ~ + \dim_to_decimal:n { \l_@@_ury_dim } ~ + \@@_backend_include_dequote:w #1 " #1 " \s_@@_stop + } + } + } + } +\cs_new_eq:NN \@@_backend_include_png:n \@@_backend_include_svg:n +\cs_new_eq:NN \@@_backend_include_jpeg:n \@@_backend_include_svg:n +\cs_new_eq:NN \@@_backend_include_jpg:n \@@_backend_include_svg:n +\cs_new:Npn \@@_backend_include_dequote:w #1 " #2 " #3 \s_@@_stop + {#2} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_backend_get_pagecount:n} +% \begin{macrocode} +\@@_backend_loaded:n + { \cs_new_eq:NN \@@_backend_get_pagecount:n \@@_get_pagecount:n } +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</dvisvgm> +% \end{macrocode} +% +% \begin{macrocode} +%</package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex |