Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
Publishing
bundsteg
bundsteg-v1.2
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File bundsteg-v1.2 of Package bundsteg
#!/bin/bash # # bundsteg v1.2 - print pdfs with gutter/gap/inner margin # (c) copyright by Elmar Stellnberger, the original author: May 2009, April 2015 # # further information: www.elstel.org/com; look here for an actual contact address # current email: estellnb@elstel.org; additional email estellnb@gmail.com # # v.1.2: important bugfix, new features, license (19.04.2015) # * important bugfix: the margin now becomes exactly as large as specified, formerly the page was scaled after adding margins which makes things buggy # now previous margins get fully cropped, all even and odd pages are scaled to the maximum while adding printer margins for both sets of pages # * pdfnup is integrated: no separate invocation of pdfnup is necessary any more to add margins + get multiple slides onto one # * page rotation possible: before any other step pages from the source document may be rotated (ranges,modulo,individually) if necessary # # v.1.1: OSS based version (14.04.2015) # * now the program relies on OSS-tools only # the changes were inspired by a comment from Alessandro Cuttin # who has sent me a version using podofocountpages rather than pdftools # # v.1.0: intial version (05.08.2009) # * adds margins to pdf-files # license() { cat <<EOQ This program may be used under the terms of GPLv3; see: https://www.gnu.org/licenses/gpl-3.0.en.html. If you apply changes please sign our contributor license agreement at https://www.elstel.org/license/CLA-elstel.pdf so that your changes can be included into the main trunk at www.elstel.org/bundsteg/ (c) copyright by Elmar Stellnberger 2015 EOQ exit 0; } rot=$'\e[1;31m'; blau=$'\e[1;34m'; nv=$'\e[0m'; ul=$'\e[4m'; err() { echo -e "${rot}$@${nv}" >&2; } warn() { echo -e "${rot}$@${nv}" >&2; } msg() { echo -e "${blau}$@${nv}" >&2; } rotate=('' 'R' 'D' 'L'); modulos=""; let should_rotate=0; pize() { local tvar tok base T mo m rem op if [[ should_rotate -eq 0 ]]; then while read tok; do echo "P$tok"; done; else while read tok; do tvar=t$tok; let base=${!tvar:-0}; for mo in $modulos; do read m rem op <<<"${mo//:/ }"; [[ tok%m -eq rem ]] && let base+=op; done T=${rotate[base%4]} echo "P$tok$T"; done; fi } addop() { local op i left right case "$1" in r|R) let op=1;; l|L) let op=3;; d|D) let op=2;; *) err "unknown operation $1.";exit 5;; esac let should_rotate=1; for i in ${2//,/ }; do left="${i%%-*}" right="${i#*-}"; let modulo=0 remainder=0; if [[ "$right" =~ \~ ]]; then modulo=${right#*~}; right=${right%%~*}; fi if [[ "$modulo" =~ : ]]; then remainder=${modulo#*:}; modulo=${modulo%%:*}; fi if [[ -z "$right" && modulo -ge 1 && ( -z "$left" || "$left" = "~$modulo" || "$left" = "~$modulo:$remainder" ) ]]; then modulos="$modulos $modulo:$remainder:$op"; elif [[ left -eq 0 || right -eq 0 ]]; then err "not a page number: $left, $right."; exit 2; elif [[ left -eq right && modulo -le 1 ]]; then let t${left}+=op; else [[ modulo -le 1 ]] && let modulo=1; let remainder=remainder%modulo; for((i=left;i<=right;i++)); do [[ i%modulo -eq remainder ]] && let t${i}+=op; done fi done } calc() { while [ -n "$1" ]; do var="${1%%=*}"; term="${1#*=}" term="$(sed 's#[A-Za-z][A-Za-z0-9]*#$&#g;s#(#\\(#g;s#)#\\)#g' <<<"$term")" eval "term=$term" export $var=$(bc <<<"scale=8;$term"); shift done } round() { while [ -n "$1" ]; do var="${1%%=*}"; term="${1#*=}" term="$(sed 's#[A-Za-z][A-Za-z0-9]*#$&#g;s#(#\\(#g;s#)#\\)#g' <<<"$term")" eval "term=$term"; export $var=$(awk "BEGIN { printf(\"%.0f\",$term); }"); shift done } interleave() { both=$((pages/2)); rem=$((pages-2*both)) for((i=1; i<=both; i++)); do echo "O$i"; echo "E$i"; done [[ rem -gt 0 ]] && echo "O$((both+1))" } pdf_first_page_size() { pdfinfo "$1" | sed -n 's#Page size:[ \t]*\([0-9]*\)[ \t]*x\?[ \t]*\([0-9]*\).*#\2 \1 #p' } let num_slurp=3; pdf_page_size_awk() { local i let count=100; # [[ -z "$count" ]] && { err "\$count not set;"; exit 1; } { for((i=1;i<=num_slurp;i++)); do [[ i -gt count ]] && break; pdfinfo -f $i -box "$1"; done; echo; } | awk 'BEGIN { maxx=0; maxy=0; } /^MediaBox:/{ maxx=max(maxx,$5-$3); maxy=max(maxy,$4-$2); } END { print maxx, maxy; } function max(a,b) { if(a>=b) return a; return b; }' #pdfinfo -box "$1" | sed -n 's#MediaBox:[ \t]*[0-9]*[ \t]*[0-9]*[ \t]*\([0-9]*\)[ \t]*\([0-9]*\).*#\1 \2 #p' - or better right-left? } pdf_page_size() { gs -dNODISPLAY -dQUIET -SFile="$1" - <<EOQ File (r) file runpdfbegin % considers MediaBox of all pages 0 0 1 1 pdfpagecount { pdfgetpage /MediaBox pget { %oforce_array ==only % (\n) print aload pop % left bottom right top exch 3 1 roll sub neg 3 1 roll sub neg % top-bottom left-right (maxy, maxx, Δy, Δx) %=print ( ) print =print (\n) print 3 2 roll max % max, Δy, new_maxx 3 1 roll max % new_maxx, new_maxy exch } if } for =print ( ) print =print (\n) print % duplicate value of last page once more runpdfend quit EOQ } pdf_every_height() { gs -dNODISPLAY -dQUIET -SFile="$1" - <<EOQ File (r) file runpdfbegin 1 1 pdfpagecount { pdfgetpage /MediaBox pget { aload pop =print pop pop pop ( ) print } if } for % duplicate value of last page once more pdfpagecount pdfgetpage /MediaBox pget { aload pop =print pop pop pop } if runpdfend quit EOQ } do_pdfcrop() { { pdfcrop "$@" 2>&1 1>&3 | sed -n "s#.*Error: Cannot move \`\([^']*\)['] to \`\([^']*\)['].*#move\n\1\n\2#p" | { read command; if [ "$command" = "move" ]; then read movefrom; read moveto; mv "$movefrom" "$moveto"; echo mv "$movefrom" "$moveto"; else [[ -n "$command" ]] && echo "$command" >&2; fi } } 3>&1 | { if [[ verbosity -le 1 ]]; then egrep -v "PDFCROP.*Copyright| pages written on |^[ \t]*$" elif [[ verbosity -le 3 ]]; then grep -v "PDFCROP.*Copyright" else cat; fi }; } help() { cat <<EOQ $(basename $0) [opts] --horiz bs[,bs2] input.pdf [output.pdf] $(basename $0) [opts] --vert bs[,bs2] input.pdf [output.pdf] bs: size of gutter in mm (or the unit specified by --mm/--inch/--zoll); use f.i. 10 or 15 you may specify a different gutter size for even pages (bs2) separated by a colon from the one for odd pages default output file: input.bundsteg.pdf [opts]: -v/--verbose/-vv: be more verbose, -q/--quiet: be quiet --a4 (default) / --a4+ / --letter / --legal --mm (default) / --inch = --zoll --rl/rr/rd ~1 / 2,3-4 ... rotate all pages / pages 2,3-4 left, right or double (twice) --rr 7-18~3:1 ... rotate pages between 7 and 18 with modulo 3 = 1 --nup 2x1 ..... fold 2x1 input pages onto one output page --frame ..... draw a frame around each page, --align-bottom / --align-top --margin 4.2[,4.2[,4.2[,4.2]]] ... specify minimum margins (left,top,right,bottom) --[no-]nup-crop ... crop margins before nup; default is currently off because of an incompatibilty between pdfnup and pdfcrop. see also: $(basename $0) --license / --help, you may visit http[s]://www.elstel.org/bundsteg to look for a demo, docs or a new upstream version EOQ # for compatibility from older versions: --slurp 7 .... consider first seven pages for margin calculation (default: only three) } checkfound() { [ -f "$1" ] && return 0 echo "executable required: $1 ${2+-package} $2"; echo notfound=true; } checkfound_gs() { while [[ $# -ge 1 ]]; do gs="$(which "$1")"; [[ -n "$gs" ]] && [ -x "$gs" ] && return shift done echo "could not find the ghostscript." notfound=true } setmargins() { set -- ${1//,/ } $2 $3 $4 if [[ -z "$1" ]]; then calc 'li=4.2*72/25.4'; else calc "li=$1*unit"; fi shift; if [[ -z "$1" ]]; then ob=$li; else calc "ob=$1*unit"; fi shift; if [[ -z "$1" ]]; then re=$li; else calc "re=$1*unit"; fi shift; if [[ -z "$1" ]]; then un=$ob; else calc "un=$1*unit"; fi } if [[ "$1" = "--license" ]]; then license; fi let verbosity=1; nup=""; frame=false; align='top'; calc 'unit=72/25.4'; let nupcrop=-1; calc 'li=4.2*72/25.4' 're=li' 'ob=li' 'un=ob' calc 'breite=210*72/25.4' 'laenge=297*72/25.4' #calc 'li=0' 're=li' 'ob=0' 'un=ob' while [[ "${1:0:1}" = "-" ]]; do if [[ "${1:0:2}" != "--" ]]; then for((i=1;i<${#1};i++)); do case "${1:i:1}" in v) let verbosity++;; q) let verbosity--;; *) err "unknown short option -${1:i:1}."; exit 2; esac; done else case "$1" in --license) license;; --help) help; exit 0;; --verbose) let verbosity++;; --quiet) let verbosity--;; --mm) calc 'unit=72/25.4';; --inch|--zoll) unit="72";; --a4) calc 'breite=210*72/25.4' 'laenge=297*72/25.4';; --a4+) calc 'breite=215.9*72/25.4' 'laenge=330.2*72/25.4';; --letter) calc 'breite=8.5*72' 'laenge=11*72';; --legal) calc 'breite=8.5*72' 'laenge=14*72';; --rr) addop R "$2"; shift;; --rl) addop L "$2"; shift;; --rd) addop D "$2"; shift;; --nup) nup="$2"; shift;; --slurp) let num_slurp=$2; shift;; --frame) frame=true;; --bottom-align|--align-bottom) align='bottom';; --top-align|--align-top) align='top';; --margin) setmargins "$2"; shift;; --nupcrop) let nupcrop=1;; --no-nupcrop) let nupcrop=0;; --horiz|--vert|--landscape|--no-landscape) break;; *) err "unknown long option $1."; exit 2;; esac; fi shift; done if [[ verbosity -le 1 ]]; then dofork=1; else dofork=0; fi [[ nupcrop -lt 0 ]] && [[ -n "$nup" ]] && let nupcrop=0; # if [[ "$frame" = "true" ]]; then let nupcrop=1; else let nupcrop=0; fi if [[ $# -ne 3 && $# -ne 4 ]]; then help; else input="$3" if [[ $# -eq 4 ]]; then output="$4"; else output="${input%.pdf}.bundsteg.pdf"; fi notfound=false; #pdftools="wine /usr/local/advanced_pdf_tools_cmd_v3.0/pdftools.exe" #checkfound ${pdftools#* } http://www.verypdf.com/pdfinfoeditor/ checkfound $(which pdfcrop) texlive-extra-utils checkfound $(which pdfinfo) poppler-utils checkfound $(which pdftk) pdftk [[ -n "$nup" ]] && checkfound $(which pdfjam) texlive-extra-utils checkfound_gs gs gsos2 gswin64c gswin64 gswin32c gswin32 $notfound && exit 1 bs1=${2%%,*}; bs2=${2#*,}; # [[ bs1 -ge 0 && bs2 -ge 0 ]] || { echo "no valid value for bs (use 10 or 15 at 2nd param)";echo; exit 2; } calc 'bs1=bs1*unit' 'bs2=bs2*unit' if [[ "$1" = "--horiz" || "$1" = "--landscape" ]]; then calc 'li1=li' 'ob1=ob+bs1' 're2=re' 'un2=un+bs2' xext=$laenge; yext=$breite; # papersize="0 0 ${laenge%.*} ${breite%.*}" orientation="--landscape"; calc 'xextodd=xext-(li+re)' 'yextodd=yext-(ob1+un)' calc 'xexteven=xext-(li+re)' 'yexteven=yext-(ob+un2)' elif [[ "$1" = "--vert" || "$1" = "--no-landscape" ]]; then calc 'li1=li+bs1' 'ob1=ob' 're2=re+bs2' 'un2=un' xext=$breite; yext=$laenge; # papersize="0 0 ${breite%.*} ${laenge%.*}" orientation="--no-landscape"; calc 'xextodd=xext-(li1+re)' 'yextodd=yext-(ob+un)' calc 'xexteven=xext-(li+re2)' 'yexteven=yext-(ob+un)' else echo "final option param needs to be either --horiz or --vert."; exit 3; fi [[ "$frame" = "true" && -z "$nup" ]] && nup="1x1" #calc 'xextodd=xext-(li1+re)' 'yextodd=yext-(ob1+un)' #calc 'xexteven=xext-(li+re2)' 'yexteven=yext-(ob+un2)' [[ verbosity -ge 3 ]] && echo [[ verbosity -ge 3 ]] && echo "xext=$xext yext=$yext" [[ verbosity -ge 3 ]] && echo "xextodd=$xextodd ($li1 $ob1 $re $un) yextodd=$yextodd" [[ verbosity -ge 3 ]] && echo "xexteven=$xexteven ($li $ob $re2 $un2) yexteven=$yexteven" #echo "$xextodd $yextodd $li1 $ob1 $re $un"; exit 1; #pages=$(pdftools --countpages "$input") #pages=$(pdftools --info "$input" | sed -n 's#.*<pages>\([0-9]*\)</pages>*#\1#p') pages=$(pdftk "$input" dump_data | sed -n 's#^NumberOfPages:[ \t]*\([0-9]*\)#\1#p') unset pdf2rot crop4nup pdf2nup; trap 'rm -f $pdf2rot $crop4nup pdf2nup' EXIT; if [[ -n "$nup" ]]; then if [[ should_rotate -ne 0 ]]; then pdf2rot="$(mktemp --suffix _rotate.pdf;)"; if [[ verbosity -ge 2 ]]; then echo $'\n'"rotating pages: pdftk P='$input' cat $(seq 1 1 $pages | pize | tr '\n' ' ';) output $pdf2rot"; elif [[ verbosity -ge 1 ]]; then echo "rotating pages with pdftk."; fi pdftk P="$input" cat $(seq 1 1 $pages | pize;) output $pdf2rot input=$pdf2rot; let should_rotate=0; [[ verbosity -ge 2 ]] && echo fi if [[ nupcrop -ne 0 ]]; then crop4nup="$(mktemp --suffix _crop4nup.pdf;)"; [[ verbosity -ge 1 ]] && echo "pdfcrop before nup."; do_pdfcrop --margins "0 0 0 0" $input $crop4nup; input=$crop4nup; [[ verbosity -ge 2 ]] && echo fi pdf2nup="$(mktemp --suffix _nup.pdf;)"; [[ verbosity -ge 1 ]] && echo "pdfjam/pdfnup --nup $nup $orientation --frame $frame --outfile $pdf2nup '$input'"; if [[ verbosity -ge 3 ]]; then bequiet=""; else bequiet="--quiet"; fi pdfjam $bequiet --nup "$nup" $orientation --frame $frame --outfile $pdf2nup "$input" input=$pdf2nup [[ -n "$pdf2rot" ]] && { rm -f $pdf2rot; unset pdf2rot; } [[ -n "$crop4nup" ]] && { rm -f $crop4nup; unset crop4nup; } pages=$(pdftk "$input" dump_data | sed -n 's#^NumberOfPages:[ \t]*\([0-9]*\)#\1#p') [[ verbosity -ge 2 ]] && echo fi unset pdf4even pdf4odd mg4even mg4odd sc4even sc4odd bs4even bs4odd trap 'rm -f $pdf2nup $pdf4even $pdf4odd $mg4even $mg4odd $sc4even $sc4odd $bs4even $bs4odd' EXIT; [[ verbosity -ge 2 ]] && echo 'splitting odd and even pages.'; pdf4even=$(mktemp --suffix _even.pdf); pdf4odd=$(mktemp --suffix _odd.pdf) [[ verbosity -ge 2 ]] && { echo "odd: $(seq 1 2 $pages | pize | tr '\n' ' ';)"; echo "even: $(seq 2 2 $pages | pize | tr '\n' ' ';)"; } pdftk P="$input" cat $(seq 1 2 $pages | pize;) output $pdf4odd pdftk P="$input" cat $(seq 2 2 $pages | pize;) output $pdf4even [[ -n "$pdf2nup" ]] && { rm -f $pdf2nup; unset pdf2nup; } mg4odd=$(mktemp --suffix _odd-mg.pdf); mg4even=$(mktemp --suffix _even-mg.pdf) bs4odd=$(mktemp --suffix _odd-bs.pdf); bs4even=$(mktemp --suffix _even-bs.pdf); oddpages() { [[ verbosity -ge 3 ]] && echo $'---------------------------------------------------------------------------\n' [[ verbosity -ge 3 ]] && pdfinfo $pdf4odd [[ verbosity -ge 2 ]] && echo [[ verbosity -ge 1 ]] && echo " odd pages: removing margins <$pdf4odd >$mg4odd" do_pdfcrop --margins "0 0 0 0" $pdf4odd $mg4odd; rm -f $pdf4odd read xcropodd ycropodd < <( pdf_page_size $mg4odd; ); [[ verbosity -ge 3 ]] && echo "$xcropodd x $ycropodd" [[ verbosity -ge 3 ]] && pdfinfo $mg4odd read -d '\n' scaleodd addxodd addyodd liodd unodd obodd < <( bc <<EOQ scale=8; define min(x,y) { if(x<=y) return x; return y; } s = min( $xextodd / $xcropodd, $yextodd / $ycropodd ); s addx = 0.5 * ( $xextodd - $xcropodd * s ) + 0.5 addx addy = 0.5 * ( $yextodd - $ycropodd * s ) + 0.5 addy $li1 + addx $un + addy $ob1 + addy EOQ ); [[ verbosity -ge 3 ]] && echo "scalodd=$scaleodd addxodd=$addxodd addyodd=$addyodd liodd=$liodd unodd=$unodd obodd=$obodd"; [[ verbosity -ge 2 ]] && echo [[ verbosity -ge 1 ]] && echo " odd pages: re-adding margins <$mg4odd >$bs4odd" # unused option: -dFitPage may not allow the exact devwidth & devheight given but rather preserve the aspect ratio if [[ "$align" = "top" ]]; then pageheightsodd="$(pdf_every_height $mg4odd)"; [[ verbosity -ge 3 ]] && { echo "page heights (+dup last): $pageheightsodd"; } $gs -sDEVICE=pdfwrite -dFIXEDMEDIA -dDEVICEWIDTHPOINTS=${xext} -dDEVICEHEIGHTPOINTS=${yext} -dBATCH -dQUIET -dNOPAUSE -sOutputFile=$bs4odd -c "<< /Install { $liodd currentpagedevice /PageSize get aload pop exch pop [$pageheightsodd] currentpagedevice /PageCount get get $scaleodd mul sub $obodd sub translate $scaleodd $scaleodd scale } bind >> setpagedevice" -f $mg4odd else $gs -sDEVICE=pdfwrite -dFIXEDMEDIA -dDEVICEWIDTHPOINTS=${xext} -dDEVICEHEIGHTPOINTS=${yext} -dBATCH -dQUIET -dNOPAUSE -sOutputFile=$bs4odd -c "<< /Install { $liodd $unodd translate $scaleodd $scaleodd scale } bind >> setpagedevice" -f $mg4odd fi rm -f $mg4odd #do_pdfcrop --bbox "0 0 $xextodd $yextodd" --margins "$li1 $ob1 $re $un" $sc4odd $bs4odd; rm -f $sc4odd [[ verbosity -ge 3 ]] && pdfinfo $bs4odd } evenpages() { [[ verbosity -ge 3 ]] && echo $'\n---------------------------------------------------------------------------\n' [[ verbosity -ge 3 ]] && pdfinfo $pdf4even [[ verbosity -ge 2 ]] && echo [[ verbosity -ge 1 ]] && echo " even pages: removing margins <$pdf4even >$mg4even" do_pdfcrop --margins "0 0 0 0" $pdf4even $mg4even; rm -f $pdf4even read xcropeven ycropeven < <( pdf_page_size $mg4even; ); [[ verbosity -ge 3 ]] && echo "$xcropeven x $ycropeven" [[ verbosity -ge 3 ]] && pdfinfo $mg4even read -d '\n' scaleeven addxeven addyeven lieven uneven obeven < <( bc <<EOQ scale=8; define min(x,y) { if(x<=y) return x; return y; } s = min( $xexteven / $xcropeven, $yexteven / $ycropeven ); s addx = 0.5 * ( $xexteven - $xcropeven * s ) + 0.5 addx addy = 0.5 * ( $yexteven - $ycropeven * s ) + 0.5 addy $li + addx $un2 + addy $ob + addy EOQ ); [[ verbosity -ge 3 ]] && echo "scaleven=$scaleeven addxeven=$addxeven addyeven=$addyeven lieven=$lieven uneven=$uneven obeven=$obeven"; [[ verbosity -ge 2 ]] && echo [[ verbosity -ge 1 ]] && echo " even pages: re-adding margins <$mg4even >$bs4even" if [[ "$align" = "top" ]]; then pageheightseven="$(pdf_every_height $mg4even)"; [[ verbosity -ge 3 ]] && { echo "page heights (+dup last): $pageheightseven"; } $gs -sDEVICE=pdfwrite -dFIXEDMEDIA -dDEVICEWIDTHPOINTS=${xext} -dDEVICEHEIGHTPOINTS=${yext} -dBATCH -dQUIET -dNOPAUSE -sOutputFile=$bs4even -c "<< /Install { $lieven currentpagedevice /PageSize get aload pop exch pop [$pageheightseven] currentpagedevice /PageCount get get $scaleeven mul sub $obeven sub translate $scaleeven $scaleeven scale } bind >> setpagedevice" -f $mg4even else $gs -sDEVICE=pdfwrite -dFIXEDMEDIA -dDEVICEWIDTHPOINTS=${xext} -dDEVICEHEIGHTPOINTS=${yext} -dBATCH -dQUIET -dNOPAUSE -sOutputFile=$bs4even -c "<< /Install { $lieven $uneven translate $scaleeven $scaleeven scale } bind >> setpagedevice" -f $mg4even fi rm -f $mg4even #do_pdfcrop --bbox "0 0 $xexteven $yexteven" --margins "$li $ob $re2 $un2" $sc4even $bs4even; rm -f $sc4even [[ verbosity -ge 3 ]] && pdfinfo $bs4even #okular $bs4even } if [[ dofork -eq 0 ]]; then oddpages evenpages else set +m oddpages & pid4odd=$! evenpages wait $pid4odd set -m fi [[ verbosity -ge 3 ]] && echo $'\n---------------------------------------------------------------------------\n' if [[ verbosity -ge 3 ]]; then echo $'\n'" pdftk E=$bs4even O=$bs4odd cat $(interleave | tr '\n' ' ') output \"$output\"" elif [[ verbosity -ge 2 ]]; then echo $'\n'"combining odd and even pages."; elif [[ verbosity -ge 1 ]]; then echo "combining odd and even pages."; fi [[ verbosity -gt 3 ]] && pdftkverbose=verbose pdftk E=$bs4even O=$bs4odd cat $(interleave) output "$output" $pdftkverbose rm -f $bs4even $bs4odd trap '' EXIT; if [[ verbostiy -ge 2 ]]; then echo $'\n'; else echo; fi fi
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor