Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Information tool.
  3.  * Print information about the input pdf.
  4.  */
  5.  
  6. #include "fitz.h"
  7. #include "mupdf.h"
  8.  
  9. pdf_xref *xref;
  10. int pagecount;
  11.  
  12. void closexref(void);
  13.  
  14. void die(fz_error error)
  15. {
  16.         fz_catch(error, "aborting");
  17.         closexref();
  18.         exit(1);
  19. }
  20.  
  21. void openxref(char *filename, char *password, int dieonbadpass, int loadpages);
  22.  
  23. enum
  24. {
  25.         DIMENSIONS = 0x01,
  26.         FONTS = 0x02,
  27.         IMAGES = 0x04,
  28.         SHADINGS = 0x08,
  29.         PATTERNS = 0x10,
  30.         XOBJS = 0x20,
  31.         ALL = DIMENSIONS | FONTS | IMAGES | SHADINGS | PATTERNS | XOBJS
  32. };
  33.  
  34. struct info
  35. {
  36.         int page;
  37.         fz_obj *pageref;
  38.         fz_obj *pageobj;
  39.         union {
  40.                 struct {
  41.                         fz_obj *obj;
  42.                 } info;
  43.                 struct {
  44.                         fz_obj *obj;
  45.                 } crypt;
  46.                 struct {
  47.                         fz_obj *obj;
  48.                         fz_rect *bbox;
  49.                 } dim;
  50.                 struct {
  51.                         fz_obj *obj;
  52.                         fz_obj *subtype;
  53.                         fz_obj *name;
  54.                 } font;
  55.                 struct {
  56.                         fz_obj *obj;
  57.                         fz_obj *width;
  58.                         fz_obj *height;
  59.                         fz_obj *bpc;
  60.                         fz_obj *filter;
  61.                         fz_obj *cs;
  62.                         fz_obj *altcs;
  63.                 } image;
  64.                 struct {
  65.                         fz_obj *obj;
  66.                         fz_obj *type;
  67.                 } shading;
  68.                 struct {
  69.                         fz_obj *obj;
  70.                         fz_obj *type;
  71.                         fz_obj *paint;
  72.                         fz_obj *tiling;
  73.                         fz_obj *shading;
  74.                 } pattern;
  75.                 struct {
  76.                         fz_obj *obj;
  77.                         fz_obj *groupsubtype;
  78.                         fz_obj *reference;
  79.                 } form;
  80.         } u;
  81. };
  82.  
  83. static struct info *dim = NULL;
  84. static int dims = 0;
  85. static struct info *font = NULL;
  86. static int fonts = 0;
  87. static struct info *image = NULL;
  88. static int images = 0;
  89. static struct info *shading = NULL;
  90. static int shadings = 0;
  91. static struct info *pattern = NULL;
  92. static int patterns = 0;
  93. static struct info *form = NULL;
  94. static int forms = 0;
  95. static struct info *psobj = NULL;
  96. static int psobjs = 0;
  97.  
  98. void closexref(void)
  99. {
  100.         int i;
  101.         if (xref)
  102.         {
  103.                 pdf_free_xref(xref);
  104.                 xref = NULL;
  105.         }
  106.  
  107.         if (dim)
  108.         {
  109.                 for (i = 0; i < dims; i++)
  110.                         fz_free(dim[i].u.dim.bbox);
  111.                 fz_free(dim);
  112.                 dim = NULL;
  113.                 dims = 0;
  114.         }
  115.  
  116.         if (font)
  117.         {
  118.                 fz_free(font);
  119.                 font = NULL;
  120.                 fonts = 0;
  121.         }
  122.  
  123.         if (image)
  124.         {
  125.                 fz_free(image);
  126.                 image = NULL;
  127.                 images = 0;
  128.         }
  129.  
  130.         if (shading)
  131.         {
  132.                 fz_free(shading);
  133.                 shading = NULL;
  134.                 shadings = 0;
  135.         }
  136.  
  137.         if (pattern)
  138.         {
  139.                 fz_free(pattern);
  140.                 pattern = NULL;
  141.                 patterns = 0;
  142.         }
  143.  
  144.         if (form)
  145.         {
  146.                 fz_free(form);
  147.                 form = NULL;
  148.                 forms = 0;
  149.         }
  150.  
  151.         if (psobj)
  152.         {
  153.                 fz_free(psobj);
  154.                 psobj = NULL;
  155.                 psobjs = 0;
  156.         }
  157.  
  158.         if (xref && xref->store)
  159.         {
  160.                 pdf_free_store(xref->store);
  161.                 xref->store = NULL;
  162.         }
  163. }
  164.  
  165. static void
  166. infousage(void)
  167. {
  168.         fprintf(stderr,
  169.                 "usage: pdfinfo [options] [file.pdf ... ]\n"
  170.                 "\t-d -\tpassword for decryption\n"
  171.                 "\t-f\tlist fonts\n"
  172.                 "\t-i\tlist images\n"
  173.                 "\t-m\tlist dimensions\n"
  174.                 "\t-p\tlist patterns\n"
  175.                 "\t-s\tlist shadings\n"
  176.                 "\t-x\tlist form and postscript xobjects\n");
  177.         exit(1);
  178. }
  179.  
  180. static void
  181. showglobalinfo(void)
  182. {
  183.         fz_obj *obj;
  184.  
  185.         printf("\nPDF-%d.%d\n", xref->version / 10, xref->version % 10);
  186.  
  187.         obj = fz_dict_gets(xref->trailer, "Info");
  188.         if (obj)
  189.         {
  190.                 printf("Info object (%d %d R):\n", fz_to_num(obj), fz_to_gen(obj));
  191.                 fz_debug_obj(fz_resolve_indirect(obj));
  192.         }
  193.  
  194.         obj = fz_dict_gets(xref->trailer, "Encrypt");
  195.         if (obj)
  196.         {
  197.                 printf("\nEncryption object (%d %d R):\n", fz_to_num(obj), fz_to_gen(obj));
  198.                 fz_debug_obj(fz_resolve_indirect(obj));
  199.         }
  200.  
  201.         printf("\nPages: %d\n\n", pagecount);
  202. }
  203.  
  204. static void
  205. gatherdimensions(int page, fz_obj *pageref, fz_obj *pageobj)
  206. {
  207.         fz_rect bbox;
  208.         fz_obj *obj;
  209.         int j;
  210.  
  211.         obj = fz_dict_gets(pageobj, "MediaBox");
  212.         if (!fz_is_array(obj))
  213.                 return;
  214.  
  215.         bbox = pdf_to_rect(obj);
  216.  
  217.         for (j = 0; j < dims; j++)
  218.                 if (!memcmp(dim[j].u.dim.bbox, &bbox, sizeof (fz_rect)))
  219.                         break;
  220.  
  221.         if (j < dims)
  222.                 return;
  223.  
  224.         dims++;
  225.  
  226.         dim = fz_realloc(dim, dims, sizeof(struct info));
  227.         dim[dims - 1].page = page;
  228.         dim[dims - 1].pageref = pageref;
  229.         dim[dims - 1].pageobj = pageobj;
  230.         dim[dims - 1].u.dim.bbox = fz_malloc(sizeof(fz_rect));
  231.         memcpy(dim[dims - 1].u.dim.bbox, &bbox, sizeof (fz_rect));
  232.  
  233.         return;
  234. }
  235.  
  236. static void
  237. gatherfonts(int page, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict)
  238. {
  239.         int i;
  240.  
  241.         for (i = 0; i < fz_dict_len(dict); i++)
  242.         {
  243.                 fz_obj *fontdict = NULL;
  244.                 fz_obj *subtype = NULL;
  245.                 fz_obj *basefont = NULL;
  246.                 fz_obj *name = NULL;
  247.                 int k;
  248.  
  249.                 fontdict = fz_dict_get_val(dict, i);
  250.                 if (!fz_is_dict(fontdict))
  251.                 {
  252.                         fz_warn("not a font dict (%d %d R)", fz_to_num(fontdict), fz_to_gen(fontdict));
  253.                         continue;
  254.                 }
  255.  
  256.                 subtype = fz_dict_gets(fontdict, "Subtype");
  257.                 basefont = fz_dict_gets(fontdict, "BaseFont");
  258.                 if (!basefont || fz_is_null(basefont))
  259.                         name = fz_dict_gets(fontdict, "Name");
  260.  
  261.                 for (k = 0; k < fonts; k++)
  262.                         if (!fz_objcmp(font[k].u.font.obj, fontdict))
  263.                                 break;
  264.  
  265.                 if (k < fonts)
  266.                         continue;
  267.  
  268.                 fonts++;
  269.  
  270.                 font = fz_realloc(font, fonts, sizeof(struct info));
  271.                 font[fonts - 1].page = page;
  272.                 font[fonts - 1].pageref = pageref;
  273.                 font[fonts - 1].pageobj = pageobj;
  274.                 font[fonts - 1].u.font.obj = fontdict;
  275.                 font[fonts - 1].u.font.subtype = subtype;
  276.                 font[fonts - 1].u.font.name = basefont ? basefont : name;
  277.         }
  278. }
  279.  
  280. static void
  281. gatherimages(int page, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict)
  282. {
  283.         int i;
  284.  
  285.         for (i = 0; i < fz_dict_len(dict); i++)
  286.         {
  287.                 fz_obj *imagedict;
  288.                 fz_obj *type;
  289.                 fz_obj *width;
  290.                 fz_obj *height;
  291.                 fz_obj *bpc = NULL;
  292.                 fz_obj *filter = NULL;
  293.                 fz_obj *cs = NULL;
  294.                 fz_obj *altcs;
  295.                 int k;
  296.  
  297.                 imagedict = fz_dict_get_val(dict, i);
  298.                 if (!fz_is_dict(imagedict))
  299.                 {
  300.                         fz_warn("not an image dict (%d %d R)", fz_to_num(imagedict), fz_to_gen(imagedict));
  301.                         continue;
  302.                 }
  303.  
  304.                 type = fz_dict_gets(imagedict, "Subtype");
  305.                 if (strcmp(fz_to_name(type), "Image"))
  306.                         continue;
  307.  
  308.                 filter = fz_dict_gets(imagedict, "Filter");
  309.  
  310.                 altcs = NULL;
  311.                 cs = fz_dict_gets(imagedict, "ColorSpace");
  312.                 if (fz_is_array(cs))
  313.                 {
  314.                         fz_obj *cses = cs;
  315.  
  316.                         cs = fz_array_get(cses, 0);
  317.                         if (fz_is_name(cs) && (!strcmp(fz_to_name(cs), "DeviceN") || !strcmp(fz_to_name(cs), "Separation")))
  318.                         {
  319.                                 altcs = fz_array_get(cses, 2);
  320.                                 if (fz_is_array(altcs))
  321.                                         altcs = fz_array_get(altcs, 0);
  322.                         }
  323.                 }
  324.  
  325.                 width = fz_dict_gets(imagedict, "Width");
  326.                 height = fz_dict_gets(imagedict, "Height");
  327.                 bpc = fz_dict_gets(imagedict, "BitsPerComponent");
  328.  
  329.                 for (k = 0; k < images; k++)
  330.                         if (!fz_objcmp(image[k].u.image.obj, imagedict))
  331.                                 break;
  332.  
  333.                 if (k < images)
  334.                         continue;
  335.  
  336.                 images++;
  337.  
  338.                 image = fz_realloc(image, images, sizeof(struct info));
  339.                 image[images - 1].page = page;
  340.                 image[images - 1].pageref = pageref;
  341.                 image[images - 1].pageobj = pageobj;
  342.                 image[images - 1].u.image.obj = imagedict;
  343.                 image[images - 1].u.image.width = width;
  344.                 image[images - 1].u.image.height = height;
  345.                 image[images - 1].u.image.bpc = bpc;
  346.                 image[images - 1].u.image.filter = filter;
  347.                 image[images - 1].u.image.cs = cs;
  348.                 image[images - 1].u.image.altcs = altcs;
  349.         }
  350. }
  351.  
  352. static void
  353. gatherforms(int page, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict)
  354. {
  355.         int i;
  356.  
  357.         for (i = 0; i < fz_dict_len(dict); i++)
  358.         {
  359.                 fz_obj *xobjdict;
  360.                 fz_obj *type;
  361.                 fz_obj *subtype;
  362.                 fz_obj *group;
  363.                 fz_obj *groupsubtype;
  364.                 fz_obj *reference;
  365.                 int k;
  366.  
  367.                 xobjdict = fz_dict_get_val(dict, i);
  368.                 if (!fz_is_dict(xobjdict))
  369.                 {
  370.                         fz_warn("not a xobject dict (%d %d R)", fz_to_num(xobjdict), fz_to_gen(xobjdict));
  371.                         continue;
  372.                 }
  373.  
  374.                 type = fz_dict_gets(xobjdict, "Subtype");
  375.                 if (strcmp(fz_to_name(type), "Form"))
  376.                         continue;
  377.  
  378.                 subtype = fz_dict_gets(xobjdict, "Subtype2");
  379.                 if (!strcmp(fz_to_name(subtype), "PS"))
  380.                         continue;
  381.  
  382.                 group = fz_dict_gets(xobjdict, "Group");
  383.                 groupsubtype = fz_dict_gets(group, "S");
  384.                 reference = fz_dict_gets(xobjdict, "Ref");
  385.  
  386.                 for (k = 0; k < forms; k++)
  387.                         if (!fz_objcmp(form[k].u.form.obj, xobjdict))
  388.                                 break;
  389.  
  390.                 if (k < forms)
  391.                         continue;
  392.  
  393.                 forms++;
  394.  
  395.                 form = fz_realloc(form, forms, sizeof(struct info));
  396.                 form[forms - 1].page = page;
  397.                 form[forms - 1].pageref = pageref;
  398.                 form[forms - 1].pageobj = pageobj;
  399.                 form[forms - 1].u.form.obj = xobjdict;
  400.                 form[forms - 1].u.form.groupsubtype = groupsubtype;
  401.                 form[forms - 1].u.form.reference = reference;
  402.         }
  403. }
  404.  
  405. static void
  406. gatherpsobjs(int page, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict)
  407. {
  408.         int i;
  409.  
  410.         for (i = 0; i < fz_dict_len(dict); i++)
  411.         {
  412.                 fz_obj *xobjdict;
  413.                 fz_obj *type;
  414.                 fz_obj *subtype;
  415.                 int k;
  416.  
  417.                 xobjdict = fz_dict_get_val(dict, i);
  418.                 if (!fz_is_dict(xobjdict))
  419.                 {
  420.                         fz_warn("not a xobject dict (%d %d R)", fz_to_num(xobjdict), fz_to_gen(xobjdict));
  421.                         continue;
  422.                 }
  423.  
  424.                 type = fz_dict_gets(xobjdict, "Subtype");
  425.                 subtype = fz_dict_gets(xobjdict, "Subtype2");
  426.                 if (strcmp(fz_to_name(type), "PS") &&
  427.                         (strcmp(fz_to_name(type), "Form") || strcmp(fz_to_name(subtype), "PS")))
  428.                         continue;
  429.  
  430.                 for (k = 0; k < psobjs; k++)
  431.                         if (!fz_objcmp(psobj[k].u.form.obj, xobjdict))
  432.                                 break;
  433.  
  434.                 if (k < psobjs)
  435.                         continue;
  436.  
  437.                 psobjs++;
  438.  
  439.                 psobj = fz_realloc(psobj, psobjs, sizeof(struct info));
  440.                 psobj[psobjs - 1].page = page;
  441.                 psobj[psobjs - 1].pageref = pageref;
  442.                 psobj[psobjs - 1].pageobj = pageobj;
  443.                 psobj[psobjs - 1].u.form.obj = xobjdict;
  444.         }
  445. }
  446.  
  447. static void
  448. gathershadings(int page, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict)
  449. {
  450.         int i;
  451.  
  452.         for (i = 0; i < fz_dict_len(dict); i++)
  453.         {
  454.                 fz_obj *shade;
  455.                 fz_obj *type;
  456.                 int k;
  457.  
  458.                 shade = fz_dict_get_val(dict, i);
  459.                 if (!fz_is_dict(shade))
  460.                 {
  461.                         fz_warn("not a shading dict (%d %d R)", fz_to_num(shade), fz_to_gen(shade));
  462.                         continue;
  463.                 }
  464.  
  465.                 type = fz_dict_gets(shade, "ShadingType");
  466.                 if (!fz_is_int(type) || fz_to_int(type) < 1 || fz_to_int(type) > 7)
  467.                 {
  468.                         fz_warn("not a shading type (%d %d R)", fz_to_num(shade), fz_to_gen(shade));
  469.                         type = NULL;
  470.                 }
  471.  
  472.                 for (k = 0; k < shadings; k++)
  473.                         if (!fz_objcmp(shading[k].u.shading.obj, shade))
  474.                                 break;
  475.  
  476.                 if (k < shadings)
  477.                         continue;
  478.  
  479.                 shadings++;
  480.  
  481.                 shading = fz_realloc(shading, shadings, sizeof(struct info));
  482.                 shading[shadings - 1].page = page;
  483.                 shading[shadings - 1].pageref = pageref;
  484.                 shading[shadings - 1].pageobj = pageobj;
  485.                 shading[shadings - 1].u.shading.obj = shade;
  486.                 shading[shadings - 1].u.shading.type = type;
  487.         }
  488. }
  489.  
  490. static void
  491. gatherpatterns(int page, fz_obj *pageref, fz_obj *pageobj, fz_obj *dict)
  492. {
  493.         int i;
  494.  
  495.         for (i = 0; i < fz_dict_len(dict); i++)
  496.         {
  497.                 fz_obj *patterndict;
  498.                 fz_obj *type;
  499.                 fz_obj *paint = NULL;
  500.                 fz_obj *tiling = NULL;
  501.                 fz_obj *shading = NULL;
  502.                 int k;
  503.  
  504.                 patterndict = fz_dict_get_val(dict, i);
  505.                 if (!fz_is_dict(patterndict))
  506.                 {
  507.                         fz_warn("not a pattern dict (%d %d R)", fz_to_num(patterndict), fz_to_gen(patterndict));
  508.                         continue;
  509.                 }
  510.  
  511.                 type = fz_dict_gets(patterndict, "PatternType");
  512.                 if (!fz_is_int(type) || fz_to_int(type) < 1 || fz_to_int(type) > 2)
  513.                 {
  514.                         fz_warn("not a pattern type (%d %d R)", fz_to_num(patterndict), fz_to_gen(patterndict));
  515.                         type = NULL;
  516.                 }
  517.  
  518.                 if (fz_to_int(type) == 1)
  519.                 {
  520.                         paint = fz_dict_gets(patterndict, "PaintType");
  521.                         if (!fz_is_int(paint) || fz_to_int(paint) < 1 || fz_to_int(paint) > 2)
  522.                         {
  523.                                 fz_warn("not a pattern paint type (%d %d R)", fz_to_num(patterndict), fz_to_gen(patterndict));
  524.                                 paint = NULL;
  525.                         }
  526.  
  527.                         tiling = fz_dict_gets(patterndict, "TilingType");
  528.                         if (!fz_is_int(tiling) || fz_to_int(tiling) < 1 || fz_to_int(tiling) > 3)
  529.                         {
  530.                                 fz_warn("not a pattern tiling type (%d %d R)", fz_to_num(patterndict), fz_to_gen(patterndict));
  531.                                 tiling = NULL;
  532.                         }
  533.                 }
  534.                 else
  535.                 {
  536.                         shading = fz_dict_gets(patterndict, "Shading");
  537.                 }
  538.  
  539.                 for (k = 0; k < patterns; k++)
  540.                         if (!fz_objcmp(pattern[k].u.pattern.obj, patterndict))
  541.                                 break;
  542.  
  543.                 if (k < patterns)
  544.                         continue;
  545.  
  546.                 patterns++;
  547.  
  548.                 pattern = fz_realloc(pattern, patterns, sizeof(struct info));
  549.                 pattern[patterns - 1].page = page;
  550.                 pattern[patterns - 1].pageref = pageref;
  551.                 pattern[patterns - 1].pageobj = pageobj;
  552.                 pattern[patterns - 1].u.pattern.obj = patterndict;
  553.                 pattern[patterns - 1].u.pattern.type = type;
  554.                 pattern[patterns - 1].u.pattern.paint = paint;
  555.                 pattern[patterns - 1].u.pattern.tiling = tiling;
  556.                 pattern[patterns - 1].u.pattern.shading = shading;
  557.         }
  558. }
  559.  
  560. static void
  561. gatherresourceinfo(int page, fz_obj *rsrc)
  562. {
  563.         fz_obj *pageobj;
  564.         fz_obj *pageref;
  565.         fz_obj *font;
  566.         fz_obj *xobj;
  567.         fz_obj *shade;
  568.         fz_obj *pattern;
  569.         fz_obj *subrsrc;
  570.         int i;
  571.  
  572.         pageobj = xref->page_objs[page-1];
  573.         pageref = xref->page_refs[page-1];
  574.  
  575.         if (!pageobj)
  576.                 die(fz_throw("cannot retrieve info from page %d", page));
  577.  
  578.         font = fz_dict_gets(rsrc, "Font");
  579.         if (font)
  580.         {
  581.                 gatherfonts(page, pageref, pageobj, font);
  582.  
  583.                 for (i = 0; i < fz_dict_len(font); i++)
  584.                 {
  585.                         fz_obj *obj = fz_dict_get_val(font, i);
  586.  
  587.                         subrsrc = fz_dict_gets(obj, "Resources");
  588.                         if (subrsrc && fz_objcmp(rsrc, subrsrc))
  589.                                 gatherresourceinfo(page, subrsrc);
  590.                 }
  591.         }
  592.  
  593.         xobj = fz_dict_gets(rsrc, "XObject");
  594.         if (xobj)
  595.         {
  596.                 gatherimages(page, pageref, pageobj, xobj);
  597.                 gatherforms(page, pageref, pageobj, xobj);
  598.                 gatherpsobjs(page, pageref, pageobj, xobj);
  599.  
  600.                 for (i = 0; i < fz_dict_len(xobj); i++)
  601.                 {
  602.                         fz_obj *obj = fz_dict_get_val(xobj, i);
  603.                         subrsrc = fz_dict_gets(obj, "Resources");
  604.                         if (subrsrc && fz_objcmp(rsrc, subrsrc))
  605.                                 gatherresourceinfo(page, subrsrc);
  606.                 }
  607.         }
  608.  
  609.         shade = fz_dict_gets(rsrc, "Shading");
  610.         if (shade)
  611.                 gathershadings(page, pageref, pageobj, shade);
  612.  
  613.         pattern = fz_dict_gets(rsrc, "Pattern");
  614.         if (pattern)
  615.         {
  616.                 gatherpatterns(page, pageref, pageobj, pattern);
  617.  
  618.                 for (i = 0; i < fz_dict_len(pattern); i++)
  619.                 {
  620.                         fz_obj *obj = fz_dict_get_val(pattern, i);
  621.                         subrsrc = fz_dict_gets(obj, "Resources");
  622.                         if (subrsrc && fz_objcmp(rsrc, subrsrc))
  623.                                 gatherresourceinfo(page, subrsrc);
  624.                 }
  625.         }
  626. }
  627.  
  628. static void
  629. gatherpageinfo(int page)
  630. {
  631.         fz_obj *pageobj;
  632.         fz_obj *pageref;
  633.         fz_obj *rsrc;
  634.  
  635.         pageobj = xref->page_objs[page-1];
  636.         pageref = xref->page_refs[page-1];
  637.  
  638.         if (!pageobj)
  639.                 die(fz_throw("cannot retrieve info from page %d", page));
  640.  
  641.         gatherdimensions(page, pageref, pageobj);
  642.  
  643.         rsrc = fz_dict_gets(pageobj, "Resources");
  644.         gatherresourceinfo(page, rsrc);
  645. }
  646.  
  647. static void
  648. printinfo(char *filename, int show, int page)
  649. {
  650.         int i;
  651.         int j;
  652.  
  653. #define PAGE_FMT "\t% 5d (% 7d %1d R): "
  654.  
  655.         if (show & DIMENSIONS && dims > 0)
  656.         {
  657.                 printf("Mediaboxes (%d):\n", dims);
  658.                 for (i = 0; i < dims; i++)
  659.                 {
  660.                         printf(PAGE_FMT "[ %g %g %g %g ]\n",
  661.                                 dim[i].page,
  662.                                 fz_to_num(dim[i].pageref), fz_to_gen(dim[i].pageref),
  663.                                 dim[i].u.dim.bbox->x0,
  664.                                 dim[i].u.dim.bbox->y0,
  665.                                 dim[i].u.dim.bbox->x1,
  666.                                 dim[i].u.dim.bbox->y1);
  667.                 }
  668.                 printf("\n");
  669.         }
  670.  
  671.         if (show & FONTS && fonts > 0)
  672.         {
  673.                 printf("Fonts (%d):\n", fonts);
  674.                 for (i = 0; i < fonts; i++)
  675.                 {
  676.                         printf(PAGE_FMT "%s '%s' (%d %d R)\n",
  677.                                 font[i].page,
  678.                                 fz_to_num(font[i].pageref), fz_to_gen(font[i].pageref),
  679.                                 fz_to_name(font[i].u.font.subtype),
  680.                                 fz_to_name(font[i].u.font.name),
  681.                                 fz_to_num(font[i].u.font.obj), fz_to_gen(font[i].u.font.obj));
  682.                 }
  683.                 printf("\n");
  684.         }
  685.  
  686.         if (show & IMAGES && images > 0)
  687.         {
  688.                 printf("Images (%d):\n", images);
  689.                 for (i = 0; i < images; i++)
  690.                 {
  691.                         char *cs = NULL;
  692.                         char *altcs = NULL;
  693.  
  694.                         printf(PAGE_FMT "[ ",
  695.                                 image[i].page,
  696.                                 fz_to_num(image[i].pageref), fz_to_gen(image[i].pageref));
  697.  
  698.                         if (fz_is_array(image[i].u.image.filter))
  699.                                 for (j = 0; j < fz_array_len(image[i].u.image.filter); j++)
  700.                                 {
  701.                                         fz_obj *obj = fz_array_get(image[i].u.image.filter, j);
  702.                                         char *filter = fz_strdup(fz_to_name(obj));
  703.  
  704.                                         if (strstr(filter, "Decode"))
  705.                                                 *(strstr(filter, "Decode")) = '\0';
  706.  
  707.                                         printf("%s%s",
  708.                                                         filter,
  709.                                                         j == fz_array_len(image[i].u.image.filter) - 1 ? "" : " ");
  710.                                         fz_free(filter);
  711.                                 }
  712.                         else if (image[i].u.image.filter)
  713.                         {
  714.                                 fz_obj *obj = image[i].u.image.filter;
  715.                                 char *filter = fz_strdup(fz_to_name(obj));
  716.  
  717.                                 if (strstr(filter, "Decode"))
  718.                                         *(strstr(filter, "Decode")) = '\0';
  719.  
  720.                                 printf("%s", filter);
  721.                                 fz_free(filter);
  722.                         }
  723.                         else
  724.                                 printf("Raw");
  725.  
  726.                         if (image[i].u.image.cs)
  727.                         {
  728.                                 cs = fz_strdup(fz_to_name(image[i].u.image.cs));
  729.  
  730.                                 if (!strncmp(cs, "Device", 6))
  731.                                 {
  732.                                         int len = strlen(cs + 6);
  733.                                         memmove(cs + 3, cs + 6, len + 1);
  734.                                         cs[3 + len + 1] = '\0';
  735.                                 }
  736.                                 if (strstr(cs, "ICC"))
  737.                                         fz_strlcpy(cs, "ICC", 4);
  738.                                 if (strstr(cs, "Indexed"))
  739.                                         fz_strlcpy(cs, "Idx", 4);
  740.                                 if (strstr(cs, "Pattern"))
  741.                                         fz_strlcpy(cs, "Pat", 4);
  742.                                 if (strstr(cs, "Separation"))
  743.                                         fz_strlcpy(cs, "Sep", 4);
  744.                         }
  745.                         if (image[i].u.image.altcs)
  746.                         {
  747.                                 altcs = fz_strdup(fz_to_name(image[i].u.image.altcs));
  748.  
  749.                                 if (!strncmp(altcs, "Device", 6))
  750.                                 {
  751.                                         int len = strlen(altcs + 6);
  752.                                         memmove(altcs + 3, altcs + 6, len + 1);
  753.                                         altcs[3 + len + 1] = '\0';
  754.                                 }
  755.                                 if (strstr(altcs, "ICC"))
  756.                                         fz_strlcpy(altcs, "ICC", 4);
  757.                                 if (strstr(altcs, "Indexed"))
  758.                                         fz_strlcpy(altcs, "Idx", 4);
  759.                                 if (strstr(altcs, "Pattern"))
  760.                                         fz_strlcpy(altcs, "Pat", 4);
  761.                                 if (strstr(altcs, "Separation"))
  762.                                         fz_strlcpy(altcs, "Sep", 4);
  763.                         }
  764.  
  765.                         printf(" ] %dx%d %dbpc %s%s%s (%d %d R)\n",
  766.                                 fz_to_int(image[i].u.image.width),
  767.                                 fz_to_int(image[i].u.image.height),
  768.                                 image[i].u.image.bpc ? fz_to_int(image[i].u.image.bpc) : 1,
  769.                                 image[i].u.image.cs ? cs : "ImageMask",
  770.                                 image[i].u.image.altcs ? " " : "",
  771.                                 image[i].u.image.altcs ? altcs : "",
  772.                                 fz_to_num(image[i].u.image.obj), fz_to_gen(image[i].u.image.obj));
  773.  
  774.                         fz_free(cs);
  775.                         fz_free(altcs);
  776.                 }
  777.                 printf("\n");
  778.         }
  779.  
  780.         if (show & SHADINGS && shadings > 0)
  781.         {
  782.                 printf("Shading patterns (%d):\n", shadings);
  783.                 for (i = 0; i < shadings; i++)
  784.                 {
  785.                         char *shadingtype[] =
  786.                         {
  787.                                 "",
  788.                                 "Function",
  789.                                 "Axial",
  790.                                 "Radial",
  791.                                 "Triangle mesh",
  792.                                 "Lattice",
  793.                                 "Coons patch",
  794.                                 "Tensor patch",
  795.                         };
  796.  
  797.                         printf(PAGE_FMT "%s (%d %d R)\n",
  798.                                 shading[i].page,
  799.                                 fz_to_num(shading[i].pageref), fz_to_gen(shading[i].pageref),
  800.                                 shadingtype[fz_to_int(shading[i].u.shading.type)],
  801.                                 fz_to_num(shading[i].u.shading.obj), fz_to_gen(shading[i].u.shading.obj));
  802.                 }
  803.                 printf("\n");
  804.         }
  805.  
  806.         if (show & PATTERNS && patterns > 0)
  807.         {
  808.                 printf("Patterns (%d):\n", patterns);
  809.                 for (i = 0; i < patterns; i++)
  810.                 {
  811.                         if (fz_to_int(pattern[i].u.pattern.type) == 1)
  812.                         {
  813.                                 char *painttype[] =
  814.                                 {
  815.                                         "",
  816.                                         "Colored",
  817.                                         "Uncolored",
  818.                                 };
  819.                                 char *tilingtype[] =
  820.                                 {
  821.                                         "",
  822.                                         "Constant",
  823.                                         "No distortion",
  824.                                         "Constant/fast tiling",
  825.                                 };
  826.  
  827.                                 printf(PAGE_FMT "Tiling %s %s (%d %d R)\n",
  828.                                                 pattern[i].page,
  829.                                                 fz_to_num(pattern[i].pageref), fz_to_gen(pattern[i].pageref),
  830.                                                 painttype[fz_to_int(pattern[i].u.pattern.paint)],
  831.                                                 tilingtype[fz_to_int(pattern[i].u.pattern.tiling)],
  832.                                                 fz_to_num(pattern[i].u.pattern.obj), fz_to_gen(pattern[i].u.pattern.obj));
  833.                         }
  834.                         else
  835.                         {
  836.                                 printf(PAGE_FMT "Shading %d %d R (%d %d R)\n",
  837.                                                 pattern[i].page,
  838.                                                 fz_to_num(pattern[i].pageref), fz_to_gen(pattern[i].pageref),
  839.                                                 fz_to_num(pattern[i].u.pattern.shading), fz_to_gen(pattern[i].u.pattern.shading),
  840.                                                 fz_to_num(pattern[i].u.pattern.obj), fz_to_gen(pattern[i].u.pattern.obj));
  841.                         }
  842.                 }
  843.                 printf("\n");
  844.         }
  845.  
  846.         if (show & XOBJS && forms > 0)
  847.         {
  848.                 printf("Form xobjects (%d):\n", forms);
  849.                 for (i = 0; i < forms; i++)
  850.                 {
  851.                         printf(PAGE_FMT "Form%s%s%s%s (%d %d R)\n",
  852.                                 form[i].page,
  853.                                 fz_to_num(form[i].pageref), fz_to_gen(form[i].pageref),
  854.                                 form[i].u.form.groupsubtype ? " " : "",
  855.                                 form[i].u.form.groupsubtype ? fz_to_name(form[i].u.form.groupsubtype) : "",
  856.                                 form[i].u.form.groupsubtype ? " Group" : "",
  857.                                 form[i].u.form.reference ? " Reference" : "",
  858.                                 fz_to_num(form[i].u.form.obj), fz_to_gen(form[i].u.form.obj));
  859.                 }
  860.                 printf("\n");
  861.         }
  862.  
  863.         if (show & XOBJS && psobjs > 0)
  864.         {
  865.                 printf("Postscript xobjects (%d):\n", psobjs);
  866.                 for (i = 0; i < psobjs; i++)
  867.                 {
  868.                         printf(PAGE_FMT "(%d %d R)\n",
  869.                                 psobj[i].page,
  870.                                 fz_to_num(psobj[i].pageref), fz_to_gen(psobj[i].pageref),
  871.                                 fz_to_num(psobj[i].u.form.obj), fz_to_gen(psobj[i].u.form.obj));
  872.                 }
  873.                 printf("\n");
  874.         }
  875. }
  876.  
  877. static void
  878. showinfo(char *filename, int show, char *pagelist)
  879. {
  880.         int page, spage, epage;
  881.         char *spec, *dash;
  882.         int allpages;
  883.  
  884.         if (!xref)
  885.                 infousage();
  886.  
  887.         allpages = !strcmp(pagelist, "1-");
  888.  
  889.         spec = fz_strsep(&pagelist, ",");
  890.         while (spec)
  891.         {
  892.                 dash = strchr(spec, '-');
  893.  
  894.                 if (dash == spec)
  895.                         spage = epage = pagecount;
  896.                 else
  897.                         spage = epage = atoi(spec);
  898.  
  899.                 if (dash)
  900.                 {
  901.                         if (strlen(dash) > 1)
  902.                                 epage = atoi(dash + 1);
  903.                         else
  904.                                 epage = pagecount;
  905.                 }
  906.  
  907.                 if (spage > epage)
  908.                         page = spage, spage = epage, epage = page;
  909.  
  910.                 if (spage < 1)
  911.                         spage = 1;
  912.                 if (epage > pagecount)
  913.                         epage = pagecount;
  914.                 if (spage > pagecount)
  915.                         spage = pagecount;
  916.  
  917.                 if (allpages)
  918.                         printf("Retrieving info from pages %d-%d...\n", spage, epage);
  919.                 if (spage >= 1)
  920.                 {
  921.                         for (page = spage; page <= epage; page++)
  922.                         {
  923.                                 gatherpageinfo(page);
  924.                                 if (!allpages)
  925.                                 {
  926.                                         printf("Page %d:\n", page);
  927.                                         printinfo(filename, show, page);
  928.                                         printf("\n");
  929.                                 }
  930.                         }
  931.                 }
  932.  
  933.                 spec = fz_strsep(&pagelist, ",");
  934.         }
  935.  
  936.         if (allpages)
  937.                 printinfo(filename, show, -1);
  938. }
  939.  
  940. int main(int argc, char **argv)
  941. {
  942.         enum { NO_FILE_OPENED, NO_INFO_GATHERED, INFO_SHOWN } state;
  943.         fz_error error;
  944.         char *filename = "";
  945.         char *password = "";
  946.         int show = ALL;
  947.         int c;
  948.  
  949.         while ((c = fz_getopt(argc, argv, "mfispxd:")) != -1)
  950.         {
  951.                 switch (c)
  952.                 {
  953.                 case 'm': if (show == ALL) show = DIMENSIONS; else show |= DIMENSIONS; break;
  954.                 case 'f': if (show == ALL) show = FONTS; else show |= FONTS; break;
  955.                 case 'i': if (show == ALL) show = IMAGES; else show |= IMAGES; break;
  956.                 case 's': if (show == ALL) show = SHADINGS; else show |= SHADINGS; break;
  957.                 case 'p': if (show == ALL) show = PATTERNS; else show |= PATTERNS; break;
  958.                 case 'x': if (show == ALL) show = XOBJS; else show |= XOBJS; break;
  959.                 case 'd': password = fz_optarg; break;
  960.                 default:
  961.                         infousage();
  962.                         break;
  963.                 }
  964.         }
  965.  
  966.         if (fz_optind == argc)
  967.                 infousage();
  968.  
  969.         state = NO_FILE_OPENED;
  970.         while (fz_optind < argc)
  971.         {
  972.                 if (strstr(argv[fz_optind], ".pdf") || strstr(argv[fz_optind], ".PDF"))
  973.                 {
  974.                         if (state == NO_INFO_GATHERED)
  975.                         {
  976.                                 showinfo(filename, show, "1-");
  977.                                 closexref();
  978.                         }
  979.  
  980.                         closexref();
  981.  
  982.                         filename = argv[fz_optind];
  983.                         printf("%s:\n", filename);
  984.                         error = pdf_open_xref(&xref, filename, password);
  985.                         if (error)
  986.                                 die(fz_rethrow(error, "cannot open input file '%s'", filename));
  987.  
  988.                         error = pdf_load_page_tree(xref);
  989.                         if (error)
  990.                                 die(fz_rethrow(error, "cannot load page tree: %s", filename));
  991.                         pagecount = pdf_count_pages(xref);
  992.  
  993.                         showglobalinfo();
  994.                         state = NO_INFO_GATHERED;
  995.                 }
  996.                 else
  997.                 {
  998.                         showinfo(filename, show, argv[fz_optind]);
  999.                         state = INFO_SHOWN;
  1000.                 }
  1001.  
  1002.                 fz_optind++;
  1003.         }
  1004.  
  1005.         if (state == NO_INFO_GATHERED)
  1006.                 showinfo(filename, show, "1-");
  1007.  
  1008.         closexref();
  1009.  
  1010.         return 0;
  1011. }
  1012.