8 #include <qpdf/QPDFWriter.hh>
13 string out_context::new_resource(const string type)
15 return "/" + type + to_string(++res_cnt);
18 class in_page : public page {
19 QPDFObjectHandle pdf_page;
20 QPDFObjectHandle xobject;
23 void render(out_context *out, pdf_matrix xform);
24 in_page(QPDFObjectHandle inpg, int idx);
27 in_page::in_page(QPDFObjectHandle inpg, int idx)
30 xobject = QPDFObjectHandle::newNull();
33 media_box = BBox(inpg.getKey("/MediaBox"));
34 width = media_box.width();
35 height = media_box.height();
37 QPDFObjectHandle art_box = inpg.getKey("/ArtBox");
39 art_box = inpg.getKey("/CropBox");
41 bbox = BBox(width, height);
45 bbox.x_min -= media_box.x_min;
46 bbox.x_max -= media_box.x_min;
47 bbox.y_min -= media_box.y_min;
48 bbox.y_max -= media_box.y_min;
52 void in_page::render(out_context *out, pdf_matrix xform)
54 // Convert page to xobject
56 xobject = out_pdf.makeIndirectObject( page_to_xobject(&out_pdf, out_pdf.copyForeignObject(pdf_page)) );
57 string xobj_res = out->new_resource("XO");
58 out->xobjects.replaceKey(xobj_res, xobject);
61 m.shift(-media_box.x_min, -media_box.y_min);
64 out->contents += "q " + m.to_string() + " cm " + xobj_res + " Do Q ";
67 static void debug_pages(vector<page *> &pages)
73 debug("Page #%d: w=%.3f h=%.3f", pg->index, pg->width, pg->height);
76 vector<page *> run_command_list(list<cmd *> &cmds, vector<page *> &pages)
83 debug("# Executing %s", c->def->name);
85 pages = c->exec->process(pages);
93 static void process(list<cmd *> &cmds, const char *in_name, const char *out_name)
95 in_pdf.processFile(in_name);
96 in_pdf.pushInheritedAttributesToPage();
99 vector<QPDFObjectHandle> const &in_pages = in_pdf.getAllPages();
100 vector<page *> pages;
102 QPDFObjectHandle page_copy = out_pdf.copyForeignObject(in_pages[0]);
105 for (auto inpg: in_pages)
106 pages.push_back(new in_page(inpg, ++cnt));
108 pages = run_command_list(cmds, pages);
113 out.resources = QPDFObjectHandle::newDictionary();
114 out.resources.replaceKey("/ProcSet", QPDFObjectHandle::parse("[/PDF]"));
115 out.xobjects = QPDFObjectHandle::newDictionary();
116 out.resources.replaceKey("/XObject", out.xobjects);
117 pg->render(&out, pdf_matrix());
119 QPDFObjectHandle contents = QPDFObjectHandle::newStream(&out_pdf, out.contents);
121 // Create the page object
122 QPDFObjectHandle out_page = out_pdf.makeIndirectObject(QPDFObjectHandle::newDictionary());
123 out_page.replaceKey("/Type", QPDFObjectHandle::newName("/Page"));
124 out_page.replaceKey("/MediaBox", BBox(pg->width, pg->height).to_array());
125 out_page.replaceKey("/CropBox", pg->bbox.to_array());
126 out_page.replaceKey("/Contents", contents);
127 out_page.replaceKey("/Resources", out.resources);
128 out_pdf.addPage(out_page, false);
131 // Produce info dictionary
132 QPDFObjectHandle trailer = out_pdf.getTrailer();
133 QPDFObjectHandle info = trailer.getKey("/Info");
136 info = QPDFObjectHandle::newDictionary();
137 trailer.replaceKey("/Info", info);
140 assert(info.isDictionary());
141 // FIXME: More meta-data
142 info.replaceKey("/Producer", unicode_string("PaperJam"));
144 // Write the output file
145 QPDFWriter writer(out_pdf, out_name);
149 int main(int argc, char **argv)
151 if (argc <= 1 || argc > 1 && !strcmp(argv[1], "--help"))
159 fprintf(stderr, "Usage: paperjam <commands> <input> <output>\n");
166 parse(argv[1], cmds);
170 process(cmds, argv[2], argv[3]);