[Tex/LaTex] \pdfbookmark to page number and location with \includepdf

bookmarkshyperrefpdfpagespositioning

I would like to use a \pdfbookmark like command to reference a page within a PDF document (included with the \includepdf command) and further to bring the user to a specific location (say 2.34 inches from the top) on that page.

Is there a command like \mypdfbookmark so that when you PDFLaTeX a document with the lines

\mypdfbookmark[2]{page 3 location 2.3in}{Test}
\includepdf[pages={-},link,linkname=Test,linkfit=FitH]{Test.pdf}

When you click on the pdfbookmark in Adode it takes you to page 3 at location 2.3 inches from the top of the document Test?

I know that I could import the pages of the pdf individually, but this doesn't solve the problem of displaying a specific location on that page. I would love to be able to reference the page and the location in one command, but could work with individual pages if I had too.

Best Answer

I know egreg will shoot at me ;-)

I played a little bit and you can use the following package placebookmarks. The package defines only one command with some options. The command is \mypdfbookmark with the following syntax:

\mypdfbookmark[<options>]{bookmarkname}

The options are:

  • level -- sets the level of \pdfbookmark; default=1
  • page -- sets the page which will get a bookmark; default=0
  • x-location -- sets the x coordinate; default=0.5\paperwidth
  • y-location -- sets the x coordinate; default=0.5\paperheight
  • draw-circle -- draw a red filled circle to see the current position

I used the following example to text the package:

\documentclass{scrreprt}
\usepackage{kantlipsum}
\usepackage{pdfpages}
\usepackage{placebookmarks}
\usepackage{hyperref}

\begin{document}
\kant

\mypdfbookmark[page=2,draw-circle=true]{Test}
\includepdf[frame=true,pages={-}]{Example-file}
\end{document}

Here the package:

\RequirePackage{expl3}
\ProvidesExplPackage {placebookmarks} {2012/05/11} {0.1}
  {Placing bookmarks on several pages}



\msg_new:nnnn { placebookmarks } { package-missing }
  { Package~'#1'~is~missing. }
  { The~'#1'~package~is~needed~by~placebookmarks. }
\cs_new_protected:Npn \placebookmarks_load_check:n #1 {
  \group_begin:
    \@ifpackageloaded {#1}
      { }
      { 
       \msg_error:nnx { placebookmarks } { package-missing } {#1} 
       \tex_endinput:D
      }
  \group_end:
}
\AtBeginDocument {
  \clist_map_function:nN { hyperref , pdfpages  }
    \placebookmarks_load_check:n
}

\RequirePackage{l3keys2e , xparse , picture }
%Define options
\keys_define:nn { placebookmarks } {
   level       .int_set:N   = \l_placebookmarks_store_level_int,
   page        .int_set:N   = \l_placebookmarks_store_page_int,
   x-location  .dim_set:N   = \l_placebookmarks_xlocation_dim,
   y-location  .dim_set:N   = \l_placebookmarks_ylocation_dim,
   draw-circle .bool_set:N  = \l_placebookmarks_drawcircle_bool,
}
\keys_set:nn { placebookmarks } { level = 1 ,page = 0 ,  draw-circle = true ,
                                  x-location= .5\paperwidth , y-location= 0.5\paperheight }




\tl_new:N \l_placebookmarks_store_bookmarktitle_tl

\cs_new_protected:Npn \placebookmarks_position_aux_i: { }


\NewDocumentCommand \mypdfbookmark {  O{} m }
{
 \keys_set:nn { placebookmarks } { #1 }
 \tl_set:Nn \l_placebookmarks_store_bookmarktitle_tl { #2 }
 \cs_set_protected:Npn \placebookmarks_position_aux_i:
  {
   \int_compare:nNnT { \AM@page } = { \l_placebookmarks_store_page_int }
   { 
    \bool_if:NT \l_placebookmarks_drawcircle_bool
        {
         \put ( \l_placebookmarks_xlocation_dim ,
                \l_placebookmarks_ylocation_dim ) 
              {\color{red}\circle*{10}}
        }
    \put ( \l_placebookmarks_xlocation_dim ,
           \l_placebookmarks_ylocation_dim )
         {
          \pdfbookmark[\int_use:N \l_placebookmarks_store_level_int]
                      {\tl_use:N \l_placebookmarks_store_bookmarktitle_tl}
                      {placebookmarks-\thepage}
         }
    \cs_gset_eq:NN \placebookmarks_position_aux_i: \tex_relax:D
   }
  }
}


\newcommand{\placebookmarks@output}[1]{%
  \c@totalnumber=0
  \if@twocolumn\let\AM@twocolumn\relax \onecolumn \fi
  \AM@disable@includegraphics
  \@ifundefined{AM@xnup}
    {\def\AM@xnup{\@ne}\def\AM@ynup{\@ne}%
     \def\AM@xnupminusi{\z@}\def\AM@ynupminusi{\z@}}{}%
  \@ifundefined{AM@deltax}
    {\def\AM@deltax{-\fboxrule}\def\AM@deltay{-\fboxrule}}{}%
  \@ifundefined{AM@xoffset}
    {\def\AM@xoffset{\z@}\def\AM@yoffset{\z@}}{}%
  \def\AM@xpos{\z@}\def\AM@ypos{\z@}%
  \ifAM@pkg@draft \setkeys{Gin}{draft=true}%
  \else \setkeys{Gin}{draft=false}%
  \fi
  \ifthenelse{\boolean{AM@landscape}}
    {\def\AM@lscape@rot{90}%
     \@ifundefined{AM@shortnupsyntax}{}
       {\let\AM@temp\AM@xnup
        \let\AM@xnup\AM@ynup
        \let\AM@ynup\AM@temp}%
    }{}%
  \AM@setphantom
  \ifthenelse{\boolean{AM@openright}}
         {\AM@openright}{}%
  \ifx\AM@signature\@empty\AM@filluppagelist
  \else\AM@prepare@signature\AM@signaturetrue\AM@turnfalse\fi
  \@tempcnta=\AM@xnup\relax \advance\@tempcnta\m@ne
  \edef\AM@xnupminusi{\the\@tempcnta}%
  \@tempcnta=\AM@ynup\relax \advance\@tempcnta\m@ne
  \edef\AM@ynupminusi{\the\@tempcnta}%
  \ifthenelse{\boolean{AM@column}%
              \and\not\boolean{AM@columnstrict}}
         {\AM@getlastn{\AM@doclist}{\AM@nup}%
          \edef\AM@lastndocs{\AM@lastnitems}%
          \AM@getlastn{\AM@pagelist}{\AM@nup}%
          \edef\AM@lastnpages{\AM@lastnitems}%
          \AM@resort
          \AM@count{\AM@pagelist}%
          \expandafter\ifx\expandafter\\\AM@pagelist\\%
            \edef\AM@pagelist{\AM@resortedpagelist}%
            \edef\AM@doclist{\AM@resorteddoclist}%
          \else
            \edef\AM@pagelist{\AM@pagelist,\AM@resortedpagelist}%
            \edef\AM@doclist{\AM@doclist,\AM@resorteddoclist}%
          \fi}{}%
  \ifthenelse{\boolean{AM@frame}}
         {\global\let\AM@fbox\fbox}
         {\global\let\AM@fbox\relax
          \setlength{\fboxrule}{\z@}}%
  \ifthenelse{\boolean{AM@reflect}}
         {\global\let\AM@reflectbox\reflectbox}
         {\global\let\AM@reflectbox\relax}%
  \setbox\AM@pagebox\null
  \ifthenelse{\boolean{AM@column}}
         {\def\AM@xnupi{\@ne}%
          \def\AM@ynupi{\z@}}
         {\def\AM@xnupi{\z@}%
          \def\AM@ynupi{\@ne}}%
  \AM@firstpagetrue
  \setlength{\fboxsep}{\z@}%
  \@ifundefined{AM@pagetemplate}
      {\AM@readfirst{\AM@pagelist}%
       \edef\AM@page{\the\toks@}}
      {\edef\AM@page{\AM@pagetemplate}}%
  \AM@readfirst{\AM@doclist}%
  \edef\AM@docname{\the\toks@}%
  \newpage
  \AM@isphantom
  \ifAM@noautoscale
    \def\AM@globalscale{1}%
  \else
    \AM@split@options{Gin@noscale}{#1}%
    \let\AM@filelist@save\@filelist
    \ifAM@DVIoutput
      \setbox\@tempboxa=\hbox{\rule{597pt}{845pt}}%
    \else
      \ifAM@templatesize
        \setbox\@tempboxa=\hbox{%
          \rotatebox{\AM@lscape@rot}{\copy\AM@templatesizebox}}%
      \else
        \setbox\@tempboxa=\hbox{%
          \expandafter\includegraphics\expandafter[\the\@temptokena,
            page=\AM@page, angle=\AM@lscape@rot]{\AM@docname}}%
      \fi
    \fi
    \ifthenelse{\boolean{AM@fitpaper}}
      {\setlength{\AM@pagewidth}{\wd\@tempboxa}%
       \setlength{\AM@pageheight}{\ht\@tempboxa + \dp\@tempboxa}%
       \setlength{\paperwidth}{\wd\@tempboxa}%
       \setlength{\paperheight}{\ht\@tempboxa + \dp\@tempboxa}%
       \AM@fitpaper@special
       \AM@setpagedimen
       \@ifundefined{stockwidth}{}{%
         \setlength{\stockwidth}{\AM@pagewidth}%
         \setlength{\stockheight}{\AM@pageheight}%
         \setlength{\trimtop}{0pt}%
         \setlength{\trimedge}{0pt}}%
      }{}%
    \ifdim\AM@pagewidth=\z@
      \AM@pagewidth=210mm
      \PackageWarningNoLine{pdfpages}{%
        Erroneous page width of 0.0pt is corrected}%
    \fi
    \ifdim\AM@pageheight=\z@
      \AM@pageheight=297mm
      \PackageWarningNoLine{pdfpages}{%
        Erroneous page height of 0.0pt is corrected}%
    \fi
    \ifdim\paperwidth=\z@
      \let\paperwidth\AM@pagewidth
    \fi
    \ifdim\paperheight=\z@
      \let\paperheight\AM@pageheight
    \fi
    \def\AM@xscale{%
      (\paperwidth - \tw@\fboxrule*\AM@xnup
       - \AM@deltax * \AM@xnupminusi) /
      (\AM@xnup * \real{\strip@pt\wd\@tempboxa})
    }%
    \setlength{\@tempdima}{\AM@xscale}%
    \edef\AM@xscale{\strip@pt\@tempdima}%
    \setlength{\@tempdimb}{\ht\@tempboxa + \dp\@tempboxa}%
    \def\AM@yscale{
      (\paperheight - \tw@\fboxrule*\AM@ynup
       - \AM@deltay *\AM@ynupminusi) /
      (\AM@ynup * \real{\strip@pt\@tempdimb})
    }%
    \setlength{\@tempdima}{\AM@yscale}%
    \edef\AM@yscale{\strip@pt\@tempdima}%
    \@tempdima=\AM@xscale\p@
    \@tempdimb=\AM@yscale\p@
    \ifdim\@tempdima<\@tempdimb
      \let\AM@globalscale\AM@xscale
    \else
      \let\AM@globalscale\AM@yscale
    \fi
  \fi
  \let\AM@filelist@save\@filelist
  \AM@split@options{Gin}{#1}%
  \ifAM@templatesize
    \setbox\@tempboxa=\hbox{%
      \scalebox{\AM@scale@factor}{\copy\AM@templatesizebox}}%
    \setbox\@tempboxa=\hbox{%
      \scalebox{\AM@globalscale}{\copy\@tempboxa}}%
    \setbox\@tempboxa=\hbox{%
      \rotatebox{\AM@lscape@rot}{\copy\@tempboxa}}%
  \else
    \setbox\@tempboxa=\hbox{%
      \expandafter\includegraphics\expandafter[\the\@temptokena,
                       page=\AM@page, scale=\AM@globalscale,
                       angle=\AM@lscape@rot]{\AM@docname}}%
  \fi
  \let\@filelist\AM@filelist@save
  \edef\AM@templatewidth{\the\wd\@tempboxa}%
  \setlength{\@tempdima}{\ht\@tempboxa + \dp\@tempboxa}%
  \edef\AM@templateheight{\the\@tempdima}%
  \setlength{\@tempdimb}{\ht\@tempboxa + \dp\@tempboxa}%
  \def\AM@xmargin{%
    (\paperwidth - (\wd\@tempboxa+\tw@\fboxrule)*\AM@xnup
     - \AM@deltax * \AM@xnupminusi) * \real{.5}%
  }%
  \def\AM@ymargin{%
    (\paperheight - (\@tempdimb+\tw@\fboxrule)*\AM@ynup
     - \AM@deltay * \AM@ynupminusi) * \real{.5}%
  }%
  \setlength{\@tempdima}{\AM@xmargin}%
  \edef\AM@xmargin{\the\@tempdima}%
  \setlength{\@tempdima}{\AM@ymargin}%
  \edef\AM@ymargin{\the\@tempdima}%
  \ifthenelse{\boolean{AM@landscape}}
       {\edef\AM@temp{\AM@xnup}%
        \edef\AM@xnup{\AM@ynup}%
        \edef\AM@ynup{\AM@temp}}
       {}%
  \ifAM@signature
    \ifAM@landscape\AM@sigrotatefalse\else\AM@sigrotatetrue\fi
  \fi
  \setboolean{AM@endoflist}{false}%
  \whiledo{\not\boolean{AM@endoflist}}{%
    \AM@getfirst{\AM@pagelist}%
      \edef\AM@page{\the\toks@}%
      \AM@isphantom
      \@tempcnta=\AM@page\relax
      \edef\AM@linktodoc@page{\the\@tempcnta}%
      \advance\@tempcnta\m@ne
      \edef\AM@linktodoc@page@m@ne{\the\@tempcnta}%
    \AM@getfirst{\AM@doclist}%
      \edef\AM@docname{\the\toks@}%
      \ifAM@linkfilename
      \else
        \let\AM@linkfilename\AM@docname
      \fi
      \ifx\@empty\AM@linkname@option \edef\AM@linkname{\the\toks@}%
      \else \edef\AM@linkname{\AM@linkname@option} \fi
    \ifthenelse{\boolean{AM@column}}
      {\@tempcnta=\AM@ynupi\relax
       \@tempcntb=\AM@ynup\relax
       \advance\@tempcnta\@ne
       \ifnum\@tempcnta>\@tempcntb
         \@tempcnta=\@ne
         \@tempcntb=\AM@xnupi\relax
         \advance\@tempcntb\@ne
         \edef\AM@xnupi{\the\@tempcntb}%
       \fi
       \edef\AM@ynupi{\the\@tempcnta}%
       \@tempcnta=\AM@xnupi\relax
       \@tempcntb=\AM@xnup\relax
       \ifnum\@tempcnta>\@tempcntb
         \def\AM@xnupi{\@ne}%
       \fi
      }
      {\@tempcnta=\AM@xnupi\relax
       \@tempcntb=\AM@xnup\relax
       \advance\@tempcnta\@ne
       \ifnum\@tempcnta>\@tempcntb
         \@tempcnta=\@ne
         \@tempcntb=\AM@ynupi\relax
         \advance\@tempcntb\@ne
         \edef\AM@ynupi{\the\@tempcntb}%
       \fi
       \edef\AM@xnupi{\the\@tempcnta}%
       \@tempcnta=\AM@ynupi\relax
       \@tempcntb=\AM@ynup\relax
       \ifnum\@tempcnta>\@tempcntb
         \def\AM@ynupi{\@ne}%
       \fi
      }%
    \setbox\@tempboxa=\hbox{%
      \expandafter\includegraphics\expandafter[\the\@temptokena,
                       page=\AM@page, scale=\AM@globalscale,
                       angle=\AM@lscape@rot]{\AM@docname}}%
    \edef\AM@localwd{\the\wd\@tempboxa}%
    \setlength{\@tempdima}{\ht\@tempboxa + \dp\@tempboxa}%
    \edef\AM@localht{\the\@tempdima}%
    \AM@rescalefalse
    \ifdim\AM@localwd=\AM@templatewidth \else \AM@rescaletrue \fi
    \ifdim\AM@localht=\AM@templateheight \else \AM@rescaletrue \fi
    \def\AM@localxoff{\z@}%
    \def\AM@localyoff{\z@}%
    \def\AM@rotateoversize{0}%
    \def\AM@localscale{\p@}%
    \ifAM@rescale
      \ifthenelse{\lengthtest{\AM@localwd<\AM@templatewidth} \and
                  \lengthtest{\AM@localht<\AM@templateheight}}{%
        \setlength{\@tempdima}{(\AM@templatewidth - \AM@localwd)
             * \real{.5}}%
        \edef\AM@localxoff{\the\@tempdima}%
        \setlength{\@tempdima}{(\AM@templateheight - \AM@localht)
             * \real{.5}}%
        \edef\AM@localyoff{\the\@tempdima}%
      }{%
        \ifAM@rotateoversize
          \def\AM@rotateoversize{90}%
          \let\AM@filelist@save\@filelist
          \setbox\@tempboxa=\hbox{%
            \expandafter\includegraphics\expandafter
                [\the\@temptokena, page=\AM@page,
                 scale=\AM@globalscale,
                 angle=\AM@lscape@rot, angle=90]{\AM@docname}}%
          \let\@filelist\AM@filelist@save
          \edef\AM@localwd{\the\wd\@tempboxa}%
          \setlength{\@tempdima}{\ht\@tempboxa + \dp\@tempboxa}%
          \edef\AM@localht{\the\@tempdima}%
        \fi
        \setlength{\@tempdima}
                  {\p@ * \ratio{\AM@templatewidth}{\AM@localwd}}%
        \edef\AM@localxscale{\the\@tempdima}%
        \setlength{\@tempdima}
                  {\p@ * \ratio{\AM@templateheight}{\AM@localht}}%
        \edef\AM@localyscale{\the\@tempdima}%
        \ifdim\AM@localxscale<\AM@localyscale
          \let\AM@localscale\AM@localxscale
          \setlength{\@tempdima}{\AM@localxscale}%
          \setlength{\@tempdima}{(\AM@templateheight -
            \AM@localht * \real{\strip@pt\@tempdima}) * \real{.5}}%
          \edef\AM@localyoff{\the\@tempdima}%
        \else
          \let\AM@localscale\AM@localyscale
          \setlength{\@tempdima}{\AM@localyscale}%
          \setlength{\@tempdima}{(\AM@templatewidth -
             \AM@localwd * \real{\strip@pt\@tempdima}) * \real{.5}}%
          \edef\AM@localxoff{\the\@tempdima}%
        \fi
      }%
    \fi
    \setlength{\@tempdima}{\AM@localscale}%
    \edef\AM@localscale{\strip@pt\@tempdima}%
    \ifAM@noautoscale
      \def\AM@localxoff{\z@}%
      \def\AM@localyoff{\z@}%
      \def\AM@localscale{1}%
    \fi
    \let\AM@filelist@save\@filelist
    \AM@split@options{Gin}{#1}%
    \setbox\@tempboxa=\hbox{%
      \expandafter\includegraphics\expandafter[\the\@temptokena,
                       page=\AM@page, scale=\AM@globalscale,
                       angle=\AM@lscape@rot]{\AM@docname}}%
    \let\@filelist\AM@filelist@save
    \setlength{\@tempdimc}{\ht\@tempboxa + \dp\@tempboxa}%
    \def\AM@add{+}%
    \if@twoside\ifodd\c@page\else\def\AM@add{-}\fi\fi
    \setlength{\@tempdimb}{\ht\@tempboxa + \dp\@tempboxa}%
    \ifthenelse{\boolean{AM@landscape}}
      {\def\AM@xpos{%
         \AM@xmargin \AM@add\AM@xoffset + \AM@localxoff +
         (\AM@templatewidth + \AM@deltax + \tw@\fboxrule) *
         (\AM@ynupi - 1)
       }%
       \def\AM@ypos{%
         \AM@ymargin + \AM@yoffset + \AM@localyoff +
         (\AM@templateheight + \AM@deltay + \tw@\fboxrule) *
         (\AM@xnupi - 1)
       }%
      }
      {\def\AM@xpos{%
         \AM@xmargin \AM@add\AM@xoffset + \AM@localxoff +
         (\AM@templatewidth + \AM@deltax + \tw@\fboxrule) *
         (\AM@xnupi - 1)
       }%
       \def\AM@ypos{%
         \AM@ymargin + \AM@yoffset + \AM@localyoff +
         (\AM@templateheight + \AM@deltay + \tw@\fboxrule) *
         (\AM@ynup-\AM@ynupi)
       }%
      }%
    \setlength{\@tempdima}{\AM@xpos}%
    \edef\AM@xpos{\strip@pt\@tempdima}%
    \setlength{\@tempdima}{\AM@ypos}%
    \edef\AM@ypos{\strip@pt\@tempdima}%
    \setlength{\fboxsep}{\z@}%
     \AM@region@calc
    \ifAM@phantompage
      \def\AM@shippage{}%
    \else
      \AM@split@options{Gin}{#1}%
      \edef\AM@shippage{%
        \noexpand\put(\AM@xpos,\AM@ypos){%
        \noexpand\raisebox{\dp\@tempboxa}{%
        \noexpand\raise \ht\@tempboxa \hbox{\AM@hyper@begin@i}%
        \AM@hyper@begin@ii\noexpand\AM@fbox{%
          \noexpand\AM@ARBug@hook
          \noexpand\AM@reflectbox{%
          \noexpand\includegraphics[\the\@temptokena,
                    page=\AM@page, scale=\AM@globalscale,
                    scale=\AM@localscale,
                    \ifAM@sigrotate angle=180,\fi
                    \ifAM@doublepagestwist\ifAM@doublepagestmp
                      angle=180,\fi\fi
                    angle=\AM@rotateoversize,
                    angle=\AM@lscape@rot]{\AM@docname}}}%
        \AM@hyper@end}}%
      }%
    \fi
    \ifAM@doublepagestwist
      \ifAM@doublepagestmpi
        \ifAM@doublepagestwistx\AM@doublepagestmpifalse\fi
        \ifAM@doublepagestmp\AM@doublepagestmpfalse
        \else\AM@doublepagestmptrue\fi
      \else\AM@doublepagestmpitrue\fi
    \fi
    \AM@AddToShipoutPicture{\setlength{\unitlength}{\p@}%
      \global\let\AM@filelist@save\@filelist}%
    \ifAM@reflectall
      \begin{lrbox}{\AM@pagebox}
        \global\let\AM@filelist@save\@filelist
        \usebox{\AM@pagebox}\AM@shippage
        \global\let\@filelist\AM@filelist@save
      \end{lrbox}
    \else
      \expandafter\AM@AddToShipoutPicture\expandafter{%
        \AM@shippage
        \placebookmarks_position_aux_i: %%%%ADDED
        \global\let\@filelist\AM@filelist@save
      }%
    \fi
    \AM@toclof{\AM@page}%
    \ifnum\AM@xnupi=\AM@xnup\relax
      \ifnum\AM@ynupi=\AM@ynup\relax
        \begingroup\AM@pagecommand\endgroup
        \hskip\z@
        \ifthenelse{\boolean{AM@turn}}
          {\ifthenelse{\boolean{AM@landscape}}
             {\AM@setlscape}{}}
          {}%
        \AM@AddToShipoutPicture{%
          \begingroup\AM@picturecommand\endgroup}%
        \ifAM@firstpage
          \AM@AddToShipoutPicture{%
            \begingroup\AM@picturecommandstar\endgroup}%
          \AM@firstpagefalse
        \fi
        \ifAM@reflectall
          \AM@AddToShipoutPicture{%
            \hskip\AM@pagewidth
            \reflectbox{\usebox\AM@pagebox}%
            \global\let\@filelist\AM@filelist@save
          }%
          \AM@ClearShipoutPicture
        \fi
        \newpage
        \ifAM@reflectall \setbox\AM@pagebox\null \fi
        \ifAM@pdflscape\PLS@Rotate{0}\fi
        \AM@ClearShipoutPicture
        \ifAM@signature
          \ifAM@sigrotate\AM@sigrotatefalse\else\AM@sigrotatetrue\fi
          \@tempdima=\AM@xoffset\relax
          \multiply\@tempdima\m@ne
          \edef\AM@xoffset{\the\@tempdima}
        \fi
      \fi
    \fi
  }% whiledo
  \ifx\AM@twocolumn\relax\twocolumn\fi
}% AM@output


\AtBeginDocument{
 \let\AM@output\placebookmarks@output
}
\tex_endinput:D
Related Question