summaryrefslogtreecommitdiff
path: root/source/tools/pdfinfo.c
diff options
context:
space:
mode:
authorTor Andersson <tor.andersson@artifex.com>2013-06-19 15:29:44 +0200
committerTor Andersson <tor.andersson@artifex.com>2013-06-20 16:45:35 +0200
commit0a927854a10e1e6b9770a81e2e1d9f3093631757 (patch)
tree3d65d820d9fdba2d0d394d99c36290c851b78ca0 /source/tools/pdfinfo.c
parent1ae8f19179c5f0f8c6352b3c7855465325d5449a (diff)
downloadmupdf-0a927854a10e1e6b9770a81e2e1d9f3093631757.tar.xz
Rearrange source files.
Diffstat (limited to 'source/tools/pdfinfo.c')
-rw-r--r--source/tools/pdfinfo.c1032
1 files changed, 1032 insertions, 0 deletions
diff --git a/source/tools/pdfinfo.c b/source/tools/pdfinfo.c
new file mode 100644
index 00000000..79743892
--- /dev/null
+++ b/source/tools/pdfinfo.c
@@ -0,0 +1,1032 @@
+/*
+ * Information tool.
+ * Print information about the input pdf.
+ */
+
+#include "mupdf/pdf.h"
+
+pdf_document *xref;
+fz_context *ctx;
+int pagecount;
+
+void closexref(void);
+
+void openxref(char *filename, char *password, int dieonbadpass, int loadpages);
+
+enum
+{
+ DIMENSIONS = 0x01,
+ FONTS = 0x02,
+ IMAGES = 0x04,
+ SHADINGS = 0x08,
+ PATTERNS = 0x10,
+ XOBJS = 0x20,
+ ALL = DIMENSIONS | FONTS | IMAGES | SHADINGS | PATTERNS | XOBJS
+};
+
+struct info
+{
+ int page;
+ pdf_obj *pageref;
+ pdf_obj *pageobj;
+ union {
+ struct {
+ pdf_obj *obj;
+ } info;
+ struct {
+ pdf_obj *obj;
+ } crypt;
+ struct {
+ pdf_obj *obj;
+ fz_rect *bbox;
+ } dim;
+ struct {
+ pdf_obj *obj;
+ pdf_obj *subtype;
+ pdf_obj *name;
+ } font;
+ struct {
+ pdf_obj *obj;
+ pdf_obj *width;
+ pdf_obj *height;
+ pdf_obj *bpc;
+ pdf_obj *filter;
+ pdf_obj *cs;
+ pdf_obj *altcs;
+ } image;
+ struct {
+ pdf_obj *obj;
+ pdf_obj *type;
+ } shading;
+ struct {
+ pdf_obj *obj;
+ pdf_obj *type;
+ pdf_obj *paint;
+ pdf_obj *tiling;
+ pdf_obj *shading;
+ } pattern;
+ struct {
+ pdf_obj *obj;
+ pdf_obj *groupsubtype;
+ pdf_obj *reference;
+ } form;
+ } u;
+};
+
+static struct info *dim = NULL;
+static int dims = 0;
+static struct info *font = NULL;
+static int fonts = 0;
+static struct info *image = NULL;
+static int images = 0;
+static struct info *shading = NULL;
+static int shadings = 0;
+static struct info *pattern = NULL;
+static int patterns = 0;
+static struct info *form = NULL;
+static int forms = 0;
+static struct info *psobj = NULL;
+static int psobjs = 0;
+
+void closexref(void)
+{
+ int i;
+ if (xref)
+ {
+ pdf_close_document(xref);
+ xref = NULL;
+ }
+
+ if (dim)
+ {
+ for (i = 0; i < dims; i++)
+ fz_free(ctx, dim[i].u.dim.bbox);
+ fz_free(ctx, dim);
+ dim = NULL;
+ dims = 0;
+ }
+
+ if (font)
+ {
+ fz_free(ctx, font);
+ font = NULL;
+ fonts = 0;
+ }
+
+ if (image)
+ {
+ fz_free(ctx, image);
+ image = NULL;
+ images = 0;
+ }
+
+ if (shading)
+ {
+ fz_free(ctx, shading);
+ shading = NULL;
+ shadings = 0;
+ }
+
+ if (pattern)
+ {
+ fz_free(ctx, pattern);
+ pattern = NULL;
+ patterns = 0;
+ }
+
+ if (form)
+ {
+ fz_free(ctx, form);
+ form = NULL;
+ forms = 0;
+ }
+
+ if (psobj)
+ {
+ fz_free(ctx, psobj);
+ psobj = NULL;
+ psobjs = 0;
+ }
+}
+
+static void
+infousage(void)
+{
+ fprintf(stderr,
+ "usage: mutool info [options] [file.pdf ... ]\n"
+ "\t-d -\tpassword for decryption\n"
+ "\t-f\tlist fonts\n"
+ "\t-i\tlist images\n"
+ "\t-m\tlist dimensions\n"
+ "\t-p\tlist patterns\n"
+ "\t-s\tlist shadings\n"
+ "\t-x\tlist form and postscript xobjects\n");
+ exit(1);
+}
+
+static void
+showglobalinfo(void)
+{
+ pdf_obj *obj;
+
+ printf("\nPDF-%d.%d\n", xref->version / 10, xref->version % 10);
+
+ obj = pdf_dict_gets(pdf_trailer(xref), "Info");
+ if (obj)
+ {
+ printf("Info object (%d %d R):\n", pdf_to_num(obj), pdf_to_gen(obj));
+ pdf_fprint_obj(stdout, pdf_resolve_indirect(obj), 0);
+ }
+
+ obj = pdf_dict_gets(pdf_trailer(xref), "Encrypt");
+ if (obj)
+ {
+ printf("\nEncryption object (%d %d R):\n", pdf_to_num(obj), pdf_to_gen(obj));
+ pdf_fprint_obj(stdout, pdf_resolve_indirect(obj), 0);
+ }
+
+ printf("\nPages: %d\n\n", pagecount);
+}
+
+static void
+gatherdimensions(int page, pdf_obj *pageref, pdf_obj *pageobj)
+{
+ fz_rect bbox;
+ pdf_obj *obj;
+ int j;
+
+ obj = pdf_dict_gets(pageobj, "MediaBox");
+ if (!pdf_is_array(obj))
+ return;
+
+ pdf_to_rect(ctx, obj, &bbox);
+
+ obj = pdf_dict_gets(pageobj, "UserUnit");
+ if (pdf_is_real(obj))
+ {
+ float unit = pdf_to_real(obj);
+ bbox.x0 *= unit;
+ bbox.y0 *= unit;
+ bbox.x1 *= unit;
+ bbox.y1 *= unit;
+ }
+
+ for (j = 0; j < dims; j++)
+ if (!memcmp(dim[j].u.dim.bbox, &bbox, sizeof (fz_rect)))
+ break;
+
+ if (j < dims)
+ return;
+
+ dim = fz_resize_array(ctx, dim, dims+1, sizeof(struct info));
+ dims++;
+
+ dim[dims - 1].page = page;
+ dim[dims - 1].pageref = pageref;
+ dim[dims - 1].pageobj = pageobj;
+ dim[dims - 1].u.dim.bbox = fz_malloc(ctx, sizeof(fz_rect));
+ memcpy(dim[dims - 1].u.dim.bbox, &bbox, sizeof (fz_rect));
+
+ return;
+}
+
+static void
+gatherfonts(int page, pdf_obj *pageref, pdf_obj *pageobj, pdf_obj *dict)
+{
+ int i, n;
+
+ n = pdf_dict_len(dict);
+ for (i = 0; i < n; i++)
+ {
+ pdf_obj *fontdict = NULL;
+ pdf_obj *subtype = NULL;
+ pdf_obj *basefont = NULL;
+ pdf_obj *name = NULL;
+ int k;
+
+ fontdict = pdf_dict_get_val(dict, i);
+ if (!pdf_is_dict(fontdict))
+ {
+ fz_warn(ctx, "not a font dict (%d %d R)", pdf_to_num(fontdict), pdf_to_gen(fontdict));
+ continue;
+ }
+
+ subtype = pdf_dict_gets(fontdict, "Subtype");
+ basefont = pdf_dict_gets(fontdict, "BaseFont");
+ if (!basefont || pdf_is_null(basefont))
+ name = pdf_dict_gets(fontdict, "Name");
+
+ for (k = 0; k < fonts; k++)
+ if (!pdf_objcmp(font[k].u.font.obj, fontdict))
+ break;
+
+ if (k < fonts)
+ continue;
+
+ font = fz_resize_array(ctx, font, fonts+1, sizeof(struct info));
+ fonts++;
+
+ font[fonts - 1].page = page;
+ font[fonts - 1].pageref = pageref;
+ font[fonts - 1].pageobj = pageobj;
+ font[fonts - 1].u.font.obj = fontdict;
+ font[fonts - 1].u.font.subtype = subtype;
+ font[fonts - 1].u.font.name = basefont ? basefont : name;
+ }
+}
+
+static void
+gatherimages(int page, pdf_obj *pageref, pdf_obj *pageobj, pdf_obj *dict)
+{
+ int i, n;
+
+ n = pdf_dict_len(dict);
+ for (i = 0; i < n; i++)
+ {
+ pdf_obj *imagedict;
+ pdf_obj *type;
+ pdf_obj *width;
+ pdf_obj *height;
+ pdf_obj *bpc = NULL;
+ pdf_obj *filter = NULL;
+ pdf_obj *cs = NULL;
+ pdf_obj *altcs;
+ int k;
+
+ imagedict = pdf_dict_get_val(dict, i);
+ if (!pdf_is_dict(imagedict))
+ {
+ fz_warn(ctx, "not an image dict (%d %d R)", pdf_to_num(imagedict), pdf_to_gen(imagedict));
+ continue;
+ }
+
+ type = pdf_dict_gets(imagedict, "Subtype");
+ if (strcmp(pdf_to_name(type), "Image"))
+ continue;
+
+ filter = pdf_dict_gets(imagedict, "Filter");
+
+ altcs = NULL;
+ cs = pdf_dict_gets(imagedict, "ColorSpace");
+ if (pdf_is_array(cs))
+ {
+ pdf_obj *cses = cs;
+
+ cs = pdf_array_get(cses, 0);
+ if (pdf_is_name(cs) && (!strcmp(pdf_to_name(cs), "DeviceN") || !strcmp(pdf_to_name(cs), "Separation")))
+ {
+ altcs = pdf_array_get(cses, 2);
+ if (pdf_is_array(altcs))
+ altcs = pdf_array_get(altcs, 0);
+ }
+ }
+
+ width = pdf_dict_gets(imagedict, "Width");
+ height = pdf_dict_gets(imagedict, "Height");
+ bpc = pdf_dict_gets(imagedict, "BitsPerComponent");
+
+ for (k = 0; k < images; k++)
+ if (!pdf_objcmp(image[k].u.image.obj, imagedict))
+ break;
+
+ if (k < images)
+ continue;
+
+ image = fz_resize_array(ctx, image, images+1, sizeof(struct info));
+ images++;
+
+ image[images - 1].page = page;
+ image[images - 1].pageref = pageref;
+ image[images - 1].pageobj = pageobj;
+ image[images - 1].u.image.obj = imagedict;
+ image[images - 1].u.image.width = width;
+ image[images - 1].u.image.height = height;
+ image[images - 1].u.image.bpc = bpc;
+ image[images - 1].u.image.filter = filter;
+ image[images - 1].u.image.cs = cs;
+ image[images - 1].u.image.altcs = altcs;
+ }
+}
+
+static void
+gatherforms(int page, pdf_obj *pageref, pdf_obj *pageobj, pdf_obj *dict)
+{
+ int i, n;
+
+ n = pdf_dict_len(dict);
+ for (i = 0; i < n; i++)
+ {
+ pdf_obj *xobjdict;
+ pdf_obj *type;
+ pdf_obj *subtype;
+ pdf_obj *group;
+ pdf_obj *groupsubtype;
+ pdf_obj *reference;
+ int k;
+
+ xobjdict = pdf_dict_get_val(dict, i);
+ if (!pdf_is_dict(xobjdict))
+ {
+ fz_warn(ctx, "not a xobject dict (%d %d R)", pdf_to_num(xobjdict), pdf_to_gen(xobjdict));
+ continue;
+ }
+
+ type = pdf_dict_gets(xobjdict, "Subtype");
+ if (strcmp(pdf_to_name(type), "Form"))
+ continue;
+
+ subtype = pdf_dict_gets(xobjdict, "Subtype2");
+ if (!strcmp(pdf_to_name(subtype), "PS"))
+ continue;
+
+ group = pdf_dict_gets(xobjdict, "Group");
+ groupsubtype = pdf_dict_gets(group, "S");
+ reference = pdf_dict_gets(xobjdict, "Ref");
+
+ for (k = 0; k < forms; k++)
+ if (!pdf_objcmp(form[k].u.form.obj, xobjdict))
+ break;
+
+ if (k < forms)
+ continue;
+
+ form = fz_resize_array(ctx, form, forms+1, sizeof(struct info));
+ forms++;
+
+ form[forms - 1].page = page;
+ form[forms - 1].pageref = pageref;
+ form[forms - 1].pageobj = pageobj;
+ form[forms - 1].u.form.obj = xobjdict;
+ form[forms - 1].u.form.groupsubtype = groupsubtype;
+ form[forms - 1].u.form.reference = reference;
+ }
+}
+
+static void
+gatherpsobjs(int page, pdf_obj *pageref, pdf_obj *pageobj, pdf_obj *dict)
+{
+ int i, n;
+
+ n = pdf_dict_len(dict);
+ for (i = 0; i < n; i++)
+ {
+ pdf_obj *xobjdict;
+ pdf_obj *type;
+ pdf_obj *subtype;
+ int k;
+
+ xobjdict = pdf_dict_get_val(dict, i);
+ if (!pdf_is_dict(xobjdict))
+ {
+ fz_warn(ctx, "not a xobject dict (%d %d R)", pdf_to_num(xobjdict), pdf_to_gen(xobjdict));
+ continue;
+ }
+
+ type = pdf_dict_gets(xobjdict, "Subtype");
+ subtype = pdf_dict_gets(xobjdict, "Subtype2");
+ if (strcmp(pdf_to_name(type), "PS") &&
+ (strcmp(pdf_to_name(type), "Form") || strcmp(pdf_to_name(subtype), "PS")))
+ continue;
+
+ for (k = 0; k < psobjs; k++)
+ if (!pdf_objcmp(psobj[k].u.form.obj, xobjdict))
+ break;
+
+ if (k < psobjs)
+ continue;
+
+ psobj = fz_resize_array(ctx, psobj, psobjs+1, sizeof(struct info));
+ psobjs++;
+
+ psobj[psobjs - 1].page = page;
+ psobj[psobjs - 1].pageref = pageref;
+ psobj[psobjs - 1].pageobj = pageobj;
+ psobj[psobjs - 1].u.form.obj = xobjdict;
+ }
+}
+
+static void
+gathershadings(int page, pdf_obj *pageref, pdf_obj *pageobj, pdf_obj *dict)
+{
+ int i, n;
+
+ n = pdf_dict_len(dict);
+ for (i = 0; i < n; i++)
+ {
+ pdf_obj *shade;
+ pdf_obj *type;
+ int k;
+
+ shade = pdf_dict_get_val(dict, i);
+ if (!pdf_is_dict(shade))
+ {
+ fz_warn(ctx, "not a shading dict (%d %d R)", pdf_to_num(shade), pdf_to_gen(shade));
+ continue;
+ }
+
+ type = pdf_dict_gets(shade, "ShadingType");
+ if (!pdf_is_int(type) || pdf_to_int(type) < 1 || pdf_to_int(type) > 7)
+ {
+ fz_warn(ctx, "not a shading type (%d %d R)", pdf_to_num(shade), pdf_to_gen(shade));
+ type = NULL;
+ }
+
+ for (k = 0; k < shadings; k++)
+ if (!pdf_objcmp(shading[k].u.shading.obj, shade))
+ break;
+
+ if (k < shadings)
+ continue;
+
+ shading = fz_resize_array(ctx, shading, shadings+1, sizeof(struct info));
+ shadings++;
+
+ shading[shadings - 1].page = page;
+ shading[shadings - 1].pageref = pageref;
+ shading[shadings - 1].pageobj = pageobj;
+ shading[shadings - 1].u.shading.obj = shade;
+ shading[shadings - 1].u.shading.type = type;
+ }
+}
+
+static void
+gatherpatterns(int page, pdf_obj *pageref, pdf_obj *pageobj, pdf_obj *dict)
+{
+ int i, n;
+
+ n = pdf_dict_len(dict);
+ for (i = 0; i < n; i++)
+ {
+ pdf_obj *patterndict;
+ pdf_obj *type;
+ pdf_obj *paint = NULL;
+ pdf_obj *tiling = NULL;
+ pdf_obj *shading = NULL;
+ int k;
+
+ patterndict = pdf_dict_get_val(dict, i);
+ if (!pdf_is_dict(patterndict))
+ {
+ fz_warn(ctx, "not a pattern dict (%d %d R)", pdf_to_num(patterndict), pdf_to_gen(patterndict));
+ continue;
+ }
+
+ type = pdf_dict_gets(patterndict, "PatternType");
+ if (!pdf_is_int(type) || pdf_to_int(type) < 1 || pdf_to_int(type) > 2)
+ {
+ fz_warn(ctx, "not a pattern type (%d %d R)", pdf_to_num(patterndict), pdf_to_gen(patterndict));
+ type = NULL;
+ }
+
+ if (pdf_to_int(type) == 1)
+ {
+ paint = pdf_dict_gets(patterndict, "PaintType");
+ if (!pdf_is_int(paint) || pdf_to_int(paint) < 1 || pdf_to_int(paint) > 2)
+ {
+ fz_warn(ctx, "not a pattern paint type (%d %d R)", pdf_to_num(patterndict), pdf_to_gen(patterndict));
+ paint = NULL;
+ }
+
+ tiling = pdf_dict_gets(patterndict, "TilingType");
+ if (!pdf_is_int(tiling) || pdf_to_int(tiling) < 1 || pdf_to_int(tiling) > 3)
+ {
+ fz_warn(ctx, "not a pattern tiling type (%d %d R)", pdf_to_num(patterndict), pdf_to_gen(patterndict));
+ tiling = NULL;
+ }
+ }
+ else
+ {
+ shading = pdf_dict_gets(patterndict, "Shading");
+ }
+
+ for (k = 0; k < patterns; k++)
+ if (!pdf_objcmp(pattern[k].u.pattern.obj, patterndict))
+ break;
+
+ if (k < patterns)
+ continue;
+
+ pattern = fz_resize_array(ctx, pattern, patterns+1, sizeof(struct info));
+ patterns++;
+
+ pattern[patterns - 1].page = page;
+ pattern[patterns - 1].pageref = pageref;
+ pattern[patterns - 1].pageobj = pageobj;
+ pattern[patterns - 1].u.pattern.obj = patterndict;
+ pattern[patterns - 1].u.pattern.type = type;
+ pattern[patterns - 1].u.pattern.paint = paint;
+ pattern[patterns - 1].u.pattern.tiling = tiling;
+ pattern[patterns - 1].u.pattern.shading = shading;
+ }
+}
+
+static void
+gatherresourceinfo(int page, pdf_obj *rsrc, int show)
+{
+ pdf_obj *pageobj;
+ pdf_obj *pageref;
+ pdf_obj *font;
+ pdf_obj *xobj;
+ pdf_obj *shade;
+ pdf_obj *pattern;
+ pdf_obj *subrsrc;
+ int i;
+
+ pageobj = xref->page_objs[page-1];
+ pageref = xref->page_refs[page-1];
+
+ if (!pageobj)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cannot retrieve info from page %d", page);
+
+ font = pdf_dict_gets(rsrc, "Font");
+ if (show & FONTS && font)
+ {
+ int n;
+
+ gatherfonts(page, pageref, pageobj, font);
+ n = pdf_dict_len(font);
+ for (i = 0; i < n; i++)
+ {
+ pdf_obj *obj = pdf_dict_get_val(font, i);
+
+ subrsrc = pdf_dict_gets(obj, "Resources");
+ if (subrsrc && pdf_objcmp(rsrc, subrsrc))
+ gatherresourceinfo(page, subrsrc, show);
+ }
+ }
+
+ xobj = pdf_dict_gets(rsrc, "XObject");
+ if (show & XOBJS && xobj)
+ {
+ int n;
+
+ gatherimages(page, pageref, pageobj, xobj);
+ gatherforms(page, pageref, pageobj, xobj);
+ gatherpsobjs(page, pageref, pageobj, xobj);
+ n = pdf_dict_len(xobj);
+ for (i = 0; i < n; i++)
+ {
+ pdf_obj *obj = pdf_dict_get_val(xobj, i);
+ subrsrc = pdf_dict_gets(obj, "Resources");
+ if (subrsrc && pdf_objcmp(rsrc, subrsrc))
+ gatherresourceinfo(page, subrsrc, show);
+ }
+ }
+
+ shade = pdf_dict_gets(rsrc, "Shading");
+ if (show & SHADINGS && shade)
+ gathershadings(page, pageref, pageobj, shade);
+
+ pattern = pdf_dict_gets(rsrc, "Pattern");
+ if (show & PATTERNS && pattern)
+ {
+ int n;
+ gatherpatterns(page, pageref, pageobj, pattern);
+ n = pdf_dict_len(pattern);
+ for (i = 0; i < n; i++)
+ {
+ pdf_obj *obj = pdf_dict_get_val(pattern, i);
+ subrsrc = pdf_dict_gets(obj, "Resources");
+ if (subrsrc && pdf_objcmp(rsrc, subrsrc))
+ gatherresourceinfo(page, subrsrc, show);
+ }
+ }
+}
+
+static void
+gatherpageinfo(int page, int show)
+{
+ pdf_obj *pageobj;
+ pdf_obj *pageref;
+ pdf_obj *rsrc;
+
+ pageobj = xref->page_objs[page-1];
+ pageref = xref->page_refs[page-1];
+
+ if (!pageobj)
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cannot retrieve info from page %d", page);
+
+ gatherdimensions(page, pageref, pageobj);
+
+ rsrc = pdf_dict_gets(pageobj, "Resources");
+ gatherresourceinfo(page, rsrc, show);
+}
+
+static void
+printinfo(char *filename, int show, int page)
+{
+ int i;
+ int j;
+
+#define PAGE_FMT "\t% 5d (% 7d %1d R): "
+
+ if (show & DIMENSIONS && dims > 0)
+ {
+ printf("Mediaboxes (%d):\n", dims);
+ for (i = 0; i < dims; i++)
+ {
+ printf(PAGE_FMT "[ %g %g %g %g ]\n",
+ dim[i].page,
+ pdf_to_num(dim[i].pageref), pdf_to_gen(dim[i].pageref),
+ dim[i].u.dim.bbox->x0,
+ dim[i].u.dim.bbox->y0,
+ dim[i].u.dim.bbox->x1,
+ dim[i].u.dim.bbox->y1);
+ }
+ printf("\n");
+ }
+
+ if (show & FONTS && fonts > 0)
+ {
+ printf("Fonts (%d):\n", fonts);
+ for (i = 0; i < fonts; i++)
+ {
+ printf(PAGE_FMT "%s '%s' (%d %d R)\n",
+ font[i].page,
+ pdf_to_num(font[i].pageref), pdf_to_gen(font[i].pageref),
+ pdf_to_name(font[i].u.font.subtype),
+ pdf_to_name(font[i].u.font.name),
+ pdf_to_num(font[i].u.font.obj), pdf_to_gen(font[i].u.font.obj));
+ }
+ printf("\n");
+ }
+
+ if (show & IMAGES && images > 0)
+ {
+ printf("Images (%d):\n", images);
+ for (i = 0; i < images; i++)
+ {
+ char *cs = NULL;
+ char *altcs = NULL;
+
+ printf(PAGE_FMT "[ ",
+ image[i].page,
+ pdf_to_num(image[i].pageref), pdf_to_gen(image[i].pageref));
+
+ if (pdf_is_array(image[i].u.image.filter))
+ {
+ int n = pdf_array_len(image[i].u.image.filter);
+ for (j = 0; j < n; j++)
+ {
+ pdf_obj *obj = pdf_array_get(image[i].u.image.filter, j);
+ char *filter = fz_strdup(ctx, pdf_to_name(obj));
+
+ if (strstr(filter, "Decode"))
+ *(strstr(filter, "Decode")) = '\0';
+
+ printf("%s%s",
+ filter,
+ j == pdf_array_len(image[i].u.image.filter) - 1 ? "" : " ");
+ fz_free(ctx, filter);
+ }
+ }
+ else if (image[i].u.image.filter)
+ {
+ pdf_obj *obj = image[i].u.image.filter;
+ char *filter = fz_strdup(ctx, pdf_to_name(obj));
+
+ if (strstr(filter, "Decode"))
+ *(strstr(filter, "Decode")) = '\0';
+
+ printf("%s", filter);
+ fz_free(ctx, filter);
+ }
+ else
+ printf("Raw");
+
+ if (image[i].u.image.cs)
+ {
+ cs = fz_strdup(ctx, pdf_to_name(image[i].u.image.cs));
+
+ if (!strncmp(cs, "Device", 6))
+ {
+ int len = strlen(cs + 6);
+ memmove(cs + 3, cs + 6, len + 1);
+ cs[3 + len + 1] = '\0';
+ }
+ if (strstr(cs, "ICC"))
+ fz_strlcpy(cs, "ICC", 4);
+ if (strstr(cs, "Indexed"))
+ fz_strlcpy(cs, "Idx", 4);
+ if (strstr(cs, "Pattern"))
+ fz_strlcpy(cs, "Pat", 4);
+ if (strstr(cs, "Separation"))
+ fz_strlcpy(cs, "Sep", 4);
+ }
+ if (image[i].u.image.altcs)
+ {
+ altcs = fz_strdup(ctx, pdf_to_name(image[i].u.image.altcs));
+
+ if (!strncmp(altcs, "Device", 6))
+ {
+ int len = strlen(altcs + 6);
+ memmove(altcs + 3, altcs + 6, len + 1);
+ altcs[3 + len + 1] = '\0';
+ }
+ if (strstr(altcs, "ICC"))
+ fz_strlcpy(altcs, "ICC", 4);
+ if (strstr(altcs, "Indexed"))
+ fz_strlcpy(altcs, "Idx", 4);
+ if (strstr(altcs, "Pattern"))
+ fz_strlcpy(altcs, "Pat", 4);
+ if (strstr(altcs, "Separation"))
+ fz_strlcpy(altcs, "Sep", 4);
+ }
+
+ printf(" ] %dx%d %dbpc %s%s%s (%d %d R)\n",
+ pdf_to_int(image[i].u.image.width),
+ pdf_to_int(image[i].u.image.height),
+ image[i].u.image.bpc ? pdf_to_int(image[i].u.image.bpc) : 1,
+ image[i].u.image.cs ? cs : "ImageMask",
+ image[i].u.image.altcs ? " " : "",
+ image[i].u.image.altcs ? altcs : "",
+ pdf_to_num(image[i].u.image.obj), pdf_to_gen(image[i].u.image.obj));
+
+ fz_free(ctx, cs);
+ fz_free(ctx, altcs);
+ }
+ printf("\n");
+ }
+
+ if (show & SHADINGS && shadings > 0)
+ {
+ printf("Shading patterns (%d):\n", shadings);
+ for (i = 0; i < shadings; i++)
+ {
+ char *shadingtype[] =
+ {
+ "",
+ "Function",
+ "Axial",
+ "Radial",
+ "Triangle mesh",
+ "Lattice",
+ "Coons patch",
+ "Tensor patch",
+ };
+
+ printf(PAGE_FMT "%s (%d %d R)\n",
+ shading[i].page,
+ pdf_to_num(shading[i].pageref), pdf_to_gen(shading[i].pageref),
+ shadingtype[pdf_to_int(shading[i].u.shading.type)],
+ pdf_to_num(shading[i].u.shading.obj), pdf_to_gen(shading[i].u.shading.obj));
+ }
+ printf("\n");
+ }
+
+ if (show & PATTERNS && patterns > 0)
+ {
+ printf("Patterns (%d):\n", patterns);
+ for (i = 0; i < patterns; i++)
+ {
+ if (pdf_to_int(pattern[i].u.pattern.type) == 1)
+ {
+ char *painttype[] =
+ {
+ "",
+ "Colored",
+ "Uncolored",
+ };
+ char *tilingtype[] =
+ {
+ "",
+ "Constant",
+ "No distortion",
+ "Constant/fast tiling",
+ };
+
+ printf(PAGE_FMT "Tiling %s %s (%d %d R)\n",
+ pattern[i].page,
+ pdf_to_num(pattern[i].pageref), pdf_to_gen(pattern[i].pageref),
+ painttype[pdf_to_int(pattern[i].u.pattern.paint)],
+ tilingtype[pdf_to_int(pattern[i].u.pattern.tiling)],
+ pdf_to_num(pattern[i].u.pattern.obj), pdf_to_gen(pattern[i].u.pattern.obj));
+ }
+ else
+ {
+ printf(PAGE_FMT "Shading %d %d R (%d %d R)\n",
+ pattern[i].page,
+ pdf_to_num(pattern[i].pageref), pdf_to_gen(pattern[i].pageref),
+ pdf_to_num(pattern[i].u.pattern.shading), pdf_to_gen(pattern[i].u.pattern.shading),
+ pdf_to_num(pattern[i].u.pattern.obj), pdf_to_gen(pattern[i].u.pattern.obj));
+ }
+ }
+ printf("\n");
+ }
+
+ if (show & XOBJS && forms > 0)
+ {
+ printf("Form xobjects (%d):\n", forms);
+ for (i = 0; i < forms; i++)
+ {
+ printf(PAGE_FMT "Form%s%s%s%s (%d %d R)\n",
+ form[i].page,
+ pdf_to_num(form[i].pageref), pdf_to_gen(form[i].pageref),
+ form[i].u.form.groupsubtype ? " " : "",
+ form[i].u.form.groupsubtype ? pdf_to_name(form[i].u.form.groupsubtype) : "",
+ form[i].u.form.groupsubtype ? " Group" : "",
+ form[i].u.form.reference ? " Reference" : "",
+ pdf_to_num(form[i].u.form.obj), pdf_to_gen(form[i].u.form.obj));
+ }
+ printf("\n");
+ }
+
+ if (show & XOBJS && psobjs > 0)
+ {
+ printf("Postscript xobjects (%d):\n", psobjs);
+ for (i = 0; i < psobjs; i++)
+ {
+ printf(PAGE_FMT "(%d %d R)\n",
+ psobj[i].page,
+ pdf_to_num(psobj[i].pageref), pdf_to_gen(psobj[i].pageref),
+ pdf_to_num(psobj[i].u.form.obj), pdf_to_gen(psobj[i].u.form.obj));
+ }
+ printf("\n");
+ }
+}
+
+static void
+showinfo(char *filename, int show, char *pagelist)
+{
+ int page, spage, epage;
+ char *spec, *dash;
+ int allpages;
+ int pagecount;
+
+ if (!xref)
+ infousage();
+
+ allpages = !strcmp(pagelist, "1-");
+
+ pagecount = pdf_count_pages(xref);
+ spec = fz_strsep(&pagelist, ",");
+ while (spec && pagecount)
+ {
+ dash = strchr(spec, '-');
+
+ if (dash == spec)
+ spage = epage = pagecount;
+ else
+ spage = epage = atoi(spec);
+
+ if (dash)
+ {
+ if (strlen(dash) > 1)
+ epage = atoi(dash + 1);
+ else
+ epage = pagecount;
+ }
+
+ if (spage > epage)
+ page = spage, spage = epage, epage = page;
+
+ spage = fz_clampi(spage, 1, pagecount);
+ epage = fz_clampi(epage, 1, pagecount);
+
+ if (allpages)
+ printf("Retrieving info from pages %d-%d...\n", spage, epage);
+ for (page = spage; page <= epage; page++)
+ {
+ gatherpageinfo(page, show);
+ if (!allpages)
+ {
+ printf("Page %d:\n", page);
+ printinfo(filename, show, page);
+ printf("\n");
+ }
+ }
+
+ spec = fz_strsep(&pagelist, ",");
+ }
+
+ if (allpages)
+ printinfo(filename, show, -1);
+}
+
+static int arg_is_page_range(const char *arg)
+{
+ int c;
+
+ while ((c = *arg++) != 0)
+ {
+ if ((c < '0' || c > '9') && (c != '-') && (c != ','))
+ return 0;
+ }
+ return 1;
+}
+
+int pdfinfo_main(int argc, char **argv)
+{
+ enum { NO_FILE_OPENED, NO_INFO_GATHERED, INFO_SHOWN } state;
+ char *filename = "";
+ char *password = "";
+ int show = ALL;
+ int c;
+
+ while ((c = fz_getopt(argc, argv, "mfispxd:")) != -1)
+ {
+ switch (c)
+ {
+ case 'm': if (show == ALL) show = DIMENSIONS; else show |= DIMENSIONS; break;
+ case 'f': if (show == ALL) show = FONTS; else show |= FONTS; break;
+ case 'i': if (show == ALL) show = IMAGES; else show |= IMAGES; break;
+ case 's': if (show == ALL) show = SHADINGS; else show |= SHADINGS; break;
+ case 'p': if (show == ALL) show = PATTERNS; else show |= PATTERNS; break;
+ case 'x': if (show == ALL) show = XOBJS; else show |= XOBJS; break;
+ case 'd': password = fz_optarg; break;
+ default:
+ infousage();
+ break;
+ }
+ }
+
+ if (fz_optind == argc)
+ infousage();
+
+ ctx = fz_new_context(NULL, NULL, FZ_STORE_UNLIMITED);
+ if (!ctx)
+ {
+ fprintf(stderr, "cannot initialise context\n");
+ exit(1);
+ }
+
+ state = NO_FILE_OPENED;
+ while (fz_optind < argc)
+ {
+ if (state == NO_FILE_OPENED || !arg_is_page_range(argv[fz_optind]))
+ {
+ if (state == NO_INFO_GATHERED)
+ {
+ showinfo(filename, show, "1-");
+ closexref();
+ }
+
+ closexref();
+
+ filename = argv[fz_optind];
+ printf("%s:\n", filename);
+ xref = pdf_open_document_no_run(ctx, filename);
+ if (pdf_needs_password(xref))
+ if (!pdf_authenticate_password(xref, password))
+ fz_throw(ctx, FZ_ERROR_GENERIC, "cannot authenticate password: %s", filename);
+ pagecount = pdf_count_pages(xref);
+
+ showglobalinfo();
+ state = NO_INFO_GATHERED;
+ }
+ else
+ {
+ showinfo(filename, show, argv[fz_optind]);
+ state = INFO_SHOWN;
+ }
+
+ fz_optind++;
+ }
+
+ if (state == NO_INFO_GATHERED)
+ showinfo(filename, show, "1-");
+
+ closexref();
+ fz_free_context(ctx);
+ return 0;
+}