1
0
mirror of https://github.com/ciromattia/kcc synced 2026-04-18 15:08:48 +00:00

Compare commits

..

15 Commits

Author SHA1 Message Date
Alex Xu
74187b0d77 bump to 7.6.0 2025-06-29 09:37:59 -07:00
Alex Xu
f39e0caad0 exclude pkg_resources (#1001) 2025-06-29 09:34:54 -07:00
Alex Xu
6299c45790 fix flatpak kindlegen detection (7.5.0 regression) (#1000)
* fix flatpak kindlegen detection

* fix shared
2025-06-29 09:28:47 -07:00
Alex Xu
c7ebb230c2 add L comment 2025-06-27 11:45:31 -07:00
Alex Xu
3e4b729a30 always convert to L
even if workImg.color = False, it could still have color pixels, which can cause problems with quantization
2025-06-27 07:19:22 -07:00
Adrian
16a1d9b45f Fix quantization for colored images (#991) 2025-06-26 07:36:22 -07:00
Alex Xu
b7aef324aa Prevent selecting Kindle as output directory (#990)
* merge conflicts

* fix

* call it is

* fix imports
2025-06-25 18:16:42 -07:00
Alex Xu
1a42730ea0 next-folder (#988) 2025-06-25 14:55:17 -07:00
Adrian
217a18b7b5 Save images in GIF when output is set to MOBI and forcepng is used (#981)
* Save images in GIF when output is set to MOBI and forcepng option is used

* Save images in GIF when output is set to EPUB, kindle profile is used and forcepng option is set

* media-type="image/gif"

---------

Co-authored-by: Alex Xu <alexkurosakimh3@gmail.com>
2025-06-24 22:14:00 -07:00
Silver0006
2ecbf7d2e9 Replaced add folders with output directory button. (#977)
* Replaced Add Folders with output directory button.

I took the code from #969 and replaced the selectDir() function with it. Then replaced the button and linked it to selectDir()

* Fixed merge error in gui

* Fixed bug

Missing () at the end of checkState on line 852

* small fixes

* fix checkbox not saving

* rename selectDir to selectOutputDirectory

---------

Co-authored-by: Alex Xu <alexkurosakimh3@gmail.com>
2025-06-24 18:58:24 -07:00
Alex Xu
a1cf9c5c7d Update README.md 2025-06-21 22:24:57 -07:00
Alex Xu
32020d6b07 display-block (#986) 2025-06-20 17:28:42 -07:00
Adrian
221f964f14 Improve code readability (#984) 2025-06-20 10:12:24 -07:00
Adrian
e9f0310b94 Fixes to grayscale pages in forcecolor mode (#978)
* Fix bit depth of non-color pages in forcecolor mode

* Optimization for JPEG non-color pages in forcecolor mode
2025-06-18 15:12:12 -07:00
Adrian
2fa90c9f59 Fix png bit depth (#976) 2025-06-18 15:11:59 -07:00
11 changed files with 231 additions and 163 deletions

View File

@@ -101,6 +101,8 @@ For flatpak, Docker, and AppImage versions, refer to the wiki: https://github.co
## FAQ
- All options have additional information in tooltips if you hover over the option.
- To get the converted book onto your Kindle/Kobo, just drag and drop the mobi/kepub into the documents folder on your Kindle/Kobo via USB
- Colors inverted?
- Disable Kindle dark mode
- Cannot connect Kindle Scribe or 2024+ Kindle to macOS
- Use official MTP [Amazon USB File Transfer app](https://www.amazon.com/gp/help/customer/display.html/ref=hp_Connect_USB_MTP?nodeId=TCUBEdEkbIhK07ysFu)
(no login required). Works much better than previously recommended Android File Transfer. Cannot run simutaneously with other transfer apps.

View File

@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>519</width>
<height>572</height>
<width>566</width>
<height>573</height>
</rect>
</property>
<property name="windowTitle">
@@ -137,27 +137,62 @@
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QPushButton" name="directoryButton">
<item row="1" column="3">
<widget class="QPushButton" name="convertButton">
<property name="minimumSize">
<size>
<width>0</width>
<height>30</height>
</size>
</property>
<property name="font">
<font>
<bold>true</bold>
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Add directory containing JPG, PNG or GIF files to queue.&lt;br/&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;CBR, CBZ and CB7 files inside will not be processed!&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Shift+Click to select the output directory for this list.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Add image folder</string>
<string>Convert</string>
</property>
<property name="icon">
<iconset resource="KCC.qrc">
<normaloff>:/Other/icons/folder_new.png</normaloff>:/Other/icons/folder_new.png</iconset>
<normaloff>:/Other/icons/convert.png</normaloff>:/Other/icons/convert.png</iconset>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QPushButton" name="clearButton">
<property name="minimumSize">
<size>
<width>0</width>
<height>30</height>
</size>
</property>
<property name="text">
<string>Clear list</string>
</property>
<property name="icon">
<iconset resource="KCC.qrc">
<normaloff>:/Other/icons/clear.png</normaloff>:/Other/icons/clear.png</iconset>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="deviceBox">
<property name="minimumSize">
<size>
<width>0</width>
<height>28</height>
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Target device.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="fileButton">
<property name="minimumSize">
<size>
@@ -177,20 +212,46 @@
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QComboBox" name="deviceBox">
<item row="0" column="5">
<widget class="QPushButton" name="defaultOutputFolderButton">
<property name="minimumSize">
<size>
<width>0</width>
<height>28</height>
<height>30</height>
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Target device.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Use this to select the default output directory.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="KCC.qrc">
<normaloff>:/Other/icons/folder_new.png</normaloff>:/Other/icons/folder_new.png</iconset>
</property>
</widget>
</item>
<item row="1" column="3">
<item row="0" column="4">
<widget class="QCheckBox" name="defaultOutputFolderBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Unchecked - next to source&lt;br/&gt;&lt;/span&gt;Place output files next to source files&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Indeterminate - folder next to source&lt;br/&gt;&lt;/span&gt;Place output files in a folder next to source files&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Checked - Custom&lt;br/&gt;&lt;/span&gt;Place output files in custom directory specified by right button&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Output Folder</string>
</property>
<property name="tristate">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="4" colspan="2">
<widget class="QComboBox" name="formatBox">
<property name="minimumSize">
<size>
@@ -203,55 +264,14 @@
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="convertButton">
<property name="minimumSize">
<size>
<width>0</width>
<height>30</height>
</size>
</property>
<property name="font">
<font>
<bold>true</bold>
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Shift+Click to select the output directory.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Convert</string>
</property>
<property name="icon">
<iconset resource="KCC.qrc">
<normaloff>:/Other/icons/convert.png</normaloff>:/Other/icons/convert.png</iconset>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="clearButton">
<property name="minimumSize">
<size>
<width>0</width>
<height>30</height>
</size>
</property>
<property name="text">
<string>Clear list</string>
</property>
<property name="icon">
<iconset resource="KCC.qrc">
<normaloff>:/Other/icons/clear.png</normaloff>:/Other/icons/clear.png</iconset>
</property>
</widget>
</item>
</layout>
<zorder>directoryButton</zorder>
<zorder>clearButton</zorder>
<zorder>fileButton</zorder>
<zorder>deviceBox</zorder>
<zorder>convertButton</zorder>
<zorder>formatBox</zorder>
<zorder>defaultOutputFolderButton</zorder>
<zorder>fileButton</zorder>
<zorder>defaultOutputFolderBox</zorder>
</widget>
</item>
<item row="1" column="0" colspan="2">
@@ -813,8 +833,6 @@
<tabstops>
<tabstop>convertButton</tabstop>
<tabstop>clearButton</tabstop>
<tabstop>directoryButton</tabstop>
<tabstop>fileButton</tabstop>
<tabstop>deviceBox</tabstop>
<tabstop>formatBox</tabstop>
<tabstop>mangaBox</tabstop>

View File

@@ -11,7 +11,7 @@ a = Analysis(['kcc-c2e.py'],
hiddenimports=['_cffi_backend'],
hookspath=[],
runtime_hooks=[],
excludes=[],
excludes=['pkg_resources'],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,

View File

@@ -11,7 +11,7 @@ a = Analysis(['kcc-c2p.py'],
hiddenimports=['_cffi_backend'],
hookspath=[],
runtime_hooks=[],
excludes=[],
excludes=['pkg_resources'],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,

View File

@@ -11,7 +11,7 @@ a = Analysis(['kcc.py'],
hiddenimports=['_cffi_backend'],
hookspath=[],
runtime_hooks=[],
excludes=[],
excludes=['pkg_resources'],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,

View File

@@ -16,6 +16,9 @@
# OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
import itertools
from pathlib import Path
from PySide6.QtCore import (QSize, QUrl, Qt, Signal, QIODeviceBase, QEvent, QThread, QSettings)
from PySide6.QtGui import (QColor, QIcon, QPixmap, QDesktopServices)
from PySide6.QtWidgets import (QApplication, QLabel, QListWidgetItem, QMainWindow, QApplication, QSystemTrayIcon, QFileDialog, QMessageBox, QDialog)
@@ -27,7 +30,7 @@ import sys
from urllib.parse import unquote
from time import sleep
from shutil import move, rmtree
from subprocess import STDOUT, PIPE
from subprocess import STDOUT, PIPE, CalledProcessError
import requests
from xml.sax.saxutils import escape
@@ -487,17 +490,33 @@ class SystemTrayIcon(QSystemTrayIcon):
class KCCGUI(KCC_ui.Ui_mainWindow):
def selectDir(self):
if self.needClean:
self.needClean = False
GUI.jobList.clear()
dname = QFileDialog.getExistingDirectory(MW, 'Select directory', self.lastPath)
def selectDefaultOutputFolder(self):
dname = QFileDialog.getExistingDirectory(MW, 'Select default output folder', self.defaultOutputFolder)
if self.is_directory_on_kindle(dname):
return
if dname != '':
if sys.platform.startswith('win'):
dname = dname.replace('/', '\\')
self.lastPath = os.path.abspath(os.path.join(dname, os.pardir))
GUI.jobList.addItem(dname)
GUI.jobList.scrollToBottom()
GUI.defaultOutputFolder = dname
def is_directory_on_kindle(self, dname):
path = Path(dname)
for parent in itertools.chain([path], path.parents):
if parent.name == 'documents' and parent.parent.joinpath('system').joinpath('thumbnails').is_dir():
self.addMessage("Cannot select Kindle as output directory", 'error')
return True
def selectOutputFolder(self):
dname = QFileDialog.getExistingDirectory(MW, 'Select output directory', self.lastPath)
if self.is_directory_on_kindle(dname):
return
if dname != '':
if sys.platform.startswith('win'):
dname = dname.replace('/', '\\')
GUI.targetDirectory = dname
else:
GUI.targetDirectory = ''
return GUI.targetDirectory
def selectFile(self):
if self.needClean:
@@ -585,7 +604,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
GUI.editorButton.setEnabled(status)
GUI.wikiButton.setEnabled(status)
GUI.deviceBox.setEnabled(status)
GUI.directoryButton.setEnabled(status)
GUI.defaultOutputFolderButton.setEnabled(status)
GUI.clearButton.setEnabled(status)
GUI.fileButton.setEnabled(status)
GUI.formatBox.setEnabled(status)
@@ -782,13 +801,10 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
self.worker.sync()
else:
if QApplication.keyboardModifiers() == Qt.KeyboardModifier.ShiftModifier:
dname = QFileDialog.getExistingDirectory(MW, 'Select output directory', self.lastPath)
if dname != '':
if sys.platform.startswith('win'):
dname = dname.replace('/', '\\')
GUI.targetDirectory = dname
else:
GUI.targetDirectory = ''
if not self.selectOutputFolder():
return
elif GUI.defaultOutputFolderBox.isChecked():
self.targetDirectory = self.defaultOutputFolder
else:
GUI.targetDirectory = ''
self.progress.start()
@@ -799,6 +815,12 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
self.addMessage('No files selected! Please choose files to convert.', 'error')
self.needClean = True
return
if GUI.defaultOutputFolderBox.checkState() == Qt.CheckState.PartiallyChecked:
parent = Path(self.jobList.item(0).text()).parent
target_path = parent.joinpath(f"{parent.name}")
if not target_path.exists():
target_path.mkdir()
self.targetDirectory = str(target_path)
if self.currentMode > 2 and (GUI.widthBox.value() == 0 or GUI.heightBox.value() == 0):
GUI.jobList.clear()
self.addMessage('Target resolution is not set!', 'error')
@@ -830,6 +852,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
event.ignore()
self.settings.setValue('settingsVersion', __version__)
self.settings.setValue('lastPath', self.lastPath)
self.settings.setValue('defaultOutputFolder', self.defaultOutputFolder)
self.settings.setValue('lastDevice', GUI.deviceBox.currentIndex())
self.settings.setValue('currentFormat', GUI.formatBox.currentIndex())
self.settings.setValue('startNumber', self.startNumber + 1)
@@ -856,6 +879,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
'deleteBox': GUI.deleteBox.checkState().value,
'spreadShiftBox': GUI.spreadShiftBox.checkState().value,
'fileFusionBox': GUI.fileFusionBox.checkState().value,
'defaultOutputFolderBox': GUI.defaultOutputFolderBox.checkState().value,
'noRotateBox': GUI.noRotateBox.checkState().value,
'maximizeStrips': GUI.maximizeStrips.checkState().value,
'gammaSlider': float(self.gammaValue) * 100,
@@ -921,7 +945,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
self.addMessage('Your <a href="https://www.amazon.com/b?node=23496309011">KindleGen</a>'
' is outdated! MOBI conversion might fail.', 'warning')
break
except FileNotFoundError:
except (FileNotFoundError, CalledProcessError):
self.kindleGen = False
if startup:
self.display_kindlegen_missing()
@@ -937,6 +961,9 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
self.settings = QSettings('ciromattia', 'kcc')
self.settingsVersion = self.settings.value('settingsVersion', '', type=str)
self.lastPath = self.settings.value('lastPath', '', type=str)
self.defaultOutputFolder = str(self.settings.value('defaultOutputFolder', '', type=str))
if not os.path.exists(self.defaultOutputFolder):
self.defaultOutputFolder = ''
self.lastDevice = self.settings.value('lastDevice', 0, type=int)
self.currentFormat = self.settings.value('currentFormat', 0, type=int)
self.startNumber = self.settings.value('startNumber', 0, type=int)
@@ -965,7 +992,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
if self.windowSize == '0x0':
MW.resize(500, 500)
elif sys.platform.startswith('darwin'):
for element in ['editorButton', 'wikiButton', 'directoryButton', 'clearButton', 'fileButton', 'deviceBox',
for element in ['editorButton', 'wikiButton', 'defaultOutputFolderButton', 'clearButton', 'fileButton', 'deviceBox',
'convertButton', 'formatBox']:
getattr(GUI, element).setMinimumSize(QSize(0, 0))
GUI.gridLayout.setContentsMargins(-1, -1, -1, -1)
@@ -1133,7 +1160,6 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
self.addMessage('<b>Welcome!</b>', 'info')
self.addMessage('<b>Tip:</b> Hover mouse over options to see additional information in tooltips.', 'info')
self.addMessage('<b>Tip:</b> You can drag and drop image folders or comic files/archives into this window to convert.', 'info')
self.addMessage('<b>Tip:</b> Shift clicking the Convert button lets you select a custom output directory', 'info')
if self.startNumber < 5:
self.addMessage('Since you are a new user of <b>KCC</b> please see few '
'<a href="https://github.com/ciromattia/kcc/wiki/Important-tips">important tips</a>.',
@@ -1147,7 +1173,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
self.detectKindleGen(True)
APP.messageFromOtherInstance.connect(self.handleMessage)
GUI.directoryButton.clicked.connect(self.selectDir)
GUI.defaultOutputFolderButton.clicked.connect(self.selectDefaultOutputFolder)
GUI.clearButton.clicked.connect(self.clearJobs)
GUI.fileButton.clicked.connect(self.selectFile)
GUI.editorButton.clicked.connect(self.selectFileMetaEditor)

View File

@@ -26,7 +26,7 @@ class Ui_mainWindow(object):
def setupUi(self, mainWindow):
if not mainWindow.objectName():
mainWindow.setObjectName(u"mainWindow")
mainWindow.resize(519, 572)
mainWindow.resize(566, 573)
icon = QIcon()
icon.addFile(u":/Icon/icons/comic2ebook.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
mainWindow.setWindowIcon(icon)
@@ -90,63 +90,75 @@ class Ui_mainWindow(object):
self.gridLayout_4 = QGridLayout(self.buttonWidget)
self.gridLayout_4.setObjectName(u"gridLayout_4")
self.gridLayout_4.setContentsMargins(0, 0, 0, 0)
self.directoryButton = QPushButton(self.buttonWidget)
self.directoryButton.setObjectName(u"directoryButton")
self.directoryButton.setMinimumSize(QSize(0, 30))
icon4 = QIcon()
icon4.addFile(u":/Other/icons/folder_new.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.directoryButton.setIcon(icon4)
self.gridLayout_4.addWidget(self.directoryButton, 0, 0, 1, 1)
self.fileButton = QPushButton(self.buttonWidget)
self.fileButton.setObjectName(u"fileButton")
self.fileButton.setMinimumSize(QSize(0, 30))
icon5 = QIcon()
icon5.addFile(u":/Other/icons/document_new.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.fileButton.setIcon(icon5)
self.gridLayout_4.addWidget(self.fileButton, 0, 3, 1, 1)
self.deviceBox = QComboBox(self.buttonWidget)
self.deviceBox.setObjectName(u"deviceBox")
self.deviceBox.setMinimumSize(QSize(0, 28))
self.gridLayout_4.addWidget(self.deviceBox, 1, 0, 1, 1)
self.formatBox = QComboBox(self.buttonWidget)
self.formatBox.setObjectName(u"formatBox")
self.formatBox.setMinimumSize(QSize(0, 28))
self.gridLayout_4.addWidget(self.formatBox, 1, 3, 1, 1)
self.convertButton = QPushButton(self.buttonWidget)
self.convertButton.setObjectName(u"convertButton")
self.convertButton.setMinimumSize(QSize(0, 30))
font = QFont()
font.setBold(True)
self.convertButton.setFont(font)
icon6 = QIcon()
icon6.addFile(u":/Other/icons/convert.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.convertButton.setIcon(icon6)
icon4 = QIcon()
icon4.addFile(u":/Other/icons/convert.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.convertButton.setIcon(icon4)
self.gridLayout_4.addWidget(self.convertButton, 1, 2, 1, 1)
self.gridLayout_4.addWidget(self.convertButton, 1, 3, 1, 1)
self.clearButton = QPushButton(self.buttonWidget)
self.clearButton.setObjectName(u"clearButton")
self.clearButton.setMinimumSize(QSize(0, 30))
icon5 = QIcon()
icon5.addFile(u":/Other/icons/clear.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.clearButton.setIcon(icon5)
self.gridLayout_4.addWidget(self.clearButton, 0, 3, 1, 1)
self.deviceBox = QComboBox(self.buttonWidget)
self.deviceBox.setObjectName(u"deviceBox")
self.deviceBox.setMinimumSize(QSize(0, 28))
self.gridLayout_4.addWidget(self.deviceBox, 1, 1, 1, 1)
self.fileButton = QPushButton(self.buttonWidget)
self.fileButton.setObjectName(u"fileButton")
self.fileButton.setMinimumSize(QSize(0, 30))
icon6 = QIcon()
icon6.addFile(u":/Other/icons/document_new.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.fileButton.setIcon(icon6)
self.gridLayout_4.addWidget(self.fileButton, 0, 1, 1, 1)
self.defaultOutputFolderButton = QPushButton(self.buttonWidget)
self.defaultOutputFolderButton.setObjectName(u"defaultOutputFolderButton")
self.defaultOutputFolderButton.setMinimumSize(QSize(0, 30))
icon7 = QIcon()
icon7.addFile(u":/Other/icons/clear.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.clearButton.setIcon(icon7)
icon7.addFile(u":/Other/icons/folder_new.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
self.defaultOutputFolderButton.setIcon(icon7)
self.gridLayout_4.addWidget(self.clearButton, 0, 2, 1, 1)
self.gridLayout_4.addWidget(self.defaultOutputFolderButton, 0, 5, 1, 1)
self.defaultOutputFolderBox = QCheckBox(self.buttonWidget)
self.defaultOutputFolderBox.setObjectName(u"defaultOutputFolderBox")
sizePolicy1 = QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
sizePolicy1.setHorizontalStretch(0)
sizePolicy1.setVerticalStretch(0)
sizePolicy1.setHeightForWidth(self.defaultOutputFolderBox.sizePolicy().hasHeightForWidth())
self.defaultOutputFolderBox.setSizePolicy(sizePolicy1)
self.defaultOutputFolderBox.setTristate(True)
self.gridLayout_4.addWidget(self.defaultOutputFolderBox, 0, 4, 1, 1)
self.formatBox = QComboBox(self.buttonWidget)
self.formatBox.setObjectName(u"formatBox")
self.formatBox.setMinimumSize(QSize(0, 28))
self.gridLayout_4.addWidget(self.formatBox, 1, 4, 1, 2)
self.directoryButton.raise_()
self.clearButton.raise_()
self.fileButton.raise_()
self.deviceBox.raise_()
self.convertButton.raise_()
self.formatBox.raise_()
self.defaultOutputFolderButton.raise_()
self.fileButton.raise_()
self.defaultOutputFolderBox.raise_()
self.gridLayout.addWidget(self.buttonWidget, 3, 0, 1, 2)
@@ -167,11 +179,11 @@ class Ui_mainWindow(object):
self.gridLayout_3.setContentsMargins(0, 0, 0, 0)
self.hLabel = QLabel(self.customWidget)
self.hLabel.setObjectName(u"hLabel")
sizePolicy1 = QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Preferred)
sizePolicy1.setHorizontalStretch(0)
sizePolicy1.setVerticalStretch(0)
sizePolicy1.setHeightForWidth(self.hLabel.sizePolicy().hasHeightForWidth())
self.hLabel.setSizePolicy(sizePolicy1)
sizePolicy2 = QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Preferred)
sizePolicy2.setHorizontalStretch(0)
sizePolicy2.setVerticalStretch(0)
sizePolicy2.setHeightForWidth(self.hLabel.sizePolicy().hasHeightForWidth())
self.hLabel.setSizePolicy(sizePolicy2)
self.gridLayout_3.addWidget(self.hLabel, 0, 2, 1, 1)
@@ -183,8 +195,8 @@ class Ui_mainWindow(object):
self.wLabel = QLabel(self.customWidget)
self.wLabel.setObjectName(u"wLabel")
sizePolicy1.setHeightForWidth(self.wLabel.sizePolicy().hasHeightForWidth())
self.wLabel.setSizePolicy(sizePolicy1)
sizePolicy2.setHeightForWidth(self.wLabel.sizePolicy().hasHeightForWidth())
self.wLabel.setSizePolicy(sizePolicy2)
self.gridLayout_3.addWidget(self.wLabel, 0, 0, 1, 1)
@@ -223,11 +235,8 @@ class Ui_mainWindow(object):
self.preserveMarginBox = QSpinBox(self.croppingWidget)
self.preserveMarginBox.setObjectName(u"preserveMarginBox")
sizePolicy2 = QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
sizePolicy2.setHorizontalStretch(0)
sizePolicy2.setVerticalStretch(0)
sizePolicy2.setHeightForWidth(self.preserveMarginBox.sizePolicy().hasHeightForWidth())
self.preserveMarginBox.setSizePolicy(sizePolicy2)
sizePolicy1.setHeightForWidth(self.preserveMarginBox.sizePolicy().hasHeightForWidth())
self.preserveMarginBox.setSizePolicy(sizePolicy1)
self.preserveMarginBox.setMaximum(99)
self.preserveMarginBox.setSingleStep(5)
self.preserveMarginBox.setValue(0)
@@ -434,9 +443,7 @@ class Ui_mainWindow(object):
self.statusBar.setSizeGripEnabled(False)
mainWindow.setStatusBar(self.statusBar)
QWidget.setTabOrder(self.convertButton, self.clearButton)
QWidget.setTabOrder(self.clearButton, self.directoryButton)
QWidget.setTabOrder(self.directoryButton, self.fileButton)
QWidget.setTabOrder(self.fileButton, self.deviceBox)
QWidget.setTabOrder(self.clearButton, self.deviceBox)
QWidget.setTabOrder(self.deviceBox, self.formatBox)
QWidget.setTabOrder(self.formatBox, self.mangaBox)
QWidget.setTabOrder(self.mangaBox, self.rotateBox)
@@ -479,24 +486,28 @@ class Ui_mainWindow(object):
self.kofiButton.setText(QCoreApplication.translate("mainWindow", u"Support me on Ko-fi", None))
self.wikiButton.setText(QCoreApplication.translate("mainWindow", u"Wiki", None))
#if QT_CONFIG(tooltip)
self.directoryButton.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Add directory containing JPG, PNG or GIF files to queue.<br/><span style=\" font-weight:600;\">CBR, CBZ and CB7 files inside will not be processed!</span></p></body></html>", None))
self.convertButton.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Shift+Click to select the output directory for this list.</p></body></html>", None))
#endif // QT_CONFIG(tooltip)
self.convertButton.setText(QCoreApplication.translate("mainWindow", u"Convert", None))
self.clearButton.setText(QCoreApplication.translate("mainWindow", u"Clear list", None))
#if QT_CONFIG(tooltip)
self.deviceBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Target device.</p></body></html>", None))
#endif // QT_CONFIG(tooltip)
self.directoryButton.setText(QCoreApplication.translate("mainWindow", u"Add image folder", None))
#if QT_CONFIG(tooltip)
self.fileButton.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Add CBR, CBZ, CB7 or PDF file to queue.</p></body></html>", None))
#endif // QT_CONFIG(tooltip)
self.fileButton.setText(QCoreApplication.translate("mainWindow", u"Add file(s)", None))
#if QT_CONFIG(tooltip)
self.deviceBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Target device.</p></body></html>", None))
self.defaultOutputFolderButton.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p>Use this to select the default output directory.</p></body></html>", None))
#endif // QT_CONFIG(tooltip)
self.defaultOutputFolderButton.setText("")
#if QT_CONFIG(tooltip)
self.defaultOutputFolderBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - next to source<br/></span>Place output files next to source files</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - folder next to source<br/></span>Place output files in a folder next to source files</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Custom<br/></span>Place output files in custom directory specified by right button</p></body></html>", None))
#endif // QT_CONFIG(tooltip)
self.defaultOutputFolderBox.setText(QCoreApplication.translate("mainWindow", u"Output Folder", None))
#if QT_CONFIG(tooltip)
self.formatBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Output format.</p></body></html>", None))
#endif // QT_CONFIG(tooltip)
#if QT_CONFIG(tooltip)
self.convertButton.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Shift+Click to select the output directory.</p></body></html>", None))
#endif // QT_CONFIG(tooltip)
self.convertButton.setText(QCoreApplication.translate("mainWindow", u"Convert", None))
self.clearButton.setText(QCoreApplication.translate("mainWindow", u"Clear list", None))
#if QT_CONFIG(tooltip)
self.hLabel.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Resolution of the target device.</p></body></html>", None))
#endif // QT_CONFIG(tooltip)

View File

@@ -1,4 +1,4 @@
__version__ = '7.5.1'
__version__ = '7.6.0'
__license__ = 'ISC'
__copyright__ = '2012-2022, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>, darodi'
__docformat__ = 'restructuredtext en'

View File

@@ -336,6 +336,8 @@ def buildOPF(dstdir, title, filelist, cover=None):
".xhtml\" media-type=\"application/xhtml+xml\"/>\n")
if '.png' == filename[1]:
mt = 'image/png'
elif '.gif' == filename[1]:
mt = 'image/gif'
else:
mt = 'image/jpeg'
f.write("<item id=\"img_" + str(uniqueid) + "\" href=\"" + folder + "/" + path[1] + "\" media-type=\"" +
@@ -448,10 +450,13 @@ def buildEPUB(path, chapternames, tomenumber, ischunked, cover: image.Cover, len
"margin: 0;\n",
"padding: 0;\n",
"}\n",
"img {\n",
"display: block;\n",
"}\n",
])
if options.kindle_scribe_azw3:
f.writelines([
"img {\n",
"display: block;\n",
"}\n",
])
if options.iskindle and options.panelview:
f.writelines(["#PV {\n",
"position: absolute;\n",
@@ -642,8 +647,12 @@ def imgFileProcessing(work):
img.autocontrastImage()
img.resizeImage()
img.optimizeForDisplay(opt.reducerainbow)
if opt.forcepng and not opt.forcecolor:
if opt.forcecolor and workImg.color:
pass
elif opt.forcepng:
img.quantizeImage()
else:
img.convertToGrayscale()
output.append(img.saveToDir())
return output
except Exception:
@@ -1229,7 +1238,7 @@ def checkTools(source):
if options.format == 'MOBI':
try:
subprocess_run(['kindlegen', '-locale', 'en'], stdout=PIPE, stderr=STDOUT, check=True)
except FileNotFoundError:
except (FileNotFoundError, CalledProcessError):
print('ERROR: KindleGen is missing!')
sys.exit(1)

View File

@@ -304,8 +304,6 @@ class ComicPage:
def saveToDir(self):
try:
flags = []
if not self.opt.forcecolor and not self.opt.forcepng:
self.image = self.image.convert('L')
if self.rotated:
flags.append('Rotated')
if self.fill != 'white':
@@ -327,8 +325,12 @@ class ComicPage:
def save_with_codec(self, image, targetPath):
if self.opt.forcepng:
image.info["transparency"] = None
targetPath += '.png'
image.save(targetPath, 'PNG', optimize=1)
if self.opt.iskindle and ('MOBI' in self.opt.format or 'EPUB' in self.opt.format):
targetPath += '.gif'
image.save(targetPath, 'GIF', optimize=1, interlace=False)
else:
targetPath += '.png'
image.save(targetPath, 'PNG', optimize=1)
else:
targetPath += '.jpg'
if self.opt.mozjpeg:
@@ -353,15 +355,16 @@ class ComicPage:
else:
self.image = ImageOps.autocontrast(Image.eval(self.image, lambda a: int(255 * (a / 255.) ** gamma)))
def convertToGrayscale(self):
self.image = self.image.convert('L')
def quantizeImage(self):
colors = len(self.palette) // 3
if colors < 256:
self.palette += self.palette[:3] * (256 - colors)
# remove all color pixels from image, since colorCheck() has some tolerance
# quantize with a small number of color pixels in a mostly b/w image can have unexpected results
self.image = self.image.convert("L").convert("RGB")
palImg = Image.new('P', (1, 1))
palImg.putpalette(self.palette)
self.image = self.image.convert('L')
self.image = self.image.convert('RGB')
# Quantize is deprecated but new function call it internally anyway...
self.image = self.image.quantize(palette=palImg)
def optimizeForDisplay(self, reducerainbow):

View File

@@ -20,7 +20,6 @@
from functools import lru_cache
import os
from hashlib import md5
from html.parser import HTMLParser
import subprocess
from packaging.version import Version
@@ -140,7 +139,7 @@ def available_archive_tools():
try:
subprocess_run([tool], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
available.append(tool)
except FileNotFoundError:
except (FileNotFoundError, subprocess.CalledProcessError):
pass
return available