mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-07 18:24:30 -04:00
Basic PDF output works
This commit is contained in:
parent
4abfcc46ab
commit
b25766f6aa
@ -261,4 +261,4 @@ class PDFOutput(OutputFormatPlugin):
|
|||||||
oeb_output = plugin_for_output_format('oeb')
|
oeb_output = plugin_for_output_format('oeb')
|
||||||
oeb_output.convert(oeb_book, oeb_dir, self.input_plugin, self.opts, self.log)
|
oeb_output.convert(oeb_book, oeb_dir, self.input_plugin, self.opts, self.log)
|
||||||
opfpath = glob.glob(os.path.join(oeb_dir, '*.opf'))[0]
|
opfpath = glob.glob(os.path.join(oeb_dir, '*.opf'))[0]
|
||||||
convert(opfpath, self.log, self.opts)
|
convert(opfpath, self.opts, self.output_path, self.log)
|
||||||
|
@ -357,7 +357,7 @@ def remove_name_attributes(root):
|
|||||||
elem.set('id', elem.attrib.pop('name'))
|
elem.set('id', elem.attrib.pop('name'))
|
||||||
|
|
||||||
|
|
||||||
def merge_html(container, names, master):
|
def merge_html(container, names, master, insert_page_breaks=False):
|
||||||
p = container.parsed
|
p = container.parsed
|
||||||
root = p(master)
|
root = p(master)
|
||||||
|
|
||||||
@ -428,6 +428,9 @@ def merge_html(container, names, master):
|
|||||||
if q in amap:
|
if q in amap:
|
||||||
a.set('href', '#' + amap[q])
|
a.set('href', '#' + amap[q])
|
||||||
|
|
||||||
|
if insert_page_breaks:
|
||||||
|
master_body.append(master_body.makeelement(XHTML('div'), style='page-break-after:always'))
|
||||||
|
|
||||||
for child in children:
|
for child in children:
|
||||||
if isinstance(child, string_or_bytes):
|
if isinstance(child, string_or_bytes):
|
||||||
add_text(master_body, child)
|
add_text(master_body, child)
|
||||||
|
@ -6,11 +6,20 @@ from __future__ import absolute_import, division, print_function, unicode_litera
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
from PyQt5.Qt import QApplication, QUrl, QTimer
|
||||||
from PyQt5.QtWebEngineWidgets import QWebEnginePage
|
from PyQt5.QtWebEngineWidgets import QWebEnginePage
|
||||||
|
|
||||||
|
from calibre.constants import iswindows
|
||||||
from calibre.ebooks.oeb.polish.container import Container as ContainerBase
|
from calibre.ebooks.oeb.polish.container import Container as ContainerBase
|
||||||
from calibre.ebooks.oeb.polish.split import merge_html
|
from calibre.ebooks.oeb.polish.split import merge_html
|
||||||
|
from calibre.gui2 import setup_unix_signals
|
||||||
from calibre.gui2.webengine import secure_webengine
|
from calibre.gui2.webengine import secure_webengine
|
||||||
|
from calibre.ebooks.pdf.image_writer import get_page_layout
|
||||||
|
from calibre.utils.logging import default_log
|
||||||
|
|
||||||
|
from polyglot.builtins import range
|
||||||
|
|
||||||
|
OK, LOAD_FAILED, KILL_SIGNAL = range(0, 3)
|
||||||
|
|
||||||
|
|
||||||
class Container(ContainerBase):
|
class Container(ContainerBase):
|
||||||
@ -27,15 +36,18 @@ class Renderer(QWebEnginePage):
|
|||||||
def __init__(self, opts):
|
def __init__(self, opts):
|
||||||
QWebEnginePage.__init__(self)
|
QWebEnginePage.__init__(self)
|
||||||
secure_webengine(self)
|
secure_webengine(self)
|
||||||
|
self.settle_time = 0
|
||||||
s = self.settings()
|
s = self.settings()
|
||||||
s.setAttribute(s.JavascriptEnabled, True)
|
s.setAttribute(s.JavascriptEnabled, True)
|
||||||
s.setFontSize(s.DefaultFontSize, opts.pdf_default_font_size)
|
s.setFontSize(s.DefaultFontSize, opts.pdf_default_font_size)
|
||||||
s.setFontSize(s.DefaultFixedFontSize, opts.pdf_mono_font_size)
|
s.setFontSize(s.DefaultFixedFontSize, opts.pdf_mono_font_size)
|
||||||
s.setFontSize(s.MinimumLogicalFontSize, 8)
|
s.setFontSize(s.MinimumLogicalFontSize, 8)
|
||||||
s.setFontSize(s.MinimumFontSize, 8)
|
s.setFontSize(s.MinimumFontSize, 8)
|
||||||
std = {'serif':opts.pdf_serif_family, 'sans':opts.pdf_sans_family,
|
std = {
|
||||||
'mono':opts.pdf_mono_family}.get(opts.pdf_standard_font,
|
'serif': opts.pdf_serif_family,
|
||||||
opts.pdf_serif_family)
|
'sans' : opts.pdf_sans_family,
|
||||||
|
'mono' : opts.pdf_mono_family
|
||||||
|
}.get(opts.pdf_standard_font, opts.pdf_serif_family)
|
||||||
if std:
|
if std:
|
||||||
s.setFontFamily(s.StandardFont, std)
|
s.setFontFamily(s.StandardFont, std)
|
||||||
if opts.pdf_serif_family:
|
if opts.pdf_serif_family:
|
||||||
@ -45,14 +57,60 @@ class Renderer(QWebEnginePage):
|
|||||||
if opts.pdf_mono_family:
|
if opts.pdf_mono_family:
|
||||||
s.setFontFamily(s.FixedFont, opts.pdf_mono_family)
|
s.setFontFamily(s.FixedFont, opts.pdf_mono_family)
|
||||||
|
|
||||||
|
self.loadFinished.connect(self.load_finished)
|
||||||
|
if not iswindows:
|
||||||
|
setup_unix_signals(self)
|
||||||
|
|
||||||
def convert(opf_path, log, opts):
|
def load_finished(self, ok):
|
||||||
|
if not ok:
|
||||||
|
QApplication.instance().exit(LOAD_FAILED)
|
||||||
|
return
|
||||||
|
QTimer.singleShot(int(1000 * self.settle_time), self.print_to_pdf)
|
||||||
|
|
||||||
|
def signal_received(self, read_fd):
|
||||||
|
try:
|
||||||
|
os.read(read_fd, 1024)
|
||||||
|
except EnvironmentError:
|
||||||
|
return
|
||||||
|
QApplication.instance().exit(KILL_SIGNAL)
|
||||||
|
|
||||||
|
def print_to_pdf(self):
|
||||||
|
self.printToPdf(self.printing_done, self.page_layout)
|
||||||
|
|
||||||
|
def printing_done(self, pdf_data):
|
||||||
|
self.pdf_data = pdf_data
|
||||||
|
QApplication.instance().exit(OK)
|
||||||
|
|
||||||
|
def convert_html_file(self, path, page_layout, settle_time=0):
|
||||||
|
self.settle_time = settle_time
|
||||||
|
self.page_layout = page_layout
|
||||||
|
self.pdf_data = None
|
||||||
|
self.setUrl(QUrl.fromLocalFile(path))
|
||||||
|
ret = QApplication.exec_()
|
||||||
|
if ret == LOAD_FAILED:
|
||||||
|
raise SystemExit('Failed to load {}'.format(path))
|
||||||
|
if ret == KILL_SIGNAL:
|
||||||
|
raise SystemExit('Kill signal received')
|
||||||
|
if ret != OK:
|
||||||
|
raise SystemExit('Unknown error occurred')
|
||||||
|
return self.pdf_data
|
||||||
|
|
||||||
|
|
||||||
|
def convert(opf_path, opts, output_path=None, log=default_log):
|
||||||
container = Container(opf_path, log)
|
container = Container(opf_path, log)
|
||||||
spine_names = [name for name in container.spine_names]
|
spine_names = [name for name, is_linear in container.spine_names]
|
||||||
master = spine_names[0]
|
master = spine_names[0]
|
||||||
if len(spine_names) > 1:
|
if len(spine_names) > 1:
|
||||||
merge_html(container, spine_names, master)
|
merge_html(container, spine_names, master, insert_page_breaks=True)
|
||||||
|
|
||||||
container.commit()
|
container.commit()
|
||||||
index_file = container.name_to_abspath(master)
|
index_file = container.name_to_abspath(master)
|
||||||
index_file
|
|
||||||
|
renderer = Renderer(opts)
|
||||||
|
page_layout = get_page_layout(opts)
|
||||||
|
pdf_data = renderer.convert_html_file(index_file, page_layout, settle_time=1)
|
||||||
|
|
||||||
|
if output_path is None:
|
||||||
|
return pdf_data
|
||||||
|
with open(output_path, 'wb') as f:
|
||||||
|
f.write(pdf_data)
|
||||||
|
@ -813,6 +813,26 @@ def setup_hidpi():
|
|||||||
prints('Not controlling automatic hidpi scaling')
|
prints('Not controlling automatic hidpi scaling')
|
||||||
|
|
||||||
|
|
||||||
|
def setup_unix_signals(self):
|
||||||
|
if hasattr(os, 'pipe2'):
|
||||||
|
read_fd, write_fd = os.pipe2(os.O_CLOEXEC | os.O_NONBLOCK)
|
||||||
|
else:
|
||||||
|
import fcntl
|
||||||
|
read_fd, write_fd = os.pipe()
|
||||||
|
cloexec_flag = getattr(fcntl, 'FD_CLOEXEC', 1)
|
||||||
|
for fd in (read_fd, write_fd):
|
||||||
|
flags = fcntl.fcntl(fd, fcntl.F_GETFD)
|
||||||
|
fcntl.fcntl(fd, fcntl.F_SETFD, flags | cloexec_flag | os.O_NONBLOCK)
|
||||||
|
|
||||||
|
for sig in (signal.SIGINT, signal.SIGTERM):
|
||||||
|
signal.signal(sig, lambda x, y: None)
|
||||||
|
signal.siginterrupt(sig, False)
|
||||||
|
signal.set_wakeup_fd(write_fd)
|
||||||
|
self.signal_notifier = QSocketNotifier(read_fd, QSocketNotifier.Read, self)
|
||||||
|
self.signal_notifier.setEnabled(True)
|
||||||
|
self.signal_notifier.activated.connect(self.signal_received, type=Qt.QueuedConnection)
|
||||||
|
|
||||||
|
|
||||||
class Application(QApplication):
|
class Application(QApplication):
|
||||||
|
|
||||||
shutdown_signal_received = pyqtSignal()
|
shutdown_signal_received = pyqtSignal()
|
||||||
@ -1066,23 +1086,7 @@ class Application(QApplication):
|
|||||||
self.setQuitOnLastWindowClosed(True)
|
self.setQuitOnLastWindowClosed(True)
|
||||||
|
|
||||||
def setup_unix_signals(self):
|
def setup_unix_signals(self):
|
||||||
import fcntl
|
setup_unix_signals(self)
|
||||||
if hasattr(os, 'pipe2'):
|
|
||||||
read_fd, write_fd = os.pipe2(os.O_CLOEXEC | os.O_NONBLOCK)
|
|
||||||
else:
|
|
||||||
read_fd, write_fd = os.pipe()
|
|
||||||
cloexec_flag = getattr(fcntl, 'FD_CLOEXEC', 1)
|
|
||||||
for fd in (read_fd, write_fd):
|
|
||||||
flags = fcntl.fcntl(fd, fcntl.F_GETFD)
|
|
||||||
fcntl.fcntl(fd, fcntl.F_SETFD, flags | cloexec_flag | os.O_NONBLOCK)
|
|
||||||
|
|
||||||
for sig in (signal.SIGINT, signal.SIGTERM):
|
|
||||||
signal.signal(sig, lambda x, y: None)
|
|
||||||
signal.siginterrupt(sig, False)
|
|
||||||
signal.set_wakeup_fd(write_fd)
|
|
||||||
self.signal_notifier = QSocketNotifier(read_fd, QSocketNotifier.Read, self)
|
|
||||||
self.signal_notifier.setEnabled(True)
|
|
||||||
self.signal_notifier.activated.connect(self.signal_received, type=Qt.QueuedConnection)
|
|
||||||
|
|
||||||
def signal_received(self, read_fd):
|
def signal_received(self, read_fd):
|
||||||
try:
|
try:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user