% \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} % % \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-03-14} % % \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} % % \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} % % \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} } % % \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 } } % % \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 } % % \end{macrocode} % \end{macro} % % \begin{macrocode} % % \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} % % \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} % % \end{macrocode} % % \begin{macrocode} % % \end{macrocode} % % \end{implementation} % % \PrintIndex