From: Martin Mares Date: Mon, 2 Apr 2018 00:21:32 +0000 (+0200) Subject: Measure bboxes by Ghostscripting X-Git-Tag: v0.1~35 X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=554561d7bfeebb0f849da0150b576a89a48c4ceb;p=paperjam.git Measure bboxes by Ghostscripting --- diff --git a/Makefile b/Makefile index 6504c15..bb74b75 100644 --- 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 index 0000000..b52448a --- /dev/null +++ b/gs.cc @@ -0,0 +1,62 @@ +#include +#include +#include +#include +#include + +#include "jam.h" + +vector 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 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 c985502..a966cea 100644 --- a/jam.h +++ b/jam.h @@ -110,3 +110,7 @@ void help(); // cmds.cc extern const cmd_def cmd_table[]; + +// gs.cc + +vector gs_bboxes(const char *in); diff --git a/paperjam.cc b/paperjam.cc index ba2bb3b..c8e1071 100644 --- a/paperjam.cc +++ b/paperjam.cc @@ -70,7 +70,10 @@ static void debug_pages(vector &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 run_command_list(list &cmds, vector &pages) @@ -90,6 +93,16 @@ vector run_command_list(list &cmds, vector &pages) return pages; } +static void find_bboxes(vector &pages, const char *in_name) +{ + vector 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; ibbox = bboxes[i]; +} + static void process(list &cmds, const char *in_name, const char *out_name) { in_pdf.processFile(in_name); @@ -105,6 +118,8 @@ static void process(list &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 &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);