mirror of
https://github.com/ciromattia/kcc
synced 2026-04-17 06:28:49 +00:00
Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9b63b7af2c | ||
|
|
f74e108a3e | ||
|
|
f088ad732e | ||
|
|
8e5d57364d | ||
|
|
b767d5dc2c | ||
|
|
7228055bca | ||
|
|
8c57fbf318 | ||
|
|
7e94861fa1 | ||
|
|
9992ca4d26 | ||
|
|
f47d1427f0 | ||
|
|
ce8998375c | ||
|
|
8870898a87 | ||
|
|
a017cfd00d | ||
|
|
3f4ef3e21e | ||
|
|
4733c6348b | ||
|
|
5ad23d9629 | ||
|
|
db4eb78963 | ||
|
|
988fc93dc5 | ||
|
|
74fee9346c | ||
|
|
9fcacd7ae6 | ||
|
|
8ac58e361f | ||
|
|
61d6972e22 | ||
|
|
c7c1557e72 | ||
|
|
cb93704e08 | ||
|
|
62c5183609 | ||
|
|
a629f267a1 | ||
|
|
aeec4dd294 | ||
|
|
0d3076465b |
2
.github/workflows/package-linux.yml
vendored
2
.github/workflows/package-linux.yml
vendored
@@ -59,7 +59,7 @@ jobs:
|
||||
env:
|
||||
UPDATE_INFO: gh-releases-zsync|ciromattia|kcc|latest|*x86_64.AppImage.zsync
|
||||
- name: upload artifact
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: AppImage
|
||||
path: './*.AppImage*'
|
||||
|
||||
6
.github/workflows/package-macos.yml
vendored
6
.github/workflows/package-macos.yml
vendored
@@ -25,8 +25,10 @@ jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ macos-13, macos-14 ]
|
||||
os: [ macos-15-intel, macos-14 ]
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
MACOSX_DEPLOYMENT_TARGET: '14.0'
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- name: Set up Python
|
||||
@@ -78,7 +80,7 @@ jobs:
|
||||
run: |
|
||||
python setup.py build_binary
|
||||
- name: upload build
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: mac-os-build-${{ runner.arch }}
|
||||
path: dist/*.dmg
|
||||
|
||||
4
.github/workflows/package-osx-legacy.yml
vendored
4
.github/workflows/package-osx-legacy.yml
vendored
@@ -23,7 +23,7 @@ jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ macos-13 ]
|
||||
os: [ macos-15-intel ]
|
||||
runs-on: ${{ matrix.os }}
|
||||
env:
|
||||
# We need the official Python, because the GA ones only support newer macOS versions
|
||||
@@ -51,7 +51,7 @@ jobs:
|
||||
run: |
|
||||
python3 setup.py build_binary
|
||||
- name: upload build
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: osx-build-${{ runner.arch }}
|
||||
path: dist/*.dmg
|
||||
|
||||
2
.github/workflows/package-windows.yml
vendored
2
.github/workflows/package-windows.yml
vendored
@@ -53,7 +53,7 @@ jobs:
|
||||
python setup.py ${{ matrix.command }}
|
||||
- name: upload-unsigned-artifact
|
||||
id: upload-unsigned-artifact
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: windows-build-${{ matrix.entry }}
|
||||
path: dist/*.exe
|
||||
|
||||
2
.github/workflows/package-windows7.yml
vendored
2
.github/workflows/package-windows7.yml
vendored
@@ -46,7 +46,7 @@ jobs:
|
||||
python setup.py build_binary
|
||||
- name: upload-unsigned-artifact
|
||||
id: upload-unsigned-artifact
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: windows7-build
|
||||
path: dist/*.exe
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
[](https://github.com/ciromattia/kcc/releases)
|
||||
|
||||
|
||||
**Kindle Comic Converter** optimizes black & white comics and manga for E-ink ereaders
|
||||
**Kindle Comic Converter** optimizes black & white (or color) comics and manga for E-ink ereaders
|
||||
like Kindle, Kobo, ReMarkable, and more.
|
||||
Pages display in fullscreen without margins,
|
||||
with proper fixed layout support.
|
||||
@@ -92,7 +92,7 @@ Click on **Assets** of the latest release.
|
||||
You probably want either
|
||||
- `KCC_*.*.*.exe` (Windows)
|
||||
- `kcc_macos_arm_*.*.*.dmg` (recent Mac with Apple Silicon M1 chip or later)
|
||||
- `kcc_macos_i386_*.*.*.dmg` (older Mac with Intel chip macOS 12+)
|
||||
- `kcc_macos_i386_*.*.*.dmg` (older Mac with Intel chip macOS 14+)
|
||||
|
||||
There are also legacy macOS 10.14+ and Windows 7 experimental versions available.
|
||||
|
||||
@@ -318,6 +318,7 @@ Depending on your system [Python](https://www.python.org) may be called either `
|
||||
If you want to edit the code, a good code editor is [VS Code](https://code.visualstudio.com).
|
||||
|
||||
If you want to edit the `.ui` files, use `pyside6-designer` which is included in the `pip install pyside6`.
|
||||
If new objects have been added, verify that correct tab order has been applied by using [Tab Order Editing Mode](https://doc.qt.io/qt-6/designer-tab-order.html).
|
||||
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
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
name: kcc
|
||||
channels:
|
||||
- conda-forge
|
||||
- defaults
|
||||
dependencies:
|
||||
- python=3.11
|
||||
- Pillow>=11.3.0
|
||||
- psutil>=5.9.5
|
||||
- python-slugify>=1.2.1
|
||||
- raven>=6.0.0
|
||||
- distro
|
||||
- natsort>=8.4.0
|
||||
- pip
|
||||
- pip:
|
||||
- mozjpeg-lossless-optimization>=1.1.2
|
||||
- pyside6>=6.5.1
|
||||
117
gui/KCC.ui
117
gui/KCC.ui
@@ -7,7 +7,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>566</width>
|
||||
<height>573</height>
|
||||
<height>581</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -348,6 +348,51 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QWidget" name="outputFolderWidget" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<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><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></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Output Folder</string>
|
||||
</property>
|
||||
<property name="tristate">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="defaultOutputFolderButton">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>30</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Use this to select the default output directory.</p></body></html></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>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -747,7 +792,7 @@
|
||||
<string><html><head/><body><p style='white-space:pre'>Add CBR, CBZ, CB7 or PDF file to queue.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Add file(s)</string>
|
||||
<string>Add input file(s)</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="KCC.qrc">
|
||||
@@ -755,19 +800,19 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="5">
|
||||
<widget class="QPushButton" name="defaultOutputFolderButton">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>30</height>
|
||||
</size>
|
||||
<item row="0" column="4">
|
||||
<widget class="QPushButton" name="directoryButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Use this to select the default output directory.</p></body></html></string>
|
||||
<string><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></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
<string>Add input folder(s)</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="KCC.qrc">
|
||||
@@ -775,26 +820,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<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><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></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">
|
||||
<item row="1" column="4">
|
||||
<widget class="QComboBox" name="formatBox">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
@@ -811,10 +837,9 @@
|
||||
<zorder>clearButton</zorder>
|
||||
<zorder>deviceBox</zorder>
|
||||
<zorder>convertButton</zorder>
|
||||
<zorder>formatBox</zorder>
|
||||
<zorder>defaultOutputFolderButton</zorder>
|
||||
<zorder>fileButton</zorder>
|
||||
<zorder>defaultOutputFolderBox</zorder>
|
||||
<zorder>directoryButton</zorder>
|
||||
<zorder>formatBox</zorder>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
@@ -898,36 +923,44 @@
|
||||
</widget>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>convertButton</tabstop>
|
||||
<tabstop>jobList</tabstop>
|
||||
<tabstop>fileButton</tabstop>
|
||||
<tabstop>clearButton</tabstop>
|
||||
<tabstop>deviceBox</tabstop>
|
||||
<tabstop>formatBox</tabstop>
|
||||
<tabstop>widthBox</tabstop>
|
||||
<tabstop>heightBox</tabstop>
|
||||
<tabstop>convertButton</tabstop>
|
||||
<tabstop>mangaBox</tabstop>
|
||||
<tabstop>rotateBox</tabstop>
|
||||
<tabstop>qualityBox</tabstop>
|
||||
<tabstop>webtoonBox</tabstop>
|
||||
<tabstop>upscaleBox</tabstop>
|
||||
<tabstop>gammaBox</tabstop>
|
||||
<tabstop>gammaSlider</tabstop>
|
||||
<tabstop>borderBox</tabstop>
|
||||
<tabstop>outputSplit</tabstop>
|
||||
<tabstop>colorBox</tabstop>
|
||||
<tabstop>mozJpegBox</tabstop>
|
||||
<tabstop>maximizeStrips</tabstop>
|
||||
<tabstop>croppingBox</tabstop>
|
||||
<tabstop>croppingPowerSlider</tabstop>
|
||||
<tabstop>preserveMarginBox</tabstop>
|
||||
<tabstop>spreadShiftBox</tabstop>
|
||||
<tabstop>deleteBox</tabstop>
|
||||
<tabstop>disableProcessingBox</tabstop>
|
||||
<tabstop>chunkSizeBox</tabstop>
|
||||
<tabstop>fileFusionBox</tabstop>
|
||||
<tabstop>noRotateBox</tabstop>
|
||||
<tabstop>interPanelCropBox</tabstop>
|
||||
<tabstop>metadataTitleBox</tabstop>
|
||||
<tabstop>chunkSizeCheckBox</tabstop>
|
||||
<tabstop>chunkSizeBox</tabstop>
|
||||
<tabstop>eraseRainbowBox</tabstop>
|
||||
<tabstop>heightBox</tabstop>
|
||||
<tabstop>croppingPowerSlider</tabstop>
|
||||
<tabstop>rotateFirstBox</tabstop>
|
||||
<tabstop>autoLevelBox</tabstop>
|
||||
<tabstop>autocontrastBox</tabstop>
|
||||
<tabstop>editorButton</tabstop>
|
||||
<tabstop>kofiButton</tabstop>
|
||||
<tabstop>wikiButton</tabstop>
|
||||
<tabstop>jobList</tabstop>
|
||||
<tabstop>gammaSlider</tabstop>
|
||||
<tabstop>widthBox</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
<include location="KCC.qrc"/>
|
||||
|
||||
@@ -192,6 +192,18 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>seriesLine</tabstop>
|
||||
<tabstop>volumeLine</tabstop>
|
||||
<tabstop>titleLine</tabstop>
|
||||
<tabstop>numberLine</tabstop>
|
||||
<tabstop>writerLine</tabstop>
|
||||
<tabstop>pencillerLine</tabstop>
|
||||
<tabstop>inkerLine</tabstop>
|
||||
<tabstop>coloristLine</tabstop>
|
||||
<tabstop>okButton</tabstop>
|
||||
<tabstop>cancelButton</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
<include location="KCC.qrc"/>
|
||||
</resources>
|
||||
|
||||
@@ -22,7 +22,7 @@ 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, QSystemTrayIcon, QFileDialog, QMessageBox, QDialog)
|
||||
from PySide6.QtWidgets import (QApplication, QLabel, QListWidgetItem, QMainWindow, QSystemTrayIcon, QFileDialog, QMessageBox, QDialog, QTreeView, QAbstractItemView)
|
||||
from PySide6.QtNetwork import (QLocalSocket, QLocalServer)
|
||||
|
||||
import os
|
||||
@@ -610,12 +610,30 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
'Comic (*.pdf);;All (*.*)')
|
||||
for fname in fnames[0]:
|
||||
if fname != '':
|
||||
if sys.platform.startswith('win'):
|
||||
fname = fname.replace('/', '\\')
|
||||
self.lastPath = os.path.abspath(os.path.join(fname, os.pardir))
|
||||
GUI.jobList.addItem(fname)
|
||||
GUI.jobList.scrollToBottom()
|
||||
|
||||
def selectDir(self):
|
||||
if self.needClean:
|
||||
self.needClean = False
|
||||
GUI.jobList.clear()
|
||||
|
||||
dialog = QFileDialog(MW, 'Select input folder(s)', self.lastPath)
|
||||
dialog.setFileMode(QFileDialog.FileMode.Directory)
|
||||
dialog.setOption(QFileDialog.Option.ShowDirsOnly, True)
|
||||
dialog.setOption(QFileDialog.Option.DontUseNativeDialog, True)
|
||||
dialog.findChild(QTreeView).setSelectionMode(QAbstractItemView.ExtendedSelection)
|
||||
|
||||
if dialog.exec():
|
||||
dnames = dialog.selectedFiles()
|
||||
for dname in dnames:
|
||||
if dname != '':
|
||||
self.lastPath = os.path.abspath(os.path.join(dname, os.pardir))
|
||||
GUI.jobList.addItem(dname)
|
||||
GUI.jobList.scrollToBottom()
|
||||
|
||||
|
||||
def selectFileMetaEditor(self, sname):
|
||||
if not sname:
|
||||
if QApplication.keyboardModifiers() == Qt.ShiftModifier:
|
||||
@@ -1319,6 +1337,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
||||
GUI.defaultOutputFolderButton.clicked.connect(self.selectDefaultOutputFolder)
|
||||
GUI.clearButton.clicked.connect(self.clearJobs)
|
||||
GUI.fileButton.clicked.connect(self.selectFile)
|
||||
GUI.directoryButton.clicked.connect(self.selectDir)
|
||||
GUI.editorButton.clicked.connect(self.selectFileMetaEditor)
|
||||
GUI.wikiButton.clicked.connect(self.openWiki)
|
||||
GUI.kofiButton.clicked.connect(self.openKofi)
|
||||
|
||||
@@ -26,7 +26,7 @@ class Ui_mainWindow(object):
|
||||
def setupUi(self, mainWindow):
|
||||
if not mainWindow.objectName():
|
||||
mainWindow.setObjectName(u"mainWindow")
|
||||
mainWindow.resize(566, 573)
|
||||
mainWindow.resize(566, 581)
|
||||
icon = QIcon()
|
||||
icon.addFile(u":/Icon/icons/comic2ebook.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
mainWindow.setWindowIcon(icon)
|
||||
@@ -190,6 +190,33 @@ class Ui_mainWindow(object):
|
||||
|
||||
self.gridLayout_2.addWidget(self.autocontrastBox, 9, 2, 1, 1)
|
||||
|
||||
self.outputFolderWidget = QWidget(self.optionWidget)
|
||||
self.outputFolderWidget.setObjectName(u"outputFolderWidget")
|
||||
self.horizontalLayout_3 = QHBoxLayout(self.outputFolderWidget)
|
||||
self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
|
||||
self.defaultOutputFolderBox = QCheckBox(self.outputFolderWidget)
|
||||
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.horizontalLayout_3.addWidget(self.defaultOutputFolderBox)
|
||||
|
||||
self.defaultOutputFolderButton = QPushButton(self.outputFolderWidget)
|
||||
self.defaultOutputFolderButton.setObjectName(u"defaultOutputFolderButton")
|
||||
self.defaultOutputFolderButton.setMinimumSize(QSize(0, 30))
|
||||
icon1 = QIcon()
|
||||
icon1.addFile(u":/Other/icons/folder_new.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
self.defaultOutputFolderButton.setIcon(icon1)
|
||||
|
||||
self.horizontalLayout_3.addWidget(self.defaultOutputFolderButton)
|
||||
|
||||
|
||||
self.gridLayout_2.addWidget(self.outputFolderWidget, 0, 2, 1, 1)
|
||||
|
||||
|
||||
self.gridLayout.addWidget(self.optionWidget, 5, 0, 1, 2)
|
||||
|
||||
@@ -211,11 +238,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)
|
||||
|
||||
@@ -227,8 +254,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)
|
||||
|
||||
@@ -271,18 +298,18 @@ class Ui_mainWindow(object):
|
||||
self.editorButton = QPushButton(self.toolWidget)
|
||||
self.editorButton.setObjectName(u"editorButton")
|
||||
self.editorButton.setMinimumSize(QSize(0, 30))
|
||||
icon1 = QIcon()
|
||||
icon1.addFile(u":/Other/icons/editor.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
self.editorButton.setIcon(icon1)
|
||||
icon2 = QIcon()
|
||||
icon2.addFile(u":/Other/icons/editor.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
self.editorButton.setIcon(icon2)
|
||||
|
||||
self.horizontalLayout.addWidget(self.editorButton)
|
||||
|
||||
self.kofiButton = QPushButton(self.toolWidget)
|
||||
self.kofiButton.setObjectName(u"kofiButton")
|
||||
self.kofiButton.setMinimumSize(QSize(0, 30))
|
||||
icon2 = QIcon()
|
||||
icon2.addFile(u":/Brand/icons/kofi_symbol.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
self.kofiButton.setIcon(icon2)
|
||||
icon3 = QIcon()
|
||||
icon3.addFile(u":/Brand/icons/kofi_symbol.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
self.kofiButton.setIcon(icon3)
|
||||
self.kofiButton.setIconSize(QSize(19, 16))
|
||||
|
||||
self.horizontalLayout.addWidget(self.kofiButton)
|
||||
@@ -290,9 +317,9 @@ class Ui_mainWindow(object):
|
||||
self.wikiButton = QPushButton(self.toolWidget)
|
||||
self.wikiButton.setObjectName(u"wikiButton")
|
||||
self.wikiButton.setMinimumSize(QSize(0, 30))
|
||||
icon3 = QIcon()
|
||||
icon3.addFile(u":/Other/icons/wiki.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
self.wikiButton.setIcon(icon3)
|
||||
icon4 = QIcon()
|
||||
icon4.addFile(u":/Other/icons/wiki.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
self.wikiButton.setIcon(icon4)
|
||||
|
||||
self.horizontalLayout.addWidget(self.wikiButton)
|
||||
|
||||
@@ -336,11 +363,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)
|
||||
@@ -364,18 +388,18 @@ class Ui_mainWindow(object):
|
||||
self.convertButton.setObjectName(u"convertButton")
|
||||
self.convertButton.setMinimumSize(QSize(0, 30))
|
||||
self.convertButton.setFont(font)
|
||||
icon4 = QIcon()
|
||||
icon4.addFile(u":/Other/icons/convert.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
self.convertButton.setIcon(icon4)
|
||||
icon5 = QIcon()
|
||||
icon5.addFile(u":/Other/icons/convert.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
self.convertButton.setIcon(icon5)
|
||||
|
||||
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)
|
||||
icon6 = QIcon()
|
||||
icon6.addFile(u":/Other/icons/clear.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
self.clearButton.setIcon(icon6)
|
||||
|
||||
self.gridLayout_4.addWidget(self.clearButton, 0, 3, 1, 1)
|
||||
|
||||
@@ -388,42 +412,35 @@ class Ui_mainWindow(object):
|
||||
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)
|
||||
icon7 = QIcon()
|
||||
icon7.addFile(u":/Other/icons/document_new.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
self.fileButton.setIcon(icon7)
|
||||
|
||||
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/folder_new.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
self.defaultOutputFolderButton.setIcon(icon7)
|
||||
self.directoryButton = QPushButton(self.buttonWidget)
|
||||
self.directoryButton.setObjectName(u"directoryButton")
|
||||
sizePolicy4 = QSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Minimum)
|
||||
sizePolicy4.setHorizontalStretch(0)
|
||||
sizePolicy4.setVerticalStretch(0)
|
||||
sizePolicy4.setHeightForWidth(self.directoryButton.sizePolicy().hasHeightForWidth())
|
||||
self.directoryButton.setSizePolicy(sizePolicy4)
|
||||
self.directoryButton.setIcon(icon1)
|
||||
|
||||
self.gridLayout_4.addWidget(self.defaultOutputFolderButton, 0, 5, 1, 1)
|
||||
|
||||
self.defaultOutputFolderBox = QCheckBox(self.buttonWidget)
|
||||
self.defaultOutputFolderBox.setObjectName(u"defaultOutputFolderBox")
|
||||
sizePolicy2.setHeightForWidth(self.defaultOutputFolderBox.sizePolicy().hasHeightForWidth())
|
||||
self.defaultOutputFolderBox.setSizePolicy(sizePolicy2)
|
||||
self.defaultOutputFolderBox.setTristate(True)
|
||||
|
||||
self.gridLayout_4.addWidget(self.defaultOutputFolderBox, 0, 4, 1, 1)
|
||||
self.gridLayout_4.addWidget(self.directoryButton, 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.gridLayout_4.addWidget(self.formatBox, 1, 4, 1, 1)
|
||||
|
||||
self.clearButton.raise_()
|
||||
self.deviceBox.raise_()
|
||||
self.convertButton.raise_()
|
||||
self.formatBox.raise_()
|
||||
self.defaultOutputFolderButton.raise_()
|
||||
self.fileButton.raise_()
|
||||
self.defaultOutputFolderBox.raise_()
|
||||
self.directoryButton.raise_()
|
||||
self.formatBox.raise_()
|
||||
|
||||
self.gridLayout.addWidget(self.buttonWidget, 3, 0, 1, 2)
|
||||
|
||||
@@ -438,11 +455,11 @@ class Ui_mainWindow(object):
|
||||
self.horizontalLayout_4.setContentsMargins(0, 0, 0, 0)
|
||||
self.chunkSizeLabel = QLabel(self.chunkSizeWidget)
|
||||
self.chunkSizeLabel.setObjectName(u"chunkSizeLabel")
|
||||
sizePolicy4 = QSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Preferred)
|
||||
sizePolicy4.setHorizontalStretch(0)
|
||||
sizePolicy4.setVerticalStretch(0)
|
||||
sizePolicy4.setHeightForWidth(self.chunkSizeLabel.sizePolicy().hasHeightForWidth())
|
||||
self.chunkSizeLabel.setSizePolicy(sizePolicy4)
|
||||
sizePolicy5 = QSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Preferred)
|
||||
sizePolicy5.setHorizontalStretch(0)
|
||||
sizePolicy5.setVerticalStretch(0)
|
||||
sizePolicy5.setHeightForWidth(self.chunkSizeLabel.sizePolicy().hasHeightForWidth())
|
||||
self.chunkSizeLabel.setSizePolicy(sizePolicy5)
|
||||
|
||||
self.horizontalLayout_4.addWidget(self.chunkSizeLabel)
|
||||
|
||||
@@ -456,8 +473,8 @@ class Ui_mainWindow(object):
|
||||
|
||||
self.chunkSizeWarnLabel = QLabel(self.chunkSizeWidget)
|
||||
self.chunkSizeWarnLabel.setObjectName(u"chunkSizeWarnLabel")
|
||||
sizePolicy4.setHeightForWidth(self.chunkSizeWarnLabel.sizePolicy().hasHeightForWidth())
|
||||
self.chunkSizeWarnLabel.setSizePolicy(sizePolicy4)
|
||||
sizePolicy5.setHeightForWidth(self.chunkSizeWarnLabel.sizePolicy().hasHeightForWidth())
|
||||
self.chunkSizeWarnLabel.setSizePolicy(sizePolicy5)
|
||||
|
||||
self.horizontalLayout_4.addWidget(self.chunkSizeWarnLabel)
|
||||
|
||||
@@ -469,35 +486,43 @@ class Ui_mainWindow(object):
|
||||
self.statusBar.setObjectName(u"statusBar")
|
||||
self.statusBar.setSizeGripEnabled(False)
|
||||
mainWindow.setStatusBar(self.statusBar)
|
||||
QWidget.setTabOrder(self.convertButton, self.clearButton)
|
||||
QWidget.setTabOrder(self.jobList, self.fileButton)
|
||||
QWidget.setTabOrder(self.fileButton, self.clearButton)
|
||||
QWidget.setTabOrder(self.clearButton, self.deviceBox)
|
||||
QWidget.setTabOrder(self.deviceBox, self.formatBox)
|
||||
QWidget.setTabOrder(self.formatBox, self.mangaBox)
|
||||
QWidget.setTabOrder(self.deviceBox, self.widthBox)
|
||||
QWidget.setTabOrder(self.widthBox, self.heightBox)
|
||||
QWidget.setTabOrder(self.heightBox, self.convertButton)
|
||||
QWidget.setTabOrder(self.convertButton, self.mangaBox)
|
||||
QWidget.setTabOrder(self.mangaBox, self.rotateBox)
|
||||
QWidget.setTabOrder(self.rotateBox, self.qualityBox)
|
||||
QWidget.setTabOrder(self.qualityBox, self.webtoonBox)
|
||||
QWidget.setTabOrder(self.webtoonBox, self.upscaleBox)
|
||||
QWidget.setTabOrder(self.upscaleBox, self.gammaBox)
|
||||
QWidget.setTabOrder(self.gammaBox, self.borderBox)
|
||||
QWidget.setTabOrder(self.gammaBox, self.gammaSlider)
|
||||
QWidget.setTabOrder(self.gammaSlider, self.borderBox)
|
||||
QWidget.setTabOrder(self.borderBox, self.outputSplit)
|
||||
QWidget.setTabOrder(self.outputSplit, self.colorBox)
|
||||
QWidget.setTabOrder(self.colorBox, self.mozJpegBox)
|
||||
QWidget.setTabOrder(self.mozJpegBox, self.maximizeStrips)
|
||||
QWidget.setTabOrder(self.maximizeStrips, self.croppingBox)
|
||||
QWidget.setTabOrder(self.croppingBox, self.spreadShiftBox)
|
||||
QWidget.setTabOrder(self.croppingBox, self.croppingPowerSlider)
|
||||
QWidget.setTabOrder(self.croppingPowerSlider, self.preserveMarginBox)
|
||||
QWidget.setTabOrder(self.preserveMarginBox, self.spreadShiftBox)
|
||||
QWidget.setTabOrder(self.spreadShiftBox, self.deleteBox)
|
||||
QWidget.setTabOrder(self.deleteBox, self.disableProcessingBox)
|
||||
QWidget.setTabOrder(self.disableProcessingBox, self.chunkSizeBox)
|
||||
QWidget.setTabOrder(self.chunkSizeBox, self.noRotateBox)
|
||||
QWidget.setTabOrder(self.disableProcessingBox, self.fileFusionBox)
|
||||
QWidget.setTabOrder(self.fileFusionBox, self.noRotateBox)
|
||||
QWidget.setTabOrder(self.noRotateBox, self.interPanelCropBox)
|
||||
QWidget.setTabOrder(self.interPanelCropBox, self.eraseRainbowBox)
|
||||
QWidget.setTabOrder(self.eraseRainbowBox, self.heightBox)
|
||||
QWidget.setTabOrder(self.heightBox, self.croppingPowerSlider)
|
||||
QWidget.setTabOrder(self.croppingPowerSlider, self.editorButton)
|
||||
QWidget.setTabOrder(self.editorButton, self.wikiButton)
|
||||
QWidget.setTabOrder(self.wikiButton, self.jobList)
|
||||
QWidget.setTabOrder(self.jobList, self.gammaSlider)
|
||||
QWidget.setTabOrder(self.gammaSlider, self.widthBox)
|
||||
QWidget.setTabOrder(self.interPanelCropBox, self.metadataTitleBox)
|
||||
QWidget.setTabOrder(self.metadataTitleBox, self.chunkSizeCheckBox)
|
||||
QWidget.setTabOrder(self.chunkSizeCheckBox, self.chunkSizeBox)
|
||||
QWidget.setTabOrder(self.chunkSizeBox, self.eraseRainbowBox)
|
||||
QWidget.setTabOrder(self.eraseRainbowBox, self.rotateFirstBox)
|
||||
QWidget.setTabOrder(self.rotateFirstBox, self.autoLevelBox)
|
||||
QWidget.setTabOrder(self.autoLevelBox, self.autocontrastBox)
|
||||
QWidget.setTabOrder(self.autocontrastBox, self.editorButton)
|
||||
QWidget.setTabOrder(self.editorButton, self.kofiButton)
|
||||
QWidget.setTabOrder(self.kofiButton, self.wikiButton)
|
||||
|
||||
self.retranslateUi(mainWindow)
|
||||
|
||||
@@ -610,6 +635,14 @@ class Ui_mainWindow(object):
|
||||
self.autocontrastBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - BW only<br/></span>Only autocontrast bw pages. Ignored for pages where near blacks or whites don't exist.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Disabled<br/></span>Disable autocontrast</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - BW and Color<br/></span>BW and color images will be autocontrasted. Ignored for pages where near blacks or whites don't exist.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
self.autocontrastBox.setText(QCoreApplication.translate("mainWindow", u"Autocontrast", None))
|
||||
#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.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.jobList.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p>Double click on source to open it in metadata editor.</p></body></html>", None))
|
||||
#endif // QT_CONFIG(tooltip)
|
||||
@@ -650,15 +683,11 @@ class Ui_mainWindow(object):
|
||||
#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))
|
||||
self.fileButton.setText(QCoreApplication.translate("mainWindow", u"Add input file(s)", None))
|
||||
#if QT_CONFIG(tooltip)
|
||||
self.defaultOutputFolderButton.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p>Use this to select the default output directory.</p></body></html>", None))
|
||||
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))
|
||||
#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))
|
||||
self.directoryButton.setText(QCoreApplication.translate("mainWindow", u"Add input folder(s)", 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)
|
||||
|
||||
@@ -156,6 +156,15 @@ class Ui_editorDialog(object):
|
||||
|
||||
self.verticalLayout.addWidget(self.optionWidget)
|
||||
|
||||
QWidget.setTabOrder(self.seriesLine, self.volumeLine)
|
||||
QWidget.setTabOrder(self.volumeLine, self.titleLine)
|
||||
QWidget.setTabOrder(self.titleLine, self.numberLine)
|
||||
QWidget.setTabOrder(self.numberLine, self.writerLine)
|
||||
QWidget.setTabOrder(self.writerLine, self.pencillerLine)
|
||||
QWidget.setTabOrder(self.pencillerLine, self.inkerLine)
|
||||
QWidget.setTabOrder(self.inkerLine, self.coloristLine)
|
||||
QWidget.setTabOrder(self.coloristLine, self.okButton)
|
||||
QWidget.setTabOrder(self.okButton, self.cancelButton)
|
||||
|
||||
self.retranslateUi(editorDialog)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
__version__ = '9.3.3'
|
||||
__version__ = '9.3.8'
|
||||
__license__ = 'ISC'
|
||||
__copyright__ = '2012-2022, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>, darodi'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
@@ -851,14 +851,16 @@ def mupdf_pdf_process_pages_parallel(filename, output_dir, target_height):
|
||||
|
||||
|
||||
|
||||
def getWorkFolder(afile):
|
||||
def getWorkFolder(afile, workdir=None):
|
||||
if not workdir:
|
||||
workdir = mkdtemp('', 'KCC-')
|
||||
fullPath = os.path.join(workdir, 'OEBPS', 'Images')
|
||||
else:
|
||||
fullPath = workdir
|
||||
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-', os.path.dirname(afile))
|
||||
try:
|
||||
os.rmdir(workdir)
|
||||
fullPath = os.path.join(workdir, 'OEBPS', 'Images')
|
||||
copytree(afile, fullPath)
|
||||
sanitizePermissions(fullPath)
|
||||
return workdir
|
||||
@@ -869,7 +871,8 @@ def getWorkFolder(afile):
|
||||
if disk_usage(gettempdir())[2] < os.path.getsize(afile) * 2.5:
|
||||
raise UserWarning("Not enough disk space to perform conversion.")
|
||||
if afile.lower().endswith('.pdf'):
|
||||
workdir = mkdtemp('', 'KCC-', os.path.dirname(afile))
|
||||
if not os.path.exists(fullPath):
|
||||
os.makedirs(fullPath)
|
||||
path = workdir
|
||||
sanitizePermissions(path)
|
||||
target_height = options.profileData[1][1]
|
||||
@@ -878,39 +881,42 @@ def getWorkFolder(afile):
|
||||
elif options.cropping == 2:
|
||||
target_height = target_height + target_height*0.25 #Account for possible margin at the top and bottom with page number
|
||||
try:
|
||||
mupdf_pdf_process_pages_parallel(afile, workdir, target_height)
|
||||
mupdf_pdf_process_pages_parallel(afile, fullPath, target_height)
|
||||
except Exception as e:
|
||||
rmtree(path, True)
|
||||
raise UserWarning(f"Failed to extract images from PDF file. {e}")
|
||||
return workdir
|
||||
else:
|
||||
workdir = mkdtemp('', 'KCC-', os.path.dirname(afile))
|
||||
if not os.path.exists(fullPath):
|
||||
os.makedirs(fullPath)
|
||||
try:
|
||||
cbx = comicarchive.ComicArchive(afile)
|
||||
path = cbx.extract(workdir)
|
||||
path = cbx.extract(fullPath)
|
||||
sanitizePermissions(path)
|
||||
|
||||
tdir = os.listdir(workdir)
|
||||
tdir = os.listdir(fullPath)
|
||||
if len(tdir) == 2 and 'ComicInfo.xml' in tdir:
|
||||
tdir.remove('ComicInfo.xml')
|
||||
if os.path.isdir(os.path.join(workdir, tdir[0])):
|
||||
if os.path.isdir(os.path.join(fullPath, tdir[0])):
|
||||
os.replace(
|
||||
os.path.join(workdir, 'ComicInfo.xml'),
|
||||
os.path.join(workdir, tdir[0], 'ComicInfo.xml')
|
||||
os.path.join(fullPath, 'ComicInfo.xml'),
|
||||
os.path.join(fullPath, tdir[0], 'ComicInfo.xml')
|
||||
)
|
||||
if len(tdir) == 1 and os.path.isdir(os.path.join(workdir, tdir[0])):
|
||||
path = os.path.join(workdir, tdir[0])
|
||||
if len(tdir) == 1 and os.path.isdir(os.path.join(fullPath, tdir[0])):
|
||||
for file in os.listdir(os.path.join(fullPath, tdir[0])):
|
||||
move(os.path.join(fullPath, tdir[0], file), fullPath)
|
||||
os.rmdir(os.path.join(fullPath, tdir[0]))
|
||||
return workdir
|
||||
|
||||
except OSError as e:
|
||||
rmtree(workdir, True)
|
||||
raise UserWarning(e)
|
||||
else:
|
||||
raise UserWarning("Failed to open source file/directory.")
|
||||
newpath = mkdtemp('', 'KCC-', os.path.dirname(afile))
|
||||
os.renames(path, os.path.join(newpath, 'OEBPS', 'Images'))
|
||||
return newpath
|
||||
|
||||
|
||||
def getOutputFilename(srcpath, wantedname, ext, tomenumber):
|
||||
source_path = Path(srcpath)
|
||||
if srcpath[-1] == os.path.sep:
|
||||
srcpath = srcpath[:-1]
|
||||
if 'Ko' in options.profile and options.format == 'EPUB':
|
||||
@@ -923,22 +929,26 @@ def getOutputFilename(srcpath, wantedname, ext, tomenumber):
|
||||
wanted_root, wanted_ext = os.path.splitext(wantedname)
|
||||
if wantedname.endswith(ext):
|
||||
filename = os.path.abspath(wantedname)
|
||||
elif wanted_ext == '.mobi' and ext == '.epub':
|
||||
filename = os.path.abspath(wanted_root + ext)
|
||||
# output directory
|
||||
elif not wanted_ext:
|
||||
else:
|
||||
abs_path = os.path.abspath(options.output)
|
||||
if not os.path.exists(abs_path):
|
||||
os.mkdir(abs_path)
|
||||
filename = os.path.join(os.path.abspath(options.output), Path(srcpath).stem + ext)
|
||||
# output file
|
||||
else:
|
||||
filename = os.path.abspath(wanted_root) + ext
|
||||
if source_path.is_file():
|
||||
filename = os.path.join(os.path.abspath(options.output), source_path.stem + tomenumber + ext)
|
||||
else:
|
||||
filename = os.path.join(os.path.abspath(options.output), source_path.name + tomenumber + ext)
|
||||
elif os.path.isdir(srcpath):
|
||||
filename = srcpath + tomenumber + ext
|
||||
else:
|
||||
if 'Ko' in options.profile and options.format == 'EPUB':
|
||||
src = pathlib.Path(srcpath)
|
||||
name = re.sub(r'\W+', '_', src.stem) + tomenumber + ext
|
||||
filename = src.with_name(name)
|
||||
if source_path.is_file():
|
||||
name = re.sub(r'\W+', '_', source_path.stem) + tomenumber + ext
|
||||
else:
|
||||
name = re.sub(r'\W+', '_', source_path.name) + tomenumber + ext
|
||||
filename = source_path.with_name(name)
|
||||
else:
|
||||
filename = os.path.splitext(srcpath)[0] + tomenumber + ext
|
||||
if os.path.isfile(filename):
|
||||
@@ -1520,17 +1530,15 @@ def makeFusion(sources: List[str]):
|
||||
print(f"Processing {source}...")
|
||||
checkPre(source)
|
||||
print("Checking images...")
|
||||
path = getWorkFolder(source)
|
||||
pathfinder = os.path.join(path, "OEBPS", "Images")
|
||||
sanitizeTree(pathfinder)
|
||||
# TODO: remove flattenTree when subchapters are supported
|
||||
flattenTree(pathfinder)
|
||||
source_path = Path(source)
|
||||
if source_path.is_file():
|
||||
os.renames(pathfinder, fusion_path.joinpath(source_path.stem))
|
||||
targetpath = fusion_path.joinpath(source_path.stem)
|
||||
else:
|
||||
os.renames(pathfinder, fusion_path.joinpath(source_path.name))
|
||||
|
||||
targetpath = fusion_path.joinpath(source_path.name)
|
||||
getWorkFolder(source, str(targetpath))
|
||||
sanitizeTree(targetpath)
|
||||
# TODO: remove flattenTree when subchapters are supported
|
||||
flattenTree(targetpath)
|
||||
|
||||
end = perf_counter()
|
||||
print(f"makefusion: {end - start} seconds")
|
||||
|
||||
@@ -67,13 +67,14 @@ def mergeDirectory(work):
|
||||
result = Image.new('RGB', (targetWidth, targetHeight))
|
||||
y = 0
|
||||
for i in imagesValid:
|
||||
img = Image.open(i).convert('RGB')
|
||||
if img.size[0] < targetWidth or img.size[0] > targetWidth:
|
||||
widthPercent = (targetWidth / float(img.size[0]))
|
||||
heightSize = int((float(img.size[1]) * float(widthPercent)))
|
||||
img = ImageOps.fit(img, (targetWidth, heightSize), method=Image.BICUBIC, centering=(0.5, 0.5))
|
||||
result.paste(img, (0, y))
|
||||
y += img.size[1]
|
||||
with Image.open(i) as img:
|
||||
img = img.convert('RGB')
|
||||
if img.size[0] < targetWidth or img.size[0] > targetWidth:
|
||||
widthPercent = (targetWidth / float(img.size[0]))
|
||||
heightSize = int((float(img.size[1]) * float(widthPercent)))
|
||||
img = ImageOps.fit(img, (targetWidth, heightSize), method=Image.BICUBIC, centering=(0.5, 0.5))
|
||||
result.paste(img, (0, y))
|
||||
y += img.size[1]
|
||||
os.remove(i)
|
||||
savePath = os.path.split(imagesValid[0])
|
||||
result.save(os.path.join(savePath[0], os.path.splitext(savePath[1])[0] + '.png'), 'PNG')
|
||||
@@ -253,10 +254,8 @@ def main(argv=None, job_progress='', qtgui=None):
|
||||
return 1
|
||||
if args.height > 0:
|
||||
for sourceDir in args.input:
|
||||
targetDir = sourceDir + "-Splitted"
|
||||
targetDir = sourceDir
|
||||
if os.path.isdir(sourceDir):
|
||||
rmtree(targetDir, True)
|
||||
os.renames(sourceDir, targetDir)
|
||||
work = []
|
||||
pagenumber = 1
|
||||
splitWorkerOutput = []
|
||||
@@ -313,8 +312,6 @@ def main(argv=None, job_progress='', qtgui=None):
|
||||
rmtree(targetDir, True)
|
||||
raise RuntimeError("One of workers crashed. Cause: " + splitWorkerOutput[0][0],
|
||||
splitWorkerOutput[0][1])
|
||||
if args.inPlace:
|
||||
os.renames(targetDir, sourceDir)
|
||||
else:
|
||||
rmtree(targetDir, True)
|
||||
raise UserWarning("C2P: Source directory is empty.")
|
||||
|
||||
@@ -485,7 +485,7 @@ class ComicPage:
|
||||
if self.opt.kindle_azw3 and any(dim > 1920 for dim in self.image.size):
|
||||
self.image = ImageOps.contain(self.image, (1920, 1920), Image.Resampling.LANCZOS)
|
||||
elif self.image.size[0] > self.size[0] * 2 or self.image.size[1] > self.size[1]:
|
||||
self.image = ImageOps.contain(self.image, (self.size[0] * 2, self.size[1], Image.Resampling.LANCZOS))
|
||||
self.image = ImageOps.contain(self.image, (self.size[0] * 2, self.size[1]), Image.Resampling.LANCZOS)
|
||||
return
|
||||
|
||||
ratio_device = float(self.size[1]) / float(self.size[0])
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
PySide6==6.5.2
|
||||
PySide6==6.4.3
|
||||
Pillow>=11.3.0
|
||||
psutil>=5.9.5
|
||||
requests>=2.31.0
|
||||
|
||||
@@ -2,7 +2,7 @@ PySide6<6.10
|
||||
Pillow>=11.3.0
|
||||
psutil>=5.9.5
|
||||
requests>=2.31.0
|
||||
python-slugify>=1.2.1
|
||||
python-slugify>=1.2.1,<9.0.0
|
||||
raven>=6.0.0
|
||||
packaging>=23.2
|
||||
mozjpeg-lossless-optimization>=1.2.0
|
||||
|
||||
13
setup.py
13
setup.py
@@ -40,8 +40,8 @@ class BuildBinaryCommand(setuptools.Command):
|
||||
if sys.platform == 'darwin':
|
||||
os.system('pyinstaller --hidden-import=_cffi_backend -y -D -i icons/comic2ebook.icns -n "Kindle Comic Converter" -w -s kcc.py')
|
||||
# TODO /usr/bin/codesign --force -s "$MACOS_CERTIFICATE_NAME" --options runtime dist/Applications/Kindle\ Comic\ Converter.app -v
|
||||
min_os = os.getenv('MACOSX_DEPLOYMENT_TARGET')
|
||||
if min_os:
|
||||
min_os = os.getenv('MACOSX_DEPLOYMENT_TARGET', '')
|
||||
if min_os.startswith('10.1'):
|
||||
os.system(f'appdmg kcc.json dist/kcc_osx_{min_os.replace(".", "_")}_legacy_{VERSION}.dmg')
|
||||
else:
|
||||
os.system(f'appdmg kcc.json dist/kcc_macos_{platform.processor()}_{VERSION}.dmg')
|
||||
@@ -148,16 +148,15 @@ setuptools.setup(
|
||||
},
|
||||
packages=['kindlecomicconverter'],
|
||||
install_requires=[
|
||||
'pyside6>=6.0.0',
|
||||
'PySide6>=6.0.0',
|
||||
'Pillow>=9.3.0',
|
||||
'PyMuPDF>=1.18.0',
|
||||
'psutil>=5.9.5',
|
||||
'requests>=2.31.0',
|
||||
'python-slugify>=1.2.1,<9.0.0',
|
||||
'raven>=6.0.0',
|
||||
'requests>=2.31.0',
|
||||
'mozjpeg-lossless-optimization>=1.1.2',
|
||||
'mozjpeg-lossless-optimization>=1.2.0',
|
||||
'natsort>=8.4.0',
|
||||
'distro',
|
||||
'distro>=1.8.0',
|
||||
'numpy>=1.22.4',
|
||||
'PyMuPDF>=1.16.1',
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user