mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Merge branch 'master' of https://github.com/davidfor/calibre
This commit is contained in:
commit
f72f500e47
@ -38,6 +38,8 @@ from polyglot.builtins import iteritems, itervalues, unicode_type, string_or_byt
|
|||||||
EPUB_EXT = '.epub'
|
EPUB_EXT = '.epub'
|
||||||
KEPUB_EXT = '.kepub'
|
KEPUB_EXT = '.kepub'
|
||||||
|
|
||||||
|
DEFAULT_COVER_LETTERBOX_COLOR = '#000000'
|
||||||
|
|
||||||
# Implementation of QtQHash for strings. This doesn't seem to be in the Python implementation.
|
# Implementation of QtQHash for strings. This doesn't seem to be in the Python implementation.
|
||||||
|
|
||||||
|
|
||||||
@ -83,7 +85,10 @@ class KOBO(USBMS):
|
|||||||
|
|
||||||
dbversion = 0
|
dbversion = 0
|
||||||
fwversion = (0,0,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
|
has_kepubs = False
|
||||||
|
|
||||||
supported_platforms = ['windows', 'osx', 'linux']
|
supported_platforms = ['windows', 'osx', 'linux']
|
||||||
@ -159,6 +164,7 @@ class KOBO(USBMS):
|
|||||||
OPT_SHOW_RECOMMENDATIONS = 5
|
OPT_SHOW_RECOMMENDATIONS = 5
|
||||||
OPT_SUPPORT_NEWER_FIRMWARE = 6
|
OPT_SUPPORT_NEWER_FIRMWARE = 6
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
USBMS.__init__(self, *args, **kwargs)
|
USBMS.__init__(self, *args, **kwargs)
|
||||||
self.plugboards = self.plugboard_func = None
|
self.plugboards = self.plugboard_func = None
|
||||||
@ -1350,7 +1356,7 @@ class KOBOTOUCH(KOBO):
|
|||||||
' Based on the existing Kobo driver by %s.') % KOBO.author
|
' Based on the existing Kobo driver by %s.') % KOBO.author
|
||||||
# icon = I('devices/kobotouch.jpg')
|
# icon = I('devices/kobotouch.jpg')
|
||||||
|
|
||||||
supported_dbversion = 161
|
supported_dbversion = 162
|
||||||
min_supported_dbversion = 53
|
min_supported_dbversion = 53
|
||||||
min_dbversion_series = 65
|
min_dbversion_series = 65
|
||||||
min_dbversion_externalid = 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
|
# 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
|
# build number. A number will be recorded here but it can be safely ignored
|
||||||
# when testing the firmware version.
|
# 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.
|
# 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.
|
# Not all are used, but this feels a good place to record it.
|
||||||
min_fwversion_shelves = (2, 0, 0)
|
min_fwversion_shelves = (2, 0, 0)
|
||||||
@ -2604,7 +2610,8 @@ class KOBOTOUCH(KOBO):
|
|||||||
self._upload_cover(
|
self._upload_cover(
|
||||||
path, filename, metadata, filepath,
|
path, filename, metadata, filepath,
|
||||||
self.upload_grayscale, self.dithered_covers,
|
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:
|
except Exception as e:
|
||||||
debug_print('KoboTouch: FAILED to upload cover=%s Exception=%s'%(filepath, unicode_type(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(
|
def _create_cover_data(
|
||||||
self, cover_data, resize_to, minify_to, kobo_size,
|
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
|
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 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 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 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
|
from calibre.utils.img import save_cover_data_to
|
||||||
data = 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,
|
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
|
return data
|
||||||
|
|
||||||
def _upload_cover(
|
def _upload_cover(
|
||||||
self, path, filename, metadata, filepath, upload_grayscale,
|
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.imghdr import identify
|
||||||
from calibre.utils.img import optimize_png
|
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
|
# Return the data resized and properly grayscaled/dithered/letterboxed if requested
|
||||||
data = self._create_cover_data(
|
data = self._create_cover_data(
|
||||||
cover_data, resize_to, expand_to, kobo_size, upload_grayscale,
|
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
|
# NOTE: If we're writing a PNG file, go through a quick
|
||||||
# optipng pass to make sure it's encoded properly, as
|
# 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('keep_cover_aspect', default=False)
|
||||||
c.add_opt('upload_grayscale', default=False)
|
c.add_opt('upload_grayscale', default=False)
|
||||||
c.add_opt('letterbox_fs_covers', 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('png_covers', default=False)
|
||||||
|
|
||||||
c.add_opt('show_archived_books', default=False)
|
c.add_opt('show_archived_books', default=False)
|
||||||
@ -3532,6 +3544,10 @@ class KOBOTOUCH(KOBO):
|
|||||||
def letterbox_fs_covers(self):
|
def letterbox_fs_covers(self):
|
||||||
return self.keep_cover_aspect and self.get_pref('letterbox_fs_covers')
|
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
|
@property
|
||||||
def png_covers(self):
|
def png_covers(self):
|
||||||
return self.upload_grayscale and self.get_pref('png_covers')
|
return self.upload_grayscale and self.get_pref('png_covers')
|
||||||
|
@ -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.gui2.device_drivers.tabbed_device_config import TabbedDeviceConfig, DeviceConfigTab, DeviceOptionsGroupBox
|
||||||
from calibre.devices.usbms.driver import debug_print
|
from calibre.devices.usbms.driver import debug_print
|
||||||
from calibre.gui2 import error_dialog
|
from calibre.gui2 import error_dialog
|
||||||
|
from calibre.gui2.widgets2 import ColorButton
|
||||||
from calibre.gui2.dialogs.template_dialog import TemplateDialog
|
from calibre.gui2.dialogs.template_dialog import TemplateDialog
|
||||||
from polyglot.builtins import unicode_type
|
from polyglot.builtins import unicode_type
|
||||||
|
|
||||||
@ -108,6 +109,7 @@ class KOBOTOUCHConfig(TabbedDeviceConfig):
|
|||||||
p['upload_grayscale'] = self.upload_grayscale
|
p['upload_grayscale'] = self.upload_grayscale
|
||||||
p['dithered_covers'] = self.dithered_covers
|
p['dithered_covers'] = self.dithered_covers
|
||||||
p['letterbox_fs_covers'] = self.letterbox_fs_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['png_covers'] = self.png_covers
|
||||||
|
|
||||||
p['show_recommendations'] = self.show_recommendations
|
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"'
|
' This is probably undesirable if you disable the "Show book covers full screen"'
|
||||||
' setting on your device.'),
|
' setting on your device.'),
|
||||||
device.get_pref('letterbox_fs_covers'))
|
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!
|
# Make it visually depend on AR being enabled!
|
||||||
self.letterbox_fs_covers_checkbox.setEnabled(device.get_pref('keep_cover_aspect'))
|
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(self.letterbox_fs_covers_checkbox.setEnabled)
|
||||||
self.keep_cover_aspect_checkbox.toggled.connect(
|
self.keep_cover_aspect_checkbox.toggled.connect(
|
||||||
lambda checked: not checked and self.letterbox_fs_covers_checkbox.setChecked(False))
|
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(
|
self.png_covers_checkbox = create_checkbox(
|
||||||
_('Save covers as PNG'),
|
_('Save covers as PNG'),
|
||||||
@ -362,11 +374,15 @@ class CoversGroupBox(DeviceOptionsGroupBox):
|
|||||||
self.upload_grayscale_checkbox.toggled.connect(
|
self.upload_grayscale_checkbox.toggled.connect(
|
||||||
lambda checked: not checked and self.png_covers_checkbox.setChecked(False))
|
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.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.letterbox_fs_covers_checkbox, 0, 1, 1, 2)
|
||||||
self.options_layout.addWidget(self.upload_grayscale_checkbox, 1, 0, 1, 1)
|
self.options_layout.addWidget(self.letterbox_fs_covers_color_button, 1, 1, 1, 1)
|
||||||
self.options_layout.addWidget(self.dithered_covers_checkbox, 1, 1, 1, 1)
|
self.options_layout.addWidget(self.upload_grayscale_checkbox, 2, 0, 1, 1)
|
||||||
self.options_layout.addWidget(self.png_covers_checkbox, 2, 1, 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
|
@property
|
||||||
def upload_covers(self):
|
def upload_covers(self):
|
||||||
@ -388,6 +404,10 @@ class CoversGroupBox(DeviceOptionsGroupBox):
|
|||||||
def letterbox_fs_covers(self):
|
def letterbox_fs_covers(self):
|
||||||
return self.letterbox_fs_covers_checkbox.isChecked()
|
return self.letterbox_fs_covers_checkbox.isChecked()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def letterbox_fs_covers_color(self):
|
||||||
|
return self.letterbox_fs_covers_color_button.color
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def png_covers(self):
|
def png_covers(self):
|
||||||
return self.png_covers_checkbox.isChecked()
|
return self.png_covers_checkbox.isChecked()
|
||||||
|
@ -215,7 +215,9 @@ def save_cover_data_to(
|
|||||||
compression_quality=90,
|
compression_quality=90,
|
||||||
minify_to=None,
|
minify_to=None,
|
||||||
grayscale=False,
|
grayscale=False,
|
||||||
eink=False, letterbox=False,
|
eink=False,
|
||||||
|
letterbox=False,
|
||||||
|
letterbox_color='#000000',
|
||||||
data_fmt='jpeg'
|
data_fmt='jpeg'
|
||||||
):
|
):
|
||||||
'''
|
'''
|
||||||
@ -243,6 +245,8 @@ def save_cover_data_to(
|
|||||||
Works best with formats that actually support color indexing (i.e., PNG)
|
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,
|
: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).
|
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:])
|
fmt = normalize_format_name(data_fmt if path is None else os.path.splitext(path)[1][1:])
|
||||||
if isinstance(data, QImage):
|
if isinstance(data, QImage):
|
||||||
@ -258,7 +262,7 @@ def save_cover_data_to(
|
|||||||
owidth, oheight = img.width(), img.height()
|
owidth, oheight = img.width(), img.height()
|
||||||
nwidth, nheight = tweaks['maximum_cover_size'] if minify_to is None else minify_to
|
nwidth, nheight = tweaks['maximum_cover_size'] if minify_to is None else minify_to
|
||||||
if letterbox:
|
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
|
# Check if we were minified
|
||||||
if oheight != nheight or owidth != nwidth:
|
if oheight != nheight or owidth != nwidth:
|
||||||
changed = True
|
changed = True
|
||||||
|
Loading…
x
Reference in New Issue
Block a user