#include <cassert>
#include <cstdlib>
#include <cstdio>
+#include <cstring>
#include <unistd.h>
#include <sys/wait.h>
public:
BBox media_box;
void render(out_context *out, pdf_matrix xform);
+ void debug_dump() { debug("Input page %d", index); }
in_page(QPDFObjectHandle inpg, int idx);
};
if (art_box.isNull())
art_box = inpg.getKey("/CropBox");
if (art_box.isNull())
- bbox = BBox(width, height);
+ image_box = BBox(width, height);
else
{
- bbox = BBox(art_box);
- bbox.x_min -= media_box.x_min;
- bbox.x_max -= media_box.x_min;
- bbox.y_min -= media_box.y_min;
- bbox.y_max -= media_box.y_min;
+ image_box = BBox(art_box);
+ image_box.x_min -= media_box.x_min;
+ image_box.x_max -= media_box.x_min;
+ image_box.y_min -= media_box.y_min;
+ image_box.y_max -= media_box.y_min;
}
}
{
// Convert page to xobject
if (xobject.isNull())
- xobject = out_pdf.makeIndirectObject( page_to_xobject(&out_pdf, out_pdf.copyForeignObject(pdf_page)) );
+ xobject = out->pdf->makeIndirectObject( page_to_xobject(out->pdf, out->pdf->copyForeignObject(pdf_page)) );
string xobj_res = out->new_resource("XO");
out->xobjects.replaceKey(xobj_res, xobject);
void debug_pages(vector<page *> &pages)
{
- if (!debug_mode)
+ if (!debug_level)
return;
for (auto pg: pages)
- 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);
+ {
+ debug("Page #%d: media[%.3f %.3f] image[%.3f %.3f %.3f %.3f][%.3f %.3f]",
+ pg->index,
+ pg->width, pg->height,
+ pg->image_box.x_min, pg->image_box.y_min, pg->image_box.x_max, pg->image_box.y_max,
+ pg->image_box.width(), pg->image_box.height());
+ if (debug_level > 2)
+ {
+ debug_indent += 4;
+ pg->debug_dump();
+ debug_indent -= 4;
+ }
+ }
}
vector<page *> run_command_list(list<cmd *> &cmds, vector<page *> &pages)
{
debug("# Executing %s", c->def->name);
debug_indent += 4;
- pages = c->exec->process(pages);
+ try
+ {
+ pages = c->exec->process(pages);
+ }
+ catch (exception &e)
+ {
+ die("Error in %s: %s", c->def->name, e.what());
+ }
debug_indent -= 4;
debug_pages(pages);
}
return pages;
}
+static void make_info_dict()
+{
+ // Create info dictionary if it did not exist yet
+ QPDFObjectHandle trailer = out_pdf.getTrailer();
+ QPDFObjectHandle info = trailer.getKey("/Info");
+ if (info.isNull())
+ {
+ info = QPDFObjectHandle::newDictionary();
+ trailer.replaceKey("/Info", info);
+ }
+ else
+ assert(info.isDictionary());
+
+ info.replaceKey("/Producer", unicode_string("PaperJam"));
+
+ // Copy entries from the source file's info dictionary
+ QPDFObjectHandle orig_trailer = in_pdf.getTrailer();
+ QPDFObjectHandle orig_info = orig_trailer.getKey("/Info");
+ if (!orig_info.isNull())
+ {
+ const string to_copy[] = { "/Title", "/Author", "/Subject", "/Keywords", "/Creator", "/CreationDate" };
+ for (string key: to_copy)
+ info.replaceOrRemoveKey(key, orig_info.getKey(key));
+ }
+}
+
void process(list<cmd *> &cmds)
{
+ debug("### Reading input");
in_pdf.processFile(in_name);
in_pdf.pushInheritedAttributesToPage();
out_pdf.emptyPDF();
if (recalc_bbox)
do_recalc_bbox(pages, in_name);
+ debug("### Running commands");
pages = run_command_list(cmds, pages);
+ debug("### Writing output");
+ int out_page = 0;
for (auto pg: pages)
{
+ ++out_page;
+ if (debug_level > 1)
+ {
+ debug("Page #%d", out_page);
+ debug_indent += 4;
+ pg->debug_dump();
+ debug_indent -= 4;
+ }
+
out_context out;
+ out.pdf = &out_pdf;
out.resources = QPDFObjectHandle::newDictionary();
out.resources.replaceKey("/ProcSet", QPDFObjectHandle::parse("[/PDF]"));
out.xobjects = QPDFObjectHandle::newDictionary();
- out.resources.replaceKey("/XObject", out.xobjects);
+ out.egstates = QPDFObjectHandle::newDictionary();
pg->render(&out, pdf_matrix());
QPDFObjectHandle contents = QPDFObjectHandle::newStream(&out_pdf, out.contents);
out_page.replaceKey("/Type", QPDFObjectHandle::newName("/Page"));
out_page.replaceKey("/MediaBox", BBox(pg->width, pg->height).to_array());
// FIXME:
- // out_page.replaceKey("/CropBox", pg->bbox.to_array());
+ // out_page.replaceKey("/CropBox", pg->image_box.to_array());
out_page.replaceKey("/Contents", contents);
+ if (!out.xobjects.getKeys().empty())
+ out.resources.replaceKey("/XObject", out.xobjects);
+ if (!out.egstates.getKeys().empty())
+ out.resources.replaceKey("/ExtGState", out.egstates);
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"));
+ make_info_dict();
// Write the output file
QPDFWriter writer(out_pdf, out_name);
writer.write();
+ debug("### Done");
}
/*** Re-calculation of bboxes ***/
static void do_recalc_bbox(vector<page *> &pages, const char *in_name)
{
+ debug("Calling Ghostscript to re-calculate bounding boxes");
vector<BBox> 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; i<pages.size(); i++)
- pages[i]->bbox = bboxes[i];
+ pages[i]->image_box = bboxes[i];
}