[pdftex] update to pdfbook utility
Jaap Eldering
eldering at phys.uu.nl
Tue Jul 26 11:52:34 CEST 2005
Hi all,
I recently was searching for a pdf utility to convert documents to a
book format like psbook+psnup+pstops and found a previous post to this
list: http://www.tug.org/pipermail/pdftex/2004-February/004760.html
I rewrote parts of this small program, because it didn't completely
fit my needs (although a good starting point).
Changes to the original include:
- using layout "nup=1x2" is optional.
- included option to pass parameters directly to pdfpages command,
which generates the new document: makes it easier to e.g. also make
a booklet from A4 to A6 (2 copies) using:
pdfbook -o 'pages=-,doublepages=true,nup=2x2,column=true'
- generate everything in a temporary directory to avoid filename
conflicts, race conditions, etc.
- fixed bug when filenames contained more than one `.'.
- the option to output pages in reverse order was lost in the process,
as I have no experience with that (I'm not Hebrew ;-).
Might be useful for others...
Kind regards,
Jaap Eldering
===============================================
/*
* $Id: pdfbook.c 1507 2005-06-16 21:23:50Z root $
*
* pdfbook.c Rearrange pages in a PDF file into signatures.
*
*
* Original author Tigran Aivazian <tigran at aivazian.fsnet.co.uk>
* Modifications by Jaap Eldering <eldering at a-eskwadraat.nl>
*
* Based on the algorithm from psutils/psbook.c, which was
* written by Angus J. C. Duggan 1991-1995.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <libgen.h>
#include <unistd.h>
#define TMP_INFILE_BASE "input"
#define TMP_OUTFILE_BASE "output"
char *program;
static void usage(void)
{
fprintf(stderr, "Usage: %s [-q] [-2] [-s <signature>] infile outfile\n"
" or: %s [-q] -o <options> infile outfile\n"
"Rearrange pages for printing as booklet.\n\n"
"Options:\n"
" -q suppress verbose output\n"
" -2 place 2 pages on 1 page of output\n"
" -s group pages together in groups of size <signature>\n"
" <signature> must be positive and divisible by 4\n"
" -o pass <options> directly to LaTeX pdfpages `includepdf' command\n"
" see the pdfpages package documentation for possible options\n",
program, program);
fflush(stderr);
exit(1);
}
char *make_tempdir()
{
static char dirtemplate[L_tmpnam+10];
char *dirname;
if ( (dirname = tempnam(NULL, "pdfbk")) == NULL ) {
fprintf(stderr, "%s: error generating temporary directory\n", program);
exit(1);
}
strcpy(dirtemplate, dirname);
strcat(dirtemplate, "XXXXXX");
if ( (dirname = mkdtemp(dirtemplate)) == NULL ) {
fprintf(stderr, "%s: error generating temporary directory\n", program);
exit(1);
}
return dirname;
}
char *allocstr(char *format, ...)
{
va_list ap;
char *str;
char tmp[2];
int len, n;
va_start(ap,format);
len = vsnprintf(tmp,1,format,ap);
va_end(ap);
if ( (str = (char *) malloc(len+1))==NULL ) return NULL;
va_start(ap,format);
n = vsnprintf(str,len+1,format,ap);
va_end(ap);
if ( n==-1 || n>len ) return NULL;
return str;
}
int main(int argc, char *argv[])
{
char *infile = NULL;
char *outfile = NULL;
char *tmpdir;
char *tmptexfile;
char *tmpinfile;
char *tmpoutfile;
FILE *fp, *fout;
int *actualpg;
static char cmdline[1024];
int quiet = 0;
int nup = 0;
int pdfcustom = 0;
int signature = 0;
int npages = 0;
int maxpage;
char *pdfcustom_str = NULL;
int i, c;
program = argv[0];
tmpdir = make_tempdir();
while ( (c = getopt(argc, argv, "s:2o:q")) != -1 ) {
switch (c) {
case 's':
signature = atoi(optarg);
if (signature < 1 || signature % 4)
usage();
break;
case '2':
nup = 1;
break;
case 'o':
pdfcustom = 1;
if ( (pdfcustom_str = strdup(optarg)) == NULL ) {
fprintf(stderr, "%s: error allocating memory\n", program);
exit(1);
}
break;
case 'q':
quiet = 1;
break;
default:
usage();
}
}
if ( optind<argc ) {
infile = argv[optind++];
} else {
fprintf(stderr, "%s: input file must be specified\n", program);
usage();
}
if ( optind<argc ) {
outfile = argv[optind++];
} else {
fprintf(stderr, "%s: output file must be specified\n", program);
usage();
}
if ( pdfcustom && (nup || signature) ) {
fprintf(stderr, "%s: option -o cannot be combined with other options\n", program);
usage();
}
sprintf(cmdline, "pdfinfo %s | sed -ne \"s/Pages: *\\([0-9]*\\)/\\1/p\"", infile);
fp = popen(cmdline, "r");
if (fscanf(fp, "%d", &npages) != 1) {
fprintf(stderr, "%s: error reading \"%s\"\n", program, infile);
exit(1);
}
if (npages < 1) {
fprintf(stderr, "%s: invalid number of pages=%d\n", program, npages);
exit(1);
}
if ( (tmptexfile = allocstr("%s/%s.tex",tmpdir,TMP_OUTFILE_BASE)) == NULL ) {
fprintf(stderr, "%s: error allocating memory\n", program);
exit(1);
}
if ( (tmpinfile = allocstr("%s/%s.pdf",tmpdir,TMP_INFILE_BASE)) == NULL ) {
fprintf(stderr, "%s: error allocating memory\n", program);
exit(1);
}
if ( (tmpoutfile = allocstr("%s/%s.pdf",tmpdir,TMP_OUTFILE_BASE)) == NULL ) {
fprintf(stderr, "%s: error allocating memory\n", program);
exit(1);
}
fout = fopen(tmptexfile, "w");
if (!fout) {
fprintf(stderr, "%s: error opening \"%s\" for write\n",
program, tmptexfile);
exit(1);
}
if (!signature)
signature = maxpage = npages + (4 - npages%4)%4;
else
maxpage = npages + (signature - npages%signature)%signature;
if ( (actualpg = (int *) calloc(maxpage,sizeof(int))) == NULL ) {
fprintf(stderr, "%s: error allocating memory\n", program);
exit(1);
}
for (i=0; i<maxpage; i++) {
int actual = i - i%signature;
switch (i%4) {
case 0:
case 3:
actual += signature - 1 - (i%signature)/2;
break;
case 1:
case 2:
actual += (i%signature)/2;
break;
}
if (actual < npages)
actualpg[i] = actual + 1;
}
fprintf(fout,
"\\documentclass{book}\n"
"\\usepackage{pdfpages}\n"
"\\begin{document}\n");
if ( pdfcustom ) {
fprintf(fout, "\\includepdf[%s]", pdfcustom_str);
} else {
if ( nup ) {
fprintf(fout,"\\includepdf[pages=-,signature=%d , landscape]",signature);
} else {
fprintf(fout,"\\includepdf[pages={");
for (i=0; i<maxpage; i++) {
if (actualpg[i]) {
fprintf(fout, "%d", actualpg[i]);
} else {
fprintf(fout, "{}");
}
fprintf(fout, "%s", i<maxpage-1 ? "," : "");
}
fprintf(fout,"}]");
}
}
fprintf(fout,"{%s.pdf}\n\\end{document}\n", TMP_INFILE_BASE);
fclose(fout);
if (!quiet)
printf("%s: Generating output file now, please wait...\n", program);
sprintf(cmdline, "cp %s %s", infile, tmpinfile);
if (system(cmdline)) {
fprintf(stderr, "%s: Failed to copy \"%s\" file to \"%s\"\n",
program, tmpoutfile, tmpinfile);
exit(1);
}
sprintf(cmdline, "cd %s && pdflatex %s > /dev/null 2>&1 < /dev/null",
tmpdir, tmptexfile);
if (system(cmdline)) {
fprintf(stderr, "%s: Failed to generate output, see \"%s/%s.log\" for details\n",
program, tmpdir, TMP_OUTFILE_BASE);
exit(1);
}
sprintf(cmdline, "cp %s %s", tmpoutfile, outfile);
if (system(cmdline)) {
fprintf(stderr, "%s: Failed to write \"%s\" file\n",
program, outfile);
exit(1);
}
sprintf(cmdline, "rm -rf %s", tmpdir);
system(cmdline);
return 0;
}
More information about the pdftex
mailing list