Is there a way to get two pages in one with LaTeX?

You could use pdfpages or pdfjam and its pdfnup tool.


It occurs to me that post-processing isn't necessary for getting two pages in one. What about just making a two column document?

\documentclass[twocolumn]{article}
\usepackage[landscape,margin=2cm]{geometry}

Andrew had the very sensible idea of not shrinking the file down to 71% since this makes the text rather small, and usually you don't want the excessive white margins. My approach to this: First magnify the file as needed, using the shell script I provide below (following Andrew's suggestion), and then use whatever tool you like to put 2 or 4 (or more) pages on one. I have to point out that I assume here that you work with postscript files. Yes, you do lose all the hyperlinks and stuff like that when you use pdftops, but I don't see any problem in this since I would only use this for printing.

My script is rather long since it tries to be clever. You don't really need instructions for using it; just type the name of the script (I call it gr since it makes things greater) without any parameters, and it'll print some usage information. I've put some comments in the file that explain a bit more. One thing I should explain: There's a nice feature that I often use, namely the so called "groptions". Suppose you have a TeX file "document.tex", and the output "document.ps". If in the first 10 lines of document.tex you have a line

%groptions: 15 thisfile -u4

then you can call the script by

gr document

and this will have the same effect as

gr 15 document -u4

namely: Magnify by 15%, and shift up by 4mm. So you don't always have to remember the parameters for that particular file.

# In the following comments I assume that this script is called "gr".
# You can also call it "mag" or whatever if you wish;
# the builtin command line help will understand this.

gv=false
[ "$1" = --gv ] && gv=true && shift
# This opens the output file with gv if the first parameter is --gv .
# I have aliased "gr" to "gr --gv", so that the --gv option
# is always selected if I type "gr" on a command line,
# and it is not selected if "gr" is called in a shell script.

# If you have a file <file>.ps, you can use
#      gr 20 <file>
# or   gr 20 <file>.
# or   gr 20 <file>.ps
# to magnify it by 20%.  The default output file is "gr.ps".
# The rationale behind this:
# If you have <file>.tex and <file>.ps in your directory,
# and you use the tab key for expanding the file name,
# then you'll only get "<file>.", and you don't have to type "ps".
#
# If the input file comes from standard input, use "gr 20 -".
if [ $# -eq 1 ]
then infile="${1%ps}"
     infile="${infile%.}"
     [ -f "$infile.tex" ] &&
     grop=`head "$infile.tex" | grep groptions | dos2unix` &&
     set -- `echo -n "$grop" | sed "s|.*groptions: ||;s|thisfile|$infile|"`
fi

compute () {
arg=`echo "$@" | sed 's|--|+|g'`
echo | awk "{print $arg}" | tr , .
}

eval "set -- `getopt -sbash r:l:u:d:o:i:x:y:2 "$@"`"
right=0
up=0
outward=0
xmin=0
xmax=595
ymin=0
ymax=842
fromsecond=false
while [ $# -gt 0 ]
do case "$1" in
    -r) right=`compute $right+$2`; shift;;
    -l) right=`compute $right-$2`; shift;;
    -u) up=`compute $up+$2`; shift;;
    -d) up=`compute $up-$2`; shift;;
    -o) outward=`compute $outward+$2`; shift;;
    -i) outward=`compute $outward-$2`; shift;;
    -x) xmin=${2%-*}; xmax=${2#*-}; shift;;
    -y) ymin=${2%-*}; ymax=${2#*-}; shift;;
    -2) fromsecond=true;;
    --) shift; break;;
   esac
   shift
done

[ -z "`echo "$1" | sed 's|[0-9.]||g'`" ] && proz=$1 && shift || proz=0 

[ $# -eq 0 ] && echo "\
${0##*/} -- magnifies the pages of postscript files
Usage: ${0##*/} <how many %> <which file>
       3rd parameter (optional): output file (without suffix .ps)
       options: -2 -- magnify only from second page on
                -l<number> -- shift left by <number>mm
                -r<number> -- shift right by <number>mm
                -u<number> -- shift up by <number>mm
                -d<number> -- shift down by <number>mm
                -o<number> -- shift outward by <number>mm
                -i<number> -- shift inward by <number>mm
                -x<min>-<max> -- cropping the x-scope <min>-<max>pt (default 0-595)
                -y<min>-<max> -- cropping the y-scope <min>-<max>pt (default 0-842)" && exit 0

outfile="${2:-gr}.ps"
if [ "$1" = - ]
then infile=/tmp/tmp$$infile.ps
     cat > $infile
     what='"$infile"'
# you can also use this script on .ps.gz files.
else infile="${1%.gz}"
     infile="${infile%ps}"
     infile="${infile%.}"
     # This is a good place where one could add conditional compilation
     # of the input file. For me this is:
     # condlatex "$infile" || exit 1
     # conddvips "$infile"
     infile="$infile.ps"
     [ -f "$infile" ] && what='"$infile"' ||
       if [ -f "$infile.gz" ]
         then unzip="gunzip -c '$infile.gz' |" && what=
         else echo "»$infile« not found" && exit 0
       fi
fi
right=`compute $right-$proz*1.05`
up=`compute $up-$proz*1.48`
proz=`compute 1+$proz/100`

pages () {
page=$(eval "$unzip head -n15 $what" | grep '%%Pages:* ' | cut -d' ' -f2 | dos2unix)
[ "$page" = "(atend)" ] && 
eval "$unzip tail $what" | grep '%%Pages:* ' | cut -d' ' -f2 | dos2unix ||
echo $page
}

if [ "$outward" = 0 ] && [ "$fromsecond" = false ]
then str="1:0@$proz(${right}mm,${up}mm)"
else pages=`pages`
     rpo=`compute $right+$outward`
     rmo=`compute $right-$outward`
     [ "$fromsecond" = true ] && str="$pages:0@1" ||
                           str="$pages:0@$proz(${rpo}mm,${up}mm)"
     p=1
     while [ $p -lt $pages ]
     do str="$str,$((p++))@$proz(${rmo}mm,${up}mm)"
    [ $p -lt $pages ] &&
    str="$str,$((p++))@$proz(${rpo}mm,${up}mm)"
     done
fi
eval "$unzip pstops -pa4 '$str' $what" | sed '
/^%%Page:* /N
/^userdict\/PStoPSsaved save put$/N
/^%%Page:* .*\nuserdict\/PStoPSsaved save put/,/^ closepath}put initclip$/{
/^userdict\/PStoPSclip{0 0 moveto$/,/^ closepath}put initclip$/d
/^PStoPSmatrix setmatrix$/a\
userdict/PStoPSclip{'"$xmin $ymin"' moveto\
'"$xmax $ymin lineto $xmax $ymax lineto $xmin $ymax"' lineto\
closepath}put initclip
}
' > "/tmp/tmp$$$outfile"
mv "/tmp/tmp$$$outfile" "$outfile"
if $gv; then
  ps w | grep "[^]] gv $outfile" >/dev/null || gv "$outfile" &
fi
[ "$outfile" = gr.ps ] && echo "output in gr.ps"
[ $proz = 1 ] && echo '         No magnification !!!'
[ "$infile" = /tmp/tmp$$infile.ps ] && rm $infile