]> mj.ucw.cz Git - paperjam.git/blobdiff - paperjam.cc
TODO: a4r paper
[paperjam.git] / paperjam.cc
index 0a95acf26abd49b8c06ba2b110bf8703611005af..0d3bf12c57fe95452fcd8cb1ec5b626966ce2f6d 100644 (file)
+/*
+ *     PaperJam -- Main program
+ *
+ *     (c) 2018--2022 Martin Mares <mj@ucw.cz>
+ */
+
 #include <cassert>
 #include <cstdarg>
 #include <cstdlib>
 #include <cstdio>
+#include <getopt.h>
 
 #include "jam.h"
 
-#include <qpdf/QPDFWriter.hh>
+/*** Options ***/
 
-static QPDF in_pdf;
-static QPDF out_pdf;
+const char *in_name;
+const char *out_name;
+bool recalc_bbox;
+bool no_auto_transforms;
+int debug_level;
+int debug_indent;
 
-string page_out::new_resource(const string type)
-{
-  return "/" + type + to_string(++res_cnt);
-}
+/*** Messages ***/
 
-class in_page : public page {
-  QPDFObjectHandle pdf_page;
-  QPDFObjectHandle xobject;
-public:
-  BBox media_box;
-  void render(page_out *out, pdf_matrix xform);
-  in_page(QPDFObjectHandle inpg, int idx);
-};
-
-in_page::in_page(QPDFObjectHandle inpg, int idx)
+void debug(const char *msg, ...)
 {
-  pdf_page = inpg;
-  xobject = QPDFObjectHandle::newNull();
-  index = idx;
-  media_box = BBox(inpg.getKey("/MediaBox"));
-  width = media_box.width();
-  height = media_box.height();
+  if (!debug_level)
+    return;
+  va_list args;
+  va_start(args, msg);
+  fprintf(stderr, "%*s", debug_indent, "");
+  vfprintf(stderr, msg, args);
+  fputc('\n', stderr);
+  va_end(args);
 }
 
-void in_page::render(page_out *out, pdf_matrix xform)
+void warn(const char *msg, ...)
 {
-  // Convert page to xobject
-  if (xobject.isNull())
-    xobject = out_pdf.makeIndirectObject( page_to_xobject(&out_pdf, out_pdf.copyForeignObject(pdf_page)) );
-  string xobj_res = out->new_resource("XO");
-  out->xobjects.replaceKey(xobj_res, xobject);
-
-  pdf_matrix m;
-  m.shift(-media_box.x_min, -media_box.y_min);
-  m.concat(xform);
-
-  out->contents += "q " + m.to_string() + " cm " + xobj_res + " Do Q";
+  va_list args;
+  va_start(args, msg);
+  fprintf(stderr, "Warning: ");
+  vfprintf(stderr, msg, args);
+  fputc('\n', stderr);
+  va_end(args);
 }
 
-static void debug_pages(vector<page *> &pages)
+void die(const char *msg, ...)
 {
-  if (!debug_mode)
-    return;
-
-  for (auto pg: pages)
-    debug("Page #%d: w=%.3f h=%.3f", pg->index, pg->width, pg->height);
+  va_list args;
+  va_start(args, msg);
+  vfprintf(stderr, msg, args);
+  fputc('\n', stderr);
+  va_end(args);
+  exit(1);
 }
 
-vector<page *> run_command_list(list<cmd *> &cmds, vector<page *> &pages)
+void err(const char *msg, ...)
 {
-  debug("# Input");
-  debug_pages(pages);
-
-  for (auto c: cmds)
-    {
-      debug("# Executing %s", c->def->name);
-      debug_indent += 4;
-      pages = c->exec->process(pages);
-      debug_indent -= 4;
-      debug_pages(pages);
-    }
-
-  return pages;
+  va_list args;
+  va_start(args, msg);
+  char buf[1024];
+  vsnprintf(buf, sizeof(buf), msg, args);
+  va_end(args);
+  throw paperjam_error(buf);
 }
 
-static void process(list<cmd *> &cmds, const char *in_name, const char *out_name)
-{
-  in_pdf.processFile(in_name);
-  in_pdf.pushInheritedAttributesToPage();
-  out_pdf.emptyPDF();
-
-  vector<QPDFObjectHandle> const &in_pages = in_pdf.getAllPages();
-  vector<page *> pages;
+/*** Arguments ***/
 
-  QPDFObjectHandle page_copy = out_pdf.copyForeignObject(in_pages[0]);
+enum opt {
+  OPT_HELP = 256,
+  OPT_VERSION,
+  OPT_NO_AUTO,
+};
 
-  int cnt = 0;
-  for (auto inpg: in_pages)
-    pages.push_back(new in_page(inpg, ++cnt));
+static const struct option long_opts[] = {
+  { "debug",   0, 0, 'd' },
+  { "help",    0, 0, OPT_HELP },
+  { "version", 0, 0, OPT_VERSION },
+  { "bbox",    0, 0, 'b' },
+  { 0,         0, 0, 0 }
+};
 
-  pages = run_command_list(cmds, pages);
+static const char short_opts[] = "bd";
 
-  for (auto pg: pages)
-    {
-      page_out out;
-      out.resources = QPDFObjectHandle::newDictionary();
-      // FIXME: What if the source page requires a broader ProcSet?
-      out.resources.replaceKey("/ProcSet", QPDFObjectHandle::parse("[/PDF /Text]"));
-      out.xobjects = QPDFObjectHandle::newDictionary();
-      out.resources.replaceKey("/XObject", out.xobjects);
-      pg->render(&out, pdf_matrix());
-
-      QPDFObjectHandle contents = QPDFObjectHandle::newStream(&out_pdf, out.contents);
-
-      // Create the page object
-      QPDFObjectHandle out_page = out_pdf.makeIndirectObject(QPDFObjectHandle::newDictionary());
-      out_page.replaceKey("/Type", QPDFObjectHandle::newName("/Page"));
-      out_page.replaceKey("/MediaBox", BBox(pg->width, pg->height).to_array());
-      out_page.replaceKey("/Contents", contents);
-      out_page.replaceKey("/Resources", out.resources);
-      out_pdf.addPage(out_page, false);
-    }
+static void usage()
+{
+  printf("Usage: paperjam [<options>] <commands> <in> <out>\n\
+\n\
+Options:\n\
+-b, --bbox             Recalculate bounding boxes\n\
+-d, --debug            Show debugging messages\n\
+    --no-auto          Disable automatic rotation of pages\n\
+\n\
+<command> = <name>(<args>, <named-arg>[=<value>], ...) [<pipeline>]\n\
+<pipeline> = { <stage>, <stage>, ... }\n\
+<stage> = <page> <page> ... [: <commands>]\n\
+\n\
+Example:\n\
+paperjam 'book nup(2, paper=a4)' input.pdf output.pdf\n\
+\n\
+Commands:\n\
+");
+  parser_help();
+}
 
-  // Produce info dictionary
-  QPDFObjectHandle trailer = out_pdf.getTrailer();
-  QPDFObjectHandle info = trailer.getKey("/Info");
-  if (info.isNull())
-    {
-      info = QPDFObjectHandle::newDictionary();
-      trailer.replaceKey("/Info", info);
-    }
-  else
-    assert(info.isDictionary());
-  // FIXME: More meta-data
-  info.replaceKey("/Producer", unicode_string("PaperJam"));
-
-  // Write the output file
-  QPDFWriter writer(out_pdf, out_name);
-  writer.write();
+static void show_version()
+{
+  printf("PaperJam " VERSION " -- a PDF processor\n");
+  printf("(c) " YEAR " Martin Mares, distributed under GNU GPL 2+\n");
+  printf("Built on " BUILD_DATE " from Git commit " BUILD_COMMIT "\n");
 }
 
 int main(int argc, char **argv)
 {
-  if (argc != 4)
-    {
-      fprintf(stderr, "Usage: paperjam <commands> <input> <output>\n");
-      return 1;
-    }
-
-  debug_mode = 100;
+  int c;
+  while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) >= 0)
+    switch (c)
+      {
+      case 'b':
+       recalc_bbox = 1;
+       break;
+      case 'd':
+       debug_level++;
+       break;
+      case OPT_VERSION:
+       show_version();
+       return 0;
+      case OPT_HELP:
+       usage();
+       return 0;
+      case OPT_NO_AUTO:
+       no_auto_transforms = true;
+       break;
+      default:
+       exit(1);
+      }
+
+  if (optind + 3 != argc)
+    die("Exactly three positional parameters should be given");
 
   list<cmd *> cmds;
-  parse(argv[1], cmds);
+  parse(argv[optind], cmds);
+  in_name = argv[optind+1];
+  out_name = argv[optind+2];
 
   try
     {
-      process(cmds, argv[2], argv[3]);
+      process(cmds);
     }
   catch (exception& e)
     {