mirror of
https://github.com/ciromattia/kcc
synced 2026-04-18 06:58:58 +00:00
Compare commits
51 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9a93cc4b17 | ||
|
|
e0471b2dc9 | ||
|
|
a87eb318cf | ||
|
|
87987c9ebf | ||
|
|
f5fe8d93b0 | ||
|
|
249f823f01 | ||
|
|
3a9d4f274d | ||
|
|
b5de6fd39d | ||
|
|
b4b9e41a0c | ||
|
|
9b9181a715 | ||
|
|
472fdc97b5 | ||
|
|
6fdfddd7d9 | ||
|
|
34fb68ac65 | ||
|
|
b4d72cd581 | ||
|
|
1dead9af8f | ||
|
|
b42f05686e | ||
|
|
adf48d24f9 | ||
|
|
723fa4c0b8 | ||
|
|
2632d18e2c | ||
|
|
94e4937566 | ||
|
|
f7ce1cf271 | ||
|
|
ab93c03838 | ||
|
|
541b1d876b | ||
|
|
d189f9909d | ||
|
|
1dce4f8d2c | ||
|
|
58aab0cb65 | ||
|
|
d2dc089c62 | ||
|
|
3660f2370f | ||
|
|
87c6e3a35e | ||
|
|
981c556550 | ||
|
|
123d603cbd | ||
|
|
a344dd73bf | ||
|
|
095694e9cf | ||
|
|
4b4860b976 | ||
|
|
56e8e24176 | ||
|
|
b0f8f1c633 | ||
|
|
38acc3bf05 | ||
|
|
fbd5980b9b | ||
|
|
667d702b8a | ||
|
|
9a4143ce62 | ||
|
|
f63387cae4 | ||
|
|
f5fd2bb7fe | ||
|
|
4baca03214 | ||
|
|
7de212dca3 | ||
|
|
c99444b96a | ||
|
|
6d7a635c3d | ||
|
|
be86bcbf6a | ||
|
|
5cbc07e65d | ||
|
|
42d94d8202 | ||
|
|
7897627c43 | ||
|
|
8e42fc1162 |
4
.github/workflows/package-linux.yml
vendored
4
.github/workflows/package-linux.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
|||||||
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 libxcb-cursor0
|
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 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
|
||||||
run: |
|
run: |
|
||||||
@@ -68,7 +68,7 @@ jobs:
|
|||||||
if: startsWith(github.ref, 'refs/tags/')
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
with:
|
with:
|
||||||
prerelease: true
|
prerelease: true
|
||||||
generate_release_notes: true
|
generate_release_notes: false
|
||||||
files: |
|
files: |
|
||||||
LICENSE.txt
|
LICENSE.txt
|
||||||
*.AppImage*
|
*.AppImage*
|
||||||
|
|||||||
4
.github/workflows/package-macos.yml
vendored
4
.github/workflows/package-macos.yml
vendored
@@ -38,7 +38,7 @@ jobs:
|
|||||||
cache: 'pip'
|
cache: 'pip'
|
||||||
- name: Install python dependencies
|
- name: Install python dependencies
|
||||||
run: |
|
run: |
|
||||||
python -m pip install --upgrade pip setuptools wheel pyinstaller certifi
|
python -m pip install --upgrade pip pyinstaller certifi
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
- name: Install the Apple certificate and provisioning profile
|
- name: Install the Apple certificate and provisioning profile
|
||||||
# TODO signing
|
# TODO signing
|
||||||
@@ -89,7 +89,7 @@ jobs:
|
|||||||
if: startsWith(github.ref, 'refs/tags/')
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
with:
|
with:
|
||||||
prerelease: true
|
prerelease: true
|
||||||
generate_release_notes: true
|
generate_release_notes: false
|
||||||
files: |
|
files: |
|
||||||
dist/*.dmg
|
dist/*.dmg
|
||||||
- name: Clean up keychain and provisioning profile
|
- name: Clean up keychain and provisioning profile
|
||||||
|
|||||||
4
.github/workflows/package-osx-legacy.yml
vendored
4
.github/workflows/package-osx-legacy.yml
vendored
@@ -40,7 +40,7 @@ jobs:
|
|||||||
- name: Install Python dependencies
|
- name: Install Python dependencies
|
||||||
run: |
|
run: |
|
||||||
python3 --version
|
python3 --version
|
||||||
pip3 install --upgrade pip setuptools wheel pyinstaller certifi
|
pip3 install --upgrade pip pyinstaller certifi
|
||||||
pip3 install --upgrade -r requirements-osx-legacy.txt
|
pip3 install --upgrade -r requirements-osx-legacy.txt
|
||||||
./gen_ui_files.sh
|
./gen_ui_files.sh
|
||||||
- uses: actions/setup-node@v6
|
- uses: actions/setup-node@v6
|
||||||
@@ -60,7 +60,7 @@ jobs:
|
|||||||
if: startsWith(github.ref, 'refs/tags/')
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
with:
|
with:
|
||||||
prerelease: true
|
prerelease: true
|
||||||
generate_release_notes: true
|
generate_release_notes: false
|
||||||
files: |
|
files: |
|
||||||
LICENSE.txt
|
LICENSE.txt
|
||||||
dist/*.dmg
|
dist/*.dmg
|
||||||
|
|||||||
4
.github/workflows/package-windows.yml
vendored
4
.github/workflows/package-windows.yml
vendored
@@ -45,7 +45,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
PYINSTALLER_COMPILE_BOOTLOADER: 1
|
PYINSTALLER_COMPILE_BOOTLOADER: 1
|
||||||
run: |
|
run: |
|
||||||
python -m pip install --upgrade pip setuptools wheel
|
python -m pip install --upgrade pip
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
pip install certifi pyinstaller --no-binary pyinstaller
|
pip install certifi pyinstaller --no-binary pyinstaller
|
||||||
- name: build binary
|
- name: build binary
|
||||||
@@ -73,6 +73,6 @@ jobs:
|
|||||||
if: startsWith(github.ref, 'refs/tags/')
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
with:
|
with:
|
||||||
prerelease: true
|
prerelease: true
|
||||||
generate_release_notes: true
|
generate_release_notes: false
|
||||||
files: |
|
files: |
|
||||||
dist/*.exe
|
dist/*.exe
|
||||||
|
|||||||
4
.github/workflows/package-windows7.yml
vendored
4
.github/workflows/package-windows7.yml
vendored
@@ -37,7 +37,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
PYINSTALLER_COMPILE_BOOTLOADER: 1
|
PYINSTALLER_COMPILE_BOOTLOADER: 1
|
||||||
run: |
|
run: |
|
||||||
python -m pip install --upgrade pip setuptools wheel
|
python -m pip install --upgrade pip
|
||||||
pip install -r requirements-win7.txt
|
pip install -r requirements-win7.txt
|
||||||
pip install certifi pyinstaller --no-binary pyinstaller
|
pip install certifi pyinstaller --no-binary pyinstaller
|
||||||
.\gen_ui_files.bat
|
.\gen_ui_files.bat
|
||||||
@@ -55,6 +55,6 @@ jobs:
|
|||||||
if: startsWith(github.ref, 'refs/tags/')
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
with:
|
with:
|
||||||
prerelease: true
|
prerelease: true
|
||||||
generate_release_notes: true
|
generate_release_notes: false
|
||||||
files: |
|
files: |
|
||||||
dist/*.exe
|
dist/*.exe
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ FROM python:3.13-slim-bullseye AS builder
|
|||||||
|
|
||||||
# Install system dependencies
|
# Install system dependencies
|
||||||
RUN set -x && \
|
RUN set -x && \
|
||||||
BUILD_DEPS="build-essential cmake libffi-dev libfreetype6-dev libfontconfig1-dev libpng-dev libjpeg-dev libssl-dev libxft-dev make python3-dev python3-setuptools python3-wheel" && \
|
BUILD_DEPS="build-essential cmake libffi-dev libfreetype6-dev libfontconfig1-dev libpng-dev libjpeg-dev libssl-dev libxft-dev make python3-dev" && \
|
||||||
RUNTIME_DEPS="bash ca-certificates chrpath locales locales-all libfreetype6 libfontconfig1 p7zip-full python3 python3-pip libgl1" && \
|
RUNTIME_DEPS="bash ca-certificates chrpath locales locales-all libfreetype6 libfontconfig1 p7zip-full python3 python3-pip libgl1" && \
|
||||||
DEBIAN_FRONTEND=noninteractive apt-get update -y && \
|
DEBIAN_FRONTEND=noninteractive apt-get update -y && \
|
||||||
apt-get install -y --no-install-recommends ${BUILD_DEPS} ${RUNTIME_DEPS}
|
apt-get install -y --no-install-recommends ${BUILD_DEPS} ${RUNTIME_DEPS}
|
||||||
|
|||||||
93
README.md
93
README.md
@@ -13,6 +13,13 @@ Pages display in fullscreen without margins,
|
|||||||
with proper fixed layout support.
|
with proper fixed layout support.
|
||||||
Supported input formats include JPG/PNG image files in folders, archives, or PDFs.
|
Supported input formats include JPG/PNG image files in folders, archives, or PDFs.
|
||||||
Supported output formats include MOBI/AZW3, EPUB, KEPUB, CBZ, and PDF.
|
Supported output formats include MOBI/AZW3, EPUB, KEPUB, CBZ, and PDF.
|
||||||
|
KCC runs on Windows, macOS, and Linux.
|
||||||
|
|
||||||
|
Just drop your input files into the KCC window, hit convert, and USB drop the output files onto your device's `documents` folder!
|
||||||
|
|
||||||
|
https://github.com/user-attachments/assets/da73d625-e082-482d-91a4-ae4765e96fd7
|
||||||
|
|
||||||
|
**WARNING**: Kindle Scribe 2025 support may not be possible. Does not work well currently.
|
||||||
|
|
||||||
**NEW**: PDF output is now supported for direct conversion to reMarkable devices!
|
**NEW**: PDF output is now supported for direct conversion to reMarkable devices!
|
||||||
When using a reMarkable profile (Rmk1, Rmk2, RmkPP), the format automatically defaults to PDF
|
When using a reMarkable profile (Rmk1, Rmk2, RmkPP), the format automatically defaults to PDF
|
||||||
@@ -34,6 +41,7 @@ KCC avoids many common formatting issues (some of which occur [even on the Kindl
|
|||||||
3) Not utilizing the full 1860x2480 resolution of the 10" Kindle Scribe
|
3) Not utilizing the full 1860x2480 resolution of the 10" Kindle Scribe
|
||||||
4) incorrect page turn direction for manga that's read right to left
|
4) incorrect page turn direction for manga that's read right to left
|
||||||
5) unaligned two page spreads in landscape, where pages are shifted over by 1
|
5) unaligned two page spreads in landscape, where pages are shifted over by 1
|
||||||
|
6) Removing without blur the rainbow effect on color eink Kaleido 3 due to manga screentones
|
||||||
|
|
||||||
The GUI looks like this, built in Qt6, with my most commonly used settings:
|
The GUI looks like this, built in Qt6, with my most commonly used settings:
|
||||||
|
|
||||||
@@ -46,7 +54,9 @@ You can change the default output directory by holding `Shift` while clicking th
|
|||||||
Then just drag and drop the generated output files onto your device's documents folder via USB.
|
Then just drag and drop the generated output files onto your device's documents folder via USB.
|
||||||
If you are on macOS and use a 2022+ Kindle, you may need to use Amazon USB File Manager for Mac.
|
If you are on macOS and use a 2022+ Kindle, you may need to use Amazon USB File Manager for Mac.
|
||||||
|
|
||||||
YouTube tutorial (please subscribe): https://www.youtube.com/watch?v=IR2Fhcm9658
|
YouTube tutorial (please subscribe): https://www.youtube.com/watch?v=QQ6zJcMF2Iw
|
||||||
|
|
||||||
|
Installation tutorial: https://www.youtube.com/watch?v=IR2Fhcm9658
|
||||||
|
|
||||||
### A word of warning
|
### A word of warning
|
||||||
**KCC** _is not_ [Amazon's Kindle Comic Creator](http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1001103761) nor is in any way endorsed by Amazon.
|
**KCC** _is not_ [Amazon's Kindle Comic Creator](http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1001103761) nor is in any way endorsed by Amazon.
|
||||||
@@ -98,7 +108,7 @@ There are also legacy macOS 10.14+ and Windows 7 experimental versions available
|
|||||||
|
|
||||||
The `c2e` and `c2p` versions are command line tools for power users.
|
The `c2e` and `c2p` versions are command line tools for power users.
|
||||||
|
|
||||||
On Mac, right click open to get past the security warning.
|
On macOS, if you get a `can't be opened` error, follow: https://support.apple.com/guide/mac-help/open-a-mac-app-from-an-unknown-developer-mh40616/mac
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
@@ -177,38 +187,44 @@ sudo apt-get install python3 p7zip-full python3-pil python3-psutil python3-slugi
|
|||||||
### Profiles:
|
### Profiles:
|
||||||
|
|
||||||
```
|
```
|
||||||
'K1': ("Kindle 1", (600, 670), Palette4, 1.8),
|
'K1': ("Kindle 1", (600, 670), Palette4, 1.0),
|
||||||
'K11': ("Kindle 11", (1072, 1448), Palette16, 1.8),
|
'K2': ("Kindle 2", (600, 670), Palette15, 1.0),
|
||||||
'K2': ("Kindle 2", (600, 670), Palette15, 1.8),
|
'K11': ("Kindle 11", (1072, 1448), Palette16, 1.0),
|
||||||
'K34': ("Kindle Keyboard/Touch", (600, 800), Palette16, 1.8),
|
'K34': ("Kindle Keyboard/Touch", (600, 800), Palette16, 1.0),
|
||||||
'K57': ("Kindle 5/7", (600, 800), Palette16, 1.8),
|
'K57': ("Kindle 5/7", (600, 800), Palette16, 1.0),
|
||||||
'K810': ("Kindle 8/10", (600, 800), Palette16, 1.8),
|
'K810': ("Kindle 8/10", (600, 800), Palette16, 1.0),
|
||||||
'KDX': ("Kindle DX/DXG", (824, 1000), Palette16, 1.8),
|
'KDX': ("Kindle DX/DXG", (824, 1000), Palette16, 1.0),
|
||||||
'KPW': ("Kindle Paperwhite 1/2", (758, 1024), Palette16, 1.8),
|
'KPW': ("Kindle Paperwhite 1/2", (758, 1024), Palette16, 1.0),
|
||||||
'KV': ("Kindle Voyage, (1072, 1448), Palette16, 1.8),
|
'KV': ("Kindle Voyage", (1072, 1448), Palette16, 1.0),
|
||||||
'KPW34': ("Kindle Paperwhite 3/4/Oasis", (1072, 1448), Palette16, 1.8),
|
'KPW34': ("Kindle Paperwhite 3/4", (1072, 1448), Palette16, 1.0),
|
||||||
'KPW5': ("Kindle Paperwhite 5/Signature Edition", (1236, 1648), Palette16, 1.8),
|
'KPW5': ("Kindle Paperwhite 5/Signature Edition", (1236, 1648), Palette16, 1.0),
|
||||||
'KO': ("Kindle Oasis 2/3/Paperwhite 12/Colorsoft 12", (1264, 1680), Palette16, 1.8),
|
'KO': ("Kindle Oasis 2/3/Paperwhite 12", (1264, 1680), Palette16, 1.0),
|
||||||
'KS': ("Kindle Scribe", (1860, 2480), Palette16, 1.8),
|
'KCS': ("Kindle Colorsoft", (1264, 1680), Palette16, 1.0),
|
||||||
'KoMT': ("Kobo Mini/Touch", (600, 800), Palette16, 1.8),
|
'KS1860': ("Kindle 1860", (1860, 1920), Palette16, 1.0),
|
||||||
'KoG': ("Kobo Glo", (768, 1024), Palette16, 1.8),
|
'KS1920': ("Kindle 1920", (1920, 1920), Palette16, 1.0),
|
||||||
'KoGHD': ("Kobo Glo HD", (1072, 1448), Palette16, 1.8),
|
'KS': ("Kindle Scribe 1/2", (1860, 2480), Palette16, 1.0),
|
||||||
'KoA': ("Kobo Aura", (758, 1024), Palette16, 1.8),
|
'KS3': ("Kindle Scribe 3", (1986, 2648), Palette16, 1.0),
|
||||||
'KoAHD': ("Kobo Aura HD", (1080, 1440), Palette16, 1.8),
|
'KSCS': ("Kindle Scribe Colorsoft", (1986, 2648), Palette16, 1.0),
|
||||||
'KoAH2O': ("Kobo Aura H2O", (1080, 1430), Palette16, 1.8),
|
'KoMT': ("Kobo Mini/Touch", (600, 800), Palette16, 1.0),
|
||||||
'KoAO': ("Kobo Aura ONE", (1404, 1872), Palette16, 1.8),
|
'KoG': ("Kobo Glo", (768, 1024), Palette16, 1.0),
|
||||||
'KoN': ("Kobo Nia", (758, 1024), Palette16, 1.8),
|
'KoGHD': ("Kobo Glo HD", (1072, 1448), Palette16, 1.0),
|
||||||
'KoC': ("Kobo Clara HD/Kobo Clara 2E", (1072, 1448), Palette16, 1.8),
|
'KoA': ("Kobo Aura", (758, 1024), Palette16, 1.0),
|
||||||
'KoCC': ("Kobo Clara Colour", (1072, 1448), Palette16, 1.8),
|
'KoAHD': ("Kobo Aura HD", (1080, 1440), Palette16, 1.0),
|
||||||
'KoL': ("Kobo Libra H2O/Kobo Libra 2", (1264, 1680), Palette16, 1.8),
|
'KoAH2O': ("Kobo Aura H2O", (1080, 1430), Palette16, 1.0),
|
||||||
'KoLC': ("Kobo Libra Colour", (1264, 1680), Palette16, 1.8),
|
'KoAO': ("Kobo Aura ONE", (1404, 1872), Palette16, 1.0),
|
||||||
'KoF': ("Kobo Forma", (1440, 1920), Palette16, 1.8),
|
'KoN': ("Kobo Nia", (758, 1024), Palette16, 1.0),
|
||||||
'KoS': ("Kobo Sage", (1440, 1920), Palette16, 1.8),
|
'KoC': ("Kobo Clara HD/Kobo Clara 2E", (1072, 1448), Palette16, 1.0),
|
||||||
'KoE': ("Kobo Elipsa", (1404, 1872), Palette16, 1.8),
|
'KoCC': ("Kobo Clara Colour", (1072, 1448), Palette16, 1.0),
|
||||||
'Rmk1': ("reMarkable 1", (1404, 1872), Palette16, 1.8),
|
'KoL': ("Kobo Libra H2O/Kobo Libra 2", (1264, 1680), Palette16, 1.0),
|
||||||
'Rmk2': ("reMarkable 2", (1404, 1872), Palette16, 1.8),
|
'KoLC': ("Kobo Libra Colour", (1264, 1680), Palette16, 1.0),
|
||||||
'RmkPP': ("reMarkable Paper Pro", (1620, 2160), Palette16, 1.8),
|
'KoF': ("Kobo Forma", (1440, 1920), Palette16, 1.0),
|
||||||
'OTHER': ("Other", (0, 0), Palette16, 1.8),
|
'KoS': ("Kobo Sage", (1440, 1920), Palette16, 1.0),
|
||||||
|
'KoE': ("Kobo Elipsa", (1404, 1872), Palette16, 1.0),
|
||||||
|
'Rmk1': ("reMarkable 1", (1404, 1872), Palette16, 1.0),
|
||||||
|
'Rmk2': ("reMarkable 2", (1404, 1872), Palette16, 1.0),
|
||||||
|
'RmkPP': ("reMarkable Paper Pro", (1620, 2160), Palette16, 1.0),
|
||||||
|
'RmkPPMove': ("reMarkable Paper Pro Move", (954, 1696), Palette16, 1.0),
|
||||||
|
'OTHER': ("Other", (0, 0), Palette16, 1.0),
|
||||||
```
|
```
|
||||||
|
|
||||||
### Standalone `kcc-c2e.py` usage:
|
### Standalone `kcc-c2e.py` usage:
|
||||||
@@ -232,6 +248,8 @@ MAIN:
|
|||||||
|
|
||||||
PROCESSING:
|
PROCESSING:
|
||||||
-n, --noprocessing Do not modify image and ignore any profile or processing option
|
-n, --noprocessing Do not modify image and ignore any profile or processing option
|
||||||
|
--pdfextract Use legacy PDF image extraction method from KCC 8 and earlier.
|
||||||
|
--pdfwidth Render vector PDFs based on device width instead of height.
|
||||||
-u, --upscale Resize images smaller than device's resolution
|
-u, --upscale Resize images smaller than device's resolution
|
||||||
-s, --stretch Stretch images to device's resolution
|
-s, --stretch Stretch images to device's resolution
|
||||||
-r SPLITTER, --splitter SPLITTER
|
-r SPLITTER, --splitter SPLITTER
|
||||||
@@ -252,8 +270,12 @@ PROCESSING:
|
|||||||
Crop empty sections. 0: Disabled 1: Horizontally 2: Both [Default=0]
|
Crop empty sections. 0: Disabled 1: Horizontally 2: Both [Default=0]
|
||||||
--blackborders Disable autodetection and force black borders
|
--blackborders Disable autodetection and force black borders
|
||||||
--whiteborders Disable autodetection and force white borders
|
--whiteborders Disable autodetection and force white borders
|
||||||
|
--coverfill Center-crop only the cover to fill target device screen
|
||||||
--forcecolor Don't convert images to grayscale
|
--forcecolor Don't convert images to grayscale
|
||||||
--forcepng Create PNG files instead JPEG
|
--forcepng Create PNG files instead JPEG for black and white images
|
||||||
|
--force-png-rgb Force color images to be saved as PNG
|
||||||
|
--pnglegacy Use a more compatible 8 bit PNG instead of 4 bit.
|
||||||
|
--noquantize Don't quantize PNG images to 16 colors
|
||||||
--mozjpeg Create JPEG files using mozJpeg
|
--mozjpeg Create JPEG files using mozJpeg
|
||||||
--jpeg-quality The JPEG quality, on a scale from 0 (worst) to 95 (best). Default 85 for most devices.
|
--jpeg-quality The JPEG quality, on a scale from 0 (worst) to 95 (best). Default 85 for most devices.
|
||||||
--maximizestrips Turn 1x4 strips to 2x2 strips
|
--maximizestrips Turn 1x4 strips to 2x2 strips
|
||||||
@@ -274,6 +296,7 @@ OUTPUT SETTINGS:
|
|||||||
Split output into multiple files. 0: Don't split 1: Automatic mode 2: Consider every subdirectory as separate volume [Default=0]
|
Split output into multiple files. 0: Don't split 1: Automatic mode 2: Consider every subdirectory as separate volume [Default=0]
|
||||||
--spreadshift Shift first page to opposite side in landscape for two page spread alignment
|
--spreadshift Shift first page to opposite side in landscape for two page spread alignment
|
||||||
--norotate Do not rotate double page spreads in spread splitter option.
|
--norotate Do not rotate double page spreads in spread splitter option.
|
||||||
|
--rotateright Rotate double page spreads in opposite direction.
|
||||||
--rotatefirst Put rotated spread first in spread splitter option.
|
--rotatefirst Put rotated spread first in spread splitter option.
|
||||||
--filefusion Combines all input files into a single file.
|
--filefusion Combines all input files into a single file.
|
||||||
--eraserainbow Erase rainbow effect on color eink screen by attenuating interfering frequencies
|
--eraserainbow Erase rainbow effect on color eink screen by attenuating interfering frequencies
|
||||||
|
|||||||
532
gui/KCC.ui
532
gui/KCC.ui
@@ -473,7 +473,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="QSpinBox" name="chunkSizeBox">
|
<widget class="QSpinBox" name="chunkSizeBox">
|
||||||
<property name="minimum">
|
<property name="minimum">
|
||||||
<number>100</number>
|
<number>50</number>
|
||||||
</property>
|
</property>
|
||||||
<property name="maximum">
|
<property name="maximum">
|
||||||
<number>600</number>
|
<number>600</number>
|
||||||
@@ -514,81 +514,6 @@
|
|||||||
<property name="bottomMargin">
|
<property name="bottomMargin">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QLineEdit" name="titleEdit">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="focusPolicy">
|
|
||||||
<enum>Qt::FocusPolicy::ClickFocus</enum>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
|
||||||
<string><html><head/><body><p>Default Title</p></body></html></string>
|
|
||||||
</property>
|
|
||||||
<property name="placeholderText">
|
|
||||||
<string>Default Title</string>
|
|
||||||
</property>
|
|
||||||
<property name="clearButtonEnabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0">
|
|
||||||
<widget class="QCheckBox" name="mangaBox">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string><html><head/><body><p style='white-space:pre'>Enable right-to-left reading.</p></body></html></string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Right-to-left (manga)</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="0">
|
|
||||||
<widget class="QCheckBox" name="webtoonBox">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string><html><head/><body><p style='white-space:pre'>Enable special parsing mode for Korean Webtoons.</p></body></html></string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Webtoon mode</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="4" column="2">
|
|
||||||
<widget class="QCheckBox" name="croppingBox">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string><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></string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Cropping mode</string>
|
|
||||||
</property>
|
|
||||||
<property name="tristate">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="4" column="1">
|
|
||||||
<widget class="QCheckBox" name="maximizeStrips">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string><html><head/><body><p><span style=" font-weight:600; text-decoration: underline;">Unchecked - 1x4<br/></span>Keep format 1x4 panels strips.</p><p><span style=" font-weight:600; text-decoration: underline;">Checked - 2x2<br/></span>Turn 1x4 strips to 2x2 to maximize screen usage.</p></body></html></string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>1x4 to 2x2 strips</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="5" column="1">
|
|
||||||
<widget class="QCheckBox" name="deleteBox">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Delete input file(s) or directory. It's not recoverable!</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Delete input</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="8" column="1">
|
<item row="8" column="1">
|
||||||
<widget class="QCheckBox" name="rotateFirstBox">
|
<widget class="QCheckBox" name="rotateFirstBox">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
@@ -609,6 +534,18 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="10" column="0">
|
||||||
|
<widget class="QCheckBox" name="pdfWidthBox">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Render vector PDFs to device width instead of height.
|
||||||
|
|
||||||
|
Useful if you plan to crop a little off the top and bottom to fill screen.</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>PDF Width Render</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item row="3" column="0">
|
<item row="3" column="0">
|
||||||
<widget class="QCheckBox" name="borderBox">
|
<widget class="QCheckBox" name="borderBox">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
@@ -622,59 +559,13 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="2">
|
<item row="5" column="1">
|
||||||
<widget class="QCheckBox" name="gammaBox">
|
<widget class="QCheckBox" name="deleteBox">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p>Set a custom gamma correction.</p><p>1.0 is default (disabled).<br/>&lt; 1.0 makes the image brighter.<br/>&gt; 1.0 makes the image darker. </p><p>1.8 was the default in KCC 9.1.0 and earlier.</p><p>Use if you want to make midtones darker.</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>Custom gamma</string>
|
<string>Delete input</string>
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="1">
|
|
||||||
<widget class="QCheckBox" name="upscaleBox">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string><html><head/><body><p><span style=" font-weight:600; text-decoration: underline;">Unchecked - Nothing<br/></span>Images smaller than device resolution will not be resized.</p><p><span style=" font-weight:600; text-decoration: underline;">Indeterminate - Stretching<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be not preserved.</p><p><span style=" font-weight:600; text-decoration: underline;">Checked - Upscaling<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be preserved.</p></body></html></string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Stretch/Upscale</string>
|
|
||||||
</property>
|
|
||||||
<property name="tristate">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="7" column="1">
|
|
||||||
<widget class="QCheckBox" name="chunkSizeCheckBox">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string><html><head/><body><p><span style=" font-weight:700; text-decoration: underline;">Unchecked<br/></span>Maximal output file size is 100 MB for Webtoon, 400 MB for others before split occurs.</p><p><span style=" font-weight:700; text-decoration: underline;">Checked</span><br/>Output file size specified in &quot;Chunk size MB&quot; before split occurs.</p></body></html></string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Chunk size</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="2">
|
|
||||||
<widget class="QCheckBox" name="colorBox">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string><html><head/><body><p style='white-space:pre'>Disable conversion to grayscale.</p></body></html></string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Color mode</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1">
|
|
||||||
<widget class="QCheckBox" name="rotateBox">
|
|
||||||
<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 - Split and rotate<br/></span>Double page spreads will be displayed twice. First split and then rotated. </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 name="text">
|
|
||||||
<string>Spread splitter</string>
|
|
||||||
</property>
|
|
||||||
<property name="tristate">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@@ -688,23 +579,23 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="5" column="2">
|
<item row="4" column="1">
|
||||||
<widget class="QCheckBox" name="disableProcessingBox">
|
<widget class="QCheckBox" name="maximizeStrips">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p style='white-space:pre'>Do not process any image, ignore profile and processing options.</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>Disable processing</string>
|
<string>1x4 to 2x2 strips</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="7" column="2">
|
<item row="2" column="0">
|
||||||
<widget class="QCheckBox" name="eraseRainbowBox">
|
<widget class="QCheckBox" name="webtoonBox">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Erase rainbow effect on color eink screen by attenuating interfering frequencies</string>
|
<string><html><head/><body><p style='white-space:pre'>Enable special parsing mode for Korean Webtoons.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Rainbow eraser</string>
|
<string>Webtoon mode</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@@ -718,116 +609,79 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="6" column="0">
|
<item row="1" column="0">
|
||||||
<widget class="QCheckBox" name="fileFusionBox">
|
<widget class="QCheckBox" name="mangaBox">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p>Combines all selected files into a single file. (Helpful for combining chapters into volumes.)</p></body></html></string>
|
<string><html><head/><body><p style='white-space:pre'>Enable right-to-left reading.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>File Fusion</string>
|
<string>Right-to-left (manga)</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="1">
|
<item row="10" column="2">
|
||||||
<widget class="QLineEdit" name="authorEdit">
|
<widget class="QCheckBox" name="noQuantizeBox">
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
<property name="focusPolicy">
|
|
||||||
<enum>Qt::FocusPolicy::ClickFocus</enum>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Default Author is KCC</string>
|
<string>Don't quantize PNG images to 16 colors (4 bit)
|
||||||
|
|
||||||
|
This will double file size but preserve all 256 colors (8 bit).
|
||||||
|
|
||||||
|
Eink only has 16 shades of gray so you probably don't want this.</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="placeholderText">
|
<property name="text">
|
||||||
<string>Default Author</string>
|
<string>No Quantize</string>
|
||||||
</property>
|
|
||||||
<property name="clearButtonEnabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="2">
|
<item row="8" column="0">
|
||||||
<widget class="QCheckBox" name="qualityBox">
|
<widget class="QCheckBox" name="jpegQualityBox">
|
||||||
<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>The JPEG quality, on a scale from 0 (worst) to 95 (best).
|
||||||
|
|
||||||
|
Default is 85 for most devices besides Kindle Scribe and Colorsoft, which are 90.
|
||||||
|
|
||||||
|
Higher values are larger and higher quality, and may resolve blank page issues.</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Panel View 4/2/HQ</string>
|
<string>Custom JPEG Quality</string>
|
||||||
</property>
|
|
||||||
<property name="tristate">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="6" column="2">
|
<item row="3" column="2">
|
||||||
<widget class="QCheckBox" name="interPanelCropBox">
|
<widget class="QCheckBox" name="colorBox">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p><span style=" font-weight:600; text-decoration: underline;">Unchecked - Disabled<br/></span>Disabled</p><p><span style=" font-weight:600; text-decoration: underline;">Indeterminate - Horizontal<br/></span>Crop empty horizontal lines.</p><p><span style=" font-weight:600; text-decoration: underline;">Checked - Both<br/></span>Crop empty horizontal and vertical lines.</p></body></html></string>
|
<string><html><head/><body><p style='white-space:pre'>Disable conversion to grayscale.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Inter-panel crop</string>
|
<string>Color mode</string>
|
||||||
</property>
|
|
||||||
<property name="tristate">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="7" column="0">
|
<item row="5" column="2">
|
||||||
<widget class="QCheckBox" name="metadataTitleBox">
|
<widget class="QCheckBox" name="disableProcessingBox">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p><span style=" font-weight:600; text-decoration: underline;">Unchecked - Don't use metadata Title<br/></span>Write default title.</p><p><span style=" font-weight:600; text-decoration: underline;">Indeterminate - Add metadata Title to the default schema<br/></span>Write default title with Title from ComicInfo.xml or other embedded metadata.</p><p><span style=" font-weight:600; text-decoration: underline;">Checked - Use metadata Title only<br/></span>Write Title from ComicInfo.xml or other embedded metadata.</p></body></html></string>
|
<string><html><head/><body><p style='white-space:pre'>Do not process any image, ignore profile and processing options.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Metadata Title</string>
|
<string>Disable processing</string>
|
||||||
</property>
|
|
||||||
<property name="tristate">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="4" column="0">
|
|
||||||
<widget class="QCheckBox" name="mozJpegBox">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string><html><head/><body><p><span style=" font-weight:600; text-decoration: underline;">Unchecked - JPEG<br/></span>Use JPEG files</p><p><span style=" font-weight:600; text-decoration: underline;">Indeterminate - force PNG<br/></span>Create PNG files instead JPEG</p><p><span style=" font-weight:600; text-decoration: underline;">Checked - mozJpeg<br/></span>10-20% smaller JPEG file, with the same image quality, but processing time multiplied by 2</p></body></html></string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>JPEG/PNG/mozJpeg</string>
|
|
||||||
</property>
|
|
||||||
<property name="tristate">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="8" column="2">
|
|
||||||
<widget class="QCheckBox" name="autoLevelBox">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string><html><head/><body><p>By default, KCC maps the darkest pixel value to pure black (the black point.)</p><p>Extreme black point sets the black point to be the most common dark pixel value.</p><p>Useful when text is black but artwork is gray.</p></body></html></string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Extreme Black Point</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="9" column="2">
|
|
||||||
<widget class="QCheckBox" name="autocontrastBox">
|
|
||||||
<property name="toolTip">
|
|
||||||
<string><html><head/><body><p><span style=" font-weight:600; text-decoration: underline;">Unchecked - BW only<br/></span>Only autocontrast bw pages. Ignored for pages where near blacks or whites don't exist.</p><p><span style=" font-weight:600; text-decoration: underline;">Indeterminate - Disabled<br/></span>Disable autocontrast</p><p><span style=" font-weight:600; text-decoration: underline;">Checked - BW and Color<br/></span>BW and color images will be autocontrasted. Ignored for pages where near blacks or whites don't exist.</p></body></html></string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Autocontrast</string>
|
|
||||||
</property>
|
|
||||||
<property name="tristate">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="2">
|
<item row="0" column="2">
|
||||||
<widget class="QWidget" name="outputFolderWidget" native="true">
|
<widget class="QWidget" name="outputFolderWidget" native="true">
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="defaultOutputFolderBox">
|
<widget class="QCheckBox" name="defaultOutputFolderBox">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
@@ -870,17 +724,254 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="8" column="0">
|
<item row="7" column="0">
|
||||||
<widget class="QCheckBox" name="jpegQualityBox">
|
<widget class="QCheckBox" name="metadataTitleBox">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>The JPEG quality, on a scale from 0 (worst) to 95 (best).
|
<string><html><head/><body><p><span style=" font-weight:600; text-decoration: underline;">Unchecked - Don't use metadata Title<br/></span>Write default title.</p><p><span style=" font-weight:600; text-decoration: underline;">Indeterminate - Add metadata Title to the default schema<br/></span>Write default title with Title from ComicInfo.xml or other embedded metadata.</p><p><span style=" font-weight:600; text-decoration: underline;">Checked - Use metadata Title only<br/></span>Write Title from ComicInfo.xml or other embedded metadata.</p></body></html></string>
|
||||||
|
|
||||||
Default is 85 for most devices besides Kindle Scribe and Colorsoft, which are 90.
|
|
||||||
|
|
||||||
Higher values are larger and higher quality, and may resolve blank page issues.</string>
|
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Custom JPEG Quality</string>
|
<string>Metadata Title</string>
|
||||||
|
</property>
|
||||||
|
<property name="tristate">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="9" column="2">
|
||||||
|
<widget class="QCheckBox" name="autocontrastBox">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p><span style=" font-weight:600; text-decoration: underline;">Unchecked - BW only<br/></span>Only autocontrast bw pages. Ignored for pages where near blacks or whites don't exist.</p><p><span style=" font-weight:600; text-decoration: underline;">Indeterminate - Disabled<br/></span>Disable autocontrast</p><p><span style=" font-weight:600; text-decoration: underline;">Checked - BW and Color<br/></span>BW and color images will be autocontrasted. Ignored for pages where near blacks or whites don't exist.</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Autocontrast</string>
|
||||||
|
</property>
|
||||||
|
<property name="tristate">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="9" column="0">
|
||||||
|
<widget class="QCheckBox" name="pdfExtractBox">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Use the PDF image extraction method from KCC 8 and earlier.
|
||||||
|
|
||||||
|
Useful for really weird PDFs.</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>PDF Legacy Extract</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QCheckBox" name="upscaleBox">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p><span style=" font-weight:600; text-decoration: underline;">Unchecked - Nothing<br/></span>Images smaller than device resolution will not be resized.</p><p><span style=" font-weight:600; text-decoration: underline;">Indeterminate - Stretching<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be not preserved.</p><p><span style=" font-weight:600; text-decoration: underline;">Checked - Upscaling<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be preserved.</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Stretch/Upscale</string>
|
||||||
|
</property>
|
||||||
|
<property name="tristate">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="7" column="1">
|
||||||
|
<widget class="QCheckBox" name="chunkSizeCheckBox">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p><span style=" font-weight:700; text-decoration: underline;">Unchecked<br/></span>Maximal output file size is 100 MB for Webtoon, 400 MB for others before split occurs.</p><p><span style=" font-weight:700; text-decoration: underline;">Checked</span><br/>Output file size specified in &quot;Chunk size MB&quot; before split occurs.</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Chunk size</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="2">
|
||||||
|
<widget class="QCheckBox" name="qualityBox">
|
||||||
|
<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>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Panel View 4/2/HQ</string>
|
||||||
|
</property>
|
||||||
|
<property name="tristate">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="0">
|
||||||
|
<widget class="QCheckBox" name="mozJpegBox">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p><span style=" font-weight:600; text-decoration: underline;">Unchecked - JPEG<br/></span>Use JPEG files</p><p><span style=" font-weight:600; text-decoration: underline;">Indeterminate - force PNG<br/></span>Create PNG files instead JPEG for black and white images</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="0" column="0">
|
||||||
|
<widget class="QLineEdit" name="titleEdit">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="focusPolicy">
|
||||||
|
<enum>Qt::FocusPolicy::ClickFocus</enum>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p>Default Title</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="placeholderText">
|
||||||
|
<string>Default Title</string>
|
||||||
|
</property>
|
||||||
|
<property name="clearButtonEnabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="7" column="2">
|
||||||
|
<widget class="QCheckBox" name="eraseRainbowBox">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Erase rainbow effect on color eink screen by attenuating interfering frequencies</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Rainbow eraser</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="0">
|
||||||
|
<widget class="QCheckBox" name="fileFusionBox">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p>Combines all selected files into a single file. (Helpful for combining chapters into volumes.)</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>File Fusion</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="9" column="1">
|
||||||
|
<widget class="QCheckBox" name="coverFillBox">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Resize cover to exact device resolution by center-cropping to aspect ratio first.
|
||||||
|
May crop top/bottom or left/right depending on source aspect ratio. Not implemented for Kindle Scribe.</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Cover Fill</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="10" column="1">
|
||||||
|
<widget class="QCheckBox" name="rotateRightBox">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Rotate 2 page spreads in opposite direction than normal.</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Rotate Right</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="2">
|
||||||
|
<widget class="QCheckBox" name="gammaBox">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p>Set a custom gamma correction.</p><p>1.0 is default (disabled).<br/>&lt; 1.0 makes the image brighter.<br/>&gt; 1.0 makes the image darker. </p><p>1.8 was the default in KCC 9.1.0 and earlier.</p><p>Use if you want to make midtones darker.</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Custom gamma</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="8" column="2">
|
||||||
|
<widget class="QCheckBox" name="autoLevelBox">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p>By default, KCC maps the darkest pixel value to pure black (the black point.)</p><p>Extreme black point sets the black point to be the most common dark pixel value.</p><p>Useful when text is black but artwork is gray.</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Extreme Black Point</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="2">
|
||||||
|
<widget class="QCheckBox" name="interPanelCropBox">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p><span style=" font-weight:600; text-decoration: underline;">Unchecked - Disabled<br/></span>Disabled</p><p><span style=" font-weight:600; text-decoration: underline;">Indeterminate - Horizontal<br/></span>Crop empty horizontal lines.</p><p><span style=" font-weight:600; text-decoration: underline;">Checked - Both<br/></span>Crop empty horizontal and vertical lines.</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Inter-panel crop</string>
|
||||||
|
</property>
|
||||||
|
<property name="tristate">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QCheckBox" name="rotateBox">
|
||||||
|
<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 - Split and rotate<br/></span>Double page spreads will be displayed twice. First split and then rotated. </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 name="text">
|
||||||
|
<string>Spread splitter</string>
|
||||||
|
</property>
|
||||||
|
<property name="tristate">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLineEdit" name="authorEdit">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="focusPolicy">
|
||||||
|
<enum>Qt::FocusPolicy::ClickFocus</enum>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Default Author is KCC</string>
|
||||||
|
</property>
|
||||||
|
<property name="placeholderText">
|
||||||
|
<string>Default Author</string>
|
||||||
|
</property>
|
||||||
|
<property name="clearButtonEnabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="2">
|
||||||
|
<widget class="QCheckBox" name="croppingBox">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><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></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Cropping mode</string>
|
||||||
|
</property>
|
||||||
|
<property name="tristate">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="11" column="0">
|
||||||
|
<widget class="QCheckBox" name="pngLegacyBox">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Use a more compatible 8 bit PNG instead of 4 bit.</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>PNG Legacy Mode</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="11" column="2">
|
||||||
|
<widget class="QCheckBox" name="forcePngRgbBox">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Force full color images to be saved in lossless PNG format, dramatically increases the filesize.</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Force PNG RGB</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@@ -1013,6 +1104,7 @@ Higher values are larger and higher quality, and may resolve blank page issues.<
|
|||||||
<tabstop>noRotateBox</tabstop>
|
<tabstop>noRotateBox</tabstop>
|
||||||
<tabstop>interPanelCropBox</tabstop>
|
<tabstop>interPanelCropBox</tabstop>
|
||||||
<tabstop>metadataTitleBox</tabstop>
|
<tabstop>metadataTitleBox</tabstop>
|
||||||
|
<tabstop>coverFillBox</tabstop>
|
||||||
<tabstop>chunkSizeCheckBox</tabstop>
|
<tabstop>chunkSizeCheckBox</tabstop>
|
||||||
<tabstop>chunkSizeBox</tabstop>
|
<tabstop>chunkSizeBox</tabstop>
|
||||||
<tabstop>eraseRainbowBox</tabstop>
|
<tabstop>eraseRainbowBox</tabstop>
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ from raven import Client
|
|||||||
from tempfile import gettempdir
|
from tempfile import gettempdir
|
||||||
|
|
||||||
from .shared import HTMLStripper, sanitizeTrace, walkLevel, subprocess_run
|
from .shared import HTMLStripper, sanitizeTrace, walkLevel, subprocess_run
|
||||||
from .comicarchive import SEVENZIP, available_archive_tools
|
from .comicarchive import SEVENZIP, TAR, available_archive_tools
|
||||||
from . import __version__
|
from . import __version__
|
||||||
from . import comic2ebook
|
from . import comic2ebook
|
||||||
from . import metadata
|
from . import metadata
|
||||||
@@ -327,6 +327,12 @@ class WorkerThread(QThread):
|
|||||||
options.maximizestrips = True
|
options.maximizestrips = True
|
||||||
if GUI.disableProcessingBox.isChecked():
|
if GUI.disableProcessingBox.isChecked():
|
||||||
options.noprocessing = True
|
options.noprocessing = True
|
||||||
|
if GUI.pdfExtractBox.isChecked():
|
||||||
|
options.pdfextract = True
|
||||||
|
if GUI.pdfWidthBox.isChecked():
|
||||||
|
options.pdfwidth = True
|
||||||
|
if GUI.coverFillBox.isChecked():
|
||||||
|
options.coverfill = True
|
||||||
if GUI.metadataTitleBox.checkState() == Qt.CheckState.PartiallyChecked:
|
if GUI.metadataTitleBox.checkState() == Qt.CheckState.PartiallyChecked:
|
||||||
options.metadatatitle = 1
|
options.metadatatitle = 1
|
||||||
elif GUI.metadataTitleBox.checkState() == Qt.CheckState.Checked:
|
elif GUI.metadataTitleBox.checkState() == Qt.CheckState.Checked:
|
||||||
@@ -341,12 +347,20 @@ class WorkerThread(QThread):
|
|||||||
options.filefusion = False
|
options.filefusion = False
|
||||||
if GUI.noRotateBox.isChecked():
|
if GUI.noRotateBox.isChecked():
|
||||||
options.norotate = True
|
options.norotate = True
|
||||||
|
if GUI.rotateRightBox.isChecked():
|
||||||
|
options.rotateright = True
|
||||||
if GUI.rotateFirstBox.isChecked():
|
if GUI.rotateFirstBox.isChecked():
|
||||||
options.rotatefirst = True
|
options.rotatefirst = True
|
||||||
|
if GUI.forcePngRgbBox.isChecked():
|
||||||
|
options.force_png_rgb = 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:
|
||||||
options.mozjpeg = True
|
options.mozjpeg = True
|
||||||
|
if GUI.pngLegacyBox.isChecked():
|
||||||
|
options.pnglegacy = True
|
||||||
|
if GUI.noQuantizeBox.isChecked():
|
||||||
|
options.noquantize = True
|
||||||
if GUI.jpegQualityBox.isChecked():
|
if GUI.jpegQualityBox.isChecked():
|
||||||
options.jpegquality = GUI.jpegQualitySpinBox.value()
|
options.jpegquality = GUI.jpegQualitySpinBox.value()
|
||||||
if GUI.currentMode > 2:
|
if GUI.currentMode > 2:
|
||||||
@@ -521,6 +535,7 @@ class WorkerThread(QThread):
|
|||||||
if os.path.exists(item.replace('.epub', '.mobi')):
|
if os.path.exists(item.replace('.epub', '.mobi')):
|
||||||
os.remove(item.replace('.epub', '.mobi'))
|
os.remove(item.replace('.epub', '.mobi'))
|
||||||
MW.addMessage.emit('KindleGen failed to create MOBI!', 'error', False)
|
MW.addMessage.emit('KindleGen failed to create MOBI!', 'error', False)
|
||||||
|
MW.addMessage.emit(self.kindlegenErrorCode[1], 'error', False)
|
||||||
MW.addTrayMessage.emit('KindleGen failed to create MOBI!', 'Critical')
|
MW.addTrayMessage.emit('KindleGen failed to create MOBI!', 'Critical')
|
||||||
if self.kindlegenErrorCode[0] == 1 and self.kindlegenErrorCode[1] != '':
|
if self.kindlegenErrorCode[0] == 1 and self.kindlegenErrorCode[1] != '':
|
||||||
MW.showDialog.emit("KindleGen error:\n\n" + self.kindlegenErrorCode[1], 'error')
|
MW.showDialog.emit("KindleGen error:\n\n" + self.kindlegenErrorCode[1], 'error')
|
||||||
@@ -878,6 +893,10 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
if bad_format in current_format:
|
if bad_format in current_format:
|
||||||
self.addMessage('Colorsoft MOBI/EPUB can have blank pages. Just go back a few pages, exit, and reenter book.', 'info')
|
self.addMessage('Colorsoft MOBI/EPUB can have blank pages. Just go back a few pages, exit, and reenter book.', 'info')
|
||||||
break
|
break
|
||||||
|
elif profile['Label'] == 'KDX':
|
||||||
|
GUI.mozJpegBox.setCheckState(Qt.CheckState.PartiallyChecked)
|
||||||
|
GUI.borderBox.setCheckState(Qt.CheckState.PartiallyChecked)
|
||||||
|
GUI.pngLegacyBox.setChecked(True)
|
||||||
if not profile['PVOptions']:
|
if not profile['PVOptions']:
|
||||||
GUI.qualityBox.setChecked(False)
|
GUI.qualityBox.setChecked(False)
|
||||||
if str(GUI.deviceBox.currentText()) == 'Other':
|
if str(GUI.deviceBox.currentText()) == 'Other':
|
||||||
@@ -904,7 +923,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
elif not GUI.webtoonBox.isChecked():
|
elif not GUI.webtoonBox.isChecked():
|
||||||
GUI.chunkSizeCheckBox.setEnabled(True)
|
GUI.chunkSizeCheckBox.setEnabled(True)
|
||||||
if GUI.formats[str(GUI.formatBox.currentText())]['format'] in ('CBZ', 'PDF') and not GUI.webtoonBox.isChecked():
|
if GUI.formats[str(GUI.formatBox.currentText())]['format'] in ('CBZ', 'PDF') and not GUI.webtoonBox.isChecked():
|
||||||
self.addMessage("Partially check W/B Margins if you don't want KCC to extend the image margins.", 'info')
|
self.addMessage("Partially check W/B Margins if you don't want KCC to extend the image margins.", 'info')
|
||||||
|
|
||||||
def stripTags(self, html):
|
def stripTags(self, html):
|
||||||
s = HTMLStripper()
|
s = HTMLStripper()
|
||||||
@@ -1032,9 +1051,16 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
'colorBox': GUI.colorBox.checkState(),
|
'colorBox': GUI.colorBox.checkState(),
|
||||||
'eraseRainbowBox': GUI.eraseRainbowBox.checkState(),
|
'eraseRainbowBox': GUI.eraseRainbowBox.checkState(),
|
||||||
'disableProcessingBox': GUI.disableProcessingBox.checkState(),
|
'disableProcessingBox': GUI.disableProcessingBox.checkState(),
|
||||||
|
'pdfExtractBox': GUI.pdfExtractBox.checkState(),
|
||||||
|
'pdfWidthBox': GUI.pdfWidthBox.checkState(),
|
||||||
|
'coverFillBox': GUI.coverFillBox.checkState(),
|
||||||
'metadataTitleBox': GUI.metadataTitleBox.checkState(),
|
'metadataTitleBox': GUI.metadataTitleBox.checkState(),
|
||||||
'mozJpegBox': GUI.mozJpegBox.checkState(),
|
'mozJpegBox': GUI.mozJpegBox.checkState(),
|
||||||
|
'forcePngRgbBox': GUI.forcePngRgbBox.checkState(),
|
||||||
|
'pngLegacyBox': GUI.pngLegacyBox.checkState(),
|
||||||
|
'noQuantizeBox': GUI.noQuantizeBox.checkState(),
|
||||||
'jpegQualityBox': GUI.jpegQualityBox.checkState(),
|
'jpegQualityBox': GUI.jpegQualityBox.checkState(),
|
||||||
|
'jpegQuality': GUI.jpegQualitySpinBox.value(),
|
||||||
'widthBox': GUI.widthBox.value(),
|
'widthBox': GUI.widthBox.value(),
|
||||||
'heightBox': GUI.heightBox.value(),
|
'heightBox': GUI.heightBox.value(),
|
||||||
'deleteBox': GUI.deleteBox.checkState(),
|
'deleteBox': GUI.deleteBox.checkState(),
|
||||||
@@ -1042,6 +1068,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
'fileFusionBox': GUI.fileFusionBox.checkState(),
|
'fileFusionBox': GUI.fileFusionBox.checkState(),
|
||||||
'defaultOutputFolderBox': GUI.defaultOutputFolderBox.checkState(),
|
'defaultOutputFolderBox': GUI.defaultOutputFolderBox.checkState(),
|
||||||
'noRotateBox': GUI.noRotateBox.checkState(),
|
'noRotateBox': GUI.noRotateBox.checkState(),
|
||||||
|
'rotateRightBox': GUI.rotateRightBox.checkState(),
|
||||||
'rotateFirstBox': GUI.rotateFirstBox.checkState(),
|
'rotateFirstBox': GUI.rotateFirstBox.checkState(),
|
||||||
'maximizeStrips': GUI.maximizeStrips.checkState(),
|
'maximizeStrips': GUI.maximizeStrips.checkState(),
|
||||||
'gammaSlider': float(self.gammaValue) * 100,
|
'gammaSlider': float(self.gammaValue) * 100,
|
||||||
@@ -1086,7 +1113,8 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
if message[-1] == '/':
|
if message[-1] == '/':
|
||||||
message = message[:-1]
|
message = message[:-1]
|
||||||
self.handleMessage(message)
|
self.handleMessage(message)
|
||||||
GUI.jobList.sortItems()
|
# sorting may conflict with manual file fusion order
|
||||||
|
# GUI.jobList.sortItems()
|
||||||
|
|
||||||
def forceShutdown(self):
|
def forceShutdown(self):
|
||||||
self.saveSettings(None)
|
self.saveSettings(None)
|
||||||
@@ -1173,6 +1201,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
"EPUB": {'icon': 'EPUB', 'format': 'EPUB'},
|
"EPUB": {'icon': 'EPUB', 'format': 'EPUB'},
|
||||||
"CBZ": {'icon': 'CBZ', 'format': 'CBZ'},
|
"CBZ": {'icon': 'CBZ', 'format': 'CBZ'},
|
||||||
"PDF": {'icon': 'EPUB', 'format': 'PDF'},
|
"PDF": {'icon': 'EPUB', 'format': 'PDF'},
|
||||||
|
"PDF (200MB limit)": {'icon': 'EPUB', 'format': 'PDF-200MB'},
|
||||||
"KFX (does not work)": {'icon': 'KFX', 'format': 'KFX'},
|
"KFX (does not work)": {'icon': 'KFX', 'format': 'KFX'},
|
||||||
"MOBI + EPUB": {'icon': 'MOBI', 'format': 'MOBI+EPUB'},
|
"MOBI + EPUB": {'icon': 'MOBI', 'format': 'MOBI+EPUB'},
|
||||||
"EPUB (200MB limit)": {'icon': 'EPUB', 'format': 'EPUB-200MB'},
|
"EPUB (200MB limit)": {'icon': 'EPUB', 'format': 'EPUB-200MB'},
|
||||||
@@ -1195,6 +1224,9 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
"Kindle 1920x1920": {
|
"Kindle 1920x1920": {
|
||||||
'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': False, 'ForceColor': False, 'Label': 'KS1920',
|
'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': False, 'ForceColor': False, 'Label': 'KS1920',
|
||||||
},
|
},
|
||||||
|
"Kindle 1240x1860": {
|
||||||
|
'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': False, 'ForceColor': False, 'Label': 'KS1240',
|
||||||
|
},
|
||||||
"Kindle Scribe 1/2": {
|
"Kindle Scribe 1/2": {
|
||||||
'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': False, 'ForceColor': False, 'Label': 'KS',
|
'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0, 'DefaultUpscale': False, 'ForceColor': False, 'Label': 'KS',
|
||||||
},
|
},
|
||||||
@@ -1280,11 +1312,9 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
profilesGUI = [
|
profilesGUI = [
|
||||||
"Kindle Scribe Colorsoft",
|
"Kindle Scribe Colorsoft",
|
||||||
"Kindle Scribe 3",
|
"Kindle Scribe 3",
|
||||||
"Kindle 1920x1920",
|
|
||||||
"Kindle Colorsoft",
|
"Kindle Colorsoft",
|
||||||
"Kindle Paperwhite 12",
|
"Kindle Paperwhite 12",
|
||||||
"Kindle Scribe 1/2",
|
"Kindle Scribe 1/2",
|
||||||
"Kindle 1860x1920",
|
|
||||||
"Kindle Paperwhite 11",
|
"Kindle Paperwhite 11",
|
||||||
"Kindle 11",
|
"Kindle 11",
|
||||||
"Kindle Oasis 9/10",
|
"Kindle Oasis 9/10",
|
||||||
@@ -1304,6 +1334,9 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
"Separator",
|
"Separator",
|
||||||
"Other",
|
"Other",
|
||||||
"Separator",
|
"Separator",
|
||||||
|
"Kindle 1920x1920",
|
||||||
|
"Kindle 1860x1920",
|
||||||
|
"Kindle 1240x1860",
|
||||||
"Kindle 8/10",
|
"Kindle 8/10",
|
||||||
"Kindle Oasis 8",
|
"Kindle Oasis 8",
|
||||||
"Kindle Paperwhite 7/10",
|
"Kindle Paperwhite 7/10",
|
||||||
@@ -1351,7 +1384,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
'<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')
|
||||||
|
|
||||||
self.tar = 'tar' in available_archive_tools()
|
self.tar = TAR in available_archive_tools()
|
||||||
self.sevenzip = SEVENZIP in available_archive_tools()
|
self.sevenzip = SEVENZIP in available_archive_tools()
|
||||||
if not any([self.tar, self.sevenzip]):
|
if not any([self.tar, self.sevenzip]):
|
||||||
self.addMessage('<a href="https://github.com/ciromattia/kcc#7-zip">Install 7z (link)</a>'
|
self.addMessage('<a href="https://github.com/ciromattia/kcc#7-zip">Install 7z (link)</a>'
|
||||||
@@ -1433,6 +1466,8 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
GUI.croppingPowerSlider.setValue(int(self.options[option]))
|
GUI.croppingPowerSlider.setValue(int(self.options[option]))
|
||||||
self.changeCroppingPower(int(self.options[option]))
|
self.changeCroppingPower(int(self.options[option]))
|
||||||
GUI.preserveMarginBox.setValue(self.options.get('preserveMarginBox', 0))
|
GUI.preserveMarginBox.setValue(self.options.get('preserveMarginBox', 0))
|
||||||
|
elif str(option) == "jpegQuality":
|
||||||
|
GUI.jpegQualitySpinBox.setValue(int(self.options[option]))
|
||||||
elif str(option) == "chunkSizeBox":
|
elif str(option) == "chunkSizeBox":
|
||||||
GUI.chunkSizeBox.setValue(int(self.options[option]))
|
GUI.chunkSizeBox.setValue(int(self.options[option]))
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -266,7 +266,7 @@ class Ui_mainWindow(object):
|
|||||||
|
|
||||||
self.chunkSizeBox = QSpinBox(self.chunkSizeWidget)
|
self.chunkSizeBox = QSpinBox(self.chunkSizeWidget)
|
||||||
self.chunkSizeBox.setObjectName(u"chunkSizeBox")
|
self.chunkSizeBox.setObjectName(u"chunkSizeBox")
|
||||||
self.chunkSizeBox.setMinimum(100)
|
self.chunkSizeBox.setMinimum(50)
|
||||||
self.chunkSizeBox.setMaximum(600)
|
self.chunkSizeBox.setMaximum(600)
|
||||||
self.chunkSizeBox.setValue(400)
|
self.chunkSizeBox.setValue(400)
|
||||||
|
|
||||||
@@ -287,41 +287,6 @@ 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.titleEdit = QLineEdit(self.optionWidget)
|
|
||||||
self.titleEdit.setObjectName(u"titleEdit")
|
|
||||||
sizePolicy4.setHeightForWidth(self.titleEdit.sizePolicy().hasHeightForWidth())
|
|
||||||
self.titleEdit.setSizePolicy(sizePolicy4)
|
|
||||||
self.titleEdit.setFocusPolicy(Qt.FocusPolicy.ClickFocus)
|
|
||||||
self.titleEdit.setClearButtonEnabled(False)
|
|
||||||
|
|
||||||
self.gridLayout_2.addWidget(self.titleEdit, 0, 0, 1, 1)
|
|
||||||
|
|
||||||
self.mangaBox = QCheckBox(self.optionWidget)
|
|
||||||
self.mangaBox.setObjectName(u"mangaBox")
|
|
||||||
|
|
||||||
self.gridLayout_2.addWidget(self.mangaBox, 1, 0, 1, 1)
|
|
||||||
|
|
||||||
self.webtoonBox = QCheckBox(self.optionWidget)
|
|
||||||
self.webtoonBox.setObjectName(u"webtoonBox")
|
|
||||||
|
|
||||||
self.gridLayout_2.addWidget(self.webtoonBox, 2, 0, 1, 1)
|
|
||||||
|
|
||||||
self.croppingBox = QCheckBox(self.optionWidget)
|
|
||||||
self.croppingBox.setObjectName(u"croppingBox")
|
|
||||||
self.croppingBox.setTristate(True)
|
|
||||||
|
|
||||||
self.gridLayout_2.addWidget(self.croppingBox, 4, 2, 1, 1)
|
|
||||||
|
|
||||||
self.maximizeStrips = QCheckBox(self.optionWidget)
|
|
||||||
self.maximizeStrips.setObjectName(u"maximizeStrips")
|
|
||||||
|
|
||||||
self.gridLayout_2.addWidget(self.maximizeStrips, 4, 1, 1, 1)
|
|
||||||
|
|
||||||
self.deleteBox = QCheckBox(self.optionWidget)
|
|
||||||
self.deleteBox.setObjectName(u"deleteBox")
|
|
||||||
|
|
||||||
self.gridLayout_2.addWidget(self.deleteBox, 5, 1, 1, 1)
|
|
||||||
|
|
||||||
self.rotateFirstBox = QCheckBox(self.optionWidget)
|
self.rotateFirstBox = QCheckBox(self.optionWidget)
|
||||||
self.rotateFirstBox.setObjectName(u"rotateFirstBox")
|
self.rotateFirstBox.setObjectName(u"rotateFirstBox")
|
||||||
|
|
||||||
@@ -332,112 +297,72 @@ class Ui_mainWindow(object):
|
|||||||
|
|
||||||
self.gridLayout_2.addWidget(self.outputSplit, 3, 1, 1, 1)
|
self.gridLayout_2.addWidget(self.outputSplit, 3, 1, 1, 1)
|
||||||
|
|
||||||
|
self.pdfWidthBox = QCheckBox(self.optionWidget)
|
||||||
|
self.pdfWidthBox.setObjectName(u"pdfWidthBox")
|
||||||
|
|
||||||
|
self.gridLayout_2.addWidget(self.pdfWidthBox, 10, 0, 1, 1)
|
||||||
|
|
||||||
self.borderBox = QCheckBox(self.optionWidget)
|
self.borderBox = QCheckBox(self.optionWidget)
|
||||||
self.borderBox.setObjectName(u"borderBox")
|
self.borderBox.setObjectName(u"borderBox")
|
||||||
self.borderBox.setTristate(True)
|
self.borderBox.setTristate(True)
|
||||||
|
|
||||||
self.gridLayout_2.addWidget(self.borderBox, 3, 0, 1, 1)
|
self.gridLayout_2.addWidget(self.borderBox, 3, 0, 1, 1)
|
||||||
|
|
||||||
self.gammaBox = QCheckBox(self.optionWidget)
|
self.deleteBox = QCheckBox(self.optionWidget)
|
||||||
self.gammaBox.setObjectName(u"gammaBox")
|
self.deleteBox.setObjectName(u"deleteBox")
|
||||||
|
|
||||||
self.gridLayout_2.addWidget(self.gammaBox, 2, 2, 1, 1)
|
self.gridLayout_2.addWidget(self.deleteBox, 5, 1, 1, 1)
|
||||||
|
|
||||||
self.upscaleBox = QCheckBox(self.optionWidget)
|
|
||||||
self.upscaleBox.setObjectName(u"upscaleBox")
|
|
||||||
self.upscaleBox.setTristate(True)
|
|
||||||
|
|
||||||
self.gridLayout_2.addWidget(self.upscaleBox, 2, 1, 1, 1)
|
|
||||||
|
|
||||||
self.chunkSizeCheckBox = QCheckBox(self.optionWidget)
|
|
||||||
self.chunkSizeCheckBox.setObjectName(u"chunkSizeCheckBox")
|
|
||||||
|
|
||||||
self.gridLayout_2.addWidget(self.chunkSizeCheckBox, 7, 1, 1, 1)
|
|
||||||
|
|
||||||
self.colorBox = QCheckBox(self.optionWidget)
|
|
||||||
self.colorBox.setObjectName(u"colorBox")
|
|
||||||
|
|
||||||
self.gridLayout_2.addWidget(self.colorBox, 3, 2, 1, 1)
|
|
||||||
|
|
||||||
self.rotateBox = QCheckBox(self.optionWidget)
|
|
||||||
self.rotateBox.setObjectName(u"rotateBox")
|
|
||||||
self.rotateBox.setTristate(True)
|
|
||||||
|
|
||||||
self.gridLayout_2.addWidget(self.rotateBox, 1, 1, 1, 1)
|
|
||||||
|
|
||||||
self.spreadShiftBox = QCheckBox(self.optionWidget)
|
self.spreadShiftBox = QCheckBox(self.optionWidget)
|
||||||
self.spreadShiftBox.setObjectName(u"spreadShiftBox")
|
self.spreadShiftBox.setObjectName(u"spreadShiftBox")
|
||||||
|
|
||||||
self.gridLayout_2.addWidget(self.spreadShiftBox, 5, 0, 1, 1)
|
self.gridLayout_2.addWidget(self.spreadShiftBox, 5, 0, 1, 1)
|
||||||
|
|
||||||
self.disableProcessingBox = QCheckBox(self.optionWidget)
|
self.maximizeStrips = QCheckBox(self.optionWidget)
|
||||||
self.disableProcessingBox.setObjectName(u"disableProcessingBox")
|
self.maximizeStrips.setObjectName(u"maximizeStrips")
|
||||||
|
|
||||||
self.gridLayout_2.addWidget(self.disableProcessingBox, 5, 2, 1, 1)
|
self.gridLayout_2.addWidget(self.maximizeStrips, 4, 1, 1, 1)
|
||||||
|
|
||||||
self.eraseRainbowBox = QCheckBox(self.optionWidget)
|
self.webtoonBox = QCheckBox(self.optionWidget)
|
||||||
self.eraseRainbowBox.setObjectName(u"eraseRainbowBox")
|
self.webtoonBox.setObjectName(u"webtoonBox")
|
||||||
|
|
||||||
self.gridLayout_2.addWidget(self.eraseRainbowBox, 7, 2, 1, 1)
|
self.gridLayout_2.addWidget(self.webtoonBox, 2, 0, 1, 1)
|
||||||
|
|
||||||
self.noRotateBox = QCheckBox(self.optionWidget)
|
self.noRotateBox = QCheckBox(self.optionWidget)
|
||||||
self.noRotateBox.setObjectName(u"noRotateBox")
|
self.noRotateBox.setObjectName(u"noRotateBox")
|
||||||
|
|
||||||
self.gridLayout_2.addWidget(self.noRotateBox, 6, 1, 1, 1)
|
self.gridLayout_2.addWidget(self.noRotateBox, 6, 1, 1, 1)
|
||||||
|
|
||||||
self.fileFusionBox = QCheckBox(self.optionWidget)
|
self.mangaBox = QCheckBox(self.optionWidget)
|
||||||
self.fileFusionBox.setObjectName(u"fileFusionBox")
|
self.mangaBox.setObjectName(u"mangaBox")
|
||||||
|
|
||||||
self.gridLayout_2.addWidget(self.fileFusionBox, 6, 0, 1, 1)
|
self.gridLayout_2.addWidget(self.mangaBox, 1, 0, 1, 1)
|
||||||
|
|
||||||
self.authorEdit = QLineEdit(self.optionWidget)
|
self.noQuantizeBox = QCheckBox(self.optionWidget)
|
||||||
self.authorEdit.setObjectName(u"authorEdit")
|
self.noQuantizeBox.setObjectName(u"noQuantizeBox")
|
||||||
sizePolicy4.setHeightForWidth(self.authorEdit.sizePolicy().hasHeightForWidth())
|
|
||||||
self.authorEdit.setSizePolicy(sizePolicy4)
|
|
||||||
self.authorEdit.setFocusPolicy(Qt.FocusPolicy.ClickFocus)
|
|
||||||
self.authorEdit.setClearButtonEnabled(False)
|
|
||||||
|
|
||||||
self.gridLayout_2.addWidget(self.authorEdit, 0, 1, 1, 1)
|
self.gridLayout_2.addWidget(self.noQuantizeBox, 10, 2, 1, 1)
|
||||||
|
|
||||||
self.qualityBox = QCheckBox(self.optionWidget)
|
self.jpegQualityBox = QCheckBox(self.optionWidget)
|
||||||
self.qualityBox.setObjectName(u"qualityBox")
|
self.jpegQualityBox.setObjectName(u"jpegQualityBox")
|
||||||
self.qualityBox.setTristate(True)
|
|
||||||
|
|
||||||
self.gridLayout_2.addWidget(self.qualityBox, 1, 2, 1, 1)
|
self.gridLayout_2.addWidget(self.jpegQualityBox, 8, 0, 1, 1)
|
||||||
|
|
||||||
self.interPanelCropBox = QCheckBox(self.optionWidget)
|
self.colorBox = QCheckBox(self.optionWidget)
|
||||||
self.interPanelCropBox.setObjectName(u"interPanelCropBox")
|
self.colorBox.setObjectName(u"colorBox")
|
||||||
self.interPanelCropBox.setTristate(True)
|
|
||||||
|
|
||||||
self.gridLayout_2.addWidget(self.interPanelCropBox, 6, 2, 1, 1)
|
self.gridLayout_2.addWidget(self.colorBox, 3, 2, 1, 1)
|
||||||
|
|
||||||
self.metadataTitleBox = QCheckBox(self.optionWidget)
|
self.disableProcessingBox = QCheckBox(self.optionWidget)
|
||||||
self.metadataTitleBox.setObjectName(u"metadataTitleBox")
|
self.disableProcessingBox.setObjectName(u"disableProcessingBox")
|
||||||
self.metadataTitleBox.setTristate(True)
|
|
||||||
|
|
||||||
self.gridLayout_2.addWidget(self.metadataTitleBox, 7, 0, 1, 1)
|
self.gridLayout_2.addWidget(self.disableProcessingBox, 5, 2, 1, 1)
|
||||||
|
|
||||||
self.mozJpegBox = QCheckBox(self.optionWidget)
|
|
||||||
self.mozJpegBox.setObjectName(u"mozJpegBox")
|
|
||||||
self.mozJpegBox.setTristate(True)
|
|
||||||
|
|
||||||
self.gridLayout_2.addWidget(self.mozJpegBox, 4, 0, 1, 1)
|
|
||||||
|
|
||||||
self.autoLevelBox = QCheckBox(self.optionWidget)
|
|
||||||
self.autoLevelBox.setObjectName(u"autoLevelBox")
|
|
||||||
|
|
||||||
self.gridLayout_2.addWidget(self.autoLevelBox, 8, 2, 1, 1)
|
|
||||||
|
|
||||||
self.autocontrastBox = QCheckBox(self.optionWidget)
|
|
||||||
self.autocontrastBox.setObjectName(u"autocontrastBox")
|
|
||||||
self.autocontrastBox.setTristate(True)
|
|
||||||
|
|
||||||
self.gridLayout_2.addWidget(self.autocontrastBox, 9, 2, 1, 1)
|
|
||||||
|
|
||||||
self.outputFolderWidget = QWidget(self.optionWidget)
|
self.outputFolderWidget = QWidget(self.optionWidget)
|
||||||
self.outputFolderWidget.setObjectName(u"outputFolderWidget")
|
self.outputFolderWidget.setObjectName(u"outputFolderWidget")
|
||||||
self.horizontalLayout_3 = QHBoxLayout(self.outputFolderWidget)
|
self.horizontalLayout_3 = QHBoxLayout(self.outputFolderWidget)
|
||||||
self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
|
self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
|
||||||
|
self.horizontalLayout_3.setContentsMargins(0, 0, 0, 0)
|
||||||
self.defaultOutputFolderBox = QCheckBox(self.outputFolderWidget)
|
self.defaultOutputFolderBox = QCheckBox(self.outputFolderWidget)
|
||||||
self.defaultOutputFolderBox.setObjectName(u"defaultOutputFolderBox")
|
self.defaultOutputFolderBox.setObjectName(u"defaultOutputFolderBox")
|
||||||
sizePolicy.setHeightForWidth(self.defaultOutputFolderBox.sizePolicy().hasHeightForWidth())
|
sizePolicy.setHeightForWidth(self.defaultOutputFolderBox.sizePolicy().hasHeightForWidth())
|
||||||
@@ -456,10 +381,121 @@ class Ui_mainWindow(object):
|
|||||||
|
|
||||||
self.gridLayout_2.addWidget(self.outputFolderWidget, 0, 2, 1, 1)
|
self.gridLayout_2.addWidget(self.outputFolderWidget, 0, 2, 1, 1)
|
||||||
|
|
||||||
self.jpegQualityBox = QCheckBox(self.optionWidget)
|
self.metadataTitleBox = QCheckBox(self.optionWidget)
|
||||||
self.jpegQualityBox.setObjectName(u"jpegQualityBox")
|
self.metadataTitleBox.setObjectName(u"metadataTitleBox")
|
||||||
|
self.metadataTitleBox.setTristate(True)
|
||||||
|
|
||||||
self.gridLayout_2.addWidget(self.jpegQualityBox, 8, 0, 1, 1)
|
self.gridLayout_2.addWidget(self.metadataTitleBox, 7, 0, 1, 1)
|
||||||
|
|
||||||
|
self.autocontrastBox = QCheckBox(self.optionWidget)
|
||||||
|
self.autocontrastBox.setObjectName(u"autocontrastBox")
|
||||||
|
self.autocontrastBox.setTristate(True)
|
||||||
|
|
||||||
|
self.gridLayout_2.addWidget(self.autocontrastBox, 9, 2, 1, 1)
|
||||||
|
|
||||||
|
self.pdfExtractBox = QCheckBox(self.optionWidget)
|
||||||
|
self.pdfExtractBox.setObjectName(u"pdfExtractBox")
|
||||||
|
|
||||||
|
self.gridLayout_2.addWidget(self.pdfExtractBox, 9, 0, 1, 1)
|
||||||
|
|
||||||
|
self.upscaleBox = QCheckBox(self.optionWidget)
|
||||||
|
self.upscaleBox.setObjectName(u"upscaleBox")
|
||||||
|
self.upscaleBox.setTristate(True)
|
||||||
|
|
||||||
|
self.gridLayout_2.addWidget(self.upscaleBox, 2, 1, 1, 1)
|
||||||
|
|
||||||
|
self.chunkSizeCheckBox = QCheckBox(self.optionWidget)
|
||||||
|
self.chunkSizeCheckBox.setObjectName(u"chunkSizeCheckBox")
|
||||||
|
|
||||||
|
self.gridLayout_2.addWidget(self.chunkSizeCheckBox, 7, 1, 1, 1)
|
||||||
|
|
||||||
|
self.qualityBox = QCheckBox(self.optionWidget)
|
||||||
|
self.qualityBox.setObjectName(u"qualityBox")
|
||||||
|
self.qualityBox.setTristate(True)
|
||||||
|
|
||||||
|
self.gridLayout_2.addWidget(self.qualityBox, 1, 2, 1, 1)
|
||||||
|
|
||||||
|
self.mozJpegBox = QCheckBox(self.optionWidget)
|
||||||
|
self.mozJpegBox.setObjectName(u"mozJpegBox")
|
||||||
|
self.mozJpegBox.setTristate(True)
|
||||||
|
|
||||||
|
self.gridLayout_2.addWidget(self.mozJpegBox, 4, 0, 1, 1)
|
||||||
|
|
||||||
|
self.titleEdit = QLineEdit(self.optionWidget)
|
||||||
|
self.titleEdit.setObjectName(u"titleEdit")
|
||||||
|
sizePolicy4.setHeightForWidth(self.titleEdit.sizePolicy().hasHeightForWidth())
|
||||||
|
self.titleEdit.setSizePolicy(sizePolicy4)
|
||||||
|
self.titleEdit.setFocusPolicy(Qt.FocusPolicy.ClickFocus)
|
||||||
|
self.titleEdit.setClearButtonEnabled(False)
|
||||||
|
|
||||||
|
self.gridLayout_2.addWidget(self.titleEdit, 0, 0, 1, 1)
|
||||||
|
|
||||||
|
self.eraseRainbowBox = QCheckBox(self.optionWidget)
|
||||||
|
self.eraseRainbowBox.setObjectName(u"eraseRainbowBox")
|
||||||
|
|
||||||
|
self.gridLayout_2.addWidget(self.eraseRainbowBox, 7, 2, 1, 1)
|
||||||
|
|
||||||
|
self.fileFusionBox = QCheckBox(self.optionWidget)
|
||||||
|
self.fileFusionBox.setObjectName(u"fileFusionBox")
|
||||||
|
|
||||||
|
self.gridLayout_2.addWidget(self.fileFusionBox, 6, 0, 1, 1)
|
||||||
|
|
||||||
|
self.coverFillBox = QCheckBox(self.optionWidget)
|
||||||
|
self.coverFillBox.setObjectName(u"coverFillBox")
|
||||||
|
|
||||||
|
self.gridLayout_2.addWidget(self.coverFillBox, 9, 1, 1, 1)
|
||||||
|
|
||||||
|
self.rotateRightBox = QCheckBox(self.optionWidget)
|
||||||
|
self.rotateRightBox.setObjectName(u"rotateRightBox")
|
||||||
|
|
||||||
|
self.gridLayout_2.addWidget(self.rotateRightBox, 10, 1, 1, 1)
|
||||||
|
|
||||||
|
self.gammaBox = QCheckBox(self.optionWidget)
|
||||||
|
self.gammaBox.setObjectName(u"gammaBox")
|
||||||
|
|
||||||
|
self.gridLayout_2.addWidget(self.gammaBox, 2, 2, 1, 1)
|
||||||
|
|
||||||
|
self.autoLevelBox = QCheckBox(self.optionWidget)
|
||||||
|
self.autoLevelBox.setObjectName(u"autoLevelBox")
|
||||||
|
|
||||||
|
self.gridLayout_2.addWidget(self.autoLevelBox, 8, 2, 1, 1)
|
||||||
|
|
||||||
|
self.interPanelCropBox = QCheckBox(self.optionWidget)
|
||||||
|
self.interPanelCropBox.setObjectName(u"interPanelCropBox")
|
||||||
|
self.interPanelCropBox.setTristate(True)
|
||||||
|
|
||||||
|
self.gridLayout_2.addWidget(self.interPanelCropBox, 6, 2, 1, 1)
|
||||||
|
|
||||||
|
self.rotateBox = QCheckBox(self.optionWidget)
|
||||||
|
self.rotateBox.setObjectName(u"rotateBox")
|
||||||
|
self.rotateBox.setTristate(True)
|
||||||
|
|
||||||
|
self.gridLayout_2.addWidget(self.rotateBox, 1, 1, 1, 1)
|
||||||
|
|
||||||
|
self.authorEdit = QLineEdit(self.optionWidget)
|
||||||
|
self.authorEdit.setObjectName(u"authorEdit")
|
||||||
|
sizePolicy4.setHeightForWidth(self.authorEdit.sizePolicy().hasHeightForWidth())
|
||||||
|
self.authorEdit.setSizePolicy(sizePolicy4)
|
||||||
|
self.authorEdit.setFocusPolicy(Qt.FocusPolicy.ClickFocus)
|
||||||
|
self.authorEdit.setClearButtonEnabled(False)
|
||||||
|
|
||||||
|
self.gridLayout_2.addWidget(self.authorEdit, 0, 1, 1, 1)
|
||||||
|
|
||||||
|
self.croppingBox = QCheckBox(self.optionWidget)
|
||||||
|
self.croppingBox.setObjectName(u"croppingBox")
|
||||||
|
self.croppingBox.setTristate(True)
|
||||||
|
|
||||||
|
self.gridLayout_2.addWidget(self.croppingBox, 4, 2, 1, 1)
|
||||||
|
|
||||||
|
self.pngLegacyBox = QCheckBox(self.optionWidget)
|
||||||
|
self.pngLegacyBox.setObjectName(u"pngLegacyBox")
|
||||||
|
|
||||||
|
self.gridLayout_2.addWidget(self.pngLegacyBox, 11, 0, 1, 1)
|
||||||
|
|
||||||
|
self.forcePngRgbBox = QCheckBox(self.optionWidget)
|
||||||
|
self.forcePngRgbBox.setObjectName(u"forcePngRgbBox")
|
||||||
|
|
||||||
|
self.gridLayout_2.addWidget(self.forcePngRgbBox, 11, 2, 1, 1)
|
||||||
|
|
||||||
|
|
||||||
self.gridLayout.addWidget(self.optionWidget, 5, 0, 1, 2)
|
self.gridLayout.addWidget(self.optionWidget, 5, 0, 1, 2)
|
||||||
@@ -543,7 +579,8 @@ class Ui_mainWindow(object):
|
|||||||
QWidget.setTabOrder(self.fileFusionBox, self.noRotateBox)
|
QWidget.setTabOrder(self.fileFusionBox, self.noRotateBox)
|
||||||
QWidget.setTabOrder(self.noRotateBox, self.interPanelCropBox)
|
QWidget.setTabOrder(self.noRotateBox, self.interPanelCropBox)
|
||||||
QWidget.setTabOrder(self.interPanelCropBox, self.metadataTitleBox)
|
QWidget.setTabOrder(self.interPanelCropBox, self.metadataTitleBox)
|
||||||
QWidget.setTabOrder(self.metadataTitleBox, self.chunkSizeCheckBox)
|
QWidget.setTabOrder(self.metadataTitleBox, self.coverFillBox)
|
||||||
|
QWidget.setTabOrder(self.coverFillBox, self.chunkSizeCheckBox)
|
||||||
QWidget.setTabOrder(self.chunkSizeCheckBox, self.chunkSizeBox)
|
QWidget.setTabOrder(self.chunkSizeCheckBox, self.chunkSizeBox)
|
||||||
QWidget.setTabOrder(self.chunkSizeBox, self.eraseRainbowBox)
|
QWidget.setTabOrder(self.chunkSizeBox, self.eraseRainbowBox)
|
||||||
QWidget.setTabOrder(self.eraseRainbowBox, self.rotateFirstBox)
|
QWidget.setTabOrder(self.eraseRainbowBox, self.rotateFirstBox)
|
||||||
@@ -612,30 +649,6 @@ class Ui_mainWindow(object):
|
|||||||
#endif // QT_CONFIG(tooltip)
|
#endif // QT_CONFIG(tooltip)
|
||||||
self.chunkSizeLabel.setText(QCoreApplication.translate("mainWindow", u"Chunk size MB:", None))
|
self.chunkSizeLabel.setText(QCoreApplication.translate("mainWindow", u"Chunk size MB:", None))
|
||||||
self.chunkSizeWarnLabel.setText(QCoreApplication.translate("mainWindow", u"Greater than default may cause performance issues on older ereaders.", None))
|
self.chunkSizeWarnLabel.setText(QCoreApplication.translate("mainWindow", u"Greater than default may cause performance issues on older ereaders.", None))
|
||||||
#if QT_CONFIG(tooltip)
|
|
||||||
self.titleEdit.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p>Default Title</p></body></html>", None))
|
|
||||||
#endif // QT_CONFIG(tooltip)
|
|
||||||
self.titleEdit.setPlaceholderText(QCoreApplication.translate("mainWindow", u"Default Title", None))
|
|
||||||
#if QT_CONFIG(tooltip)
|
|
||||||
self.mangaBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Enable right-to-left reading.</p></body></html>", None))
|
|
||||||
#endif // QT_CONFIG(tooltip)
|
|
||||||
self.mangaBox.setText(QCoreApplication.translate("mainWindow", u"Right-to-left (manga)", 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.croppingBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Disabled</span></p><p>Disabled</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Margins<br/></span>Margins</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Margins + page numbers<br/></span>Margins +page numbers</p></body></html>", None))
|
|
||||||
#endif // QT_CONFIG(tooltip)
|
|
||||||
self.croppingBox.setText(QCoreApplication.translate("mainWindow", u"Cropping mode", None))
|
|
||||||
#if QT_CONFIG(tooltip)
|
|
||||||
self.maximizeStrips.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - 1x4<br/></span>Keep format 1x4 panels strips.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - 2x2<br/></span>Turn 1x4 strips to 2x2 to maximize screen usage.</p></body></html>", None))
|
|
||||||
#endif // QT_CONFIG(tooltip)
|
|
||||||
self.maximizeStrips.setText(QCoreApplication.translate("mainWindow", u"1x4 to 2x2 strips", None))
|
|
||||||
#if QT_CONFIG(tooltip)
|
|
||||||
self.deleteBox.setToolTip(QCoreApplication.translate("mainWindow", u"Delete input file(s) or directory. It's not recoverable!", None))
|
|
||||||
#endif // QT_CONFIG(tooltip)
|
|
||||||
self.deleteBox.setText(QCoreApplication.translate("mainWindow", u"Delete input", None))
|
|
||||||
#if QT_CONFIG(tooltip)
|
#if QT_CONFIG(tooltip)
|
||||||
self.rotateFirstBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p>When the spread splitter option is partially checked,</p><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Rotate Last<br/></span>Put the rotated 2 page spread after the split spreads.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Rotate First<br/></span>Put the rotated 2 page spread before the split spreads.</p></body></html>", None))
|
self.rotateFirstBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p>When the spread splitter option is partially checked,</p><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Rotate Last<br/></span>Put the rotated 2 page spread after the split spreads.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Rotate First<br/></span>Put the rotated 2 page spread before the split spreads.</p></body></html>", None))
|
||||||
#endif // QT_CONFIG(tooltip)
|
#endif // QT_CONFIG(tooltip)
|
||||||
@@ -644,78 +657,64 @@ class Ui_mainWindow(object):
|
|||||||
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.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.outputSplit.setText(QCoreApplication.translate("mainWindow", u"Output split", None))
|
self.outputSplit.setText(QCoreApplication.translate("mainWindow", u"Output split", None))
|
||||||
|
#if QT_CONFIG(tooltip)
|
||||||
|
self.pdfWidthBox.setToolTip(QCoreApplication.translate("mainWindow", u"Render vector PDFs to device width instead of height.\n"
|
||||||
|
"\n"
|
||||||
|
"Useful if you plan to crop a little off the top and bottom to fill screen.", None))
|
||||||
|
#endif // QT_CONFIG(tooltip)
|
||||||
|
self.pdfWidthBox.setText(QCoreApplication.translate("mainWindow", u"PDF Width Render", None))
|
||||||
#if QT_CONFIG(tooltip)
|
#if QT_CONFIG(tooltip)
|
||||||
self.borderBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Autodetection<br/></span>The color of margins fill will be detected automatically.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - White<br/></span>Margins will be untouched.</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 untouched.</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)
|
#if QT_CONFIG(tooltip)
|
||||||
self.gammaBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p>Set a custom gamma correction.</p><p>1.0 is default (disabled).<br/>< 1.0 makes the image brighter.<br/>> 1.0 makes the image darker. </p><p>1.8 was the default in KCC 9.1.0 and earlier.</p><p>Use if you want to make midtones darker.</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.gammaBox.setText(QCoreApplication.translate("mainWindow", u"Custom gamma", None))
|
self.deleteBox.setText(QCoreApplication.translate("mainWindow", u"Delete input", None))
|
||||||
#if QT_CONFIG(tooltip)
|
|
||||||
self.upscaleBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Nothing<br/></span>Images smaller than device resolution will not be resized.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Stretching<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be not preserved.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Upscaling<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be preserved.</p></body></html>", None))
|
|
||||||
#endif // QT_CONFIG(tooltip)
|
|
||||||
self.upscaleBox.setText(QCoreApplication.translate("mainWindow", u"Stretch/Upscale", None))
|
|
||||||
#if QT_CONFIG(tooltip)
|
|
||||||
self.chunkSizeCheckBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p><span style=\" font-weight:700; text-decoration: underline;\">Unchecked<br/></span>Maximal output file size is 100 MB for Webtoon, 400 MB for others before split occurs.</p><p><span style=\" font-weight:700; text-decoration: underline;\">Checked</span><br/>Output file size specified in "Chunk size MB" before split occurs.</p></body></html>", None))
|
|
||||||
#endif // QT_CONFIG(tooltip)
|
|
||||||
self.chunkSizeCheckBox.setText(QCoreApplication.translate("mainWindow", u"Chunk size", None))
|
|
||||||
#if QT_CONFIG(tooltip)
|
|
||||||
self.colorBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Disable conversion to grayscale.</p></body></html>", None))
|
|
||||||
#endif // QT_CONFIG(tooltip)
|
|
||||||
self.colorBox.setText(QCoreApplication.translate("mainWindow", u"Color mode", None))
|
|
||||||
#if QT_CONFIG(tooltip)
|
|
||||||
self.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 - Split and rotate<br/></span>Double page spreads will be displayed twice. First split and then rotated. </p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Rotate<br/></span>Double page spreads will be rotated.</p></body></html>", None))
|
|
||||||
#endif // QT_CONFIG(tooltip)
|
|
||||||
self.rotateBox.setText(QCoreApplication.translate("mainWindow", u"Spread splitter", None))
|
|
||||||
#if QT_CONFIG(tooltip)
|
#if QT_CONFIG(tooltip)
|
||||||
self.spreadShiftBox.setToolTip(QCoreApplication.translate("mainWindow", u"Shift first page to opposite side in landscape for two page spread alignment", None))
|
self.spreadShiftBox.setToolTip(QCoreApplication.translate("mainWindow", u"Shift first page to opposite side in landscape for two page spread alignment", None))
|
||||||
#endif // QT_CONFIG(tooltip)
|
#endif // QT_CONFIG(tooltip)
|
||||||
self.spreadShiftBox.setText(QCoreApplication.translate("mainWindow", u"Spread shift", None))
|
self.spreadShiftBox.setText(QCoreApplication.translate("mainWindow", u"Spread shift", None))
|
||||||
#if QT_CONFIG(tooltip)
|
#if QT_CONFIG(tooltip)
|
||||||
self.disableProcessingBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Do not process any image, ignore profile and processing options.</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.disableProcessingBox.setText(QCoreApplication.translate("mainWindow", u"Disable processing", None))
|
self.maximizeStrips.setText(QCoreApplication.translate("mainWindow", u"1x4 to 2x2 strips", None))
|
||||||
#if QT_CONFIG(tooltip)
|
#if QT_CONFIG(tooltip)
|
||||||
self.eraseRainbowBox.setToolTip(QCoreApplication.translate("mainWindow", u"Erase rainbow effect on color eink screen by attenuating interfering frequencies", None))
|
self.webtoonBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Enable special parsing mode for Korean Webtoons.</p></body></html>", None))
|
||||||
#endif // QT_CONFIG(tooltip)
|
#endif // QT_CONFIG(tooltip)
|
||||||
self.eraseRainbowBox.setText(QCoreApplication.translate("mainWindow", u"Rainbow eraser", None))
|
self.webtoonBox.setText(QCoreApplication.translate("mainWindow", u"Webtoon mode", None))
|
||||||
#if QT_CONFIG(tooltip)
|
#if QT_CONFIG(tooltip)
|
||||||
self.noRotateBox.setToolTip(QCoreApplication.translate("mainWindow", u"Do not rotate double page spreads in spread splitter option.", None))
|
self.noRotateBox.setToolTip(QCoreApplication.translate("mainWindow", u"Do not rotate double page spreads in spread splitter option.", None))
|
||||||
#endif // QT_CONFIG(tooltip)
|
#endif // QT_CONFIG(tooltip)
|
||||||
self.noRotateBox.setText(QCoreApplication.translate("mainWindow", u"No rotate", None))
|
self.noRotateBox.setText(QCoreApplication.translate("mainWindow", u"No rotate", None))
|
||||||
#if QT_CONFIG(tooltip)
|
#if QT_CONFIG(tooltip)
|
||||||
self.fileFusionBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p>Combines all selected files into a single file. (Helpful for combining chapters into volumes.)</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.fileFusionBox.setText(QCoreApplication.translate("mainWindow", u"File Fusion", None))
|
self.mangaBox.setText(QCoreApplication.translate("mainWindow", u"Right-to-left (manga)", None))
|
||||||
#if QT_CONFIG(tooltip)
|
#if QT_CONFIG(tooltip)
|
||||||
self.authorEdit.setToolTip(QCoreApplication.translate("mainWindow", u"Default Author is KCC", None))
|
self.noQuantizeBox.setToolTip(QCoreApplication.translate("mainWindow", u"Don't quantize PNG images to 16 colors (4 bit)\n"
|
||||||
|
"\n"
|
||||||
|
"This will double file size but preserve all 256 colors (8 bit).\n"
|
||||||
|
"\n"
|
||||||
|
"Eink only has 16 shades of gray so you probably don't want this.", None))
|
||||||
#endif // QT_CONFIG(tooltip)
|
#endif // QT_CONFIG(tooltip)
|
||||||
self.authorEdit.setPlaceholderText(QCoreApplication.translate("mainWindow", u"Default Author", None))
|
self.noQuantizeBox.setText(QCoreApplication.translate("mainWindow", u"No Quantize", 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.jpegQualityBox.setToolTip(QCoreApplication.translate("mainWindow", u"The JPEG quality, on a scale from 0 (worst) to 95 (best). \n"
|
||||||
|
"\n"
|
||||||
|
"Default is 85 for most devices besides Kindle Scribe and Colorsoft, which are 90.\n"
|
||||||
|
"\n"
|
||||||
|
"Higher values are larger and higher quality, and may resolve blank page issues.", None))
|
||||||
#endif // QT_CONFIG(tooltip)
|
#endif // QT_CONFIG(tooltip)
|
||||||
self.qualityBox.setText(QCoreApplication.translate("mainWindow", u"Panel View 4/2/HQ", None))
|
self.jpegQualityBox.setText(QCoreApplication.translate("mainWindow", u"Custom JPEG Quality", None))
|
||||||
#if QT_CONFIG(tooltip)
|
#if QT_CONFIG(tooltip)
|
||||||
self.interPanelCropBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Disabled<br/></span>Disabled</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Horizontal<br/></span>Crop empty horizontal lines.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Both<br/></span>Crop empty horizontal and vertical lines.</p></body></html>", None))
|
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)
|
#endif // QT_CONFIG(tooltip)
|
||||||
self.interPanelCropBox.setText(QCoreApplication.translate("mainWindow", u"Inter-panel crop", None))
|
self.colorBox.setText(QCoreApplication.translate("mainWindow", u"Color mode", None))
|
||||||
#if QT_CONFIG(tooltip)
|
#if QT_CONFIG(tooltip)
|
||||||
self.metadataTitleBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Don't use metadata Title<br/></span>Write default title.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Add metadata Title to the default schema<br/></span>Write default title with Title from ComicInfo.xml or other embedded metadata.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Use metadata Title only<br/></span>Write Title from ComicInfo.xml or other embedded metadata.</p></body></html>", None))
|
self.disableProcessingBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'>Do not process any image, ignore profile and processing options.</p></body></html>", None))
|
||||||
#endif // QT_CONFIG(tooltip)
|
#endif // QT_CONFIG(tooltip)
|
||||||
self.metadataTitleBox.setText(QCoreApplication.translate("mainWindow", u"Metadata Title", None))
|
self.disableProcessingBox.setText(QCoreApplication.translate("mainWindow", u"Disable processing", 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.autoLevelBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p>By default, KCC maps the darkest pixel value to pure black (the black point.)</p><p>Extreme black point sets the black point to be the most common dark pixel value.</p><p>Useful when text is black but artwork is gray.</p></body></html>", None))
|
|
||||||
#endif // QT_CONFIG(tooltip)
|
|
||||||
self.autoLevelBox.setText(QCoreApplication.translate("mainWindow", u"Extreme Black Point", None))
|
|
||||||
#if QT_CONFIG(tooltip)
|
|
||||||
self.autocontrastBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - BW only<br/></span>Only autocontrast bw pages. Ignored for pages where near blacks or whites don't exist.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Disabled<br/></span>Disable autocontrast</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - BW and Color<br/></span>BW and color images will be autocontrasted. Ignored for pages where near blacks or whites don't exist.</p></body></html>", None))
|
|
||||||
#endif // QT_CONFIG(tooltip)
|
|
||||||
self.autocontrastBox.setText(QCoreApplication.translate("mainWindow", u"Autocontrast", None))
|
|
||||||
#if QT_CONFIG(tooltip)
|
#if QT_CONFIG(tooltip)
|
||||||
self.defaultOutputFolderBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - next to source<br/></span>Place output files next to source files</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - folder next to source<br/></span>Place output files in a folder next to source files</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Custom<br/></span>Place output files in custom directory specified by right button</p></body></html>", None))
|
self.defaultOutputFolderBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - next to source<br/></span>Place output files next to source files</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - folder next to source<br/></span>Place output files in a folder next to source files</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Custom<br/></span>Place output files in custom directory specified by right button</p></body></html>", None))
|
||||||
#endif // QT_CONFIG(tooltip)
|
#endif // QT_CONFIG(tooltip)
|
||||||
@@ -725,13 +724,88 @@ class Ui_mainWindow(object):
|
|||||||
#endif // QT_CONFIG(tooltip)
|
#endif // QT_CONFIG(tooltip)
|
||||||
self.defaultOutputFolderButton.setText("")
|
self.defaultOutputFolderButton.setText("")
|
||||||
#if QT_CONFIG(tooltip)
|
#if QT_CONFIG(tooltip)
|
||||||
self.jpegQualityBox.setToolTip(QCoreApplication.translate("mainWindow", u"The JPEG quality, on a scale from 0 (worst) to 95 (best). \n"
|
self.metadataTitleBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Don't use metadata Title<br/></span>Write default title.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Add metadata Title to the default schema<br/></span>Write default title with Title from ComicInfo.xml or other embedded metadata.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Use metadata Title only<br/></span>Write Title from ComicInfo.xml or other embedded metadata.</p></body></html>", None))
|
||||||
"\n"
|
|
||||||
"Default is 85 for most devices besides Kindle Scribe and Colorsoft, which are 90.\n"
|
|
||||||
"\n"
|
|
||||||
"Higher values are larger and higher quality, and may resolve blank page issues.", None))
|
|
||||||
#endif // QT_CONFIG(tooltip)
|
#endif // QT_CONFIG(tooltip)
|
||||||
self.jpegQualityBox.setText(QCoreApplication.translate("mainWindow", u"Custom JPEG Quality", None))
|
self.metadataTitleBox.setText(QCoreApplication.translate("mainWindow", u"Metadata Title", None))
|
||||||
|
#if QT_CONFIG(tooltip)
|
||||||
|
self.autocontrastBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - BW only<br/></span>Only autocontrast bw pages. Ignored for pages where near blacks or whites don't exist.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Disabled<br/></span>Disable autocontrast</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - BW and Color<br/></span>BW and color images will be autocontrasted. Ignored for pages where near blacks or whites don't exist.</p></body></html>", None))
|
||||||
|
#endif // QT_CONFIG(tooltip)
|
||||||
|
self.autocontrastBox.setText(QCoreApplication.translate("mainWindow", u"Autocontrast", None))
|
||||||
|
#if QT_CONFIG(tooltip)
|
||||||
|
self.pdfExtractBox.setToolTip(QCoreApplication.translate("mainWindow", u"Use the PDF image extraction method from KCC 8 and earlier.\n"
|
||||||
|
"\n"
|
||||||
|
"Useful for really weird PDFs.", None))
|
||||||
|
#endif // QT_CONFIG(tooltip)
|
||||||
|
self.pdfExtractBox.setText(QCoreApplication.translate("mainWindow", u"PDF Legacy Extract", None))
|
||||||
|
#if QT_CONFIG(tooltip)
|
||||||
|
self.upscaleBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Nothing<br/></span>Images smaller than device resolution will not be resized.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Stretching<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be not preserved.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Upscaling<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be preserved.</p></body></html>", None))
|
||||||
|
#endif // QT_CONFIG(tooltip)
|
||||||
|
self.upscaleBox.setText(QCoreApplication.translate("mainWindow", u"Stretch/Upscale", None))
|
||||||
|
#if QT_CONFIG(tooltip)
|
||||||
|
self.chunkSizeCheckBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p><span style=\" font-weight:700; text-decoration: underline;\">Unchecked<br/></span>Maximal output file size is 100 MB for Webtoon, 400 MB for others before split occurs.</p><p><span style=\" font-weight:700; text-decoration: underline;\">Checked</span><br/>Output file size specified in "Chunk size MB" before split occurs.</p></body></html>", None))
|
||||||
|
#endif // QT_CONFIG(tooltip)
|
||||||
|
self.chunkSizeCheckBox.setText(QCoreApplication.translate("mainWindow", u"Chunk size", None))
|
||||||
|
#if QT_CONFIG(tooltip)
|
||||||
|
self.qualityBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p style='white-space:pre'><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - 4 panels<br/></span>Zoom each corner separately.</p><p style='white-space:pre'><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - 2 panels<br/></span>Zoom only the top and bottom of the page.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - 4 high-quality panels<br/></span>Zoom each corner separately. Try to increase the quality of magnification. Check wiki for more details.</p></body></html>", None))
|
||||||
|
#endif // QT_CONFIG(tooltip)
|
||||||
|
self.qualityBox.setText(QCoreApplication.translate("mainWindow", u"Panel View 4/2/HQ", 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 for black and white images</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.titleEdit.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p>Default Title</p></body></html>", None))
|
||||||
|
#endif // QT_CONFIG(tooltip)
|
||||||
|
self.titleEdit.setPlaceholderText(QCoreApplication.translate("mainWindow", u"Default Title", None))
|
||||||
|
#if QT_CONFIG(tooltip)
|
||||||
|
self.eraseRainbowBox.setToolTip(QCoreApplication.translate("mainWindow", u"Erase rainbow effect on color eink screen by attenuating interfering frequencies", None))
|
||||||
|
#endif // QT_CONFIG(tooltip)
|
||||||
|
self.eraseRainbowBox.setText(QCoreApplication.translate("mainWindow", u"Rainbow eraser", None))
|
||||||
|
#if QT_CONFIG(tooltip)
|
||||||
|
self.fileFusionBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p>Combines all selected files into a single file. (Helpful for combining chapters into volumes.)</p></body></html>", None))
|
||||||
|
#endif // QT_CONFIG(tooltip)
|
||||||
|
self.fileFusionBox.setText(QCoreApplication.translate("mainWindow", u"File Fusion", None))
|
||||||
|
#if QT_CONFIG(tooltip)
|
||||||
|
self.coverFillBox.setToolTip(QCoreApplication.translate("mainWindow", u"Resize cover to exact device resolution by center-cropping to aspect ratio first.\n"
|
||||||
|
"May crop top/bottom or left/right depending on source aspect ratio. Not implemented for Kindle Scribe.", None))
|
||||||
|
#endif // QT_CONFIG(tooltip)
|
||||||
|
self.coverFillBox.setText(QCoreApplication.translate("mainWindow", u"Cover Fill", None))
|
||||||
|
#if QT_CONFIG(tooltip)
|
||||||
|
self.rotateRightBox.setToolTip(QCoreApplication.translate("mainWindow", u"Rotate 2 page spreads in opposite direction than normal.", None))
|
||||||
|
#endif // QT_CONFIG(tooltip)
|
||||||
|
self.rotateRightBox.setText(QCoreApplication.translate("mainWindow", u"Rotate Right", None))
|
||||||
|
#if QT_CONFIG(tooltip)
|
||||||
|
self.gammaBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p>Set a custom gamma correction.</p><p>1.0 is default (disabled).<br/>< 1.0 makes the image brighter.<br/>> 1.0 makes the image darker. </p><p>1.8 was the default in KCC 9.1.0 and earlier.</p><p>Use if you want to make midtones darker.</p></body></html>", None))
|
||||||
|
#endif // QT_CONFIG(tooltip)
|
||||||
|
self.gammaBox.setText(QCoreApplication.translate("mainWindow", u"Custom gamma", None))
|
||||||
|
#if QT_CONFIG(tooltip)
|
||||||
|
self.autoLevelBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p>By default, KCC maps the darkest pixel value to pure black (the black point.)</p><p>Extreme black point sets the black point to be the most common dark pixel value.</p><p>Useful when text is black but artwork is gray.</p></body></html>", None))
|
||||||
|
#endif // QT_CONFIG(tooltip)
|
||||||
|
self.autoLevelBox.setText(QCoreApplication.translate("mainWindow", u"Extreme Black Point", None))
|
||||||
|
#if QT_CONFIG(tooltip)
|
||||||
|
self.interPanelCropBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Disabled<br/></span>Disabled</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Horizontal<br/></span>Crop empty horizontal lines.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Both<br/></span>Crop empty horizontal and vertical lines.</p></body></html>", None))
|
||||||
|
#endif // QT_CONFIG(tooltip)
|
||||||
|
self.interPanelCropBox.setText(QCoreApplication.translate("mainWindow", u"Inter-panel crop", None))
|
||||||
|
#if QT_CONFIG(tooltip)
|
||||||
|
self.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 - Split and rotate<br/></span>Double page spreads will be displayed twice. First split and then rotated. </p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Rotate<br/></span>Double page spreads will be rotated.</p></body></html>", None))
|
||||||
|
#endif // QT_CONFIG(tooltip)
|
||||||
|
self.rotateBox.setText(QCoreApplication.translate("mainWindow", u"Spread splitter", None))
|
||||||
|
#if QT_CONFIG(tooltip)
|
||||||
|
self.authorEdit.setToolTip(QCoreApplication.translate("mainWindow", u"Default Author is KCC", None))
|
||||||
|
#endif // QT_CONFIG(tooltip)
|
||||||
|
self.authorEdit.setPlaceholderText(QCoreApplication.translate("mainWindow", u"Default Author", None))
|
||||||
|
#if QT_CONFIG(tooltip)
|
||||||
|
self.croppingBox.setToolTip(QCoreApplication.translate("mainWindow", u"<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Disabled</span></p><p>Disabled</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Margins<br/></span>Margins</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Margins + page numbers<br/></span>Margins +page numbers</p></body></html>", None))
|
||||||
|
#endif // QT_CONFIG(tooltip)
|
||||||
|
self.croppingBox.setText(QCoreApplication.translate("mainWindow", u"Cropping mode", None))
|
||||||
|
#if QT_CONFIG(tooltip)
|
||||||
|
self.pngLegacyBox.setToolTip(QCoreApplication.translate("mainWindow", u"Use a more compatible 8 bit PNG instead of 4 bit.", None))
|
||||||
|
#endif // QT_CONFIG(tooltip)
|
||||||
|
self.pngLegacyBox.setText(QCoreApplication.translate("mainWindow", u"PNG Legacy Mode", None))
|
||||||
|
#if QT_CONFIG(tooltip)
|
||||||
|
self.forcePngRgbBox.setToolTip(QCoreApplication.translate("mainWindow", u"Force full color images to be saved in lossless PNG format, dramatically increases the filesize.", None))
|
||||||
|
#endif // QT_CONFIG(tooltip)
|
||||||
|
self.forcePngRgbBox.setText(QCoreApplication.translate("mainWindow", u"Force PNG RGB", None))
|
||||||
self.gammaLabel.setText(QCoreApplication.translate("mainWindow", u"Gamma: Auto", None))
|
self.gammaLabel.setText(QCoreApplication.translate("mainWindow", u"Gamma: Auto", None))
|
||||||
self.jpegQualityLabel.setText(QCoreApplication.translate("mainWindow", u"JPEG Quality:", None))
|
self.jpegQualityLabel.setText(QCoreApplication.translate("mainWindow", u"JPEG Quality:", None))
|
||||||
# retranslateUi
|
# retranslateUi
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
__version__ = '9.4.1'
|
__version__ = '9.6.2'
|
||||||
__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'
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ from .comicarchive import SEVENZIP, available_archive_tools
|
|||||||
from . import comic2panel
|
from . import comic2panel
|
||||||
from . import image
|
from . import image
|
||||||
from . import comicarchive
|
from . import comicarchive
|
||||||
|
from . import pdfjpgextract
|
||||||
from . import dualmetafix
|
from . import dualmetafix
|
||||||
from . import metadata
|
from . import metadata
|
||||||
from . import kindle
|
from . import kindle
|
||||||
@@ -65,16 +66,16 @@ def main(argv=None):
|
|||||||
parser.print_help()
|
parser.print_help()
|
||||||
return 0
|
return 0
|
||||||
if sys.platform.startswith('win'):
|
if sys.platform.startswith('win'):
|
||||||
sources = set([source for option in options.input for source in glob(escape(option))])
|
sources = [source for option in options.input for source in glob(escape(option))]
|
||||||
else:
|
else:
|
||||||
sources = set(options.input)
|
sources = options.input
|
||||||
if len(sources) == 0:
|
if len(sources) == 0:
|
||||||
print('No matching files found.')
|
print('No matching files found.')
|
||||||
return 1
|
return 1
|
||||||
if options.filefusion:
|
if options.filefusion:
|
||||||
fusion_path = makeFusion(list(sources))
|
fusion_path = makeFusion(list(sources))
|
||||||
sources.clear()
|
sources.clear()
|
||||||
sources.add(fusion_path)
|
sources.append(fusion_path)
|
||||||
for source in sources:
|
for source in sources:
|
||||||
source = source.rstrip('\\').rstrip('/')
|
source = source.rstrip('\\').rstrip('/')
|
||||||
options = copy(args)
|
options = copy(args)
|
||||||
@@ -659,7 +660,7 @@ def imgDirectoryProcessing(path, job_progress=''):
|
|||||||
raise UserWarning("Conversion interrupted.")
|
raise UserWarning("Conversion interrupted.")
|
||||||
if len(workerOutput) > 0:
|
if len(workerOutput) > 0:
|
||||||
rmtree(os.path.join(path, '..', '..'), True)
|
rmtree(os.path.join(path, '..', '..'), True)
|
||||||
raise RuntimeError("One of workers crashed. Cause: " + workerOutput[0][0], workerOutput[0][1])
|
raise RuntimeError("One of workers crashed. Maybe restart PC. Cause: " + workerOutput[0][0], workerOutput[0][1])
|
||||||
else:
|
else:
|
||||||
rmtree(os.path.join(path, '..', '..'), True)
|
rmtree(os.path.join(path, '..', '..'), True)
|
||||||
raise UserWarning("C2E: Source directory is empty.")
|
raise UserWarning("C2E: Source directory is empty.")
|
||||||
@@ -688,7 +689,6 @@ def imgFileProcessing(work):
|
|||||||
workImg = image.ComicPageParser((dirpath, afile), opt)
|
workImg = image.ComicPageParser((dirpath, afile), opt)
|
||||||
for i in workImg.payload:
|
for i in workImg.payload:
|
||||||
img = image.ComicPage(opt, *i)
|
img = image.ComicPage(opt, *i)
|
||||||
is_color = (opt.forcecolor and img.color)
|
|
||||||
if opt.cropping == 2 and not opt.webtoon:
|
if opt.cropping == 2 and not opt.webtoon:
|
||||||
img.cropPageNumber(opt.croppingp, opt.croppingm)
|
img.cropPageNumber(opt.croppingp, opt.croppingm)
|
||||||
if opt.cropping == 1 and not opt.webtoon:
|
if opt.cropping == 1 and not opt.webtoon:
|
||||||
@@ -698,18 +698,24 @@ def imgFileProcessing(work):
|
|||||||
|
|
||||||
img.gammaCorrectImage()
|
img.gammaCorrectImage()
|
||||||
|
|
||||||
|
if not img.colorOutput:
|
||||||
|
img.convertToGrayscale()
|
||||||
|
|
||||||
img.autocontrastImage()
|
img.autocontrastImage()
|
||||||
img.resizeImage()
|
img.resizeImage()
|
||||||
img.optimizeForDisplay(opt.eraserainbow, is_color)
|
img.optimizeForDisplay(opt.eraserainbow, img.colorOutput)
|
||||||
|
|
||||||
if is_color:
|
if img.colorOutput:
|
||||||
pass
|
pass
|
||||||
elif opt.forcepng:
|
elif opt.forcepng:
|
||||||
img.convertToGrayscale()
|
if not opt.noquantize:
|
||||||
if opt.format != 'PDF':
|
|
||||||
img.quantizeImage()
|
img.quantizeImage()
|
||||||
else:
|
if opt.format == 'PDF':
|
||||||
img.convertToGrayscale()
|
img.convertToGrayscale()
|
||||||
|
elif opt.profile == 'KDX' and opt.format == 'CBZ':
|
||||||
|
img.convertToGrayscale()
|
||||||
|
elif opt.pnglegacy:
|
||||||
|
img.convertToGrayscale()
|
||||||
output.append(img.saveToDir())
|
output.append(img.saveToDir())
|
||||||
return output
|
return output
|
||||||
except Exception:
|
except Exception:
|
||||||
@@ -739,7 +745,9 @@ def render_page(vector):
|
|||||||
cpu = vector[1] # number of CPUs
|
cpu = vector[1] # number of CPUs
|
||||||
filename = vector[2] # document filename
|
filename = vector[2] # document filename
|
||||||
output_dir = vector[3]
|
output_dir = vector[3]
|
||||||
target_height = vector[4]
|
target_width = vector[4]
|
||||||
|
target_height = vector[5]
|
||||||
|
pdf_width = vector[6]
|
||||||
with pymupdf.open(filename) as doc: # open the document
|
with pymupdf.open(filename) as doc: # open the document
|
||||||
num_pages = doc.page_count # get number of pages
|
num_pages = doc.page_count # get number of pages
|
||||||
|
|
||||||
@@ -750,7 +758,10 @@ def render_page(vector):
|
|||||||
|
|
||||||
for i in range(seg_from, seg_to): # work through our page segment
|
for i in range(seg_from, seg_to): # work through our page segment
|
||||||
page = doc[i]
|
page = doc[i]
|
||||||
zoom = target_height / page.rect.height
|
if not pdf_width or page.rect.width > page.rect.height:
|
||||||
|
zoom = target_height / page.rect.height
|
||||||
|
else:
|
||||||
|
zoom = target_width / page.rect.width
|
||||||
mat = pymupdf.Matrix(zoom, zoom)
|
mat = pymupdf.Matrix(zoom, zoom)
|
||||||
# TODO: decide colorspace earlier so later color check is cheaper.
|
# TODO: decide colorspace earlier so later color check is cheaper.
|
||||||
# This is actually pretty hard when you have to deal with color vector text
|
# This is actually pretty hard when you have to deal with color vector text
|
||||||
@@ -800,9 +811,7 @@ def extract_page(vector):
|
|||||||
if len(image_list) > 1:
|
if len(image_list) > 1:
|
||||||
raise UserWarning("mupdf_pdf_extract_page_image() function can be used only with single image pages.")
|
raise UserWarning("mupdf_pdf_extract_page_image() function can be used only with single image pages.")
|
||||||
if not image_list:
|
if not image_list:
|
||||||
width, height = int(page.rect.width), int(page.rect.height)
|
continue
|
||||||
blank_page = Image.new("RGB", (width, height), "white")
|
|
||||||
blank_page.save(output_path)
|
|
||||||
else:
|
else:
|
||||||
xref = image_list[0][0]
|
xref = image_list[0][0]
|
||||||
d = doc.extract_image(xref)
|
d = doc.extract_image(xref)
|
||||||
@@ -817,7 +826,7 @@ def extract_page(vector):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def mupdf_pdf_process_pages_parallel(filename, output_dir, target_height):
|
def mupdf_pdf_process_pages_parallel(filename, output_dir, target_width, target_height):
|
||||||
render = False
|
render = False
|
||||||
with pymupdf.open(filename) as doc:
|
with pymupdf.open(filename) as doc:
|
||||||
for page in doc:
|
for page in doc:
|
||||||
@@ -837,7 +846,7 @@ def mupdf_pdf_process_pages_parallel(filename, output_dir, target_height):
|
|||||||
cpu = cpu_count()
|
cpu = cpu_count()
|
||||||
|
|
||||||
# make vectors of arguments for the processes
|
# make vectors of arguments for the processes
|
||||||
vectors = [(i, cpu, filename, output_dir, target_height) for i in range(cpu)]
|
vectors = [(i, cpu, filename, output_dir, target_width, target_height, options.pdfwidth) for i in range(cpu)]
|
||||||
print("Starting %i processes for '%s'." % (cpu, filename))
|
print("Starting %i processes for '%s'." % (cpu, filename))
|
||||||
|
|
||||||
|
|
||||||
@@ -854,6 +863,7 @@ def mupdf_pdf_process_pages_parallel(filename, output_dir, target_height):
|
|||||||
def getWorkFolder(afile, workdir=None):
|
def getWorkFolder(afile, workdir=None):
|
||||||
if not workdir:
|
if not workdir:
|
||||||
workdir = mkdtemp('', 'KCC-')
|
workdir = mkdtemp('', 'KCC-')
|
||||||
|
# workdir = mkdtemp('', 'KCC-', os.path.dirname(afile))
|
||||||
fullPath = os.path.join(workdir, 'OEBPS', 'Images')
|
fullPath = os.path.join(workdir, 'OEBPS', 'Images')
|
||||||
else:
|
else:
|
||||||
fullPath = workdir
|
fullPath = workdir
|
||||||
@@ -875,13 +885,19 @@ def getWorkFolder(afile, workdir=None):
|
|||||||
os.makedirs(fullPath)
|
os.makedirs(fullPath)
|
||||||
path = workdir
|
path = workdir
|
||||||
sanitizePermissions(path)
|
sanitizePermissions(path)
|
||||||
target_height = options.profileData[1][1]
|
if options.pdfextract:
|
||||||
|
pdf = pdfjpgextract.PdfJpgExtract(afile, fullPath)
|
||||||
|
njpg = pdf.extract()
|
||||||
|
if njpg == 0:
|
||||||
|
raise UserWarning("Failed to extract images from PDF file.")
|
||||||
|
return workdir
|
||||||
|
target_width, target_height = options.profileData[1]
|
||||||
if options.cropping == 1:
|
if options.cropping == 1:
|
||||||
target_height = target_height + target_height*0.20 #Account for possible margin at the top and bottom
|
target_height = target_height + target_height*0.20 #Account for possible margin at the top and bottom
|
||||||
elif options.cropping == 2:
|
elif options.cropping == 2:
|
||||||
target_height = target_height + target_height*0.25 #Account for possible margin at the top and bottom with page number
|
target_height = target_height + target_height*0.25 #Account for possible margin at the top and bottom with page number
|
||||||
try:
|
try:
|
||||||
mupdf_pdf_process_pages_parallel(afile, fullPath, target_height)
|
mupdf_pdf_process_pages_parallel(afile, fullPath, target_width, target_height)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
rmtree(path, True)
|
rmtree(path, True)
|
||||||
raise UserWarning(f"Failed to extract images from PDF file. {e}")
|
raise UserWarning(f"Failed to extract images from PDF file. {e}")
|
||||||
@@ -957,6 +973,13 @@ def getOutputFilename(srcpath, wantedname, ext, tomenumber):
|
|||||||
while os.path.isfile(basename + '_kcc' + str(counter) + ext):
|
while os.path.isfile(basename + '_kcc' + str(counter) + ext):
|
||||||
counter += 1
|
counter += 1
|
||||||
filename = basename + '_kcc' + str(counter) + ext
|
filename = basename + '_kcc' + str(counter) + ext
|
||||||
|
elif options.format == 'MOBI' and ext == '.epub':
|
||||||
|
counter = 0
|
||||||
|
basename = os.path.splitext(filename)[0]
|
||||||
|
if os.path.isfile(basename + '.mobi'):
|
||||||
|
while os.path.isfile(basename + '_kcc' + str(counter) + '.mobi'):
|
||||||
|
counter += 1
|
||||||
|
filename = basename + '_kcc' + str(counter) + ext
|
||||||
return filename
|
return filename
|
||||||
|
|
||||||
|
|
||||||
@@ -1066,7 +1089,7 @@ def removeNonImages(filetree):
|
|||||||
raise UserWarning('No images detected, nested archives are not supported.')
|
raise UserWarning('No images detected, nested archives are not supported.')
|
||||||
|
|
||||||
|
|
||||||
def sanitizeTree(filetree):
|
def sanitizeTree(filetree, prefix='kcc'):
|
||||||
chapterNames = {}
|
chapterNames = {}
|
||||||
page = 1
|
page = 1
|
||||||
cover_path = None
|
cover_path = None
|
||||||
@@ -1076,7 +1099,7 @@ def sanitizeTree(filetree):
|
|||||||
_, ext = getImageFileName(name)
|
_, ext = getImageFileName(name)
|
||||||
|
|
||||||
# 9999 page limit
|
# 9999 page limit
|
||||||
unique_name = f'kcc-{page:04}'
|
unique_name = f'{prefix}-{page:04}'
|
||||||
page += 1
|
page += 1
|
||||||
|
|
||||||
newKey = os.path.join(root, unique_name + ext)
|
newKey = os.path.join(root, unique_name + ext)
|
||||||
@@ -1125,7 +1148,7 @@ def chunk_directory(path):
|
|||||||
for root, _, files in os.walk(os.path.join(path, 'OEBPS', 'Images')):
|
for root, _, files in os.walk(os.path.join(path, 'OEBPS', 'Images')):
|
||||||
for f in files:
|
for f in files:
|
||||||
# Windows MAX_LEN = 260 plus some buffer
|
# Windows MAX_LEN = 260 plus some buffer
|
||||||
if os.name == 'nt' and len(os.path.join(root, f)) > 180:
|
if os.name == 'nt' and len(os.path.join(root, f)) > 220:
|
||||||
flattenTree(os.path.join(path, 'OEBPS', 'Images'))
|
flattenTree(os.path.join(path, 'OEBPS', 'Images'))
|
||||||
level = 1
|
level = 1
|
||||||
break
|
break
|
||||||
@@ -1269,10 +1292,13 @@ def makeZIP(zipfilename, basedir, job_progress='', isepub=False):
|
|||||||
zipfilename = os.path.abspath(zipfilename) + '.zip'
|
zipfilename = os.path.abspath(zipfilename) + '.zip'
|
||||||
if SEVENZIP in available_archive_tools():
|
if SEVENZIP in available_archive_tools():
|
||||||
if isepub:
|
if isepub:
|
||||||
mimetypeFile = open(os.path.join(basedir, 'mimetype'), 'w')
|
mimetypeFile = open(os.path.join(basedir, '!mimetype'), 'w')
|
||||||
mimetypeFile.write('application/epub+zip')
|
mimetypeFile.write('application/epub+zip')
|
||||||
mimetypeFile.close()
|
mimetypeFile.close()
|
||||||
subprocess_run([SEVENZIP, 'a', '-tzip', zipfilename, "*"], capture_output=True, check=True, cwd=basedir)
|
subprocess_run([SEVENZIP, 'a', '-tzip', zipfilename, "*"], capture_output=True, check=True, cwd=basedir)
|
||||||
|
# crazy hack to ensure mimetype is first when using 7zip
|
||||||
|
if isepub:
|
||||||
|
subprocess_run([SEVENZIP, 'rn', zipfilename, '!mimetype', 'mimetype'], capture_output=True, check=True, cwd=basedir)
|
||||||
else:
|
else:
|
||||||
zipOutput = ZipFile(zipfilename, 'w', ZIP_DEFLATED)
|
zipOutput = ZipFile(zipfilename, 'w', ZIP_DEFLATED)
|
||||||
if isepub:
|
if isepub:
|
||||||
@@ -1337,11 +1363,19 @@ def makeParser():
|
|||||||
help="Shift first page to opposite side in landscape for spread alignment")
|
help="Shift first page to opposite side in landscape for spread alignment")
|
||||||
output_options.add_argument("--norotate", action="store_true", dest="norotate", default=False,
|
output_options.add_argument("--norotate", action="store_true", dest="norotate", default=False,
|
||||||
help="Do not rotate double page spreads in spread splitter option.")
|
help="Do not rotate double page spreads in spread splitter option.")
|
||||||
|
output_options.add_argument("--rotateright", action="store_true", dest="rotateright", default=False,
|
||||||
|
help="Rotate double page spreads in opposite direction.")
|
||||||
output_options.add_argument("--rotatefirst", action="store_true", dest="rotatefirst", default=False,
|
output_options.add_argument("--rotatefirst", action="store_true", dest="rotatefirst", default=False,
|
||||||
help="Put rotated 2 page spread first in spread splitter option.")
|
help="Put rotated 2 page spread first in spread splitter option.")
|
||||||
|
|
||||||
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 profile or processing option")
|
help="Do not modify image and ignore any profile or processing option")
|
||||||
|
processing_options.add_argument("--pdfextract", action="store_true", dest="pdfextract", default=False,
|
||||||
|
help="Use the legacy PDF image extraction method from KCC 8 and earlier")
|
||||||
|
processing_options.add_argument("--pdfwidth", action="store_true", dest="pdfwidth", default=False,
|
||||||
|
help="Render vector PDFs to device width instead of height.")
|
||||||
|
processing_options.add_argument("--coverfill", action="store_true", dest="coverfill", default=False,
|
||||||
|
help="Crop cover to fill screen")
|
||||||
processing_options.add_argument("-u", "--upscale", action="store_true", dest="upscale", default=False,
|
processing_options.add_argument("-u", "--upscale", action="store_true", dest="upscale", default=False,
|
||||||
help="Resize images smaller than device's resolution")
|
help="Resize images smaller than device's resolution")
|
||||||
processing_options.add_argument("-s", "--stretch", action="store_true", dest="stretch", default=False,
|
processing_options.add_argument("-s", "--stretch", action="store_true", dest="stretch", default=False,
|
||||||
@@ -1377,7 +1411,13 @@ def makeParser():
|
|||||||
output_options.add_argument("--eraserainbow", action="store_true", dest="eraserainbow", default=False,
|
output_options.add_argument("--eraserainbow", action="store_true", dest="eraserainbow", default=False,
|
||||||
help="Erase rainbow effect on color eink screen by attenuating interfering frequencies")
|
help="Erase rainbow effect on color eink screen by attenuating interfering frequencies")
|
||||||
processing_options.add_argument("--forcepng", action="store_true", dest="forcepng", default=False,
|
processing_options.add_argument("--forcepng", action="store_true", dest="forcepng", default=False,
|
||||||
help="Create PNG files instead JPEG")
|
help="Create PNG files instead JPEG for black and white images")
|
||||||
|
processing_options.add_argument("--force-png-rgb", action="store_true", dest="force_png_rgb", default=False,
|
||||||
|
help="Force color images to be saved as PNG")
|
||||||
|
processing_options.add_argument("--pnglegacy", action="store_true", dest="pnglegacy", default=False,
|
||||||
|
help="Use a more compatible 8 bit png instead of 4 bit")
|
||||||
|
processing_options.add_argument("--noquantize", action="store_true", dest="noquantize", default=False,
|
||||||
|
help="Don't quantize to 16 color PNG")
|
||||||
processing_options.add_argument("--mozjpeg", action="store_true", dest="mozjpeg", default=False,
|
processing_options.add_argument("--mozjpeg", action="store_true", dest="mozjpeg", default=False,
|
||||||
help="Create JPEG files using mozJpeg")
|
help="Create JPEG files using mozJpeg")
|
||||||
processing_options.add_argument("--jpeg-quality", type=int, dest="jpegquality",
|
processing_options.add_argument("--jpeg-quality", type=int, dest="jpegquality",
|
||||||
@@ -1404,6 +1444,11 @@ def checkOptions(options):
|
|||||||
options.isKobo = False
|
options.isKobo = False
|
||||||
options.bordersColor = None
|
options.bordersColor = None
|
||||||
options.keep_epub = False
|
options.keep_epub = False
|
||||||
|
if options.format == 'PDF-200MB':
|
||||||
|
options.targetsize = 195
|
||||||
|
options.format = 'PDF'
|
||||||
|
if options.batchsplit != 2:
|
||||||
|
options.batchsplit = 1
|
||||||
if options.format == 'EPUB-200MB':
|
if options.format == 'EPUB-200MB':
|
||||||
options.targetsize = 195
|
options.targetsize = 195
|
||||||
options.format = 'EPUB'
|
options.format = 'EPUB'
|
||||||
@@ -1415,6 +1460,8 @@ def checkOptions(options):
|
|||||||
options.format = 'MOBI'
|
options.format = 'MOBI'
|
||||||
if options.batchsplit != 2:
|
if options.batchsplit != 2:
|
||||||
options.batchsplit = 1
|
options.batchsplit = 1
|
||||||
|
if not options.targetsize and options.profile.startswith('Rmk'):
|
||||||
|
options.targetsize = 95
|
||||||
if options.format == 'MOBI+EPUB':
|
if options.format == 'MOBI+EPUB':
|
||||||
options.keep_epub = True
|
options.keep_epub = True
|
||||||
options.format = 'MOBI'
|
options.format = 'MOBI'
|
||||||
@@ -1460,9 +1507,6 @@ def checkOptions(options):
|
|||||||
if 'Ko' in options.profile:
|
if 'Ko' in options.profile:
|
||||||
options.panelview = False
|
options.panelview = False
|
||||||
options.hq = False
|
options.hq = False
|
||||||
# CBZ files on Kindle DX/DXG support higher resolution
|
|
||||||
if options.profile == 'KDX' and options.format == 'CBZ':
|
|
||||||
options.customheight = 1200
|
|
||||||
# KFX output create EPUB that might be can be by jhowell KFX Output Calibre plugin
|
# KFX output create EPUB that might be can be by jhowell KFX Output Calibre plugin
|
||||||
if options.format == 'KFX':
|
if options.format == 'KFX':
|
||||||
options.format = 'EPUB'
|
options.format = 'EPUB'
|
||||||
@@ -1488,6 +1532,13 @@ def checkOptions(options):
|
|||||||
options.jpegquality = 85
|
options.jpegquality = 85
|
||||||
options.kindle_azw3 = options.iskindle and ('MOBI' in options.format or 'EPUB' in options.format)
|
options.kindle_azw3 = options.iskindle and ('MOBI' in options.format or 'EPUB' in options.format)
|
||||||
options.kindle_scribe_azw3 = options.profile.startswith('KS') and options.kindle_azw3
|
options.kindle_scribe_azw3 = options.profile.startswith('KS') and options.kindle_azw3
|
||||||
|
|
||||||
|
# CBZ files on Kindle DX/DXG support higher resolution
|
||||||
|
if options.profile == 'KDX' and options.format == 'CBZ':
|
||||||
|
options.profileData = list(image.ProfileData.Profiles[options.profile])
|
||||||
|
options.profileData[1] = list(options.profileData[1])
|
||||||
|
options.profileData[1][1] = 1200
|
||||||
|
|
||||||
if options.kindle_scribe_azw3:
|
if options.kindle_scribe_azw3:
|
||||||
options.profileData = list(image.ProfileData.Profiles[options.profile])
|
options.profileData = list(image.ProfileData.Profiles[options.profile])
|
||||||
options.profileData[1] = list(options.profileData[1])
|
options.profileData[1] = list(options.profileData[1])
|
||||||
@@ -1539,17 +1590,26 @@ def makeFusion(sources: List[str]):
|
|||||||
fusion_path = first_path.parent.joinpath(first_path.name + ' [fused]')
|
fusion_path = first_path.parent.joinpath(first_path.name + ' [fused]')
|
||||||
print("Running Fusion")
|
print("Running Fusion")
|
||||||
|
|
||||||
for source in sources:
|
# Check if prefix is needed when user-specified ordering differs from OS natural sorting
|
||||||
|
path_names = [Path(s).stem if Path(s).is_file() else Path(s).name for s in sources]
|
||||||
|
needs_prefix = os_sorted(path_names) != path_names
|
||||||
|
|
||||||
|
for index, source in enumerate(sources, start=1):
|
||||||
print(f"Processing {source}...")
|
print(f"Processing {source}...")
|
||||||
checkPre(source)
|
checkPre(source)
|
||||||
print("Checking images...")
|
print("Checking images...")
|
||||||
source_path = Path(source)
|
source_path = Path(source)
|
||||||
|
# Add the fusion_0001_ prefix to maintain user-specified order if needed
|
||||||
|
prefix = ''
|
||||||
|
if needs_prefix:
|
||||||
|
prefix = f'fusion_{index:04d}_'
|
||||||
if source_path.is_file():
|
if source_path.is_file():
|
||||||
targetpath = fusion_path.joinpath(source_path.stem)
|
targetpath = fusion_path.joinpath(f'{prefix}{source_path.stem}')
|
||||||
else:
|
else:
|
||||||
targetpath = fusion_path.joinpath(source_path.name)
|
targetpath = fusion_path.joinpath(f'{prefix}{source_path.name}')
|
||||||
|
|
||||||
getWorkFolder(source, str(targetpath))
|
getWorkFolder(source, str(targetpath))
|
||||||
sanitizeTree(targetpath)
|
sanitizeTree(targetpath, prefix='fusion')
|
||||||
# TODO: remove flattenTree when subchapters are supported
|
# TODO: remove flattenTree when subchapters are supported
|
||||||
flattenTree(targetpath)
|
flattenTree(targetpath)
|
||||||
|
|
||||||
@@ -1576,6 +1636,9 @@ def makeBook(source, qtgui=None, job_progress=''):
|
|||||||
removeNonImages(os.path.join(path, "OEBPS", "Images"))
|
removeNonImages(os.path.join(path, "OEBPS", "Images"))
|
||||||
detectSuboptimalProcessing(os.path.join(path, "OEBPS", "Images"), source)
|
detectSuboptimalProcessing(os.path.join(path, "OEBPS", "Images"), source)
|
||||||
chapterNames, cover_path = sanitizeTree(os.path.join(path, 'OEBPS', 'Images'))
|
chapterNames, cover_path = sanitizeTree(os.path.join(path, 'OEBPS', 'Images'))
|
||||||
|
if options.filefusion:
|
||||||
|
# Strip the fusion_0001_ sort prefix from makeFusion if present
|
||||||
|
chapterNames = {k: sub(r'^fusion_\d{4}_', '', v) for k, v in chapterNames.items()}
|
||||||
cover = None
|
cover = None
|
||||||
if not options.webtoon:
|
if not options.webtoon:
|
||||||
cover = image.Cover(cover_path, options)
|
cover = image.Cover(cover_path, options)
|
||||||
@@ -1767,4 +1830,3 @@ def makeMOBI(work, qtgui=None):
|
|||||||
makeMOBIWorkerPool.close()
|
makeMOBIWorkerPool.close()
|
||||||
makeMOBIWorkerPool.join()
|
makeMOBIWorkerPool.join()
|
||||||
return makeMOBIWorkerOutput
|
return makeMOBIWorkerOutput
|
||||||
|
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ def mergeDirectory(work):
|
|||||||
imagesValid.append(i[0])
|
imagesValid.append(i[0])
|
||||||
# Silently drop directories that contain too many images
|
# Silently drop directories that contain too many images
|
||||||
# 131072 = GIMP_MAX_IMAGE_SIZE / 4
|
# 131072 = GIMP_MAX_IMAGE_SIZE / 4
|
||||||
if targetHeight > 131072 * 3:
|
if targetHeight > 131072 * 4:
|
||||||
raise RuntimeError(f'Image too tall at {targetHeight} pixels. {targetWidth} pixels wide. Try using separate chapter folders or file fusion.')
|
raise RuntimeError(f'Image too tall at {targetHeight} pixels. {targetWidth} pixels wide. Try using separate chapter folders or file fusion.')
|
||||||
result = Image.new('RGB', (targetWidth, targetHeight))
|
result = Image.new('RGB', (targetWidth, targetHeight))
|
||||||
y = 0
|
y = 0
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ from .shared import IMAGE_TYPES, subprocess_run
|
|||||||
|
|
||||||
EXTRACTION_ERROR = 'Failed to extract archive. Try extracting file outside of KCC.'
|
EXTRACTION_ERROR = 'Failed to extract archive. Try extracting file outside of KCC.'
|
||||||
SEVENZIP = '7zz' if platform.system() == 'Darwin' else '7z'
|
SEVENZIP = '7zz' if platform.system() == 'Darwin' else '7z'
|
||||||
|
TAR = 'bsdtar' if platform.system() == 'Linux' else 'tar'
|
||||||
|
|
||||||
|
|
||||||
class ComicArchive:
|
class ComicArchive:
|
||||||
@@ -73,7 +74,7 @@ class ComicArchive:
|
|||||||
missing = []
|
missing = []
|
||||||
|
|
||||||
extraction_commands = [
|
extraction_commands = [
|
||||||
['tar', '--exclude', '__MACOSX', '--exclude', '.DS_Store', '--exclude', 'thumbs.db', '--exclude', 'Thumbs.db', '-xf', self.basename, '-C', targetdir],
|
[TAR, '--exclude', '__MACOSX', '--exclude', '.DS_Store', '--exclude', 'thumbs.db', '--exclude', 'Thumbs.db', '-xf', self.basename, '-C', targetdir],
|
||||||
[SEVENZIP, 'x', '-y', '-xr!__MACOSX', '-xr!.DS_Store', '-xr!thumbs.db', '-xr!Thumbs.db', '-o' + targetdir, self.basename],
|
[SEVENZIP, 'x', '-y', '-xr!__MACOSX', '-xr!.DS_Store', '-xr!thumbs.db', '-xr!Thumbs.db', '-o' + targetdir, self.basename],
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -125,7 +126,7 @@ class ComicArchive:
|
|||||||
def available_archive_tools():
|
def available_archive_tools():
|
||||||
available = []
|
available = []
|
||||||
|
|
||||||
for tool in ['tar', SEVENZIP, 'unar', 'unrar']:
|
for tool in [TAR, SEVENZIP, 'unar', 'unrar']:
|
||||||
try:
|
try:
|
||||||
subprocess_run([tool], stdout=PIPE, stderr=STDOUT)
|
subprocess_run([tool], stdout=PIPE, stderr=STDOUT)
|
||||||
available.append(tool)
|
available.append(tool)
|
||||||
|
|||||||
@@ -101,12 +101,13 @@ class ProfileData:
|
|||||||
'KO': ("Kindle Oasis 2/3/Paperwhite 12", (1264, 1680), Palette16, 1.0),
|
'KO': ("Kindle Oasis 2/3/Paperwhite 12", (1264, 1680), Palette16, 1.0),
|
||||||
'K11': ("Kindle 11", (1072, 1448), Palette16, 1.0),
|
'K11': ("Kindle 11", (1072, 1448), Palette16, 1.0),
|
||||||
'KPW5': ("Kindle Paperwhite 5/Signature Edition", (1236, 1648), Palette16, 1.0),
|
'KPW5': ("Kindle Paperwhite 5/Signature Edition", (1236, 1648), Palette16, 1.0),
|
||||||
'KS1860': ("Kindle 1920", (1860, 1920), Palette16, 1.0),
|
'KS1860': ("Kindle 1860", (1860, 1920), Palette16, 1.0),
|
||||||
'KS1920': ("Kindle 1920", (1920, 1920), Palette16, 1.0),
|
'KS1920': ("Kindle 1920", (1920, 1920), Palette16, 1.0),
|
||||||
|
'KS1240': ("Kindle 1240", (1240, 1860), Palette16, 1.0),
|
||||||
'KS': ("Kindle Scribe 1/2", (1860, 2480), Palette16, 1.0),
|
'KS': ("Kindle Scribe 1/2", (1860, 2480), Palette16, 1.0),
|
||||||
'KCS': ("Kindle Colorsoft", (1264, 1680), Palette16, 1.0),
|
'KCS': ("Kindle Colorsoft", (1264, 1680), Palette16, 1.0),
|
||||||
'KS3': ("Kindle Scribe 3", (1980, 2640), Palette16, 1.0),
|
'KS3': ("Kindle Scribe 3", (1986, 2648), Palette16, 1.0),
|
||||||
'KSCS': ("Kindle Scribe Colorsoft", (1980, 2640), Palette16, 1.0),
|
'KSCS': ("Kindle Scribe Colorsoft", (1986, 2648), Palette16, 1.0),
|
||||||
}
|
}
|
||||||
|
|
||||||
ProfilesKindle = {
|
ProfilesKindle = {
|
||||||
@@ -157,7 +158,7 @@ class ComicPageParser:
|
|||||||
|
|
||||||
# Detect corruption in source image, let caller catch any exceptions triggered.
|
# Detect corruption in source image, let caller catch any exceptions triggered.
|
||||||
srcImgPath = os.path.join(source[0], source[1])
|
srcImgPath = os.path.join(source[0], source[1])
|
||||||
Image.open(srcImgPath).verify()
|
# Image.open(srcImgPath).verify()
|
||||||
with Image.open(srcImgPath) as im:
|
with Image.open(srcImgPath) as im:
|
||||||
self.image = im.copy()
|
self.image = im.copy()
|
||||||
|
|
||||||
@@ -196,7 +197,10 @@ class ComicPageParser:
|
|||||||
and not self.opt.webtoon and self.opt.splitter == 1:
|
and not self.opt.webtoon and self.opt.splitter == 1:
|
||||||
spread = self.image
|
spread = self.image
|
||||||
if not self.opt.norotate:
|
if not self.opt.norotate:
|
||||||
spread = spread.rotate(90, Image.Resampling.BICUBIC, True)
|
if not self.opt.rotateright:
|
||||||
|
spread = spread.rotate(90, Image.Resampling.BICUBIC, True)
|
||||||
|
else:
|
||||||
|
spread = spread.rotate(-90, Image.Resampling.BICUBIC, True)
|
||||||
self.payload.append(['R', self.source, spread, self.fill])
|
self.payload.append(['R', self.source, spread, self.fill])
|
||||||
elif (width > height) != (dstwidth > dstheight) and not self.opt.webtoon:
|
elif (width > height) != (dstwidth > dstheight) and not self.opt.webtoon:
|
||||||
if self.opt.splitter != 1:
|
if self.opt.splitter != 1:
|
||||||
@@ -217,7 +221,10 @@ class ComicPageParser:
|
|||||||
if self.opt.splitter > 0:
|
if self.opt.splitter > 0:
|
||||||
spread = self.image
|
spread = self.image
|
||||||
if not self.opt.norotate:
|
if not self.opt.norotate:
|
||||||
spread = spread.rotate(90, Image.Resampling.BICUBIC, True)
|
if not self.opt.rotateright:
|
||||||
|
spread = spread.rotate(90, Image.Resampling.BICUBIC, True)
|
||||||
|
else:
|
||||||
|
spread = spread.rotate(-90, Image.Resampling.BICUBIC, True)
|
||||||
self.payload.append(['R', self.source, spread, self.fill])
|
self.payload.append(['R', self.source, spread, self.fill])
|
||||||
else:
|
else:
|
||||||
self.payload.append(['N', self.source, self.image, self.fill])
|
self.payload.append(['N', self.source, self.image, self.fill])
|
||||||
@@ -270,6 +277,8 @@ class ComicPage:
|
|||||||
self.original_color_mode = image.mode
|
self.original_color_mode = image.mode
|
||||||
# TODO: color check earlier
|
# TODO: color check earlier
|
||||||
self.image = image.convert("RGB")
|
self.image = image.convert("RGB")
|
||||||
|
self.color = self.colorCheck()
|
||||||
|
self.colorOutput = self.color and self.opt.forcecolor
|
||||||
self.fill = fill
|
self.fill = fill
|
||||||
self.rotated = False
|
self.rotated = False
|
||||||
self.orgPath = os.path.join(path[0], path[1])
|
self.orgPath = os.path.join(path[0], path[1])
|
||||||
@@ -288,8 +297,7 @@ class ComicPage:
|
|||||||
if not hasattr(Image, 'Resampling'):
|
if not hasattr(Image, 'Resampling'):
|
||||||
Image.Resampling = Image
|
Image.Resampling = Image
|
||||||
|
|
||||||
@cached_property
|
def colorCheck(self):
|
||||||
def color(self):
|
|
||||||
if self.original_color_mode in ("L", "1"):
|
if self.original_color_mode in ("L", "1"):
|
||||||
return False
|
return False
|
||||||
if self.opt.webtoon:
|
if self.opt.webtoon:
|
||||||
@@ -398,7 +406,7 @@ class ComicPage:
|
|||||||
raise RuntimeError('Cannot save image. ' + str(err))
|
raise RuntimeError('Cannot save image. ' + str(err))
|
||||||
|
|
||||||
def save_with_codec(self, image, targetPath):
|
def save_with_codec(self, image, targetPath):
|
||||||
if self.opt.forcepng:
|
if self.opt.forcepng and (not self.colorOutput or self.opt.force_png_rgb):
|
||||||
image.info.pop('transparency', None)
|
image.info.pop('transparency', None)
|
||||||
if self.opt.iskindle and ('MOBI' in self.opt.format or 'EPUB' in self.opt.format):
|
if self.opt.iskindle and ('MOBI' in self.opt.format or 'EPUB' in self.opt.format):
|
||||||
targetPath += '.gif'
|
targetPath += '.gif'
|
||||||
@@ -500,7 +508,9 @@ class ComicPage:
|
|||||||
elif method == Image.Resampling.BICUBIC and not self.opt.upscale:
|
elif method == Image.Resampling.BICUBIC and not self.opt.upscale:
|
||||||
pass
|
pass
|
||||||
else: # if image bigger than device resolution or smaller with upscaling
|
else: # if image bigger than device resolution or smaller with upscaling
|
||||||
if abs(ratio_image - ratio_device) < AUTO_CROP_THRESHOLD:
|
if self.opt.profile == 'KDX' and abs(ratio_image - ratio_device) < AUTO_CROP_THRESHOLD * 3:
|
||||||
|
self.image = ImageOps.fit(self.image, self.size, method=method)
|
||||||
|
elif abs(ratio_image - ratio_device) < AUTO_CROP_THRESHOLD:
|
||||||
self.image = ImageOps.fit(self.image, self.size, method=method)
|
self.image = ImageOps.fit(self.image, self.size, method=method)
|
||||||
elif (self.opt.format in ('CBZ', 'PDF') or self.opt.kfx) and not self.opt.white_borders:
|
elif (self.opt.format in ('CBZ', 'PDF') or self.opt.kfx) and not self.opt.white_borders:
|
||||||
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)
|
||||||
@@ -508,7 +518,7 @@ class ComicPage:
|
|||||||
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]:
|
||||||
return Image.Resampling.BICUBIC
|
return Image.Resampling.BICUBIC
|
||||||
else:
|
else:
|
||||||
return Image.Resampling.LANCZOS
|
return Image.Resampling.LANCZOS
|
||||||
@@ -568,7 +578,11 @@ class Cover:
|
|||||||
if self.options.kindle_scribe_azw3:
|
if self.options.kindle_scribe_azw3:
|
||||||
size[0] = min(size[0], 1920)
|
size[0] = min(size[0], 1920)
|
||||||
size[1] = min(size[1], 1920)
|
size[1] = min(size[1], 1920)
|
||||||
self.image.thumbnail(tuple(size), Image.Resampling.LANCZOS)
|
if self.options.coverfill and not self.options.kindle_scribe_azw3:
|
||||||
|
# TODO: Kindle Scribe case
|
||||||
|
self.image = ImageOps.fit(self.image, tuple(size), Image.Resampling.LANCZOS, centering=(0.5, 0.5))
|
||||||
|
else:
|
||||||
|
self.image.thumbnail(tuple(size), Image.Resampling.LANCZOS)
|
||||||
|
|
||||||
def crop_main_cover(self):
|
def crop_main_cover(self):
|
||||||
w, h = self.image.size
|
w, h = self.image.size
|
||||||
|
|||||||
@@ -160,6 +160,8 @@ def ignore_pixels_near_edge(bw_img):
|
|||||||
for box in edge_bbox:
|
for box in edge_bbox:
|
||||||
edge = bw_img.crop(box)
|
edge = bw_img.crop(box)
|
||||||
h = edge.histogram()
|
h = edge.histogram()
|
||||||
|
if not edge.height or not edge.width:
|
||||||
|
continue
|
||||||
imperfections = h[255] / (edge.height * edge.width)
|
imperfections = h[255] / (edge.height * edge.width)
|
||||||
if imperfections > 0 and imperfections < .02:
|
if imperfections > 0 and imperfections < .02:
|
||||||
bw_img.paste(im=0, box=box)
|
bw_img.paste(im=0, box=box)
|
||||||
|
|||||||
75
kindlecomicconverter/pdfjpgextract.py
Normal file
75
kindlecomicconverter/pdfjpgextract.py
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||||
|
# Copyright (c) 2013-2019 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
|
#
|
||||||
|
# Based upon the code snippet by Ned Batchelder
|
||||||
|
# (http://nedbatchelder.com/blog/200712/extracting_jpgs_from_pdfs.html)
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, and/or distribute this software for
|
||||||
|
# any purpose with or without fee is hereby granted, provided that the
|
||||||
|
# above copyright notice and this permission notice appear in all
|
||||||
|
# copies.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||||
|
# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||||
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||||
|
# AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
# DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
|
||||||
|
# OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||||
|
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
# PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
#
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
# skip stray images a few pixels in size in some PDFs
|
||||||
|
# typical images are many thousands in length
|
||||||
|
# https://github.com/ciromattia/kcc/pull/546
|
||||||
|
STRAY_IMAGE_LENGTH_THRESHOLD = 300
|
||||||
|
|
||||||
|
|
||||||
|
class PdfJpgExtract:
|
||||||
|
def __init__(self, fname, fullPath):
|
||||||
|
self.fname = fname
|
||||||
|
self.path = fullPath
|
||||||
|
|
||||||
|
def getPath(self):
|
||||||
|
return self.path
|
||||||
|
|
||||||
|
def extract(self):
|
||||||
|
pdf = open(self.fname, "rb").read()
|
||||||
|
startmark = b"\xff\xd8"
|
||||||
|
startfix = 0
|
||||||
|
endmark = b"\xff\xd9"
|
||||||
|
endfix = 2
|
||||||
|
i = 0
|
||||||
|
njpg = 0
|
||||||
|
while True:
|
||||||
|
istream = pdf.find(b"stream", i)
|
||||||
|
if istream < 0:
|
||||||
|
break
|
||||||
|
istart = pdf.find(startmark, istream, istream + 20)
|
||||||
|
if istart < 0:
|
||||||
|
i = istream + 20
|
||||||
|
continue
|
||||||
|
iend = pdf.find(b"endstream", istart)
|
||||||
|
if iend < 0:
|
||||||
|
raise Exception("Didn't find end of stream!")
|
||||||
|
iend = pdf.find(endmark, iend - 20)
|
||||||
|
if iend < 0:
|
||||||
|
raise Exception("Didn't find end of JPG!")
|
||||||
|
istart += startfix
|
||||||
|
iend += endfix
|
||||||
|
i = iend
|
||||||
|
|
||||||
|
if iend - istart < STRAY_IMAGE_LENGTH_THRESHOLD:
|
||||||
|
continue
|
||||||
|
|
||||||
|
jpg = pdf[istart:iend]
|
||||||
|
jpgfile = open(os.path.join(self.path, "jpg%d.jpg" % njpg), "wb")
|
||||||
|
jpgfile.write(jpg)
|
||||||
|
jpgfile.close()
|
||||||
|
njpg += 1
|
||||||
|
|
||||||
|
return njpg
|
||||||
Reference in New Issue
Block a user