2

The following MWE (to be run at least twice) points out on its 2nd page (the number of which being invisible, BTW) that the height of (pdfpages) \includepdf files seems to not be taken into account.

Do you see what's going on?

% File to be included
\begin{filecontents}{\jobname-bis.tex}
\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{lmodern}
\usepackage{mwe}
\usepackage[a4paper]{geometry}
\usepackage{babel}
\begin{document}
\lipsum[1-6]
\end{document}
\end{filecontents}
%
% Main file
\documentclass{report}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{lmodern}
\usepackage[a4paper]{geometry}
\usepackage[draft]{pdfpages}
\usepackage{mwe}
\usepackage{babel}
%
\begin{document}
\chapter{Foo foo foo foo foo foo foo foo foo foo foo foo foo}
\begin{figure}[hb]
  \includegraphics[scale=0.425]{example-image-a4}
\end{figure}

\chapter{Foo foo foo foo foo foo foo foo foo foo foo foo foo}
\IfFileExists{\jobname-bis.pdf}{%
  \begin{figure}[hb]
    \includepdf[scale=0.425,frame]{\jobname-bis}
  \end{figure}
}{%
}
\end{document}

enter image description here

Edit

In the real use case, (pdfpages) \includepdf is necessary because multiple pages of the .pdf should be included in the same float.

Denis Bitouzé
  • 9,652
  • 4
  • 27
  • 85
  • 1
    Do you mind rephrasing the first paragraph, I'm having a hard time figuring out what you are referring to. Besides that, why are you including a \includepdf inside a float? To the float that thing will have no size as everything is added into the background of the page. – daleif Jun 18 '18 at 14:59
  • 1
    I'm getting the creeps seeing \includepdf used inside a float. Why don't you use \includegraphics? – Ulrike Fischer Jun 18 '18 at 15:03
  • @daleif Hmmm, sorry for being unclear but I can't see how to be clearer :) The reason of including \includepdf inside a float is, in the real use, we want to include multiple logical pages of an external document at once and this takes some vertical space (floats then welcome) plus a caption is needed. But you probably pointed out the trouble: "everything is added into the background of the page": strange and unfortunate for this use case. – Denis Bitouzé Jun 18 '18 at 15:09
  • 1
    If several pages from the same known PDF is needed why no use several \includegraphics calls plus the page=X option. – daleif Jun 18 '18 at 15:09
  • 1
    It is not stange, \includepdf is specifically made for including full page PDFs as full pages in the output (statement with modifications of course), it is not meant to be used inside floats. – daleif Jun 18 '18 at 15:10
  • @UlrikeFischer Because \includegraphics cannot include multiple pages at the same time. Okay, as said by daleif, we could use several \includegraphics calls plus the page=X option. That's less convenient than pages={X-Y},nup=AxB from pdfpages but, if there isn't any better solution, we will use this. – Denis Bitouzé Jun 18 '18 at 15:13
  • @daleif If I'm right, the pdfpages doesn't mention \includepdf is specifically made for including full page PDFs as full pages in the output nor it is not meant to be used inside floats. – Denis Bitouzé Jun 18 '18 at 15:18
  • You might want to mention this to the author of pdfpages, it seems to be a fair feature request to be able to use the nup inside a float, plus he should make better notice that in general includepdf should not be used inside floats (unmodified as it may lead to undesired results). The fact that the pdfpages manual does not mention floats has stumped many new users (I know well you're not a new user) – daleif Jun 18 '18 at 15:41
  • 1
    Author's attention drawn. – Denis Bitouzé Jun 18 '18 at 19:46
  • @DenisBitouzé from pdfpages manual, the description of the nup key: "Puts multiple logical pages onto each sheet of paper." Also the first and second paragraphs of the introduction don't explicitly mention that it is only meant to include on single pages in the output PDF, but to me this is implicitly clear inside the text. – Skillmon Jun 19 '18 at 23:11
  • @Skillmon Maybe because my English is a bit rusty, but not that clear to my mind. Explicit would be better than implicit here :) – Denis Bitouzé Jun 20 '18 at 06:10

1 Answers1

4

I don't know whether the following satisfies your needs. I don't remember the syntax and behaviour of pdfpages too well (I used it only once) and was too lazy to look it up.

The following defines the new macro \multpages. It takes an optional argument and a mandatory one. The mandatory one is the file from which the pages should be taken. The optional has the following options:

  • pages: a list of pages to include, it should be a comma-separated list which can contain ranges
  • nup: the arrangement of the images. It can either be a single number, which then sets the number of pages displayed next to each other horizontally, with a line break following those, or something matching the pattern AxB. In this case A images are displayed horizontally next to each other and B vertically. The images have the maximum width of hsize divided by the number of horizontally arranged images (padding respected), and the maximum height of vsize divided by the number of vertically arranged images (padding respected). However there is no box forced around the images, they might line or page break unexpectedly. The product of AxB doesn't have to be greater or equal to the number of included pages.
  • hpad: the padding in horizontal direction between the images. No padding is applied on the outermost sides.
  • vpad: the padding in vertical direction between the images. No padding is applied on the outermost sides.
  • hsize: the horizontally available space. If you don't specify this one the current \textwidth will be used.
  • vsize: the vertically available space. If you don't specify this one the current \textheight will be used. Has no effect if nup doesn't contain a vertical part.

Every unknown key is forwarded to the underlying \includegraphics commands.

Changes by edit:

  • hpad and vpad are now skips not dim, so they accept glue as argument.
  • pages with pattern -B are now ranges beginning by 1, A- are now ranges until the last page of the pdf to be included.

Changes by edit2:

  • hcor and vcor keys, allowing to make small adjustments to the calculation of height and width (introduced instead of the fixed value of .1pt, initially set to 0pt)
  • less vertical space after the image array, resulting in the same caption placement as under a single \includegraphics
  • consistent vertical space with and without \centering
  • removed duplicate code and more modularized by defining more functions and reusing functions instead of code blocks

Changes by edit3:

  • hboxed key: is a choice between true meaning a horizontal box is put around each row of figures, fixed meaning the row is put into a box with the width fixed to the hsize, and false meaning it is not boxed
  • vboxed key: also a choice between true, fixed, and false, with ruffly the same meaning but the vertical box is put around the whole array
  • \noindent is forced prior to the array, you can suppress this using the nonoindent key

Changes by edit4:

  • pages with undelimited range on the right side now works with LuaTeX and XeTeX, too.

Known issues:

  • the vertical height doesn't match the specified vsize, it tends to be bigger for more than one row and to be smaller for one row (as far as I have encountered so far). As a result vboxed=fixed results in the lowest row overlapping the \vbox downwards. As of now, I don't know what causes this.

Known issues (if hboxed=false)

  • for some combinations of options in a figure environment the width seems to be a bit too wide, the figures are line broken prematurely
  • line breaks can change depending on \centering being present or not

I won't use \centering if I don't use a vertical nup argument and no hsize, as in this case the result always takes the full text width and there is no need for centring the output, but it could lead to unexpected line breaks.

Perhaps it would be better to box up single rows in a \hbox, but I don't know whether I will invest the time to change the output loop to test this.

Code:

\documentclass[]{article}

\usepackage{showframe}% for debugging
\usepackage{graphicx}
\usepackage{xparse}

\ExplSyntaxOn
\clist_new:N \g_DenisBitouze_pages_clist
\clist_new:N \l_DenisBitouze_tmp_clist
\dim_new:N \l_DenisBitouze_hsize_dim
\dim_new:N \l_DenisBitouze_vsize_dim
\skip_new:N \l_DenisBitouze_tmp_skip
\int_new:N \l_DenisBitouze_hnup_int
\int_new:N \l_DenisBitouze_vnup_int
\int_new:N \l_DenisBitouze_tmp_int
\tl_new:N \l_DenisBitouze_tmp_tl
\tl_new:N \l_DenisBitouze_graphicx_opt_tl
\cs_new_protected:Nn \DenisBitouze_not_hboxed:n { #1 }
\keys_define:nn { DenisBitouze }%>>>
  {
    ,pages       .tl_set:N   = \l_DenisBitouze_pages_tl
    ,nup         .tl_set:N   = \l_DenisBitouze_nup_tl
    ,hpad        .skip_set:N = \l_DenisBitouze_hpad_skip
    ,hpad        .initial:n  = 1em
    ,vpad        .skip_set:N = \l_DenisBitouze_vpad_skip
    ,vpad        .initial:n  = 1em
    ,hsize       .dim_set:N  = \l_DenisBitouze_hsize_available_dim
    ,hsize       .default:n  = \textwidth
    ,vsize       .dim_set:N  = \l_DenisBitouze_vsize_available_dim
    ,vsize       .default:n  = \textheight
    ,hcorrection .dim_set:N  = \l_DenisBitouze_hcor_dim
    ,hcorrection .initial:n  = 0pt
    ,hcor        .meta:n     = { hcorrection = #1 }
    ,vcorrection .dim_set:N  = \l_DenisBitouze_vcor_dim
    ,vcorrection .initial:n  = 0pt
    ,vcor        .meta:n     = { vcorrection = #1 }
    ,vboxed      .choice:
    ,vboxed / true  .code:n  =
      \cs_set_protected:Nn \DenisBitouze_vbox:n { \vbox:n { ##1 } }
    ,vboxed / false .code:n  =
      \cs_set_protected:Nn \DenisBitouze_vbox:n { ##1 }
    ,vboxed / fixed .code:n  =
      \cs_set_protected:Nn \DenisBitouze_vbox:n
        { \vbox_to_ht:nn { \l_DenisBitouze_vsize_available_dim } { ##1 } }
    ,vboxed      .default:n  = true
    ,vboxed      .initial:n  = true
    ,hboxed      .choice:
    ,hboxed / true  .code:n  =
      \cs_set_eq:NN \DenisBitouze_hbox:n \hbox:n
    ,hboxed / false .code:n  =
      \cs_set_eq:NN \DenisBitouze_hbox:n \DenisBitouze_not_hboxed:n
    ,hboxed / fixed .code:n  =
      \cs_set_protected:Nn \DenisBitouze_hbox:n
        { \hbox_to_wd:nn { \l_DenisBitouze_hsize_available_dim } { ##1 } }
    ,hboxed      .default:n  = true
    ,hboxed      .initial:n  = true
    ,nonoindent  .bool_set:N = \l_DenisBitouze_no_noindent_bool
    ,nonoindent  .default:n  = true
    ,unknown     .code:n     =
      {
        \tl_put_right:NV \l_DenisBitouze_graphicx_opt_tl \l_keys_key_tl
        \tl_if_empty:nF { #1 }
          { \tl_put_right:Nn \l_DenisBitouze_graphicx_opt_tl { =#1 } }
        \tl_put_right:Nn \l_DenisBitouze_graphicx_opt_tl { , }
      }
  }%<<<
\cs_new_protected:Nn \DenisBitouze_store_pages_count:n%>>>
  {
    \group_end:
    \cs_set:Nn \DenisBitouze_pages_count: { #1 }
  }%<<<
\cs_generate_variant:Nn \DenisBitouze_store_pages_count:n { x }
\cs_new_protected:Nn \DenisBitouze_define_count_pages:nn%>>>
  {
    \cs_set_protected:Nn \DenisBitouze_count_pages:n
      {
        \group_begin:
        #1
        \DenisBitouze_store_pages_count:x { #2 }
      }
  }%<<<
\sys_if_engine_pdftex:T%>>>
  {
    \DenisBitouze_define_count_pages:nn
      { \pdfximage { #1 } }
      { \the\pdflastximagepages }
  }%<<<
\sys_if_engine_luatex:T%>>>
  {
    \DenisBitouze_define_count_pages:nn
      { \saveimageresource { #1 } }
      { \the\lastsavedimageresourcepages }
  }%<<<
\sys_if_engine_xetex:T%>>>
  {
    \DenisBitouze_define_count_pages:nn
      {}
      { \the\XeTeXpdfpagecount #1 \relax }
  }%<<<
\cs_new:Nn \DenisBitouze_recall_parse:nnn%>>>
  {
    \DenisBitouze_parse_range:w #1 - #2 \q_stop { #3 }
  }%<<<
\cs_generate_variant:Nn \DenisBitouze_recall_parse:nnn { nxn }
\cs_new_protected:Npn \DenisBitouze_parse_range:w #1-#2\q_stop#3%>>>
  {
    \tl_if_blank:nTF { #1 }
      {
        \DenisBitouze_parse_range:w 1-#2\q_stop { #3 }
      }
      {
        \tl_if_blank:nTF { #2 }
          {
            \tl_if_in:nnTF { #3 } { .pdf }
              { \DenisBitouze_count_pages:n { #3 } }
              { \DenisBitouze_count_pages:n { #3.pdf } }
            \DenisBitouze_recall_parse:nxn
              { #1 } { \DenisBitouze_pages_count: } { #3 }
          }
          {
            \int_step_inline:nnn { #1 } { #2 }
              {
                \clist_gput_right:Nn \g_DenisBitouze_pages_clist { ##1 }
              }
          }
      }
  }%<<<
\cs_new_protected:Nn \DenisBitouze_parse_pages:n%>>>
  {
    \clist_gclear:N \g_DenisBitouze_pages_clist
    \clist_set:NV \l_DenisBitouze_tmp_clist \l_DenisBitouze_pages_tl
    \clist_map_inline:Nn \l_DenisBitouze_tmp_clist
      {
        \tl_if_in:nnTF { ##1 } { - }
          {
            \DenisBitouze_parse_range:w ##1 \q_stop { #1 }
          }
          {
            \clist_gput_right:Nn \g_DenisBitouze_pages_clist { ##1 }
          }
      }
  }%<<<
\cs_new_protected:Npn \DenisBitouze_parse_nup_x:w #1x#2\q_stop%>>>
  {
    \int_set:Nn \l_DenisBitouze_hnup_int { #1 }
    \int_set:Nn \l_DenisBitouze_vnup_int { #2 }
  }%<<<
\cs_new_protected:Nn \DenisBitouze_parse_nup:n%>>>
  {
    \tl_if_empty:nTF { #1 }
      {
        \int_set:Nn \l_DenisBitouze_hnup_int { \c_one }
        \int_set:Nn \l_DenisBitouze_vnup_int { \c_zero }
      }
      {
        \tl_if_in:nnTF { #1 } { x }
          {
            \DenisBitouze_parse_nup_x:w #1 \q_stop
          }
          {
            \int_set:Nn \l_DenisBitouze_hnup_int { #1 }
            \int_set:Nn \l_DenisBitouze_vnup_int { \c_zero }
          }
      }
  }%<<<
\cs_generate_variant:Nn \DenisBitouze_parse_nup:n { V }
\cs_new_protected:Nn \DenisBitouze_output_single:nnn%>>>
  {
    \includegraphics [ #1, #2 ] { #3 }
  }%<<<
\cs_generate_variant:Nn \DenisBitouze_output_single:nnn { nVn }
\cs_new_protected:Nn \DenisBitouze_output_single_no_vnup:nn%>>>
  {
    \DenisBitouze_output_single:nVn
      { width=\l_DenisBitouze_hsize_dim, page=#1 }
      \l_DenisBitouze_graphicx_opt_tl
      { #2 }
  }%<<<
\cs_new_protected:Nn \DenisBitouze_output_single_with_vnup:nn%>>>
  {
    \DenisBitouze_output_single:nVn
      {
        width=\l_DenisBitouze_hsize_dim,
        height=\l_DenisBitouze_vsize_dim,
        keepaspectratio=true,
        page = #1
      }
      \l_DenisBitouze_graphicx_opt_tl
      { #2 }
  }%<<<
\cs_generate_variant:Nn \DenisBitouze_output_single_no_vnup:nn { V }
\cs_generate_variant:Nn \DenisBitouze_output_single_with_vnup:nn { V }
\cs_new_protected:Nn \DenisBitouze_calc_hsize:%>>>
  {
    \dim_set:Nn \l_DenisBitouze_hsize_dim
      {
        (
          \l_DenisBitouze_hsize_available_dim
          + \l_DenisBitouze_hpad_skip
        )
        / \l_DenisBitouze_hnup_int
        - \l_DenisBitouze_hpad_skip
        % rounding could lead to too much horizontal space taken without
        % this in a figure environment
        - \l_DenisBitouze_hcor_dim
      }
  }%<<<
\cs_new_protected:Nn \DenisBitouze_calc_vsize:%>>>
  {
    \dim_set:Nn \l_DenisBitouze_vsize_dim
      {
        (
          \l_DenisBitouze_vsize_available_dim
          + \l_DenisBitouze_vpad_skip
        )
        / \l_DenisBitouze_vnup_int
        - \l_DenisBitouze_vpad_skip
        - \l_DenisBitouze_vcor_dim
      }
  }%<<<
\cs_new_protected:Nn \DenisBitouze_output_line:Nn%>>>
  {
    \int_step_inline:nn { \l_DenisBitouze_hnup_int }
      {
        \clist_if_empty:NF \g_DenisBitouze_pages_clist
          {
            \clist_gpop:NN \g_DenisBitouze_pages_clist \l_DenisBitouze_tmp_tl
            #1 \l_DenisBitouze_tmp_tl { #2 }
            \skip_horizontal:N \l_DenisBitouze_hpad_skip
          }
      }
    \skip_horizontal:n { -\l_DenisBitouze_hpad_skip }
  }%<<<
\cs_new_protected:Nn \DenisBitouze_output_loop:Nn%>>>
  {
    \bool_do_while:nn { !\clist_if_empty_p:N \g_DenisBitouze_pages_clist }
      {
        \bool_if:NF \l_DenisBitouze_no_noindent_bool { \noindent }
        \mbox{}
        \DenisBitouze_hbox:n { \DenisBitouze_output_line:Nn #1 { #2 } }
        \mbox{}
        \skip_vertical:N \l_DenisBitouze_vpad_skip
      }
  }%<<<
\cs_new_protected:Nn \DenisBitouze_after_loop:%>>>
  {
    \skip_vertical:n { - \l_DenisBitouze_vpad_skip }
  }%<<<
\cs_new_protected:Nn \DenisBitouze_output_no_vnup:n%>>>
  {
    \DenisBitouze_output_loop:Nn
      \DenisBitouze_output_single_no_vnup:Vn { #1 }
  }%<<<
\cs_new_protected:Nn \DenisBitouze_output_with_vnup:n%>>>
  {
    \DenisBitouze_calc_vsize:
    \DenisBitouze_output_loop:Nn
      \DenisBitouze_output_single_with_vnup:Vn { #1 }
  }%<<<
\NewDocumentCommand \multpages { O{} m }%>>>
  {
    \group_begin:
    \keys_set:nn { DenisBitouze } { hsize, vsize, #1 }
    \DenisBitouze_parse_pages:n { #2 }
    \clist_if_empty:NT \g_DenisBitouze_pages_clist
      {
        \clist_gset:Nn \g_DenisBitouze_pages_clist { \c_one }
      }
    \DenisBitouze_parse_nup:V \l_DenisBitouze_nup_tl
    \DenisBitouze_calc_hsize:
    \DenisBitouze_vbox:n
      {
        \int_compare:nNnTF { \l_DenisBitouze_vnup_int } = { \c_zero }
          { \DenisBitouze_output_no_vnup:n { #2 } }
          { \DenisBitouze_output_with_vnup:n  { #2 } }
        \DenisBitouze_after_loop:
      }
    \group_end:
  }%<<<
\ExplSyntaxOff

\begin{document}
\begin{figure}[t]% >>>
  \centering
  \multpages[pages=1-5,nup=3]{example-image-duck.pdf}
  \caption
    {%
      A happy duck family%
      \label{fig:ducks}%
    }%
\end{figure}% <<<
\end{document}

enter image description here

enter image description here

Skillmon
  • 60,462
  • You can get the total number of pages with \pdflastximagepages see https://tex.stackexchange.com/a/8324/2388 – Ulrike Fischer Jun 18 '18 at 17:59
  • @UlrikeFischer thank you very much! I had that one anywhere back in my head, but didn't need it for a long time now:) Is it even necessary to get that one. Currently I'm defaulting to page 1, would it be better to default to all pages? – Skillmon Jun 18 '18 at 18:01
  • includepdf defaults to one too, pages=- is the syntax for all pages. – Ulrike Fischer Jun 18 '18 at 18:03
  • Wow, brilliant! Could be a nice package :) – Denis Bitouzé Jun 18 '18 at 19:41
  • @DenisBitouzé it is way too fragile to be a package. For that I'd have to box up some stuff and perhaps introduce a key or two to control the boxing (each row in a \hbox or not, the full array in a \vbox or not). But I don't know whether this really leads to more stable behaviour or would introduce other unwanted effects. – Skillmon Jun 19 '18 at 09:08
  • 1
    @DenisBitouzé I've added the possibility to box the stuff up (horizontally and vertically). It could use some testing, debugging, restructuring, but it should work. I'm not sure whether it's completely stable. I won't consider it package level code, but perhaps use it myself... – Skillmon Jun 19 '18 at 16:08