]> mj.ucw.cz Git - paperjam.git/blob - paperjam.cc
bebfb922a44965351e7c00e8f474d9ac634d5129
[paperjam.git] / paperjam.cc
1 #include <cassert>
2 #include <cstdarg>
3 #include <cstdlib>
4 #include <cstdio>
5
6 #include "jam.h"
7
8 #include <qpdf/QPDFWriter.hh>
9
10 static QPDF in_pdf;
11 static QPDF out_pdf;
12
13 string page_out::new_resource(const string type)
14 {
15   return "/" + type + to_string(++res_cnt);
16 }
17
18 class in_page : public page {
19   QPDFObjectHandle pdf_page;
20 public:
21   BBox media_box;
22   void render(page_out *out, pdf_matrix xform);
23   in_page(QPDFObjectHandle inpg, int idx);
24 };
25
26 in_page::in_page(QPDFObjectHandle inpg, int idx)
27 {
28   pdf_page = inpg;
29   index = idx;
30   media_box = BBox(inpg.getKey("/MediaBox"));
31   width = media_box.width();
32   height = media_box.height();
33 }
34
35 void in_page::render(page_out *out, pdf_matrix xform)
36 {
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));
41
42   pdf_matrix m;
43   m.shift(-media_box.x_min, -media_box.y_min);
44   m.concat(xform);
45
46   out->contents += "q " + m.to_string() + " cm " + xobj_res + " Do Q";
47 }
48
49 static void debug_pages(vector<page *> &pages)
50 {
51   if (!debug_mode)
52     return;
53
54   for (auto pg: pages)
55     debug("Page #%d: w=%.3f h=%.3f", pg->index, pg->width, pg->height);
56 }
57
58 static void process(list<cmd *> &cmds, const char *in_name, const char *out_name)
59 {
60   in_pdf.processFile(in_name);
61   in_pdf.pushInheritedAttributesToPage();
62   out_pdf.emptyPDF();
63
64   vector<QPDFObjectHandle> const &in_pages = in_pdf.getAllPages();
65   vector<page *> pages;
66
67   QPDFObjectHandle page_copy = out_pdf.copyForeignObject(in_pages[0]);
68
69   int cnt = 0;
70   for (auto inpg: in_pages)
71     pages.push_back(new in_page(inpg, ++cnt));
72   debug("# Input document");
73   debug_pages(pages);
74
75   for (auto c: cmds)
76     {
77       debug("# Executing %s", c->def->name);
78       pages = c->exec->process(pages);
79       debug_pages(pages);
80     }
81
82   for (auto pg: pages)
83     {
84       page_out out;
85       out.resources = QPDFObjectHandle::newDictionary();
86       // FIXME: What if the source page requires a broader ProcSet?
87       out.resources.replaceKey("/ProcSet", QPDFObjectHandle::parse("[/PDF /Text]"));
88       out.xobjects = QPDFObjectHandle::newDictionary();
89       out.resources.replaceKey("/XObject", out.xobjects);
90       pg->render(&out, pdf_matrix());
91
92       QPDFObjectHandle contents = QPDFObjectHandle::newStream(&out_pdf, out.contents);
93
94       // Create the page object
95       QPDFObjectHandle out_page = out_pdf.makeIndirectObject(QPDFObjectHandle::newDictionary());
96       out_page.replaceKey("/Type", QPDFObjectHandle::newName("/Page"));
97       out_page.replaceKey("/MediaBox", BBox(pg->width, pg->height).to_array());
98       out_page.replaceKey("/Contents", contents);
99       out_page.replaceKey("/Resources", out.resources);
100       out_pdf.addPage(out_page, false);
101     }
102
103   // Produce info dictionary
104   QPDFObjectHandle trailer = out_pdf.getTrailer();
105   QPDFObjectHandle info = trailer.getKey("/Info");
106   if (info.isNull())
107     {
108       info = QPDFObjectHandle::newDictionary();
109       trailer.replaceKey("/Info", info);
110     }
111   else
112     assert(info.isDictionary());
113   // FIXME: More meta-data
114   info.replaceKey("/Producer", unicode_string("PaperJam"));
115
116   // Write the output file
117   QPDFWriter writer(out_pdf, out_name);
118   writer.write();
119 }
120
121 int main(int argc, char **argv)
122 {
123   if (argc != 4)
124     {
125       fprintf(stderr, "Usage: pdfjam <commands> <input> <output>\n");
126       return 1;
127     }
128
129   debug_mode = 100;
130
131   list<cmd *> cmds;
132   parse(argv[1], cmds);
133
134   try
135     {
136       process(cmds, argv[2], argv[3]);
137     }
138   catch (exception& e)
139     {
140       die("%s", e.what());
141     }
142
143   return 0;
144 }