From e0c6872cf40896c7be36b11dcc744620f10adf1d Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Mon, 2 Sep 2019 13:46:59 +0900 Subject: Initial commit --- macros/latex/contrib/pdfoverlay/pdfoverlay.dtx | 647 +++++++++++++++++++++++++ 1 file changed, 647 insertions(+) create mode 100644 macros/latex/contrib/pdfoverlay/pdfoverlay.dtx (limited to 'macros/latex/contrib/pdfoverlay/pdfoverlay.dtx') diff --git a/macros/latex/contrib/pdfoverlay/pdfoverlay.dtx b/macros/latex/contrib/pdfoverlay/pdfoverlay.dtx new file mode 100644 index 0000000000..15425f7ed5 --- /dev/null +++ b/macros/latex/contrib/pdfoverlay/pdfoverlay.dtx @@ -0,0 +1,647 @@ +% \iffalse meta-comment +% +% Copyright (c) 2018 David Purton +% +% This work may be distributed and/or modified under the conditions of +% the LaTeX Project Public License, either version 1.3c of this license +% or (at your option) any later version. The latest version of this +% license is in +% http://www.latex-project.org/lppl.txt +% and version 1.3c or later is part of all distributions of LaTeX +% version 2005/12/01 or later. +% +%<*driver> +\documentclass[a4paper]{l3doc} +\begin{document} +\DocInput{\jobname.dtx} +\end{document} +% +% \fi +% +% \changes{v1.0}{2018/05/08}{First public release} +% +% \title{The \pkg{pdfoverlay} package} +% \author{David Purton\thanks{Email: \url{dcpurton@marshwiggle.net}}} +% \date{2018/05/08 v1.0} +% +% \maketitle +% +% \begin{abstract} +% This \pkg{pdfoverlay} package provides a simple interface to overlay text +% on to an existing PDF. The text to be overlayed is typeset and positioned +% normally as you would any other \LaTeX{} document. Some or all of the pages +% of the PDF can be included and not all pages of the PDF need have overlayed +% text. It's also possible to include text between pages of the PDF. +% \end{abstract} +% +% \tableofcontents +% +% \begin{documentation} +% +% \section{Introduction} +% +% It's often desirable to take an exisiting PDF and easily add annotations or +% text overlaying the PDF. This might arise if you wish to add comments to a +% PDF, fill in a PDF form, or add text to a PDF where space has been left for +% notes. +% +% This package provides a simple interface to do this without having to resort +% to inserting one page at a time. Some or all of the pages of the PDF can be +% included and not all pages of the PDF need have overlayed text. It's also +% possible to include text between pages of the PDF. +% +% Another advantage of this package is that the overlayed text can be set as +% normal flowing from one page to another or with manual page breaks if you +% wish. It's also possible to use any standard method to position text at +% arbitrary places on a given page. +% +% \section{Acknowlegements} +% +% This package is particularly indebted to the \pkg{pdfpages} package to count +% the number of pages in the PDF file, the \pkg{eso-pic} package to output +% pages from the PDF file in the document background, and the \pkg{everypage} +% package to ensure that PDF pages are inserted at every page in the document. +% +% \section{Bug Reports and Feature Requests} +% +% Bug reports and feature requests can be made at the \pkg{pdfoverlay} package +% GitHub respoitory. See \url{https://github.com/dcpurton/pdfoverlay}. +% +% \section{Documentation} +% +% \subsection{Basic Usage} +% +% At it's simplest, the only thing required is to specify the PDF to overlay +% with text and then begin typing your document. The pages of the PDF will be +% inserted as you go automatically. If your text takes up more pages than the +% PDF then any remaining text is inserted on blank pages. +% \begin{verbatim} +% \documentclass{article} +% \usepackage{pdfoverlay} +% \pdfoverlaySetPDF{filename.pdf} +% \begin{document} +% ... +% \end{document} +% \end{verbatim} +% The PDF will be centered on and scaled to fit the document page size while +% keeping a fixed aspect ratio. +% +% \subsection{Main Interface} +% +% \begin{function}{\pdfoverlaySetPDF, \pdfoverlay_set_pdf:n} +% \begin{syntax} +% \cs{pdfoverlaySetPDF} \Arg{PDF filename} +% \end{syntax} +% Specify the \meta{PDF filename} to overlay text on to. This function must +% be called first. It can be used either in the preamble or at any point in +% the document body. It is possible to call this more than once to include +% multiple PDF files. If the specified \meta{PDF filename} cannot be found an +% error is generated. +% \end{function} +% +% \begin{function}{\pdfoverlaySetGraphicsOptions, +% \pdfoverlay_set_graphics_options:n} +% \begin{syntax} +% \cs{pdfoverlaySetGraphicsOptions} \Arg{Options} +% \end{syntax} +% Set the \meta{Options} to be passed to \cs{includegraphics} when each page +% of the PDF is output. See the \pkg{graphicx} package documentation for +% valid options. \textbf{Note} that it is not necessary to specify the +% \texttt{page} option as this is appended automatically in the right format. +% The default options are: \texttt{keepaspectratio, +% width=}\cs{paperwidth}\texttt{, height=}\cs{paperheight}. +% \end{function} +% +% \begin{function}{\pdfoverlayIncludeToPage, \pdfoverlay_include_to_page:n} +% \begin{syntax} +% \cs{pdfoverlayIncludeToPage} \Arg{page number} +% \end{syntax} +% Output all pages in the PDF file up until the specified \meta{page number}. +% If the specified \meta{page number} does not evaluate to an integer or does +% not exist in the PDF an error is generated. +% \end{function} +% +% \begin{function}{\pdfoverlayIncludeToLastPage, \pdfoverlay_include_to_last_page:} +% \begin{syntax} +% \cs{pdfoverlayIncludeToLastPage} +% \end{syntax} +% Output all remaining pages in the PDF file. +% \end{function} +% +% \begin{function}{\pdfoverlaySkipToPage, \pdfoverlay_skip_to_page:n} +% \begin{syntax} +% \cs{pdfoverlaySkipToPage} \Arg{page number} +% \end{syntax} +% Skip to the specified \meta{page number}. This can be before or after the +% current page in the PDF file. If the specified \meta{page number} does not +% evaluate to an integer or does not exist in the PDF an error is generated. +% \end{function} +% +% \begin{function}{\pdfoverlayPauseOutput, \pdfoverlay_pause_output:} +% \begin{syntax} +% \cs{pdfoverlayPauseOutput} +% \end{syntax} +% Pause outputting pages from the PDF file. Any subsequent text will by +% output on blank pages. +% \end{function} +% +% \begin{function}{\pdfoverlayResumeOutput, \pdfoverlay_resume_output:} +% \begin{syntax} +% \cs{pdfoverlayResumeOutput} +% \end{syntax} +% Resume outputting pages from the PDF file. +% \end{function} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{Implementation} +% +% \begin{macrocode} +%<*package> +%<@@=pdfoverlay> +% \end{macrocode} +% +% \begin{macrocode} +\RequirePackage{xparse} +% \end{macrocode} +% +% \begin{macrocode} +\ProvidesExplPackage{pdfoverlay}{2018/05/08}{1.0} + {Overlay text on an existing PDF document (DCP)} +% \end{macrocode} +% +% \noindent The \pkg{everypage} and \pkg{pdfpages} packages are required. +% +% \begin{macrocode} +\RequirePackage{everypage,pdfpages} +% \end{macrocode} +% +% \noindent Call \cs{@@_output_pdf_page:} on every page using the +% \pkg{everypage} package. +% \begin{macrocode} +\AddEverypageHook { \@@_output_pdf_page: } +% \end{macrocode} +% +% \noindent Add \cs{null} to the end of the document if an action is pending. +% This is required to ensure that the last requested page from the PDF file is +% output even if there isn't any other content on the page. +% \begin{macrocode} +\AtEndDocument { + \bool_if:NT \g_@@_action_pending_bool + { + \null + } +} +% \end{macrocode} +% +% \subsection{Messages} +% +% Error message when specified PDF file cannot be found. \\ +% |#|1: PDF file name +% \begin{macrocode} +\msg_new:nnnn { pdfoverlay } { file-not-found } + { PDF~file~`#1'~not~found. } + { Unable~to~find~the~file~`#1'. \\ + Check~that~the~file~exists~and~you~have~spelt~it~correctly. } +% \end{macrocode} +% +% \noindent Error message when no PDF file has been set. +% \begin{macrocode} +\msg_new:nnnn { pdfoverlay } { file-not-set } + { PDF~file~not~set. } + { You~have~not~specified~a~PDF~file. \\ + Set~a~PDF~file~using~\pdfoverlaySetPDF. } +% \end{macrocode} +% +% \noindent Error message when the requested page number cannot be found in the +% PDF file. \\ +% |#1|: PDF file name \\ +% |#2|: Requested page number \\ +% |#3|: Total number of pages in PDF +% \begin{macrocode} +\msg_new:nnnn { pdfoverlay } { page-not-found } + { Page~not~found~in~PDF. } + { PDF~file~`#1'~does~not~contain~page~#2. \\ + Specify~a~page~between~1~and~#3. } +% \end{macrocode} +% +% \noindent Error message when the requested page number to include to is less +% than the current page number being output from the PDF file. \\ +% |#1|: Requested page number \\ +% |#2|: Current page number in PDF \\ +% |#3|: Total number of pages in PDF +% \begin{macrocode} +\msg_new:nnnn { pdfoverlay } { page-too-low } + { Requested~page~less~than~current~page~in~PDF. } + { You~have~requested~to~include~to~page~#1, \\ + but~the~current~page~is~already~at~page~#2. \\ + Specify~a~page~between~#2~and~#3. } +% \end{macrocode} +% +% \subsection{Private Variables and Helper Functions} +% +% \begin{macro}{\g_@@_pdf_file_name_str} +% Store the PDF file name. +% \begin{macrocode} +\str_new:N \g_@@_pdf_file_name_str +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\g_@@_page_count_int} +% Store the total number of pages in the PDF file. +% \begin{macrocode} +\int_new:N \g_@@_page_count_int +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\g_@@_page_int} +% Keep track of the current page in the PDF file. +% \begin{macrocode} +\int_new:N \g_@@_page_int +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\g_@@_output_active_bool} +% Flag to store whether to output pages from the PDF file or not. +% \begin{macrocode} +\bool_new:N \g_@@_output_active_bool +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\g_@@_action_pending_bool} +% Flag to store whether an action (\cs{pdfoverlay_include_to_page:n} or +% \cs{pdfoverlay_set_page:n}) is pending. If an action is pending, these +% functions will start a new page. +% \begin{macrocode} +\bool_new:N \g_@@_action_pending_bool +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\g_@@_graphics_options_clist} +% Hold the options passed to \cs{includegraphics} when including a page from +% the PDF. The default options scale the PDF page to fit the document page +% while keeping the original PDF page aspect ratio. +% \begin{macrocode} +\clist_new:N \g_@@_graphics_options_clist +\clist_set:Nn \g_@@_graphics_options_clist + { + keepaspectratio , + width = \paperwidth , + height = \paperheight , + page = \int_use:N \g_@@_page_int + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_output_pdf_page:} +% Main function to output the current page of the PDF file. This is called +% before every page is shipped using the \pkg{everypage} package. +% \begin{macrocode} +\cs_new:Nn \@@_output_pdf_page: + { +% \end{macrocode} +% Check if we are currently outputting pages, a PDF file has been set, and +% the requested page exists in the PDF file. +% \begin{macrocode} + \bool_lazy_all:nT + { + { \bool_if_p:N \g_@@_output_active_bool } + { \bool_not_p:n + { \str_if_empty_p:N \g_@@_pdf_file_name_str } } + { \int_compare_p:n + { \c_zero <= \g_@@_page_int + < \g_@@_page_count_int } } + } + { +% \end{macrocode} +% Place requested page from the PDF file in the background of the +% document page with the specified format. +% \begin{macrocode} + \AddToShipoutPictureBG* + { + \@@_format_pdf_page: + } +% \end{macrocode} +% Increment the current page counter. +% \begin{macrocode} + \int_gincr:N \g_@@_page_int +% \end{macrocode} +% Set action pending flag to false. +% \begin{macrocode} + \bool_gset_false:N \g_@@_action_pending_bool + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_format_pdf_page:} +% Format the PDF page in the centre of the document page with options from +% \cs{g_@@_graphics_options_clist}. Although marked as private, this function +% could be redifined to position the PDF page at a different location on the +% document page. See the \pkg{eso-pic} package documentation for hints on how +% to position the PDF page. +% \begin{macrocode} +\cs_new:Nn \@@_format_pdf_page: + { + \AtPageCenter + { + \makebox (0, 0) + { + \use:x + { + \exp_not:N \includegraphics + [ \clist_use:Nn \g_@@_graphics_options_clist { , } ] + { \g_@@_pdf_file_name_str } + } + } + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\@@_check_page:n} +% Check if a PDF file has been set and the requested page is valid. If not, +% generate suitable error messages. +% \begin{macrocode} +\prg_new_conditional:Npnn \@@_if_page_exists:n #1 { p, T, F, TF } + { + \str_if_empty:NTF \g_@@_pdf_file_name_str + { + \msg_error:nn { pdfoverlay } { file-not-set } + \prg_return_false: + } + { + \int_compare:nTF + { + \c_one <= #1 <= \g_@@_page_count_int + } + { + \prg_return_true: + } + { + \msg_error:nnxxx { pdfoverlay } { page-not-found } + { \str_use:N \g_@@_pdf_file_name_str } + { \int_eval:n { #1 } } + { \int_use:N \g_@@_page_count_int } + \prg_return_false: + } + } + } +% \end{macrocode} +% \end{macro} +% +% +% \subsection{Public Expl3 Functions} +% +% \begin{macro}{\pdfoverlay_set_pdf:n} +% Specify a PDF file to overlay text on to. +% \begin{macrocode} +\cs_new:Npn \pdfoverlay_set_pdf:n #1 + { +% \end{macrocode} +% Test if the file exists and generate a suitable error if it doesn't. +% \begin{macrocode} + \file_if_exist:nTF { #1 } + { + \str_gset:Nn \g_@@_pdf_file_name_str { #1 } +% \end{macrocode} +% Use the \pkg{pdfpages} package to find the number of pages in the PDF file. +% \begin{macrocode} + \edef \AM@currentdocname { #1 } + \AM@getpagecount +% \end{macrocode} +% Initialise variables. +% \begin{macrocode} + \int_gset_eq:NN \g_@@_page_count_int \AM@pagecount + \int_gset_eq:NN \g_@@_page_int \c_zero + \bool_gset_true:N \g_@@_output_active_bool + \bool_gset_false:N \g_@@_action_pending_bool + } + { + \msg_error:nnn { pdfoverlay } { file-not-found } { #1 } + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\pdfoverlay_set_graphics_options:n} +% Set the options as a comma separated list to be passed to +% \cs{includegraphics} when outputting each page from the PDF file. The +% \texttt{page} option is appended automatically in the +% correct format. +% \begin{macrocode} +\cs_new:Nn \pdfoverlay_set_graphics_options:n + { + \clist_gset:Nn \g_@@_graphics_options_clist { #1 } + \clist_gput_right:Nn \g_@@_graphics_options_clist + { + page = \int_use:N \g_@@_page_int + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\pdfoverlay_include_to_page:n} +% Output all pages in the PDF file up until the specified page. Since the +% actual PDF page is inserted by \cs{__pdfoverlay_output_pdf_page:} using the +% \pkg{everypage} package before the page is shipped, we just insert the +% required number of blank pages into the document. +% \begin{macrocode} +\cs_new:Npn \pdfoverlay_include_to_page:n #1 + { +% \end{macrocode} +% Check if a PDF file is set and the requested page exists. +% \begin{macrocode} + \@@_if_page_exists:nT { #1 } + { +% \end{macrocode} +% Check if the requested page is greater than the current page. +% \begin{macrocode} + \int_compare:nTF + { + #1 >= \g_@@_page_int + 1 + } + { +% \end{macrocode} +% Check if an action is pending and start a new page if so. +% \begin{macrocode} + \bool_lazy_all:nT + { + { \bool_if_p:n { \g_@@_action_pending_bool } } + { \int_compare_p:n { \g_@@_page_int < + \g_@@_page_count_int - 1 } } + { \int_compare_p:n { #1 != \g_@@_page_int + 1 } } + } + { + \null + \clearpage + } +% \end{macrocode} +% Loop until the specified page, inserting blank pages. +% \begin{macrocode} + \int_while_do:nNnn { \g_@@_page_int } < { #1 - 1 } + { + \null + \clearpage + } +% \end{macrocode} +% Set the action pending flag, so final page is output even if no text is +% overlayed on it. +% \begin{macrocode} + \bool_gset_true:N \g_@@_action_pending_bool + } + { + \msg_error:nnxxx { pdfoverlay } { page-too-low } + { \int_eval:n { #1 } } + { \int_eval:n { \g_@@_page_int + 1 } } + { \int_use:N \g_@@_page_count_int } + } + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\pdfoverlay_include_to_last_page:} +% Output all remaining pages in the PDF file. +% \begin{macrocode} +\cs_new:Nn \pdfoverlay_include_to_last_page: + { + \pdfoverlay_include_to_page:n { \g_@@_page_count_int } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\pdfoverlay_skip_to_page:n} +% Skip to the specified page number in the PDF file. +% \begin{macrocode} +\cs_new:Npn \pdfoverlay_skip_to_page:n #1 + { + \@@_if_page_exists:nT { #1 } + { +% \end{macrocode} +% Check if an action is pending and start a new page if so. +% \begin{macrocode} + \bool_if:nT { \g_@@_action_pending_bool } + { + \null + \clearpage + } +% \end{macrocode} +% Set the page numer for the next page to be output. +% \begin{macrocode} + \int_gset:Nn \g_@@_page_int { #1 - 1 } +% \end{macrocode} +% Set the action pending flag, so final page is output even if no text is +% overlayed on it. +% \begin{macrocode} + \bool_gset_true:N \g_@@_action_pending_bool + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\pdfoverlay_pause_output:} +% Pause outputting pages from the PDF file. +% \begin{macrocode} +\cs_new:Nn \pdfoverlay_pause_output: + { + \bool_gset_false:N \g_@@_output_active_bool + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\pdfoverlay_resume_output:} +% Resume outputting pages from the PDF file. +% \begin{macrocode} +\cs_new:Nn \pdfoverlay_resume_output: + { + \bool_gset_true:N \g_@@_output_active_bool + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Public \LaTeX{} Interface} +% +% \begin{macro}{\pdfoverlaySetPDF} +% Specify a PDF file to overlay text on to. +% \begin{macrocode} +\NewDocumentCommand \pdfoverlaySetPDF { m } + { + \pdfoverlay_set_pdf:n { #1 } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\pdfoverlaySetGraphicsOptions} +% Set the options as a comma separated list to be passed to +% \cs{includegraphics} when outputting each page from the PDF file. The +% \texttt{page} option is appended automatically in the right format. +% \begin{macrocode} +\NewDocumentCommand \pdfoverlaySetGraphicsOptions { m } + { + \pdfoverlay_set_graphics_options:n { #1 } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\pdfoverlayIncludeToPage} +% Output all pages in the PDF file up until the specified page. +% \begin{macrocode} +\NewDocumentCommand \pdfoverlayIncludeToPage { m } + { + \pdfoverlay_include_to_page:n { #1 } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\pdfoverlayIncludeToLastPage} +% Output all remaining pages in the PDF file. +% \begin{macrocode} +\NewDocumentCommand \pdfoverlayIncludeToLastPage { } + { + \pdfoverlay_include_to_last_page: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\pdfoverlaySkipToPage} +% Skip ahead to the specified page number in the PDF file. +% \begin{macrocode} +\NewDocumentCommand \pdfoverlaySkipToPage { m } + { + \pdfoverlay_skip_to_page:n { #1 } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\pdfoverlayPauseOutput} +% Pause outputting pages from the PDF file. +% \begin{macrocode} +\NewDocumentCommand \pdfoverlayPauseOutput { } + { + \pdfoverlay_pause_output: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\pdfoverlayResumeOutput} +% Resume outputting pages from the PDF file. +% \begin{macrocode} +\NewDocumentCommand \pdfoverlayResumeOutput { } + { + \pdfoverlay_resume_output: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +% +% \end{macrocode} +% +% \end{implementation} +% +% \PrintChanges +% +% \PrintIndex -- cgit v1.2.3