% \iffalse meta-comment
%
%% File: l3backend-graphics.dtx
%
% Copyright (C) 2019-2026 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 "l3kernel 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 2026-08-10}
%
% \maketitle
%
% \begin{documentation}
%
% \end{documentation}
%
% \begin{implementation}
%
% \section{\pkg{l3backend-graphics} implementation}
%
%    \begin{macrocode}
%<*package>
%<@@=graphics>
%    \end{macrocode}
%
% \subsection{\texttt{dvips} backend}
%
%    \begin{macrocode}
%<*dvips>
%    \end{macrocode}
%
% \begin{variable}[no-user-doc]{\l_graphics_search_ext_seq}
%    \begin{macrocode}
\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}
\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}
\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}
\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{variable}{\l_@@_transgroup_bool}
%   Needed to indicate that a transparency group should be applied: only
%   currently for PDF images, but could be extended.
%    \begin{macrocode}
\bool_new:N \l_@@_transgroup_bool
%    \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
    \bool_set_false:N \l_@@_transgroup_bool
    \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_true:N \l_@@_transgroup_bool
    \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. We always apply a transparency group attribute
%   here as included PDFs otherwise may have non-obvious behavior.
%    \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 }
          { \l_@@_transgroup_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_@@_transgroup_bool
                { /Group << /S /Transparency /K ~ false /I ~ false >> }
              \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_@@_tmp_box
      { \tex_pdfrefximage:D \tex_pdflastximage:D }
    \dim_set:Nn \l_@@_urx_dim { \box_wd:N \l_@@_tmp_box }
    \dim_set:Nn \l_@@_ury_dim { \box_ht:N \l_@@_tmp_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. Modeled 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}
\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}
\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}{\l_@@_transgroup_bool}
%   Needed to indicate that a transparency group should be applied: only
%   currently for PDF images, but could be extended.
%    \begin{macrocode}
\bool_new:N \l_@@_transgroup_bool
%    \end{macrocode}
% \end{variable}
%
% \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:n}
%  \begin{macro}{\@@_backend_include_auxii:nn, \@@_backend_include_auxii:en}
%  \begin{macro}{\@@_backend_include_auxiii:nn}
%   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
%    \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_jpg:n #1
  {
    \bool_set_false:N \l_@@_transgroup_bool
    \@@_backend_include_auxi:n {#1}
  }
\cs_new_eq:NN \@@_backend_include_jpeg:n \@@_backend_include_jpg:n
\cs_new_eq:NN \@@_backend_include_bmp:n \@@_backend_include_jpg:n
\cs_new_eq:NN \@@_backend_include_png:n \@@_backend_include_jpg:n
\cs_new_protected:Npn \@@_backend_include_pdf:n #1
  {
    \bool_set_true:N \l_@@_transgroup_bool
    \@@_backend_include_auxi:n {#1}
  }
\cs_new_protected:Npn \@@_backend_include_auxi:n #1
  {
    \@@_backend_include_auxii:en
      {
        \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}
  }
\cs_new_protected:Npn \@@_backend_include_auxii:nn #1#2
  {
    \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:nn {#2} {#1} }
  }
\cs_generate_variant:Nn \@@_backend_include_auxii:nn { 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! We use the \texttt{dvipdfmx} special in all
%  cases as it allows attributes to be added to the XObject.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_backend_include_auxiii:nn #1#2
  {
    \int_gincr:N \g_@@_track_int
    \int_const:cn { c_@@_ #1#2 _int } { \g_@@_track_int }
    \__kernel_backend_literal:e
      {
        pdf:image ~
        @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_any:nT
          {
            { \l_@@_interpolate_bool }
            { \l_@@_transgroup_bool }
            { ! \tl_if_empty_p:N \l_@@_decodearray_str }
          }
          {
            <<
              \tl_if_empty:NF \l_@@_decodearray_str
                { /Decode~[ \l_@@_decodearray_str ] }
              \bool_if:NT \l_@@_transgroup_bool
                { /Group << /S /Transparency /K ~ false /I ~ false >> }
              \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>
\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_@@_tmp_box { #2 #1 ~ #4 }
    \dim_set:Nn \l_@@_urx_dim { \box_wd:N \l_@@_tmp_box }
    \dim_set:Nn \l_@@_ury_dim { \box_ht:N \l_@@_tmp_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_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}
\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_@@_tmp_ior {#1}
        \ior_if_eof:NTF \l_@@_tmp_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_@@_tmp_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_@@_tmp_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_@@_tmp_dim #2 bp \scan_stop:
    \dim_set_eq:NN #1 \l_@@_tmp_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}
\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,
%   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}
\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
