1
0
mirror of https://github.com/ciromattia/kcc synced 2026-04-17 14:38:47 +00:00

Compare commits

...

20 Commits

Author SHA1 Message Date
Alex Xu
9b63b7af2c Bump version to 9.3.8 2025-12-27 12:23:39 -08:00
tokyis
f74e108a3e Fixed resizing bug
caused by misplaced closing parenthesis.
2025-12-27 12:22:10 -08:00
Alex Xu
f088ad732e default MACOSX_DEPLOYMENT_TARGET 2025-12-23 13:19:40 -08:00
jaroslawjanas
8e5d57364d Remove environment.yml 2025-12-15 09:48:49 -08:00
dependabot[bot]
b767d5dc2c Bump actions/upload-artifact from 5 to 6 (#1196)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 5 to 6.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-15 09:48:49 -08:00
Alex Xu
7228055bca reduce file operations in webtoon and file fusion (#1191)
* reduce file operations in webtoon

* reduce file operations of file fusion

* fix file fusion failed to prepare

* close webtoon image before remove

* use temp directory
2025-12-14 23:44:30 -08:00
Alex Xu
8c57fbf318 fix add folder button sizePolicy 2025-12-14 18:59:28 -08:00
Alex Xu
7e94861fa1 input folder multiselect (#1195) 2025-12-14 16:13:24 -08:00
Alex Xu
9992ca4d26 fix mac legacy build naming 2025-12-10 22:00:56 -08:00
Alex Xu
f47d1427f0 Update README.md
Clarified description of Kindle Comic Converter's capabilities.
2025-12-09 23:22:31 -08:00
Alex Xu
ce8998375c macOS 14 minimum for non legacy 2025-12-08 22:27:40 -08:00
Alex Xu
8870898a87 macOS 14 minimum for non legacy builds (#1189) 2025-12-08 22:25:59 -08:00
Alex Xu
a017cfd00d specify 12.0 instead of 12 2025-12-08 21:31:38 -08:00
Alex Xu
3f4ef3e21e Bump version to 9.3.7 2025-12-08 20:59:26 -08:00
Alex Xu
4733c6348b specify macOS 12 minimum for standard builds (#1188) 2025-12-08 20:58:15 -08:00
Alex Xu
5ad23d9629 mention color 2025-12-08 19:50:34 -08:00
Alex Xu
db4eb78963 Bump version to 9.3.6 2025-12-08 19:15:47 -08:00
Alex Xu
988fc93dc5 Fix macOS 10.14+ legacy compatibility (#1187)
* Update requirements-osx-legacy.txt

* upgrade macos-13 to macos-15-intel

* upgrade macos-13 to macos-15-intel
2025-12-08 18:08:16 -08:00
Alex Xu
74fee9346c Bump version to 9.3.5 2025-12-03 19:15:45 -08:00
Alex Xu
9fcacd7ae6 fix comicinfo detection in corner case (9.3.4 regression) (#1185) 2025-12-03 19:13:19 -08:00
16 changed files with 208 additions and 168 deletions

View File

@@ -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*'

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -7,7 +7,7 @@
[![Github All Releases](https://img.shields.io/github/downloads/ciromattia/kcc/total.svg)](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.

View File

@@ -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

View File

@@ -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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Unchecked - next to source&lt;br/&gt;&lt;/span&gt;Place output files next to source files&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Indeterminate - folder next to source&lt;br/&gt;&lt;/span&gt;Place output files in a folder next to source files&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Checked - Custom&lt;br/&gt;&lt;/span&gt;Place output files in custom directory specified by right button&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Output Folder</string>
</property>
<property name="tristate">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="defaultOutputFolderButton">
<property name="minimumSize">
<size>
<width>0</width>
<height>30</height>
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Use this to select the default output directory.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="KCC.qrc">
<normaloff>:/Other/icons/folder_new.png</normaloff>:/Other/icons/folder_new.png</iconset>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
@@ -747,7 +792,7 @@
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Add CBR, CBZ, CB7 or PDF file to queue.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Use this to select the default output directory.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Add directory containing JPG, PNG or GIF files to queue.&lt;br/&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;CBR, CBZ and CB7 files inside will not be processed!&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Unchecked - next to source&lt;br/&gt;&lt;/span&gt;Place output files next to source files&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Indeterminate - folder next to source&lt;br/&gt;&lt;/span&gt;Place output files in a folder next to source files&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Checked - Custom&lt;br/&gt;&lt;/span&gt;Place output files in custom directory specified by right button&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Output Folder</string>
</property>
<property name="tristate">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="4" colspan="2">
<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">
@@ -901,12 +926,9 @@
<tabstop>jobList</tabstop>
<tabstop>fileButton</tabstop>
<tabstop>clearButton</tabstop>
<tabstop>defaultOutputFolderButton</tabstop>
<tabstop>defaultOutputFolderBox</tabstop>
<tabstop>deviceBox</tabstop>
<tabstop>widthBox</tabstop>
<tabstop>heightBox</tabstop>
<tabstop>formatBox</tabstop>
<tabstop>convertButton</tabstop>
<tabstop>mangaBox</tabstop>
<tabstop>rotateBox</tabstop>

View File

@@ -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)

View File

@@ -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)
@@ -471,13 +488,10 @@ class Ui_mainWindow(object):
mainWindow.setStatusBar(self.statusBar)
QWidget.setTabOrder(self.jobList, self.fileButton)
QWidget.setTabOrder(self.fileButton, self.clearButton)
QWidget.setTabOrder(self.clearButton, self.defaultOutputFolderButton)
QWidget.setTabOrder(self.defaultOutputFolderButton, self.defaultOutputFolderBox)
QWidget.setTabOrder(self.defaultOutputFolderBox, self.deviceBox)
QWidget.setTabOrder(self.clearButton, self.deviceBox)
QWidget.setTabOrder(self.deviceBox, self.widthBox)
QWidget.setTabOrder(self.widthBox, self.heightBox)
QWidget.setTabOrder(self.heightBox, self.formatBox)
QWidget.setTabOrder(self.formatBox, self.convertButton)
QWidget.setTabOrder(self.heightBox, self.convertButton)
QWidget.setTabOrder(self.convertButton, self.mangaBox)
QWidget.setTabOrder(self.mangaBox, self.rotateBox)
QWidget.setTabOrder(self.rotateBox, self.qualityBox)
@@ -621,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)
@@ -661,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)

View File

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

View File

@@ -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,8 +871,6 @@ 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))
fullPath = os.path.join(workdir, 'OEBPS', 'Images')
if not os.path.exists(fullPath):
os.makedirs(fullPath)
path = workdir
@@ -887,8 +887,6 @@ def getWorkFolder(afile):
raise UserWarning(f"Failed to extract images from PDF file. {e}")
return workdir
else:
workdir = mkdtemp('', 'KCC-', os.path.dirname(afile))
fullPath = os.path.join(workdir, 'OEBPS', 'Images')
if not os.path.exists(fullPath):
os.makedirs(fullPath)
try:
@@ -905,7 +903,9 @@ def getWorkFolder(afile):
os.path.join(fullPath, tdir[0], 'ComicInfo.xml')
)
if len(tdir) == 1 and os.path.isdir(os.path.join(fullPath, tdir[0])):
path = 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:
@@ -1530,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")

View File

@@ -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.")

View File

@@ -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])

View File

@@ -1,4 +1,4 @@
PySide6==6.5.2
PySide6==6.4.3
Pillow>=11.3.0
psutil>=5.9.5
requests>=2.31.0

View File

@@ -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')