8 #include <qpdf/QPDFWriter.hh>
13 string page_out::new_resource(const string type)
15 return "/" + type + to_string(++res_cnt);
18 class in_page : public page {
19 QPDFObjectHandle pdf_page;
22 void render(page_out *out, pdf_matrix xform);
23 in_page(QPDFObjectHandle inpg, int idx);
26 in_page::in_page(QPDFObjectHandle inpg, int idx)
30 media_box = BBox(inpg.getKey("/MediaBox"));
31 width = media_box.width();
32 height = media_box.height();
35 void in_page::render(page_out *out, pdf_matrix xform)
37 // Convert page to xobject
38 QPDFObjectHandle page_copy = page_to_xobject(&out_pdf, out_pdf.copyForeignObject(pdf_page));
39 string xobj_res = out->new_resource("XO");
40 out->xobjects.replaceKey(xobj_res, out_pdf.makeIndirectObject(page_copy));
43 m.shift(-media_box.x_min, -media_box.y_min);
46 out->contents += "q " + m.to_string() + " cm " + xobj_res + " Do Q";
49 static int run_indent;
51 static void debug_pages(vector<page *> &pages)
57 debug("%*sPage #%d: w=%.3f h=%.3f", run_indent, "", pg->index, pg->width, pg->height);
60 vector<page *> run_command_list(list<cmd *> &cmds, vector<page *> &pages)
62 debug("%*s# Input", run_indent, "");
67 debug("%*s# Executing %s", run_indent, "", c->def->name);
69 pages = c->exec->process(pages);
77 static void process(list<cmd *> &cmds, const char *in_name, const char *out_name)
79 in_pdf.processFile(in_name);
80 in_pdf.pushInheritedAttributesToPage();
83 vector<QPDFObjectHandle> const &in_pages = in_pdf.getAllPages();
86 QPDFObjectHandle page_copy = out_pdf.copyForeignObject(in_pages[0]);
89 for (auto inpg: in_pages)
90 pages.push_back(new in_page(inpg, ++cnt));
92 pages = run_command_list(cmds, pages);
97 out.resources = QPDFObjectHandle::newDictionary();
98 // FIXME: What if the source page requires a broader ProcSet?
99 out.resources.replaceKey("/ProcSet", QPDFObjectHandle::parse("[/PDF /Text]"));
100 out.xobjects = QPDFObjectHandle::newDictionary();
101 out.resources.replaceKey("/XObject", out.xobjects);
102 pg->render(&out, pdf_matrix());
104 QPDFObjectHandle contents = QPDFObjectHandle::newStream(&out_pdf, out.contents);
106 // Create the page object
107 QPDFObjectHandle out_page = out_pdf.makeIndirectObject(QPDFObjectHandle::newDictionary());
108 out_page.replaceKey("/Type", QPDFObjectHandle::newName("/Page"));
109 out_page.replaceKey("/MediaBox", BBox(pg->width, pg->height).to_array());
110 out_page.replaceKey("/Contents", contents);
111 out_page.replaceKey("/Resources", out.resources);
112 out_pdf.addPage(out_page, false);
115 // Produce info dictionary
116 QPDFObjectHandle trailer = out_pdf.getTrailer();
117 QPDFObjectHandle info = trailer.getKey("/Info");
120 info = QPDFObjectHandle::newDictionary();
121 trailer.replaceKey("/Info", info);
124 assert(info.isDictionary());
125 // FIXME: More meta-data
126 info.replaceKey("/Producer", unicode_string("PaperJam"));
128 // Write the output file
129 QPDFWriter writer(out_pdf, out_name);
133 int main(int argc, char **argv)
137 fprintf(stderr, "Usage: paperjam <commands> <input> <output>\n");
144 parse(argv[1], cmds);
148 process(cmds, argv[2], argv[3]);