]> mj.ucw.cz Git - paperjam.git/blobdiff - cmds.cc
One more <cstring>
[paperjam.git] / cmds.cc
diff --git a/cmds.cc b/cmds.cc
index 73daa4cbc4211419c3a939f11a8e833c9c5b8d08..7d0f9b659d934323bd02ef1b336c1811990867b6 100644 (file)
--- a/cmds.cc
+++ b/cmds.cc
@@ -32,6 +32,11 @@ class xform_page : public page {
   pdf_matrix xform;
 public:
   void render(out_context *out, pdf_matrix xform) override;
+  void debug_dump() override
+    {
+      debug("Transform [%s]", xform.to_string().c_str());
+      orig_page->debug_dump();
+    }
   xform_page(page *p, pdf_matrix xf);
 };
 
@@ -199,8 +204,8 @@ public:
     {
       bb->x_min += l;
       bb->x_max -= r;
-      bb->y_min += b;
-      bb->y_max -= t;
+      bb->y_min += t;
+      bb->y_max -= b;
       if (bb->x_min >= bb->x_max || bb->y_min >= bb->y_max)
        err("Margins cannot be larger than the whole page");
     }
@@ -208,8 +213,8 @@ public:
     {
       bb->x_min -= l;
       bb->x_max += r;
-      bb->y_min -= b;
-      bb->y_max += t;
+      bb->y_min -= t;
+      bb->y_max += b;
     }
 };
 
@@ -575,7 +580,7 @@ vector<page *> select_cmd::process(vector<page *> &pages)
          int f = validate_page_index(pages, ps.from);
          int t = validate_page_index(pages, ps.to);
          int step = (f <= t) ? 1 : -1;
-         for (int i=f; f<=t; f += step)
+         for (int i=f; i<=t; i += step)
            selected.push_back(pages[i]);
        }
       auto processed = run_command_list(pb->commands, selected);
@@ -718,6 +723,11 @@ public:
       out->contents += page_cm->pdf_stream(out, page_bbox, xform);
       out->contents += image_cm->pdf_stream(out, image_box, xform);
     }
+  void debug_dump() override
+    {
+      debug("Draw debugging boxes");
+      orig_page->debug_dump();
+    }
 };
 
 class debug_cmd : public cmd_exec_simple {
@@ -778,6 +788,14 @@ public:
       for (auto p: orig_pages)
        p->render(out, xform);
     }
+  void debug_dump() override
+    {
+      debug("Merge pages");
+      debug_indent += 4;
+      for (auto p: orig_pages)
+       p->debug_dump();
+      debug_indent -= 4;
+    }
 };
 
 vector<page *> merge_cmd::process(vector<page *> &pages)
@@ -920,14 +938,10 @@ public:
   margins_cmd(cmd *c) : marg(c, "size", "") { }
   page *process_page(page *p) override
     {
-      pdf_matrix xf;
-      xf.shift(-p->image_box.x_min, -p->image_box.y_min);
-      xf.shift(marg.l, marg.b);
-      page *q = new xform_page(p, xf);
-      q->width = p->image_box.width() + marg.l + marg.r;
-      q->height = p->image_box.height() + marg.t + marg.b;
-      if (q->width < 0.001 || q->height < 0.001)
-       err("Margins must result in positive page dimensions");
+      page *q = new xform_page(p, pdf_matrix());
+      q->image_box = BBox(marg.l, marg.t, p->width - marg.r, p->height - marg.b);
+      if (q->image_box.width() < 0.001 || q->image_box.height() < 0.001)
+       err("Margins must result in positive image dimensions");
       return q;
     }
 };
@@ -1267,6 +1281,14 @@ public:
   cropmark_spec *cmarks;
   void render(out_context *out, pdf_matrix xform) override;
   nup_page(nup_state &st) : page(st.paper_w, st.paper_h) { }
+  void debug_dump() override
+    {
+      debug("N-up printing");
+      debug_indent += 4;
+      for (auto p: orig_pages)
+       p->debug_dump();
+      debug_indent -= 4;
+    }
 };
 
 void nup_page::render(out_context *out, pdf_matrix parent_xform)
@@ -1364,6 +1386,11 @@ public:
       orig_page->render(out, xform);
       out->contents += cm->pdf_stream(out, image_box, xform);
     }
+  void debug_dump() override
+    {
+      debug("Add cropmarks");
+      orig_page->debug_dump();
+    }
   cropmarks_page(page *p, cropmark_spec *cms) : page(p), orig_page(p), cm(cms) { }
 };
 
@@ -1394,6 +1421,11 @@ public:
       orig_page->render(out, xform);
       out->contents += "Q ";
     }
+  void debug_dump() override
+    {
+      debug("Clip [%.3f %.3f %.3f %.3f]", clip_to.x_min, clip_to.y_min, clip_to.x_max, clip_to.y_max);
+      orig_page->debug_dump();
+    }
   clip_page(page *p, BBox &to) : page(p), orig_page(p), clip_to(to) { }
 };
 
@@ -1416,6 +1448,103 @@ static const arg_def clip_args[] = {
   { NULL,      0,                              NULL }
 };
 
+/*** common ***/
+
+class common_cmd : public cmd_exec {
+  vector<page *> process(vector<page *> &pages) override
+    {
+      if (!pages.size())
+        return pages;
+
+      const page *first = pages[0];
+      BBox pbox(first->width, first->height);
+      BBox ibox = first->image_box;
+      for (auto p: pages)
+       {
+         BBox pg(p->width, p->height);
+         pbox.join(pg);
+         ibox.join(p->image_box);
+       }
+
+      vector<page *> out;
+      for (auto p: pages)
+       {
+         page *q = new xform_page(p, pdf_matrix());
+         q->width = pbox.width();
+         q->height = pbox.height();
+         q->image_box = ibox;
+         out.push_back(q);
+       }
+
+      return out;
+    }
+public:
+  common_cmd(cmd *c UNUSED) { }
+};
+
+/*** slice ***/
+
+class slice_cmd : public cmd_exec {
+  paper_spec paper;
+  pos_spec pos;
+  margin_spec margin;
+  double bleed;
+public:
+  slice_cmd(cmd *c) : paper(c), pos(c), margin(c, "margin", "margin")
+    {
+      if (is_zero(paper.w) || is_zero(paper.h))
+       err("Paper format must be given");
+      bleed = c->arg("bleed")->as_double(0);
+    }
+  vector<page *> process(vector<page *> &pages) override;
+};
+
+vector<page *> slice_cmd::process(vector<page *> &pages)
+{
+  vector<page *> out;
+
+  for (auto p: pages)
+    {
+      double pw = paper.w - margin.l - margin.r;
+      double ph = paper.h - margin.t - margin.b;
+      if (pw < 0 || ph < 0)
+       err("Margins larger than paper");
+
+      int cols = (int) ceil((p->image_box.width() - 2*mm) / pw);
+      int rows = (int) ceil((p->image_box.height() - 2*mm) / ph);
+      BBox big_box(cols*pw, rows*ph);
+      pdf_matrix placement = pos.place(p->image_box, big_box);
+
+      debug("Slicing [%.3f,%.3f] to %dx%d [%.3f,%.3f]", p->image_box.width(), p->image_box.height(), rows, cols, pw, ph);
+      for (int r=0; r<rows; r++)
+       for (int c=0; c<cols; c++)
+         {
+           pdf_matrix xf = placement;
+           xf.shift(-c*pw, -(rows-1-r)*ph);
+           xf.shift(margin.l, margin.t);
+           page *q = new xform_page(p, xf);
+           q->width = paper.w;
+           q->height = paper.h;
+           BBox slice_box = BBox(margin.l, margin.t, paper.w - margin.r, paper.h - margin.b);
+           q->image_box = p->image_box.transformed(xf);
+           q->image_box.intersect(slice_box);
+           BBox bleeding_slice = slice_box.enlarged(bleed);
+           out.push_back(new clip_page(q, bleeding_slice));
+         }
+    }
+
+  return out;
+}
+
+static const arg_def slice_args[] = {
+  PAPER_ARGS,
+  POS_ARGS,
+  MARGIN_ARGS1_NAMED("margin"),
+  MARGIN_ARGS2("margin"),
+  { "bleed",   AT_DIMEN,                       "Allow bleeding of image outside its box" },
+  { NULL,      0,                              NULL }
+};
+
 /*** Command table ***/
 
 template<typename T> cmd_exec *ctor(cmd *c) { return new T(c); }
@@ -1429,6 +1558,8 @@ const cmd_def cmd_table[] = {
                "Prepare booklets for book binding" },
   { "clip",    clip_args,      0,      &ctor<clip_cmd>,
                "Suppress page contents drawn outside the image box" },
+  { "common",  no_args,        0,      &ctor<common_cmd>,
+               "Use a common page size and image box for all pages" },
   { "cropmarks",cropmarks_args,        0,      &ctor<cropmarks_cmd>,
                "Draw cropping marks around the image box" },
   { "debug",   no_args,        0,      &ctor<debug_cmd>,
@@ -1461,6 +1592,8 @@ const cmd_def cmd_table[] = {
                "Scale the page to a given size" },
   { "select",  no_args,        1,      &ctor<select_cmd>,
                "Select a subset of pages" },
+  { "slice",   slice_args,     0,      &ctor<slice_cmd>,
+               "Slice to smaller pages" },
   { NULL,      NULL,           0,      NULL,
                NULL, }
 };