diff --git a/setup/extensions.json b/setup/extensions.json index 56bfadf50b..b64e8b12ae 100644 --- a/setup/extensions.json +++ b/setup/extensions.json @@ -116,7 +116,7 @@ }, { "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", "libraries": "podofo", "lib_dirs": "!podofo_lib", diff --git a/src/calibre/ebooks/pdf/html_writer.py b/src/calibre/ebooks/pdf/html_writer.py index b8143b1e12..19f2b0ffa1 100644 --- a/src/calibre/ebooks/pdf/html_writer.py +++ b/src/calibre/ebooks/pdf/html_writer.py @@ -860,7 +860,7 @@ def add_header_footer(manager, opts, pdf_doc, container, page_number_display_map root = container.parsed(name) body = root[-1] 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) 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', 'border-width': '0', 'overflow': 'hidden', + 'background-color': 'unset', } 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 = ( '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) for child in ans.xpath('descendant-or-self::*[@class]'): 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): raise SystemExit(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.impose(1, first_page_num + 1, num_pages) report_progress(0.9, _('Headers and footers added')) # }}} diff --git a/src/calibre/utils/podofo/doc.cpp b/src/calibre/utils/podofo/doc.cpp index 7de327ebfe..075ba80729 100644 --- a/src/calibre/utils/podofo/doc.cpp +++ b/src/calibre/utils/podofo/doc.cpp @@ -756,6 +756,9 @@ static PyMethodDef PDFDoc_methods[] = { {"dedup_type3_fonts", (PyCFunction)py_dedup_type3_fonts, METH_VARARGS, "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_page(page_num, count=1) -> Delete the specified pages from the pdf." }, diff --git a/src/calibre/utils/podofo/fonts.cpp b/src/calibre/utils/podofo/fonts.cpp index 8fc135e5e5..4d710d789a 100644 --- a/src/calibre/utils/podofo/fonts.cpp +++ b/src/calibre/utils/podofo/fonts.cpp @@ -11,14 +11,6 @@ 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* ref_as_tuple(const PdfReference &ref) { unsigned long num = ref.ObjectNumber(), generation = ref.GenerationNumber(); diff --git a/src/calibre/utils/podofo/global.h b/src/calibre/utils/podofo/global.h index c8eae1dbb5..b32fbd95e5 100644 --- a/src/calibre/utils/podofo/global.h +++ b/src/calibre/utils/podofo/global.h @@ -100,5 +100,14 @@ PyObject* py_list_fonts(PDFDoc*, PyObject*); PyObject* py_remove_unused_fonts(PDFDoc *self, PyObject *args); PyObject* py_merge_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; } \ +} diff --git a/src/calibre/utils/podofo/impose.cpp b/src/calibre/utils/podofo/impose.cpp new file mode 100644 index 0000000000..2eea6d525c --- /dev/null +++ b/src/calibre/utils/podofo/impose.cpp @@ -0,0 +1,40 @@ +/* + * impose.cpp + * Copyright (C) 2019 Kovid Goyal + * + * 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) diff --git a/src/calibre/utils/podofo/utils.cpp b/src/calibre/utils/podofo/utils.cpp index ff83bef39c..dee0aeb981 100644 --- a/src/calibre/utils/podofo/utils.cpp +++ b/src/calibre/utils/podofo/utils.cpp @@ -18,7 +18,7 @@ pdf::podofo_set_exception(const PdfError &err) { const TDequeErrorInfo &s = err.GetCallstack(); for (TDequeErrorInfo::const_iterator it = s.begin(); it != s.end(); 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()); }