Subversion Repositories Kolibri OS

Rev

Rev 4680 | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * pdfdraw -- command line tool for drawing pdf documents
  3.  */
  4.  
  5. #include "fitz.h"
  6. #include "mupdf.h"
  7.  
  8. #ifdef _MSC_VER
  9. #include <winsock2.h>
  10. #else
  11. #include <sys/time.h>
  12. #endif
  13.  
  14. char *output = NULL;
  15. float resolution = 72;
  16. float rotation = 0;
  17.  
  18. int showxml = 0;
  19. int showtext = 0;
  20. int showtime = 0;
  21. int showmd5 = 0;
  22. int savealpha = 0;
  23. int uselist = 1;
  24. int alphabits = 8;
  25. float gamma_value = 1;
  26. int invert = 0;
  27.  
  28. fz_colorspace *colorspace;
  29. fz_glyph_cache *glyphcache;
  30. char *filename;
  31.  
  32. struct {
  33.         int count, total;
  34.         int min, max;
  35.         int minpage, maxpage;
  36. } timing;
  37.  
  38. static void die(fz_error error)
  39. {
  40.         fz_catch(error, "aborting");
  41.         exit(1);
  42. }
  43.  
  44. static void usage(void)
  45. {
  46.         fprintf(stderr,
  47.                 "usage: pdfdraw [options] input.pdf [pages]\n"
  48.                 "\t-o -\toutput filename (%%d for page number)\n"
  49.                 "\t\tsupported formats: pgm, ppm, pam, png, pbm\n"
  50.                 "\t-p -\tpassword\n"
  51.                 "\t-r -\tresolution in dpi (default: 72)\n"
  52.                 "\t-A\tdisable accelerated functions\n"
  53.                 "\t-a\tsave alpha channel (only pam and png)\n"
  54.                 "\t-b -\tnumber of bits of antialiasing (0 to 8)\n"
  55.                 "\t-g\trender in grayscale\n"
  56.                 "\t-m\tshow timing information\n"
  57.                 "\t-t\tshow text (-tt for xml)\n"
  58.                 "\t-x\tshow display list\n"
  59.                 "\t-d\tdisable use of display list\n"
  60.                 "\t-5\tshow md5 checksums\n"
  61.                 "\t-R -\trotate clockwise by given number of degrees\n"
  62.                 "\t-G gamma\tgamma correct output\n"
  63.                 "\t-I\tinvert output\n"
  64.                 "\tpages\tcomma separated list of ranges\n");
  65.         exit(1);
  66. }
  67.  
  68. static int gettime(void)
  69. {
  70.         static struct timeval first;
  71.         static int once = 1;
  72.         struct timeval now;
  73.         if (once)
  74.         {
  75.                 gettimeofday(&first, NULL);
  76.                 once = 0;
  77.         }
  78.         gettimeofday(&now, NULL);
  79.         return (now.tv_sec - first.tv_sec) * 1000 + (now.tv_usec - first.tv_usec) / 1000;
  80. }
  81.  
  82. static int isrange(char *s)
  83. {
  84.         while (*s)
  85.         {
  86.                 if ((*s < '0' || *s > '9') && *s != '-' && *s != ',')
  87.                         return 0;
  88.                 s++;
  89.         }
  90.         return 1;
  91. }
  92.  
  93. static void drawpage(pdf_xref *xref, int pagenum)
  94. {
  95.         fz_error error;
  96.         pdf_page *page;
  97.         fz_display_list *list;
  98.         fz_device *dev;
  99.         int start;
  100.  
  101.         if (showtime)
  102.         {
  103.                 start = gettime();
  104.         }
  105.  
  106.         error = pdf_load_page(&page, xref, pagenum - 1);
  107.         if (error)
  108.                 die(fz_rethrow(error, "cannot load page %d in file '%s'", pagenum, filename));
  109.  
  110.         list = NULL;
  111.  
  112.         if (uselist)
  113.         {
  114.                 list = fz_new_display_list();
  115.                 dev = fz_new_list_device(list);
  116.                 error = pdf_run_page(xref, page, dev, fz_identity);
  117.                 if (error)
  118.                         die(fz_rethrow(error, "cannot draw page %d in file '%s'", pagenum, filename));
  119.                 fz_free_device(dev);
  120.         }
  121.  
  122.         if (showxml)
  123.         {
  124.                 dev = fz_new_trace_device();
  125.                 printf("<page number=\"%d\">\n", pagenum);
  126.                 if (list)
  127.                         fz_execute_display_list(list, dev, fz_identity, fz_infinite_bbox);
  128.                 else
  129.                         pdf_run_page(xref, page, dev, fz_identity);
  130.                 printf("</page>\n");
  131.                 fz_free_device(dev);
  132.         }
  133.  
  134.         if (showtext)
  135.         {
  136.                 fz_text_span *text = fz_new_text_span();
  137.                 dev = fz_new_text_device(text);
  138.                 if (list)
  139.                         fz_execute_display_list(list, dev, fz_identity, fz_infinite_bbox);
  140.                 else
  141.                         pdf_run_page(xref, page, dev, fz_identity);
  142.                 fz_free_device(dev);
  143.                 printf("[Page %d]\n", pagenum);
  144.                 if (showtext > 1)
  145.                         fz_debug_text_span_xml(text);
  146.                 else
  147.                         fz_debug_text_span(text);
  148.                 printf("\n");
  149.                 fz_free_text_span(text);
  150.         }
  151.  
  152.         if (showmd5 || showtime)
  153.                 printf("page %s %d", filename, pagenum);
  154.  
  155.         if (output || showmd5 || showtime)
  156.         {
  157.                 float zoom;
  158.                 fz_matrix ctm;
  159.                 fz_bbox bbox;
  160.                 fz_pixmap *pix;
  161.  
  162.                 zoom = resolution / 72;
  163.                 ctm = fz_translate(0, -page->mediabox.y1);
  164.                 ctm = fz_concat(ctm, fz_scale(zoom, -zoom));
  165.                 ctm = fz_concat(ctm, fz_rotate(page->rotate));
  166.                 ctm = fz_concat(ctm, fz_rotate(rotation));
  167.                 bbox = fz_round_rect(fz_transform_rect(ctm, page->mediabox));
  168.  
  169.                 /* TODO: banded rendering and multi-page ppm */
  170.  
  171.                 pix = fz_new_pixmap_with_rect(colorspace, bbox);
  172.  
  173.                 if (savealpha)
  174.                         fz_clear_pixmap(pix);
  175.                 else
  176.                         fz_clear_pixmap_with_color(pix, 255);
  177.  
  178.                 dev = fz_new_draw_device(glyphcache, pix);
  179.                 if (list)
  180.                         fz_execute_display_list(list, dev, ctm, bbox);
  181.                 else
  182.                         pdf_run_page(xref, page, dev, ctm);
  183.                 fz_free_device(dev);
  184.  
  185.                 if (invert)
  186.                         fz_invert_pixmap(pix);
  187.                 if (gamma_value != 1)
  188.                         fz_gamma_pixmap(pix, gamma_value);
  189.  
  190.                 if (output)
  191.                 {
  192.                         char buf[512];
  193.                         sprintf(buf, output, pagenum);
  194.                         if (strstr(output, ".pgm") || strstr(output, ".ppm") || strstr(output, ".pnm"))
  195.                                 fz_write_pnm(pix, buf);
  196.                         else if (strstr(output, ".pam"))
  197.                                 fz_write_pam(pix, buf, savealpha);
  198.                         else if (strstr(output, ".png"))
  199.                                 fz_write_png(pix, buf, savealpha);
  200.                         else if (strstr(output, ".pbm")) {
  201.                                 fz_halftone *ht = fz_get_default_halftone(1);
  202.                                 fz_bitmap *bit = fz_halftone_pixmap(pix, ht);
  203.                                 fz_write_pbm(bit, buf);
  204.                                 fz_drop_bitmap(bit);
  205.                                 fz_drop_halftone(ht);
  206.                         }
  207.                 }
  208.  
  209.                 if (showmd5)
  210.                 {
  211.                         fz_md5 md5;
  212.                         unsigned char digest[16];
  213.                         int i;
  214.  
  215.                         fz_md5_init(&md5);
  216.                         fz_md5_update(&md5, pix->samples, pix->w * pix->h * pix->n);
  217.                         fz_md5_final(&md5, digest);
  218.  
  219.                         printf(" ");
  220.                         for (i = 0; i < 16; i++)
  221.                                 printf("%02x", digest[i]);
  222.                 }
  223.  
  224.                 fz_drop_pixmap(pix);
  225.         }
  226.  
  227.         if (list)
  228.                 fz_free_display_list(list);
  229.  
  230.         pdf_free_page(page);
  231.  
  232.         if (showtime)
  233.         {
  234.                 int end = gettime();
  235.                 int diff = end - start;
  236.  
  237.                 if (diff < timing.min)
  238.                 {
  239.                         timing.min = diff;
  240.                         timing.minpage = pagenum;
  241.                 }
  242.                 if (diff > timing.max)
  243.                 {
  244.                         timing.max = diff;
  245.                         timing.maxpage = pagenum;
  246.                 }
  247.                 timing.total += diff;
  248.                 timing.count ++;
  249.  
  250.                 printf(" %dms", diff);
  251.         }
  252.  
  253.         if (showmd5 || showtime)
  254.                 printf("\n");
  255.  
  256.         pdf_age_store(xref->store, 3);
  257.  
  258.         fz_flush_warnings();
  259. }
  260.  
  261. static void drawrange(pdf_xref *xref, char *range)
  262. {
  263.         int page, spage, epage;
  264.         char *spec, *dash;
  265.  
  266.         spec = fz_strsep(&range, ",");
  267.         while (spec)
  268.         {
  269.                 dash = strchr(spec, '-');
  270.  
  271.                 if (dash == spec)
  272.                         spage = epage = pdf_count_pages(xref);
  273.                 else
  274.                         spage = epage = atoi(spec);
  275.  
  276.                 if (dash)
  277.                 {
  278.                         if (strlen(dash) > 1)
  279.                                 epage = atoi(dash + 1);
  280.                         else
  281.                                 epage = pdf_count_pages(xref);
  282.                 }
  283.  
  284.                 spage = CLAMP(spage, 1, pdf_count_pages(xref));
  285.                 epage = CLAMP(epage, 1, pdf_count_pages(xref));
  286.  
  287.                 if (spage < epage)
  288.                         for (page = spage; page <= epage; page++)
  289.                                 drawpage(xref, page);
  290.                 else
  291.                         for (page = spage; page >= epage; page--)
  292.                                 drawpage(xref, page);
  293.  
  294.                 spec = fz_strsep(&range, ",");
  295.         }
  296. }
  297.  
  298. int main(int argc, char **argv)
  299. {
  300.         char *password = "";
  301.         int grayscale = 0;
  302.         int accelerate = 1;
  303.         pdf_xref *xref;
  304.         fz_error error;
  305.         int c;
  306.  
  307.         while ((c = fz_getopt(argc, argv, "o:p:r:R:Aab:dgmtx5G:I")) != -1)
  308.         {
  309.                 switch (c)
  310.                 {
  311.                 case 'o': output = fz_optarg; break;
  312.                 case 'p': password = fz_optarg; break;
  313.                 case 'r': resolution = atof(fz_optarg); break;
  314.                 case 'R': rotation = atof(fz_optarg); break;
  315.                 case 'A': accelerate = 0; break;
  316.                 case 'a': savealpha = 1; break;
  317.                 case 'b': alphabits = atoi(fz_optarg); break;
  318.                 case 'm': showtime++; break;
  319.                 case 't': showtext++; break;
  320.                 case 'x': showxml++; break;
  321.                 case '5': showmd5++; break;
  322.                 case 'g': grayscale++; break;
  323.                 case 'd': uselist = 0; break;
  324.                 case 'G': gamma_value = atof(fz_optarg); break;
  325.                 case 'I': invert++; break;
  326.                 default: usage(); break;
  327.                 }
  328.         }
  329.  
  330.         fz_set_aa_level(alphabits);
  331.  
  332.         if (fz_optind == argc)
  333.                 usage();
  334.  
  335.         if (!showtext && !showxml && !showtime && !showmd5 && !output)
  336.         {
  337.                 printf("nothing to do\n");
  338.                 exit(0);
  339.         }
  340.  
  341.         if (accelerate)
  342.                 fz_accelerate();
  343.  
  344.         glyphcache = fz_new_glyph_cache();
  345.  
  346.         colorspace = fz_device_rgb;
  347.         if (grayscale)
  348.                 colorspace = fz_device_gray;
  349.         if (output && strstr(output, ".pgm"))
  350.                 colorspace = fz_device_gray;
  351.         if (output && strstr(output, ".ppm"))
  352.                 colorspace = fz_device_rgb;
  353.         if (output && strstr(output, ".pbm"))
  354.                 colorspace = fz_device_gray;
  355.  
  356.         timing.count = 0;
  357.         timing.total = 0;
  358.         timing.min = 1 << 30;
  359.         timing.max = 0;
  360.         timing.minpage = 0;
  361.         timing.maxpage = 0;
  362.  
  363.         if (showxml)
  364.                 printf("<?xml version=\"1.0\"?>\n");
  365.  
  366.         while (fz_optind < argc)
  367.         {
  368.                 filename = argv[fz_optind++];
  369.  
  370.                 error = pdf_open_xref(&xref, filename, password);
  371.                 if (error)
  372.                         die(fz_rethrow(error, "cannot open document: %s", filename));
  373.  
  374.                 error = pdf_load_page_tree(xref);
  375.                 if (error)
  376.                         die(fz_rethrow(error, "cannot load page tree: %s", filename));
  377.  
  378.                 if (showxml)
  379.                         printf("<document name=\"%s\">\n", filename);
  380.  
  381.                 if (fz_optind == argc || !isrange(argv[fz_optind]))
  382.                         drawrange(xref, "1-");
  383.                 if (fz_optind < argc && isrange(argv[fz_optind]))
  384.                         drawrange(xref, argv[fz_optind++]);
  385.  
  386.                 if (showxml)
  387.                         printf("</document>\n");
  388.  
  389.                 pdf_free_xref(xref);
  390.         }
  391.  
  392.         if (showtime)
  393.         {
  394.                 printf("total %dms / %d pages for an average of %dms\n",
  395.                         timing.total, timing.count, timing.total / timing.count);
  396.                 printf("fastest page %d: %dms\n", timing.minpage, timing.min);
  397.                 printf("slowest page %d: %dms\n", timing.maxpage, timing.max);
  398.         }
  399.  
  400.         fz_free_glyph_cache(glyphcache);
  401.  
  402.         fz_flush_warnings();
  403.  
  404.         return 0;
  405. }
  406.