/* * Information tool. * Print information about the input pdf. */ #include "pdftool.h" 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 *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; } pattern; struct { fz_obj *obj; fz_obj *group; fz_obj *reference; } form; } u; }; static struct info *info = nil; static struct info *cryptinfo = nil; static struct info **dim = nil; static int dims = 0; static struct info **font = nil; static int fonts = 0; static struct info **image = nil; static int images = 0; static struct info **shading = nil; static int shadings = 0; static struct info **pattern = nil; static int patterns = 0; static struct info **form = nil; static int forms = 0; static struct info **psobj = nil; static int psobjs = 0; static void local_cleanup(void) { int i; if (info) { free(info); info = nil; } if (dim) { for (i = 0; i < dims; i++) free(dim[i]); free(dim); dim = nil; } if (font) { for (i = 0; i < fonts; i++) free(font[i]); free(font); font = nil; } if (image) { for (i = 0; i < images; i++) free(image[i]); free(image); image = nil; } if (shading) { for (i = 0; i < shadings; i++) free(shading[i]); free(shading); shading = nil; } if (pattern) { for (i = 0; i < patterns; i++) free(pattern[i]); free(pattern); pattern = nil; } if (form) { for (i = 0; i < forms; i++) free(form[i]); free(form); form = nil; } if (psobj) { for (i = 0; i < psobjs; i++) free(psobj[i]); free(psobj); psobj = nil; } if (xref && xref->store) { pdf_freestore(xref->store); xref->store = nil; } } 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 gatherglobalinfo(void) { info = fz_malloc(sizeof (struct info)); info->page = -1; info->pageobj = nil; info->u.info.obj = nil; info->u.info.obj = fz_dictgets(xref->trailer, "Info"); if (!fz_isindirect(info->u.info.obj)) die(fz_throw("not an indirect info object")); cryptinfo = fz_malloc(sizeof (struct info)); cryptinfo->page = -1; cryptinfo->pageobj = nil; cryptinfo->u.crypt.obj = nil; cryptinfo->u.info.obj = fz_dictgets(xref->trailer, "Encrypt"); if (cryptinfo->u.info.obj && !fz_isdict(cryptinfo->u.info.obj) && !fz_isindirect(cryptinfo->u.info.obj)) die(fz_throw("not an indirect crypt object")); } static fz_error gatherdimensions(int page, fz_obj *pageobj) { fz_rect bbox; fz_obj *obj; int j; obj = fz_dictgets(pageobj, "MediaBox"); if (!fz_isarray(obj)) return fz_throw("cannot find page bounds (%d %d R)", fz_tonum(obj), fz_togen(obj)); bbox = pdf_torect(obj); for (j = 0; j < dims; j++) if (!memcmp(dim[j]->u.dim.bbox, &bbox, sizeof (fz_rect))) break; if (j < dims) return fz_okay; dims++; dim = fz_realloc(dim, dims * sizeof (struct info *)); dim[dims - 1] = fz_malloc(sizeof (struct info)); dim[dims - 1]->u.dim.bbox = fz_malloc(sizeof (fz_rect)); dim[dims - 1]->page = page; dim[dims - 1]->pageobj = pageobj; memcpy(dim[dims - 1]->u.dim.bbox, &bbox, sizeof (fz_rect)); return fz_okay; } static fz_error gatherfonts(int page, fz_obj *pageobj, fz_obj *dict) { int i; for (i = 0; i < fz_dictlen(dict); i++) { fz_obj *fontdict; fz_obj *subtype; fz_obj *basefont; fz_obj *name; int k; fontdict = fz_dictgetval(dict, i); if (!fz_isdict(fontdict)) { fz_warn("not a font dict (%d %d R)", fz_tonum(fontdict), fz_togen(fontdict)); continue; } subtype = fz_dictgets(fontdict, "Subtype"); if (!fz_isname(subtype)) fz_warn("not a font dict subtype (%d %d R)", fz_tonum(fontdict), fz_togen(fontdict)); basefont = fz_dictgets(fontdict, "BaseFont"); if (basefont) { if (!fz_isname(basefont)) return fz_throw("not a font dict basefont (%d %d R)", fz_tonum(fontdict), fz_togen(fontdict)); } else { name = fz_dictgets(fontdict, "Name"); if (name && !fz_isname(name)) return fz_throw("not a font dict name (%d %d R)", fz_tonum(fontdict), fz_togen(fontdict)); } for (k = 0; k < fonts; k++) if (fz_tonum(font[k]->u.font.obj) == fz_tonum(fontdict) && fz_togen(font[k]->u.font.obj) == fz_togen(fontdict)) break; if (k < fonts) continue; fonts++; font = fz_realloc(font, fonts * sizeof (struct info *)); font[fonts - 1] = fz_malloc(sizeof (struct info)); font[fonts - 1]->page = page; 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; } return fz_okay; } static fz_error gatherimages(int page, fz_obj *pageobj, fz_obj *dict) { int i; for (i = 0; i < fz_dictlen(dict); i++) { fz_obj *imagedict; fz_obj *type; fz_obj *width; fz_obj *height; fz_obj *bpc = nil; fz_obj *filter = nil; fz_obj *mask; fz_obj *cs = nil; fz_obj *altcs; int k; imagedict = fz_dictgetval(dict, i); if (!fz_isdict(imagedict)) return fz_throw("not an image dict (%d %d R)", fz_tonum(imagedict), fz_togen(imagedict)); type = fz_dictgets(imagedict, "Subtype"); if (!fz_isname(type)) return fz_throw("not an image subtype (%d %d R)", fz_tonum(imagedict), fz_togen(imagedict)); if (strcmp(fz_toname(type), "Image")) continue; filter = fz_dictgets(imagedict, "Filter"); if (filter && !fz_isname(filter) && !fz_isarray(filter)) return fz_throw("not an image filter (%d %d R)", fz_tonum(imagedict), fz_togen(imagedict)); mask = fz_dictgets(imagedict, "ImageMask"); altcs = nil; cs = fz_dictgets(imagedict, "ColorSpace"); if (fz_isarray(cs)) { fz_obj *cses = cs; cs = fz_arrayget(cses, 0); if (fz_isname(cs) && (!strcmp(fz_toname(cs), "DeviceN") || !strcmp(fz_toname(cs), "Separation"))) { altcs = fz_arrayget(cses, 2); if (fz_isarray(altcs)) altcs = fz_arrayget(altcs, 0); } } if (fz_isbool(mask) && fz_tobool(mask)) { if (cs) fz_warn("image mask (%d %d R) may not have colorspace", fz_tonum(imagedict), fz_togen(imagedict)); } if (cs && !fz_isname(cs)) return fz_throw("not an image colorspace (%d %d R)", fz_tonum(imagedict), fz_togen(imagedict)); if (altcs && !fz_isname(altcs)) return fz_throw("not an image alternate colorspace (%d %d R)", fz_tonum(imagedict), fz_togen(imagedict)); width = fz_dictgets(imagedict, "Width"); if (!fz_isint(width)) return fz_throw("not an image width (%d %d R)", fz_tonum(imagedict), fz_togen(imagedict)); height = fz_dictgets(imagedict, "Height"); if (!fz_isint(height)) return fz_throw("not an image height (%d %d R)", fz_tonum(imagedict), fz_togen(imagedict)); bpc = fz_dictgets(imagedict, "BitsPerComponent"); if (!fz_tobool(mask) && !fz_isint(bpc)) return fz_throw("not an image bits per component (%d %d R)", fz_tonum(imagedict), fz_togen(imagedict)); if (fz_tobool(mask) && fz_isint(bpc) && fz_toint(bpc) != 1) return fz_throw("not an image mask bits per component (%d %d R)", fz_tonum(imagedict), fz_togen(imagedict)); for (k = 0; k < images; k++) if (fz_tonum(image[k]->u.image.obj) == fz_tonum(imagedict) && fz_togen(image[k]->u.image.obj) == fz_togen(imagedict)) break; if (k < images) continue; images++; image = fz_realloc(image, images * sizeof (struct info *)); image[images - 1] = fz_malloc(sizeof (struct info)); image[images - 1]->page = page; 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; } return fz_okay; } static fz_error gatherforms(int page, fz_obj *pageobj, fz_obj *dict) { int i; for (i = 0; i < fz_dictlen(dict); i++) { fz_obj *xobjdict; fz_obj *type; fz_obj *subtype; fz_obj *group; fz_obj *reference; int k; xobjdict = fz_dictgetval(dict, i); if (!fz_isdict(xobjdict)) return fz_throw("not a xobject dict (%d %d R)", fz_tonum(xobjdict), fz_togen(xobjdict)); type = fz_dictgets(xobjdict, "Subtype"); if (!fz_isname(type)) return fz_throw("not a xobject type (%d %d R)", fz_tonum(xobjdict), fz_togen(xobjdict)); if (strcmp(fz_toname(type), "Form")) continue; subtype = fz_dictgets(xobjdict, "Subtype2"); if (subtype && !fz_isname(subtype)) return fz_throw("not a xobject subtype (%d %d R)", fz_tonum(xobjdict), fz_togen(xobjdict)); if (strcmp(fz_toname(subtype), "PS")) continue; group = fz_dictgets(xobjdict, "Group"); if (group && !fz_isdict(group)) return fz_throw("not a form xobject group dict (%d %d R)", fz_tonum(xobjdict), fz_togen(xobjdict)); reference = fz_dictgets(xobjdict, "Ref"); if (reference && !fz_isdict(reference)) return fz_throw("not a form xobject reference dict (%d %d R)", fz_tonum(xobjdict), fz_togen(xobjdict)); for (k = 0; k < forms; k++) if (fz_tonum(form[k]->u.form.obj) == fz_tonum(xobjdict) && fz_togen(form[k]->u.form.obj) == fz_togen(xobjdict)) break; if (k < forms) continue; forms++; form = fz_realloc(form, forms * sizeof (struct info *)); form[forms - 1] = fz_malloc(sizeof (struct info)); form[forms - 1]->page = page; form[forms - 1]->pageobj = pageobj; form[forms - 1]->u.form.obj = xobjdict; form[forms - 1]->u.form.group = group; form[forms - 1]->u.form.reference = reference; } return fz_okay; } static fz_error gatherpsobjs(int page, fz_obj *pageobj, fz_obj *dict) { int i; for (i = 0; i < fz_dictlen(dict); i++) { fz_obj *xobjdict; fz_obj *type; fz_obj *subtype; int k; xobjdict = fz_dictgetval(dict, i); if (!fz_isdict(xobjdict)) return fz_throw("not a xobject dict (%d %d R)", fz_tonum(xobjdict), fz_togen(xobjdict)); type = fz_dictgets(xobjdict, "Subtype"); if (!fz_isname(type)) return fz_throw("not a xobject type (%d %d R)", fz_tonum(xobjdict), fz_togen(xobjdict)); if (strcmp(fz_toname(type), "Form")) continue; subtype = fz_dictgets(xobjdict, "Subtype2"); if (subtype && !fz_isname(subtype)) return fz_throw("not a xobject subtype (%d %d R)", fz_tonum(xobjdict), fz_togen(xobjdict)); if (strcmp(fz_toname(type), "PS") && (strcmp(fz_toname(type), "Form") || strcmp(fz_toname(subtype), "PS"))) continue; for (k = 0; k < psobjs; k++) if (fz_tonum(psobj[k]->u.form.obj) == fz_tonum(xobjdict) && fz_togen(psobj[k]->u.form.obj) == fz_togen(xobjdict)) break; if (k < psobjs) continue; psobjs++; psobj = fz_realloc(psobj, psobjs * sizeof (struct info *)); psobj[psobjs - 1] = fz_malloc(sizeof (struct info)); psobj[psobjs - 1]->page = page; psobj[psobjs - 1]->pageobj = pageobj; psobj[psobjs - 1]->u.form.obj = xobjdict; } return fz_okay; } static fz_error gathershadings(int page, fz_obj *pageobj, fz_obj *dict) { int i; for (i = 0; i < fz_dictlen(dict); i++) { fz_obj *shade; fz_obj *type; int k; shade = fz_dictgetval(dict, i); if (!fz_isdict(shade)) return fz_throw("not a shading dict (%d %d R)", fz_tonum(shade), fz_togen(shade)); type = fz_dictgets(shade, "ShadingType"); if (!fz_isint(type) || fz_toint(type) < 1 || fz_toint(type) > 7) { fz_warn("not a shading type (%d %d R)", fz_tonum(shade), fz_togen(shade)); type = nil; } for (k = 0; k < shadings; k++) if (fz_tonum(shading[k]->u.shading.obj) == fz_tonum(shade) && fz_togen(shading[k]->u.shading.obj) == fz_togen(shade)) break; if (k < shadings) continue; shadings++; shading = fz_realloc(shading, shadings * sizeof (struct info *)); shading[shadings - 1] = fz_malloc(sizeof (struct info)); shading[shadings - 1]->page = page; shading[shadings - 1]->pageobj = pageobj; shading[shadings - 1]->u.shading.obj = shade; shading[shadings - 1]->u.shading.type = type; } return fz_okay; } static fz_error gatherpatterns(int page, fz_obj *pageobj, fz_obj *dict) { int i; for (i = 0; i < fz_dictlen(dict); i++) { fz_obj *patterndict; fz_obj *type; fz_obj *paint = nil; fz_obj *tiling = nil; int k; patterndict = fz_dictgetval(dict, i); if (!fz_isdict(patterndict)) return fz_throw("not a pattern dict (%d %d R)", fz_tonum(patterndict), fz_togen(patterndict)); type = fz_dictgets(patterndict, "PatternType"); if (!fz_isint(type) || fz_toint(type) < 1 || fz_toint(type) > 2) { fz_warn("not a pattern type (%d %d R)", fz_tonum(patterndict), fz_togen(patterndict)); type = nil; } if (fz_toint(type) == 1) { paint = fz_dictgets(patterndict, "PaintType"); if (!fz_isint(paint) || fz_toint(paint) < 1 || fz_toint(paint) > 2) { fz_warn("not a pattern paint type (%d %d R)", fz_tonum(patterndict), fz_togen(patterndict)); paint = nil; } tiling = fz_dictgets(patterndict, "TilingType"); if (!fz_isint(tiling) || fz_toint(tiling) < 1 || fz_toint(tiling) > 3) { fz_warn("not a pattern tiling type (%d %d R)", fz_tonum(patterndict), fz_togen(patterndict)); tiling = nil; } } for (k = 0; k < patterns; k++) if (fz_tonum(pattern[k]->u.pattern.obj) == fz_tonum(patterndict) && fz_togen(pattern[k]->u.pattern.obj) == fz_togen(patterndict)) break; if (k < patterns) continue; patterns++; pattern = fz_realloc(pattern, patterns * sizeof (struct info *)); pattern[patterns - 1] = fz_malloc(sizeof (struct info)); pattern[patterns - 1]->page = page; 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; } return fz_okay; } static void gatherinfo(int show, int page) { fz_error error; fz_obj *pageobj; fz_obj *rsrc; fz_obj *font; fz_obj *xobj; fz_obj *shade; fz_obj *pattern; pageobj = pdf_getpageobject(xref, page); if (!pageobj) die(fz_throw("cannot retrieve info from page %d", page)); if (show & DIMENSIONS) { error = gatherdimensions(page, pageobj); if (error) die(fz_rethrow(error, "gathering dimensions at page %d (%d %d R)", page, fz_tonum(pageobj), fz_togen(pageobj))); } rsrc = fz_dictgets(pageobj, "Resources"); if (show & FONTS) { font = fz_dictgets(rsrc, "Font"); if (font) { error = gatherfonts(page, pageobj, font); if (error) die(fz_rethrow(error, "gathering fonts at page %d (%d %d R)", page, fz_tonum(pageobj), fz_togen(pageobj))); } } if (show & IMAGES || show & XOBJS) { xobj = fz_dictgets(rsrc, "XObject"); if (xobj) { error = gatherimages(page, pageobj, xobj); if (error) die(fz_rethrow(error, "gathering images at page %d (%d %d R)", page, fz_tonum(pageobj), fz_togen(pageobj))); error = gatherforms(page, pageobj, xobj); if (error) die(fz_rethrow(error, "gathering forms at page %d (%d %d R)", page, fz_tonum(pageobj), fz_togen(pageobj))); error = gatherpsobjs(page, pageobj, xobj); if (error) die(fz_rethrow(error, "gathering postscript objects at page %d (%d %d R)", page, fz_tonum(pageobj), fz_togen(pageobj))); } } if (show & SHADINGS) { shade = fz_dictgets(rsrc, "Shading"); if (shade) { error = gathershadings(page, pageobj, shade); if (error) die(fz_rethrow(error, "gathering shadings at page %d (%d %d R)", page, fz_tonum(pageobj), fz_togen(pageobj))); } } if (show & PATTERNS) { pattern = fz_dictgets(rsrc, "Pattern"); if (pattern) { error = gatherpatterns(page, pageobj, pattern); if (error) die(fz_rethrow(error, "gathering shadings at page %d (%d %d R)", page, fz_tonum(pageobj), fz_togen(pageobj))); } } } static void printglobalinfo(void) { printf("\nPDF-%d.%d\n", xref->version / 10, xref->version % 10); if (info->u.info.obj) { printf("Info object (%d %d R):\n", fz_tonum(info->u.info.obj), fz_togen(info->u.info.obj)); fz_debugobj(info->u.info.obj); } if (cryptinfo->u.crypt.obj) { printf("\nEncryption object (%d %d R):\n", fz_tonum(cryptinfo->u.info.obj), fz_togen(cryptinfo->u.info.obj)); fz_debugobj(cryptinfo->u.crypt.obj); } printf("\nPages: %d\n\n", pagecount); } static void printinfo(char *filename, int show, int page) { int i; int j; #define PAGE_FMT "\t% 6d (% 6d %1d R): " if (show & DIMENSIONS && dims > 0) { printf("MediaBox: "); printf("\n"); for (i = 0; i < dims; i++) { printf(PAGE_FMT "[ %g %g %g %g ]\n", dim[i]->page, fz_tonum(dim[i]->pageobj), fz_togen(dim[i]->pageobj), 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"); for (i = 0; i < dims; i++) { fz_free(dim[i]->u.dim.bbox); fz_free(dim[i]); } fz_free(dim); dim = nil; dims = 0; } 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_tonum(font[i]->pageobj), fz_togen(font[i]->pageobj), fz_toname(font[i]->u.font.subtype), fz_toname(font[i]->u.font.name), fz_tonum(font[i]->u.font.obj), fz_togen(font[i]->u.font.obj)); } printf("\n"); for (i = 0; i < fonts; i++) fz_free(font[i]); fz_free(font); font = nil; fonts = 0; } if (show & IMAGES && images > 0) { printf("Images (%d):\n", images); for (i = 0; i < images; i++) { printf(PAGE_FMT "[ ", image[i]->page, fz_tonum(image[i]->pageobj), fz_togen(image[i]->pageobj)); if (fz_isarray(image[i]->u.image.filter)) for (j = 0; j < fz_arraylen(image[i]->u.image.filter); j++) { printf("%s%s", fz_toname(fz_arrayget(image[i]->u.image.filter, j)), j == fz_arraylen(image[i]->u.image.filter) - 1 ? "" : " "); } else if (image[i]->u.image.filter) printf("%s", fz_toname(image[i]->u.image.filter)); else printf("Raw"); printf(" ] %dx%d %dbpc %s%s%s (%d %d R)\n", fz_toint(image[i]->u.image.width), fz_toint(image[i]->u.image.height), image[i]->u.image.bpc ? fz_toint(image[i]->u.image.bpc) : 1, image[i]->u.image.cs ? fz_toname(image[i]->u.image.cs) : "ImageMask", image[i]->u.image.altcs ? " " : "", image[i]->u.image.altcs ? fz_toname(image[i]->u.image.altcs) : "", fz_tonum(image[i]->u.image.obj), fz_togen(image[i]->u.image.obj)); } printf("\n"); for (i = 0; i < images; i++) fz_free(image[i]); fz_free(image); image = nil; images = 0; } if (show & SHADINGS && shadings > 0) { printf("Shading patterns (%d):\n", shadings); for (i = 0; i < shadings; i++) { char *shadingtype[] = { "", "Function", "Axial", "Radial", "Free-form triangle mesh", "Lattice-form triangle mesh", "Coons patch mesh", "Tensor-product patch mesh", }; printf(PAGE_FMT "%s (%d %d R)\n", shading[i]->page, fz_tonum(shading[i]->pageobj), fz_togen(shading[i]->pageobj), shadingtype[fz_toint(shading[i]->u.shading.type)], fz_tonum(shading[i]->u.shading.obj), fz_togen(shading[i]->u.shading.obj)); } printf("\n"); for (i = 0; i < shadings; i++) fz_free(shading[i]); fz_free(shading); shading = nil; shadings = 0; } if (show & PATTERNS && patterns > 0) { printf("Patterns (%d):\n", patterns); for (i = 0; i < patterns; i++) { char *patterntype[] = { "", "Tiling", "Shading", }; char *painttype[] = { "", "Colored", "Uncolored", }; char *tilingtype[] = { "", "Constant spacing", "No distortion", "Constant space/fast tiling", }; printf(PAGE_FMT "%s %s %s (%d %d R)\n", pattern[i]->page, fz_tonum(pattern[i]->pageobj), fz_togen(pattern[i]->pageobj), patterntype[fz_toint(pattern[i]->u.pattern.type)], painttype[fz_toint(pattern[i]->u.pattern.paint)], tilingtype[fz_toint(pattern[i]->u.pattern.tiling)], fz_tonum(pattern[i]->u.pattern.obj), fz_togen(pattern[i]->u.pattern.obj)); } printf("\n"); for (i = 0; i < patterns; i++) fz_free(pattern[i]); fz_free(pattern); pattern = nil; patterns = 0; } if (show & XOBJS && forms > 0) { printf("Form xobjects (%d):\n", forms); for (i = 0; i < forms; i++) { printf(PAGE_FMT "%s%s (%d %d R)\n", form[i]->page, fz_tonum(form[i]->pageobj), fz_togen(form[i]->pageobj), form[i]->u.form.group ? "Group" : "", form[i]->u.form.reference ? "Reference" : "", fz_tonum(form[i]->u.form.obj), fz_togen(form[i]->u.form.obj)); } printf("\n"); for (i = 0; i < forms; i++) fz_free(form[i]); fz_free(form); form = nil; forms = 0; } 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_tonum(psobj[i]->pageobj), fz_togen(psobj[i]->pageobj), fz_tonum(psobj[i]->u.form.obj), fz_togen(psobj[i]->u.form.obj)); } printf("\n"); for (i = 0; i < psobjs; i++) fz_free(psobj[i]); fz_free(psobj); psobj = nil; psobjs = 0; } } 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 = 1; 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++) { gatherinfo(show, page); if (!allpages) { printf("Page %05d:\n", page); printinfo(filename, show, page); printf("\n"); } } } spec = fz_strsep(&pagelist, ","); } if (allpages) printinfo(filename, show, -1); } int 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(); setcleanup(local_cleanup); state = NO_FILE_OPENED; while (fz_optind < argc) { if (strstr(argv[fz_optind], ".pdf") || strstr(argv[fz_optind], ".PDF")) { if (state == NO_INFO_GATHERED) { printglobalinfo(); showinfo(filename, show, "1-"); closexref(); } closexref(); filename = argv[fz_optind]; printf("%s:\n", filename); openxref(filename, password, 0, 1); gatherglobalinfo(); state = NO_INFO_GATHERED; } else { if (state == NO_INFO_GATHERED) printglobalinfo(); showinfo(filename, show, argv[fz_optind]); state = INFO_SHOWN; } fz_optind++; } if (state == NO_INFO_GATHERED) { printglobalinfo(); showinfo(filename, show, "1-"); } closexref(); return 0; }