summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Jamfile3
-rw-r--r--apps/pdfclean.c27
-rw-r--r--apps/pdfmerge.c54
-rw-r--r--apps/pdfrip.c74
-rw-r--r--apps/pdfselect.c299
-rw-r--r--include/mupdf.h1
-rw-r--r--include/mupdf/version.h8
-rw-r--r--mupdf/pagetree.c9
-rw-r--r--mupdf/xref.c2
9 files changed, 417 insertions, 60 deletions
diff --git a/Jamfile b/Jamfile
index 4add9813..3dbd289f 100644
--- a/Jamfile
+++ b/Jamfile
@@ -260,5 +260,6 @@ Main pdfclean : apps/pdfclean.c ;
Main pdfdebug : apps/pdfdebug.c ;
Main pdfrip : apps/pdfrip.c ;
Main pdfmerge : apps/pdfmerge.c ;
-LinkLibraries pdfclean pdfdebug pdfrip pdfmerge : libmupdf libfitz ;
+Main pdfselect : apps/pdfselect.c ;
+LinkLibraries pdfclean pdfdebug pdfrip pdfmerge pdfselect : libmupdf libfitz ;
diff --git a/apps/pdfclean.c b/apps/pdfclean.c
index a55b94ef..05bef10f 100644
--- a/apps/pdfclean.c
+++ b/apps/pdfclean.c
@@ -5,14 +5,14 @@ void usage()
{
fprintf(stderr,
"usage: pdfclean [options] infile.pdf outfile.pdf\n"
- " -r\trebuild xref table\n"
- " -g\tgarbage collect unused objects\n"
- " -x\texpand compressed streams\n"
- " -d -\tset user password for decryption\n"
- " -e\tencrypt outfile\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\n"
+ " -p -\tset permissions (combine letters 'pmca')\n"
" -n -\tkey length in bits: 40 <= n <= 128\n"
);
exit(1);
@@ -91,7 +91,7 @@ int main(int argc, char **argv)
char *userpw = "";
char *ownerpw = "";
- int perms = -4; /* 0xfffffffc */
+ unsigned perms = 0xfffff0c0; /* nothing allowed */
int keylen = 40;
char *password = "";
@@ -105,7 +105,18 @@ int main(int argc, char **argv)
case 'e': ++ doencrypt; break;
case 'u': userpw = optarg; break;
case 'o': ownerpw = optarg; break;
- case 'p': perms = atoi(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();
diff --git a/apps/pdfmerge.c b/apps/pdfmerge.c
index 5ad161f0..8c431308 100644
--- a/apps/pdfmerge.c
+++ b/apps/pdfmerge.c
@@ -4,14 +4,10 @@
void usage()
{
fprintf(stderr,
- "usage: pdfmerge [options] file.pdf pages ...\n"
+ "usage: pdfmerge [options] file1.pdf file2.pdf ...\n"
+ " -d -\tpassword for decryption\n"
" -o -\toutput file name (default out.pdf)\n"
- " -d -\tset user password for decryption\n"
- " -e\tencrypt outfile\n"
- " -U -\tset user password for encryption\n"
- " -O -\tset owner password\n"
- " -P -\tset permissions\n"
- " -N -\tkey length in bits: 40 <= n <= 128\n"
+ " -v \tverbose\n"
);
exit(1);
}
@@ -35,25 +31,15 @@ int main(int argc, char **argv)
int i, k;
int c;
- pdf_crypt *encrypt = 0;
- int doencrypt = 0;
-
- char *userpw = "";
- char *ownerpw = "";
- int perms = -4; /* 0xfffffffc */
- int keylen = 40;
+ int verbose = 0;
char *password = "";
- while ((c = getopt(argc, argv, "reo:U:O:P:N:")) != -1)
+ while ((c = getopt(argc, argv, "vo:d:")) != -1)
{
switch (c)
{
- case 'e': ++ doencrypt; break;
+ case 'v': ++ verbose; break;
case 'o': savename = optarg; break;
- case 'U': userpw = optarg; break;
- case 'O': ownerpw = optarg; break;
- case 'P': perms = atoi(optarg); break;
- case 'N': keylen = atoi(optarg); break;
case 'd': password = optarg; break;
default: usage();
}
@@ -84,6 +70,12 @@ int main(int argc, char **argv)
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);
@@ -111,6 +103,9 @@ int main(int argc, char **argv)
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");
@@ -152,6 +147,10 @@ int main(int argc, char **argv)
* 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);
@@ -213,20 +212,7 @@ int main(int argc, char **argv)
* Write out the new PDF
*/
- if (doencrypt)
- {
- fz_obj *id = fz_dictgets(dst->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);
- }
-
- error = pdf_savexref(dst, savename, encrypt);
+ error = pdf_savexref(dst, savename, nil);
if (error)
fz_abort(error);
diff --git a/apps/pdfrip.c b/apps/pdfrip.c
index c9c761ce..b160ea65 100644
--- a/apps/pdfrip.c
+++ b/apps/pdfrip.c
@@ -6,10 +6,19 @@ float zoom = 1.0;
char *namefmt = nil;
fz_renderer *gc;
int nbands = 1;
+int verbose = 0;
void usage()
{
- fprintf(stderr, "usage: pdfrip [-d] [-b bands] [-o out-%%02d.ppm] [-p password] [-z zoom] file.pdf pages...\n");
+ fprintf(stderr,
+"usage: pdfrip [options] file.pdf pageranges\n"
+" -b -\trender page in N bands (default 1)\n"
+" -d -\tpassword for decryption\n"
+" -o -\toutput filename format (default out-%%03d.ppm)\n"
+" -t \tshow display tree\n"
+" -v \tverbose\n"
+" -z -\tzoom factor (default 1.0 = 72 dpi)\n"
+ );
exit(1);
}
@@ -31,6 +40,9 @@ void showpage(pdf_xref *xref, fz_obj *pageobj, int pagenum)
int w, h;
int b, bh;
+ if (verbose)
+ printf("page %d\n", pagenum);
+
sprintf(namebuf, namefmt, pagenum);
error = pdf_loadpage(&page, xref, pageobj);
@@ -81,7 +93,8 @@ void showpage(pdf_xref *xref, fz_obj *pageobj, int pagenum)
for (b = 0; b < nbands; b++)
{
- printf("band %d / %d\n", b, nbands);
+ if (verbose)
+ printf("render band %d of %d\n", b + 1, nbands);
memset(pix->samples, 0xff, pix->w * pix->h * 4);
@@ -119,20 +132,20 @@ int main(int argc, char **argv)
pdf_xref *xref;
pdf_pagetree *pages;
int c;
- static char namebuf[256];
char *password = "";
fz_cpudetect();
fz_accelerate();
- while ((c = getopt(argc, argv, "dz:p:o:b:")) != -1)
+ while ((c = getopt(argc, argv, "Vtvz:d:o:b:")) != -1)
{
switch (c)
{
- case 'p': password = optarg; break;
+ case 't': ++showtree; break;
+ case 'v': ++verbose; break;
+ case 'd': password = optarg; break;
case 'z': zoom = atof(optarg); break;
- case 'd': ++showtree; break;
case 'o': namefmt = optarg; break;
case 'b': nbands = atoi(optarg); break;
default: usage();
@@ -146,6 +159,10 @@ int main(int argc, char **argv)
if (!namefmt)
{
+#if 1
+ namefmt = "out-%03d.ppm";
+#else
+ char namebuf[256];
char *s;
s = strrchr(filename, '/');
if (!s)
@@ -159,8 +176,12 @@ int main(int argc, char **argv)
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);
@@ -184,10 +205,11 @@ int main(int argc, char **argv)
if (error)
fz_abort(error);
+ if (verbose)
+ pdf_debugpagetree(pages);
+
if (optind == argc)
- {
- printf("number of pages: %d\n", pdf_getpagecount(pages));
- }
+ printf("%d pages\n", pdf_getpagecount(pages));
error = fz_newrenderer(&gc, pdf_devicergb, 0, 1024 * 512);
if (error)
@@ -195,11 +217,35 @@ int main(int argc, char **argv)
for ( ; optind < argc; optind++)
{
- int page = atoi(argv[optind]);
- if (page < 1 || page > pdf_getpagecount(pages))
- fprintf(stderr, "page out of bounds: %d\n", page);
- printf("page %d\n", page);
- showpage(xref, pdf_getpageobject(pages, page - 1), page);
+ 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);
diff --git a/apps/pdfselect.c b/apps/pdfselect.c
new file mode 100644
index 00000000..f2381f94
--- /dev/null
+++ b/apps/pdfselect.c
@@ -0,0 +1,299 @@
+#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/include/mupdf.h b/include/mupdf.h
index 94d47812..7556484a 100644
--- a/include/mupdf.h
+++ b/include/mupdf.h
@@ -14,6 +14,7 @@ void pdf_logimage(char *fmt, ...);
void pdf_logshade(char *fmt, ...);
void pdf_logpage(char *fmt, ...);
+#include "mupdf/version.h"
#include "mupdf/syntax.h"
#include "mupdf/xref.h"
#include "mupdf/rsrc.h"
diff --git a/include/mupdf/version.h b/include/mupdf/version.h
new file mode 100644
index 00000000..af218190
--- /dev/null
+++ b/include/mupdf/version.h
@@ -0,0 +1,8 @@
+/*
+ * Version strings
+ */
+
+#define PDF_NAME "GhostPDF"
+#define PDF_VERSION (1)
+#define PDF_COPYRIGHT "Copyright (C) 2005 artofcode LLC"
+
diff --git a/mupdf/pagetree.c b/mupdf/pagetree.c
index eafc0599..315c2bd2 100644
--- a/mupdf/pagetree.c
+++ b/mupdf/pagetree.c
@@ -72,6 +72,9 @@ loadpagetree(pdf_xref *xref, pdf_pagetree *pages,
if (inh) inherit.rotate = inh;
kids = fz_dictgets(obj, "Kids");
+ error = pdf_resolve(&kids, xref);
+ if (error)
+ return error;
pdf_logpage("subtree %d {\n", fz_arraylen(kids));
@@ -80,13 +83,15 @@ loadpagetree(pdf_xref *xref, pdf_pagetree *pages,
kref = fz_arrayget(kids, i);
error = pdf_loadindirect(&kobj, xref, kref);
- if (error) return error;
+ if (error) { fz_dropobj(kids); return error; }
error = loadpagetree(xref, pages, inherit, kobj, kref);
fz_dropobj(kobj);
- if (error) return error;
+ if (error) { fz_dropobj(kids); return error; }
}
+ fz_dropobj(kids);
+
pdf_logpage("}\n");
}
diff --git a/mupdf/xref.c b/mupdf/xref.c
index c5305b28..01b3dbf8 100644
--- a/mupdf/xref.c
+++ b/mupdf/xref.c
@@ -20,7 +20,7 @@ pdf_newxref(pdf_xref **xrefp)
pdf_logxref("newxref %p\n", xref);
xref->file = nil;
- xref->version = 1.0;
+ xref->version = 1.3;
xref->startxref = 0;
xref->crypt = nil;