]> mj.ucw.cz Git - paperjam.git/commitdiff
Measure bboxes by Ghostscripting
authorMartin Mares <mj@ucw.cz>
Mon, 2 Apr 2018 00:21:32 +0000 (02:21 +0200)
committerMartin Mares <mj@ucw.cz>
Mon, 2 Apr 2018 00:21:32 +0000 (02:21 +0200)
Makefile
gs.cc [new file with mode: 0644]
jam.h
paperjam.cc

index 6504c15ba2be562ab75baebac68234bc639b8a85..bb74b758783b4ae6b1936893045d78c0f63429b1 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@ CXXFLAGS=-O2 -Wall -Wextra -Wno-parentheses -std=gnu++11 -g
 
 all: paperjam
 
-paperjam: paperjam.o pdf-tools.o parse.o cmds.o
+paperjam: paperjam.o pdf-tools.o parse.o cmds.o gs.o
        $(LD) -o $@ $^ $(LDLIBS)
 paperjam: LDLIBS += -lqpdf
 paperjam: LD=$(CXX)
@@ -11,3 +11,4 @@ paperjam.o: jam.h pdf-tools.h
 pdf-tools.o: jam.h pdf-tools.h
 parse.o: jam.h pdf-tools.h
 cmds.o: jam.h pdf-tools.h
+gs.o: jam.h pdf-tools.h
diff --git a/gs.cc b/gs.cc
new file mode 100644 (file)
index 0000000..b52448a
--- /dev/null
+++ b/gs.cc
@@ -0,0 +1,62 @@
+#include <cassert>
+#include <cstdlib>
+#include <cstdio>
+#include <unistd.h>
+#include <sys/wait.h>
+
+#include "jam.h"
+
+vector<BBox> gs_bboxes(const char *in)
+{
+  int pipes[2];
+  if (pipe(pipes) < 0)
+    die("Cannot create pipe: %m");
+
+  pid_t pid = fork();
+  if (pid < 0)
+    die("Cannot fork: %m");
+
+  if (!pid)
+    {
+      close(pipes[0]);
+      dup2(pipes[1], 1);
+      dup2(pipes[1], 2);
+      close(pipes[1]);
+      execlp("gs", "gs", "-sDEVICE=bbox", "-dSAFER", "-dBATCH", "-dNOPAUSE", "-q", in, NULL);
+      die("Cannot execute gs: %m");
+    }
+
+  close(pipes[1]);
+  FILE *f = fdopen(pipes[0], "r");
+  if (!f)
+    die("fdopen failed: %m");
+
+  char line[1024];
+  vector<BBox> bboxes;
+  while (fgets(line, sizeof(line), f))
+    {
+      char *eol = strchr(line, '\n');
+      if (!eol)
+       die("Ghostscript produced too long lines");
+      *eol = 0;
+
+      if (!strncmp(line, "%%HiResBoundingBox: ", 20))
+       {
+         double x1, y1, x2, y2;
+         if (sscanf(line+20, "%lf%lf%lf%lf", &x1, &y1, &x2, &y2) != 4)
+           die("Cannot parse Ghostscript output: %s", line);
+         bboxes.push_back(BBox(x1, y1, x2, y2));
+       }
+      else if (line[0] != '%')
+       fprintf(stderr, "%s\n", line);
+    }
+  fclose(f);
+
+  int stat;
+  if (waitpid(pid, &stat, 0) < 0)
+    die("wait failed: %m");
+  if (!WIFEXITED(stat) || WEXITSTATUS(stat))
+    die("Ghostscript failed");
+
+  return bboxes;
+}
diff --git a/jam.h b/jam.h
index c985502f745420505200d74573257c972e65ce69..a966cea36d72bce230f9b775284f190ef8ef05eb 100644 (file)
--- a/jam.h
+++ b/jam.h
@@ -110,3 +110,7 @@ void help();
 // cmds.cc
 
 extern const cmd_def cmd_table[];
+
+// gs.cc
+
+vector<BBox> gs_bboxes(const char *in);
index ba2bb3bf8bd6b55a3dea24f90da74cb85a27d39c..c8e107181d7ad97b1b1bdb195c20e45405a1b6eb 100644 (file)
@@ -70,7 +70,10 @@ static void debug_pages(vector<page *> &pages)
     return;
 
   for (auto pg: pages)
-    debug("Page #%d: w=%.3f h=%.3f", pg->index, pg->width, pg->height);
+    debug("Page #%d: media[%.3f %.3f] bbox[%.3f %.3f %.3f %.3f]",
+      pg->index,
+      pg->width, pg->height,
+      pg->bbox.x_min, pg->bbox.y_min, pg->bbox.x_max, pg->bbox.y_max);
 }
 
 vector<page *> run_command_list(list<cmd *> &cmds, vector<page *> &pages)
@@ -90,6 +93,16 @@ vector<page *> run_command_list(list<cmd *> &cmds, vector<page *> &pages)
   return pages;
 }
 
+static void find_bboxes(vector<page *> &pages, const char *in_name)
+{
+  vector<BBox> bboxes = gs_bboxes(in_name);
+  if (pages.size() != bboxes.size())
+    die("Ghostscript failed to produce the right number of bboxes");
+
+  for (size_t i=0; i<pages.size(); i++)
+    pages[i]->bbox = bboxes[i];
+}
+
 static void process(list<cmd *> &cmds, const char *in_name, const char *out_name)
 {
   in_pdf.processFile(in_name);
@@ -105,6 +118,8 @@ static void process(list<cmd *> &cmds, const char *in_name, const char *out_name
   for (auto inpg: in_pages)
     pages.push_back(new in_page(inpg, ++cnt));
 
+  find_bboxes(pages, in_name);
+
   pages = run_command_list(cmds, pages);
 
   for (auto pg: pages)
@@ -122,7 +137,8 @@ static void process(list<cmd *> &cmds, const char *in_name, const char *out_name
       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("/CropBox", pg->bbox.to_array());
+      // FIXME:
+      // out_page.replaceKey("/CropBox", pg->bbox.to_array());
       out_page.replaceKey("/Contents", contents);
       out_page.replaceKey("/Resources", out.resources);
       out_pdf.addPage(out_page, false);