Implement imposing headers/footers onto their target pages

This commit is contained in:
Kovid Goyal 2019-07-28 12:13:45 +05:30
parent 848d91c6d8
commit 227679985f
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
7 changed files with 63 additions and 12 deletions

View File

@ -116,7 +116,7 @@
}, },
{ {
"name": "podofo", "name": "podofo",
"sources": "calibre/utils/podofo/utils.cpp calibre/utils/podofo/output.cpp calibre/utils/podofo/doc.cpp calibre/utils/podofo/outline.cpp calibre/utils/podofo/fonts.cpp calibre/utils/podofo/podofo.cpp", "sources": "calibre/utils/podofo/utils.cpp calibre/utils/podofo/output.cpp calibre/utils/podofo/doc.cpp calibre/utils/podofo/outline.cpp calibre/utils/podofo/fonts.cpp calibre/utils/podofo/impose.cpp calibre/utils/podofo/podofo.cpp",
"headers": "calibre/utils/podofo/global.h", "headers": "calibre/utils/podofo/global.h",
"libraries": "podofo", "libraries": "podofo",
"lib_dirs": "!podofo_lib", "lib_dirs": "!podofo_lib",

View File

@ -860,7 +860,7 @@ def add_header_footer(manager, opts, pdf_doc, container, page_number_display_map
root = container.parsed(name) root = container.parsed(name)
body = root[-1] body = root[-1]
body.attrib.pop('id', None) body.attrib.pop('id', None)
body.set('style', 'margin: 0; padding: 0; border-width: 0') body.set('style', 'margin: 0; padding: 0; border-width: 0; background-color: unset')
job = job_for_name(container, name, Margins(0, 0, 0, 0), page_layout) job = job_for_name(container, name, Margins(0, 0, 0, 0), page_layout)
def m(tag_name, text=None, style=None, **attrs): def m(tag_name, text=None, style=None, **attrs):
@ -928,6 +928,7 @@ def add_header_footer(manager, opts, pdf_doc, container, page_number_display_map
'padding': '0', 'padding': '0',
'border-width': '0', 'border-width': '0',
'overflow': 'hidden', 'overflow': 'hidden',
'background-color': 'unset',
} }
ans = m('div', style=style, id='p{}'.format(page_num)) ans = m('div', style=style, id='p{}'.format(page_num))
@ -944,7 +945,7 @@ def add_header_footer(manager, opts, pdf_doc, container, page_number_display_map
style = ans.get('style') or '' style = ans.get('style') or ''
style = ( style = (
'margin: 0; padding: 0; height: {height}pt; border-width: 0;' 'margin: 0; padding: 0; height: {height}pt; border-width: 0;'
'display: flex; align-items: center; overflow: hidden').format(height=height) + style 'display: flex; align-items: center; overflow: hidden; background-color: unset').format(height=height) + style
ans.set('style', style) ans.set('style', style)
for child in ans.xpath('descendant-or-self::*[@class]'): for child in ans.xpath('descendant-or-self::*[@class]'):
cls = frozenset(child.get('class').split()) cls = frozenset(child.get('class').split())
@ -970,7 +971,13 @@ def add_header_footer(manager, opts, pdf_doc, container, page_number_display_map
if not isinstance(data, bytes): if not isinstance(data, bytes):
raise SystemExit(data) raise SystemExit(data)
doc = data_as_pdf_doc(data) doc = data_as_pdf_doc(data)
first_page_num = pdf_doc.page_count()
num_pages = doc.page_count()
if first_page_num != num_pages:
raise ValueError('The number of header/footers pages ({}) != number of document pages ({})'.format(
num_pages, first_page_num))
pdf_doc.append(doc) pdf_doc.append(doc)
pdf_doc.impose(1, first_page_num + 1, num_pages)
report_progress(0.9, _('Headers and footers added')) report_progress(0.9, _('Headers and footers added'))
# }}} # }}}

View File

@ -756,6 +756,9 @@ static PyMethodDef PDFDoc_methods[] = {
{"dedup_type3_fonts", (PyCFunction)py_dedup_type3_fonts, METH_VARARGS, {"dedup_type3_fonts", (PyCFunction)py_dedup_type3_fonts, METH_VARARGS,
"dedup_type3_fonts() -> De-duplicate repeated glyphs in Type3 fonts" "dedup_type3_fonts() -> De-duplicate repeated glyphs in Type3 fonts"
}, },
{"impose", (PyCFunction)py_impose, METH_VARARGS,
"impose() -> impose pages onto each other"
},
{"delete_pages", (PyCFunction)PDFDoc_delete_pages, METH_VARARGS, {"delete_pages", (PyCFunction)PDFDoc_delete_pages, METH_VARARGS,
"delete_page(page_num, count=1) -> Delete the specified pages from the pdf." "delete_page(page_num, count=1) -> Delete the specified pages from the pdf."
}, },

View File

@ -11,14 +11,6 @@
using namespace pdf; using namespace pdf;
#define PYWRAP(name) extern "C" PyObject* py_##name(PDFDoc *self, PyObject *args) { \
try { \
return name(self, args); \
} catch (const PdfError &err) { podofo_set_exception(err); return NULL; \
} catch (const std::exception &err) { PyErr_Format(Error, "Error in %s(): %s", #name, err.what()); return NULL; \
} catch (...) { PyErr_SetString(Error, "An unknown error occurred in " #name); return NULL; } \
}
static inline PyObject* static inline PyObject*
ref_as_tuple(const PdfReference &ref) { ref_as_tuple(const PdfReference &ref) {
unsigned long num = ref.ObjectNumber(), generation = ref.GenerationNumber(); unsigned long num = ref.ObjectNumber(), generation = ref.GenerationNumber();

View File

@ -100,5 +100,14 @@ PyObject* py_list_fonts(PDFDoc*, PyObject*);
PyObject* py_remove_unused_fonts(PDFDoc *self, PyObject *args); PyObject* py_remove_unused_fonts(PDFDoc *self, PyObject *args);
PyObject* py_merge_fonts(PDFDoc *self, PyObject *args); PyObject* py_merge_fonts(PDFDoc *self, PyObject *args);
PyObject* py_dedup_type3_fonts(PDFDoc *self, PyObject *args); PyObject* py_dedup_type3_fonts(PDFDoc *self, PyObject *args);
PyObject* py_impose(PDFDoc *self, PyObject *args);
} }
} }
#define PYWRAP(name) extern "C" PyObject* py_##name(PDFDoc *self, PyObject *args) { \
try { \
return name(self, args); \
} catch (const PdfError &err) { podofo_set_exception(err); return NULL; \
} catch (const std::exception &err) { PyErr_Format(Error, "Error in %s(): %s", #name, err.what()); return NULL; \
} catch (...) { PyErr_SetString(Error, "An unknown error occurred in " #name); return NULL; } \
}

View File

@ -0,0 +1,40 @@
/*
* impose.cpp
* Copyright (C) 2019 Kovid Goyal <kovid at kovidgoyal.net>
*
* Distributed under terms of the GPL3 license.
*/
#include "global.h"
using namespace pdf;
static void
impose_page(PdfMemDocument *doc, unsigned long dest_page_num, unsigned long src_page_num) {
PdfXObject *xobj = new PdfXObject(doc, src_page_num, "HeaderFooter");
PdfPage *dest = doc->GetPage(dest_page_num);
dest->AddResource(xobj->GetIdentifier(), xobj->GetObject()->Reference(), "XObject");
PdfStream *stream = dest->GetContents()->GetStream();
char *buffer = NULL; pdf_long sz;
stream->GetFilteredCopy(&buffer, &sz);
stream->BeginAppend();
stream->Append("q\n1 0 0 1 0 0 cm\n/");
stream->Append(xobj->GetIdentifier().GetName());
stream->Append(" Do\nQ\n");
stream->Append(buffer, sz);
stream->EndAppend();
podofo_free(buffer);
}
static PyObject*
impose(PDFDoc *self, PyObject *args) {
unsigned long dest_page_num, src_page_num, count;
if (!PyArg_ParseTuple(args, "kkk", &dest_page_num, &src_page_num, &count)) return NULL;
for (unsigned long i = 0; i < count; i++) {
impose_page(self->doc, dest_page_num - 1 + i, src_page_num - 1 + i);
}
self->doc->DeletePages(src_page_num - 1, count);
Py_RETURN_NONE;
}
PYWRAP(impose)

View File

@ -18,7 +18,7 @@ pdf::podofo_set_exception(const PdfError &err) {
const TDequeErrorInfo &s = err.GetCallstack(); const TDequeErrorInfo &s = err.GetCallstack();
for (TDequeErrorInfo::const_iterator it = s.begin(); it != s.end(); it++) { for (TDequeErrorInfo::const_iterator it = s.begin(); it != s.end(); it++) {
const PdfErrorInfo &info = (*it); const PdfErrorInfo &info = (*it);
stream << "File: " << info.GetFilename() << "Line: " << info.GetLine() << " " << info.GetInformation() << "\n"; stream << "File: " << info.GetFilename() << " Line: " << info.GetLine() << " " << info.GetInformation() << "\n";
} }
PyErr_SetString(Error, stream.str().c_str()); PyErr_SetString(Error, stream.str().c_str());
} }