/*** null ***/
class null_cmd : public cmd_exec {
- vector<page *> process(vector<page *> pages) { return pages; }
+ vector<page *> process(vector<page *> &pages) { return pages; }
};
static const arg_def null_args[] = {
class move_cmd : public cmd_exec {
public:
double x, y;
- vector<page *> process(vector<page *> pages);
+ vector<page *> process(vector<page *> &pages);
};
class xform_page : public page {
orig_page->render(out, xform * parent_xform);
}
-vector<page *> move_cmd::process(vector<page *> pages)
+vector<page *> move_cmd::process(vector<page *> &pages)
{
vector<page *> out;
for (auto p: pages)
class scale_cmd : public cmd_exec {
public:
double x_factor, y_factor;
- vector<page *> process(vector<page *> pages);
+ vector<page *> process(vector<page *> &pages);
};
-vector<page *> scale_cmd::process(vector<page *> pages)
+vector<page *> scale_cmd::process(vector<page *> &pages)
{
vector<page *> out;
for (auto p: pages)
};
struct page_out {
+ QPDFObjectHandle resources;
+ QPDFObjectHandle xobjects;
+ string contents;
+ int res_cnt;
+ string new_resource(const string type);
};
struct page {
+ int index;
double width;
double height;
virtual void render(page_out *out UNUSED, pdf_matrix xform UNUSED) { abort(); }
- page(double _w, double _h) : width(_w), height(_h) { }
+ page(double _w=0, double _h=0) : width(_w), height(_h) { }
};
struct cmd_exec {
- virtual vector<page *> process(vector <page *> pages UNUSED) { abort(); }
+ virtual vector<page *> process(vector <page *> &pages UNUSED) { abort(); }
};
struct cmd_def {
// parse.cc
-void parse(const char *in, list<cmd *> *cmds);
+void parse(const char *in, list<cmd *> &cmds);
// cmds.cc
#include "jam.h"
+#include <qpdf/QPDFWriter.hh>
+
+static QPDF in_pdf;
+static QPDF out_pdf;
+
+string page_out::new_resource(const string type)
+{
+ return "/" + type + to_string(++res_cnt);
+}
+
+class in_page : public page {
+ QPDFObjectHandle pdf_page;
+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)
+{
+ pdf_page = inpg;
+ index = idx;
+ media_box = BBox(inpg.getKey("/MediaBox"));
+ width = media_box.width();
+ height = media_box.height();
+}
+
+void in_page::render(page_out *out, pdf_matrix xform)
+{
+ // Convert page to xobject
+ QPDFObjectHandle page_copy = page_to_xobject(&out_pdf, out_pdf.copyForeignObject(pdf_page));
+ string xobj_res = out->new_resource("XO");
+ out->xobjects.replaceKey(xobj_res, out_pdf.makeIndirectObject(page_copy));
+
+ 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";
+}
+
+static void debug_pages(vector<page *> &pages)
+{
+ if (!debug_mode)
+ return;
+
+ for (auto pg: pages)
+ debug("Page #%d: w=%.3f h=%.3f", pg->index, pg->width, pg->height);
+}
+
+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;
+
+ QPDFObjectHandle page_copy = out_pdf.copyForeignObject(in_pages[0]);
+
+ int cnt = 0;
+ for (auto inpg: in_pages)
+ pages.push_back(new in_page(inpg, ++cnt));
+ debug("# Input document");
+ debug_pages(pages);
+
+ for (auto c: cmds)
+ {
+ debug("# Executing %s", c->def->name);
+ pages = c->exec->process(pages);
+ debug_pages(pages);
+ }
+
+ 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);
+ }
+
+ // 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();
+}
+
int main(int argc, char **argv)
{
if (argc != 4)
return 1;
}
+ debug_mode = 100;
+
list<cmd *> cmds;
- parse(argv[1], &cmds);
+ parse(argv[1], cmds);
+
+ try
+ {
+ process(cmds, argv[2], argv[3]);
+ }
+ catch (exception& e)
+ {
+ die("%s", e.what());
+ }
return 0;
}
static double token_num;
static void NONRET parse_error(const char *msg, ...);
-static void parse_commands(list<cmd *> *cmds);
+static void parse_commands(list<cmd *> &cmds);
static void parse_error(const char *msg, ...)
{
pb->selectors.push_back(ps);
}
- parse_commands(&pb->commands);
+ parse_commands(pb->commands);
}
c->pipe = pp;
}
}
-static void debug_cmds(list<cmd *> *cmds)
+static void debug_cmds(list<cmd *> &cmds)
{
- for (auto c: *cmds)
+ for (auto c: cmds)
debug_cmd(c);
}
return c;
}
-static void parse_commands(list<cmd *> *cmds)
+static void parse_commands(list<cmd *> &cmds)
{
for (;;)
{
}
cmd *c = parse_cmd();
- cmds->push_back(c);
+ cmds.push_back(c);
}
}
-static void instantiate(list<cmd *> *cmds)
+static void instantiate(list<cmd *> &cmds)
{
- for (auto c: *cmds)
+ for (auto c: cmds)
{
c->exec = c->def->constructor(c);
if (c->pipe)
{
for (auto pb: c->pipe->branches)
- instantiate(&pb->commands);
+ instantiate(pb->commands);
}
}
}
-void parse(const char *in, list<cmd *> *cmds)
+void parse(const char *in, list<cmd *> &cmds)
{
in_pos = in;
parse_commands(cmds);