summaryrefslogtreecommitdiff
path: root/apps/mupdfinfo.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/mupdfinfo.c')
-rw-r--r--apps/mupdfinfo.c1020
1 files changed, 1020 insertions, 0 deletions
diff --git a/apps/mupdfinfo.c b/apps/mupdfinfo.c
new file mode 100644
index 00000000..c6c6b35c
--- /dev/null
+++ b/apps/mupdfinfo.c
@@ -0,0 +1,1020 @@
+/*
+ * Information tool.
+ * Print information about the input pdf.
+ */
+
+#include "fitz.h"
+#include "mupdf.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;
+ fz_obj *pageref;
+ fz_obj *pageobj;
+ union {
+ struct {
+ fz_obj *obj;
+ } info;
+ struct {
+ fz_obj *obj;
+ } crypt;
+ struct {
+ fz_obj *obj;
+ fz_rect *bbox;
+ } dim;
+ struct {
+ fz_obj *obj;
+ fz_obj *subtype;
+ fz_obj *name;
+ } font;
+ struct {
+ fz_obj *obj;
+ fz_obj *width;
+ fz_obj *height;
+ fz_obj *bpc;
+ fz_obj *filter;
+ fz_obj *cs;
+ fz_obj *altcs;
+ } image;
+ struct {
+ fz_obj *obj;
+ fz_obj *type;
+ } shading;
+ struct {
+ fz_obj *obj;
+ fz_obj *type;
+ fz_obj *paint;
+ fz_obj *tiling;
+ fz_obj *shading;
+ } pattern;
+ struct {
+ fz_obj *obj;
+ fz_obj *groupsubtype;
+ fz_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: pdfinfo [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)
+{
+ fz_obj *obj;
+
+ printf("\nPDF-%d.%d\n", xref->version / 10, xref->version % 10);
+
+ obj = fz_dict_gets(xref->trailer, "Info");
+ if (obj)
+ {
+ printf("Info object (%d %d R):\n", fz_to_num(obj), fz_to_gen(obj));
+ fz_debug_obj(fz_resolve_indirect(obj));
+ }
+
+ obj = fz_dict_gets(xref->trailer, "Encrypt");
+ if (obj)
+ {
+ printf("\nEncryption object (%d %d R):\n", fz_to_num(obj), fz_to_gen(obj));
+ fz_debug_obj(fz_resolve_indirect(obj));
+ }
+
+ printf("\nPages: %d\n\n", pagecount);
+}
+
+static void
+gatherdimensions(int page, fz_obj *pageref, fz_obj *pageobj)
+{
+ fz_rect bbox;
+ fz_obj *obj;
+ int j;
+
+ obj = fz_dict_gets(pageobj, "MediaBox");
+ if (!fz_is_array(obj))
+ return;
+
+ bbox = pdf_to_rect(ctx, obj);
+
+ for (j = 0; j < dims; j++)
+ if (!memcmp(dim[j].u.dim.bbox, &bbox, sizeof (fz_rect)))
+ break;
+
+ if (j < dims)
+ return;
+
+ dims++;
+
+ dim = fz_resize_array(ctx, dim, dims, sizeof(struct info));
+ 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, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict)
+{
+ int i, n;
+
+ n = fz_dict_len(dict);
+ for (i = 0; i < n; i++)
+ {
+ fz_obj *fontdict = NULL;
+ fz_obj *subtype = NULL;
+ fz_obj *basefont = NULL;
+ fz_obj *name = NULL;
+ int k;
+
+ fontdict = fz_dict_get_val(dict, i);
+ if (!fz_is_dict(fontdict))
+ {
+ fz_warn(ctx, "not a font dict (%d %d R)", fz_to_num(fontdict), fz_to_gen(fontdict));
+ continue;
+ }
+
+ subtype = fz_dict_gets(fontdict, "Subtype");
+ basefont = fz_dict_gets(fontdict, "BaseFont");
+ if (!basefont || fz_is_null(basefont))
+ name = fz_dict_gets(fontdict, "Name");
+
+ for (k = 0; k < fonts; k++)
+ if (!fz_objcmp(font[k].u.font.obj, fontdict))
+ break;
+
+ if (k < fonts)
+ continue;
+
+ fonts++;
+
+ font = fz_resize_array(ctx, font, fonts, sizeof(struct info));
+ 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, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict)
+{
+ int i, n;
+
+ n = fz_dict_len(dict);
+ for (i = 0; i < n; i++)
+ {
+ fz_obj *imagedict;
+ fz_obj *type;
+ fz_obj *width;
+ fz_obj *height;
+ fz_obj *bpc = NULL;
+ fz_obj *filter = NULL;
+ fz_obj *cs = NULL;
+ fz_obj *altcs;
+ int k;
+
+ imagedict = fz_dict_get_val(dict, i);
+ if (!fz_is_dict(imagedict))
+ {
+ fz_warn(ctx, "not an image dict (%d %d R)", fz_to_num(imagedict), fz_to_gen(imagedict));
+ continue;
+ }
+
+ type = fz_dict_gets(imagedict, "Subtype");
+ if (strcmp(fz_to_name(type), "Image"))
+ continue;
+
+ filter = fz_dict_gets(imagedict, "Filter");
+
+ altcs = NULL;
+ cs = fz_dict_gets(imagedict, "ColorSpace");
+ if (fz_is_array(cs))
+ {
+ fz_obj *cses = cs;
+
+ cs = fz_array_get(cses, 0);
+ if (fz_is_name(cs) && (!strcmp(fz_to_name(cs), "DeviceN") || !strcmp(fz_to_name(cs), "Separation")))
+ {
+ altcs = fz_array_get(cses, 2);
+ if (fz_is_array(altcs))
+ altcs = fz_array_get(altcs, 0);
+ }
+ }
+
+ width = fz_dict_gets(imagedict, "Width");
+ height = fz_dict_gets(imagedict, "Height");
+ bpc = fz_dict_gets(imagedict, "BitsPerComponent");
+
+ for (k = 0; k < images; k++)
+ if (!fz_objcmp(image[k].u.image.obj, imagedict))
+ break;
+
+ if (k < images)
+ continue;
+
+ images++;
+
+ image = fz_resize_array(ctx, image, images, sizeof(struct info));
+ 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, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict)
+{
+ int i, n;
+
+ n = fz_dict_len(dict);
+ for (i = 0; i < n; i++)
+ {
+ fz_obj *xobjdict;
+ fz_obj *type;
+ fz_obj *subtype;
+ fz_obj *group;
+ fz_obj *groupsubtype;
+ fz_obj *reference;
+ int k;
+
+ xobjdict = fz_dict_get_val(dict, i);
+ if (!fz_is_dict(xobjdict))
+ {
+ fz_warn(ctx, "not a xobject dict (%d %d R)", fz_to_num(xobjdict), fz_to_gen(xobjdict));
+ continue;
+ }
+
+ type = fz_dict_gets(xobjdict, "Subtype");
+ if (strcmp(fz_to_name(type), "Form"))
+ continue;
+
+ subtype = fz_dict_gets(xobjdict, "Subtype2");
+ if (!strcmp(fz_to_name(subtype), "PS"))
+ continue;
+
+ group = fz_dict_gets(xobjdict, "Group");
+ groupsubtype = fz_dict_gets(group, "S");
+ reference = fz_dict_gets(xobjdict, "Ref");
+
+ for (k = 0; k < forms; k++)
+ if (!fz_objcmp(form[k].u.form.obj, xobjdict))
+ break;
+
+ if (k < forms)
+ continue;
+
+ forms++;
+
+ form = fz_resize_array(ctx, form, forms, sizeof(struct info));
+ 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, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict)
+{
+ int i, n;
+
+ n = fz_dict_len(dict);
+ for (i = 0; i < n; i++)
+ {
+ fz_obj *xobjdict;
+ fz_obj *type;
+ fz_obj *subtype;
+ int k;
+
+ xobjdict = fz_dict_get_val(dict, i);
+ if (!fz_is_dict(xobjdict))
+ {
+ fz_warn(ctx, "not a xobject dict (%d %d R)", fz_to_num(xobjdict), fz_to_gen(xobjdict));
+ continue;
+ }
+
+ type = fz_dict_gets(xobjdict, "Subtype");
+ subtype = fz_dict_gets(xobjdict, "Subtype2");
+ if (strcmp(fz_to_name(type), "PS") &&
+ (strcmp(fz_to_name(type), "Form") || strcmp(fz_to_name(subtype), "PS")))
+ continue;
+
+ for (k = 0; k < psobjs; k++)
+ if (!fz_objcmp(psobj[k].u.form.obj, xobjdict))
+ break;
+
+ if (k < psobjs)
+ continue;
+
+ psobjs++;
+
+ psobj = fz_resize_array(ctx, psobj, psobjs, sizeof(struct info));
+ 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, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict)
+{
+ int i, n;
+
+ n = fz_dict_len(dict);
+ for (i = 0; i < n; i++)
+ {
+ fz_obj *shade;
+ fz_obj *type;
+ int k;
+
+ shade = fz_dict_get_val(dict, i);
+ if (!fz_is_dict(shade))
+ {
+ fz_warn(ctx, "not a shading dict (%d %d R)", fz_to_num(shade), fz_to_gen(shade));
+ continue;
+ }
+
+ type = fz_dict_gets(shade, "ShadingType");
+ if (!fz_is_int(type) || fz_to_int(type) < 1 || fz_to_int(type) > 7)
+ {
+ fz_warn(ctx, "not a shading type (%d %d R)", fz_to_num(shade), fz_to_gen(shade));
+ type = NULL;
+ }
+
+ for (k = 0; k < shadings; k++)
+ if (!fz_objcmp(shading[k].u.shading.obj, shade))
+ break;
+
+ if (k < shadings)
+ continue;
+
+ shadings++;
+
+ shading = fz_resize_array(ctx, shading, shadings, sizeof(struct info));
+ 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, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict)
+{
+ int i, n;
+
+ n = fz_dict_len(dict);
+ for (i = 0; i < n; i++)
+ {
+ fz_obj *patterndict;
+ fz_obj *type;
+ fz_obj *paint = NULL;
+ fz_obj *tiling = NULL;
+ fz_obj *shading = NULL;
+ int k;
+
+ patterndict = fz_dict_get_val(dict, i);
+ if (!fz_is_dict(patterndict))
+ {
+ fz_warn(ctx, "not a pattern dict (%d %d R)", fz_to_num(patterndict), fz_to_gen(patterndict));
+ continue;
+ }
+
+ type = fz_dict_gets(patterndict, "PatternType");
+ if (!fz_is_int(type) || fz_to_int(type) < 1 || fz_to_int(type) > 2)
+ {
+ fz_warn(ctx, "not a pattern type (%d %d R)", fz_to_num(patterndict), fz_to_gen(patterndict));
+ type = NULL;
+ }
+
+ if (fz_to_int(type) == 1)
+ {
+ paint = fz_dict_gets(patterndict, "PaintType");
+ if (!fz_is_int(paint) || fz_to_int(paint) < 1 || fz_to_int(paint) > 2)
+ {
+ fz_warn(ctx, "not a pattern paint type (%d %d R)", fz_to_num(patterndict), fz_to_gen(patterndict));
+ paint = NULL;
+ }
+
+ tiling = fz_dict_gets(patterndict, "TilingType");
+ if (!fz_is_int(tiling) || fz_to_int(tiling) < 1 || fz_to_int(tiling) > 3)
+ {
+ fz_warn(ctx, "not a pattern tiling type (%d %d R)", fz_to_num(patterndict), fz_to_gen(patterndict));
+ tiling = NULL;
+ }
+ }
+ else
+ {
+ shading = fz_dict_gets(patterndict, "Shading");
+ }
+
+ for (k = 0; k < patterns; k++)
+ if (!fz_objcmp(pattern[k].u.pattern.obj, patterndict))
+ break;
+
+ if (k < patterns)
+ continue;
+
+ patterns++;
+
+ pattern = fz_resize_array(ctx, pattern, patterns, sizeof(struct info));
+ 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, fz_obj *rsrc)
+{
+ fz_obj *pageobj;
+ fz_obj *pageref;
+ fz_obj *font;
+ fz_obj *xobj;
+ fz_obj *shade;
+ fz_obj *pattern;
+ fz_obj *subrsrc;
+ int i;
+
+ pageobj = xref->page_objs[page-1];
+ pageref = xref->page_refs[page-1];
+
+ if (!pageobj)
+ fz_throw(ctx, "cannot retrieve info from page %d", page);
+
+ font = fz_dict_gets(rsrc, "Font");
+ if (font)
+ {
+ int n;
+
+ gatherfonts(page, pageref, pageobj, font);
+ n = fz_dict_len(font);
+ for (i = 0; i < n; i++)
+ {
+ fz_obj *obj = fz_dict_get_val(font, i);
+
+ subrsrc = fz_dict_gets(obj, "Resources");
+ if (subrsrc && fz_objcmp(rsrc, subrsrc))
+ gatherresourceinfo(page, subrsrc);
+ }
+ }
+
+ xobj = fz_dict_gets(rsrc, "XObject");
+ if (xobj)
+ {
+ int n;
+
+ gatherimages(page, pageref, pageobj, xobj);
+ gatherforms(page, pageref, pageobj, xobj);
+ gatherpsobjs(page, pageref, pageobj, xobj);
+ n = fz_dict_len(xobj);
+ for (i = 0; i < n; i++)
+ {
+ fz_obj *obj = fz_dict_get_val(xobj, i);
+ subrsrc = fz_dict_gets(obj, "Resources");
+ if (subrsrc && fz_objcmp(rsrc, subrsrc))
+ gatherresourceinfo(page, subrsrc);
+ }
+ }
+
+ shade = fz_dict_gets(rsrc, "Shading");
+ if (shade)
+ gathershadings(page, pageref, pageobj, shade);
+
+ pattern = fz_dict_gets(rsrc, "Pattern");
+ if (pattern)
+ {
+ int n;
+ gatherpatterns(page, pageref, pageobj, pattern);
+ n = fz_dict_len(pattern);
+ for (i = 0; i < n; i++)
+ {
+ fz_obj *obj = fz_dict_get_val(pattern, i);
+ subrsrc = fz_dict_gets(obj, "Resources");
+ if (subrsrc && fz_objcmp(rsrc, subrsrc))
+ gatherresourceinfo(page, subrsrc);
+ }
+ }
+}
+
+static void
+gatherpageinfo(int page)
+{
+ fz_obj *pageobj;
+ fz_obj *pageref;
+ fz_obj *rsrc;
+
+ pageobj = xref->page_objs[page-1];
+ pageref = xref->page_refs[page-1];
+
+ if (!pageobj)
+ fz_throw(ctx, "cannot retrieve info from page %d", page);
+
+ gatherdimensions(page, pageref, pageobj);
+
+ rsrc = fz_dict_gets(pageobj, "Resources");
+ gatherresourceinfo(page, rsrc);
+}
+
+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,
+ fz_to_num(dim[i].pageref), fz_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,
+ fz_to_num(font[i].pageref), fz_to_gen(font[i].pageref),
+ fz_to_name(font[i].u.font.subtype),
+ fz_to_name(font[i].u.font.name),
+ fz_to_num(font[i].u.font.obj), fz_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,
+ fz_to_num(image[i].pageref), fz_to_gen(image[i].pageref));
+
+ if (fz_is_array(image[i].u.image.filter))
+ {
+ int n = fz_array_len(image[i].u.image.filter);
+ for (j = 0; j < n; j++)
+ {
+ fz_obj *obj = fz_array_get(image[i].u.image.filter, j);
+ char *filter = fz_strdup(ctx, fz_to_name(obj));
+
+ if (strstr(filter, "Decode"))
+ *(strstr(filter, "Decode")) = '\0';
+
+ printf("%s%s",
+ filter,
+ j == fz_array_len(image[i].u.image.filter) - 1 ? "" : " ");
+ fz_free(ctx, filter);
+ }
+ }
+ else if (image[i].u.image.filter)
+ {
+ fz_obj *obj = image[i].u.image.filter;
+ char *filter = fz_strdup(ctx, fz_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, fz_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, fz_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",
+ fz_to_int(image[i].u.image.width),
+ fz_to_int(image[i].u.image.height),
+ image[i].u.image.bpc ? fz_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 : "",
+ fz_to_num(image[i].u.image.obj), fz_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,
+ fz_to_num(shading[i].pageref), fz_to_gen(shading[i].pageref),
+ shadingtype[fz_to_int(shading[i].u.shading.type)],
+ fz_to_num(shading[i].u.shading.obj), fz_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 (fz_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,
+ fz_to_num(pattern[i].pageref), fz_to_gen(pattern[i].pageref),
+ painttype[fz_to_int(pattern[i].u.pattern.paint)],
+ tilingtype[fz_to_int(pattern[i].u.pattern.tiling)],
+ fz_to_num(pattern[i].u.pattern.obj), fz_to_gen(pattern[i].u.pattern.obj));
+ }
+ else
+ {
+ printf(PAGE_FMT "Shading %d %d R (%d %d R)\n",
+ pattern[i].page,
+ fz_to_num(pattern[i].pageref), fz_to_gen(pattern[i].pageref),
+ fz_to_num(pattern[i].u.pattern.shading), fz_to_gen(pattern[i].u.pattern.shading),
+ fz_to_num(pattern[i].u.pattern.obj), fz_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,
+ fz_to_num(form[i].pageref), fz_to_gen(form[i].pageref),
+ form[i].u.form.groupsubtype ? " " : "",
+ form[i].u.form.groupsubtype ? fz_to_name(form[i].u.form.groupsubtype) : "",
+ form[i].u.form.groupsubtype ? " Group" : "",
+ form[i].u.form.reference ? " Reference" : "",
+ fz_to_num(form[i].u.form.obj), fz_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,
+ fz_to_num(psobj[i].pageref), fz_to_gen(psobj[i].pageref),
+ fz_to_num(psobj[i].u.form.obj), fz_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;
+
+ if (!xref)
+ infousage();
+
+ allpages = !strcmp(pagelist, "1-");
+
+ spec = fz_strsep(&pagelist, ",");
+ while (spec)
+ {
+ 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;
+
+ if (spage < 1)
+ spage = 1;
+ if (epage > pagecount)
+ epage = pagecount;
+ if (spage > pagecount)
+ spage = pagecount;
+
+ if (allpages)
+ printf("Retrieving info from pages %d-%d...\n", spage, epage);
+ if (spage >= 1)
+ {
+ for (page = spage; page <= epage; page++)
+ {
+ gatherpageinfo(page);
+ if (!allpages)
+ {
+ printf("Page %d:\n", page);
+ printinfo(filename, show, page);
+ printf("\n");
+ }
+ }
+ }
+
+ spec = fz_strsep(&pagelist, ",");
+ }
+
+ if (allpages)
+ printinfo(filename, show, -1);
+}
+
+#ifdef MUPDF_COMBINED_EXE
+int pdfinfo_main(int argc, char **argv)
+#else
+int main(int argc, char **argv)
+#endif
+{
+ 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, FZ_STORE_UNLIMITED);
+ if (!ctx)
+ {
+ fprintf(stderr, "cannot initialise context\n");
+ exit(1);
+ }
+
+ state = NO_FILE_OPENED;
+ while (fz_optind < argc)
+ {
+ if (strstr(argv[fz_optind], ".pdf") || strstr(argv[fz_optind], ".PDF"))
+ {
+ if (state == NO_INFO_GATHERED)
+ {
+ showinfo(filename, show, "1-");
+ closexref();
+ }
+
+ closexref();
+
+ filename = argv[fz_optind];
+ printf("%s:\n", filename);
+ xref = pdf_open_document(ctx, filename);
+ if (pdf_needs_password(xref))
+ if (!pdf_authenticate_password(xref, password))
+ fz_throw(ctx, "cannot authenticate password: %s\n", 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;
+}