summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Jamrules2
-rw-r--r--apps/Jamfile6
-rw-r--r--apps/pdfclean.c184
-rw-r--r--apps/pdfdebug.c190
-rw-r--r--apps/pdfmerge.c224
-rw-r--r--apps/pdfrip.c290
-rw-r--r--apps/pdfselect.c299
-rw-r--r--apps/pdftool.c874
-rw-r--r--apps/samshow.c30
-rw-r--r--base/base_error.c16
-rw-r--r--include/fitz/base_runtime.h1
11 files changed, 901 insertions, 1215 deletions
diff --git a/Jamrules b/Jamrules
index 1b344bfa..ee06b007 100644
--- a/Jamrules
+++ b/Jamrules
@@ -43,7 +43,7 @@ switch $(OS)
NEED_STRLCAT = yes ;
NEED_STRSEP = yes ;
FLAG_CCALL += -std=gnu99 -DHAVE_C99 ;
- FLAG_LDALL += -L/usr/X11R6/lib ;
+ FLAG_LDALL += -L/opt/local/lib -L/usr/X11R6/lib ;
switch $(CC)-$(OSPLAT)
{
diff --git a/apps/Jamfile b/apps/Jamfile
index 4accf75a..672b8671 100644
--- a/apps/Jamfile
+++ b/apps/Jamfile
@@ -6,11 +6,7 @@
SubDir TOP apps ;
APPLIST =
- pdfrip
- pdfclean
- pdfdebug
- pdfmerge
- pdfselect
+ pdftool
samshow
;
diff --git a/apps/pdfclean.c b/apps/pdfclean.c
deleted file mode 100644
index 05bef10f..00000000
--- a/apps/pdfclean.c
+++ /dev/null
@@ -1,184 +0,0 @@
-#include <fitz.h>
-#include <mupdf.h>
-
-void usage()
-{
- fprintf(stderr,
- "usage: pdfclean [options] infile.pdf outfile.pdf\n"
- " -d -\tpassword for decryption\n"
- " -g \tgarbage collect unused objects\n"
- " -r \trebuild xref table\n"
- " -x \texpand compressed streams\n"
- " -e \tencrypt outfile\n"
- " -u -\tset user password for encryption\n"
- " -o -\tset owner password\n"
- " -p -\tset permissions (combine letters 'pmca')\n"
- " -n -\tkey length in bits: 40 <= n <= 128\n"
- );
- exit(1);
-}
-
-void preloadobjstms(pdf_xref *xref)
-{
- fz_error *error;
- fz_obj *obj;
- int i;
-
- for (i = 0; i < xref->len; i++)
- {
- if (xref->table[i].type == 'o')
- {
- error = pdf_loadobject(&obj, xref, i, 0);
- if (error) fz_abort(error);
- fz_dropobj(obj);
- }
- }
-}
-
-void expandstreams(pdf_xref *xref)
-{
- fz_error *error;
- fz_obj *stmobj;
- fz_buffer *buf;
- fz_obj *stmlen;
- int i, gen;
-
- for (i = 0; i < xref->len; i++)
- {
- if (xref->table[i].type == 'n')
- {
- gen = xref->table[i].gen;
-
- if (pdf_isstream(xref, i, gen))
- {
- error = pdf_loadobject(&stmobj, xref, i, gen);
- if (error) fz_abort(error);
-
- error = pdf_loadstream(&buf, xref, i, gen);
- if (error) fz_abort(error);
-
- fz_dictdels(stmobj, "Filter");
- fz_dictdels(stmobj, "DecodeParms");
-
- error = fz_newint(&stmlen, buf->wp - buf->rp);
- if (error) fz_abort(error);
- error = fz_dictputs(stmobj, "Length", stmlen);
- if (error) fz_abort(error);
- fz_dropobj(stmlen);
-
- pdf_updateobject(xref, i, gen, stmobj);
- pdf_updatestream(xref, i, gen, buf);
-
- fz_dropobj(stmobj);
- }
- }
- }
-}
-
-int main(int argc, char **argv)
-{
- fz_error *error;
- char *infile;
- char *outfile;
- pdf_xref *xref;
- int c;
-
- pdf_crypt *encrypt = 0;
- int doencrypt = 0;
- int dorepair = 0;
- int doexpand = 0;
- int dogc = 0;
-
- char *userpw = "";
- char *ownerpw = "";
- unsigned perms = 0xfffff0c0; /* nothing allowed */
- int keylen = 40;
- char *password = "";
-
- while ((c = getopt(argc, argv, "rgxd:eu:o:p:n:")) != -1)
- {
- switch (c)
- {
- case 'r': ++ dorepair; break;
- case 'x': ++ doexpand; break;
- case 'g': ++ dogc; break;
- case 'e': ++ doencrypt; break;
- case 'u': userpw = optarg; break;
- case 'o': ownerpw = optarg; break;
- case 'p':
- /* see TABLE 3.15 User access permissions */
- perms = 0xfffff0c0;
- if (strchr(optarg, 'p')) /* print */
- perms |= (1 << 2) | (1 << 11);
- if (strchr(optarg, 'm')) /* modify */
- perms |= (1 << 3) | (1 << 10);
- if (strchr(optarg, 'c')) /* copy */
- perms |= (1 << 4) | (1 << 9);
- if (strchr(optarg, 'a')) /* annotate / forms */
- perms |= (1 << 5) | (1 << 8);
- break;
- case 'n': keylen = atoi(optarg); break;
- case 'd': password = optarg; break;
- default: usage();
- }
- }
-
- if (argc - optind < 2)
- usage();
-
- infile = argv[optind++];
- outfile = argv[optind++];
-
- error = pdf_newxref(&xref);
-
- if (dorepair)
- error = pdf_repairxref(xref, infile);
- else
- error = pdf_loadxref(xref, infile);
- if (error)
- fz_abort(error);
-
- error = pdf_decryptxref(xref);
- if (error)
- fz_abort(error);
-
- if (xref->crypt)
- {
- error = pdf_setpassword(xref->crypt, password);
- if (error) fz_abort(error);
- }
-
- if (doencrypt)
- {
- fz_obj *id = fz_dictgets(xref->trailer, "ID");
- if (!id)
- fz_packobj(&id, "[(ABCDEFGHIJKLMNOP)(ABCDEFGHIJKLMNOP)]");
- else
- fz_keepobj(id);
- error = pdf_newencrypt(&encrypt, userpw, ownerpw, perms, keylen, id);
- if (error)
- fz_abort(error);
- fz_dropobj(id);
- }
-
- if (doexpand)
- expandstreams(xref);
-
- if (dogc)
- {
- preloadobjstms(xref);
- pdf_garbagecollect(xref);
- }
-
- error = pdf_savexref(xref, outfile, encrypt);
- if (error)
- fz_abort(error);
-
- if (encrypt)
- pdf_dropcrypt(encrypt);
-
- pdf_closexref(xref);
-
- return 0;
-}
-
diff --git a/apps/pdfdebug.c b/apps/pdfdebug.c
deleted file mode 100644
index 3a3f8321..00000000
--- a/apps/pdfdebug.c
+++ /dev/null
@@ -1,190 +0,0 @@
-#include <fitz.h>
-#include <mupdf.h>
-
-static char *password = "";
-static int dodecode = 0;
-static int doprintxref = 0;
-
-void usage()
-{
- fprintf(stderr, "usage: pdfdebug [-dx] [-u password] file.pdf [oid ...]\n");
- exit(1);
-}
-
-/*
- * Debug-print stream contents
- */
-
-static int safecol = 0;
-
-void printsafe(unsigned char *buf, int n)
-{
- int i;
- for (i = 0; i < n; i++) {
- if (buf[i] == '\r' || buf[i] == '\n') {
- printf("\n");
- safecol = 0;
- }
- else if (buf[i] < 32 || buf[i] > 126) {
- printf(".");
- safecol ++;
- }
- else {
- printf("%c", buf[i]);
- safecol ++;
- }
- if (safecol == 79) {
- printf("\n");
- safecol = 0;
- }
- }
-}
-
-void decodestream(pdf_xref *xref, int oid, int gid)
-{
- fz_error *error;
- fz_stream *stm;
- unsigned char buf[512];
-
- safecol = 0;
-
- error = pdf_openstream(&stm, xref, oid, gid);
- if (error) fz_abort(error);
-
- while (1)
- {
- int n = fz_read(stm, buf, sizeof buf);
- if (n == 0)
- break;
- if (n < 0)
- fz_abort(fz_ioerror(stm));
- printsafe(buf, n);
- }
-
- fz_dropstream(stm);
-}
-
-void copystream(pdf_xref *xref, int oid, int gid)
-{
- fz_error *error;
- fz_stream *stm;
- unsigned char buf[512];
-
- safecol = 0;
-
- error = pdf_openrawstream(&stm, xref, oid, gid);
- if (error) fz_abort(error);
-
- while (1)
- {
- int n = fz_read(stm, buf, sizeof buf);
- if (n == 0)
- break;
- if (n < 0)
- fz_abort(fz_ioerror(stm));
- printsafe(buf, n);
- }
-
- fz_dropstream(stm);
-}
-
-void printobject(pdf_xref *xref, int oid, int gid)
-{
- fz_error *error;
- fz_obj *obj;
-
- error = pdf_loadobject(&obj, xref, oid, gid);
- if (error) fz_abort(error);
-
- printf("%d %d obj\n", oid, gid);
- fz_debugobj(obj);
- printf("\n");
-
- if (xref->table[oid].stmofs) {
- printf("stream\n");
- if (dodecode)
- decodestream(xref, oid, gid);
- else
- copystream(xref, oid, gid);
- printf("endstream\n");
- }
-
- printf("endobj\n");
-
- fz_dropobj(obj);
-}
-
-int main(int argc, char **argv)
-{
- fz_error *error;
- char *filename;
- pdf_xref *xref;
- int c;
-
- while ((c = getopt(argc, argv, "dxu:")) != -1)
- {
- switch (c)
- {
- case 'd':
- dodecode ++;
- break;
- case 'x':
- doprintxref ++;
- break;
- case 'u':
- password = optarg;
- break;
- default:
- usage();
- }
- }
-
- if (argc - optind == 0)
- usage();
-
- filename = argv[optind++];
-
- error = pdf_newxref(&xref);
- if (error)
- fz_abort(error);
-
- error = pdf_loadxref(xref, filename);
- if (error)
- {
- fz_warn("trying to repair");
- error = pdf_repairxref(xref, filename);
- if (error)
- fz_abort(error);
- }
-
- error = pdf_decryptxref(xref);
- if (error)
- fz_abort(error);
-
- if (xref->crypt)
- {
- error = pdf_setpassword(xref->crypt, password);
- if (error) fz_abort(error);
- }
-
- if (optind == argc)
- {
- printf("trailer\n");
- fz_debugobj(xref->trailer);
- printf("\n");
- }
-
- for ( ; optind < argc; optind++)
- {
- printobject(xref, atoi(argv[optind]), 0);
- printf("\n");
- }
-
- if (doprintxref)
- pdf_debugxref(xref);
-
- pdf_closexref(xref);
-
- return 0;
-}
-
diff --git a/apps/pdfmerge.c b/apps/pdfmerge.c
deleted file mode 100644
index 8c431308..00000000
--- a/apps/pdfmerge.c
+++ /dev/null
@@ -1,224 +0,0 @@
-#include <fitz.h>
-#include <mupdf.h>
-
-void usage()
-{
- fprintf(stderr,
- "usage: pdfmerge [options] file1.pdf file2.pdf ...\n"
- " -d -\tpassword for decryption\n"
- " -o -\toutput file name (default out.pdf)\n"
- " -v \tverbose\n"
- );
- exit(1);
-}
-
-int main(int argc, char **argv)
-{
- fz_error *error;
- char *savename = "out.pdf";
- pdf_pagetree *srcpages;
- fz_obj *srcrefs;
- fz_obj *newsrcrefs;
- fz_obj *dstrefs;
- pdf_xref *dst;
- pdf_xref *src;
- int rootoid;
- int rootgid;
- int pagesoid;
- int pagesgid;
- fz_obj *pagesref;
- fz_obj *obj;
- int i, k;
- int c;
-
- int verbose = 0;
- char *password = "";
-
- while ((c = getopt(argc, argv, "vo:d:")) != -1)
- {
- switch (c)
- {
- case 'v': ++ verbose; break;
- case 'o': savename = optarg; break;
- case 'd': password = optarg; break;
- default: usage();
- }
- }
-
- if (argc - optind < 1)
- usage();
-
- /*
- * Create new blank xref table
- */
-
- error = pdf_newxref(&dst);
- if (error)
- fz_abort(error);
-
- error = pdf_initxref(dst);
- if (error)
- fz_abort(error);
-
- error = fz_newarray(&dstrefs, 100);
- if (error)
- fz_abort(error);
-
- /*
- * Copy pages saving refs in dstrefs
- */
-
- for (i = optind; i < argc; i++)
- {
- if (verbose)
- {
- printf("loading pdf '%s' ", argv[i]);
- fflush(stdout);
- }
-
- error = pdf_newxref(&src);
- if (error)
- fz_abort(error);
-
- error = pdf_loadxref(src, argv[i]);
- if (error)
- fz_abort(error);
-
- error = pdf_decryptxref(src);
- if (error)
- fz_abort(error);
-
- if (src->crypt)
- {
- error = pdf_setpassword(src->crypt, password);
- if (error)
- fz_abort(error);
- }
-
- error = pdf_loadpagetree(&srcpages, src);
- if (error)
- fz_abort(error);
-
- error = fz_newarray(&srcrefs, 100);
- if (error)
- fz_abort(error);
-
- if (verbose)
- printf("(%d pages)\n", srcpages->count);
-
- for (k = 0; k < srcpages->count; k++)
- {
- fz_dictdels(srcpages->pobj[k], "Parent");
- fz_dictdels(srcpages->pobj[k], "B");
- fz_dictdels(srcpages->pobj[k], "PieceInfo");
- fz_dictdels(srcpages->pobj[k], "Metadata");
- fz_dictdels(srcpages->pobj[k], "Annots");
- fz_dictdels(srcpages->pobj[k], "Tabs");
-
- pdf_updateobject(src,
- fz_tonum(srcpages->pref[k]),
- fz_togen(srcpages->pref[k]),
- srcpages->pobj[k]);
- error = fz_arraypush(srcrefs, srcpages->pref[k]);
- if (error)
- fz_abort(error);
- }
-
- error = pdf_transplant(dst, src, &newsrcrefs, srcrefs);
- if (error)
- fz_abort(error);
-
- for (k = 0; k < fz_arraylen(newsrcrefs); k++)
- {
- error = fz_arraypush(dstrefs, fz_arrayget(newsrcrefs, k));
- if (error)
- fz_abort(error);
- }
-
- fz_dropobj(srcrefs);
- fz_dropobj(newsrcrefs);
-
- pdf_droppagetree(srcpages);
-
- pdf_closexref(src);
- }
-
- /*
- * Create and relink Pages object
- */
-
- if (verbose)
- printf("creating pdf '%s' (%d pages)\n",
- savename, fz_arraylen(dstrefs));
-
- error = pdf_allocobject(dst, &pagesoid, &pagesgid);
- if (error)
- fz_abort(error);
-
- error = fz_packobj(&obj,
- "<</Type/Pages/Count %i/Kids %o>>",
- fz_arraylen(dstrefs),
- dstrefs);
- if (error)
- fz_abort(error);
-
- pdf_updateobject(dst, pagesoid, pagesgid, obj);
-
- fz_dropobj(obj);
-
- error = fz_newindirect(&pagesref, pagesoid, pagesgid);
- if (error)
- fz_abort(error);
-
- for (i = 0; i < fz_arraylen(dstrefs); i++)
- {
- int oid = fz_tonum(fz_arrayget(dstrefs, i));
- int gid = fz_togen(fz_arrayget(dstrefs, i));
- error = pdf_loadobject(&obj, dst, oid, gid);
- if (error)
- fz_abort(error);
- error = fz_dictputs(obj, "Parent", pagesref);
- if (error)
- fz_abort(error);
- pdf_updateobject(dst, oid, gid, obj);
- fz_dropobj(obj);
- }
-
- fz_dropobj(pagesref);
-
- /*
- * Create Catalog and trailer
- */
-
- error = pdf_allocobject(dst, &rootoid, &rootgid);
- if (error)
- fz_abort(error);
-
- error = fz_packobj(&obj,
- "<</Type/Catalog/Pages %r>>",
- pagesoid, pagesgid);
- if (error)
- fz_abort(error);
-
- pdf_updateobject(dst, rootoid, rootgid, obj);
-
- fz_dropobj(obj);
-
- error = fz_packobj(&dst->trailer, "<</Root %r>>", rootoid, rootgid);
- if (error)
- fz_abort(error);
-
- /*
- * Write out the new PDF
- */
-
- error = pdf_savexref(dst, savename, nil);
- if (error)
- fz_abort(error);
-
- fz_dropobj(dstrefs);
- pdf_closexref(dst);
-
- return 0;
-}
-
diff --git a/apps/pdfrip.c b/apps/pdfrip.c
deleted file mode 100644
index 59d0fa48..00000000
--- a/apps/pdfrip.c
+++ /dev/null
@@ -1,290 +0,0 @@
-#include <fitz.h>
-#include <mupdf.h>
-
-int showtree = 0;
-float zoom = 1.0;
-char *namefmt = nil;
-fz_renderer *gc;
-int nbands = 1;
-int verbose = 0;
-int textonly = 0;
-
-void usage()
-{
- fprintf(stderr,
-"usage: pdfrip [options] file.pdf pageranges\n"
-" -b -\trender page in N bands (default 1)\n"
-" -d -\tpassword for decryption\n"
-" -g \tshow display tree -- debug\n"
-" -o -\toutput filename format (default out-%%03d.ppm)\n"
-" -t \tprint text on stdout instead of rendering\n"
-" -v \tverbose\n"
-" -z -\tzoom factor (default 1.0 = 72 dpi)\n"
- );
- exit(1);
-}
-
-/*
- * Draw page
- */
-
-void showpage(pdf_xref *xref, fz_obj *pageobj, int pagenum)
-{
- fz_error *error;
- pdf_page *page;
- char namebuf[256];
- char buf[128];
- fz_pixmap *pix;
- fz_matrix ctm;
- fz_irect bbox;
- int fd;
- int x, y;
- int w, h;
- int b, bh;
-
- if (verbose)
- printf("page %d\n", pagenum);
-
- sprintf(namebuf, namefmt, pagenum);
-
- error = pdf_loadpage(&page, xref, pageobj);
- if (error)
- fz_abort(error);
-
- if (showtree)
- {
- fz_debugobj(pageobj);
- printf("\n");
-
- printf("page\n");
- printf(" mediabox [ %g %g %g %g ]\n",
- page->mediabox.x0, page->mediabox.y0,
- page->mediabox.x1, page->mediabox.y1);
- printf(" rotate %d\n", page->rotate);
-
- printf(" resources\n");
- fz_debugobj(page->resources);
- printf("\n");
-
- printf("tree\n");
- fz_debugtree(page->tree);
- printf("endtree\n");
- }
-
- ctm = fz_concat(fz_translate(0, -page->mediabox.y1),
- fz_scale(zoom, -zoom));
-
- if (textonly)
- {
- pdf_textline *line;
-
- error = pdf_loadtextfromtree(&line, page->tree, ctm);
- if (error)
- fz_abort(error);
- pdf_debugtextline(line);
- pdf_droptextline(line);
- pdf_droppage(page);
-
- printf("\n\f\n");
-
- return;
- }
-
- bbox = fz_roundrect(page->mediabox);
- bbox.x0 = bbox.x0 * zoom;
- bbox.y0 = bbox.y0 * zoom;
- bbox.x1 = bbox.x1 * zoom;
- bbox.y1 = bbox.y1 * zoom;
- w = bbox.x1 - bbox.x0;
- h = bbox.y1 - bbox.y0;
- bh = h / nbands;
-
- fd = open(namebuf, O_BINARY|O_WRONLY|O_CREAT|O_TRUNC, 0666);
- if (fd < 0)
- fz_abort(fz_throw("open %s failed: %s", namebuf, strerror(errno)));
- sprintf(buf, "P6\n%d %d\n255\n", w, bh * nbands);
- write(fd, buf, strlen(buf));
-
- error = fz_newpixmap(&pix, bbox.x0, bbox.y0, w, bh, 4);
- if (error)
- fz_abort(error);
-
- for (b = 0; b < nbands; b++)
- {
- if (verbose)
- printf("render band %d of %d\n", b + 1, nbands);
-
- memset(pix->samples, 0xff, pix->w * pix->h * 4);
-
- error = fz_rendertreeover(gc, pix, page->tree, ctm);
- if (error)
- fz_abort(error);
-
- for (y = 0; y < pix->h; y++)
- {
- unsigned char *src = pix->samples + y * pix->w * 4;
- unsigned char *dst = src;
-
- for (x = 0; x < pix->w; x++)
- {
- dst[x * 3 + 0] = src[x * 4 + 1];
- dst[x * 3 + 1] = src[x * 4 + 2];
- dst[x * 3 + 2] = src[x * 4 + 3];
- }
-
- write(fd, dst, pix->w * 3);
- }
-
- pix->y += bh;
- }
-
- fz_droppixmap(pix);
-
- close(fd);
-
- pdf_droppage(page);
-}
-
-int main(int argc, char **argv)
-{
- fz_error *error;
- char *filename;
- pdf_xref *xref;
- pdf_pagetree *pages;
- int c;
-
- char *password = "";
-
- fz_cpudetect();
- fz_accelerate();
-
- while ((c = getopt(argc, argv, "Vgtvz:d:o:b:")) != -1)
- {
- switch (c)
- {
- case 'g': ++showtree; break;
- case 't': ++textonly; break;
- case 'v': ++verbose; break;
- case 'd': password = optarg; break;
- case 'z': zoom = atof(optarg); break;
- case 'o': namefmt = optarg; break;
- case 'b': nbands = atoi(optarg); break;
- default: usage();
- }
- }
-
- if (argc - optind == 0)
- usage();
-
- filename = argv[optind++];
-
- if (!namefmt)
- {
-#if 1
- namefmt = "out-%03d.ppm";
-#else
- char namebuf[256];
- char *s;
- s = strrchr(filename, '/');
- if (!s)
- s = filename;
- else
- s ++;
- strcpy(namebuf, s);
- s = strrchr(namebuf, '.');
- if (s)
- strcpy(s, "-%03d.ppm");
- else
- strcat(namebuf, "-%03d.ppm");
- namefmt = namebuf;
-#endif
- }
-
- if (verbose)
- printf("loading pdf: '%s'\n", filename);
-
- error = pdf_newxref(&xref);
- if (error)
- fz_abort(error);
-
- error = pdf_loadxref(xref, filename);
- if (error)
- fz_abort(error);
-
- error = pdf_decryptxref(xref);
- if (error)
- fz_abort(error);
-
- if (xref->crypt)
- {
- error = pdf_setpassword(xref->crypt, password);
- if (error)
- fz_abort(error);
- }
-
- error = pdf_loadpagetree(&pages, xref);
- if (error)
- fz_abort(error);
-
- if (verbose)
- pdf_debugpagetree(pages);
-
- if (optind == argc)
- {
- printf("%d pages\n", pdf_getpagecount(pages));
- return 0;
- }
-
- if (textonly)
- {
- puts("Content-Type: text/plain; charset=UTF-8");
- puts("");
- }
-
- error = fz_newrenderer(&gc, pdf_devicergb, 0, 1024 * 512);
- if (error)
- fz_abort(error);
-
- for ( ; optind < argc; optind++)
- {
- int spage, epage, page;
- char *spec = argv[optind];
- char *dash = strchr(spec, '-');
-
- if (dash == spec)
- spage = epage = 1;
- else
- spage = epage = atoi(spec);
-
- if (dash)
- {
- if (strlen(dash) > 1)
- epage = atoi(dash+1);
- else
- epage = pdf_getpagecount(pages);
- }
-
- if (spage > epage)
- page = spage, spage = epage, epage = page;
-
- for (page = spage; page <= epage; page++)
- {
- if (page < 1 || page > pdf_getpagecount(pages))
- fprintf(stderr, "page out of bounds: %d\n", page);
- else
- {
- showpage(xref, pdf_getpageobject(pages, page - 1), page);
- }
- }
- }
-
- fz_droprenderer(gc);
-
- pdf_dropstore(xref->store);
- xref->store = nil;
-
- pdf_closexref(xref);
-
- return 0;
-}
-
diff --git a/apps/pdfselect.c b/apps/pdfselect.c
deleted file mode 100644
index f2381f94..00000000
--- a/apps/pdfselect.c
+++ /dev/null
@@ -1,299 +0,0 @@
-#include <fitz.h>
-#include <mupdf.h>
-
-void usage()
-{
- fprintf(stderr,
- "usage: pdfselect [options] infile.pdf outfile.pdf pageranges\n"
- " -d -\tpassword for decryption\n"
- " -e \tselect only even pages\n"
- " -o \tselect only odd pages\n"
- " -r \toutput in reverse order\n"
- " -v \tverbose\n"
- );
- exit(1);
-}
-
-void preloadobjstms(pdf_xref *xref)
-{
- fz_error *error;
- fz_obj *obj;
- int i;
-
- for (i = 0; i < xref->len; i++)
- {
- if (xref->table[i].type == 'o')
- {
- error = pdf_loadobject(&obj, xref, i, 0);
- if (error) fz_abort(error);
- fz_dropobj(obj);
- }
- }
-}
-
-int main(int argc, char **argv)
-{
- fz_error *error;
- char *password = "";
- char *infile;
- char *outfile;
- pdf_xref *xref;
- pdf_pagetree *pages;
- fz_obj *pagesref;
- fz_obj *kids;
- int i, k;
- int c;
- int page;
- int rootoid;
- int rootgid;
- int kidsoid;
- int kidsgid;
- int pagesoid;
- int pagesgid;
- fz_obj *obj;
-
- int verbose = 0;
- int even = 0;
- int odd = 0;
- int reverse = 0;
- int all = 0;
-
- while ((c = getopt(argc, argv, "d:eorv")) != -1)
- {
- switch (c)
- {
- case 'd': password = optarg; break;
- case 'e': ++ even; break;
- case 'o': ++ odd; break;
- case 'r': ++ reverse; break;
- case 'v': ++ verbose; break;
- default: usage();
- }
- }
-
- if (argc - optind < 2)
- usage();
-
- if (argc - optind < 3 && !even && !odd && !reverse)
- usage();
-
- if (argc - optind == 2)
- all = 1;
-
- infile = argv[optind++];
- outfile = argv[optind++];
-
- if (verbose)
- printf("loading pdf '%s'\n", infile);
-
- error = pdf_newxref(&xref);
- if (error)
- fz_abort(error);
-
- error = pdf_loadxref(xref, infile);
- if (error)
- fz_abort(error);
-
- error = pdf_decryptxref(xref);
- if (error)
- fz_abort(error);
-
- if (xref->crypt)
- {
- error = pdf_setpassword(xref->crypt, password);
- if (error)
- fz_abort(error);
- }
-
- error = pdf_loadpagetree(&pages, xref);
- if (error)
- fz_abort(error);
-
- /*
- * Kill annotations on all pages
- */
-
- if (verbose)
- printf("killing time\n");
-
- for (k = 0; k < pages->count; k++)
- {
- fz_dictdels(pages->pobj[k], "Parent");
- fz_dictdels(pages->pobj[k], "B");
- fz_dictdels(pages->pobj[k], "PieceInfo");
- fz_dictdels(pages->pobj[k], "Metadata");
- fz_dictdels(pages->pobj[k], "Annots");
- fz_dictdels(pages->pobj[k], "Tabs");
- pdf_updateobject(xref,
- fz_tonum(pages->pref[k]),
- fz_togen(pages->pref[k]),
- pages->pobj[k]);
- }
-
- /*
- * Save the pages we want to keep, in the order specified
- */
-
- error = fz_newarray(&kids, 100);
- if (error)
- fz_abort(error);
-
- for ( ; optind < argc; optind++)
- {
- int spage, epage;
- char *spec = argv[optind];
- char *dash = strchr(spec, '-');
-
- if (dash == spec)
- spage = epage = 1;
- else
- spage = epage = atoi(spec);
-
- if (dash)
- {
- if (strlen(dash) > 1)
- epage = atoi(dash+1);
- else
- epage = pdf_getpagecount(pages);
- }
-
- if (spage > epage)
- page = spage, spage = epage, epage = page;
-
- for (page = spage; page <= epage; page++)
- {
- if (page < 1 || page > pdf_getpagecount(pages))
- continue;
- if (odd && (page & 1) != 1)
- continue;
- if (even && (page & 1) != 0)
- continue;
- error = fz_arraypush(kids, pages->pref[page-1]);
- if (error)
- fz_abort(error);
- }
- }
-
- if (all)
- {
- for (page = 1; page <= pdf_getpagecount(pages); page++)
- {
- if (odd && (page & 1) != 1)
- continue;
- if (even && (page & 1) != 0)
- continue;
- error = fz_arraypush(kids, pages->pref[page-1]);
- if (error)
- fz_abort(error);
- }
- }
-
- if (reverse)
- {
- fz_obj *o1, *o2;
- int len = fz_arraylen(kids);
- for (i = 0; i < len / 2; i++)
- {
- o1 = fz_keepobj(fz_arrayget(kids, i));
- o2 = fz_keepobj(fz_arrayget(kids, len - i - 1));
- fz_arrayput(kids, i, o2);
- fz_arrayput(kids, len - i - 1, o1);
- }
- }
-
- /*
- * Save the new kids array
- */
-
- error = pdf_allocobject(xref, &kidsoid, &kidsgid);
- if (error)
- fz_abort(error);
-
- pdf_updateobject(xref, kidsoid, kidsgid, kids);
-
- /*
- * Save the new pages object
- */
-
- error = pdf_allocobject(xref, &pagesoid, &pagesgid);
- if (error)
- fz_abort(error);
-
- error = fz_packobj(&obj,
- "<</Type/Pages/Count %i/Kids %r>>",
- fz_arraylen(kids), kidsoid, kidsgid);
- if (error)
- fz_abort(error);
-
- pdf_updateobject(xref, pagesoid, pagesgid, obj);
-
- fz_dropobj(obj);
-
- /*
- * Relink parents to point to new pages object
- */
-
- error = fz_newindirect(&pagesref, pagesoid, pagesgid);
- if (error)
- fz_abort(error);
-
- for (i = 0; i < fz_arraylen(kids); i++)
- {
- int oid = fz_tonum(fz_arrayget(kids, i));
- int gid = fz_togen(fz_arrayget(kids, i));
- error = pdf_loadobject(&obj, xref, oid, gid);
- if (error)
- fz_abort(error);
- error = fz_dictputs(obj, "Parent", pagesref);
- if (error)
- fz_abort(error);
- pdf_updateobject(xref, oid, gid, obj);
- fz_dropobj(obj);
- }
-
- fz_dropobj(pagesref);
-
- /*
- * Create new catalog and trailer
- */
-
- error = pdf_allocobject(xref, &rootoid, &rootgid);
- if (error)
- fz_abort(error);
-
- error = fz_packobj(&obj,
- "<</Type/Catalog/Pages %r>>",
- pagesoid, pagesgid);
- if (error)
- fz_abort(error);
-
- pdf_updateobject(xref, rootoid, rootgid, obj);
-
- fz_dropobj(obj);
-
- error = fz_packobj(&xref->trailer, "<</Root %r>>", rootoid, rootgid);
- if (error)
- fz_abort(error);
-
- /*
- * Write out the new PDF
- */
-
- if (verbose)
- printf("garbage collecting\n");
-
- preloadobjstms(xref);
- pdf_garbagecollect(xref);
-
- if (verbose)
- printf("saving pdf '%s'\n", outfile);
-
- error = pdf_savexref(xref, outfile, nil);
- if (error)
- fz_abort(error);
-
- pdf_closexref(xref);
-
- return 0;
-}
-
diff --git a/apps/pdftool.c b/apps/pdftool.c
new file mode 100644
index 00000000..ba721e96
--- /dev/null
+++ b/apps/pdftool.c
@@ -0,0 +1,874 @@
+/*
+ * Swiss army knife for manipulating and debugging PDFs.
+ *
+ * There are a few major modes of operation:
+ *
+ * show -- pretty-print objects and streams
+ * draw -- render pages to bitmap
+ * clean -- simple rewrite of pdf file
+ * edit -- edit pages (impose and copy operations)
+ */
+
+#include "fitz.h"
+#include "mupdf.h"
+
+/*
+ * Common operations.
+ * Parse page selectors.
+ * Load and decrypt a PDF file.
+ * Select pages.
+ */
+
+pdf_xref *src = nil;
+pdf_pagetree *srcpages = nil;
+
+void die(fz_error *eo)
+{
+ fflush(stdout);
+ fprintf(stderr, "%s:%d: %s(): %s\n", eo->file, eo->line, eo->func, eo->msg);
+ fflush(stderr);
+ abort();
+}
+
+void closesrc(void)
+{
+ if (srcpages)
+ {
+ pdf_droppagetree(srcpages);
+ srcpages = nil;
+ }
+
+ if (src)
+ {
+ if (src->store)
+ {
+ pdf_dropstore(src->store);
+ src->store = nil;
+ }
+ pdf_closexref(src);
+ src = nil;
+ }
+}
+
+void opensrc(char *filename, char *password, int loadpages)
+{
+ fz_error *error;
+
+ closesrc();
+
+ error = pdf_newxref(&src);
+ if (error)
+ die(error);
+
+ error = pdf_loadxref(src, filename);
+ if (error)
+ {
+ fz_warn("trying to repair");
+ error = pdf_repairxref(src, filename);
+ if (error)
+ die(error);
+ }
+
+ error = pdf_decryptxref(src);
+ if (error)
+ die(error);
+
+ if (src->crypt)
+ {
+ error = pdf_setpassword(src->crypt, password);
+ if (error)
+ die(error);
+ }
+
+ if (loadpages)
+ {
+ error = pdf_loadpagetree(&srcpages, src);
+ if (error)
+ die(error);
+ }
+}
+
+void preloadobjstms(void)
+{
+ fz_error *error;
+ fz_obj *obj;
+ int i;
+
+ for (i = 0; i < src->len; i++)
+ {
+ if (src->table[i].type == 'o')
+ {
+ error = pdf_loadobject(&obj, src, i, 0);
+ if (error) die(error);
+ fz_dropobj(obj);
+ }
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Debug print parts of the PDF.
+ */
+
+int showbinary = 0;
+int showdecode = 0;
+int showcolumn;
+
+void showusage(void)
+{
+ fprintf(stderr, "usage: pdftool show [-bd] <file> [xref] [trailer] [object numbers]\n");
+ fprintf(stderr, " -b \tprint streams as raw binary data\n");
+ fprintf(stderr, " -d \tdecode streams\n");
+ exit(1);
+}
+
+void showtrailer(void)
+{
+ if (!src)
+ die(fz_throw("no file specified"));
+ printf("trailer\n");
+ fz_debugobj(src->trailer);
+ printf("\n\n");
+}
+
+void showxref(void)
+{
+ if (!src)
+ die(fz_throw("no file specified"));
+ pdf_debugxref(src);
+ printf("\n");
+}
+
+void showsafe(unsigned char *buf, int n)
+{
+ int i;
+ for (i = 0; i < n; i++) {
+ if (buf[i] == '\r' || buf[i] == '\n') {
+ putchar('\n');
+ showcolumn = 0;
+ }
+ else if (buf[i] < 32 || buf[i] > 126) {
+ putchar('.');
+ showcolumn ++;
+ }
+ else {
+ putchar(buf[i]);
+ showcolumn ++;
+ }
+ if (showcolumn == 79) {
+ putchar('\n');
+ showcolumn = 0;
+ }
+ }
+}
+
+void showstream(int num, int gen)
+{
+ fz_error *error;
+ fz_stream *stm;
+ unsigned char buf[2048];
+ int n;
+
+ showcolumn = 0;
+
+ if (showdecode)
+ error = pdf_openstream(&stm, src, num, gen);
+ else
+ error = pdf_openrawstream(&stm, src, num, gen);
+ if (error)
+ die(error);
+
+ while (1)
+ {
+ n = fz_read(stm, buf, sizeof buf);
+ if (n == 0)
+ break;
+ if (n < 0)
+ die(fz_ioerror(stm));
+
+ if (showbinary)
+ fwrite(buf, 1, n, stdout);
+ else
+ showsafe(buf, n);
+ }
+
+ fz_dropstream(stm);
+}
+
+void showobject(int num, int gen)
+{
+ fz_error *error;
+ fz_obj *obj;
+
+ if (!src)
+ die(fz_throw("no file specified"));
+
+ error = pdf_loadobject(&obj, src, num, gen);
+ if (error)
+ die(error);
+
+ printf("%d %d obj\n", num, gen);
+ fz_debugobj(obj);
+ printf("\n");
+
+ if (pdf_isstream(src, num, gen))
+ {
+ printf("stream\n");
+ showstream(num, gen);
+ printf("endstream\n");
+ }
+
+ printf("endobj\n\n");
+
+ fz_dropobj(obj);
+}
+
+void
+showmain(int argc, char **argv)
+{
+ int c;
+
+ while ((c = getopt(argc, argv, "bd")) != -1)
+ {
+ switch (c)
+ {
+ case 'b': showbinary ++; break;
+ case 'd': showdecode ++; break;
+ default:
+ showusage();
+ break;
+ }
+ }
+
+ if (optind == argc)
+ showusage();
+
+ opensrc(argv[optind++], "", 0);
+
+ if (optind == argc)
+ showtrailer();
+
+ while (optind < argc)
+ {
+ if (!strcmp(argv[optind], "trailer"))
+ showtrailer();
+ else if (!strcmp(argv[optind], "xref"))
+ showxref();
+ else
+ showobject(atoi(argv[optind]), 0);
+ optind++;
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Clean tool.
+ * Rewrite PDF.
+ * Garbage collect.
+ * Decompress streams.
+ * Encrypt or decrypt.
+ */
+
+void
+cleanusage(void)
+{
+ fprintf(stderr,
+ "usage: pdftool clean [options] input.pdf [outfile.pdf]\n"
+ " -d -\tpassword for decryption\n"
+ " -g \tgarbage collect unused objects\n"
+ " -x \texpand compressed streams\n"
+ " -e \tencrypt output\n"
+ " -u -\tset user password for encryption\n"
+ " -o -\tset owner password\n"
+ " -p -\tset permissions (combine letters 'pmca')\n"
+ " -n -\tkey length in bits: 40 <= n <= 128\n");
+ exit(1);
+}
+
+void
+cleanexpand(void)
+{
+ fz_error *error;
+ fz_obj *stmobj;
+ fz_buffer *buf;
+ fz_obj *stmlen;
+ int i, gen;
+
+ for (i = 0; i < src->len; i++)
+ {
+ if (src->table[i].type == 'n')
+ {
+ gen = src->table[i].gen;
+
+ if (pdf_isstream(src, i, gen))
+ {
+ error = pdf_loadobject(&stmobj, src, i, gen);
+ if (error) die(error);
+
+ error = pdf_loadstream(&buf, src, i, gen);
+ if (error) die(error);
+
+ fz_dictdels(stmobj, "Filter");
+ fz_dictdels(stmobj, "DecodeParms");
+
+ error = fz_newint(&stmlen, buf->wp - buf->rp);
+ if (error) die(error);
+ error = fz_dictputs(stmobj, "Length", stmlen);
+ if (error) die(error);
+ fz_dropobj(stmlen);
+
+ pdf_updateobject(src, i, gen, stmobj);
+ pdf_updatestream(src, i, gen, buf);
+
+ fz_dropobj(stmobj);
+ }
+ }
+ }
+}
+
+void
+cleanmain(int argc, char **argv)
+{
+ int doencrypt = 0;
+ int dogarbage = 0;
+ int doexpand = 0;
+ pdf_crypt *encrypt = nil;
+ char *infile;
+ char *outfile = "out.pdf";
+ char *userpw = "";
+ char *ownerpw = "";
+ unsigned perms = 0xfffff0c0; /* nothing allowed */
+ int keylen = 40;
+ char *password = "";
+ fz_error *error;
+ int c;
+
+ while ((c = getopt(argc, argv, "d:egn:o:p:u:x")) != -1)
+ {
+ switch (c)
+ {
+ case 'p':
+ /* see TABLE 3.15 User access permissions */
+ perms = 0xfffff0c0;
+ if (strchr(optarg, 'p')) /* print */
+ perms |= (1 << 2) | (1 << 11);
+ if (strchr(optarg, 'm')) /* modify */
+ perms |= (1 << 3) | (1 << 10);
+ if (strchr(optarg, 'c')) /* copy */
+ perms |= (1 << 4) | (1 << 9);
+ if (strchr(optarg, 'a')) /* annotate / forms */
+ perms |= (1 << 5) | (1 << 8);
+ break;
+ case 'd': password = optarg; break;
+ case 'e': doencrypt ++; break;
+ case 'g': dogarbage ++; break;
+ case 'n': keylen = atoi(optarg); break;
+ case 'o': ownerpw = optarg; break;
+ case 'u': userpw = optarg; break;
+ case 'x': doexpand ++; break;
+ default: cleanusage(); break;
+ }
+ }
+
+ if (argc - optind < 1)
+ cleanusage();
+
+ infile = argv[optind++];
+ if (argc - optind > 0)
+ outfile = argv[optind++];
+
+ opensrc(infile, password, 0);
+
+ if (doencrypt)
+ {
+ fz_obj *id = fz_dictgets(src->trailer, "ID");
+ if (!id)
+ {
+ error = fz_packobj(&id, "[(ABCDEFGHIJKLMNOP)(ABCDEFGHIJKLMNOP)]");
+ if (error)
+ die(error);
+ }
+ else
+ fz_keepobj(id);
+
+ error = pdf_newencrypt(&encrypt, userpw, ownerpw, perms, keylen, id);
+ if (error)
+ die(error);
+
+ fz_dropobj(id);
+ }
+
+ if (doexpand)
+ cleanexpand();
+
+ if (dogarbage)
+ {
+ preloadobjstms();
+ pdf_garbagecollect(src);
+ }
+
+ error = pdf_savexref(src, outfile, encrypt);
+ if (error)
+ die(error);
+
+ if (encrypt)
+ pdf_dropcrypt(encrypt);
+
+ pdf_closexref(src);
+}
+
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Draw pages to PPM bitmaps.
+ */
+
+enum { DRAWPNM, DRAWTXT, DRAWXML };
+
+fz_renderer *drawgc = nil;
+int drawmode = DRAWPNM;
+char *drawpattern = "out%0.3d.pnm";
+pdf_page *drawpage = nil;
+float drawzoom = 1.0;
+int drawrotate = 0;
+int drawbands = 1;
+int drawcount = 0;
+
+void
+drawusage(void)
+{
+ fprintf(stderr,
+ "usage: pdftool draw [options] [file.pdf pages ... ]\n"
+ " -b -\tdraw page in N bands\n"
+ " -d -\tpassword for decryption\n"
+ " -o -\tpattern (%%d for page number) for output file\n"
+ " -r -\tresolution in dpi\n"
+ " -t \tutf-8 text output instead of graphics\n"
+ " -x \txml dump of display tree\n"
+ " example:\n"
+ " pdftool draw -o out%%0.3d.pnm a.pdf 1-3,5,9-\n");
+ exit(1);
+}
+
+void
+drawloadpage(int pagenum)
+{
+ fz_error *error;
+ fz_obj *pageobj;
+
+ pageobj = pdf_getpageobject(srcpages, pagenum - 1);
+ error = pdf_loadpage(&drawpage, src, pageobj);
+ if (error)
+ die(error);
+
+ fprintf(stderr, "page %d mediabox [ %g %g %g %g ] rotate %d\n",
+ pagenum,
+ drawpage->mediabox.x0, drawpage->mediabox.y0,
+ drawpage->mediabox.x1, drawpage->mediabox.y1,
+ drawpage->rotate);
+}
+
+void
+drawfreepage(void)
+{
+ pdf_droppage(drawpage);
+ drawpage = nil;
+}
+
+void
+drawpnm(int pagenum)
+{
+ fz_error *error;
+ fz_matrix ctm;
+ fz_irect bbox;
+ fz_pixmap *pix;
+ char namebuf[256];
+ char buf[256];
+ int x, y, w, h, b, bh;
+ int fd;
+
+ drawloadpage(pagenum);
+
+ ctm = fz_identity();
+ ctm = fz_concat(ctm, fz_translate(0, -drawpage->mediabox.y1));
+ ctm = fz_concat(ctm, fz_scale(drawzoom, -drawzoom));
+ ctm = fz_concat(ctm, fz_rotate(drawrotate + drawpage->rotate));
+
+ bbox = fz_roundrect(fz_transformaabb(ctm, drawpage->mediabox));
+ w = bbox.x1 - bbox.x0;
+ h = bbox.y1 - bbox.y0;
+ bh = h / drawbands;
+
+ if (drawpattern)
+ {
+ sprintf(namebuf, drawpattern, drawcount++);
+ fd = open(namebuf, O_BINARY|O_WRONLY|O_CREAT|O_TRUNC, 0666);
+ if (fd < 0)
+ die(fz_throw("ioerror: could not open file '%s'", namebuf));
+ }
+ else
+ fd = 1;
+
+ sprintf(buf, "P6\n%d %d\n255\n", w, h);
+ write(fd, buf, strlen(buf));
+
+ error = fz_newpixmap(&pix, bbox.x0, bbox.y0, w, bh, 4);
+ if (error)
+ die(error);
+
+ memset(pix->samples, 0xff, pix->h * pix->w * pix->n);
+
+ for (b = 0; b < drawbands; b++)
+ {
+ if (drawbands > 1)
+ fprintf(stderr, "drawing band %d / %d\n", b + 1, drawbands);
+
+ error = fz_rendertreeover(drawgc, pix, drawpage->tree, ctm);
+ if (error)
+ die(error);
+
+ for (y = 0; y < pix->h; y++)
+ {
+ unsigned char *src = pix->samples + y * pix->w * 4;
+ unsigned char *dst = src;
+
+ for (x = 0; x < pix->w; x++)
+ {
+ dst[x * 3 + 0] = src[x * 4 + 1];
+ dst[x * 3 + 1] = src[x * 4 + 2];
+ dst[x * 3 + 2] = src[x * 4 + 3];
+ }
+
+ write(fd, dst, pix->w * 3);
+
+ memset(src, 0xff, pix->w * 4);
+ }
+
+ pix->y += bh;
+ if (pix->y + pix->h > bbox.y1)
+ pix->h = bbox.y1 - pix->y;
+ }
+
+ fz_droppixmap(pix);
+
+ if (drawpattern)
+ close(fd);
+
+ drawfreepage();
+}
+
+void
+drawtxt(int pagenum)
+{
+ fz_error *error;
+ pdf_textline *line;
+ fz_matrix ctm;
+
+ drawloadpage(pagenum);
+
+ ctm = fz_concat(
+ fz_translate(0, -drawpage->mediabox.y1),
+ fz_scale(drawzoom, -drawzoom));
+
+ error = pdf_loadtextfromtree(&line, drawpage->tree, ctm);
+ if (error)
+ die(error);
+
+ pdf_debugtextline(line);
+ pdf_droptextline(line);
+
+ drawfreepage();
+}
+
+void
+drawxml(int pagenum)
+{
+ drawloadpage(pagenum);
+ fz_debugtree(drawpage->tree);
+ drawfreepage();
+}
+
+void
+drawpages(char *pagelist)
+{
+ int page, spage, epage;
+ char *spec, *dash;
+
+ if (!src)
+ drawusage();
+
+ spec = strsep(&pagelist, ",");
+ while (spec)
+ {
+ dash = strchr(spec, '-');
+
+ if (dash == spec)
+ spage = epage = 1;
+ else
+ spage = epage = atoi(spec);
+
+ if (dash)
+ {
+ if (strlen(dash) > 1)
+ epage = atoi(dash + 1);
+ else
+ epage = pdf_getpagecount(srcpages);
+ }
+
+ if (spage > epage)
+ page = spage, spage = epage, epage = page;
+
+ for (page = spage; page <= epage; page++)
+ {
+ if (page < 1 || page > pdf_getpagecount(srcpages))
+ continue;
+ switch (drawmode)
+ {
+ case DRAWPNM: drawpnm(page); break;
+ case DRAWTXT: drawtxt(page); break;
+ case DRAWXML: drawxml(page); break;
+ }
+ }
+
+ spec = strsep(&pagelist, ",");
+ }
+}
+
+void
+drawmain(int argc, char **argv)
+{
+ fz_error *error;
+ char *password = "";
+ int c;
+
+ while ((c = getopt(argc, argv, "b:d:o:r:tx")) != -1)
+ {
+ switch (c)
+ {
+ case 'b': drawbands = atoi(optarg); break;
+ case 'd': password = optarg; break;
+ case 'o': drawpattern = optarg; break;
+ case 'r': drawzoom = atof(optarg) / 72.0; break;
+ case 't': drawmode = DRAWTXT; break;
+ case 'x': drawmode = DRAWXML; break;
+ default:
+ drawusage();
+ break;
+ }
+ }
+
+ if (optind == argc)
+ drawusage();
+
+ error = fz_newrenderer(&drawgc, pdf_devicergb, 0, 1024 * 512);
+ if (error)
+ die(error);
+
+ while (optind < argc)
+ {
+ if (strstr(argv[optind], ".pdf"))
+ opensrc(argv[optind], password, 1);
+ else
+ drawpages(argv[optind]);
+ optind++;
+ }
+
+ closesrc();
+
+ fz_droprenderer(drawgc);
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Edit tool.
+ * Copy or impose pages from other pdf files into output pdf.
+ */
+
+/* for each source pdf, build a list of objects to transplant.
+ * for each source pdf, do the transplants at the end of object collecting.
+ * build a new page tree structure for output.
+ * change page nodes into xobjects for over and n-up modes.
+ * create new page nodes.
+ * create new page tree.
+ */
+
+enum { COPY, OVER, NUP2, NUP4, NUP8 };
+
+pdf_xref *editxref = nil;
+fz_obj *editkids = nil;
+int editmode = COPY;
+
+void
+editusage(void)
+{
+ fprintf(stderr, "usage: pdftool edit [-o file.pdf] [mode file.pdf pages ... ]\n");
+ fprintf(stderr, " mode is one of: copy over 2up 4up 8up\n");
+ fprintf(stderr, " pages is a comma separated list of ranges\n");
+ fprintf(stderr, " example:\n");
+ fprintf(stderr, " pdftool edit -o output.pdf copy one.pdf 1-3,5,9 two.pdf 1-\n");
+ exit(1);
+}
+
+void
+editcopy(int pagenum)
+{
+ printf("copy page %d\n", pagenum);
+}
+
+void editover(int pagenum) { }
+void edit2up(int pagenum) { }
+void edit4up(int pagenum) { }
+void edit8up(int pagenum) { }
+
+void
+editpages(char *pagelist)
+{
+ int page, spage, epage;
+ char *spec, *dash;
+
+ if (!src)
+ editusage();
+
+ spec = strsep(&pagelist, ",");
+ while (spec)
+ {
+ dash = strchr(spec, '-');
+
+ if (dash == spec)
+ spage = epage = 1;
+ else
+ spage = epage = atoi(spec);
+
+ if (dash)
+ {
+ if (strlen(dash) > 1)
+ epage = atoi(dash + 1);
+ else
+ epage = pdf_getpagecount(srcpages);
+ }
+
+ if (spage > epage)
+ page = spage, spage = epage, epage = page;
+
+ for (page = spage; page <= epage; page++)
+ {
+ if (page < 1 || page > pdf_getpagecount(srcpages))
+ continue;
+ switch (editmode)
+ {
+ case COPY: editcopy(page); break;
+ case OVER: editover(page); break;
+ case NUP2: edit2up(page); break;
+ case NUP4: edit4up(page); break;
+ case NUP8: edit8up(page); break;
+ }
+ }
+
+ spec = strsep(&pagelist, ",");
+ }
+}
+
+void
+editmain(int argc, char **argv)
+{
+ char *outfile = "out.pdf";
+ fz_error *error;
+ int c;
+
+ while ((c = getopt(argc, argv, "o:")) != -1)
+ {
+ switch (c)
+ {
+ case 'o':
+ outfile = optarg;
+ break;
+ default:
+ editusage();
+ break;
+ }
+ }
+
+ if (optind == argc)
+ editusage();
+
+ fprintf(stderr, "edit tool is not implemented yet\n");
+ exit(1);
+
+ error = pdf_newxref(&editxref);
+ if (error)
+ die(error);
+
+ error = pdf_initxref(editxref);
+ if (error)
+ die(error);
+
+ while (optind < argc)
+ {
+ if (strstr(argv[optind], ".pdf"))
+ {
+ opensrc(argv[optind], "", 1);
+ }
+ else if (!strcmp(argv[optind], "copy"))
+ editmode = COPY;
+ else if (!strcmp(argv[optind], "over"))
+ editmode = OVER;
+ else if (!strcmp(argv[optind], "2up"))
+ editmode = NUP2;
+ else if (!strcmp(argv[optind], "4up"))
+ editmode = NUP4;
+ else if (!strcmp(argv[optind], "8up"))
+ editmode = NUP8;
+ else
+ editpages(argv[optind]);
+ optind++;
+ }
+
+ closesrc();
+
+ error = pdf_savexref(editxref, outfile, nil);
+ if (error)
+ die(error);
+
+ pdf_closexref(editxref);
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Main!
+ */
+
+void
+mainusage(void)
+{
+ fprintf(stderr, "usage: pdftool <command> [options...]\n");
+ fprintf(stderr, " command is one of: show, draw, clean, edit\n");
+ exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+ if (argc >= 2)
+ {
+ optind = 2;
+ if (!strcmp(argv[1], "show"))
+ showmain(argc, argv);
+ else if (!strcmp(argv[1], "draw"))
+ drawmain(argc, argv);
+ else if (!strcmp(argv[1], "clean"))
+ cleanmain(argc, argv);
+ else if (!strcmp(argv[1], "edit"))
+ editmain(argc, argv);
+ else
+ mainusage();
+ }
+ else
+ mainusage();
+ return 0;
+}
+
diff --git a/apps/samshow.c b/apps/samshow.c
index e9ce86f1..a1563c9d 100644
--- a/apps/samshow.c
+++ b/apps/samshow.c
@@ -1,6 +1,14 @@
#include "fitz.h"
#include "samus.h"
+void die(fz_error *eo)
+{
+ fflush(stdout);
+ fprintf(stderr, "%s:%d: %s(): %s\n", eo->file, eo->line, eo->func, eo->msg);
+ fflush(stderr);
+ abort();
+}
+
void showfixdocseq(sa_package *pack, char *part)
{
fz_error *error;
@@ -8,7 +16,7 @@ void showfixdocseq(sa_package *pack, char *part)
error = sa_loadfixdocseq(&seq, pack, part);
if (error)
- fz_abort(error);
+ die(error);
sa_debugfixdocseq(seq);
@@ -38,14 +46,14 @@ int runpack(int argc, char **argv)
error = sa_openpackage(&pack, argv[1]);
if (error)
- fz_abort(error);
+ die(error);
sa_debugpackage(pack);
printf("\n");
error = sa_loadrelations(&rels, pack, "/");
if (error)
- fz_abort(error);
+ die(error);
sa_debugrelations(rels);
printf("\n");
@@ -67,7 +75,7 @@ int runpack(int argc, char **argv)
error = sa_loadrelations(&rels, pack, argv[i]);
if (error)
- fz_abort(error);
+ die(error);
sa_debugrelations(rels);
sa_droprelations(rels);
@@ -89,7 +97,7 @@ int runzip(int argc, char **argv)
error = sa_openzip(&zip, argv[1]);
if (error)
- fz_abort(error);
+ die(error);
if (argc == 2)
sa_debugzip(zip);
@@ -98,10 +106,10 @@ int runzip(int argc, char **argv)
{
error = sa_openzipentry(&stm, zip, argv[i]);
if (error)
- fz_abort(error);
+ die(error);
n = fz_readall(&buf, stm);
if (n < 0)
- fz_abort(fz_ioerror(stm));
+ die(fz_ioerror(stm));
fz_dropstream(stm);
fwrite(buf->rp, 1, buf->wp - buf->rp, stdout);
@@ -123,11 +131,11 @@ int runxml(int argc, char **argv)
error = fz_openrfile(&file, argv[1]);
if (error)
- fz_abort(error);
+ die(error);
error = sa_openxml(&parser, file, 0);
if (error)
- fz_abort(error);
+ die(error);
item = sa_xmlnext(parser);
if (item)
@@ -148,11 +156,11 @@ int runtiff(int argc, char **argv)
error = fz_openrfile(&file, argv[1]);
if (error)
- fz_abort(error);
+ die(error);
error = sa_readtiff(file);
if (error)
- fz_abort(error);
+ die(error);
fz_dropstream(file);
diff --git a/base/base_error.c b/base/base_error.c
index e9823f14..e0bf1567 100644
--- a/base/base_error.c
+++ b/base/base_error.c
@@ -53,7 +53,12 @@ fz_throw0(const char *func, const char *file, int line, char *fmt, ...)
va_end(ap);
if (getenv("BOMB"))
- fz_abort(eo);
+ {
+ fflush(stdout);
+ fprintf(stderr, "%s:%d: %s(): %s\n", eo->file, eo->line, eo->func, eo->msg);
+ fflush(stderr);
+ abort();
+ }
return eo;
}
@@ -67,12 +72,3 @@ fz_droperror(fz_error *eo)
fz_free(eo);
}
-void
-fz_abort(fz_error *eo)
-{
- fflush(stdout);
- fprintf(stderr, "%s:%d: %s(): %s\n", eo->file, eo->line, eo->func, eo->msg);
- fflush(stderr);
- abort();
-}
-
diff --git a/include/fitz/base_runtime.h b/include/fitz/base_runtime.h
index feeb7ffc..717b22e9 100644
--- a/include/fitz/base_runtime.h
+++ b/include/fitz/base_runtime.h
@@ -57,7 +57,6 @@ fz_error *fz_throw0(const char *func, const char *file, int line, char *fmt, ...
fz_error *fz_throw1(char *fmt, ...);
void fz_warn(char *fmt, ...);
-void fz_abort(fz_error *eo);
void fz_droperror(fz_error *eo);
typedef struct fz_memorycontext_s fz_memorycontext;