mirror of
https://github.com/ciromattia/kcc
synced 2026-04-18 06:58:58 +00:00
Compare commits
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2fc32bae58 | ||
|
|
db25a0939c | ||
|
|
1bd7506140 | ||
|
|
4fc5cc9dfb | ||
|
|
89289412a3 | ||
|
|
193297c8fc | ||
|
|
367d71e4ad | ||
|
|
cdde0f18cd | ||
|
|
9fe82a9dd4 | ||
|
|
e958edd135 | ||
|
|
6738b70487 | ||
|
|
44094bdb21 | ||
|
|
a9a2f47e30 | ||
|
|
c35dd137ea | ||
|
|
1ea008c8f3 | ||
|
|
cbc1ed5db4 | ||
|
|
6bf662bea3 | ||
|
|
cfae306731 | ||
|
|
f6475f4c61 | ||
|
|
9646518575 | ||
|
|
937dd3984a | ||
|
|
4e6f6ec8e8 | ||
|
|
4b36fdbfa2 | ||
|
|
d8141af4eb | ||
|
|
cf38c4d445 | ||
|
|
283b2da1a0 | ||
|
|
4a9f693574 | ||
|
|
9a48887edc | ||
|
|
0981ec3c6d | ||
|
|
e0e6606736 | ||
|
|
518e67c132 | ||
|
|
6c593dac1f | ||
|
|
9d065676db | ||
|
|
9520e59a29 | ||
|
|
461a7fda88 | ||
|
|
5ccbb770a6 | ||
|
|
49bf80f5d8 |
4
.github/workflows/package-linux.yml
vendored
4
.github/workflows/package-linux.yml
vendored
@@ -34,7 +34,7 @@ jobs:
|
|||||||
- name: Install python dependencies
|
- name: Install python dependencies
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y libpng-dev libjpeg-dev p7zip-full p7zip-rar python3-pip squashfs-tools libfuse2
|
sudo apt-get install -y libpng-dev libjpeg-dev p7zip-full p7zip-rar python3-pip squashfs-tools libfuse2 libxcb-cursor0
|
||||||
python -m pip install --upgrade pip setuptools wheel certifi pyinstaller --no-binary pyinstaller
|
python -m pip install --upgrade pip setuptools wheel certifi pyinstaller --no-binary pyinstaller
|
||||||
python -m pip install -r requirements.txt
|
python -m pip install -r requirements.txt
|
||||||
- name: build binary
|
- name: build binary
|
||||||
@@ -64,7 +64,7 @@ jobs:
|
|||||||
name: AppImage
|
name: AppImage
|
||||||
path: './*.AppImage*'
|
path: './*.AppImage*'
|
||||||
- name: Release
|
- name: Release
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v2
|
||||||
if: startsWith(github.ref, 'refs/tags/')
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
with:
|
with:
|
||||||
prerelease: true
|
prerelease: true
|
||||||
|
|||||||
4
.github/workflows/package-macos.yml
vendored
4
.github/workflows/package-macos.yml
vendored
@@ -25,7 +25,7 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ macos-latest, macos-14 ]
|
os: [ macos-12, macos-14 ]
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@@ -83,7 +83,7 @@ jobs:
|
|||||||
name: mac-os-build-${{ runner.arch }}
|
name: mac-os-build-${{ runner.arch }}
|
||||||
path: dist/*.dmg
|
path: dist/*.dmg
|
||||||
- name: Release
|
- name: Release
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v2
|
||||||
if: startsWith(github.ref, 'refs/tags/')
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
with:
|
with:
|
||||||
prerelease: true
|
prerelease: true
|
||||||
|
|||||||
@@ -26,24 +26,18 @@ jobs:
|
|||||||
# run: |
|
# run: |
|
||||||
# pyi-makespec -F -i icons\\comic2ebook.ico -n KCC_test -w --noupx kcc.py
|
# pyi-makespec -F -i icons\\comic2ebook.ico -n KCC_test -w --noupx kcc.py
|
||||||
- name: Package Application
|
- name: Package Application
|
||||||
uses: JackMcKew/pyinstaller-action-windows@python3-10-pyinstaller-5-3
|
uses: JackMcKew/pyinstaller-action-windows@main
|
||||||
with:
|
|
||||||
path: .
|
|
||||||
spec: ./kcc.spec
|
|
||||||
- name: Package Application
|
|
||||||
uses: JackMcKew/pyinstaller-action-windows@python3-10-pyinstaller-5-3
|
|
||||||
with:
|
with:
|
||||||
path: .
|
path: .
|
||||||
spec: ./kcc-c2e.spec
|
spec: ./kcc-c2e.spec
|
||||||
- name: Package Application
|
- name: Package Application
|
||||||
uses: JackMcKew/pyinstaller-action-windows@python3-10-pyinstaller-5-3
|
uses: JackMcKew/pyinstaller-action-windows@main
|
||||||
with:
|
with:
|
||||||
path: .
|
path: .
|
||||||
spec: ./kcc-c2p.spec
|
spec: ./kcc-c2p.spec
|
||||||
- name: rename binaries
|
- name: rename binaries
|
||||||
run: |
|
run: |
|
||||||
version_built=$(cat kindlecomicconverter/__init__.py | grep version | awk '{print $3}' | sed "s/[^.0-9b]//g")
|
version_built=$(cat kindlecomicconverter/__init__.py | grep version | awk '{print $3}' | sed "s/[^.0-9b]//g")
|
||||||
mv dist/windows/kcc.exe dist/windows/KCC_${version_built}.exe
|
|
||||||
mv dist/windows/kcc-c2e.exe dist/windows/KCC_c2e_${version_built}.exe
|
mv dist/windows/kcc-c2e.exe dist/windows/KCC_c2e_${version_built}.exe
|
||||||
mv dist/windows/kcc-c2p.exe dist/windows/KCC_c2p_${version_built}.exe
|
mv dist/windows/kcc-c2p.exe dist/windows/KCC_c2p_${version_built}.exe
|
||||||
- name: upload build
|
- name: upload build
|
||||||
@@ -52,7 +46,7 @@ jobs:
|
|||||||
name: windows-build
|
name: windows-build
|
||||||
path: dist/windows/*.exe
|
path: dist/windows/*.exe
|
||||||
- name: Release
|
- name: Release
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v2
|
||||||
if: startsWith(github.ref, 'refs/tags/')
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
with:
|
with:
|
||||||
prerelease: true
|
prerelease: true
|
||||||
|
|||||||
2
.github/workflows/package-windows.yml
vendored
2
.github/workflows/package-windows.yml
vendored
@@ -47,7 +47,7 @@ jobs:
|
|||||||
name: windows-build
|
name: windows-build
|
||||||
path: dist/*.exe
|
path: dist/*.exe
|
||||||
- name: Release
|
- name: Release
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v2
|
||||||
if: startsWith(github.ref, 'refs/tags/')
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
with:
|
with:
|
||||||
prerelease: true
|
prerelease: true
|
||||||
|
|||||||
86
README.md
86
README.md
@@ -51,33 +51,28 @@ On Mac, right click open to get past the security warning.
|
|||||||
|
|
||||||
For flatpak, Docker, and AppImage versions, refer to the wiki: https://github.com/ciromattia/kcc/wiki/Installation
|
For flatpak, Docker, and AppImage versions, refer to the wiki: https://github.com/ciromattia/kcc/wiki/Installation
|
||||||
|
|
||||||
|
## FAQ
|
||||||
|
|
||||||
|
- [Kindle Scribe cover guide](https://github.com/ciromattia/kcc/issues/508) (also works for older Kindles)
|
||||||
|
- [Windows 7 support](https://github.com/ciromattia/kcc/issues/678)
|
||||||
|
|
||||||
## PREREQUISITES
|
## PREREQUISITES
|
||||||
|
|
||||||
You'll need to install various tools to access important but optional features.
|
You'll need to install various tools to access important but optional features. Close and re-open KCC to get KCC to detect them.
|
||||||
|
|
||||||
The installation process has been greatly streamlined. No need to add 7z to PATH or locate KindleGen from the internet and put it in a special folder with KCC. Just run it and KCC will tell you what to install.
|
|
||||||
|
|
||||||
### 7-Zip
|
|
||||||
|
|
||||||
#### Windows 7-Zip
|
|
||||||
|
|
||||||
First install 7z from https://www.7-zip.org/ or with command line:
|
|
||||||
```
|
|
||||||
winget install --id 7zip.7zip
|
|
||||||
```
|
|
||||||
|
|
||||||
#### macOS 7-Zip/Unar
|
|
||||||
with [Homebrew](https://brew.sh/) installed
|
|
||||||
```
|
|
||||||
brew install p7zip
|
|
||||||
brew install unar
|
|
||||||
```
|
|
||||||
|
|
||||||
### KindleGen
|
### KindleGen
|
||||||
|
|
||||||
#### Windows / macOS KindleGen
|
#### Windows / macOS KindleGen
|
||||||
|
|
||||||
Install [Kindle Previewer](https://www.amazon.com/Kindle-Previewer/b?ie=UTF8&node=21381691011). KCC will automatically detect KindleGen from it.
|
Install [Kindle Previewer](https://www.amazon.com/Kindle-Previewer/b?ie=UTF8&node=21381691011) and `kindlegen` will be autodetected from it.
|
||||||
|
|
||||||
|
If you have issues detecting it, or use another OS, refer to the wiki: https://github.com/ciromattia/kcc/wiki/Installation#kindlegen
|
||||||
|
|
||||||
|
### 7-Zip
|
||||||
|
|
||||||
|
This is an optional requirement as of KCC 6.1.0. You only need to install it if 1) you are using advanced features, 2) are using Windows 10 (2017) or earlier, or 3) need to use an older KCC version.
|
||||||
|
|
||||||
|
If you need to install it, refer to the wiki: https://github.com/ciromattia/kcc/wiki/Installation#7-zip
|
||||||
|
|
||||||
## INPUT FORMATS
|
## INPUT FORMATS
|
||||||
**KCC** can understand and convert, at the moment, the following input types:
|
**KCC** can understand and convert, at the moment, the following input types:
|
||||||
@@ -123,14 +118,15 @@ sudo apt-get install python3 p7zip-full python3-pil python3-psutil python3-slugi
|
|||||||
'KoAO': ("Kobo Aura ONE", (1404, 1872), Palette16, 1.8),
|
'KoAO': ("Kobo Aura ONE", (1404, 1872), Palette16, 1.8),
|
||||||
'KoN': ("Kobo Nia", (758, 1024), Palette16, 1.8),
|
'KoN': ("Kobo Nia", (758, 1024), Palette16, 1.8),
|
||||||
'KoC': ("Kobo Clara HD/Kobo Clara 2E", (1072, 1448), Palette16, 1.8),
|
'KoC': ("Kobo Clara HD/Kobo Clara 2E", (1072, 1448), Palette16, 1.8),
|
||||||
|
'KoCC': ("Kobo Clara Colour", (1072, 1448), Palette16, 1.8),
|
||||||
'KoL': ("Kobo Libra H2O/Kobo Libra 2", (1264, 1680), Palette16, 1.8),
|
'KoL': ("Kobo Libra H2O/Kobo Libra 2", (1264, 1680), Palette16, 1.8),
|
||||||
|
'KoLC': ("Kobo Libra Colour", (1264, 1680), Palette16, 1.8),
|
||||||
'KoF': ("Kobo Forma", (1440, 1920), Palette16, 1.8),
|
'KoF': ("Kobo Forma", (1440, 1920), Palette16, 1.8),
|
||||||
'KoS': ("Kobo Sage", (1440, 1920), Palette16, 1.8),
|
'KoS': ("Kobo Sage", (1440, 1920), Palette16, 1.8),
|
||||||
'KoE': ("Kobo Elipsa", (1404, 1872), Palette16, 1.8),
|
'KoE': ("Kobo Elipsa", (1404, 1872), Palette16, 1.8),
|
||||||
'OTHER': ("Other", (0, 0), Palette16, 1.8),
|
'OTHER': ("Other", (0, 0), Palette16, 1.8),
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### Standalone `kcc-c2e.py` usage:
|
### Standalone `kcc-c2e.py` usage:
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -211,6 +207,54 @@ OTHER:
|
|||||||
-h, --help Show this help message and exit
|
-h, --help Show this help message and exit
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## INSTALL FROM SOURCE
|
||||||
|
|
||||||
|
This section is for developers who want to contribute to KCC or power users who want to run the latest code without waiting for an official release.
|
||||||
|
|
||||||
|
Easiest to use [GitHub Desktop](https://desktop.github.com) to clone the KCC repo. From GitHub Desktop, click on `Repository` in the toolbar, then `Command Prompt` (Windows)/`Terminal` (Mac) to open a window in the KCC repo.
|
||||||
|
|
||||||
|
Depending on your system [Python](https://www.python.org) may be called either `python` or `python3`. We use virtual environments (venv) to manage dependencies.
|
||||||
|
|
||||||
|
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 [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.
|
||||||
|
|
||||||
|
|
||||||
|
### Windows install from source
|
||||||
|
|
||||||
|
One time setup and running for the first time:
|
||||||
|
```
|
||||||
|
python -m venv venv
|
||||||
|
venv\Scripts\activate.bat
|
||||||
|
pip install -r requirements.txt
|
||||||
|
python kcc.py
|
||||||
|
```
|
||||||
|
|
||||||
|
Every time you close Command Prompt, you will need to re-activate the virtual environment and re-run:
|
||||||
|
|
||||||
|
```
|
||||||
|
venv\Scripts\activate.bat
|
||||||
|
python kcc.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### macOS install from source
|
||||||
|
|
||||||
|
One time setup and running for the first time:
|
||||||
|
```
|
||||||
|
python3 -m venv venv
|
||||||
|
source venv/bin/activate
|
||||||
|
pip install -r requirements.txt
|
||||||
|
python kcc.py
|
||||||
|
```
|
||||||
|
|
||||||
|
Every time you close Terminal, you will need to reactivate the virtual environment and re-run:
|
||||||
|
|
||||||
|
```
|
||||||
|
source venv/bin/activate
|
||||||
|
python kcc.py
|
||||||
|
```
|
||||||
|
|
||||||
## CREDITS
|
## CREDITS
|
||||||
**KCC** is made by
|
**KCC** is made by
|
||||||
|
|
||||||
|
|||||||
142
gui/KCC.ui
142
gui/KCC.ui
@@ -37,59 +37,36 @@
|
|||||||
<property name="bottomMargin">
|
<property name="bottomMargin">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<item row="1" column="1">
|
<item row="0" column="2">
|
||||||
<widget class="QCheckBox" name="upscaleBox">
|
<widget class="QCheckBox" name="qualityBox">
|
||||||
<property name="toolTip">
|
<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'><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></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Stretch/Upscale</string>
|
<string>Panel View 4/2/HQ</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="tristate">
|
<property name="tristate">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="1">
|
<item row="4" column="1">
|
||||||
<widget class="QCheckBox" name="rotateBox">
|
<widget class="QCheckBox" name="deleteBox">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><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></string>
|
<string>Delete input file(s) or directory. It's not recoverable!</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Spread splitter</string>
|
<string>Delete input</string>
|
||||||
</property>
|
|
||||||
<property name="tristate">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="1">
|
<item row="3" column="1">
|
||||||
<widget class="QCheckBox" name="outputSplit">
|
<widget class="QCheckBox" name="maximizeStrips">
|
||||||
<property name="toolTip">
|
<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>
|
<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>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Output split</string>
|
<string>1x4 to 2x2 strips</string>
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" 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="2" 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>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@@ -116,6 +93,29 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="1" 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="1" 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="0" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QCheckBox" name="mangaBox">
|
<widget class="QCheckBox" name="mangaBox">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
@@ -126,42 +126,19 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="2">
|
<item row="0" column="1">
|
||||||
<widget class="QCheckBox" name="qualityBox">
|
<widget class="QCheckBox" name="rotateBox">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><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></string>
|
<string><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></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Panel View 4/2/HQ</string>
|
<string>Spread splitter</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="tristate">
|
<property name="tristate">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" 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="3" 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="2">
|
<item row="3" column="2">
|
||||||
<widget class="QCheckBox" name="croppingBox">
|
<widget class="QCheckBox" name="croppingBox">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
@@ -175,13 +152,36 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="1">
|
<item row="2" column="1">
|
||||||
<widget class="QCheckBox" name="deleteBox">
|
<widget class="QCheckBox" name="outputSplit">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Delete input file(s) or directory. It's not recoverable!</string>
|
<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>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Delete input</string>
|
<string>Output split</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" 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="2" 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>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@@ -195,6 +195,16 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="4" column="0">
|
||||||
|
<widget class="QCheckBox" name="dedupeCoverBox">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p>Don't duplicate the first page as the cover. Useful for 2 page spread alignment.</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>De-dupe cover</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|||||||
5
kcc.py
5
kcc.py
@@ -50,7 +50,12 @@ elif sys.platform.startswith('win'):
|
|||||||
win_paths = [
|
win_paths = [
|
||||||
os.path.expandvars('%LOCALAPPDATA%\\Amazon\\KC2'),
|
os.path.expandvars('%LOCALAPPDATA%\\Amazon\\KC2'),
|
||||||
os.path.expandvars('%LOCALAPPDATA%\\Amazon\\Kindle Previewer 3\\lib\\fc\\bin\\'),
|
os.path.expandvars('%LOCALAPPDATA%\\Amazon\\Kindle Previewer 3\\lib\\fc\\bin\\'),
|
||||||
|
'C:\\Apps\\Kindle Previewer 3\\lib\\fc\\bin',
|
||||||
|
'D:\\Apps\\Kindle Previewer 3\\lib\\fc\\bin',
|
||||||
|
'E:\\Apps\\Kindle Previewer 3\\lib\\fc\\bin',
|
||||||
'C:\\Program Files\\7-Zip',
|
'C:\\Program Files\\7-Zip',
|
||||||
|
'D:\\Program Files\\7-Zip',
|
||||||
|
'E:\\Program Files\\7-Zip',
|
||||||
]
|
]
|
||||||
if getattr(sys, 'frozen', False):
|
if getattr(sys, 'frozen', False):
|
||||||
os.environ['PATH'] += os.pathsep + os.pathsep.join(win_paths)
|
os.environ['PATH'] += os.pathsep + os.pathsep.join(win_paths)
|
||||||
|
|||||||
39
kcc.spec
39
kcc.spec
@@ -1,39 +0,0 @@
|
|||||||
# -*- mode: python ; coding: utf-8 -*-
|
|
||||||
|
|
||||||
|
|
||||||
block_cipher = None
|
|
||||||
|
|
||||||
|
|
||||||
a = Analysis(['kcc.py'],
|
|
||||||
pathex=['.'],
|
|
||||||
binaries=[],
|
|
||||||
datas=[],
|
|
||||||
hiddenimports=[],
|
|
||||||
hookspath=[],
|
|
||||||
runtime_hooks=[],
|
|
||||||
excludes=[],
|
|
||||||
win_no_prefer_redirects=False,
|
|
||||||
win_private_assemblies=False,
|
|
||||||
cipher=block_cipher,
|
|
||||||
noarchive=False)
|
|
||||||
pyz = PYZ(a.pure, a.zipped_data,
|
|
||||||
cipher=block_cipher)
|
|
||||||
|
|
||||||
exe = EXE(pyz,
|
|
||||||
a.scripts,
|
|
||||||
a.binaries,
|
|
||||||
a.zipfiles,
|
|
||||||
a.datas,
|
|
||||||
[],
|
|
||||||
name='kcc',
|
|
||||||
debug=False,
|
|
||||||
bootloader_ignore_signals=False,
|
|
||||||
strip=False,
|
|
||||||
upx=False,
|
|
||||||
upx_exclude=[],
|
|
||||||
runtime_tmpdir=None,
|
|
||||||
console=False,
|
|
||||||
disable_windowed_traceback=False,
|
|
||||||
target_arch=None,
|
|
||||||
codesign_identity=None,
|
|
||||||
entitlements_file=None , icon='icons\\comic2ebook.ico')
|
|
||||||
@@ -254,6 +254,8 @@ class WorkerThread(QtCore.QThread):
|
|||||||
options.noprocessing = True
|
options.noprocessing = True
|
||||||
if GUI.deleteBox.isChecked():
|
if GUI.deleteBox.isChecked():
|
||||||
options.delete = True
|
options.delete = True
|
||||||
|
if GUI.dedupeCoverBox.isChecked():
|
||||||
|
options.dedupecover = True
|
||||||
if GUI.mozJpegBox.checkState() == Qt.CheckState.PartiallyChecked:
|
if GUI.mozJpegBox.checkState() == Qt.CheckState.PartiallyChecked:
|
||||||
options.forcepng = True
|
options.forcepng = True
|
||||||
elif GUI.mozJpegBox.checkState() == Qt.CheckState.Checked:
|
elif GUI.mozJpegBox.checkState() == Qt.CheckState.Checked:
|
||||||
@@ -462,7 +464,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
if self.needClean:
|
if self.needClean:
|
||||||
self.needClean = False
|
self.needClean = False
|
||||||
GUI.jobList.clear()
|
GUI.jobList.clear()
|
||||||
if self.sevenzip:
|
if self.tar or self.sevenzip:
|
||||||
fnames = QtWidgets.QFileDialog.getOpenFileNames(MW, 'Select file', self.lastPath,
|
fnames = QtWidgets.QFileDialog.getOpenFileNames(MW, 'Select file', self.lastPath,
|
||||||
'Comic (*.cbz *.cbr *.cb7 *.zip *.rar *.7z *.pdf);;All (*.*)')
|
'Comic (*.cbz *.cbr *.cb7 *.zip *.rar *.7z *.pdf);;All (*.*)')
|
||||||
else:
|
else:
|
||||||
@@ -492,6 +494,8 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
else:
|
else:
|
||||||
fname = ['']
|
fname = ['']
|
||||||
self.showDialog("Editor is disabled due to a lack of 7z.", 'error')
|
self.showDialog("Editor is disabled due to a lack of 7z.", 'error')
|
||||||
|
self.addMessage('<a href="https://github.com/ciromattia/kcc#7-zip">Install 7z (link)</a>'
|
||||||
|
' to enable metadata editing.', 'warning')
|
||||||
if fname[0] != '':
|
if fname[0] != '':
|
||||||
if sys.platform.startswith('win'):
|
if sys.platform.startswith('win'):
|
||||||
sname = fname[0].replace('/', '\\')
|
sname = fname[0].replace('/', '\\')
|
||||||
@@ -638,6 +642,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
self.modeChange(2)
|
self.modeChange(2)
|
||||||
else:
|
else:
|
||||||
self.modeChange(1)
|
self.modeChange(1)
|
||||||
|
GUI.colorBox.setChecked(profile['ForceColor'])
|
||||||
self.changeFormat()
|
self.changeFormat()
|
||||||
GUI.gammaSlider.setValue(0)
|
GUI.gammaSlider.setValue(0)
|
||||||
self.changeGamma(0)
|
self.changeGamma(0)
|
||||||
@@ -787,6 +792,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
'widthBox': GUI.widthBox.value(),
|
'widthBox': GUI.widthBox.value(),
|
||||||
'heightBox': GUI.heightBox.value(),
|
'heightBox': GUI.heightBox.value(),
|
||||||
'deleteBox': GUI.deleteBox.checkState().value,
|
'deleteBox': GUI.deleteBox.checkState().value,
|
||||||
|
'dedupeCoverBox': GUI.dedupeCoverBox.checkState().value,
|
||||||
'maximizeStrips': GUI.maximizeStrips.checkState().value,
|
'maximizeStrips': GUI.maximizeStrips.checkState().value,
|
||||||
'gammaSlider': float(self.gammaValue) * 100})
|
'gammaSlider': float(self.gammaValue) * 100})
|
||||||
self.settings.sync()
|
self.settings.sync()
|
||||||
@@ -802,7 +808,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
self.needClean = False
|
self.needClean = False
|
||||||
GUI.jobList.clear()
|
GUI.jobList.clear()
|
||||||
formats = ['.pdf']
|
formats = ['.pdf']
|
||||||
if self.sevenzip:
|
if self.tar or self.sevenzip:
|
||||||
formats.extend(['.cb7', '.7z', '.cbz', '.zip', '.cbr', '.rar'])
|
formats.extend(['.cb7', '.7z', '.cbz', '.zip', '.cbr', '.rar'])
|
||||||
if os.path.isdir(message):
|
if os.path.isdir(message):
|
||||||
GUI.jobList.addItem(message)
|
GUI.jobList.addItem(message)
|
||||||
@@ -914,67 +920,71 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
|
|
||||||
self.profiles = {
|
self.profiles = {
|
||||||
"Kindle Oasis 9/10": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle Oasis 9/10": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': True, 'Label': 'KO'},
|
'DefaultUpscale': True, 'ForceColor': False, 'Label': 'KO'},
|
||||||
"Kindle Oasis 8": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle Oasis 8": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': True, 'Label': 'KV'},
|
'DefaultUpscale': True, 'ForceColor': False, 'Label': 'KV'},
|
||||||
"Kindle Voyage": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle Voyage": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': True, 'Label': 'KV'},
|
'DefaultUpscale': True, 'ForceColor': False, 'Label': 'KV'},
|
||||||
"Kindle Scribe": {
|
"Kindle Scribe": {
|
||||||
'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': False, 'Label': 'KS',
|
'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': False, 'ForceColor': False, 'Label': 'KS',
|
||||||
},
|
},
|
||||||
"Kindle 11": {
|
"Kindle 11": {
|
||||||
'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': True, 'Label': 'K11',
|
'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': True, 'ForceColor': False, 'Label': 'K11',
|
||||||
},
|
},
|
||||||
"Kindle PW 11": {
|
"Kindle PW 11": {
|
||||||
'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': True, 'Label': 'KPW5',
|
'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': True, 'ForceColor': False, 'Label': 'KPW5',
|
||||||
},
|
},
|
||||||
"Kindle PW 7/10": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle PW 7/10": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': True, 'Label': 'KV'},
|
'DefaultUpscale': True, 'ForceColor': False, 'Label': 'KV'},
|
||||||
"Kindle PW 5/6": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle PW 5/6": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': False, 'Label': 'KPW'},
|
'DefaultUpscale': False, 'ForceColor': False, 'Label': 'KPW'},
|
||||||
"Kindle 4/5/7/8/10": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle 4/5/7/8/10": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': False, 'Label': 'K578'},
|
'DefaultUpscale': False, 'ForceColor': False, 'Label': 'K578'},
|
||||||
"Kindle DX": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 2,
|
"Kindle DX": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 2,
|
||||||
'DefaultUpscale': False, 'Label': 'KDX'},
|
'DefaultUpscale': False, 'ForceColor': False, 'Label': 'KDX'},
|
||||||
"Kobo Mini/Touch": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
"Kobo Mini/Touch": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
||||||
'DefaultUpscale': False, 'Label': 'KoMT'},
|
'DefaultUpscale': False, 'ForceColor': False, 'Label': 'KoMT'},
|
||||||
"Kobo Glo": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
"Kobo Glo": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
||||||
'DefaultUpscale': False, 'Label': 'KoG'},
|
'DefaultUpscale': False, 'ForceColor': False, 'Label': 'KoG'},
|
||||||
"Kobo Glo HD": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
"Kobo Glo HD": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
||||||
'DefaultUpscale': False, 'Label': 'KoGHD'},
|
'DefaultUpscale': False, 'ForceColor': False, 'Label': 'KoGHD'},
|
||||||
"Kobo Aura": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
"Kobo Aura": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
||||||
'DefaultUpscale': False, 'Label': 'KoA'},
|
'DefaultUpscale': False, 'ForceColor': False, 'Label': 'KoA'},
|
||||||
"Kobo Aura HD": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
"Kobo Aura HD": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
||||||
'DefaultUpscale': True, 'Label': 'KoAHD'},
|
'DefaultUpscale': True, 'ForceColor': False, 'Label': 'KoAHD'},
|
||||||
"Kobo Aura H2O": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
"Kobo Aura H2O": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
||||||
'DefaultUpscale': True, 'Label': 'KoAH2O'},
|
'DefaultUpscale': True, 'ForceColor': False, 'Label': 'KoAH2O'},
|
||||||
"Kobo Aura ONE": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
"Kobo Aura ONE": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
||||||
'DefaultUpscale': True, 'Label': 'KoAO'},
|
'DefaultUpscale': True, 'ForceColor': False, 'Label': 'KoAO'},
|
||||||
"Kobo Clara HD": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
"Kobo Clara HD": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
||||||
'DefaultUpscale': True, 'Label': 'KoC'},
|
'DefaultUpscale': True, 'ForceColor': False, 'Label': 'KoC'},
|
||||||
"Kobo Libra H2O": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
"Kobo Libra H2O": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
||||||
'DefaultUpscale': True, 'Label': 'KoL'},
|
'DefaultUpscale': True, 'ForceColor': False, 'Label': 'KoL'},
|
||||||
"Kobo Forma": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
"Kobo Forma": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
||||||
'DefaultUpscale': True, 'Label': 'KoF'},
|
'DefaultUpscale': True, 'ForceColor': False, 'Label': 'KoF'},
|
||||||
"Kindle 1": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle 1": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': False, 'Label': 'K1'},
|
'DefaultUpscale': False, 'ForceColor': False, 'Label': 'K1'},
|
||||||
"Kindle 2": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle 2": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': False, 'Label': 'K2'},
|
'DefaultUpscale': False, 'ForceColor': False, 'Label': 'K2'},
|
||||||
"Kindle Keyboard": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle Keyboard": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': False, 'Label': 'K34'},
|
'DefaultUpscale': False, 'ForceColor': False, 'Label': 'K34'},
|
||||||
"Kindle Touch": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle Touch": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': False, 'Label': 'K34'},
|
'DefaultUpscale': False, 'ForceColor': False, 'Label': 'K34'},
|
||||||
"Kobo Nia": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': True,
|
"Kobo Nia": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': True, 'ForceColor': False,
|
||||||
'Label': 'KoN'},
|
'Label': 'KoN'},
|
||||||
"Kobo Clara 2E": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': True,
|
"Kobo Clara 2E": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': True, 'ForceColor': False,
|
||||||
'Label': 'KoC'},
|
'Label': 'KoC'},
|
||||||
"Kobo Libra 2": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': True,
|
"Kobo Clara Colour": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': True, 'ForceColor': True,
|
||||||
|
'Label': 'KoCC'},
|
||||||
|
"Kobo Libra 2": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': True, 'ForceColor': False,
|
||||||
'Label': 'KoL'},
|
'Label': 'KoL'},
|
||||||
"Kobo Sage": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': True,
|
"Kobo Libra Colour": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': True, 'ForceColor': True,
|
||||||
|
'Label': 'KoLC'},
|
||||||
|
"Kobo Sage": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': True, 'ForceColor': False,
|
||||||
'Label': 'KoS'},
|
'Label': 'KoS'},
|
||||||
"Kobo Elipsa": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': True,
|
"Kobo Elipsa": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1, 'DefaultUpscale': True, 'ForceColor': False,
|
||||||
'Label': 'KoE'},
|
'Label': 'KoE'},
|
||||||
"Other": {'PVOptions': False, 'ForceExpert': True, 'DefaultFormat': 1, 'DefaultUpscale': False,
|
"Other": {'PVOptions': False, 'ForceExpert': True, 'DefaultFormat': 1, 'DefaultUpscale': False, 'ForceColor': False,
|
||||||
'Label': 'OTHER'},
|
'Label': 'OTHER'},
|
||||||
}
|
}
|
||||||
profilesGUI = [
|
profilesGUI = [
|
||||||
@@ -984,8 +994,10 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
"Kindle Oasis 9/10",
|
"Kindle Oasis 9/10",
|
||||||
"Separator",
|
"Separator",
|
||||||
"Kobo Clara 2E",
|
"Kobo Clara 2E",
|
||||||
|
"Kobo Clara Colour",
|
||||||
"Kobo Sage",
|
"Kobo Sage",
|
||||||
"Kobo Libra 2",
|
"Kobo Libra 2",
|
||||||
|
"Kobo Libra Colour",
|
||||||
"Kobo Elipsa",
|
"Kobo Elipsa",
|
||||||
"Kobo Nia",
|
"Kobo Nia",
|
||||||
"Separator",
|
"Separator",
|
||||||
@@ -1028,13 +1040,19 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
self.addMessage('Since you are a new user of <b>KCC</b> please see few '
|
self.addMessage('Since you are a new user of <b>KCC</b> please see few '
|
||||||
'<a href="https://github.com/ciromattia/kcc/wiki/Important-tips">important tips</a>.',
|
'<a href="https://github.com/ciromattia/kcc/wiki/Important-tips">important tips</a>.',
|
||||||
'info')
|
'info')
|
||||||
|
try:
|
||||||
|
subprocess_run_silent(['tar'], stdout=PIPE, stderr=STDOUT)
|
||||||
|
self.tar = True
|
||||||
|
except FileNotFoundError:
|
||||||
|
self.tar = False
|
||||||
try:
|
try:
|
||||||
subprocess_run_silent(['7z'], stdout=PIPE, stderr=STDOUT)
|
subprocess_run_silent(['7z'], stdout=PIPE, stderr=STDOUT)
|
||||||
self.sevenzip = True
|
self.sevenzip = True
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
self.sevenzip = False
|
self.sevenzip = False
|
||||||
self.addMessage('<a href="https://github.com/ciromattia/kcc#7-zip">Install 7z (link)</a>'
|
if not self.tar:
|
||||||
' to enable CBZ/CBR/ZIP/etc processing.', 'warning')
|
self.addMessage('<a href="https://github.com/ciromattia/kcc#7-zip">Install 7z (link)</a>'
|
||||||
|
' to enable CBZ/CBR/ZIP/etc processing.', 'warning')
|
||||||
self.detectKindleGen(True)
|
self.detectKindleGen(True)
|
||||||
|
|
||||||
APP.messageFromOtherInstance.connect(self.handleMessage)
|
APP.messageFromOtherInstance.connect(self.handleMessage)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Resource object code (Python 3)
|
# Resource object code (Python 3)
|
||||||
# Created by: object code
|
# Created by: object code
|
||||||
# Created by: The Resource Compiler for Qt version 6.5.1
|
# Created by: The Resource Compiler for Qt version 6.5.2
|
||||||
# WARNING! All changes made in this file will be lost!
|
# WARNING! All changes made in this file will be lost!
|
||||||
|
|
||||||
from PySide6 import QtCore
|
from PySide6 import QtCore
|
||||||
@@ -11476,49 +11476,49 @@ qt_resource_struct = b"\
|
|||||||
\x00\x00\x00X\x00\x02\x00\x00\x00\x04\x00\x00\x00\x07\
|
\x00\x00\x00X\x00\x02\x00\x00\x00\x04\x00\x00\x00\x07\
|
||||||
\x00\x00\x00\x00\x00\x00\x00\x00\
|
\x00\x00\x00\x00\x00\x00\x00\x00\
|
||||||
\x00\x00\x01\xac\x00\x00\x00\x00\x00\x01\x00\x02&\xd7\
|
\x00\x00\x01\xac\x00\x00\x00\x00\x00\x01\x00\x02&\xd7\
|
||||||
\x00\x00\x01\x89\x0c\xe8\xc1\x86\
|
\x00\x00\x01\x88;p\xbcB\
|
||||||
\x00\x00\x01\xea\x00\x00\x00\x00\x00\x01\x00\x02{q\
|
\x00\x00\x01\xea\x00\x00\x00\x00\x00\x01\x00\x02{q\
|
||||||
\x00\x00\x01\x89\x0c\xe8\xc1\x85\
|
\x00\x00\x01\x88;p\xbcB\
|
||||||
\x00\x00\x01\xd6\x00\x00\x00\x00\x00\x01\x00\x02Qv\
|
\x00\x00\x01\xd6\x00\x00\x00\x00\x00\x01\x00\x02Qv\
|
||||||
\x00\x00\x01\x89\x0c\xe8\xc1\x84\
|
\x00\x00\x01\x88;p\xbcB\
|
||||||
\x00\x00\x01\xc2\x00\x00\x00\x00\x00\x01\x00\x02F\x13\
|
\x00\x00\x01\xc2\x00\x00\x00\x00\x00\x01\x00\x02F\x13\
|
||||||
\x00\x00\x01\x89\x0c\xe8\xc1\x85\
|
\x00\x00\x01\x89\x89D9.\
|
||||||
\x00\x00\x00X\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0c\
|
\x00\x00\x00X\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0c\
|
||||||
\x00\x00\x00\x00\x00\x00\x00\x00\
|
\x00\x00\x00\x00\x00\x00\x00\x00\
|
||||||
\x00\x00\x00\xa6\x00\x00\x00\x00\x00\x01\x00\x01(\x97\
|
\x00\x00\x00\xa6\x00\x00\x00\x00\x00\x01\x00\x01(\x97\
|
||||||
\x00\x00\x01\x89\x0c\xe8\xc1\x86\
|
\x00\x00\x01\x88;p\xbcB\
|
||||||
\x00\x00\x00\x8c\x00\x00\x00\x00\x00\x01\x00\x01\x1d\x90\
|
\x00\x00\x00\x8c\x00\x00\x00\x00\x00\x01\x00\x01\x1d\x90\
|
||||||
\x00\x00\x01\x89\x0c\xe8\xc1\x86\
|
\x00\x00\x01\x88;p\xbcB\
|
||||||
\x00\x00\x00\xbc\x00\x00\x00\x00\x00\x01\x00\x011\xef\
|
\x00\x00\x00\xbc\x00\x00\x00\x00\x00\x01\x00\x011\xef\
|
||||||
\x00\x00\x01\x89\x0c\xe8\xc1\x87\
|
\x00\x00\x01\x88;p\xbcB\
|
||||||
\x00\x00\x00X\x00\x02\x00\x00\x00\x03\x00\x00\x00\x10\
|
\x00\x00\x00X\x00\x02\x00\x00\x00\x03\x00\x00\x00\x10\
|
||||||
\x00\x00\x00\x00\x00\x00\x00\x00\
|
\x00\x00\x00\x00\x00\x00\x00\x00\
|
||||||
\x00\x00\x02.\x00\x00\x00\x00\x00\x01\x00\x02\xad\xbd\
|
\x00\x00\x02.\x00\x00\x00\x00\x00\x01\x00\x02\xad\xbd\
|
||||||
\x00\x00\x01\x89\x0c\xe8\xc1\x9a\
|
\x00\x00\x01\x88;p\xbcJ\
|
||||||
\x00\x00\x02\x00\x00\x00\x00\x00\x00\x01\x00\x02\x97\xc0\
|
\x00\x00\x02\x00\x00\x00\x00\x00\x00\x01\x00\x02\x97\xc0\
|
||||||
\x00\x00\x01\x89\x0c\xe8\xc1\x98\
|
\x00\x00\x01\x88;p\xbcI\
|
||||||
\x00\x00\x02\x16\x00\x00\x00\x00\x00\x01\x00\x02\xa1\x1d\
|
\x00\x00\x02\x16\x00\x00\x00\x00\x00\x01\x00\x02\xa1\x1d\
|
||||||
\x00\x00\x01\x89\x0c\xe8\xc1\x97\
|
\x00\x00\x01\x88;p\xbcI\
|
||||||
\x00\x00\x00X\x00\x02\x00\x00\x00\x07\x00\x00\x00\x14\
|
\x00\x00\x00X\x00\x02\x00\x00\x00\x07\x00\x00\x00\x14\
|
||||||
\x00\x00\x00\x00\x00\x00\x00\x00\
|
\x00\x00\x00\x00\x00\x00\x00\x00\
|
||||||
\x00\x00\x01\x08\x00\x00\x00\x00\x00\x01\x00\x01H\x9b\
|
\x00\x00\x01\x08\x00\x00\x00\x00\x00\x01\x00\x01H\x9b\
|
||||||
\x00\x00\x01\x89\x0c\xe8\xc1\x9b\
|
\x00\x00\x01\x88;p\xbcJ\
|
||||||
\x00\x00\x01\x1e\x00\x00\x00\x00\x00\x01\x00\x01qC\
|
\x00\x00\x01\x1e\x00\x00\x00\x00\x00\x01\x00\x01qC\
|
||||||
\x00\x00\x01\x89\x0c\xe8\xc1\x97\
|
\x00\x00\x01\x88;p\xbcI\
|
||||||
\x00\x00\x01\x80\x00\x00\x00\x00\x00\x01\x00\x01\xca\x17\
|
\x00\x00\x01\x80\x00\x00\x00\x00\x00\x01\x00\x01\xca\x17\
|
||||||
\x00\x00\x01\x89\x0c\xe8\xc1\x98\
|
\x00\x00\x01\x88;p\xbcI\
|
||||||
\x00\x00\x01f\x00\x00\x00\x00\x00\x01\x00\x01\x84\xd0\
|
\x00\x00\x01f\x00\x00\x00\x00\x00\x01\x00\x01\x84\xd0\
|
||||||
\x00\x00\x01\x89\x0c\xe8\xc1\x97\
|
\x00\x00\x01\x88;p\xbcH\
|
||||||
\x00\x00\x00\xf0\x00\x00\x00\x00\x00\x01\x00\x01D<\
|
\x00\x00\x00\xf0\x00\x00\x00\x00\x00\x01\x00\x01D<\
|
||||||
\x00\x00\x01\x89\x0c\xe8\xc1\x8f\
|
\x00\x00\x01\x88;p\xbcF\
|
||||||
\x00\x00\x00\xd4\x00\x00\x00\x00\x00\x01\x00\x017\xd3\
|
\x00\x00\x00\xd4\x00\x00\x00\x00\x00\x01\x00\x017\xd3\
|
||||||
\x00\x00\x01\x89\x0c\xe8\xc1\x96\
|
\x00\x00\x01\x88;p\xbcH\
|
||||||
\x00\x00\x01@\x00\x00\x00\x00\x00\x01\x00\x01z\x9a\
|
\x00\x00\x01@\x00\x00\x00\x00\x00\x01\x00\x01z\x9a\
|
||||||
\x00\x00\x01\x89\x0c\xe8\xc1\x96\
|
\x00\x00\x01\x88;p\xbcH\
|
||||||
\x00\x00\x00X\x00\x02\x00\x00\x00\x01\x00\x00\x00\x1c\
|
\x00\x00\x00X\x00\x02\x00\x00\x00\x01\x00\x00\x00\x1c\
|
||||||
\x00\x00\x00\x00\x00\x00\x00\x00\
|
\x00\x00\x00\x00\x00\x00\x00\x00\
|
||||||
\x00\x00\x00h\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
|
\x00\x00\x00h\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
|
||||||
\x00\x00\x01\x89\x0c\xe8\xc1\x96\
|
\x00\x00\x01\x88;p\xbcH\
|
||||||
"
|
"
|
||||||
|
|
||||||
def qInitResources():
|
def qInitResources():
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
################################################################################
|
################################################################################
|
||||||
## Form generated from reading UI file 'KCC.ui'
|
## Form generated from reading UI file 'KCC.ui'
|
||||||
##
|
##
|
||||||
## Created by: Qt User Interface Compiler version 6.5.1
|
## Created by: Qt User Interface Compiler version 6.5.2
|
||||||
##
|
##
|
||||||
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
||||||
################################################################################
|
################################################################################
|
||||||
@@ -40,32 +40,21 @@ class Ui_mainWindow(object):
|
|||||||
self.gridLayout_2 = QGridLayout(self.optionWidget)
|
self.gridLayout_2 = QGridLayout(self.optionWidget)
|
||||||
self.gridLayout_2.setObjectName(u"gridLayout_2")
|
self.gridLayout_2.setObjectName(u"gridLayout_2")
|
||||||
self.gridLayout_2.setContentsMargins(0, 0, 0, 0)
|
self.gridLayout_2.setContentsMargins(0, 0, 0, 0)
|
||||||
self.upscaleBox = QCheckBox(self.optionWidget)
|
self.qualityBox = QCheckBox(self.optionWidget)
|
||||||
self.upscaleBox.setObjectName(u"upscaleBox")
|
self.qualityBox.setObjectName(u"qualityBox")
|
||||||
self.upscaleBox.setTristate(True)
|
self.qualityBox.setTristate(True)
|
||||||
|
|
||||||
self.gridLayout_2.addWidget(self.upscaleBox, 1, 1, 1, 1)
|
self.gridLayout_2.addWidget(self.qualityBox, 0, 2, 1, 1)
|
||||||
|
|
||||||
self.rotateBox = QCheckBox(self.optionWidget)
|
self.deleteBox = QCheckBox(self.optionWidget)
|
||||||
self.rotateBox.setObjectName(u"rotateBox")
|
self.deleteBox.setObjectName(u"deleteBox")
|
||||||
self.rotateBox.setTristate(True)
|
|
||||||
|
|
||||||
self.gridLayout_2.addWidget(self.rotateBox, 0, 1, 1, 1)
|
self.gridLayout_2.addWidget(self.deleteBox, 4, 1, 1, 1)
|
||||||
|
|
||||||
self.outputSplit = QCheckBox(self.optionWidget)
|
self.maximizeStrips = QCheckBox(self.optionWidget)
|
||||||
self.outputSplit.setObjectName(u"outputSplit")
|
self.maximizeStrips.setObjectName(u"maximizeStrips")
|
||||||
|
|
||||||
self.gridLayout_2.addWidget(self.outputSplit, 2, 1, 1, 1)
|
self.gridLayout_2.addWidget(self.maximizeStrips, 3, 1, 1, 1)
|
||||||
|
|
||||||
self.webtoonBox = QCheckBox(self.optionWidget)
|
|
||||||
self.webtoonBox.setObjectName(u"webtoonBox")
|
|
||||||
|
|
||||||
self.gridLayout_2.addWidget(self.webtoonBox, 1, 0, 1, 1)
|
|
||||||
|
|
||||||
self.colorBox = QCheckBox(self.optionWidget)
|
|
||||||
self.colorBox.setObjectName(u"colorBox")
|
|
||||||
|
|
||||||
self.gridLayout_2.addWidget(self.colorBox, 2, 2, 1, 1)
|
|
||||||
|
|
||||||
self.gammaBox = QCheckBox(self.optionWidget)
|
self.gammaBox = QCheckBox(self.optionWidget)
|
||||||
self.gammaBox.setObjectName(u"gammaBox")
|
self.gammaBox.setObjectName(u"gammaBox")
|
||||||
@@ -78,27 +67,27 @@ class Ui_mainWindow(object):
|
|||||||
|
|
||||||
self.gridLayout_2.addWidget(self.borderBox, 2, 0, 1, 1)
|
self.gridLayout_2.addWidget(self.borderBox, 2, 0, 1, 1)
|
||||||
|
|
||||||
|
self.webtoonBox = QCheckBox(self.optionWidget)
|
||||||
|
self.webtoonBox.setObjectName(u"webtoonBox")
|
||||||
|
|
||||||
|
self.gridLayout_2.addWidget(self.webtoonBox, 1, 0, 1, 1)
|
||||||
|
|
||||||
|
self.upscaleBox = QCheckBox(self.optionWidget)
|
||||||
|
self.upscaleBox.setObjectName(u"upscaleBox")
|
||||||
|
self.upscaleBox.setTristate(True)
|
||||||
|
|
||||||
|
self.gridLayout_2.addWidget(self.upscaleBox, 1, 1, 1, 1)
|
||||||
|
|
||||||
self.mangaBox = QCheckBox(self.optionWidget)
|
self.mangaBox = QCheckBox(self.optionWidget)
|
||||||
self.mangaBox.setObjectName(u"mangaBox")
|
self.mangaBox.setObjectName(u"mangaBox")
|
||||||
|
|
||||||
self.gridLayout_2.addWidget(self.mangaBox, 0, 0, 1, 1)
|
self.gridLayout_2.addWidget(self.mangaBox, 0, 0, 1, 1)
|
||||||
|
|
||||||
self.qualityBox = QCheckBox(self.optionWidget)
|
self.rotateBox = QCheckBox(self.optionWidget)
|
||||||
self.qualityBox.setObjectName(u"qualityBox")
|
self.rotateBox.setObjectName(u"rotateBox")
|
||||||
self.qualityBox.setTristate(True)
|
self.rotateBox.setTristate(True)
|
||||||
|
|
||||||
self.gridLayout_2.addWidget(self.qualityBox, 0, 2, 1, 1)
|
self.gridLayout_2.addWidget(self.rotateBox, 0, 1, 1, 1)
|
||||||
|
|
||||||
self.mozJpegBox = QCheckBox(self.optionWidget)
|
|
||||||
self.mozJpegBox.setObjectName(u"mozJpegBox")
|
|
||||||
self.mozJpegBox.setTristate(True)
|
|
||||||
|
|
||||||
self.gridLayout_2.addWidget(self.mozJpegBox, 3, 0, 1, 1)
|
|
||||||
|
|
||||||
self.maximizeStrips = QCheckBox(self.optionWidget)
|
|
||||||
self.maximizeStrips.setObjectName(u"maximizeStrips")
|
|
||||||
|
|
||||||
self.gridLayout_2.addWidget(self.maximizeStrips, 3, 1, 1, 1)
|
|
||||||
|
|
||||||
self.croppingBox = QCheckBox(self.optionWidget)
|
self.croppingBox = QCheckBox(self.optionWidget)
|
||||||
self.croppingBox.setObjectName(u"croppingBox")
|
self.croppingBox.setObjectName(u"croppingBox")
|
||||||
@@ -106,16 +95,32 @@ class Ui_mainWindow(object):
|
|||||||
|
|
||||||
self.gridLayout_2.addWidget(self.croppingBox, 3, 2, 1, 1)
|
self.gridLayout_2.addWidget(self.croppingBox, 3, 2, 1, 1)
|
||||||
|
|
||||||
self.deleteBox = QCheckBox(self.optionWidget)
|
self.outputSplit = QCheckBox(self.optionWidget)
|
||||||
self.deleteBox.setObjectName(u"deleteBox")
|
self.outputSplit.setObjectName(u"outputSplit")
|
||||||
|
|
||||||
self.gridLayout_2.addWidget(self.deleteBox, 4, 1, 1, 1)
|
self.gridLayout_2.addWidget(self.outputSplit, 2, 1, 1, 1)
|
||||||
|
|
||||||
|
self.mozJpegBox = QCheckBox(self.optionWidget)
|
||||||
|
self.mozJpegBox.setObjectName(u"mozJpegBox")
|
||||||
|
self.mozJpegBox.setTristate(True)
|
||||||
|
|
||||||
|
self.gridLayout_2.addWidget(self.mozJpegBox, 3, 0, 1, 1)
|
||||||
|
|
||||||
|
self.colorBox = QCheckBox(self.optionWidget)
|
||||||
|
self.colorBox.setObjectName(u"colorBox")
|
||||||
|
|
||||||
|
self.gridLayout_2.addWidget(self.colorBox, 2, 2, 1, 1)
|
||||||
|
|
||||||
self.disableProcessingBox = QCheckBox(self.optionWidget)
|
self.disableProcessingBox = QCheckBox(self.optionWidget)
|
||||||
self.disableProcessingBox.setObjectName(u"disableProcessingBox")
|
self.disableProcessingBox.setObjectName(u"disableProcessingBox")
|
||||||
|
|
||||||
self.gridLayout_2.addWidget(self.disableProcessingBox, 4, 2, 1, 1)
|
self.gridLayout_2.addWidget(self.disableProcessingBox, 4, 2, 1, 1)
|
||||||
|
|
||||||
|
self.dedupeCoverBox = QCheckBox(self.optionWidget)
|
||||||
|
self.dedupeCoverBox.setObjectName(u"dedupeCoverBox")
|
||||||
|
|
||||||
|
self.gridLayout_2.addWidget(self.dedupeCoverBox, 4, 0, 1, 1)
|
||||||
|
|
||||||
|
|
||||||
self.gridLayout.addWidget(self.optionWidget, 5, 0, 1, 2)
|
self.gridLayout.addWidget(self.optionWidget, 5, 0, 1, 2)
|
||||||
|
|
||||||
@@ -355,25 +360,17 @@ class Ui_mainWindow(object):
|
|||||||
def retranslateUi(self, mainWindow):
|
def retranslateUi(self, mainWindow):
|
||||||
mainWindow.setWindowTitle(QCoreApplication.translate("mainWindow", u"Kindle Comic Converter", None))
|
mainWindow.setWindowTitle(QCoreApplication.translate("mainWindow", u"Kindle Comic Converter", None))
|
||||||
#if QT_CONFIG(tooltip)
|
#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))
|
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)
|
#endif // QT_CONFIG(tooltip)
|
||||||
self.upscaleBox.setText(QCoreApplication.translate("mainWindow", u"Stretch/Upscale", None))
|
self.qualityBox.setText(QCoreApplication.translate("mainWindow", u"Panel View 4/2/HQ", None))
|
||||||
#if QT_CONFIG(tooltip)
|
#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))
|
self.deleteBox.setToolTip(QCoreApplication.translate("mainWindow", u"Delete input file(s) or directory. It's not recoverable!", None))
|
||||||
#endif // QT_CONFIG(tooltip)
|
#endif // QT_CONFIG(tooltip)
|
||||||
self.rotateBox.setText(QCoreApplication.translate("mainWindow", u"Spread splitter", None))
|
self.deleteBox.setText(QCoreApplication.translate("mainWindow", u"Delete input", None))
|
||||||
#if QT_CONFIG(tooltip)
|
#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.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)
|
#endif // QT_CONFIG(tooltip)
|
||||||
self.outputSplit.setText(QCoreApplication.translate("mainWindow", u"Output split", None))
|
self.maximizeStrips.setText(QCoreApplication.translate("mainWindow", u"1x4 to 2x2 strips", 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.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)
|
#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))
|
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)
|
#endif // QT_CONFIG(tooltip)
|
||||||
@@ -382,34 +379,46 @@ class Ui_mainWindow(object):
|
|||||||
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))
|
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)
|
#endif // QT_CONFIG(tooltip)
|
||||||
self.borderBox.setText(QCoreApplication.translate("mainWindow", u"W/B margins", None))
|
self.borderBox.setText(QCoreApplication.translate("mainWindow", u"W/B margins", 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.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)
|
#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))
|
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)
|
#endif // QT_CONFIG(tooltip)
|
||||||
self.mangaBox.setText(QCoreApplication.translate("mainWindow", u"Manga mode", None))
|
self.mangaBox.setText(QCoreApplication.translate("mainWindow", u"Manga mode", None))
|
||||||
#if QT_CONFIG(tooltip)
|
#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))
|
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)
|
#endif // QT_CONFIG(tooltip)
|
||||||
self.qualityBox.setText(QCoreApplication.translate("mainWindow", u"Panel View 4/2/HQ", None))
|
self.rotateBox.setText(QCoreApplication.translate("mainWindow", u"Spread splitter", 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.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)
|
#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))
|
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)
|
#endif // QT_CONFIG(tooltip)
|
||||||
self.croppingBox.setText(QCoreApplication.translate("mainWindow", u"Cropping mode", None))
|
self.croppingBox.setText(QCoreApplication.translate("mainWindow", u"Cropping mode", None))
|
||||||
#if QT_CONFIG(tooltip)
|
#if QT_CONFIG(tooltip)
|
||||||
self.deleteBox.setToolTip(QCoreApplication.translate("mainWindow", u"Delete input file(s) or directory. It's not recoverable!", None))
|
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)
|
#endif // QT_CONFIG(tooltip)
|
||||||
self.deleteBox.setText(QCoreApplication.translate("mainWindow", u"Delete input", None))
|
self.outputSplit.setText(QCoreApplication.translate("mainWindow", u"Output split", 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.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)
|
#if QT_CONFIG(tooltip)
|
||||||
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))
|
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)
|
#endif // QT_CONFIG(tooltip)
|
||||||
self.disableProcessingBox.setText(QCoreApplication.translate("mainWindow", u"Disable processing", None))
|
self.disableProcessingBox.setText(QCoreApplication.translate("mainWindow", u"Disable processing", None))
|
||||||
|
#if QT_CONFIG(tooltip)
|
||||||
|
self.dedupeCoverBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p>Don't duplicate the first page as the cover. Useful for 2 page spread alignment.</p></body></html>", None))
|
||||||
|
#endif // QT_CONFIG(tooltip)
|
||||||
|
self.dedupeCoverBox.setText(QCoreApplication.translate("mainWindow", u"De-dupe cover", None))
|
||||||
self.gammaLabel.setText(QCoreApplication.translate("mainWindow", u"Gamma: Auto", None))
|
self.gammaLabel.setText(QCoreApplication.translate("mainWindow", u"Gamma: Auto", None))
|
||||||
self.croppingPowerLabel.setText(QCoreApplication.translate("mainWindow", u"Cropping power:", None))
|
self.croppingPowerLabel.setText(QCoreApplication.translate("mainWindow", u"Cropping power:", None))
|
||||||
#if QT_CONFIG(tooltip)
|
#if QT_CONFIG(tooltip)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
################################################################################
|
################################################################################
|
||||||
## Form generated from reading UI file 'MetaEditor.ui'
|
## Form generated from reading UI file 'MetaEditor.ui'
|
||||||
##
|
##
|
||||||
## Created by: Qt User Interface Compiler version 6.5.1
|
## Created by: Qt User Interface Compiler version 6.5.2
|
||||||
##
|
##
|
||||||
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
__version__ = '5.6.5'
|
__version__ = '6.1.0'
|
||||||
__license__ = 'ISC'
|
__license__ = 'ISC'
|
||||||
__copyright__ = '2012-2022, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>, darodi'
|
__copyright__ = '2012-2022, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>, darodi'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|||||||
@@ -21,7 +21,6 @@
|
|||||||
import os
|
import os
|
||||||
import pathlib
|
import pathlib
|
||||||
import re
|
import re
|
||||||
import subprocess
|
|
||||||
import sys
|
import sys
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
from time import strftime, gmtime
|
from time import strftime, gmtime
|
||||||
@@ -36,7 +35,7 @@ from multiprocessing import Pool
|
|||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
from natsort import os_sorted
|
from natsort import os_sorted
|
||||||
from slugify import slugify as slugify_ext
|
from slugify import slugify as slugify_ext
|
||||||
from PIL import Image
|
from PIL import Image, ImageFile
|
||||||
from subprocess import STDOUT, PIPE
|
from subprocess import STDOUT, PIPE
|
||||||
from psutil import virtual_memory, disk_usage
|
from psutil import virtual_memory, disk_usage
|
||||||
from html import escape as hescape
|
from html import escape as hescape
|
||||||
@@ -51,6 +50,8 @@ from . import metadata
|
|||||||
from . import kindle
|
from . import kindle
|
||||||
from . import __version__
|
from . import __version__
|
||||||
|
|
||||||
|
ImageFile.LOAD_TRUNCATED_IMAGES = True
|
||||||
|
|
||||||
|
|
||||||
def main(argv=None):
|
def main(argv=None):
|
||||||
global options
|
global options
|
||||||
@@ -503,15 +504,18 @@ def buildEPUB(path, chapternames, tomenumber):
|
|||||||
chapter = False
|
chapter = False
|
||||||
dirnames, filenames = walkSort(dirnames, filenames)
|
dirnames, filenames = walkSort(dirnames, filenames)
|
||||||
for afile in filenames:
|
for afile in filenames:
|
||||||
|
if cover is None:
|
||||||
|
cover = os.path.join(os.path.join(path, 'OEBPS', 'Images'),
|
||||||
|
'cover' + getImageFileName(afile)[1])
|
||||||
|
options.covers.append((image.Cover(os.path.join(dirpath, afile), cover, options,
|
||||||
|
tomenumber), options.uuid))
|
||||||
|
if options.dedupecover:
|
||||||
|
os.remove(os.path.join(dirpath, afile))
|
||||||
|
continue
|
||||||
filelist.append(buildHTML(dirpath, afile, os.path.join(dirpath, afile)))
|
filelist.append(buildHTML(dirpath, afile, os.path.join(dirpath, afile)))
|
||||||
if not chapter:
|
if not chapter:
|
||||||
chapterlist.append((dirpath.replace('Images', 'Text'), filelist[-1][1]))
|
chapterlist.append((dirpath.replace('Images', 'Text'), filelist[-1][1]))
|
||||||
chapter = True
|
chapter = True
|
||||||
if cover is None:
|
|
||||||
cover = os.path.join(os.path.join(path, 'OEBPS', 'Images'),
|
|
||||||
'cover' + getImageFileName(filelist[-1][1])[1])
|
|
||||||
options.covers.append((image.Cover(os.path.join(filelist[-1][0], filelist[-1][1]), cover, options,
|
|
||||||
tomenumber), options.uuid))
|
|
||||||
# Overwrite chapternames if tree is flat and ComicInfo.xml has bookmarks
|
# Overwrite chapternames if tree is flat and ComicInfo.xml has bookmarks
|
||||||
if not chapternames and options.chapters:
|
if not chapternames and options.chapters:
|
||||||
chapterlist = []
|
chapterlist = []
|
||||||
@@ -643,6 +647,9 @@ def getWorkFolder(afile):
|
|||||||
try:
|
try:
|
||||||
cbx = comicarchive.ComicArchive(afile)
|
cbx = comicarchive.ComicArchive(afile)
|
||||||
path = cbx.extract(workdir)
|
path = cbx.extract(workdir)
|
||||||
|
tdir = os.listdir(workdir)
|
||||||
|
if 'ComicInfo.xml' in tdir:
|
||||||
|
tdir.remove('ComicInfo.xml')
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
rmtree(workdir, True)
|
rmtree(workdir, True)
|
||||||
raise UserWarning(e)
|
raise UserWarning(e)
|
||||||
@@ -688,7 +695,6 @@ def getOutputFilename(srcpath, wantedname, ext, tomenumber):
|
|||||||
|
|
||||||
def getComicInfo(path, originalpath):
|
def getComicInfo(path, originalpath):
|
||||||
xmlPath = os.path.join(path, 'ComicInfo.xml')
|
xmlPath = os.path.join(path, 'ComicInfo.xml')
|
||||||
options.authors = ['KCC']
|
|
||||||
options.chapters = []
|
options.chapters = []
|
||||||
options.summary = ''
|
options.summary = ''
|
||||||
titleSuffix = ''
|
titleSuffix = ''
|
||||||
@@ -700,13 +706,18 @@ def getComicInfo(path, originalpath):
|
|||||||
options.title = os.path.splitext(os.path.basename(originalpath))[0]
|
options.title = os.path.splitext(os.path.basename(originalpath))[0]
|
||||||
else:
|
else:
|
||||||
defaultTitle = False
|
defaultTitle = False
|
||||||
|
if options.author == 'defaultauthor':
|
||||||
|
defaultAuthor = True
|
||||||
|
options.authors = ['KCC']
|
||||||
|
else:
|
||||||
|
defaultAuthor = False
|
||||||
|
options.authors = [options.author]
|
||||||
if os.path.exists(xmlPath):
|
if os.path.exists(xmlPath):
|
||||||
try:
|
try:
|
||||||
xml = metadata.MetadataParser(xmlPath)
|
xml = metadata.MetadataParser(xmlPath)
|
||||||
except Exception:
|
except Exception:
|
||||||
os.remove(xmlPath)
|
os.remove(xmlPath)
|
||||||
return
|
return
|
||||||
options.authors = []
|
|
||||||
if xml.data['Title']:
|
if xml.data['Title']:
|
||||||
options.title = hescape(xml.data['Title'])
|
options.title = hescape(xml.data['Title'])
|
||||||
elif defaultTitle:
|
elif defaultTitle:
|
||||||
@@ -717,14 +728,16 @@ def getComicInfo(path, originalpath):
|
|||||||
if xml.data['Number']:
|
if xml.data['Number']:
|
||||||
titleSuffix += ' #' + xml.data['Number'].zfill(3)
|
titleSuffix += ' #' + xml.data['Number'].zfill(3)
|
||||||
options.title += titleSuffix
|
options.title += titleSuffix
|
||||||
for field in ['Writers', 'Pencillers', 'Inkers', 'Colorists']:
|
if defaultAuthor:
|
||||||
for person in xml.data[field]:
|
options.authors = []
|
||||||
options.authors.append(hescape(person))
|
for field in ['Writers', 'Pencillers', 'Inkers', 'Colorists']:
|
||||||
if len(options.authors) > 0:
|
for person in xml.data[field]:
|
||||||
options.authors = list(set(options.authors))
|
options.authors.append(hescape(person))
|
||||||
options.authors.sort()
|
if len(options.authors) > 0:
|
||||||
else:
|
options.authors = list(set(options.authors))
|
||||||
options.authors = ['KCC']
|
options.authors.sort()
|
||||||
|
else:
|
||||||
|
options.authors = ['KCC']
|
||||||
if xml.data['Bookmarks'] and options.batchsplit == 0:
|
if xml.data['Bookmarks'] and options.batchsplit == 0:
|
||||||
options.chapters = xml.data['Bookmarks']
|
options.chapters = xml.data['Bookmarks']
|
||||||
if xml.data['Summary']:
|
if xml.data['Summary']:
|
||||||
@@ -893,7 +906,7 @@ def detectCorruption(tmppath, orgpath):
|
|||||||
GUI.addMessage.emit('Source files are probably created by KCC. The second conversion will decrease quality.'
|
GUI.addMessage.emit('Source files are probably created by KCC. The second conversion will decrease quality.'
|
||||||
, 'warning', False)
|
, 'warning', False)
|
||||||
GUI.addMessage.emit('', '', False)
|
GUI.addMessage.emit('', '', False)
|
||||||
if imageSmaller > imageNumber * 0.25 and not options.upscale and not options.stretch:
|
if imageSmaller > imageNumber * 0.25 and not options.upscale and not options.stretch and options.profile != 'KS':
|
||||||
print("WARNING: More than 25% of images are smaller than target device resolution. "
|
print("WARNING: More than 25% of images are smaller than target device resolution. "
|
||||||
"Consider enabling stretching or upscaling to improve readability.")
|
"Consider enabling stretching or upscaling to improve readability.")
|
||||||
if GUI:
|
if GUI:
|
||||||
@@ -945,7 +958,7 @@ def makeParser():
|
|||||||
|
|
||||||
main_options.add_argument("-p", "--profile", action="store", dest="profile", default="KV",
|
main_options.add_argument("-p", "--profile", action="store", dest="profile", default="KV",
|
||||||
help="Device profile (Available options: K1, K2, K34, K578, KDX, KPW, KPW5, KV, KO, "
|
help="Device profile (Available options: K1, K2, K34, K578, KDX, KPW, KPW5, KV, KO, "
|
||||||
"K11, KS, KoMT, KoG, KoGHD, KoA, KoAHD, KoAH2O, KoAO, KoN, KoC, KoL, KoF, KoS, KoE)"
|
"K11, KS, KoMT, KoG, KoGHD, KoA, KoAHD, KoAH2O, KoAO, KoN, KoC, KoCC, KoL, KoLC, KoF, KoS, KoE)"
|
||||||
" [Default=KV]")
|
" [Default=KV]")
|
||||||
main_options.add_argument("-m", "--manga-style", action="store_true", dest="righttoleft", default=False,
|
main_options.add_argument("-m", "--manga-style", action="store_true", dest="righttoleft", default=False,
|
||||||
help="Manga style (right-to-left reading and splitting)")
|
help="Manga style (right-to-left reading and splitting)")
|
||||||
@@ -963,12 +976,16 @@ def makeParser():
|
|||||||
help="Output generated file to specified directory or file")
|
help="Output generated file to specified directory or file")
|
||||||
output_options.add_argument("-t", "--title", action="store", dest="title", default="defaulttitle",
|
output_options.add_argument("-t", "--title", action="store", dest="title", default="defaulttitle",
|
||||||
help="Comic title [Default=filename or directory name]")
|
help="Comic title [Default=filename or directory name]")
|
||||||
|
output_options.add_argument("-a", "--author", action="store", dest="author", default="defaultauthor",
|
||||||
|
help="Author name [Default=KCC]")
|
||||||
output_options.add_argument("-f", "--format", action="store", dest="format", default="Auto",
|
output_options.add_argument("-f", "--format", action="store", dest="format", default="Auto",
|
||||||
help="Output format (Available options: Auto, MOBI, EPUB, CBZ, KFX, MOBI+EPUB) "
|
help="Output format (Available options: Auto, MOBI, EPUB, CBZ, KFX, MOBI+EPUB) "
|
||||||
"[Default=Auto]")
|
"[Default=Auto]")
|
||||||
output_options.add_argument("-b", "--batchsplit", type=int, dest="batchsplit", default="0",
|
output_options.add_argument("-b", "--batchsplit", type=int, dest="batchsplit", default="0",
|
||||||
help="Split output into multiple files. 0: Don't split 1: Automatic mode "
|
help="Split output into multiple files. 0: Don't split 1: Automatic mode "
|
||||||
"2: Consider every subdirectory as separate volume [Default=0]")
|
"2: Consider every subdirectory as separate volume [Default=0]")
|
||||||
|
output_options.add_argument("--dedupecover", action="store_true", dest="dedupecover", default=False,
|
||||||
|
help="De-duplicate the cover as the first page in the book")
|
||||||
|
|
||||||
processing_options.add_argument("-n", "--noprocessing", action="store_true", dest="noprocessing", default=False,
|
processing_options.add_argument("-n", "--noprocessing", action="store_true", dest="noprocessing", default=False,
|
||||||
help="Do not modify image and ignore any profil or processing option")
|
help="Do not modify image and ignore any profil or processing option")
|
||||||
@@ -1032,13 +1049,13 @@ def checkOptions(options):
|
|||||||
if options.profile in ['K1', 'K2', 'K34', 'K578', 'KPW', 'KPW5', 'KV', 'KO', 'K11', 'KS']:
|
if options.profile in ['K1', 'K2', 'K34', 'K578', 'KPW', 'KPW5', 'KV', 'KO', 'K11', 'KS']:
|
||||||
options.format = 'MOBI'
|
options.format = 'MOBI'
|
||||||
elif options.profile in ['OTHER', 'KoMT', 'KoG', 'KoGHD', 'KoA', 'KoAHD', 'KoAH2O', 'KoAO',
|
elif options.profile in ['OTHER', 'KoMT', 'KoG', 'KoGHD', 'KoA', 'KoAHD', 'KoAH2O', 'KoAO',
|
||||||
'KoN', 'KoC', 'KoL', 'KoF', 'KoS', 'KoE']:
|
'KoN', 'KoC', 'KoCC', 'KoL', 'KoLC', 'KoF', 'KoS', 'KoE']:
|
||||||
options.format = 'EPUB'
|
options.format = 'EPUB'
|
||||||
elif options.profile in ['KDX']:
|
elif options.profile in ['KDX']:
|
||||||
options.format = 'CBZ'
|
options.format = 'CBZ'
|
||||||
if options.profile in ['K1', 'K2', 'K34', 'K578', 'KPW', 'KPW5', 'KV', 'KO', 'K11', 'KS']:
|
if options.profile in ['K1', 'K2', 'K34', 'K578', 'KPW', 'KPW5', 'KV', 'KO', 'K11', 'KS']:
|
||||||
options.iskindle = True
|
options.iskindle = True
|
||||||
elif options.profile in ['OTHER', 'KoMT', 'KoG', 'KoGHD', 'KoA', 'KoAHD', 'KoAH2O', 'KoAO', 'KoN', 'KoC', 'KoL', 'KoF', 'KoS', 'KoE']:
|
elif options.profile in ['OTHER', 'KoMT', 'KoG', 'KoGHD', 'KoA', 'KoAHD', 'KoAH2O', 'KoAO', 'KoN', 'KoC', 'KoCC', 'KoL', 'KoLC', 'KoF', 'KoS', 'KoE']:
|
||||||
options.isKobo = True
|
options.isKobo = True
|
||||||
# Other Kobo devices probably support synthetic spreads as well, but
|
# Other Kobo devices probably support synthetic spreads as well, but
|
||||||
# they haven't been tested.
|
# they haven't been tested.
|
||||||
@@ -1089,10 +1106,6 @@ def checkOptions(options):
|
|||||||
image.ProfileData.Profiles["Custom"] = newProfile
|
image.ProfileData.Profiles["Custom"] = newProfile
|
||||||
options.profile = "Custom"
|
options.profile = "Custom"
|
||||||
options.profileData = image.ProfileData.Profiles[options.profile]
|
options.profileData = image.ProfileData.Profiles[options.profile]
|
||||||
# kindle scribe conversion to mobi is limited in resolution by kindlegen, same with send to kindle and epub
|
|
||||||
if options.profile == 'KS' and (options.format == 'MOBI' or options.format == 'EPUB'):
|
|
||||||
options.profileData = list(options.profileData)
|
|
||||||
options.profileData[1] = (1440, 1920)
|
|
||||||
return options
|
return options
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import platform
|
|||||||
import subprocess
|
import subprocess
|
||||||
import distro
|
import distro
|
||||||
from shutil import move
|
from shutil import move
|
||||||
from subprocess import STDOUT, PIPE
|
from subprocess import STDOUT, PIPE, CalledProcessError
|
||||||
from xml.dom.minidom import parseString
|
from xml.dom.minidom import parseString
|
||||||
from xml.parsers.expat import ExpatError
|
from xml.parsers.expat import ExpatError
|
||||||
from .shared import subprocess_run_silent
|
from .shared import subprocess_run_silent
|
||||||
@@ -37,7 +37,10 @@ class ComicArchive:
|
|||||||
self.type = None
|
self.type = None
|
||||||
if not os.path.isfile(self.filepath):
|
if not os.path.isfile(self.filepath):
|
||||||
raise OSError('File not found.')
|
raise OSError('File not found.')
|
||||||
process = subprocess_run_silent(['7z', 'l', '-y', '-p1', self.filepath], stderr=STDOUT, stdout=PIPE)
|
try:
|
||||||
|
process = subprocess_run_silent(['7z', 'l', '-y', '-p1', self.filepath], stderr=STDOUT, stdout=PIPE)
|
||||||
|
except FileNotFoundError:
|
||||||
|
return
|
||||||
for line in process.stdout.splitlines():
|
for line in process.stdout.splitlines():
|
||||||
if b'Type =' in line:
|
if b'Type =' in line:
|
||||||
self.type = line.rstrip().decode().split(' = ')[1].upper()
|
self.type = line.rstrip().decode().split(' = ')[1].upper()
|
||||||
@@ -54,6 +57,12 @@ class ComicArchive:
|
|||||||
def extract(self, targetdir):
|
def extract(self, targetdir):
|
||||||
if not os.path.isdir(targetdir):
|
if not os.path.isdir(targetdir):
|
||||||
raise OSError('Target directory doesn\'t exist.')
|
raise OSError('Target directory doesn\'t exist.')
|
||||||
|
try:
|
||||||
|
process = subprocess_run_silent(['tar', '-xf', self.filepath, '-C', targetdir],
|
||||||
|
stdout=PIPE, stderr=STDOUT, check=True)
|
||||||
|
return targetdir
|
||||||
|
except (FileNotFoundError, CalledProcessError):
|
||||||
|
pass
|
||||||
process = subprocess_run_silent(['7z', 'x', '-y', '-xr!__MACOSX', '-xr!.DS_Store', '-xr!thumbs.db', '-xr!Thumbs.db', '-o' + targetdir, self.filepath],
|
process = subprocess_run_silent(['7z', 'x', '-y', '-xr!__MACOSX', '-xr!.DS_Store', '-xr!thumbs.db', '-xr!Thumbs.db', '-o' + targetdir, self.filepath],
|
||||||
stdout=PIPE, stderr=STDOUT)
|
stdout=PIPE, stderr=STDOUT)
|
||||||
if process.returncode != 0 and distro.id() == 'fedora':
|
if process.returncode != 0 and distro.id() == 'fedora':
|
||||||
@@ -61,14 +70,8 @@ class ComicArchive:
|
|||||||
, stdout=PIPE, stderr=STDOUT)
|
, stdout=PIPE, stderr=STDOUT)
|
||||||
if process.returncode != 0:
|
if process.returncode != 0:
|
||||||
raise OSError(EXTRACTION_ERROR)
|
raise OSError(EXTRACTION_ERROR)
|
||||||
elif process.returncode != 0 and platform.system() == 'Darwin':
|
|
||||||
process = subprocess_run_silent(['unar', self.filepath, '-f', '-o', targetdir],
|
|
||||||
stdout=PIPE, stderr=STDOUT)
|
|
||||||
elif process.returncode != 0:
|
elif process.returncode != 0:
|
||||||
raise OSError(EXTRACTION_ERROR)
|
raise OSError(EXTRACTION_ERROR)
|
||||||
tdir = os.listdir(targetdir)
|
|
||||||
if 'ComicInfo.xml' in tdir:
|
|
||||||
tdir.remove('ComicInfo.xml')
|
|
||||||
return targetdir
|
return targetdir
|
||||||
|
|
||||||
def addFile(self, sourcefile):
|
def addFile(self, sourcefile):
|
||||||
|
|||||||
@@ -99,7 +99,9 @@ class ProfileData:
|
|||||||
'KoAO': ("Kobo Aura ONE", (1404, 1872), Palette16, 1.8),
|
'KoAO': ("Kobo Aura ONE", (1404, 1872), Palette16, 1.8),
|
||||||
'KoN': ("Kobo Nia", (758, 1024), Palette16, 1.8),
|
'KoN': ("Kobo Nia", (758, 1024), Palette16, 1.8),
|
||||||
'KoC': ("Kobo Clara HD/Kobo Clara 2E", (1072, 1448), Palette16, 1.8),
|
'KoC': ("Kobo Clara HD/Kobo Clara 2E", (1072, 1448), Palette16, 1.8),
|
||||||
|
'KoCC': ("Kobo Clara Colour", (1072, 1448), Palette16, 1.8),
|
||||||
'KoL': ("Kobo Libra H2O/Kobo Libra 2", (1264, 1680), Palette16, 1.8),
|
'KoL': ("Kobo Libra H2O/Kobo Libra 2", (1264, 1680), Palette16, 1.8),
|
||||||
|
'KoLC': ("Kobo Libra Colour", (1264, 1680), Palette16, 1.8),
|
||||||
'KoF': ("Kobo Forma", (1440, 1920), Palette16, 1.8),
|
'KoF': ("Kobo Forma", (1440, 1920), Palette16, 1.8),
|
||||||
'KoS': ("Kobo Sage", (1440, 1920), Palette16, 1.8),
|
'KoS': ("Kobo Sage", (1440, 1920), Palette16, 1.8),
|
||||||
'KoE': ("Kobo Elipsa", (1404, 1872), Palette16, 1.8),
|
'KoE': ("Kobo Elipsa", (1404, 1872), Palette16, 1.8),
|
||||||
@@ -239,6 +241,7 @@ class ComicPage:
|
|||||||
_, self.size, self.palette, self.gamma = self.opt.profileData
|
_, self.size, self.palette, self.gamma = self.opt.profileData
|
||||||
if self.opt.hq:
|
if self.opt.hq:
|
||||||
self.size = (int(self.size[0] * 1.5), int(self.size[1] * 1.5))
|
self.size = (int(self.size[0] * 1.5), int(self.size[1] * 1.5))
|
||||||
|
self.kindle_scribe_azw3 = (options.profile == 'KS') and (options.format in ('MOBI', 'EPUB'))
|
||||||
self.image = image
|
self.image = image
|
||||||
self.color = color
|
self.color = color
|
||||||
self.fill = fill
|
self.fill = fill
|
||||||
@@ -308,6 +311,9 @@ class ComicPage:
|
|||||||
self.image = self.image.quantize(palette=palImg)
|
self.image = self.image.quantize(palette=palImg)
|
||||||
|
|
||||||
def resizeImage(self):
|
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:
|
||||||
|
self.size = (1440, 1920)
|
||||||
ratio_device = float(self.size[1]) / float(self.size[0])
|
ratio_device = float(self.size[1]) / float(self.size[0])
|
||||||
ratio_image = float(self.image.size[1]) / float(self.image.size[0])
|
ratio_image = float(self.image.size[1]) / float(self.image.size[0])
|
||||||
method = self.resize_method()
|
method = self.resize_method()
|
||||||
@@ -326,14 +332,15 @@ class ComicPage:
|
|||||||
elif self.opt.format == 'CBZ' or self.opt.kfx:
|
elif self.opt.format == 'CBZ' or self.opt.kfx:
|
||||||
self.image = ImageOps.pad(self.image, self.size, method=method, color=self.fill)
|
self.image = ImageOps.pad(self.image, self.size, method=method, color=self.fill)
|
||||||
else:
|
else:
|
||||||
|
if self.kindle_scribe_azw3:
|
||||||
|
self.size = (1860, 1920)
|
||||||
self.image = ImageOps.contain(self.image, self.size, method=method)
|
self.image = ImageOps.contain(self.image, self.size, method=method)
|
||||||
|
|
||||||
def resize_method(self):
|
def resize_method(self):
|
||||||
if self.image.size[0] <= self.size[0] and self.image.size[1] <= self.size[1]:
|
if self.image.size[0] <= self.size[0] and self.image.size[1] <= self.size[1]:
|
||||||
method = Image.Resampling.BICUBIC
|
return Image.Resampling.BICUBIC
|
||||||
else:
|
else:
|
||||||
method = Image.Resampling.LANCZOS
|
return Image.Resampling.LANCZOS
|
||||||
return method
|
|
||||||
|
|
||||||
def getBoundingBox(self, tmptmg):
|
def getBoundingBox(self, tmptmg):
|
||||||
min_margin = [int(0.005 * i + 0.5) for i in tmptmg.size]
|
min_margin = [int(0.005 * i + 0.5) for i in tmptmg.size]
|
||||||
|
|||||||
Reference in New Issue
Block a user