mirror of
https://github.com/ciromattia/kcc
synced 2026-04-15 05:28:49 +00:00
Compare commits
15 Commits
v7.1.2
...
revert-753
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
04618d5bbf | ||
|
|
b35a2baf05 | ||
|
|
11a395e983 | ||
|
|
2e39a8c227 | ||
|
|
02535421a0 | ||
|
|
3d4fae62d8 | ||
|
|
2b550b8b98 | ||
|
|
ecee7cf6f5 | ||
|
|
b0a5558da1 | ||
|
|
1b487c18d6 | ||
|
|
a3546d19c3 | ||
|
|
2f703ef92c | ||
|
|
4fb993b38b | ||
|
|
1401f94c1f | ||
|
|
70d10204ee |
17
README.md
17
README.md
@@ -163,6 +163,8 @@ PROCESSING:
|
||||
Set cropping power [Default=1.0]
|
||||
--cm CROPPINGM, --croppingminimum CROPPINGM
|
||||
Set cropping minimum area ratio [Default=0.0]
|
||||
--ipc INTERPANELCROP, --interpanelcrop INTERPANELCROP
|
||||
Crop empty sections. 0: Disabled 1: Horizontally 2: Both [Default=0]
|
||||
--blackborders Disable autodetection and force black borders
|
||||
--whiteborders Disable autodetection and force white borders
|
||||
--forcecolor Don't convert images to grayscale
|
||||
@@ -185,6 +187,7 @@ OUTPUT SETTINGS:
|
||||
Split output into multiple files. 0: Don't split 1: Automatic mode 2: Consider every subdirectory as separate volume [Default=0]
|
||||
--spreadshift Shift first page to opposite side in landscape for two page spread alignment
|
||||
--norotate Do not rotate double page spreads in spread splitter option.
|
||||
--reducerainbow Reduce rainbow effect on color eink by slightly blurring images
|
||||
|
||||
CUSTOM PROFILE:
|
||||
--customwidth CUSTOMWIDTH
|
||||
@@ -229,6 +232,8 @@ If you want to edit the code, a good code editor is [VS Code](https://code.visua
|
||||
If you want to edit the `.ui` files, use [Qt Creator](https://www.qt.io/download-qt-installer-oss), included in **Qt for desktop development**.
|
||||
Then use the `gen_ui_files` scripts to autogenerate the python UI.
|
||||
|
||||
An example PR adding a new checkbox is here: https://github.com/ciromattia/kcc/pull/785
|
||||
|
||||
|
||||
### Windows install from source
|
||||
|
||||
@@ -247,6 +252,12 @@ venv\Scripts\activate.bat
|
||||
python kcc.py
|
||||
```
|
||||
|
||||
You can build a `.exe` of KCC like the downloads we offer with
|
||||
|
||||
```
|
||||
python setup.py build_binary
|
||||
```
|
||||
|
||||
### macOS install from source
|
||||
|
||||
One time setup and running for the first time:
|
||||
@@ -264,6 +275,12 @@ source venv/bin/activate
|
||||
python kcc.py
|
||||
```
|
||||
|
||||
You can build a `.app` of KCC like the downloads we offer with
|
||||
|
||||
```
|
||||
python setup.py build_binary
|
||||
```
|
||||
|
||||
## CREDITS
|
||||
**KCC** is made by
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
pyside6-uic gui/KCC.ui > kindlecomicconverter/KCC_ui.py
|
||||
pyside6-uic gui/MetaEditor.ui > kindlecomicconverter/KCC_ui_editor.py
|
||||
pyside6-uic gui/KCC.ui --from-imports > kindlecomicconverter/KCC_ui.py
|
||||
pyside6-uic gui/MetaEditor.ui --from-imports > kindlecomicconverter/KCC_ui_editor.py
|
||||
pyside6-rcc gui/KCC.qrc > kindlecomicconverter/KCC_rc.py
|
||||
|
||||
237
gui/KCC.ui
237
gui/KCC.ui
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>450</width>
|
||||
<height>400</height>
|
||||
<width>482</width>
|
||||
<height>448</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -37,36 +37,6 @@
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="5" column="1">
|
||||
<widget class="QCheckBox" name="deleteBox">
|
||||
<property name="toolTip">
|
||||
<string>Delete input file(s) or directory. It's not recoverable!</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Delete input</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="mangaBox">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p style='white-space:pre'>Enable right-to-left reading.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Manga mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QCheckBox" name="outputSplit">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p style='white-space:pre'><span style=" font-weight:600; text-decoration: underline;">Unchecked - Automatic mode<br/></span>The output will be split automatically.</p><p style='white-space:pre'><span style=" font-weight:600; text-decoration: underline;">Checked - Volume mode<br/></span>Every subdirectory will be considered as a separate volume.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Output split</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<widget class="QCheckBox" name="croppingBox">
|
||||
<property name="toolTip">
|
||||
@@ -80,39 +50,23 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QCheckBox" name="mozJpegBox">
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="mangaBox">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p><span style=" font-weight:600; text-decoration: underline;">Unchecked - JPEG<br/></span>Use JPEG files</p><p><span style=" font-weight:600; text-decoration: underline;">Indeterminate - force PNG<br/></span>Create PNG files instead JPEG</p><p><span style=" font-weight:600; text-decoration: underline;">Checked - mozJpeg<br/></span>10-20% smaller JPEG file, with the same image quality, but processing time multiplied by 2</p></body></html></string>
|
||||
<string><html><head/><body><p style='white-space:pre'>Enable right-to-left reading.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>JPEG/PNG/mozJpeg</string>
|
||||
</property>
|
||||
<property name="tristate">
|
||||
<bool>true</bool>
|
||||
<string>Manga mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="upscaleBox">
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="webtoonBox">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p><span style=" font-weight:600; text-decoration: underline;">Unchecked - Nothing<br/></span>Images smaller than device resolution will not be resized.</p><p><span style=" font-weight:600; text-decoration: underline;">Indeterminate - Stretching<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be not preserved.</p><p><span style=" font-weight:600; text-decoration: underline;">Checked - Upscaling<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be preserved.</p></body></html></string>
|
||||
<string><html><head/><body><p style='white-space:pre'>Enable special parsing mode for Korean Webtoons.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Stretch/Upscale</string>
|
||||
</property>
|
||||
<property name="tristate">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QCheckBox" name="colorBox">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p style='white-space:pre'>Disable conversion to grayscale.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Color mode</string>
|
||||
<string>Webtoon mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -129,46 +83,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QCheckBox" name="gammaBox">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p style='white-space:pre'>Disable automatic gamma correction.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Custom gamma</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QCheckBox" name="spreadShiftBox">
|
||||
<property name="toolTip">
|
||||
<string>Shift first page to opposite side in landscape for two page spread alignment</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Spread shift</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="webtoonBox">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p style='white-space:pre'>Enable special parsing mode for Korean Webtoons.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Webtoon mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QCheckBox" name="maximizeStrips">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p><span style=" font-weight:600; text-decoration: underline;">Unchecked - 1x4<br/></span>Keep format 1x4 panels strips.</p><p><span style=" font-weight:600; text-decoration: underline;">Checked - 2x2<br/></span>Turn 1x4 strips to 2x2 to maximize screen usage.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>1x4 to 2x2 strips</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QCheckBox" name="borderBox">
|
||||
<property name="toolTip">
|
||||
@@ -182,13 +96,36 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QCheckBox" name="noRotateBox">
|
||||
<item row="2" column="2">
|
||||
<widget class="QCheckBox" name="gammaBox">
|
||||
<property name="toolTip">
|
||||
<string>Do not rotate double page spreads in spread splitter option.</string>
|
||||
<string><html><head/><body><p style='white-space:pre'>Disable automatic gamma correction.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>No rotate</string>
|
||||
<string>Custom gamma</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="2">
|
||||
<widget class="QCheckBox" name="interPanelCropBox">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p><span style=" font-weight:600; text-decoration: underline;">Unchecked - Disabled<br/></span>Disabled</p><p><span style=" font-weight:600; text-decoration: underline;">Indeterminate - Horizontal<br/></span>Crop empty horizontal lines.</p><p><span style=" font-weight:600; text-decoration: underline;">Checked - Both<br/></span>Crop empty horizontal and vertical lines.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Inter-panel crop</string>
|
||||
</property>
|
||||
<property name="tristate">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QCheckBox" name="colorBox">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p style='white-space:pre'>Disable conversion to grayscale.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Color mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -215,6 +152,16 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QCheckBox" name="maximizeStrips">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p><span style=" font-weight:600; text-decoration: underline;">Unchecked - 1x4<br/></span>Keep format 1x4 panels strips.</p><p><span style=" font-weight:600; text-decoration: underline;">Checked - 2x2<br/></span>Turn 1x4 strips to 2x2 to maximize screen usage.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>1x4 to 2x2 strips</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLineEdit" name="authorEdit">
|
||||
<property name="sizePolicy">
|
||||
@@ -224,7 +171,7 @@
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::ClickFocus</enum>
|
||||
<enum>Qt::FocusPolicy::ClickFocus</enum>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Default Author is KCC</string>
|
||||
@@ -237,6 +184,82 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QCheckBox" name="deleteBox">
|
||||
<property name="toolTip">
|
||||
<string>Delete input file(s) or directory. It's not recoverable!</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Delete input</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QCheckBox" name="mozJpegBox">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p><span style=" font-weight:600; text-decoration: underline;">Unchecked - JPEG<br/></span>Use JPEG files</p><p><span style=" font-weight:600; text-decoration: underline;">Indeterminate - force PNG<br/></span>Create PNG files instead JPEG</p><p><span style=" font-weight:600; text-decoration: underline;">Checked - mozJpeg<br/></span>10-20% smaller JPEG file, with the same image quality, but processing time multiplied by 2</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>JPEG/PNG/mozJpeg</string>
|
||||
</property>
|
||||
<property name="tristate">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QCheckBox" name="spreadShiftBox">
|
||||
<property name="toolTip">
|
||||
<string>Shift first page to opposite side in landscape for two page spread alignment</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Spread shift</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="upscaleBox">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p><span style=" font-weight:600; text-decoration: underline;">Unchecked - Nothing<br/></span>Images smaller than device resolution will not be resized.</p><p><span style=" font-weight:600; text-decoration: underline;">Indeterminate - Stretching<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be not preserved.</p><p><span style=" font-weight:600; text-decoration: underline;">Checked - Upscaling<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be preserved.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Stretch/Upscale</string>
|
||||
</property>
|
||||
<property name="tristate">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QCheckBox" name="outputSplit">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p style='white-space:pre'><span style=" font-weight:600; text-decoration: underline;">Unchecked - Automatic mode<br/></span>The output will be split automatically.</p><p style='white-space:pre'><span style=" font-weight:600; text-decoration: underline;">Checked - Volume mode<br/></span>Every subdirectory will be considered as a separate volume.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Output split</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QCheckBox" name="noRotateBox">
|
||||
<property name="toolTip">
|
||||
<string>Do not rotate double page spreads in spread splitter option.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>No rotate</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="2">
|
||||
<widget class="QCheckBox" name="reduceRainbowBox">
|
||||
<property name="toolTip">
|
||||
<string>Reduce rainbow effect on color eink by slightly blurring images</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Reduce Rainbow</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -274,7 +297,7 @@
|
||||
<number>5</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -315,7 +338,7 @@
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -521,13 +544,13 @@
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::NoSelection</enum>
|
||||
<enum>QAbstractItemView::SelectionMode::NoSelection</enum>
|
||||
</property>
|
||||
<property name="verticalScrollMode">
|
||||
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
||||
<enum>QAbstractItemView::ScrollMode::ScrollPerPixel</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollMode">
|
||||
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
||||
<enum>QAbstractItemView::ScrollMode::ScrollPerPixel</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -548,7 +571,7 @@
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignJustify|Qt::AlignVCenter</set>
|
||||
<set>Qt::AlignmentFlag::AlignJustify|Qt::AlignmentFlag::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -16,6 +16,11 @@
|
||||
# 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.
|
||||
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)
|
||||
from PySide6.QtNetwork import (QLocalSocket, QLocalServer)
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
@@ -25,9 +30,6 @@ from shutil import move, rmtree
|
||||
from subprocess import STDOUT, PIPE
|
||||
|
||||
import requests
|
||||
# noinspection PyUnresolvedReferences
|
||||
from PySide6 import QtGui, QtCore, QtWidgets, QtNetwork
|
||||
from PySide6.QtCore import Qt
|
||||
from xml.sax.saxutils import escape
|
||||
from psutil import Process
|
||||
from copy import copy
|
||||
@@ -44,18 +46,18 @@ from . import KCC_ui
|
||||
from . import KCC_ui_editor
|
||||
|
||||
|
||||
class QApplicationMessaging(QtWidgets.QApplication):
|
||||
messageFromOtherInstance = QtCore.Signal(bytes)
|
||||
class QApplicationMessaging(QApplication):
|
||||
messageFromOtherInstance = Signal(bytes)
|
||||
|
||||
def __init__(self, argv):
|
||||
QtWidgets.QApplication.__init__(self, argv)
|
||||
QApplication.__init__(self, argv)
|
||||
self._key = 'KCC'
|
||||
self._timeout = 1000
|
||||
self._locked = False
|
||||
socket = QtNetwork.QLocalSocket(self)
|
||||
socket.connectToServer(self._key, QtCore.QIODeviceBase.OpenModeFlag.WriteOnly)
|
||||
socket = QLocalSocket(self)
|
||||
socket.connectToServer(self._key, QIODeviceBase.OpenModeFlag.WriteOnly)
|
||||
if not socket.waitForConnected(self._timeout):
|
||||
self._server = QtNetwork.QLocalServer(self)
|
||||
self._server = QLocalServer(self)
|
||||
self._server.newConnection.connect(self.handleMessage)
|
||||
self._server.listen(self._key)
|
||||
else:
|
||||
@@ -67,11 +69,11 @@ class QApplicationMessaging(QtWidgets.QApplication):
|
||||
self._server.close()
|
||||
|
||||
def event(self, e):
|
||||
if e.type() == QtCore.QEvent.Type.FileOpen:
|
||||
if e.type() == QEvent.Type.FileOpen:
|
||||
self.messageFromOtherInstance.emit(bytes(e.file(), 'UTF-8'))
|
||||
return True
|
||||
else:
|
||||
return QtWidgets.QApplication.event(self, e)
|
||||
return QApplication.event(self, e)
|
||||
|
||||
def isRunning(self):
|
||||
return self._locked
|
||||
@@ -82,56 +84,56 @@ class QApplicationMessaging(QtWidgets.QApplication):
|
||||
self.messageFromOtherInstance.emit(socket.readAll().data())
|
||||
|
||||
def sendMessage(self, message):
|
||||
socket = QtNetwork.QLocalSocket(self)
|
||||
socket.connectToServer(self._key, QtCore.QIODeviceBase.OpenModeFlag.WriteOnly)
|
||||
socket = QLocalSocket(self)
|
||||
socket.connectToServer(self._key, QIODeviceBase.OpenModeFlag.WriteOnly)
|
||||
socket.waitForConnected(self._timeout)
|
||||
socket.write(bytes(message, 'UTF-8'))
|
||||
socket.waitForBytesWritten(self._timeout)
|
||||
socket.disconnectFromServer()
|
||||
|
||||
|
||||
class QMainWindowKCC(QtWidgets.QMainWindow):
|
||||
progressBarTick = QtCore.Signal(str)
|
||||
modeConvert = QtCore.Signal(int)
|
||||
addMessage = QtCore.Signal(str, str, bool)
|
||||
addTrayMessage = QtCore.Signal(str, str)
|
||||
showDialog = QtCore.Signal(str, str)
|
||||
hideProgressBar = QtCore.Signal()
|
||||
forceShutdown = QtCore.Signal()
|
||||
class QMainWindowKCC(QMainWindow):
|
||||
progressBarTick = Signal(str)
|
||||
modeConvert = Signal(int)
|
||||
addMessage = Signal(str, str, bool)
|
||||
addTrayMessage = Signal(str, str)
|
||||
showDialog = Signal(str, str)
|
||||
hideProgressBar = Signal()
|
||||
forceShutdown = Signal()
|
||||
|
||||
|
||||
class Icons:
|
||||
def __init__(self):
|
||||
self.deviceKindle = QtGui.QIcon()
|
||||
self.deviceKindle.addPixmap(QtGui.QPixmap(":/Devices/icons/Kindle.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
||||
self.deviceKobo = QtGui.QIcon()
|
||||
self.deviceKobo.addPixmap(QtGui.QPixmap(":/Devices/icons/Kobo.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
||||
self.deviceRmk = QtGui.QIcon()
|
||||
self.deviceRmk.addPixmap(QtGui.QPixmap(":/Devices/icons/Rmk.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
||||
self.deviceOther = QtGui.QIcon()
|
||||
self.deviceOther.addPixmap(QtGui.QPixmap(":/Devices/icons/Other.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
||||
self.deviceKindle = QIcon()
|
||||
self.deviceKindle.addPixmap(QPixmap(":/Devices/icons/Kindle.png"), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
self.deviceKobo = QIcon()
|
||||
self.deviceKobo.addPixmap(QPixmap(":/Devices/icons/Kobo.png"), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
self.deviceRmk = QIcon()
|
||||
self.deviceRmk.addPixmap(QPixmap(":/Devices/icons/Rmk.png"), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
self.deviceOther = QIcon()
|
||||
self.deviceOther.addPixmap(QPixmap(":/Devices/icons/Other.png"), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
|
||||
self.MOBIFormat = QtGui.QIcon()
|
||||
self.MOBIFormat.addPixmap(QtGui.QPixmap(":/Formats/icons/MOBI.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
||||
self.CBZFormat = QtGui.QIcon()
|
||||
self.CBZFormat.addPixmap(QtGui.QPixmap(":/Formats/icons/CBZ.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
||||
self.EPUBFormat = QtGui.QIcon()
|
||||
self.EPUBFormat.addPixmap(QtGui.QPixmap(":/Formats/icons/EPUB.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
||||
self.MOBIFormat = QIcon()
|
||||
self.MOBIFormat.addPixmap(QPixmap(":/Formats/icons/MOBI.png"), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
self.CBZFormat = QIcon()
|
||||
self.CBZFormat.addPixmap(QPixmap(":/Formats/icons/CBZ.png"), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
self.EPUBFormat = QIcon()
|
||||
self.EPUBFormat.addPixmap(QPixmap(":/Formats/icons/EPUB.png"), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
|
||||
self.info = QtGui.QIcon()
|
||||
self.info.addPixmap(QtGui.QPixmap(":/Status/icons/info.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
||||
self.warning = QtGui.QIcon()
|
||||
self.warning.addPixmap(QtGui.QPixmap(":/Status/icons/warning.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
||||
self.error = QtGui.QIcon()
|
||||
self.error.addPixmap(QtGui.QPixmap(":/Status/icons/error.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
||||
self.info = QIcon()
|
||||
self.info.addPixmap(QPixmap(":/Status/icons/info.png"), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
self.warning = QIcon()
|
||||
self.warning.addPixmap(QPixmap(":/Status/icons/warning.png"), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
self.error = QIcon()
|
||||
self.error.addPixmap(QPixmap(":/Status/icons/error.png"), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
|
||||
self.programIcon = QtGui.QIcon()
|
||||
self.programIcon.addPixmap(QtGui.QPixmap(":/Icon/icons/comic2ebook.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
||||
self.programIcon = QIcon()
|
||||
self.programIcon.addPixmap(QPixmap(":/Icon/icons/comic2ebook.png"), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
|
||||
|
||||
class VersionThread(QtCore.QThread):
|
||||
class VersionThread(QThread):
|
||||
def __init__(self):
|
||||
QtCore.QThread.__init__(self)
|
||||
QThread.__init__(self)
|
||||
self.newVersion = ''
|
||||
self.md5 = ''
|
||||
self.barProgress = 0
|
||||
@@ -160,9 +162,9 @@ class VersionThread(QtCore.QThread):
|
||||
self.answer = dialoganswer
|
||||
|
||||
|
||||
class ProgressThread(QtCore.QThread):
|
||||
class ProgressThread(QThread):
|
||||
def __init__(self):
|
||||
QtCore.QThread.__init__(self)
|
||||
QThread.__init__(self)
|
||||
self.running = False
|
||||
self.content = None
|
||||
self.progress = 0
|
||||
@@ -184,9 +186,9 @@ class ProgressThread(QtCore.QThread):
|
||||
self.running = False
|
||||
|
||||
|
||||
class WorkerThread(QtCore.QThread):
|
||||
class WorkerThread(QThread):
|
||||
def __init__(self):
|
||||
QtCore.QThread.__init__(self)
|
||||
QThread.__init__(self)
|
||||
self.conversionAlive = False
|
||||
self.errors = False
|
||||
self.kindlegenErrorCode = [0]
|
||||
@@ -242,6 +244,7 @@ class WorkerThread(QtCore.QThread):
|
||||
options.cropping = GUI.croppingBox.checkState().value
|
||||
if GUI.croppingBox.checkState() != Qt.CheckState.Unchecked:
|
||||
options.croppingp = float(GUI.croppingPowerValue)
|
||||
options.interpanelcrop = GUI.interPanelCropBox.checkState().value
|
||||
if GUI.borderBox.checkState() == Qt.CheckState.PartiallyChecked:
|
||||
options.white_borders = True
|
||||
elif GUI.borderBox.checkState() == Qt.CheckState.Checked:
|
||||
@@ -250,6 +253,8 @@ class WorkerThread(QtCore.QThread):
|
||||
options.batchsplit = 2
|
||||
if GUI.colorBox.isChecked():
|
||||
options.forcecolor = True
|
||||
if GUI.reduceRainbowBox.isChecked():
|
||||
options.reducerainbow = True
|
||||
if GUI.maximizeStrips.isChecked():
|
||||
options.maximizestrips = True
|
||||
if GUI.disableProcessingBox.isChecked():
|
||||
@@ -435,7 +440,7 @@ class WorkerThread(QtCore.QThread):
|
||||
MW.modeConvert.emit(1)
|
||||
|
||||
|
||||
class SystemTrayIcon(QtWidgets.QSystemTrayIcon):
|
||||
class SystemTrayIcon(QSystemTrayIcon):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
if self.isSystemTrayAvailable():
|
||||
@@ -448,7 +453,7 @@ class SystemTrayIcon(QtWidgets.QSystemTrayIcon):
|
||||
MW.activateWindow()
|
||||
|
||||
def addTrayMessage(self, message, icon):
|
||||
icon = getattr(QtWidgets.QSystemTrayIcon.MessageIcon, icon)
|
||||
icon = getattr(QSystemTrayIcon.MessageIcon, icon)
|
||||
if self.supportsMessages() and not MW.isActiveWindow():
|
||||
self.showMessage('Kindle Comic Converter', message, icon)
|
||||
|
||||
@@ -458,7 +463,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
if self.needClean:
|
||||
self.needClean = False
|
||||
GUI.jobList.clear()
|
||||
dname = QtWidgets.QFileDialog.getExistingDirectory(MW, 'Select directory', self.lastPath)
|
||||
dname = QFileDialog.getExistingDirectory(MW, 'Select directory', self.lastPath)
|
||||
if dname != '':
|
||||
if sys.platform.startswith('win'):
|
||||
dname = dname.replace('/', '\\')
|
||||
@@ -471,10 +476,10 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
self.needClean = False
|
||||
GUI.jobList.clear()
|
||||
if self.tar or self.sevenzip:
|
||||
fnames = QtWidgets.QFileDialog.getOpenFileNames(MW, 'Select file', self.lastPath,
|
||||
fnames = QFileDialog.getOpenFileNames(MW, 'Select file', self.lastPath,
|
||||
'Comic (*.cbz *.cbr *.cb7 *.zip *.rar *.7z *.pdf);;All (*.*)')
|
||||
else:
|
||||
fnames = QtWidgets.QFileDialog.getOpenFileNames(MW, 'Select file', self.lastPath,
|
||||
fnames = QFileDialog.getOpenFileNames(MW, 'Select file', self.lastPath,
|
||||
'Comic (*.pdf);;All (*.*)')
|
||||
for fname in fnames[0]:
|
||||
if fname != '':
|
||||
@@ -486,8 +491,8 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
|
||||
def selectFileMetaEditor(self):
|
||||
sname = ''
|
||||
if QtWidgets.QApplication.keyboardModifiers() == QtCore.Qt.ShiftModifier:
|
||||
dname = QtWidgets.QFileDialog.getExistingDirectory(MW, 'Select directory', self.lastPath)
|
||||
if QApplication.keyboardModifiers() == Qt.ShiftModifier:
|
||||
dname = QFileDialog.getExistingDirectory(MW, 'Select directory', self.lastPath)
|
||||
if dname != '':
|
||||
sname = os.path.join(dname, 'ComicInfo.xml')
|
||||
if sys.platform.startswith('win'):
|
||||
@@ -495,7 +500,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
self.lastPath = os.path.abspath(sname)
|
||||
else:
|
||||
if self.sevenzip:
|
||||
fname = QtWidgets.QFileDialog.getOpenFileName(MW, 'Select file', self.lastPath,
|
||||
fname = QFileDialog.getOpenFileName(MW, 'Select file', self.lastPath,
|
||||
'Comic (*.cbz *.cbr *.cb7)')
|
||||
else:
|
||||
fname = ['']
|
||||
@@ -524,7 +529,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
|
||||
def openWiki(self):
|
||||
# noinspection PyCallByClass
|
||||
QtGui.QDesktopServices.openUrl(QtCore.QUrl('https://github.com/ciromattia/kcc/wiki'))
|
||||
QDesktopServices.openUrl(QUrl('https://github.com/ciromattia/kcc/wiki'))
|
||||
|
||||
def modeChange(self, mode):
|
||||
if mode == 1:
|
||||
@@ -559,16 +564,16 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
if enable == 1:
|
||||
self.conversionAlive = False
|
||||
self.worker.sync()
|
||||
icon = QtGui.QIcon()
|
||||
icon.addPixmap(QtGui.QPixmap(":/Other/icons/convert.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
||||
icon = QIcon()
|
||||
icon.addPixmap(QPixmap(":/Other/icons/convert.png"), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
GUI.convertButton.setIcon(icon)
|
||||
GUI.convertButton.setText('Convert')
|
||||
GUI.centralWidget.setAcceptDrops(True)
|
||||
elif enable == 0:
|
||||
self.conversionAlive = True
|
||||
self.worker.sync()
|
||||
icon = QtGui.QIcon()
|
||||
icon.addPixmap(QtGui.QPixmap(":/Other/icons/clear.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
|
||||
icon = QIcon()
|
||||
icon.addPixmap(QPixmap(":/Other/icons/clear.png"), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
GUI.convertButton.setIcon(icon)
|
||||
GUI.convertButton.setText('Abort')
|
||||
GUI.centralWidget.setAcceptDrops(False)
|
||||
@@ -684,15 +689,15 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
def addMessage(self, message, icon, replace=False):
|
||||
if icon != '':
|
||||
icon = getattr(self.icons, icon)
|
||||
item = QtWidgets.QListWidgetItem(icon, ' ' + self.stripTags(message))
|
||||
item = QListWidgetItem(icon, ' ' + self.stripTags(message))
|
||||
else:
|
||||
item = QtWidgets.QListWidgetItem(' ' + self.stripTags(message))
|
||||
item = QListWidgetItem(' ' + self.stripTags(message))
|
||||
if replace:
|
||||
GUI.jobList.takeItem(GUI.jobList.count() - 1)
|
||||
# Due to lack of HTML support in QListWidgetItem we overlay text field with QLabel
|
||||
# We still fill original text field with transparent content to trigger creation of horizontal scrollbar
|
||||
item.setForeground(QtGui.QColor('transparent'))
|
||||
label = QtWidgets.QLabel(message)
|
||||
item.setForeground(QColor('transparent'))
|
||||
label = QLabel(message)
|
||||
label.setOpenExternalLinks(True)
|
||||
GUI.jobList.addItem(item)
|
||||
GUI.jobList.setItemWidget(item, label)
|
||||
@@ -700,11 +705,11 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
|
||||
def showDialog(self, message, kind):
|
||||
if kind == 'error':
|
||||
QtWidgets.QMessageBox.critical(MW, 'KCC - Error', message, QtWidgets.QMessageBox.StandardButton.Ok)
|
||||
QMessageBox.critical(MW, 'KCC - Error', message, QMessageBox.StandardButton.Ok)
|
||||
elif kind == 'question':
|
||||
GUI.versionCheck.setAnswer(QtWidgets.QMessageBox.question(MW, 'KCC - Question', message,
|
||||
QtWidgets.QMessageBox.Yes,
|
||||
QtWidgets.QMessageBox.No))
|
||||
GUI.versionCheck.setAnswer(QMessageBox.question(MW, 'KCC - Question', message,
|
||||
QMessageBox.Yes,
|
||||
QMessageBox.No))
|
||||
|
||||
def updateProgressbar(self, command):
|
||||
if command == 'tick':
|
||||
@@ -728,8 +733,8 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
self.conversionAlive = False
|
||||
self.worker.sync()
|
||||
else:
|
||||
if QtWidgets.QApplication.keyboardModifiers() == QtCore.Qt.KeyboardModifier.ShiftModifier:
|
||||
dname = QtWidgets.QFileDialog.getExistingDirectory(MW, 'Select output directory', self.lastPath)
|
||||
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('/', '\\')
|
||||
@@ -787,11 +792,13 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
'gammaBox': GUI.gammaBox.checkState().value,
|
||||
'croppingBox': GUI.croppingBox.checkState().value,
|
||||
'croppingPowerSlider': float(self.croppingPowerValue) * 100,
|
||||
'interPanelCropBox': GUI.interPanelCropBox.checkState().value,
|
||||
'upscaleBox': GUI.upscaleBox.checkState().value,
|
||||
'borderBox': GUI.borderBox.checkState().value,
|
||||
'webtoonBox': GUI.webtoonBox.checkState().value,
|
||||
'outputSplit': GUI.outputSplit.checkState().value,
|
||||
'colorBox': GUI.colorBox.checkState().value,
|
||||
'reduceRainbowBox': GUI.reduceRainbowBox.checkState().value,
|
||||
'disableProcessingBox': GUI.disableProcessingBox.checkState().value,
|
||||
'mozJpegBox': GUI.mozJpegBox.checkState().value,
|
||||
'widthBox': GUI.widthBox.value(),
|
||||
@@ -874,7 +881,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
self.setupUi(MW)
|
||||
self.editor = KCCGUI_MetaEditor()
|
||||
self.icons = Icons()
|
||||
self.settings = QtCore.QSettings('ciromattia', 'kcc')
|
||||
self.settings = QSettings('ciromattia', 'kcc')
|
||||
self.settingsVersion = self.settings.value('settingsVersion', '', type=str)
|
||||
self.lastPath = self.settings.value('lastPath', '', type=str)
|
||||
self.lastDevice = self.settings.value('lastDevice', 0, type=int)
|
||||
@@ -907,7 +914,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
elif sys.platform.startswith('darwin'):
|
||||
for element in ['editorButton', 'wikiButton', 'directoryButton', 'clearButton', 'fileButton', 'deviceBox',
|
||||
'convertButton', 'formatBox']:
|
||||
getattr(GUI, element).setMinimumSize(QtCore.QSize(0, 0))
|
||||
getattr(GUI, element).setMinimumSize(QSize(0, 0))
|
||||
GUI.gridLayout.setContentsMargins(-1, -1, -1, -1)
|
||||
for element in ['gridLayout_2', 'gridLayout_3', 'gridLayout_4', 'horizontalLayout', 'horizontalLayout_2']:
|
||||
getattr(GUI, element).setContentsMargins(-1, 0, -1, 0)
|
||||
@@ -1050,11 +1057,11 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
"Kobo Mini/Touch",
|
||||
]
|
||||
|
||||
statusBarLabel = QtWidgets.QLabel('<b><a href="https://kcc.iosphe.re/">HOMEPAGE</a> - <a href="https://github.'
|
||||
statusBarLabel = QLabel('<b><a href="https://kcc.iosphe.re/">HOMEPAGE</a> - <a href="https://github.'
|
||||
'com/ciromattia/kcc/blob/master/README.md#issues--new-features--donations">DO'
|
||||
'NATE</a> - <a href="http://www.mobileread.com/forums/showthread.php?t=207461'
|
||||
'">FORUM</a></b>')
|
||||
statusBarLabel.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
|
||||
statusBarLabel.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
statusBarLabel.setOpenExternalLinks(True)
|
||||
GUI.statusBar.addPermanentWidget(statusBarLabel, 1)
|
||||
|
||||
@@ -1218,15 +1225,15 @@ class KCCGUI_MetaEditor(KCC_ui_editor.Ui_editorDialog):
|
||||
return escape(s.strip())
|
||||
|
||||
def __init__(self):
|
||||
self.ui = QtWidgets.QDialog()
|
||||
self.ui = QDialog()
|
||||
self.parser = None
|
||||
self.setupUi(self.ui)
|
||||
self.ui.setWindowFlags(self.ui.windowFlags() & ~QtCore.Qt.WindowType.WindowContextHelpButtonHint)
|
||||
self.ui.setWindowFlags(self.ui.windowFlags() & ~Qt.WindowType.WindowContextHelpButtonHint)
|
||||
self.okButton.clicked.connect(self.saveData)
|
||||
self.cancelButton.clicked.connect(self.ui.close)
|
||||
if sys.platform.startswith('linux'):
|
||||
self.ui.resize(450, 260)
|
||||
self.ui.setMinimumSize(QtCore.QSize(450, 260))
|
||||
self.ui.setMinimumSize(QSize(450, 260))
|
||||
elif sys.platform.startswith('darwin'):
|
||||
self.ui.resize(450, 310)
|
||||
self.ui.setMinimumSize(QtCore.QSize(450, 310))
|
||||
self.ui.setMinimumSize(QSize(450, 310))
|
||||
|
||||
@@ -11644,7 +11644,7 @@ qt_resource_struct = b"\
|
||||
\x00\x00\x012\x00\x00\x00\x00\x00\x01\x00\x01yY\
|
||||
\x00\x00\x01\x88;p\xbcI\
|
||||
\x00\x00\x01\x94\x00\x00\x00\x00\x00\x01\x00\x01\xd2-\
|
||||
\x00\x00\x01\x94\x1a\xbb\xe8\xa7\
|
||||
\x00\x00\x01\x94\xb4\xd4\xf0a\
|
||||
\x00\x00\x01z\x00\x00\x00\x00\x00\x01\x00\x01\x8c\xe6\
|
||||
\x00\x00\x01\x88;p\xbcH\
|
||||
\x00\x00\x01\x04\x00\x00\x00\x00\x00\x01\x00\x01LR\
|
||||
|
||||
@@ -26,7 +26,7 @@ class Ui_mainWindow(object):
|
||||
def setupUi(self, mainWindow):
|
||||
if not mainWindow.objectName():
|
||||
mainWindow.setObjectName(u"mainWindow")
|
||||
mainWindow.resize(450, 400)
|
||||
mainWindow.resize(482, 448)
|
||||
icon = QIcon()
|
||||
icon.addFile(u":/Icon/icons/comic2ebook.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
mainWindow.setWindowIcon(icon)
|
||||
@@ -40,43 +40,21 @@ class Ui_mainWindow(object):
|
||||
self.gridLayout_2 = QGridLayout(self.optionWidget)
|
||||
self.gridLayout_2.setObjectName(u"gridLayout_2")
|
||||
self.gridLayout_2.setContentsMargins(0, 0, 0, 0)
|
||||
self.deleteBox = QCheckBox(self.optionWidget)
|
||||
self.deleteBox.setObjectName(u"deleteBox")
|
||||
|
||||
self.gridLayout_2.addWidget(self.deleteBox, 5, 1, 1, 1)
|
||||
|
||||
self.mangaBox = QCheckBox(self.optionWidget)
|
||||
self.mangaBox.setObjectName(u"mangaBox")
|
||||
|
||||
self.gridLayout_2.addWidget(self.mangaBox, 1, 0, 1, 1)
|
||||
|
||||
self.outputSplit = QCheckBox(self.optionWidget)
|
||||
self.outputSplit.setObjectName(u"outputSplit")
|
||||
|
||||
self.gridLayout_2.addWidget(self.outputSplit, 3, 1, 1, 1)
|
||||
|
||||
self.croppingBox = QCheckBox(self.optionWidget)
|
||||
self.croppingBox.setObjectName(u"croppingBox")
|
||||
self.croppingBox.setTristate(True)
|
||||
|
||||
self.gridLayout_2.addWidget(self.croppingBox, 4, 2, 1, 1)
|
||||
|
||||
self.mozJpegBox = QCheckBox(self.optionWidget)
|
||||
self.mozJpegBox.setObjectName(u"mozJpegBox")
|
||||
self.mozJpegBox.setTristate(True)
|
||||
self.mangaBox = QCheckBox(self.optionWidget)
|
||||
self.mangaBox.setObjectName(u"mangaBox")
|
||||
|
||||
self.gridLayout_2.addWidget(self.mozJpegBox, 4, 0, 1, 1)
|
||||
self.gridLayout_2.addWidget(self.mangaBox, 1, 0, 1, 1)
|
||||
|
||||
self.upscaleBox = QCheckBox(self.optionWidget)
|
||||
self.upscaleBox.setObjectName(u"upscaleBox")
|
||||
self.upscaleBox.setTristate(True)
|
||||
self.webtoonBox = QCheckBox(self.optionWidget)
|
||||
self.webtoonBox.setObjectName(u"webtoonBox")
|
||||
|
||||
self.gridLayout_2.addWidget(self.upscaleBox, 2, 1, 1, 1)
|
||||
|
||||
self.colorBox = QCheckBox(self.optionWidget)
|
||||
self.colorBox.setObjectName(u"colorBox")
|
||||
|
||||
self.gridLayout_2.addWidget(self.colorBox, 3, 2, 1, 1)
|
||||
self.gridLayout_2.addWidget(self.webtoonBox, 2, 0, 1, 1)
|
||||
|
||||
self.rotateBox = QCheckBox(self.optionWidget)
|
||||
self.rotateBox.setObjectName(u"rotateBox")
|
||||
@@ -84,36 +62,27 @@ class Ui_mainWindow(object):
|
||||
|
||||
self.gridLayout_2.addWidget(self.rotateBox, 1, 1, 1, 1)
|
||||
|
||||
self.gammaBox = QCheckBox(self.optionWidget)
|
||||
self.gammaBox.setObjectName(u"gammaBox")
|
||||
|
||||
self.gridLayout_2.addWidget(self.gammaBox, 2, 2, 1, 1)
|
||||
|
||||
self.spreadShiftBox = QCheckBox(self.optionWidget)
|
||||
self.spreadShiftBox.setObjectName(u"spreadShiftBox")
|
||||
|
||||
self.gridLayout_2.addWidget(self.spreadShiftBox, 5, 0, 1, 1)
|
||||
|
||||
self.webtoonBox = QCheckBox(self.optionWidget)
|
||||
self.webtoonBox.setObjectName(u"webtoonBox")
|
||||
|
||||
self.gridLayout_2.addWidget(self.webtoonBox, 2, 0, 1, 1)
|
||||
|
||||
self.maximizeStrips = QCheckBox(self.optionWidget)
|
||||
self.maximizeStrips.setObjectName(u"maximizeStrips")
|
||||
|
||||
self.gridLayout_2.addWidget(self.maximizeStrips, 4, 1, 1, 1)
|
||||
|
||||
self.borderBox = QCheckBox(self.optionWidget)
|
||||
self.borderBox.setObjectName(u"borderBox")
|
||||
self.borderBox.setTristate(True)
|
||||
|
||||
self.gridLayout_2.addWidget(self.borderBox, 3, 0, 1, 1)
|
||||
|
||||
self.noRotateBox = QCheckBox(self.optionWidget)
|
||||
self.noRotateBox.setObjectName(u"noRotateBox")
|
||||
self.gammaBox = QCheckBox(self.optionWidget)
|
||||
self.gammaBox.setObjectName(u"gammaBox")
|
||||
|
||||
self.gridLayout_2.addWidget(self.noRotateBox, 6, 1, 1, 1)
|
||||
self.gridLayout_2.addWidget(self.gammaBox, 2, 2, 1, 1)
|
||||
|
||||
self.interPanelCropBox = QCheckBox(self.optionWidget)
|
||||
self.interPanelCropBox.setObjectName(u"interPanelCropBox")
|
||||
self.interPanelCropBox.setTristate(True)
|
||||
|
||||
self.gridLayout_2.addWidget(self.interPanelCropBox, 6, 2, 1, 1)
|
||||
|
||||
self.colorBox = QCheckBox(self.optionWidget)
|
||||
self.colorBox.setObjectName(u"colorBox")
|
||||
|
||||
self.gridLayout_2.addWidget(self.colorBox, 3, 2, 1, 1)
|
||||
|
||||
self.qualityBox = QCheckBox(self.optionWidget)
|
||||
self.qualityBox.setObjectName(u"qualityBox")
|
||||
@@ -126,6 +95,11 @@ class Ui_mainWindow(object):
|
||||
|
||||
self.gridLayout_2.addWidget(self.disableProcessingBox, 5, 2, 1, 1)
|
||||
|
||||
self.maximizeStrips = QCheckBox(self.optionWidget)
|
||||
self.maximizeStrips.setObjectName(u"maximizeStrips")
|
||||
|
||||
self.gridLayout_2.addWidget(self.maximizeStrips, 4, 1, 1, 1)
|
||||
|
||||
self.authorEdit = QLineEdit(self.optionWidget)
|
||||
self.authorEdit.setObjectName(u"authorEdit")
|
||||
sizePolicy = QSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Fixed)
|
||||
@@ -133,11 +107,48 @@ class Ui_mainWindow(object):
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.authorEdit.sizePolicy().hasHeightForWidth())
|
||||
self.authorEdit.setSizePolicy(sizePolicy)
|
||||
self.authorEdit.setFocusPolicy(Qt.ClickFocus)
|
||||
self.authorEdit.setFocusPolicy(Qt.FocusPolicy.ClickFocus)
|
||||
self.authorEdit.setClearButtonEnabled(False)
|
||||
|
||||
self.gridLayout_2.addWidget(self.authorEdit, 0, 0, 1, 1)
|
||||
|
||||
self.deleteBox = QCheckBox(self.optionWidget)
|
||||
self.deleteBox.setObjectName(u"deleteBox")
|
||||
|
||||
self.gridLayout_2.addWidget(self.deleteBox, 5, 1, 1, 1)
|
||||
|
||||
self.mozJpegBox = QCheckBox(self.optionWidget)
|
||||
self.mozJpegBox.setObjectName(u"mozJpegBox")
|
||||
self.mozJpegBox.setTristate(True)
|
||||
|
||||
self.gridLayout_2.addWidget(self.mozJpegBox, 4, 0, 1, 1)
|
||||
|
||||
self.spreadShiftBox = QCheckBox(self.optionWidget)
|
||||
self.spreadShiftBox.setObjectName(u"spreadShiftBox")
|
||||
|
||||
self.gridLayout_2.addWidget(self.spreadShiftBox, 5, 0, 1, 1)
|
||||
|
||||
self.upscaleBox = QCheckBox(self.optionWidget)
|
||||
self.upscaleBox.setObjectName(u"upscaleBox")
|
||||
self.upscaleBox.setTristate(True)
|
||||
|
||||
self.gridLayout_2.addWidget(self.upscaleBox, 2, 1, 1, 1)
|
||||
|
||||
self.outputSplit = QCheckBox(self.optionWidget)
|
||||
self.outputSplit.setObjectName(u"outputSplit")
|
||||
|
||||
self.gridLayout_2.addWidget(self.outputSplit, 3, 1, 1, 1)
|
||||
|
||||
self.noRotateBox = QCheckBox(self.optionWidget)
|
||||
self.noRotateBox.setObjectName(u"noRotateBox")
|
||||
|
||||
self.gridLayout_2.addWidget(self.noRotateBox, 6, 1, 1, 1)
|
||||
|
||||
self.reduceRainbowBox = QCheckBox(self.optionWidget)
|
||||
self.reduceRainbowBox.setObjectName(u"reduceRainbowBox")
|
||||
|
||||
self.gridLayout_2.addWidget(self.reduceRainbowBox, 7, 2, 1, 1)
|
||||
|
||||
|
||||
self.gridLayout.addWidget(self.optionWidget, 5, 0, 1, 2)
|
||||
|
||||
@@ -156,7 +167,7 @@ class Ui_mainWindow(object):
|
||||
self.gammaSlider.setObjectName(u"gammaSlider")
|
||||
self.gammaSlider.setMaximum(250)
|
||||
self.gammaSlider.setSingleStep(5)
|
||||
self.gammaSlider.setOrientation(Qt.Horizontal)
|
||||
self.gammaSlider.setOrientation(Qt.Orientation.Horizontal)
|
||||
|
||||
self.horizontalLayout_2.addWidget(self.gammaSlider)
|
||||
|
||||
@@ -178,7 +189,7 @@ class Ui_mainWindow(object):
|
||||
self.croppingPowerSlider.setObjectName(u"croppingPowerSlider")
|
||||
self.croppingPowerSlider.setMaximum(300)
|
||||
self.croppingPowerSlider.setSingleStep(1)
|
||||
self.croppingPowerSlider.setOrientation(Qt.Horizontal)
|
||||
self.croppingPowerSlider.setOrientation(Qt.Orientation.Horizontal)
|
||||
|
||||
self.horizontalLayout_3.addWidget(self.croppingPowerSlider)
|
||||
|
||||
@@ -284,9 +295,9 @@ class Ui_mainWindow(object):
|
||||
self.jobList = QListWidget(self.centralWidget)
|
||||
self.jobList.setObjectName(u"jobList")
|
||||
self.jobList.setStyleSheet(u"")
|
||||
self.jobList.setSelectionMode(QAbstractItemView.NoSelection)
|
||||
self.jobList.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel)
|
||||
self.jobList.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel)
|
||||
self.jobList.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection)
|
||||
self.jobList.setVerticalScrollMode(QAbstractItemView.ScrollMode.ScrollPerPixel)
|
||||
self.jobList.setHorizontalScrollMode(QAbstractItemView.ScrollMode.ScrollPerPixel)
|
||||
|
||||
self.gridLayout.addWidget(self.jobList, 2, 0, 1, 2)
|
||||
|
||||
@@ -295,7 +306,7 @@ class Ui_mainWindow(object):
|
||||
self.progressBar.setMinimumSize(QSize(0, 30))
|
||||
self.progressBar.setFont(font)
|
||||
self.progressBar.setVisible(False)
|
||||
self.progressBar.setAlignment(Qt.AlignJustify|Qt.AlignVCenter)
|
||||
self.progressBar.setAlignment(Qt.AlignmentFlag.AlignJustify|Qt.AlignmentFlag.AlignVCenter)
|
||||
|
||||
self.gridLayout.addWidget(self.progressBar, 1, 0, 1, 2)
|
||||
|
||||
@@ -377,61 +388,37 @@ class Ui_mainWindow(object):
|
||||
def retranslateUi(self, mainWindow):
|
||||
mainWindow.setWindowTitle(QCoreApplication.translate("mainWindow", u"Kindle Comic Converter", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.deleteBox.setToolTip(QCoreApplication.translate("mainWindow", u"Delete input file(s) or directory. It's not recoverable!", None))
|
||||
self.croppingBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Disabled</span></p><p>Disabled</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Margins<br/></span>Margins</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Margins + page numbers<br/></span>Margins +page numbers</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.deleteBox.setText(QCoreApplication.translate("mainWindow", u"Delete input", None))
|
||||
self.croppingBox.setText(QCoreApplication.translate("mainWindow", u"Cropping mode", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.mangaBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Enable right-to-left reading.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.mangaBox.setText(QCoreApplication.translate("mainWindow", u"Manga mode", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.outputSplit.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Automatic mode<br/></span>The output will be split automatically.</p><p style='white-space:pre'><span style=\" font-weight:600; text-decoration: underline;\">Checked - Volume mode<br/></span>Every subdirectory will be considered as a separate volume.</p></body></html>", None))
|
||||
self.webtoonBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Enable special parsing mode for Korean Webtoons.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.outputSplit.setText(QCoreApplication.translate("mainWindow", u"Output split", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.croppingBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Disabled</span></p><p>Disabled</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Margins<br/></span>Margins</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Margins + page numbers<br/></span>Margins +page numbers</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.croppingBox.setText(QCoreApplication.translate("mainWindow", u"Cropping mode", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.mozJpegBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - JPEG<br/></span>Use JPEG files</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - force PNG<br/></span>Create PNG files instead JPEG</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - mozJpeg<br/></span>10-20% smaller JPEG file, with the same image quality, but processing time multiplied by 2</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.mozJpegBox.setText(QCoreApplication.translate("mainWindow", u"JPEG/PNG/mozJpeg", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.upscaleBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Nothing<br/></span>Images smaller than device resolution will not be resized.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Stretching<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be not preserved.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Upscaling<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be preserved.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.upscaleBox.setText(QCoreApplication.translate("mainWindow", u"Stretch/Upscale", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.colorBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Disable conversion to grayscale.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.colorBox.setText(QCoreApplication.translate("mainWindow", u"Color mode", None))
|
||||
self.webtoonBox.setText(QCoreApplication.translate("mainWindow", u"Webtoon mode", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.rotateBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Split<br/></span>Double page spreads will be cut into two separate pages.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Rotate and split<br/></span>Double page spreads will be displayed twice. First rotated and then split. </p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Rotate<br/></span>Double page spreads will be rotated.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.rotateBox.setText(QCoreApplication.translate("mainWindow", u"Spread splitter", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.gammaBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Disable automatic gamma correction.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.gammaBox.setText(QCoreApplication.translate("mainWindow", u"Custom gamma", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.spreadShiftBox.setToolTip(QCoreApplication.translate("mainWindow", u"Shift first page to opposite side in landscape for two page spread alignment", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.spreadShiftBox.setText(QCoreApplication.translate("mainWindow", u"Spread shift", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.webtoonBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Enable special parsing mode for Korean Webtoons.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.webtoonBox.setText(QCoreApplication.translate("mainWindow", u"Webtoon mode", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.maximizeStrips.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - 1x4<br/></span>Keep format 1x4 panels strips.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - 2x2<br/></span>Turn 1x4 strips to 2x2 to maximize screen usage.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.maximizeStrips.setText(QCoreApplication.translate("mainWindow", u"1x4 to 2x2 strips", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.borderBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Autodetection<br/></span>The color of margins fill will be detected automatically.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - White<br/></span>Margins will be filled with white color.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Black<br/></span>Margins will be filled with black color.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.borderBox.setText(QCoreApplication.translate("mainWindow", u"W/B margins", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.noRotateBox.setToolTip(QCoreApplication.translate("mainWindow", u"Do not rotate double page spreads in spread splitter option.", None))
|
||||
self.gammaBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Disable automatic gamma correction.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.noRotateBox.setText(QCoreApplication.translate("mainWindow", u"No rotate", None))
|
||||
self.gammaBox.setText(QCoreApplication.translate("mainWindow", u"Custom gamma", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.interPanelCropBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Disabled<br/></span>Disabled</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Horizontal<br/></span>Crop empty horizontal lines.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Both<br/></span>Crop empty horizontal and vertical lines.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.interPanelCropBox.setText(QCoreApplication.translate("mainWindow", u"Inter-panel crop", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.colorBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Disable conversion to grayscale.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.colorBox.setText(QCoreApplication.translate("mainWindow", u"Color mode", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.qualityBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - 4 panels<br/></span>Zoom each corner separately.</p><p style='white-space:pre'><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - 2 panels<br/></span>Zoom only the top and bottom of the page.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - 4 high-quality panels<br/></span>Zoom each corner separately. Try to increase the quality of magnification. Check wiki for more details.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
@@ -440,10 +427,42 @@ class Ui_mainWindow(object):
|
||||
self.disableProcessingBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><pre style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Do not process any image, ignore profile and processing options</pre></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.disableProcessingBox.setText(QCoreApplication.translate("mainWindow", u"Disable processing", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.maximizeStrips.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - 1x4<br/></span>Keep format 1x4 panels strips.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - 2x2<br/></span>Turn 1x4 strips to 2x2 to maximize screen usage.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.maximizeStrips.setText(QCoreApplication.translate("mainWindow", u"1x4 to 2x2 strips", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.authorEdit.setToolTip(QCoreApplication.translate("mainWindow", u"Default Author is KCC", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.authorEdit.setPlaceholderText(QCoreApplication.translate("mainWindow", u"Default Author", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.deleteBox.setToolTip(QCoreApplication.translate("mainWindow", u"Delete input file(s) or directory. It's not recoverable!", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.deleteBox.setText(QCoreApplication.translate("mainWindow", u"Delete input", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.mozJpegBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - JPEG<br/></span>Use JPEG files</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - force PNG<br/></span>Create PNG files instead JPEG</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - mozJpeg<br/></span>10-20% smaller JPEG file, with the same image quality, but processing time multiplied by 2</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.mozJpegBox.setText(QCoreApplication.translate("mainWindow", u"JPEG/PNG/mozJpeg", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.spreadShiftBox.setToolTip(QCoreApplication.translate("mainWindow", u"Shift first page to opposite side in landscape for two page spread alignment", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.spreadShiftBox.setText(QCoreApplication.translate("mainWindow", u"Spread shift", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.upscaleBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Nothing<br/></span>Images smaller than device resolution will not be resized.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Stretching<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be not preserved.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Upscaling<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be preserved.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.upscaleBox.setText(QCoreApplication.translate("mainWindow", u"Stretch/Upscale", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.outputSplit.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Automatic mode<br/></span>The output will be split automatically.</p><p style='white-space:pre'><span style=\" font-weight:600; text-decoration: underline;\">Checked - Volume mode<br/></span>Every subdirectory will be considered as a separate volume.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.outputSplit.setText(QCoreApplication.translate("mainWindow", u"Output split", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.noRotateBox.setToolTip(QCoreApplication.translate("mainWindow", u"Do not rotate double page spreads in spread splitter option.", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.noRotateBox.setText(QCoreApplication.translate("mainWindow", u"No rotate", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.reduceRainbowBox.setToolTip(QCoreApplication.translate("mainWindow", u"Reduce rainbow effect on color eink by slightly blurring images", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.reduceRainbowBox.setText(QCoreApplication.translate("mainWindow", u"Reduce Rainbow", None))
|
||||
self.gammaLabel.setText(QCoreApplication.translate("mainWindow", u"Gamma: Auto", None))
|
||||
self.croppingPowerLabel.setText(QCoreApplication.translate("mainWindow", u"Cropping power:", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
__version__ = '7.1.2'
|
||||
__version__ = '7.2.1'
|
||||
__license__ = 'ISC'
|
||||
__copyright__ = '2012-2022, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>, darodi'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
@@ -612,8 +612,11 @@ def imgFileProcessing(work):
|
||||
img.cropPageNumber(opt.croppingp, opt.croppingm)
|
||||
if opt.cropping > 0 and not opt.webtoon:
|
||||
img.cropMargin(opt.croppingp, opt.croppingm)
|
||||
if opt.interpanelcrop > 0:
|
||||
img.cropInterPanelEmptySections("horizontal" if opt.interpanelcrop == 1 else "both")
|
||||
img.autocontrastImage()
|
||||
img.resizeImage()
|
||||
img.optimizeForDisplay(opt.reducerainbow)
|
||||
if opt.forcepng and not opt.forcecolor:
|
||||
img.quantizeImage()
|
||||
output.append(img.saveToDir())
|
||||
@@ -626,7 +629,7 @@ def getWorkFolder(afile):
|
||||
if os.path.isdir(afile):
|
||||
if disk_usage(gettempdir())[2] < getDirectorySize(afile) * 2.5:
|
||||
raise UserWarning("Not enough disk space to perform conversion.")
|
||||
workdir = mkdtemp('', 'KCC-')
|
||||
workdir = mkdtemp('', 'KCC-', os.path.dirname(afile))
|
||||
try:
|
||||
os.rmdir(workdir)
|
||||
fullPath = os.path.join(workdir, 'OEBPS', 'Images')
|
||||
@@ -642,26 +645,37 @@ def getWorkFolder(afile):
|
||||
if afile.lower().endswith('.pdf'):
|
||||
pdf = pdfjpgextract.PdfJpgExtract(afile)
|
||||
path, njpg = pdf.extract()
|
||||
workdir = path
|
||||
sanitizePermissions(path)
|
||||
if njpg == 0:
|
||||
rmtree(path, True)
|
||||
raise UserWarning("Failed to extract images from PDF file.")
|
||||
else:
|
||||
workdir = mkdtemp('', 'KCC-')
|
||||
workdir = mkdtemp('', 'KCC-', os.path.dirname(afile))
|
||||
try:
|
||||
cbx = comicarchive.ComicArchive(afile)
|
||||
path = cbx.extract(workdir)
|
||||
sanitizePermissions(path)
|
||||
tdir = os.listdir(workdir)
|
||||
if 'ComicInfo.xml' in tdir:
|
||||
tdir.remove('ComicInfo.xml')
|
||||
is_nested_single_dir = False
|
||||
if len(tdir) == 2 and 'ComicInfo.xml' in tdir:
|
||||
tdir.remove('ComicInfo.xml')
|
||||
is_nested_single_dir = os.path.isdir(os.path.join(workdir, tdir[0]))
|
||||
if is_nested_single_dir:
|
||||
os.replace(
|
||||
os.path.join(workdir, 'ComicInfo.xml'),
|
||||
os.path.join(workdir, tdir[0], 'ComicInfo.xml')
|
||||
)
|
||||
if len(tdir) == 1 and is_nested_single_dir:
|
||||
path = os.path.join(workdir, tdir[0])
|
||||
except OSError as e:
|
||||
rmtree(workdir, True)
|
||||
raise UserWarning(e)
|
||||
else:
|
||||
raise UserWarning("Failed to open source file/directory.")
|
||||
sanitizePermissions(path)
|
||||
newpath = mkdtemp('', 'KCC-')
|
||||
newpath = mkdtemp('', 'KCC-', os.path.dirname(afile))
|
||||
copytree(path, os.path.join(newpath, 'OEBPS', 'Images'))
|
||||
rmtree(path, True)
|
||||
rmtree(workdir, True)
|
||||
return newpath
|
||||
|
||||
|
||||
@@ -815,12 +829,11 @@ def sanitizePermissions(filetree):
|
||||
os.chmod(os.path.join(root, name), S_IWRITE | S_IREAD | S_IEXEC)
|
||||
|
||||
|
||||
def splitDirectory(path):
|
||||
def chunk_directory(path):
|
||||
level = -1
|
||||
for root, _, files in os.walk(os.path.join(path, 'OEBPS', 'Images')):
|
||||
for f in files:
|
||||
if f.endswith('.jpg') or f.endswith('.jpeg') or f.endswith('.png') or f.endswith('.gif') or \
|
||||
f.endswith('.webp'):
|
||||
if getImageFileName(f):
|
||||
newLevel = os.path.join(root, f).replace(os.path.join(path, 'OEBPS', 'Images'), '').count(os.sep)
|
||||
if level != -1 and level != newLevel:
|
||||
level = 0
|
||||
@@ -828,16 +841,17 @@ def splitDirectory(path):
|
||||
else:
|
||||
level = newLevel
|
||||
if level > 0:
|
||||
splitter = splitProcess(os.path.join(path, 'OEBPS', 'Images'), level)
|
||||
parent = pathlib.Path(path).parent
|
||||
chunker = chunk_process(os.path.join(path, 'OEBPS', 'Images'), level, parent)
|
||||
path = [path]
|
||||
for tome in splitter:
|
||||
for tome in chunker:
|
||||
path.append(tome)
|
||||
return path
|
||||
else:
|
||||
raise UserWarning('Unsupported directory structure.')
|
||||
|
||||
|
||||
def splitProcess(path, mode):
|
||||
def chunk_process(path, mode, parent):
|
||||
output = []
|
||||
currentSize = 0
|
||||
currentTarget = path
|
||||
@@ -857,7 +871,7 @@ def splitProcess(path, mode):
|
||||
else:
|
||||
size = getDirectorySize(os.path.join(root, name))
|
||||
if currentSize + size > targetSize:
|
||||
currentTarget, pathRoot = createNewTome()
|
||||
currentTarget, pathRoot = createNewTome(parent)
|
||||
output.append(pathRoot)
|
||||
currentSize = size
|
||||
else:
|
||||
@@ -869,7 +883,7 @@ def splitProcess(path, mode):
|
||||
for root, dirs, _ in walkLevel(path, 0):
|
||||
for name in dirs:
|
||||
if not firstTome:
|
||||
currentTarget, pathRoot = createNewTome()
|
||||
currentTarget, pathRoot = createNewTome(parent)
|
||||
output.append(pathRoot)
|
||||
move(os.path.join(root, name), os.path.join(currentTarget, name))
|
||||
else:
|
||||
@@ -906,7 +920,10 @@ def detectCorruption(tmppath, orgpath):
|
||||
else:
|
||||
raise RuntimeError('Image file %s is corrupted. Error: %s' % (pathOrg, str(err)))
|
||||
else:
|
||||
os.remove(os.path.join(root, name))
|
||||
try:
|
||||
os.remove(os.path.join(root, name))
|
||||
except OSError as e:
|
||||
raise RuntimeError(f"{name}: {e}")
|
||||
if alreadyProcessed:
|
||||
print("WARNING: Source files are probably created by KCC. The second conversion will decrease quality.")
|
||||
if GUI:
|
||||
@@ -922,8 +939,8 @@ def detectCorruption(tmppath, orgpath):
|
||||
GUI.addMessage.emit('', '', False)
|
||||
|
||||
|
||||
def createNewTome():
|
||||
tomePathRoot = mkdtemp('', 'KCC-')
|
||||
def createNewTome(parent):
|
||||
tomePathRoot = mkdtemp('', 'KCC-', parent)
|
||||
tomePath = os.path.join(tomePathRoot, 'OEBPS', 'Images')
|
||||
os.makedirs(tomePath)
|
||||
return tomePath, tomePathRoot
|
||||
@@ -1013,12 +1030,16 @@ def makeParser():
|
||||
help="Set cropping power [Default=1.0]")
|
||||
processing_options.add_argument("--cm", "--croppingminimum", type=float, dest="croppingm", default="0.0",
|
||||
help="Set cropping minimum area ratio [Default=0.0]")
|
||||
processing_options.add_argument("--ipc", "--interpanelcrop", type=int, dest="interpanelcrop", default="0",
|
||||
help="Crop empty sections. 0: Disabled 1: Horizontally 2: Both [Default=0]")
|
||||
processing_options.add_argument("--blackborders", action="store_true", dest="black_borders", default=False,
|
||||
help="Disable autodetection and force black borders")
|
||||
processing_options.add_argument("--whiteborders", action="store_true", dest="white_borders", default=False,
|
||||
help="Disable autodetection and force white borders")
|
||||
processing_options.add_argument("--forcecolor", action="store_true", dest="forcecolor", default=False,
|
||||
help="Don't convert images to grayscale")
|
||||
output_options.add_argument("--reducerainbow", action="store_true", dest="reducerainbow", default=False,
|
||||
help="Reduce rainbow effect on color eink by slightly blurring images.")
|
||||
processing_options.add_argument("--forcepng", action="store_true", dest="forcepng", default=False,
|
||||
help="Create PNG files instead JPEG")
|
||||
processing_options.add_argument("--mozjpeg", action="store_true", dest="mozjpeg", default=False,
|
||||
@@ -1175,7 +1196,7 @@ def makeBook(source, qtgui=None):
|
||||
GUI.progressBarTick.emit('1')
|
||||
chapterNames = sanitizeTree(os.path.join(path, 'OEBPS', 'Images'))
|
||||
if options.batchsplit > 0:
|
||||
tomes = splitDirectory(path)
|
||||
tomes = chunk_directory(path)
|
||||
else:
|
||||
tomes = [path]
|
||||
filepath = []
|
||||
|
||||
28
kindlecomicconverter/common_crop.py
Normal file
28
kindlecomicconverter/common_crop.py
Normal file
@@ -0,0 +1,28 @@
|
||||
def threshold_from_power(power):
|
||||
return 240-(power*64)
|
||||
|
||||
|
||||
'''
|
||||
Groups close values together
|
||||
'''
|
||||
def group_close_values(vals, max_dist_tolerated):
|
||||
groups = []
|
||||
|
||||
group_start = -1
|
||||
group_end = 0
|
||||
for i in range(len(vals)):
|
||||
dist = vals[i] - group_end
|
||||
if group_start == -1:
|
||||
group_start = vals[i]
|
||||
group_end = vals[i]
|
||||
elif dist <= max_dist_tolerated:
|
||||
group_end = vals[i]
|
||||
else:
|
||||
groups.append((group_start, group_end))
|
||||
group_start = -1
|
||||
group_end = -1
|
||||
|
||||
if group_start != -1:
|
||||
groups.append((group_start, group_end))
|
||||
|
||||
return groups
|
||||
@@ -24,6 +24,7 @@ import mozjpeg_lossless_optimization
|
||||
from PIL import Image, ImageOps, ImageStat, ImageChops, ImageFilter
|
||||
from .shared import md5Checksum
|
||||
from .page_number_crop_alg import get_bbox_crop_margin_page_number, get_bbox_crop_margin
|
||||
from .inter_panel_crop_alg import crop_empty_inter_panel
|
||||
|
||||
AUTO_CROP_THRESHOLD = 0.015
|
||||
|
||||
@@ -340,6 +341,14 @@ class ComicPage:
|
||||
# Quantize is deprecated but new function call it internally anyway...
|
||||
self.image = self.image.quantize(palette=palImg)
|
||||
|
||||
def optimizeForDisplay(self, reducerainbow):
|
||||
# Reduce rainbow artifacts for grayscale images by breaking up dither patterns that cause Moire interference with color filter array
|
||||
if reducerainbow and not self.color:
|
||||
unsharpFilter = ImageFilter.UnsharpMask(radius=1, percent=100)
|
||||
self.image = self.image.filter(unsharpFilter)
|
||||
self.image = self.image.filter(ImageFilter.BoxBlur(1.0))
|
||||
self.image = self.image.filter(unsharpFilter)
|
||||
|
||||
def resizeImage(self):
|
||||
# kindle scribe conversion to mobi is limited in resolution by kindlegen, same with send to kindle and epub
|
||||
if self.kindle_scribe_azw3:
|
||||
@@ -390,6 +399,8 @@ class ComicPage:
|
||||
if bbox:
|
||||
self.maybeCrop(bbox, minimum)
|
||||
|
||||
def cropInterPanelEmptySections(self, direction):
|
||||
self.image = crop_empty_inter_panel(self.image, direction, background_color=self.fill)
|
||||
|
||||
class Cover:
|
||||
def __init__(self, source, target, opt, tomeid):
|
||||
|
||||
76
kindlecomicconverter/inter_panel_crop_alg.py
Normal file
76
kindlecomicconverter/inter_panel_crop_alg.py
Normal file
@@ -0,0 +1,76 @@
|
||||
from PIL import Image, ImageFilter, ImageOps
|
||||
import numpy as np
|
||||
from typing import Literal
|
||||
from .common_crop import threshold_from_power, group_close_values
|
||||
|
||||
|
||||
'''
|
||||
Crops inter-panel empty spaces (ignores empty spaces near borders - for that use crop margins).
|
||||
|
||||
Parameters:
|
||||
img (PIL image): A PIL image.
|
||||
direction (horizontal or vertical or both): To crop rows (horizontal), cols (vertical) or both.
|
||||
keep (float): Distance to keep between panels after cropping (in percentage relative to the original distance).
|
||||
background_color (string): 'white' for white background, anything else for black.
|
||||
Returns:
|
||||
img (PIL image): A PIL image after cropping empty sections.
|
||||
'''
|
||||
def crop_empty_inter_panel(img, direction: Literal["horizontal", "vertical", "both"], keep=0.04, background_color='white'):
|
||||
img_temp = img
|
||||
|
||||
if img.mode != 'L':
|
||||
img_temp = ImageOps.grayscale(img)
|
||||
|
||||
if background_color != 'white':
|
||||
img_temp = ImageOps.invert(img)
|
||||
|
||||
img_mat = np.array(img)
|
||||
|
||||
power = 1
|
||||
img_temp = ImageOps.autocontrast(img_temp, 1).filter(ImageFilter.BoxBlur(1))
|
||||
img_temp = img_temp.point(lambda p: 255 if p <= threshold_from_power(power) else 0)
|
||||
|
||||
if direction in ["horizontal", "both"]:
|
||||
rows_idx_to_remove = empty_sections(img_temp, keep, horizontal=True)
|
||||
img_mat = np.delete(img_mat, rows_idx_to_remove, 0)
|
||||
|
||||
if direction in ["vertical", "both"]:
|
||||
cols_idx_to_remove = empty_sections(img_temp, keep, horizontal=False)
|
||||
img_mat = np.delete(img_mat, cols_idx_to_remove, 1)
|
||||
|
||||
return Image.fromarray(img_mat)
|
||||
|
||||
|
||||
'''
|
||||
Finds empty sections (excluding near borders).
|
||||
|
||||
Parameters:
|
||||
img (PIL image): A PIL image.
|
||||
keep (float): Distance to keep between panels after cropping (in percentage relative to the original distance).
|
||||
horizontal (boolean): True to find empty rows, False to find empty columns.
|
||||
Returns:
|
||||
Itertable (list or NumPy array): indices of rows or columns to remove.
|
||||
'''
|
||||
def empty_sections(img, keep, horizontal=True):
|
||||
axis = 1 if horizontal else 0
|
||||
|
||||
img_mat = np.array(img)
|
||||
img_mat_max = np.max(img_mat, axis=axis)
|
||||
img_mat_empty_idx = np.where(img_mat_max == 0)[0]
|
||||
|
||||
empty_sections = group_close_values(img_mat_empty_idx, 1)
|
||||
sections_to_remove = []
|
||||
for section in empty_sections:
|
||||
if section[1] < img.size[1] * 0.99 and section[0] > img.size[1] * 0.01: # if not near borders
|
||||
sections_to_remove.append(section)
|
||||
|
||||
if len(sections_to_remove) != 0:
|
||||
sections_to_remove_after_keep = [(int(x1+(keep/2)*(x2-x1)), int(x2-(keep/2)*(x2-x1))) for x1,x2 in sections_to_remove]
|
||||
idx_to_remove = np.concatenate([np.arange(x1, x2) for x1,x2 in sections_to_remove_after_keep])
|
||||
|
||||
return idx_to_remove
|
||||
|
||||
return []
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
from PIL import ImageOps, ImageFilter
|
||||
import numpy as np
|
||||
from .common_crop import threshold_from_power, group_close_values
|
||||
|
||||
|
||||
'''
|
||||
Some assupmptions on the page number sizes
|
||||
@@ -51,12 +53,11 @@ def get_bbox_crop_margin_page_number(img, power=1, background_color='white'):
|
||||
threshold = threshold_from_power(power)
|
||||
bw_img = img.point(lambda p: 255 if p <= threshold else 0)
|
||||
bw_bbox = bw_img.getbbox()
|
||||
|
||||
if not bw_bbox: # bbox cannot be found in case that the entire resulted image is black.
|
||||
return None
|
||||
|
||||
left, top_y_pos, right, bot_y_pos = bw_bbox
|
||||
|
||||
|
||||
'''
|
||||
We inspect the lower bottom part of the image where we suspect might be a page number.
|
||||
We assume that page number consist of 1 to 3 digits and the total min and max size of the number
|
||||
@@ -73,7 +74,7 @@ def get_bbox_crop_margin_page_number(img, power=1, background_color='white'):
|
||||
img_part_mat = np.array(img_part)
|
||||
window_groups = []
|
||||
for i in range(img_part.size[1]):
|
||||
row_groups = [(g[0], g[1], i, i) for g in group_pixels(img_part_mat[i], img.size[0]*max_dist_size[0], threshold)]
|
||||
row_groups = [(g[0], g[1], i, i) for g in group_close_values(np.where(img_part_mat[i] <= threshold)[0], img.size[0]*max_dist_size[0])]
|
||||
window_groups.extend(row_groups)
|
||||
|
||||
window_groups = np.array(window_groups)
|
||||
@@ -109,7 +110,6 @@ def get_bbox_crop_margin_page_number(img, power=1, background_color='white'):
|
||||
cropped_bbox = (0, 0, img.size[0], bot_y_pos-(window_h-boxes_in_same_y_range[0][2]+1))
|
||||
|
||||
cropped_bbox = bw_img.crop(cropped_bbox).getbbox()
|
||||
|
||||
return cropped_bbox
|
||||
|
||||
|
||||
@@ -145,33 +145,6 @@ def get_bbox_crop_margin(img, power=1, background_color='white'):
|
||||
return bw_img.getbbox()
|
||||
|
||||
|
||||
'''
|
||||
Groups close pixels together (x axis)
|
||||
'''
|
||||
def group_pixels(row, max_dist_tolerated, threshold):
|
||||
groups = []
|
||||
idx = np.where(row <= threshold)[0]
|
||||
|
||||
group_start = -1
|
||||
group_end = 0
|
||||
for i in range(len(idx)):
|
||||
dist = idx[i] - group_end
|
||||
if group_start == -1:
|
||||
group_start = idx[i]
|
||||
group_end = idx[i]
|
||||
elif dist <= max_dist_tolerated:
|
||||
group_end = idx[i]
|
||||
else:
|
||||
groups.append((group_start, group_end))
|
||||
group_start = -1
|
||||
group_end = -1
|
||||
|
||||
if group_start != -1:
|
||||
groups.append((group_start, group_end))
|
||||
|
||||
return groups
|
||||
|
||||
|
||||
def box_intersect(box1, box2, max_dist):
|
||||
return not (box2[0]-max_dist[0] > box1[1]
|
||||
or box2[1]+max_dist[0] < box1[0]
|
||||
@@ -209,7 +182,3 @@ def merge_boxes(boxes, max_dist_tolerated):
|
||||
else:
|
||||
j += 1
|
||||
return boxes
|
||||
|
||||
|
||||
def threshold_from_power(power):
|
||||
return 240-(power*64)
|
||||
@@ -49,7 +49,7 @@ class HTMLStripper(HTMLParser):
|
||||
def getImageFileName(imgfile):
|
||||
name, ext = os.path.splitext(imgfile)
|
||||
ext = ext.lower()
|
||||
if (name.startswith('.') and len(name) == 1) or ext not in ['.png', '.jpg', '.jpeg', '.gif', '.webp']:
|
||||
if (name.startswith('.') and len(name) == 1) or ext not in ['.png', '.jpg', '.jpeg', '.gif', '.webp', '.jp2', '.j2k', '.jpx']:
|
||||
return None
|
||||
return [name, ext]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user