% \iffalse meta-comment % %% File: l3drivers-image.dtx % % Copyright (C) 2011-2019 The LaTeX3 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} % % \fi % % \title{^^A % The \textsf{l3drivers-image} package\\ Driver image support^^A % } % % \author{^^A % The \LaTeX3 Project\thanks % {^^A % E-mail: % \href{mailto:latex-team@latex-project.org} % {latex-team@latex-project.org}^^A % }^^A % } % % \date{Released 2019-05-03} % % \maketitle % % \begin{documentation} % % \end{documentation} % % \begin{implementation} % % \section{\pkg{l3drivers-image} Implementation} % % \begin{macrocode} %<*initex|package> %<@@=driver> % \end{macrocode} % % \subsection{\texttt{dvips} driver} % % \begin{macrocode} %<*dvips> % \end{macrocode} % % \begin{macro}{\@@_image_getbb_eps:n} % Simply use the generic function. % \begin{macrocode} \cs_new_eq:NN \@@_image_getbb_eps:n \image_read_bb:n % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_image_include_eps:n} % The special syntax is relatively clear here: remember we need PostScript % sizes here. % \begin{macrocode} \cs_new_protected:Npn \@@_image_include_eps:n #1 { \@@_literal:n { PSfile = #1 } } % \end{macrocode} % \end{macro} % % \begin{macrocode} % % \end{macrocode} % % \subsection{\texttt{pdfmode} driver} % % \begin{macrocode} %<*pdfmode> % \end{macrocode} % % \begin{variable}{\l_@@_image_attr_tl} % In PDF mode, additional attributes of an image (such as page number) are % needed both to obtain the bounding box and when inserting the image: this % occurs as the image 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_@@_image_attr_tl % \end{macrocode} % \end{variable} % % \begin{macro} % {\@@_image_getbb_jpg:n, \@@_image_getbb_pdf:n, \@@_image_getbb_png:n} % \begin{macro} % {\@@_image_getbb_auxi:n, \@@_image_getbb_auxii:n} % Getting the bounding box here requires us to box up the image and % measure it. To deal with the difference in feature support in bitmap % and vector images 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 \@@_image_getbb_jpg:n #1 { \int_zero:N \l_image_page_int \tl_clear:N \l_image_pagebox_tl \tl_set:Nx \l_@@_image_attr_tl { \tl_if_empty:NF \l_image_decode_tl { :D \l_image_decodearray_tl } \bool_if:NT \l_image_interpolate_bool { :I } } \tl_clear:N \l_@@_image_attr_tl \@@_image_getbb_auxi:n {#1} } \cs_new_eq:NN \@@_image_getbb_png:n \@@_image_getbb_jpg:n \cs_new_protected:Npn \@@_image_getbb_pdf:n #1 { \tl_clear:N \l_image_decode_tl \bool_set_false:N \l_image_interpolate_bool \tl_set:Nx \l_@@_image_attr_tl { : \l_image_pagebox_tl \int_compare:nNnT \l_image_page_int > 1 { :P \int_use:N \l_image_page_int } } \@@_image_getbb_auxi:n {#1} } \cs_new_protected:Npn \@@_image_getbb_auxi:n #1 { \image_bb_restore:xF { #1 \l_@@_image_attr_tl } { \@@_image_getbb_auxii:n {#1} } } % \begin{macrocode} % Measuring the image is done by boxing up: for PDF images 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. % \begin{macrocode} \cs_new_protected:Npn \@@_image_getbb_auxii:n #1 { \tex_immediate:D \tex_pdfximage:D \bool_lazy_or:nnT { \l_image_interpolate_bool } { ! \tl_if_empty_p:N \l_image_decodearray_tl } { attr ~ { \tl_if_empty:NF \l_image_decode_tl { /Decode~[ \l_image_decodearray_tl ] } \bool_if:NT \l_image_interpolate_bool { /Interpolate~true } } } \int_compare:nNnT \l_image_page_int > 0 { page ~ \int_use:N \l_image_page_int } \tl_if_empty:NF \l_image_pagebox_tl { \l_image_pagebox_tl } {#1} \hbox_set:Nn \l_@@_tmp_box { \tex_pdfrefximage:D \tex_pdflastximage:D } \dim_set:Nn \l_image_urx_dim { \box_wd:N \l_@@_tmp_box } \dim_set:Nn \l_image_ury_dim { \box_ht:N \l_@@_tmp_box } \int_const:cn { c_@@_image_ #1 \l_@@_image_attr_tl _int } { \tex_the:D \tex_pdflastximage:D } \image_bb_save:x { #1 \l_@@_image_attr_tl } } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro} % {\@@_image_include_jpg:n, \@@_image_include_pdf:n, \@@_image_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 \@@_image_include_jpg:n #1 { \tex_pdfrefximage:D \int_use:c { c_@@_image_ #1 \l_@@_image_attr_tl _int } } \cs_new_eq:NN \@@_image_include_pdf:n \@@_image_include_jpg:n \cs_new_eq:NN \@@_image_include_png:n \@@_image_include_jpg:n % \end{macrocode} % \end{macro} % % \begin{macrocode} % % \end{macrocode} % % \subsection{\texttt{dvipdfmx} driver} % % \begin{macrocode} %<*dvipdfmx|xdvipdfmx> % \end{macrocode} % % \begin{macro} % { % \@@_image_getbb_eps:n, \@@_image_getbb_jpg:n, % \@@_image_getbb_pdf:n, \@@_image_getbb_png:n % } % Simply use the generic functions: only for \texttt{dvipdfmx} in the % extraction cases. % \begin{macrocode} \cs_new_eq:NN \@@_image_getbb_eps:n \image_read_bb:n %<*dvipdfmx> \cs_new_protected:Npn \@@_image_getbb_jpg:n #1 { \int_zero:N \l_image_page_int \tl_clear:N \l_image_pagebox_tl \image_extract_bb:n {#1} } \cs_new_eq:NN \@@_image_getbb_png:n \@@_image_getbb_jpg:n \cs_new_protected:Npn \@@_image_getbb_pdf:n #1 { \tl_clear:N \l_image_decode_tl \bool_set_false:N \l_image_interpolate_bool \image_extract_bb:n {#1} } % % \end{macrocode} % \end{macro} % % \begin{variable}{\g_@@_image_int} % Used to track the object number associated with each image. % \begin{macrocode} \int_new:N \g_@@_image_int % \end{macrocode} % \end{variable} % % \begin{macro} % { % \@@_image_include_eps:n, \@@_image_include_jpg:n, % \@@_image_include_pdf:n, \@@_image_include_png:n % } % \begin{macro}{\@@_image_include_auxi:nn} % \begin{macro}{\@@_image_include_auxii:nnn, \@@_image_include_auxii:xnn} % \begin{macro}{\@@_image_include_auxiii:nn} % The special syntax depends on the file type. There is a difference in % how PDF images are best handled between |dvipdfmx| and |xdvipdfmx|: 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 \@@_image_include_eps:n #1 { \@@_literal:n { PSfile = #1 } } \cs_new_protected:Npn \@@_image_include_jpg:n #1 { \@@_image_include_auxi:nn {#1} { image } } \cs_new_eq:NN \@@_image_include_png:n \@@_image_include_jpg:n %<*dvipdfmx> \cs_new_protected:Npn \@@_image_include_pdf:n #1 { \@@_image_include_auxi:nn {#1} { epdf } } % % \end{macrocode} % Image 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 \@@_image_include_auxi:nn #1#2 { \@@_image_include_auxii:xnn { \tl_if_empty:NF \l_image_pagebox_tl { : \l_image_pagebox_tl } \int_compare:nNnT \l_image_page_int > 1 { :P \int_use:N \l_image_page_int } \tl_if_empty:NF \l_image_decode_tl { :D \l_image_decodearray_tl } \bool_if:NT \l_image_interpolate_bool { :I } } {#1} {#2} } \cs_new_protected:Npn \@@_image_include_auxii:nnn #1#2#3 { \int_if_exist:cTF { c_@@_image_ #2#1 _int } { \@@_literal:x { pdf:usexobj~@image \int_use:c { c_@@_image_ #2#1 _int } } } { \@@_image_include_auxiii:nn {#2} {#1} {#3} } } \cs_generate_variant:Nn \@@_image_include_auxii:nnn { x } % \end{macrocode} % Inclusion using the specials is relatively straight-forward, but there % is one wrinkle. To get the |pagebox| correct for PDF images 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 \@@_image_include_auxiii:nnn #1#2#3 { \int_gincr:N \g_@@_image_int \int_const:cn { c_@@_image_ #1#2 _int } { \g_@@_image_int } \@@_literal:x { pdf:#3~ @image \int_use:c { c_@@_image_ #1#2 _int } \int_compare:nNnT \l_image_page_int > 1 { page ~ \int_use:N \l_image_page_int \c_space_tl } \tl_if_empty:NF \l_image_pagebox_tl { pagebox ~ \l_image_pagebox_tl \c_space_tl bbox ~ \dim_to_decimal_in_bp:n \l_image_llx_dim \c_space_tl \dim_to_decimal_in_bp:n \l_image_lly_dim \c_space_tl \dim_to_decimal_in_bp:n \l_image_urx_dim \c_space_tl \dim_to_decimal_in_bp:n \l_image_ury_dim \c_space_tl } (#1) \bool_lazy_or:nnT { \l_image_interpolate_bool } { ! \tl_if_empty_p:N \l_image_decodearray_tl } { << \tl_if_empty:NF \l_image_decode_tl { /Decode~[ \l_image_decodearray_tl ] } \bool_if:NT \l_image_interpolate_bool { /Interpolate~true> } >> } } } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macrocode} % % \end{macrocode} % % \subsection{\texttt{xdvipdfmx} driver} % % \begin{macrocode} %<*xdvipdfmx> % \end{macrocode} % % \subsubsection{Images} % % \begin{macro} % {\@@_image_getbb_jpg:n, \@@_image_getbb_pdf:n, \@@_image_getbb_png:n} % \begin{macro}{\@@_image_getbb_auxi:nN} % \begin{macro}{\@@_image_getbb_auxii:nnN, \@@_image_getbb_auxii:VnN} % \begin{macro}{\@@_image_getbb_auxiii:nNnn} % \begin{macro}{\@@_image_getbb_auxiv:nnNnn, \@@_image_getbb_auxiv:VnNnn} % \begin{macro}{\@@_image_getbb_auxv:nNnn, \@@_image_getbb_auxv:nNnn} % \begin{macro}[EXP]{\@@_image_getbb_pagebox:w} % For \texttt{xdvipdfmx}, 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 \@@_image_getbb_jpg:n #1 { \int_zero:N \l_image_page_int \tl_clear:N \l_image_pagebox_tl \@@_image_getbb_auxi:nN {#1} \tex_XeTeXpicfile:D } \cs_new_eq:NN \@@_image_getbb_png:n \@@_image_getbb_jpg:n \cs_new_protected:Npn \@@_image_getbb_pdf:n #1 { \tl_clear:N \l_image_decode_tl \bool_set_false:N \l_image_interpolate_bool \@@_image_getbb_auxi:nN {#1} \tex_XeTeXpdffile:D } \cs_new_protected:Npn \@@_image_getbb_auxi:nN #1#2 { \int_compare:nNnTF \l_image_page_int > 1 { \@@_image_getbb_auxii:VnN \l_image_page_int {#1} #2 } { \@@_image_getbb_auxiii:nNnn {#1} #2 } } \cs_new_protected:Npn \@@_image_getbb_auxii:nnN #1#2#3 { \@@_image_getbb_aux:nNnn {#2} #3 { :P #1 } { page #1 } } \cs_generate_variant:Nn \@@_image_getbb_auxii:nnN { V } \cs_new_protected:Npn \@@_image_getbb_auxiii:nNnn #1#2#3#4 { \tl_if_empty:NTF \l_image_pagebox_tl { \@@_image_getbb_auxiv:VnNnn \l_image_pagebox_tl } { \@@_image_getbb_auxv:nNnn } {#1} #2 {#3} {#4} } \cs_new_protected:Npn \@@_image_getbb_auxiv:nnNnn #1#2#3#4#5 { \use:x { \@@_image_getbb_auxv:nNnn {#2} #3 { : #1 #4 } { #5 ~ \@@_image_getbb_pagebox:w #1 } } } \cs_generate_variant:Nn \@@_image_getbb_auxiv:nnNnn { V } \cs_new_protected:Npn \@@_image_getbb_auxv:nNnn #1#2#3#4 { \image_bb_restore:nF {#1#3} { \@@_image_getbb_auxvi:nNnn {#1} #2 {#3} {#4} } } \cs_new_protected:Npn \@@_image_getbb_auxvi:nNnn #1#2#3#4 { \hbox_set:Nn \l_@@_tmp_box { #2 #1 ~ #4 } \dim_set:Nn \l_image_utx_dim { \box_wd:N \l_@@_tmp_box } \dim_set:Nn \l_image_ury_dim { \box_ht:N \l_@@_tmp_box } \image_bb_save:n {#1#3} } \cs_new:Npn \@@_image_getbb_pagebox:w #1 box {#1} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\@@_image_include_pdf:n} % For PDF images, 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 image measurement part, although we know at this % stage that there must be some valid setting for \cs{l_image_pagebox_tl}. % \begin{macrocode} \cs_new_protected:Npn \@@_image_include_pdf:n #1 { \tex_XeTeXpdffile:D "#1" ~ \int_compare:nNnT \l_image_page_int > 0 { page~ \int_use:N \l_image_page_int } \@@_image_getbb_auxiv:VnNnn \l_image_pagebox_tl } % \end{macrocode} % \end{macro} % % \begin{macrocode} % % \end{macrocode} % % \subsection{\texttt{dvisvgm} driver} % % \begin{macrocode} %<*dvisvgm> % \end{macrocode} % % \begin{macro}{\@@_image_getbb_png:n, \@@_image_getbb_jpg:n} % These can be included by extracting the bounding box data. % \begin{macrocode} \cs_new_eq:NN \@@_image_getbb_png:n \image_extract_bb:n \cs_new_eq:NN \@@_image_getbb_jpg:n \image_extract_bb:n % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_image_include_png:n, \@@_image_include_jpg:n} % \begin{macro}{\@@_image_include_bitmap_quote:w} % The driver here has built-in support for basic image inclusion (see % \texttt{dvisvgm.def} for a more complex approach, needed if clipping, % \emph{etc.}, is covered at the image driver level). The only 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 \@@_image_include_png:n #1 { \@@_literal:x { dvisvgm:img~ \dim_to_decimal:n { \l_image_ury_dim } ~ \dim_to_decimal:n { \l_image_ury_dim } ~ \@@_image_include_bitmap_quote:w #1 " #1 " \q_stop } } \cs_new_eq:NN \@@_image_include_jpg:n \@@_image_include_png:n \cs_new:Npn \@@_image_include_bitmap_quote:w #1 " #2 " #3 \q_stop { " #2 " } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macrocode} % % \end{macrocode} % % \begin{macrocode} % % \end{macrocode} % % \end{implementation} % % \PrintIndex