% \iffalse meta-comment
%
% Copyright (C) 2007, 2017-2022 by Rolf Niepraschk 
% ---------------------------------------------------------------------------
% This work may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either version 1.3
% 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.3 or later is part of all distributions of LaTeX
% version 2005/12/01 or later.
%
% This work has the LPPL maintenance status `maintained'.
%
% The Current Maintainer of this work is Rolf Niepraschk. 
%
% This work consists of the files blowup.dtx and blowup.ins
% and the derived filebase blowup.sty.
%
% \fi
%
% \iffalse
%<*driver>
\ProvidesFile{blowup.dtx}
%</driver>
%<package>\NeedsTeXFormat{LaTeX2e}[2020/10/01]
%<package>\ProvidesPackage{blowup}[2023/07/15 2.2.0 Page scaling (RN)]
%
%<*driver>
\documentclass{ltxdoc}
\usepackage{blowup,array,longtable,ragged2e}
\let\RaggedRight=\raggedright
\newcommand{\m}[1]{\mbox{$\langle$\it #1\/$\rangle$}}
\renewcommand{\arg}[1]{{\ttfamily\string{}\m{#1}{\ttfamily\string}}}
\EnableCrossrefs
\CodelineIndex
\RecordChanges
\begin{document}
  \DocInput{blowup.dtx}
  \PrintChanges
  \PrintIndex
\end{document}
%</driver>
% \fi
%
% \CheckSum{546}
%
% \CharacterTable
%  {Upper-case    \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
%   Lower-case    \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
%   Digits        \0\1\2\3\4\5\6\7\8\9
%   Exclamation   \!     Double quote  \"     Hash (number) \#
%   Dollar        \$     Percent       \%     Ampersand     \&
%   Acute accent  \'     Left paren    \(     Right paren   \)
%   Asterisk      \*     Plus          \+     Comma         \,
%   Minus         \-     Point         \.     Solidus       \/
%   Colon         \:     Semicolon     \;     Less than     \<
%   Equals        \=     Greater than  \>     Question mark \?
%   Commercial at \@     Left bracket  \[     Backslash     \\
%   Right bracket \]     Circumflex    \^     Underscore    \_
%   Grave accent  \`     Left brace    \{     Vertical bar  \|
%   Right brace   \}     Tilde         \~}
%
%
% \changes{0.1a}{2007/08/14}{Initial version. (RN)}
% \changes{2.0.0}{2022/09/19}{Major parts rewritten. (RN)}
%
% \DoNotIndex{\newcommand,\newenvironment,\z@,\vskip,\hskip,\vss,\hss,\value,
%  \the,\ifx,\if,\fi,ifdim,\ifodd,\else,\providecommand,\newif,\newlength,\noexpand,
%  \let,\def,\gdef,\edef,\xdef,\kern,\string,\box,\copy,\csname,\endcsname,
%  \begingroup,\endgroup,\expandafter,\relax,\@tempboxa,\@tempdima,\@tempdimb,
%  \@empty,\@firstoftwo,\@ifundefined,\@nil,\@secondoftwo,\@tempswafalse,
%  \@tempswatrue,\if@tempswa,\@for,\do,\ht,\wd,\dp,\g@addto@macro,\hbox,\vbox,
%  \hb@xt@,\vb@xt@,\global,\l@addto@macro,\moveright,\BL@tempa,\BL@tempb}
%
% \providecommand*{\url}{\texttt}
% \GetFileInfo{blowup.sty}  
% \title{The \textsf{blowup} package}
% \author{Rolf Niepraschk} 
% \date{Version~\fileversion~(\filedate)}
%
% \maketitle
%
% \section{Introduction}
%
% This package only defines the user-level macro \cmd{\blowUp}, which can be 
% used to scale all pages of a document up or down. It is similar to the \TeX\ 
% primitive \cmd{\mag}, but more accurate and user-friendly. \cmd{\blowUp} can
% be useful for creating posters from a normal sized document and for many other 
% types of fine-tuning of a finished document (e.g., minor scaling changes and 
% position of the pages).  
%
% \section{Usage}
% The only user macro is \cmd{\blowUp}\arg{key=value}. Call it before 
% |\begin{document}| to scale all pages of the document:  \par \medskip\noindent
%  
%  \setlength\extrarowheight{.2ex}
%  \newcolumntype{P}[1]{>{\RaggedRight\hspace{0pt}}p{#1}}
%  \begin{longtable}{@{}lP{.75\linewidth}@{}}
%    \multicolumn{1}{@{}l}{\textbf{key}} & 
%    \multicolumn{1}{l@{}}{\textbf{value}} \tabularnewline \hline 
%    target    & The final paper size: \tabularnewline
%              & |letter|, |legal|, |executive| or a paper size from the 
%              ISO/DIN paper series A, B, C, D 
%              (e.\,g., |a8|, |c7|,..., |b1|, |a0|) or a pair of dimensions
%              in curly brackets (e.\,g., |target={925mm,1225mm}|) or the 
%              letter `x' followed by a scaling factor 
%              (e.\,g., |target=x1.414213|). \tabularnewline[.75ex]
%    origin    & Scaled size of the source document: \tabularnewline
%              & |letter|, |legal|, |executive| or a paper size from the 
%              ISO/DIN paper series A, B, C, D 
%              (e.\,g., |a8|, |c7|,..., |b1|, |a0|) or a pair of dimensions
%              in curly brackets (e.\,g., |origin={925mm,1225mm}|) or the 
%              letter `x' followed by a scaling factor 
%              (e.\,g., |origin=x1.414213|). \tabularnewline[.75ex]
%  h-mirroring & horizontally mirroring of the final pages \tabularnewline
%              & |true| (the same as no value) or |false| (default: |false|). 
%                 \tabularnewline[.75ex]
%  v-mirroring & vertically mirroring of the final pages \tabularnewline
%              & |true| (the same as no value) or |false| (default: |false|). 
%                 \tabularnewline[.75ex]
%    landscape & Exchanges paperwidth and paperheight: \tabularnewline
%              & |true| (the same as no value) or |false| (default: |false|). 
%                 \tabularnewline[.75ex]
%    noscale   & No scaling of the original paper size: \tabularnewline
%              & |true| (the same as no value) or |false| (default: |false|).
%                 \tabularnewline[.75ex]
%    pos       & Position of the page on the paper: \tabularnewline
%              & |left| or |right|, |inside| or |outside|, |top| or |bottom| 
%              (only the first letter is significant; default is 
%              centering), or
%              a pair of dimensions in curly brackets which means the offset  
%              from the lower left or lower outside corner of the final paper. 
%              Only meaningful for |noscale=true| and up-scaled paper 
%              size. \tabularnewline[.75ex]
%    onepage   & Suppresses the second page and all following pages: 
%                 \tabularnewline 
%              & |true| (the same as no value) or |false| (default: |false|).
%                 \tabularnewline
%              & Useful for creating a one-page document like a poster.
%  \end{longtable}
%  \vspace{0\baselineskip}
%  See also the example documents |blowup-ex?.tex|.
%
% \StopEventually{}
%
% \section{Implementation}
%
% \iffalse
%<*package>
% \fi
%
%  Load some packages for utility macros. 
%    \begin{macrocode}
\RequirePackage{keyval,graphics}
\@ifpackageloaded{typearea}{}{%
  \newcommand*\BL@save@dimen[1]{%
    \@ifundefined{BL@#1}{%
      \expandafter\newlength\csname BL@#1\endcsname}{}%
    \csname BL@#1\endcsname\csname #1\endcsname
    \g@addto@macro\BL@restore@dimens{%
      \csname #1\endcsname\csname BL@#1\endcsname}%
  }%
%    \end{macrocode}
% \begin{macro}{\BL@restore@dimens}
% Some dimensions changed by \textsf{typearea} must be saved and restored.
%    \begin{macrocode}
  \newcommand*\BL@restore@dimens{}%
%    \end{macrocode}
% \end{macro}
%    \begin{macrocode}
  \BL@save@dimen{paperwidth}%
  \BL@save@dimen{paperheight}%
  \BL@save@dimen{textwidth}%
  \BL@save@dimen{textheight}%
  \BL@save@dimen{evensidemargin}%
  \BL@save@dimen{oddsidemargin}%
  \BL@save@dimen{topmargin}%
  \BL@save@dimen{headheight}%
  \BL@save@dimen{headsep}%
  \BL@save@dimen{topskip}%
  \BL@save@dimen{footskip}%
  \BL@save@dimen{baselineskip}%
  \let\l@addto@macro=\relax
  \RequirePackage[pagesize=false]{typearea}%
  \expandafter\let\csname ver@typearea.sty\endcsname=\relax
  \BL@restore@dimens
  \let\BL@save@dimen=\relax
  \let\BL@restore@dimens=\relax
}
%    \end{macrocode}
%
% \begin{macro}{\vb@xt@}
%   Similar to \cmd{\hb@xt@}
%    \begin{macrocode}
\providecommand*\vb@xt@{\vbox to}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\tPaperWidth}
% \begin{macro}{\tPaperHeight}
%   The size of the scaled final pages.
%    \begin{macrocode}
\newlength\tPaperWidth
\newlength\tPaperHeight
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \begin{macro}{\oPaperWidth}
% \begin{macro}{\oPaperHeight}
%    The size of the original pages.
%    \begin{macrocode}
\newlength\oPaperWidth  \oPaperWidth=\z@
\newlength\oPaperHeight \oPaperHeight=\z@
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\BL@resize}
%   Resizes the shipout box.
%    \begin{macrocode}
\newcommand*\BL@resize[1]{#1}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\BL@scalePage}
%   The whole scaling process of the the shipout box to the dimension of the 
%   new paper size.
%   \changes{2.1.0}{2022/09/22}{New options `h-mirroring' and `v-mirroring' (RN)}
%   \changes{2.2.0}{2023/07/15}{Using \LaTeX's \cmd{\ShipoutBox} (RN)}
%    \begin{macrocode}
\newcommand*\BL@scalePage{%
%    \end{macrocode}
%   Normalize the shipout box
%    \begin{macrocode}
  \setbox\ShipoutBox=\vbox{%
    \vskip1in\moveright1in\box\ShipoutBox}%
  \setbox\ShipoutBox=\hb@xt@\paperwidth{%
    \box\ShipoutBox\hss}%
  \setbox\ShipoutBox=\vb@xt@\paperheight{%
    \box\ShipoutBox\vss}%
  \ifBL@noscale\else
    \ifdim\oPaperWidth>\z@
      \setbox\ShipoutBox=\hbox{\resizebox{\oPaperWidth}{\oPaperHeight}%
        {\box\ShipoutBox}}%
    \else
      \def\BL@resize##1{\resizebox{\tPaperWidth}{!}{##1}}%
      \setbox\@tempboxa=\hbox{\BL@resize{\copy\ShipoutBox}}%
      \ifdim\ht\@tempboxa>\tPaperHeight
        \def\BL@resize##1{\resizebox{!}{\tPaperHeight}{##1}}%
      \fi
    \fi
  \fi
  \setbox\@tempboxa=\vb@xt@\tPaperHeight{%
    \kern\z@\BL@t
    \hb@xt@\tPaperWidth{\BL@l\BL@resize{\box\ShipoutBox}\BL@r}%
    \BL@b\kern\z@
  }%
  \ifBL@mirroring
    \setbox\@tempboxa=\hbox{\scalebox{\BL@h}[\BL@v]{\box\@tempboxa}}%
  \fi  
%    \end{macrocode}
%   Denormalize the shipout box
%    \begin{macrocode}
  \setbox\ShipoutBox=\vbox{%
    \vskip-1in\moveright-1in\box\@tempboxa}%
}
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
\newcommand\BL@tempa{}
\newcommand\BL@tempb{}
\newcommand*\BL@strip@comma{}
\def\BL@strip@comma#1,{#1}
%    \end{macrocode}
%
% \begin{macro}{\BL@is@dimen@pair}
%   The parameter two will be executed if the first parameter is 
%   a comma-separated pair of two dimensions. If not the parameter three 
%   will be executed.   
%    \begin{macrocode}
\newcommand*\BL@is@dimen@pair[1]{%
  \expandafter\BL@@is@dimen@pair#1,\@nil
}
\newcommand*\BL@@is@dimen@pair{}
\def\BL@@is@dimen@pair#1,#2\@nil{%
  \edef\BL@tempa{#1}\edef\BL@tempb{#2}%
  \@tempswafalse
  \ifx\BL@tempb\@empty\else
    \edef\BL@tempb{\expandafter\BL@strip@comma\BL@tempb}%
    \ifdimen{\BL@tempa}{%
      \ifdimen{\BL@tempb}{\@tempswatrue}{}%
    }{}%
  \fi
  \if@tempswa
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
}
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
\newcommand*\BL@strip@x{}
\def\BL@strip@x#1x{#1}
%    \end{macrocode}
%
% \begin{macro}{\BL@is@factor}
%   The parameter two will be executed if the first parameter is the 
%   small letter x (`times') immediately followed by a number. If not 
%   the parameter three will be executed.
%    \begin{macrocode}
\newcommand*\BL@is@factor[1]{%
  \expandafter\BL@@is@factor#1x\@nil
}
\newcommand*\BL@@is@factor{}
\def\BL@@is@factor#1x#2\@nil{%
  \edef\BL@tempa{#2}%
  \@tempswafalse
  \ifx\BL@tempa\@empty\else
    \edef\BL@tempa{\expandafter\BL@strip@x\BL@tempa}%
    \ifdimen{\BL@tempa pt}{\@tempswatrue}{}%
  \fi
  \if@tempswa
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\BL@getDimens}
%   Sets the two dimen registers (|#2| and |#3|) according to parameter |#1|.
%    \begin{macrocode}
\newcommand*\BL@getDimens[3]{%
  \BL@is@dimen@pair{#1}{%
    \global#2=\BL@tempa\relax
    \global#3=\BL@tempb\relax
  }{%
    \BL@is@factor{#1}{%
      \global#2=\BL@tempa\paperwidth
      \global#3=\BL@tempa\paperheight
    }{%
      \begingroup
        \KOMAoptions{paper=portrait,paper=#1}%
        \global#2=\paperwidth
        \global#3=\paperheight
      \endgroup
    }%
  }%
}
%    \end{macrocode}
% \end{macro}
%  The key-value definitions for \cmd{\blowUp}:
%    \begin{macrocode}
\define@key{BL@}{origin}{%
  \BL@getDimens{#1}{\oPaperWidth}{\oPaperHeight}%
}
%    \end{macrocode}
%
%    \begin{macrocode}
\define@key{BL@}{target}{%
  \BL@getDimens{#1}{\tPaperWidth}{\tPaperHeight}%
}
%    \end{macrocode}
%
%    \begin{macrocode}
\newif\ifBL@noscale \BL@noscalefalse
\newif\ifBL@mirroring \BL@mirroringfalse
%    \end{macrocode}
%
%    \begin{macrocode}
\define@key{BL@}{noscale}[true]{%
  \global\csname BL@noscale#1\endcsname
}
\define@key{BL@}{h-mirroring}[true]{%
  \global\csname BL@mirroring#1\endcsname
  \gdef\BL@h{-1}%
}
\define@key{BL@}{v-mirroring}[true]{%
  \global\csname BL@mirroring#1\endcsname
  \gdef\BL@v{-1}%
}
%    \end{macrocode}
%
%    \begin{macrocode}
\newcommand*\BL@l{}
\newcommand*\BL@r{}
\newcommand*\BL@i{}
\newcommand*\BL@o{}
\newcommand*\BL@t{}
\newcommand*\BL@b{}
\newcommand*\BL@h{1}
\newcommand*\BL@v{1}
%    \end{macrocode}
%
%
% \begin{macro}{\BL@setPos}
%   Modify the macros \cmd{\BL@l}, \cmd{\BL@r} (\cmd{\BL@i}, \cmd{\BL@o}), 
%   \cmd{\BL@t}, and \cmd{\BL@b} for positioning the page on the paper.
%    \begin{macrocode}
\newcommand\BL@setPos[1]{%
  \def\BL@l{\hss}\def\BL@r{\hss}%
  \def\BL@o{\hss}\def\BL@i{\hss}%
  \def\BL@t{\vss}\def\BL@b{\vss}%
  \BL@is@dimen@pair{#1}{%
    \edef\BL@b{\vskip\BL@tempb}%
    \if@twoside
      \edef\BL@l{\noexpand\ifodd\value{page}%
        \hskip\BL@tempa\noexpand\else\hss\noexpand\fi}%
      \edef\BL@r{\noexpand\ifodd\value{page}%
        \hss\noexpand\else\hskip\BL@tempa\noexpand\fi}%
    \else
      \edef\BL@l{\hskip\BL@tempa}%
    \if
  }{%
    \@for\BL@tempa:=#1\do{%
      \edef\BL@tempb{\expandafter\@car\BL@tempa\@nil}%
      \expandafter\let\csname BL@\BL@tempb \endcsname\relax
    }%
    \if@twoside
      \ifx\BL@i\relax
        \def\BL@r{\ifodd\value{page}\hss\else\relax\fi}%
        \def\BL@l{\ifodd\value{page}\relax\else\hss\fi}%
      \fi
      \ifx\BL@o\relax
        \def\BL@l{\ifodd\value{page}\hss\else\relax\fi}%
        \def\BL@r{\ifodd\value{page}\relax\else\hss\fi}%
      \fi
    \else
      \let\BL@l=\BL@o
      \let\BL@r=\BL@i
    \fi
  }%
}
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
\define@key{BL@}{pos}{%
  \BL@setPos{#1}%
}
%    \end{macrocode}
%
%    \begin{macrocode}
\newif\ifBL@landscape \BL@landscapefalse
%    \end{macrocode}
%
%    \begin{macrocode}
\define@key{BL@}{landscape}[true]{%
  \csname BL@landscape#1\endcsname
}
%    \end{macrocode}
%
%    \begin{macrocode}
\newcommand*\BL@setup{}
%    \end{macrocode}
%
%    \begin{macrocode}
\define@key{BL@}{onepage}[true]{%
  \csname if#1\endcsname
    \def\BL@setup{\gdef\shipout{\deadcycles\z@\setbox\@tempboxa=}}%
  \fi
}
%    \end{macrocode}
%
% \begin{macro}{\blowUp}
%   The only user-level macro.
%   \changes{2.2.0}{2023/07/15}{Using \LaTeX's shipout hook instead of package `atbegshi'}
%    \begin{macrocode}
\newcommand*\blowUp[1]{%
  \global\tPaperWidth=\paperwidth
  \global\tPaperHeight=\paperheight
  \setkeys{BL@}{#1}%
  \ifBL@landscape
    \@tempdima=\tPaperWidth
    \global\tPaperWidth=\tPaperHeight
    \global\tPaperHeight=\@tempdima
  \fi
  \AtBeginDocument{%
    \AtBeginDvi{\BL@pagesize@code{\tPaperWidth}{\tPaperHeight}}%
    \AddToHook{shipout}{\BL@setup\BL@scalePage}%
  }%
  \gdef\blowUp##1{%
    \PackageWarning{blowup}{Only the first call of `\string\blowUp'
      \MessageBreak is effective}}%
}
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
\@onlypreamble\blowUp
%    \end{macrocode}
%
% \begin{macro}{\BL@pagesize@code}
%   Page size information (depending on the \TeX\ compiler or driver).
%    \begin{macrocode}
\newcommand*\BL@pagesize@code[2]{}
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
\RequirePackage{iftex}
%    \end{macrocode}
%
%    \begin{macrocode}
\ifluatex
  \PackageInfo{blowup}{Generating code for LuaTeX}%
  \@ifundefined{pagewidth}{%
    \def\BL@pagesize@code#1#2{\global\pdfpagewidth=#1 %
      \global\pdfpageheight=#2}%
  }{%
    \def\BL@pagesize@code#1#2{\global\pagewidth=#1 %
      \global\pageheight=#2}%
  }
\else
  \ifxetex
    \PackageInfo{blowup}{Generating code for XeTeX}%
    \def\BL@pagesize@code#1#2{\global\pdfpagewidth=#1 %
      \global\pdfpageheight=#2}%
  \else
    \ifvtex
      \PackageInfo{blowup}{Generating code for VTeX}%
      \def\BL@pagesize@code#1#2{\global\mediawidth=#1 %
        \global\mediaheight=#2}%
    \else
      \ifpdf
        \PackageInfo{blowup}{Generating code for pdfTeX}%
        \def\BL@pagesize@code#1#2{\global\pdfpagewidth=#1 %
          \global\pdfpageheight=#2}%
      \else
        \PackageInfo{blowup}{Generating code for dvips}%
        \def\BL@pagesize@code#1#2{%
          \@tempdima=#1 \@tempdimb=#2 %
          \special{papersize=\the\@tempdima,\the\@tempdimb}%
        }%
      \fi
    \fi
  \fi
\fi
%    \end{macrocode}
%
% \iffalse
%</package>
% \fi
%
% \Finale
\endinput
