This commit is contained in:
Kovid Goyal 2021-02-21 11:22:19 +05:30
commit f72f500e47
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 55 additions and 15 deletions

View File

@ -38,6 +38,8 @@ from polyglot.builtins import iteritems, itervalues, unicode_type, string_or_byt
EPUB_EXT = '.epub'
KEPUB_EXT = '.kepub'
DEFAULT_COVER_LETTERBOX_COLOR = '#000000'
# Implementation of QtQHash for strings. This doesn't seem to be in the Python implementation.
@ -83,7 +85,10 @@ class KOBO(USBMS):
dbversion = 0
fwversion = (0,0,0)
supported_dbversion = 160
# The firmware for these devices is not being updated. But the Kobo desktop application
# will update the database if the device is connected. The database structure is completely
# backwardly compatible.
supported_dbversion = 162
has_kepubs = False
supported_platforms = ['windows', 'osx', 'linux']
@ -159,6 +164,7 @@ class KOBO(USBMS):
OPT_SHOW_RECOMMENDATIONS = 5
OPT_SUPPORT_NEWER_FIRMWARE = 6
def __init__(self, *args, **kwargs):
USBMS.__init__(self, *args, **kwargs)
self.plugboards = self.plugboard_func = None
@ -1350,7 +1356,7 @@ class KOBOTOUCH(KOBO):
' Based on the existing Kobo driver by %s.') % KOBO.author
# icon = I('devices/kobotouch.jpg')
supported_dbversion = 161
supported_dbversion = 162
min_supported_dbversion = 53
min_dbversion_series = 65
min_dbversion_externalid = 65
@ -1363,7 +1369,7 @@ class KOBOTOUCH(KOBO):
# Starting with firmware version 3.19.x, the last number appears to be is a
# build number. A number will be recorded here but it can be safely ignored
# when testing the firmware version.
max_supported_fwversion = (4, 25, 15821)
max_supported_fwversion = (4, 26, 16704)
# The following document firwmare versions where new function or devices were added.
# Not all are used, but this feels a good place to record it.
min_fwversion_shelves = (2, 0, 0)
@ -2604,7 +2610,8 @@ class KOBOTOUCH(KOBO):
self._upload_cover(
path, filename, metadata, filepath,
self.upload_grayscale, self.dithered_covers,
self.keep_cover_aspect, self.letterbox_fs_covers, self.png_covers)
self.keep_cover_aspect, self.letterbox_fs_covers, self.png_covers,
letterbox_color=self.letterbox_fs_covers_color)
except Exception as e:
debug_print('KoboTouch: FAILED to upload cover=%s Exception=%s'%(filepath, unicode_type(e)))
@ -2661,7 +2668,8 @@ class KOBOTOUCH(KOBO):
def _create_cover_data(
self, cover_data, resize_to, minify_to, kobo_size,
upload_grayscale=False, dithered_covers=False, keep_cover_aspect=False, is_full_size=False, letterbox=False, png_covers=False, quality=90
upload_grayscale=False, dithered_covers=False, keep_cover_aspect=False, is_full_size=False, letterbox=False, png_covers=False, quality=90,
letterbox_color=DEFAULT_COVER_LETTERBOX_COLOR
):
'''
This will generate the new cover image from the cover in the library. It is a wrapper
@ -2681,17 +2689,19 @@ class KOBOTOUCH(KOBO):
:param letterbox: True if we were asked to handle the letterboxing
:param png_covers: True if we were asked to encode those images in PNG instead of JPG
:param quality: 0-100 Output encoding quality (or compression level for PNG, àla IM)
:param letterbox_color: Colour used for letterboxing.
'''
from calibre.utils.img import save_cover_data_to
data = save_cover_data_to(
cover_data, resize_to=resize_to, compression_quality=quality, minify_to=minify_to, grayscale=upload_grayscale, eink=dithered_covers,
letterbox=letterbox, data_fmt="png" if png_covers else "jpeg")
letterbox=letterbox, data_fmt="png" if png_covers else "jpeg", letterbox_color=letterbox_color)
return data
def _upload_cover(
self, path, filename, metadata, filepath, upload_grayscale,
dithered_covers=False, keep_cover_aspect=False, letterbox_fs_covers=False, png_covers=False
dithered_covers=False, keep_cover_aspect=False, letterbox_fs_covers=False, png_covers=False,
letterbox_color=DEFAULT_COVER_LETTERBOX_COLOR
):
from calibre.utils.imghdr import identify
from calibre.utils.img import optimize_png
@ -2790,7 +2800,8 @@ class KOBOTOUCH(KOBO):
# Return the data resized and properly grayscaled/dithered/letterboxed if requested
data = self._create_cover_data(
cover_data, resize_to, expand_to, kobo_size, upload_grayscale,
dithered_covers, keep_cover_aspect, is_full_size, letterbox, png_covers, quality)
dithered_covers, keep_cover_aspect, is_full_size, letterbox, png_covers, quality,
letterbox_color=letterbox_color)
# NOTE: If we're writing a PNG file, go through a quick
# optipng pass to make sure it's encoded properly, as
@ -3323,6 +3334,7 @@ class KOBOTOUCH(KOBO):
c.add_opt('keep_cover_aspect', default=False)
c.add_opt('upload_grayscale', default=False)
c.add_opt('letterbox_fs_covers', default=False)
c.add_opt('letterbox_fs_covers_color', default=DEFAULT_COVER_LETTERBOX_COLOR)
c.add_opt('png_covers', default=False)
c.add_opt('show_archived_books', default=False)
@ -3532,6 +3544,10 @@ class KOBOTOUCH(KOBO):
def letterbox_fs_covers(self):
return self.keep_cover_aspect and self.get_pref('letterbox_fs_covers')
@property
def letterbox_fs_covers_color(self):
return self.get_pref('letterbox_fs_covers_color')
@property
def png_covers(self):
return self.upload_grayscale and self.get_pref('png_covers')

View File

@ -14,6 +14,7 @@ from PyQt5.Qt import (QWidget, QLabel, QGridLayout, QLineEdit, QVBoxLayout,
from calibre.gui2.device_drivers.tabbed_device_config import TabbedDeviceConfig, DeviceConfigTab, DeviceOptionsGroupBox
from calibre.devices.usbms.driver import debug_print
from calibre.gui2 import error_dialog
from calibre.gui2.widgets2 import ColorButton
from calibre.gui2.dialogs.template_dialog import TemplateDialog
from polyglot.builtins import unicode_type
@ -108,6 +109,7 @@ class KOBOTOUCHConfig(TabbedDeviceConfig):
p['upload_grayscale'] = self.upload_grayscale
p['dithered_covers'] = self.dithered_covers
p['letterbox_fs_covers'] = self.letterbox_fs_covers
p['letterbox_fs_covers_color'] = self.letterbox_fs_covers_color
p['png_covers'] = self.png_covers
p['show_recommendations'] = self.show_recommendations
@ -341,11 +343,21 @@ class CoversGroupBox(DeviceOptionsGroupBox):
' This is probably undesirable if you disable the "Show book covers full screen"'
' setting on your device.'),
device.get_pref('letterbox_fs_covers'))
self.letterbox_fs_covers_color_button = ColorButton(self.options_layout)
self.letterbox_fs_covers_color_button.setToolTip(_('Choose the color to use when letterboxing the cover.'
' The default color is black (#000000)'
)
)
self.letterbox_fs_covers_color_button.color = device.get_pref('letterbox_fs_covers_color')
# Make it visually depend on AR being enabled!
self.letterbox_fs_covers_checkbox.setEnabled(device.get_pref('keep_cover_aspect'))
self.letterbox_fs_covers_color_button.setEnabled(device.get_pref('keep_cover_aspect') and device.get_pref('letterbox_fs_covers'))
self.keep_cover_aspect_checkbox.toggled.connect(self.letterbox_fs_covers_checkbox.setEnabled)
self.keep_cover_aspect_checkbox.toggled.connect(
lambda checked: not checked and self.letterbox_fs_covers_checkbox.setChecked(False))
self.letterbox_fs_covers_checkbox.toggled.connect(self.letterbox_fs_covers_color_button.setEnabled)
self.png_covers_checkbox = create_checkbox(
_('Save covers as PNG'),
@ -363,10 +375,14 @@ class CoversGroupBox(DeviceOptionsGroupBox):
lambda checked: not checked and self.png_covers_checkbox.setChecked(False))
self.options_layout.addWidget(self.keep_cover_aspect_checkbox, 0, 0, 1, 1)
self.options_layout.addWidget(self.letterbox_fs_covers_checkbox, 0, 1, 1, 1)
self.options_layout.addWidget(self.upload_grayscale_checkbox, 1, 0, 1, 1)
self.options_layout.addWidget(self.dithered_covers_checkbox, 1, 1, 1, 1)
self.options_layout.addWidget(self.png_covers_checkbox, 2, 1, 1, 1)
self.options_layout.addWidget(self.letterbox_fs_covers_checkbox, 0, 1, 1, 2)
self.options_layout.addWidget(self.letterbox_fs_covers_color_button, 1, 1, 1, 1)
self.options_layout.addWidget(self.upload_grayscale_checkbox, 2, 0, 1, 1)
self.options_layout.addWidget(self.dithered_covers_checkbox, 2, 1, 1, 2)
self.options_layout.addWidget(self.png_covers_checkbox, 3, 1, 1, 2)
self.options_layout.setColumnStretch(0, 0)
self.options_layout.setColumnStretch(1, 0)
self.options_layout.setColumnStretch(2, 1)
@property
def upload_covers(self):
@ -388,6 +404,10 @@ class CoversGroupBox(DeviceOptionsGroupBox):
def letterbox_fs_covers(self):
return self.letterbox_fs_covers_checkbox.isChecked()
@property
def letterbox_fs_covers_color(self):
return self.letterbox_fs_covers_color_button.color
@property
def png_covers(self):
return self.png_covers_checkbox.isChecked()

View File

@ -215,7 +215,9 @@ def save_cover_data_to(
compression_quality=90,
minify_to=None,
grayscale=False,
eink=False, letterbox=False,
eink=False,
letterbox=False,
letterbox_color='#000000',
data_fmt='jpeg'
):
'''
@ -243,6 +245,8 @@ def save_cover_data_to(
Works best with formats that actually support color indexing (i.e., PNG)
:param letterbox: If True, in addition to fit resize_to inside minify_to,
the image will be letterboxed (i.e., centered on a black background).
:param letterbox_color: If letterboxing is used, this is the background color
used. The default is black.
'''
fmt = normalize_format_name(data_fmt if path is None else os.path.splitext(path)[1][1:])
if isinstance(data, QImage):
@ -258,7 +262,7 @@ def save_cover_data_to(
owidth, oheight = img.width(), img.height()
nwidth, nheight = tweaks['maximum_cover_size'] if minify_to is None else minify_to
if letterbox:
img = blend_on_canvas(img, nwidth, nheight, bgcolor='#000000')
img = blend_on_canvas(img, nwidth, nheight, bgcolor=letterbox_color)
# Check if we were minified
if oheight != nheight or owidth != nwidth:
changed = True