mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
PDF Output: Add support for document margins
This commit is contained in:
parent
19fc96cb31
commit
5067454aa4
@ -216,12 +216,12 @@ class PDFOutput(OutputFormatPlugin):
|
|||||||
self.oeb.container.write(path, nraw)
|
self.oeb.container.write(path, nraw)
|
||||||
|
|
||||||
def convert_text(self, oeb_book):
|
def convert_text(self, oeb_book):
|
||||||
|
import json
|
||||||
from calibre.ebooks.pdf.html_writer import convert
|
from calibre.ebooks.pdf.html_writer import convert
|
||||||
self.get_cover_data()
|
self.get_cover_data()
|
||||||
self.process_fonts()
|
self.process_fonts()
|
||||||
|
|
||||||
if self.opts.pdf_use_document_margins and self.stored_page_margins:
|
if self.opts.pdf_use_document_margins and self.stored_page_margins:
|
||||||
import json
|
|
||||||
for href, margins in iteritems(self.stored_page_margins):
|
for href, margins in iteritems(self.stored_page_margins):
|
||||||
item = oeb_book.manifest.hrefs.get(href)
|
item = oeb_book.manifest.hrefs.get(href)
|
||||||
if item is not None:
|
if item is not None:
|
||||||
|
@ -4,10 +4,12 @@
|
|||||||
|
|
||||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||||
|
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
|
import signal
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
from PyQt5.Qt import QApplication, QTimer, QUrl
|
from PyQt5.Qt import QApplication, QMarginsF, QPageLayout, QTimer, QUrl
|
||||||
from PyQt5.QtWebEngineWidgets import QWebEnginePage
|
from PyQt5.QtWebEngineWidgets import QWebEnginePage
|
||||||
|
|
||||||
from calibre.constants import iswindows
|
from calibre.constants import iswindows
|
||||||
@ -64,7 +66,15 @@ class Renderer(QWebEnginePage):
|
|||||||
|
|
||||||
self.loadFinished.connect(self.load_finished)
|
self.loadFinished.connect(self.load_finished)
|
||||||
if not iswindows:
|
if not iswindows:
|
||||||
setup_unix_signals(self)
|
self.original_signal_handlers = setup_unix_signals(self)
|
||||||
|
|
||||||
|
def block_signal_handlers(self):
|
||||||
|
for sig in self.original_signal_handlers:
|
||||||
|
signal.signal(sig, lambda x, y: None)
|
||||||
|
|
||||||
|
def restore_signal_handlers(self):
|
||||||
|
for sig, handler in self.original_signal_handlers.items():
|
||||||
|
signal.signal(sig, handler)
|
||||||
|
|
||||||
def load_finished(self, ok):
|
def load_finished(self, ok):
|
||||||
if not ok:
|
if not ok:
|
||||||
@ -86,12 +96,19 @@ class Renderer(QWebEnginePage):
|
|||||||
self.pdf_data = pdf_data
|
self.pdf_data = pdf_data
|
||||||
QApplication.instance().exit(OK)
|
QApplication.instance().exit(OK)
|
||||||
|
|
||||||
|
def run_loop(self):
|
||||||
|
self.block_signal_handlers()
|
||||||
|
try:
|
||||||
|
return QApplication.exec_()
|
||||||
|
finally:
|
||||||
|
self.restore_signal_handlers()
|
||||||
|
|
||||||
def convert_html_file(self, path, page_layout, settle_time=0):
|
def convert_html_file(self, path, page_layout, settle_time=0):
|
||||||
self.settle_time = settle_time
|
self.settle_time = settle_time
|
||||||
self.page_layout = page_layout
|
self.page_layout = page_layout
|
||||||
self.pdf_data = None
|
self.pdf_data = None
|
||||||
self.setUrl(QUrl.fromLocalFile(path))
|
self.setUrl(QUrl.fromLocalFile(path))
|
||||||
ret = QApplication.exec_()
|
ret = self.run_loop()
|
||||||
if ret == LOAD_FAILED:
|
if ret == LOAD_FAILED:
|
||||||
raise SystemExit('Failed to load {}'.format(path))
|
raise SystemExit('Failed to load {}'.format(path))
|
||||||
if ret == KILL_SIGNAL:
|
if ret == KILL_SIGNAL:
|
||||||
@ -124,22 +141,66 @@ def add_cover(pdf_doc, cover_data, page_layout, opts):
|
|||||||
pdf_doc.insert_existing_page(cover_pdf_doc)
|
pdf_doc.insert_existing_page(cover_pdf_doc)
|
||||||
|
|
||||||
|
|
||||||
def convert(opf_path, opts, metadata=None, output_path=None, log=default_log, cover_data=None):
|
def create_margin_groups(container):
|
||||||
container = Container(opf_path, log)
|
|
||||||
spine_names = [name for name, is_linear in container.spine_names]
|
|
||||||
master = spine_names[0]
|
|
||||||
if len(spine_names) > 1:
|
|
||||||
merge_html(container, spine_names, master, insert_page_breaks=True)
|
|
||||||
|
|
||||||
container.commit()
|
def merge_group(group):
|
||||||
index_file = container.name_to_abspath(master)
|
if len(group) > 1:
|
||||||
|
group_margins = group[0][1]
|
||||||
|
names = [name for (name, margins) in group]
|
||||||
|
merge_html(container, names, names[0], insert_page_breaks=True)
|
||||||
|
group = [(names[0], group_margins)]
|
||||||
|
return group
|
||||||
|
|
||||||
renderer = Renderer(opts)
|
groups = []
|
||||||
page_layout = get_page_layout(opts)
|
current_group = []
|
||||||
|
for name, is_linear in container.spine_names:
|
||||||
|
root = container.parsed(name)
|
||||||
|
margins = root.get('data-calibre-pdf-output-page-margins')
|
||||||
|
if margins:
|
||||||
|
margins = json.loads(margins)
|
||||||
|
if current_group:
|
||||||
|
prev_margins = current_group[-1][1]
|
||||||
|
if prev_margins != margins:
|
||||||
|
groups.append(merge_group(current_group))
|
||||||
|
current_group = []
|
||||||
|
current_group.append((name, margins))
|
||||||
|
if current_group:
|
||||||
|
groups.append(merge_group(current_group))
|
||||||
|
return groups
|
||||||
|
|
||||||
|
|
||||||
|
def render_name(container, name, margins, renderer, page_layout):
|
||||||
|
index_file = container.name_to_abspath(name)
|
||||||
|
if margins:
|
||||||
|
page_layout = QPageLayout(page_layout)
|
||||||
|
page_layout.setUnits(QPageLayout.Point)
|
||||||
|
old_margins = page_layout.marginsPoints()
|
||||||
|
new_margins = QMarginsF(
|
||||||
|
margins.get('left', old_margins.left()),
|
||||||
|
margins.get('top', old_margins.top()),
|
||||||
|
margins.get('right', old_margins.right()),
|
||||||
|
margins.get('bottom', old_margins.bottom()))
|
||||||
|
page_layout.setMargins(new_margins)
|
||||||
pdf_data = renderer.convert_html_file(index_file, page_layout, settle_time=1)
|
pdf_data = renderer.convert_html_file(index_file, page_layout, settle_time=1)
|
||||||
podofo = get_podofo()
|
podofo = get_podofo()
|
||||||
pdf_doc = podofo.PDFDoc()
|
pdf_doc = podofo.PDFDoc()
|
||||||
pdf_doc.load(pdf_data)
|
pdf_doc.load(pdf_data)
|
||||||
|
return pdf_doc
|
||||||
|
|
||||||
|
|
||||||
|
def convert(opf_path, opts, metadata=None, output_path=None, log=default_log, cover_data=None):
|
||||||
|
container = Container(opf_path, log)
|
||||||
|
margin_groups = create_margin_groups(container)
|
||||||
|
container.commit()
|
||||||
|
renderer = Renderer(opts)
|
||||||
|
page_layout = get_page_layout(opts)
|
||||||
|
pdf_doc = None
|
||||||
|
for group in margin_groups:
|
||||||
|
doc = render_name(container, group[0][0], group[0][1], renderer, page_layout)
|
||||||
|
if pdf_doc is None:
|
||||||
|
pdf_doc = doc
|
||||||
|
else:
|
||||||
|
pdf_doc.append(doc)
|
||||||
|
|
||||||
if cover_data:
|
if cover_data:
|
||||||
add_cover(pdf_doc, cover_data, page_layout, opts)
|
add_cover(pdf_doc, cover_data, page_layout, opts)
|
||||||
|
@ -824,13 +824,15 @@ def setup_unix_signals(self):
|
|||||||
flags = fcntl.fcntl(fd, fcntl.F_GETFD)
|
flags = fcntl.fcntl(fd, fcntl.F_GETFD)
|
||||||
fcntl.fcntl(fd, fcntl.F_SETFD, flags | cloexec_flag | os.O_NONBLOCK)
|
fcntl.fcntl(fd, fcntl.F_SETFD, flags | cloexec_flag | os.O_NONBLOCK)
|
||||||
|
|
||||||
|
original_handlers = {}
|
||||||
for sig in (signal.SIGINT, signal.SIGTERM):
|
for sig in (signal.SIGINT, signal.SIGTERM):
|
||||||
signal.signal(sig, lambda x, y: None)
|
original_handlers[sig] = signal.signal(sig, lambda x, y: None)
|
||||||
signal.siginterrupt(sig, False)
|
signal.siginterrupt(sig, False)
|
||||||
signal.set_wakeup_fd(write_fd)
|
signal.set_wakeup_fd(write_fd)
|
||||||
self.signal_notifier = QSocketNotifier(read_fd, QSocketNotifier.Read, self)
|
self.signal_notifier = QSocketNotifier(read_fd, QSocketNotifier.Read, self)
|
||||||
self.signal_notifier.setEnabled(True)
|
self.signal_notifier.setEnabled(True)
|
||||||
self.signal_notifier.activated.connect(self.signal_received, type=Qt.QueuedConnection)
|
self.signal_notifier.activated.connect(self.signal_received, type=Qt.QueuedConnection)
|
||||||
|
return original_handlers
|
||||||
|
|
||||||
|
|
||||||
class Application(QApplication):
|
class Application(QApplication):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user