mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
PDF Output: Improved cover and comic handling
This commit is contained in:
parent
16fd984fdc
commit
bfef38f5bf
@ -15,42 +15,14 @@ from calibre.customize.conversion import OutputFormatPlugin, \
|
|||||||
OptionRecommendation
|
OptionRecommendation
|
||||||
from calibre.ebooks.metadata.opf2 import OPF
|
from calibre.ebooks.metadata.opf2 import OPF
|
||||||
from calibre.ptempfile import TemporaryDirectory
|
from calibre.ptempfile import TemporaryDirectory
|
||||||
from calibre.ebooks.pdf.writer import PDFWriter, ImagePDFWriter, PDFMetadata, \
|
from calibre.ebooks.pdf.writer import PDFWriter, ImagePDFWriter, PDFMetadata
|
||||||
get_pdf_page_size
|
|
||||||
from calibre.ebooks.pdf.pageoptions import UNITS, PAPER_SIZES, \
|
from calibre.ebooks.pdf.pageoptions import UNITS, PAPER_SIZES, \
|
||||||
ORIENTATIONS
|
ORIENTATIONS
|
||||||
from calibre.ebooks.epub.output import CoverManager
|
|
||||||
|
|
||||||
class CoverManagerPDF(CoverManager):
|
class PDFOutput(OutputFormatPlugin):
|
||||||
|
|
||||||
def setup_cover(self, opts):
|
|
||||||
width, height = get_pdf_page_size(opts)
|
|
||||||
factor = opts.output_profile.dpi
|
|
||||||
self.NONSVG_TITLEPAGE_COVER = '''\
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
|
||||||
<meta name="calibre:cover" content="true" />
|
|
||||||
<title>Cover</title>
|
|
||||||
<style type="text/css" title="override_css">
|
|
||||||
@page {padding: 0pt; margin:0pt}
|
|
||||||
body { text-align: center; padding:0pt; margin: 0pt; }
|
|
||||||
div { padding:0pt; margin: 0pt; }
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div>
|
|
||||||
<img src="%%s" alt="cover" width="%d" height="%d" />
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
'''%(int(width*factor), int(height*factor)-5)
|
|
||||||
|
|
||||||
|
|
||||||
class PDFOutput(OutputFormatPlugin, CoverManagerPDF):
|
|
||||||
|
|
||||||
name = 'PDF Output'
|
name = 'PDF Output'
|
||||||
author = 'John Schember'
|
author = 'John Schember and Kovid Goyal'
|
||||||
file_type = 'pdf'
|
file_type = 'pdf'
|
||||||
|
|
||||||
options = set([
|
options = set([
|
||||||
@ -72,6 +44,12 @@ class PDFOutput(OutputFormatPlugin, CoverManagerPDF):
|
|||||||
level=OptionRecommendation.LOW, choices=ORIENTATIONS.keys(),
|
level=OptionRecommendation.LOW, choices=ORIENTATIONS.keys(),
|
||||||
help=_('The orientation of the page. Default is portrait. Choices '
|
help=_('The orientation of the page. Default is portrait. Choices '
|
||||||
'are %s') % ORIENTATIONS.keys()),
|
'are %s') % ORIENTATIONS.keys()),
|
||||||
|
OptionRecommendation(name='preserve_cover_aspect_ratio',
|
||||||
|
recommended_value=False,
|
||||||
|
help=_('Preserve the aspect ratio of the cover, instead'
|
||||||
|
' of stretching it to fill the ull first page of the'
|
||||||
|
' generated pdf.')
|
||||||
|
),
|
||||||
])
|
])
|
||||||
|
|
||||||
def convert(self, oeb_book, output_path, input_plugin, opts, log):
|
def convert(self, oeb_book, output_path, input_plugin, opts, log):
|
||||||
@ -79,6 +57,7 @@ class PDFOutput(OutputFormatPlugin, CoverManagerPDF):
|
|||||||
self.input_plugin, self.opts, self.log = input_plugin, opts, log
|
self.input_plugin, self.opts, self.log = input_plugin, opts, log
|
||||||
self.output_path = output_path
|
self.output_path = output_path
|
||||||
self.metadata = oeb_book.metadata
|
self.metadata = oeb_book.metadata
|
||||||
|
self.cover_data = None
|
||||||
|
|
||||||
if input_plugin.is_image_collection:
|
if input_plugin.is_image_collection:
|
||||||
log.debug('Converting input as an image collection...')
|
log.debug('Converting input as an image collection...')
|
||||||
@ -90,13 +69,20 @@ class PDFOutput(OutputFormatPlugin, CoverManagerPDF):
|
|||||||
def convert_images(self, images):
|
def convert_images(self, images):
|
||||||
self.write(ImagePDFWriter, images)
|
self.write(ImagePDFWriter, images)
|
||||||
|
|
||||||
|
def get_cover_data(self):
|
||||||
|
g, m = self.oeb.guide, self.oeb.manifest
|
||||||
|
if 'titlepage' not in g:
|
||||||
|
if 'cover' in g:
|
||||||
|
href = g['cover'].href
|
||||||
|
from calibre.ebooks.oeb.base import urlnormalize
|
||||||
|
for item in m:
|
||||||
|
if item.href == urlnormalize(href):
|
||||||
|
self.cover_data = item.data
|
||||||
|
|
||||||
def convert_text(self, oeb_book):
|
def convert_text(self, oeb_book):
|
||||||
self.log.debug('Serializing oeb input to disk for processing...')
|
self.log.debug('Serializing oeb input to disk for processing...')
|
||||||
self.opts.no_svg_cover = True
|
self.get_cover_data()
|
||||||
self.opts.no_default_epub_cover = True
|
|
||||||
self.opts.preserve_cover_aspect_ratio = False
|
|
||||||
self.setup_cover(self.opts)
|
|
||||||
self.insert_cover()
|
|
||||||
with TemporaryDirectory('_pdf_out') as oeb_dir:
|
with TemporaryDirectory('_pdf_out') as oeb_dir:
|
||||||
from calibre.customize.ui import plugin_for_output_format
|
from calibre.customize.ui import plugin_for_output_format
|
||||||
oeb_output = plugin_for_output_format('oeb')
|
oeb_output = plugin_for_output_format('oeb')
|
||||||
@ -108,7 +94,7 @@ class PDFOutput(OutputFormatPlugin, CoverManagerPDF):
|
|||||||
self.write(PDFWriter, [s.path for s in opf.spine])
|
self.write(PDFWriter, [s.path for s in opf.spine])
|
||||||
|
|
||||||
def write(self, Writer, items):
|
def write(self, Writer, items):
|
||||||
writer = Writer(self.opts, self.log)
|
writer = Writer(self.opts, self.log, cover_data=self.cover_data)
|
||||||
|
|
||||||
close = False
|
close = False
|
||||||
if not hasattr(self.output_path, 'write'):
|
if not hasattr(self.output_path, 'write'):
|
||||||
|
@ -15,14 +15,20 @@ from calibre.ptempfile import PersistentTemporaryDirectory
|
|||||||
from calibre.ebooks.pdf.pageoptions import unit, paper_size, \
|
from calibre.ebooks.pdf.pageoptions import unit, paper_size, \
|
||||||
orientation
|
orientation
|
||||||
from calibre.ebooks.metadata import authors_to_string
|
from calibre.ebooks.metadata import authors_to_string
|
||||||
|
from calibre.ptempfile import PersistentTemporaryFile
|
||||||
|
from calibre import __appname__, __version__, fit_image
|
||||||
|
|
||||||
from PyQt4 import QtCore
|
from PyQt4 import QtCore
|
||||||
from PyQt4.Qt import QUrl, QEventLoop, SIGNAL, QObject, \
|
from PyQt4.Qt import QUrl, QEventLoop, QObject, \
|
||||||
QPrinter, QMetaObject, QSizeF, Qt, QPainter
|
QPrinter, QMetaObject, QSizeF, Qt, QPainter, QPixmap
|
||||||
from PyQt4.QtWebKit import QWebView
|
from PyQt4.QtWebKit import QWebView
|
||||||
|
|
||||||
from pyPdf import PdfFileWriter, PdfFileReader
|
from pyPdf import PdfFileWriter, PdfFileReader
|
||||||
|
|
||||||
|
def get_pdf_printer():
|
||||||
|
return QPrinter(QPrinter.HighResolution)
|
||||||
|
|
||||||
|
|
||||||
def get_custom_size(opts):
|
def get_custom_size(opts):
|
||||||
custom_size = None
|
custom_size = None
|
||||||
if opts.custom_size != None:
|
if opts.custom_size != None:
|
||||||
@ -36,12 +42,12 @@ def get_custom_size(opts):
|
|||||||
custom_size = None
|
custom_size = None
|
||||||
return custom_size
|
return custom_size
|
||||||
|
|
||||||
def get_pdf_page_size(opts):
|
def setup_printer(opts, for_comic=False):
|
||||||
from calibre.gui2 import is_ok_to_use_qt
|
from calibre.gui2 import is_ok_to_use_qt
|
||||||
if not is_ok_to_use_qt():
|
if not is_ok_to_use_qt():
|
||||||
raise Exception('Not OK to use Qt')
|
raise Exception('Not OK to use Qt')
|
||||||
|
|
||||||
printer = QPrinter(QPrinter.HighResolution)
|
printer = get_pdf_printer()
|
||||||
custom_size = get_custom_size(opts)
|
custom_size = get_custom_size(opts)
|
||||||
|
|
||||||
if opts.output_profile.short_name == 'default':
|
if opts.output_profile.short_name == 'default':
|
||||||
@ -50,37 +56,41 @@ def get_pdf_page_size(opts):
|
|||||||
else:
|
else:
|
||||||
printer.setPaperSize(QSizeF(custom_size[0], custom_size[1]), unit(opts.unit))
|
printer.setPaperSize(QSizeF(custom_size[0], custom_size[1]), unit(opts.unit))
|
||||||
else:
|
else:
|
||||||
printer.setPaperSize(QSizeF(opts.output_profile.width / opts.output_profile.dpi,
|
w = opts.output_profile.comic_screen_size[0] if for_comic else \
|
||||||
opts.output_profile.height / opts.output_profile.dpi), QPrinter.Inch)
|
opts.output_profile.width
|
||||||
|
h = opts.output_profile.comic_screen_size[1] if for_comic else \
|
||||||
|
opts.output_profile.height
|
||||||
|
dpi = opts.output_profile.dpi
|
||||||
|
printer.setPaperSize(QSizeF(float(w) / dpi, float(h)/dpi), QPrinter.Inch)
|
||||||
|
|
||||||
printer.setPageMargins(0, 0, 0, 0, QPrinter.Point)
|
printer.setPageMargins(0, 0, 0, 0, QPrinter.Point)
|
||||||
printer.setOrientation(orientation(opts.orientation))
|
printer.setOrientation(orientation(opts.orientation))
|
||||||
printer.setOutputFormat(QPrinter.PdfFormat)
|
printer.setOutputFormat(QPrinter.PdfFormat)
|
||||||
|
return printer
|
||||||
|
|
||||||
size = printer.paperSize(QPrinter.Millimeter)
|
def get_printer_page_size(opts, for_comic=False):
|
||||||
|
printer = setup_printer(opts, for_comic=for_comic)
|
||||||
|
size = printer.paperSize(QPrinter.Millimeter)
|
||||||
|
return size.width() / 10., size.height() / 10.
|
||||||
|
|
||||||
return size.width() / 10, size.height() / 10
|
def draw_image_page(printer, painter, p, preserve_aspect_ratio=True):
|
||||||
|
page_rect = printer.pageRect()
|
||||||
|
if preserve_aspect_ratio:
|
||||||
|
aspect_ratio = float(p.width())/p.height()
|
||||||
|
nw, nh = page_rect.width(), page_rect.height()
|
||||||
|
if aspect_ratio > 1:
|
||||||
|
nh = int(page_rect.width()/aspect_ratio)
|
||||||
|
else: # Width is smaller than height
|
||||||
|
nw = page_rect.height()*aspect_ratio
|
||||||
|
__, nnw, nnh = fit_image(nw, nh, page_rect.width(),
|
||||||
|
page_rect.height())
|
||||||
|
dx = int((page_rect.width() - nnw)/2.)
|
||||||
|
dy = int((page_rect.height() - nnh)/2.)
|
||||||
|
page_rect.moveTo(dx, dy)
|
||||||
|
page_rect.setHeight(nnh)
|
||||||
|
page_rect.setWidth(nnw)
|
||||||
|
painter.drawPixmap(page_rect, p, p.rect())
|
||||||
|
|
||||||
def get_imagepdf_page_size(opts):
|
|
||||||
printer = QPrinter(QPrinter.HighResolution)
|
|
||||||
custom_size = get_custom_size(opts)
|
|
||||||
|
|
||||||
if opts.output_profile.short_name == 'default':
|
|
||||||
if custom_size == None:
|
|
||||||
printer.setPaperSize(paper_size(opts.paper_size))
|
|
||||||
else:
|
|
||||||
printer.setPaperSize(QSizeF(custom_size[0], custom_size[1]), unit(opts.unit))
|
|
||||||
else:
|
|
||||||
printer.setPaperSize(QSizeF(opts.output_profile.comic_screen_size[0] / opts.output_profile.dpi,
|
|
||||||
opts.output_profile.comic_screen_size[1] / opts.output_profile.dpi), QPrinter.Inch)
|
|
||||||
|
|
||||||
printer.setPageMargins(0, 0, 0, 0, QPrinter.Point)
|
|
||||||
printer.setOrientation(orientation(opts.orientation))
|
|
||||||
printer.setOutputFormat(QPrinter.PdfFormat)
|
|
||||||
|
|
||||||
size = printer.paperSize(QPrinter.Millimeter)
|
|
||||||
|
|
||||||
return size.width() / 10, size.height() / 10
|
|
||||||
|
|
||||||
class PDFMetadata(object):
|
class PDFMetadata(object):
|
||||||
def __init__(self, oeb_metadata=None):
|
def __init__(self, oeb_metadata=None):
|
||||||
@ -94,9 +104,9 @@ class PDFMetadata(object):
|
|||||||
self.author = authors_to_string([x.value for x in oeb_metadata.creator])
|
self.author = authors_to_string([x.value for x in oeb_metadata.creator])
|
||||||
|
|
||||||
|
|
||||||
class PDFWriter(QObject):
|
class PDFWriter(QObject): # {{{
|
||||||
|
|
||||||
def __init__(self, opts, log):
|
def __init__(self, opts, log, cover_data=None):
|
||||||
from calibre.gui2 import is_ok_to_use_qt
|
from calibre.gui2 import is_ok_to_use_qt
|
||||||
if not is_ok_to_use_qt():
|
if not is_ok_to_use_qt():
|
||||||
raise Exception('Not OK to use Qt')
|
raise Exception('Not OK to use Qt')
|
||||||
@ -107,14 +117,15 @@ class PDFWriter(QObject):
|
|||||||
self.loop = QEventLoop()
|
self.loop = QEventLoop()
|
||||||
self.view = QWebView()
|
self.view = QWebView()
|
||||||
self.view.setRenderHints(QPainter.Antialiasing|QPainter.TextAntialiasing|QPainter.SmoothPixmapTransform)
|
self.view.setRenderHints(QPainter.Antialiasing|QPainter.TextAntialiasing|QPainter.SmoothPixmapTransform)
|
||||||
self.connect(self.view, SIGNAL('loadFinished(bool)'), self._render_html)
|
self.view.loadFinished.connect(self._render_html,
|
||||||
|
type=Qt.QueuedConnection)
|
||||||
self.render_queue = []
|
self.render_queue = []
|
||||||
self.combine_queue = []
|
self.combine_queue = []
|
||||||
self.tmp_path = PersistentTemporaryDirectory('_pdf_output_parts')
|
self.tmp_path = PersistentTemporaryDirectory('_pdf_output_parts')
|
||||||
|
|
||||||
self.opts = opts
|
self.opts = opts
|
||||||
|
self.size = get_printer_page_size(opts)
|
||||||
self.size = get_pdf_page_size(opts)
|
self.cover_data = cover_data
|
||||||
|
|
||||||
def dump(self, items, out_stream, pdf_metadata):
|
def dump(self, items, out_stream, pdf_metadata):
|
||||||
self.metadata = pdf_metadata
|
self.metadata = pdf_metadata
|
||||||
@ -143,17 +154,20 @@ class PDFWriter(QObject):
|
|||||||
|
|
||||||
self.view.load(QUrl.fromLocalFile(item))
|
self.view.load(QUrl.fromLocalFile(item))
|
||||||
|
|
||||||
|
def get_printer(self):
|
||||||
|
printer = get_pdf_printer()
|
||||||
|
printer.setPaperSize(QSizeF(self.size[0] * 10, self.size[1] * 10), QPrinter.Millimeter)
|
||||||
|
printer.setPageMargins(0, 0, 0, 0, QPrinter.Point)
|
||||||
|
printer.setOrientation(orientation(self.opts.orientation))
|
||||||
|
printer.setOutputFormat(QPrinter.PdfFormat)
|
||||||
|
printer.setFullPage(True)
|
||||||
|
return printer
|
||||||
|
|
||||||
def _render_html(self, ok):
|
def _render_html(self, ok):
|
||||||
if ok:
|
if ok:
|
||||||
item_path = os.path.join(self.tmp_path, '%i.pdf' % len(self.combine_queue))
|
item_path = os.path.join(self.tmp_path, '%i.pdf' % len(self.combine_queue))
|
||||||
|
|
||||||
self.logger.debug('\tRendering item %s as %i' % (os.path.basename(str(self.view.url().toLocalFile())), len(self.combine_queue)))
|
self.logger.debug('\tRendering item %s as %i' % (os.path.basename(str(self.view.url().toLocalFile())), len(self.combine_queue)))
|
||||||
|
printer = self.get_printer()
|
||||||
printer = QPrinter(QPrinter.HighResolution)
|
|
||||||
printer.setPaperSize(QSizeF(self.size[0] * 10, self.size[1] * 10), QPrinter.Millimeter)
|
|
||||||
printer.setPageMargins(0, 0, 0, 0, QPrinter.Point)
|
|
||||||
printer.setOrientation(orientation(self.opts.orientation))
|
|
||||||
printer.setOutputFormat(QPrinter.PdfFormat)
|
|
||||||
printer.setOutputFileName(item_path)
|
printer.setOutputFileName(item_path)
|
||||||
self.view.print_(printer)
|
self.view.print_(printer)
|
||||||
self._render_book()
|
self._render_book()
|
||||||
@ -163,9 +177,27 @@ class PDFWriter(QObject):
|
|||||||
shutil.rmtree(self.tmp_path, True)
|
shutil.rmtree(self.tmp_path, True)
|
||||||
self.tmp_path = PersistentTemporaryDirectory('_pdf_output_parts')
|
self.tmp_path = PersistentTemporaryDirectory('_pdf_output_parts')
|
||||||
|
|
||||||
|
def insert_cover(self):
|
||||||
|
if self.cover_data is None:
|
||||||
|
return
|
||||||
|
item_path = os.path.join(self.tmp_path, 'cover.pdf')
|
||||||
|
printer = self.get_printer()
|
||||||
|
printer.setOutputFileName(item_path)
|
||||||
|
self.combine_queue.insert(0, item_path)
|
||||||
|
p = QPixmap()
|
||||||
|
p.loadFromData(self.cover_data)
|
||||||
|
if not p.isNull():
|
||||||
|
painter = QPainter(printer)
|
||||||
|
draw_image_page(printer, painter, p,
|
||||||
|
preserve_aspect_ratio=self.opts.preserve_cover_aspect_ratio)
|
||||||
|
painter.end()
|
||||||
|
|
||||||
|
|
||||||
def _write(self):
|
def _write(self):
|
||||||
self.logger.debug('Combining individual PDF parts...')
|
self.logger.debug('Combining individual PDF parts...')
|
||||||
|
|
||||||
|
self.insert_cover()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
outPDF = PdfFileWriter(title=self.metadata.title, author=self.metadata.author)
|
outPDF = PdfFileWriter(title=self.metadata.title, author=self.metadata.author)
|
||||||
for item in self.combine_queue:
|
for item in self.combine_queue:
|
||||||
@ -177,23 +209,50 @@ class PDFWriter(QObject):
|
|||||||
self._delete_tmpdir()
|
self._delete_tmpdir()
|
||||||
self.loop.exit(0)
|
self.loop.exit(0)
|
||||||
|
|
||||||
|
# }}}
|
||||||
|
|
||||||
class ImagePDFWriter(PDFWriter):
|
class ImagePDFWriter(object):
|
||||||
|
|
||||||
def __init__(self, opts, log):
|
def __init__(self, opts, log, cover_data=None):
|
||||||
PDFWriter.__init__(self, opts, log)
|
self.opts = opts
|
||||||
self.size = get_imagepdf_page_size(opts)
|
self.log = log
|
||||||
|
self.size = get_printer_page_size(opts, for_comic=True)
|
||||||
|
|
||||||
def _render_next(self):
|
def dump(self, items, out_stream, pdf_metadata):
|
||||||
item = str(self.render_queue.pop(0))
|
f = PersistentTemporaryFile('_comic2pdf.pdf')
|
||||||
self.combine_queue.append(os.path.join(self.tmp_path, '%i.pdf' % (len(self.combine_queue) + 1)))
|
f.close()
|
||||||
|
try:
|
||||||
|
self.render_images(f.name, pdf_metadata, items)
|
||||||
|
with open(f.name, 'rb') as x:
|
||||||
|
shutil.copyfileobj(x, out_stream)
|
||||||
|
finally:
|
||||||
|
os.remove(f.name)
|
||||||
|
|
||||||
self.logger.debug('Processing %s...' % item)
|
def render_images(self, outpath, mi, items):
|
||||||
|
printer = get_pdf_printer()
|
||||||
|
printer.setPaperSize(QSizeF(self.size[0] * 10, self.size[1] * 10), QPrinter.Millimeter)
|
||||||
|
printer.setPageMargins(0, 0, 0, 0, QPrinter.Point)
|
||||||
|
printer.setOrientation(orientation(self.opts.orientation))
|
||||||
|
printer.setOutputFormat(QPrinter.PdfFormat)
|
||||||
|
printer.setOutputFileName(outpath)
|
||||||
|
printer.setDocName(mi.title)
|
||||||
|
printer.setCreator(u'%s [%s]'%(__appname__, __version__))
|
||||||
|
# Seems to be no way to set author
|
||||||
|
printer.setFullPage(True)
|
||||||
|
|
||||||
height = 'height: %fcm;' % (self.size[1] * 1.3)
|
painter = QPainter(printer)
|
||||||
|
painter.setRenderHints(QPainter.Antialiasing|QPainter.SmoothPixmapTransform)
|
||||||
|
|
||||||
html = '<html><body style="margin: 0;"><img src="%s" style="%s display: block; margin-left: auto; margin-right: auto; padding: 0px;" /></body></html>' % (item, height)
|
for i, imgpath in enumerate(items):
|
||||||
|
self.log('Rendering image:', i)
|
||||||
self.view.setHtml(html)
|
p = QPixmap()
|
||||||
|
p.load(imgpath)
|
||||||
|
if not p.isNull():
|
||||||
|
if i > 0:
|
||||||
|
printer.newPage()
|
||||||
|
draw_image_page(printer, painter, p)
|
||||||
|
else:
|
||||||
|
self.log.warn('Failed to load image', i)
|
||||||
|
painter.end()
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,7 +18,8 @@ class PluginWidget(Widget, Ui_Form):
|
|||||||
HELP = _('Options specific to')+' PDF '+_('output')
|
HELP = _('Options specific to')+' PDF '+_('output')
|
||||||
|
|
||||||
def __init__(self, parent, get_option, get_help, db=None, book_id=None):
|
def __init__(self, parent, get_option, get_help, db=None, book_id=None):
|
||||||
Widget.__init__(self, parent, 'pdf_output', ['paper_size', 'orientation'])
|
Widget.__init__(self, parent, 'pdf_output', ['paper_size',
|
||||||
|
'orientation', 'preserve_cover_aspect_ratio'])
|
||||||
self.db, self.book_id = db, book_id
|
self.db, self.book_id = db, book_id
|
||||||
self.initialize_options(get_option, get_help, db, book_id)
|
self.initialize_options(get_option, get_help, db, book_id)
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@
|
|||||||
<item row="1" column="1">
|
<item row="1" column="1">
|
||||||
<widget class="QComboBox" name="opt_orientation"/>
|
<widget class="QComboBox" name="opt_orientation"/>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0">
|
<item row="3" column="0">
|
||||||
<spacer name="verticalSpacer">
|
<spacer name="verticalSpacer">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Vertical</enum>
|
||||||
@ -53,6 +53,13 @@
|
|||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="2" column="0" colspan="2">
|
||||||
|
<widget class="QCheckBox" name="opt_preserve_cover_aspect_ratio">
|
||||||
|
<property name="text">
|
||||||
|
<string>Preserve &aspect ratio of cover</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<resources/>
|
<resources/>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user