mirror of
https://github.com/ciromattia/kcc
synced 2026-04-17 14:38:47 +00:00
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dd5c907bad | ||
|
|
64fb4a9eca | ||
|
|
284c577894 | ||
|
|
c68c9892e4 | ||
|
|
aa00ea3aa2 | ||
|
|
88f005824c | ||
|
|
2a2bfae112 | ||
|
|
583eec787f | ||
|
|
9ce691aecb | ||
|
|
d1a07d7ffa | ||
|
|
b545f7ad48 | ||
|
|
9e01797d28 | ||
|
|
c68c5f25bf | ||
|
|
a04bf5262f | ||
|
|
b09b2527d9 | ||
|
|
94b372f47d | ||
|
|
b978adcc7c | ||
|
|
9dee4432ad | ||
|
|
15055c6c0c | ||
|
|
3f948a10b0 | ||
|
|
1c942d81db |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -4,7 +4,6 @@
|
|||||||
.idea
|
.idea
|
||||||
.DS_Store
|
.DS_Store
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
build
|
|
||||||
dist
|
dist
|
||||||
Output
|
Output
|
||||||
test
|
test
|
||||||
@@ -14,3 +13,4 @@ kindlegen*
|
|||||||
setup.bat
|
setup.bat
|
||||||
setup.sh
|
setup.sh
|
||||||
kcc/sentry.py
|
kcc/sentry.py
|
||||||
|
build/
|
||||||
|
|||||||
53
README.md
53
README.md
@@ -6,7 +6,7 @@ actually a comic/manga to EPUB converter that every e-reader owner can happily u
|
|||||||
It can also optionally optimize images by applying a number of transformations.
|
It can also optionally optimize images by applying a number of transformations.
|
||||||
|
|
||||||
### 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.
|
||||||
Amazon's tool is for comic publishers and involves a lot of manual effort, while **KCC** is for comic/manga readers.
|
Amazon's tool is for comic publishers and involves a lot of manual effort, while **KCC** is for comic/manga readers.
|
||||||
_KC2_ in no way is a replacement for **KCC** so you can be quite confident we'll going to carry on developing our little monster ;-)
|
_KC2_ in no way is a replacement for **KCC** so you can be quite confident we'll going to carry on developing our little monster ;-)
|
||||||
|
|
||||||
@@ -75,9 +75,11 @@ Usage: kcc-c2e [options] comic_file|comic_folder
|
|||||||
Options:
|
Options:
|
||||||
MAIN:
|
MAIN:
|
||||||
-p PROFILE, --profile=PROFILE
|
-p PROFILE, --profile=PROFILE
|
||||||
Device profile (Available options: K1, K2, K3, K45, KDX,
|
Device profile (Available options: K1, K2, K3, K45,
|
||||||
KPW, KV, KoMT, KoG, KoGHD, KoA, KoAHD, KoAH2O) [Default=KV]
|
KDX, KPW, KV, KoMT, KoG, KoGHD, KoA, KoAHD, KoAH2O,
|
||||||
|
KoAO) [Default=KV]
|
||||||
-m, --manga-style Manga style (right-to-left reading and splitting)
|
-m, --manga-style Manga style (right-to-left reading and splitting)
|
||||||
|
-2, --two-panel Display two not four panels in Panel View mode
|
||||||
-w, --webtoon Webtoon processing mode
|
-w, --webtoon Webtoon processing mode
|
||||||
|
|
||||||
OUTPUT SETTINGS:
|
OUTPUT SETTINGS:
|
||||||
@@ -86,29 +88,28 @@ Options:
|
|||||||
-t TITLE, --title=TITLE
|
-t TITLE, --title=TITLE
|
||||||
Comic title [Default=filename or directory name]
|
Comic title [Default=filename or directory name]
|
||||||
-f FORMAT, --format=FORMAT
|
-f FORMAT, --format=FORMAT
|
||||||
Output format (Available options: Auto, MOBI, EPUB, CBZ)
|
Output format (Available options: Auto, MOBI, EPUB,
|
||||||
[Default=Auto]
|
CBZ) [Default=Auto]
|
||||||
-b, --batchsplit Split output into multiple files
|
-b, --batchsplit Split output into multiple files
|
||||||
|
|
||||||
PROCESSING:
|
PROCESSING:
|
||||||
-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
|
||||||
Double page parsing mode. 0: Split 1: Rotate 2: Both [Default=0]
|
Double page parsing mode. 0: Split 1: Rotate 2: Both
|
||||||
|
[Default=0]
|
||||||
-g GAMMA, --gamma=GAMMA
|
-g GAMMA, --gamma=GAMMA
|
||||||
Apply gamma correction to linearize the image [Default=Auto]
|
Apply gamma correction to linearize the image
|
||||||
--hq Enable high quality Panel View
|
[Default=Auto]
|
||||||
|
-c CROPPING, --cropping=CROPPING
|
||||||
|
Set cropping mode. 0: Disabled 1: Margins 2: Margins +
|
||||||
|
page numbers [Default=2]
|
||||||
|
--cp=CROPPINGP, --croppingpower=CROPPINGP
|
||||||
|
Set cropping power [Default=1.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
|
||||||
--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
|
||||||
--cropping=CROPPING
|
|
||||||
Set cropping mode. 0: Disabled 1: Margins 2: Margins +
|
|
||||||
page numbers [Default=2]
|
|
||||||
--croppingpower=CROPPINGP
|
|
||||||
Set margin cropping threshold [Default=0.1]
|
|
||||||
--croppingpowerpage=CROPPINGPN
|
|
||||||
Set page number cropping threshold [Default=5.0]
|
|
||||||
|
|
||||||
CUSTOM PROFILE:
|
CUSTOM PROFILE:
|
||||||
--customwidth=CUSTOMWIDTH
|
--customwidth=CUSTOMWIDTH
|
||||||
@@ -153,16 +154,28 @@ The app relies and includes the following scripts:
|
|||||||
* [Kindle Paperwhite 3 / Voyage / Oasis](http://kcc.iosphe.re/Samples/Ubunchu!-KV.mobi)
|
* [Kindle Paperwhite 3 / Voyage / Oasis](http://kcc.iosphe.re/Samples/Ubunchu!-KV.mobi)
|
||||||
* [Kindle Paperwhite 1 / 2](http://kcc.iosphe.re/Samples/Ubunchu!-KPW.mobi)
|
* [Kindle Paperwhite 1 / 2](http://kcc.iosphe.re/Samples/Ubunchu!-KPW.mobi)
|
||||||
* [Kindle](http://kcc.iosphe.re/Samples/Ubunchu!-K45.mobi)
|
* [Kindle](http://kcc.iosphe.re/Samples/Ubunchu!-K45.mobi)
|
||||||
* [Kindle Keyboard](http://kcc.iosphe.re/Samples/Ubunchu!-K3.mobi)
|
|
||||||
* [Kindle DX/DXG](http://kcc.iosphe.re/Samples/Ubunchu!-KDX.cbz)
|
|
||||||
* [Kobo Mini/Touch](http://kcc.iosphe.re/Samples/Ubunchu-KoMT.kepub.epub)
|
|
||||||
* [Kobo Glo](http://kcc.iosphe.re/Samples/Ubunchu-KoG.kepub.epub)
|
|
||||||
* [Kobo Glo HD](http://kcc.iosphe.re/Samples/Ubunchu-KoGHD.kepub.epub)
|
|
||||||
* [Kobo Aura](http://kcc.iosphe.re/Samples/Ubunchu-KoA.kepub.epub)
|
* [Kobo Aura](http://kcc.iosphe.re/Samples/Ubunchu-KoA.kepub.epub)
|
||||||
* [Kobo Aura HD](http://kcc.iosphe.re/Samples/Ubunchu-KoAHD.kepub.epub)
|
* [Kobo Aura HD](http://kcc.iosphe.re/Samples/Ubunchu-KoAHD.kepub.epub)
|
||||||
* [Kobo Aura H2O](http://kcc.iosphe.re/Samples/Ubunchu-KoAH2O.kepub.epub)
|
* [Kobo Aura H2O](http://kcc.iosphe.re/Samples/Ubunchu-KoAH2O.kepub.epub)
|
||||||
|
* [Kobo Aura ONE](http://kcc.iosphe.re/Samples/Ubunchu-KoAO.kepub.epub)
|
||||||
|
|
||||||
## CHANGELOG
|
## CHANGELOG
|
||||||
|
####5.2:
|
||||||
|
* Added new Panel View options
|
||||||
|
* Implemented new margin detection algorithm
|
||||||
|
* Removed HQ Panel View mode
|
||||||
|
* Fixed multiple smaller issues
|
||||||
|
|
||||||
|
####5.1.3:
|
||||||
|
* Added Kobo Aura ONE profile
|
||||||
|
* Fixed few small bugs
|
||||||
|
|
||||||
|
####5.1.2:
|
||||||
|
* Fixed error reporting
|
||||||
|
|
||||||
|
####5.1.1:
|
||||||
|
* Fixed multiple GUI bugs
|
||||||
|
|
||||||
####5.1:
|
####5.1:
|
||||||
* GUI now can be resized and high DPI support was somewhat improved
|
* GUI now can be resized and high DPI support was somewhat improved
|
||||||
* Added profile for Kindle Oasis
|
* Added profile for Kindle Oasis
|
||||||
|
|||||||
18
docker/Build
Executable file
18
docker/Build
Executable file
@@ -0,0 +1,18 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
pip3 install --upgrade pip setuptools wheel
|
||||||
|
pip3 install pillow python-slugify psutil pyinstaller==3.1.1 raven pyqt5 certifi
|
||||||
|
gem install fpm
|
||||||
|
|
||||||
|
cd /app
|
||||||
|
pyinstaller -F -s kcc.py
|
||||||
|
mkdir -p dist/usr/bin dist/usr/share/applications dist/usr/share/doc/kindlecomicconverter dist/usr/share/kindlecomicconverter dist/usr/share/lintian/overrides
|
||||||
|
mv dist/kcc dist/usr/bin
|
||||||
|
cp icons/comic2ebook.png dist/usr/share/kindlecomicconverter
|
||||||
|
cp LICENSE.txt dist/usr/share/doc/kindlecomicconverter/copyright
|
||||||
|
cp other/linux/kindlecomicconverter.desktop dist/usr/share/applications
|
||||||
|
cp other/linux/kindlecomicconverter dist/usr/share/lintian/overrides
|
||||||
|
|
||||||
|
cd /app/dist
|
||||||
|
fpm -f -s dir -t deb -n kindlecomicconverter -v $KCCVER -m "Paweł Jastrzębski <pawelj@iosphe.re>" --license "ISC" --description "$(printf "Comic and Manga converter for e-book readers.\nThis app allows you to transform your PNG, JPG, GIF, CBZ, CBR and CB7 files\ninto EPUB or MOBI format e-books.")" --url "https://kcc.iosphe.re/" --deb-priority "optional" --vendor "" --category "graphics" -d "unrar | unrar-free" -d "p7zip-full" -d "libc6" usr
|
||||||
18
docker/Dockerfile
Normal file
18
docker/Dockerfile
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# acidweb/kcc
|
||||||
|
FROM debian:jessie
|
||||||
|
MAINTAINER Paweł Jastrzębski <pawelj@iosphe.re>
|
||||||
|
|
||||||
|
ADD ./Build /Build
|
||||||
|
|
||||||
|
RUN printf "deb http://httpredir.debian.org/debian stretch main" > /etc/apt/sources.list.d/stretch.list
|
||||||
|
RUN printf "Package: *\nPin: release a=testing\nPin-Priority: 400\n" > /etc/apt/preferences.d/stretch.pref
|
||||||
|
RUN printf "deb http://httpredir.debian.org/debian sid main" > /etc/apt/sources.list.d/sid.list
|
||||||
|
RUN printf "Package: *\nPin: release a=testing\nPin-Priority: 300\n" > /etc/apt/preferences.d/sid.pref
|
||||||
|
RUN apt-get update && apt-get -y dist-upgrade
|
||||||
|
RUN apt-get -y install build-essential curl ruby ruby-dev libpng-dev libjpeg-dev
|
||||||
|
RUN apt-get -y -t testing install python3 python3-dev
|
||||||
|
RUN apt-get -y -t unstable install python3-pyqt5
|
||||||
|
RUN curl https://bootstrap.pypa.io/get-pip.py | python3
|
||||||
|
RUN apt-get clean -y && apt-get autoclean -y && apt-get autoremove -y && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||||
|
|
||||||
|
CMD /Build
|
||||||
304
gui/KCC.ui
304
gui/KCC.ui
@@ -7,7 +7,7 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>450</width>
|
<width>450</width>
|
||||||
<height>450</height>
|
<height>400</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
@@ -22,64 +22,7 @@
|
|||||||
<property name="bottomMargin">
|
<property name="bottomMargin">
|
||||||
<number>5</number>
|
<number>5</number>
|
||||||
</property>
|
</property>
|
||||||
<item row="3" column="0">
|
<item row="1" column="0" colspan="2">
|
||||||
<widget class="QPushButton" name="directoryButton">
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>130</width>
|
|
||||||
<height>30</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
|
||||||
<string><html><head/><body><p style='white-space:pre'>Add directory containing JPG, PNG or GIF files to queue.<br/><span style=" font-weight:600;">CBR, CBZ and CB7 files inside will not be processed!</span></p></body></html></string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Add directory</string>
|
|
||||||
</property>
|
|
||||||
<property name="icon">
|
|
||||||
<iconset resource="KCC.qrc">
|
|
||||||
<normaloff>:/Other/icons/folder_new.png</normaloff>:/Other/icons/folder_new.png</iconset>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="1">
|
|
||||||
<widget class="QPushButton" name="clearButton">
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>0</width>
|
|
||||||
<height>30</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Clear list</string>
|
|
||||||
</property>
|
|
||||||
<property name="icon">
|
|
||||||
<iconset resource="KCC.qrc">
|
|
||||||
<normaloff>:/Other/icons/clear.png</normaloff>:/Other/icons/clear.png</iconset>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="2">
|
|
||||||
<widget class="QPushButton" name="fileButton">
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>130</width>
|
|
||||||
<height>30</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
|
||||||
<string><html><head/><body><p style='white-space:pre'>Add CBR, CBZ, CB7 or PDF file to queue.</p></body></html></string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Add file</string>
|
|
||||||
</property>
|
|
||||||
<property name="icon">
|
|
||||||
<iconset resource="KCC.qrc">
|
|
||||||
<normaloff>:/Other/icons/document_new.png</normaloff>:/Other/icons/document_new.png</iconset>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0" colspan="3">
|
|
||||||
<widget class="QProgressBar" name="progressBar">
|
<widget class="QProgressBar" name="progressBar">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
@@ -101,59 +44,7 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="0">
|
<item row="2" column="0" colspan="2">
|
||||||
<widget class="QComboBox" name="deviceBox">
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>0</width>
|
|
||||||
<height>28</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
|
||||||
<string><html><head/><body><p style='white-space:pre'>Target device.</p></body></html></string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="4" column="1">
|
|
||||||
<widget class="QPushButton" name="convertButton">
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>0</width>
|
|
||||||
<height>30</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="font">
|
|
||||||
<font>
|
|
||||||
<weight>75</weight>
|
|
||||||
<bold>true</bold>
|
|
||||||
</font>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
|
||||||
<string><html><head/><body><p style='white-space:pre'>Shift+Click to select the output directory.</p></body></html></string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Convert</string>
|
|
||||||
</property>
|
|
||||||
<property name="icon">
|
|
||||||
<iconset resource="KCC.qrc">
|
|
||||||
<normaloff>:/Other/icons/convert.png</normaloff>:/Other/icons/convert.png</iconset>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="4" column="2">
|
|
||||||
<widget class="QComboBox" name="formatBox">
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>0</width>
|
|
||||||
<height>28</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
|
||||||
<string><html><head/><body><p style='white-space:pre'>Output format.</p></body></html></string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="0" colspan="3">
|
|
||||||
<widget class="QListWidget" name="jobList">
|
<widget class="QListWidget" name="jobList">
|
||||||
<property name="styleSheet">
|
<property name="styleSheet">
|
||||||
<string notr="true">QListWidget#jobList {background:#ffffff;background-image:url(:/Other/icons/list_background.png);background-position:center center;background-repeat:no-repeat;}</string>
|
<string notr="true">QListWidget#jobList {background:#ffffff;background-image:url(:/Other/icons/list_background.png);background-position:center center;background-repeat:no-repeat;}</string>
|
||||||
@@ -169,7 +60,7 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="7" column="0" colspan="3">
|
<item row="6" column="0" colspan="2">
|
||||||
<widget class="QWidget" name="customWidget" native="true">
|
<widget class="QWidget" name="customWidget" native="true">
|
||||||
<property name="visible">
|
<property name="visible">
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
@@ -242,7 +133,7 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="5" column="0" colspan="3">
|
<item row="4" column="0" colspan="2">
|
||||||
<widget class="QWidget" name="optionWidget" native="true">
|
<widget class="QWidget" name="optionWidget" native="true">
|
||||||
<layout class="QGridLayout" name="gridLayout_2">
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
<property name="leftMargin">
|
<property name="leftMargin">
|
||||||
@@ -275,15 +166,18 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Spread splitter</string>
|
<string>Spread splitter</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="tristate">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="2">
|
<item row="0" column="2">
|
||||||
<widget class="QCheckBox" name="qualityBox">
|
<widget class="QCheckBox" name="qualityBox">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p style='white-space:pre'>High quality Panel View.<br/>Require source files with bigger resolution than target device.<br/><span style=" font-weight:600;">Highly impact size of output file!</span></p></body></html></string>
|
<string><html><head/><body><p style=\'white-space:pre\'><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - 4 panels<br/></span>Zoom each corner separately.</p><p style=\'white-space:pre\'><span style=\" font-weight:600; text-decoration: underline;\">Checked - 2 panels<br/></span>Zoom only the top and bottom of the page.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>HQ zoom</string>
|
<string>Panel View 4/2</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@@ -305,6 +199,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Stretch/Upscale</string>
|
<string>Stretch/Upscale</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="tristate">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="2">
|
<item row="1" column="2">
|
||||||
@@ -325,6 +222,9 @@
|
|||||||
<property name="text">
|
<property name="text">
|
||||||
<string>W/B margins</string>
|
<string>W/B margins</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="tristate">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="1">
|
<item row="2" column="1">
|
||||||
@@ -350,7 +250,7 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="6" column="0" colspan="3">
|
<item row="5" column="0" colspan="2">
|
||||||
<widget class="QWidget" name="gammaWidget" native="true">
|
<widget class="QWidget" name="gammaWidget" native="true">
|
||||||
<property name="visible">
|
<property name="visible">
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
@@ -391,7 +291,7 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="0" colspan="3">
|
<item row="0" column="0" colspan="2">
|
||||||
<widget class="QWidget" name="toolWidget" native="true">
|
<widget class="QWidget" name="toolWidget" native="true">
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
<property name="leftMargin">
|
<property name="leftMargin">
|
||||||
@@ -443,6 +343,151 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="3" column="0" colspan="2">
|
||||||
|
<widget class="QWidget" name="buttonWidget" native="true">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_4">
|
||||||
|
<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 row="0" column="0">
|
||||||
|
<widget class="QPushButton" name="directoryButton">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>30</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p style='white-space:pre'>Add directory containing JPG, PNG or GIF files to queue.<br/><span style=" font-weight:600;">CBR, CBZ and CB7 files inside will not be processed!</span></p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Add directory</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="KCC.qrc">
|
||||||
|
<normaloff>:/Other/icons/folder_new.png</normaloff>:/Other/icons/folder_new.png</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="3">
|
||||||
|
<widget class="QPushButton" name="fileButton">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>30</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p style='white-space:pre'>Add CBR, CBZ, CB7 or PDF file to queue.</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Add file</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="KCC.qrc">
|
||||||
|
<normaloff>:/Other/icons/document_new.png</normaloff>:/Other/icons/document_new.png</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QComboBox" name="deviceBox">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>28</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p style='white-space:pre'>Target device.</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="sizeAdjustPolicy">
|
||||||
|
<enum>QComboBox::AdjustToMinimumContentsLength</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="3">
|
||||||
|
<widget class="QComboBox" name="formatBox">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>28</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p style='white-space:pre'>Output format.</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="sizeAdjustPolicy">
|
||||||
|
<enum>QComboBox::AdjustToMinimumContentsLength</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="2">
|
||||||
|
<widget class="QPushButton" name="convertButton">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>30</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p style='white-space:pre'>Shift+Click to select the output directory.</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Convert</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="KCC.qrc">
|
||||||
|
<normaloff>:/Other/icons/convert.png</normaloff>:/Other/icons/convert.png</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2">
|
||||||
|
<widget class="QPushButton" name="clearButton">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>30</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Clear list</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="KCC.qrc">
|
||||||
|
<normaloff>:/Other/icons/clear.png</normaloff>:/Other/icons/clear.png</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
<zorder>directoryButton</zorder>
|
||||||
|
<zorder>clearButton</zorder>
|
||||||
|
<zorder>fileButton</zorder>
|
||||||
|
<zorder>deviceBox</zorder>
|
||||||
|
<zorder>convertButton</zorder>
|
||||||
|
<zorder>formatBox</zorder>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QStatusBar" name="statusBar">
|
<widget class="QStatusBar" name="statusBar">
|
||||||
@@ -451,6 +496,29 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
|
<tabstops>
|
||||||
|
<tabstop>convertButton</tabstop>
|
||||||
|
<tabstop>clearButton</tabstop>
|
||||||
|
<tabstop>directoryButton</tabstop>
|
||||||
|
<tabstop>fileButton</tabstop>
|
||||||
|
<tabstop>deviceBox</tabstop>
|
||||||
|
<tabstop>formatBox</tabstop>
|
||||||
|
<tabstop>mangaBox</tabstop>
|
||||||
|
<tabstop>rotateBox</tabstop>
|
||||||
|
<tabstop>qualityBox</tabstop>
|
||||||
|
<tabstop>webtoonBox</tabstop>
|
||||||
|
<tabstop>upscaleBox</tabstop>
|
||||||
|
<tabstop>gammaBox</tabstop>
|
||||||
|
<tabstop>borderBox</tabstop>
|
||||||
|
<tabstop>noDitheringBox</tabstop>
|
||||||
|
<tabstop>colorBox</tabstop>
|
||||||
|
<tabstop>editorButton</tabstop>
|
||||||
|
<tabstop>wikiButton</tabstop>
|
||||||
|
<tabstop>jobList</tabstop>
|
||||||
|
<tabstop>gammaSlider</tabstop>
|
||||||
|
<tabstop>widthBox</tabstop>
|
||||||
|
<tabstop>heightBox</tabstop>
|
||||||
|
</tabstops>
|
||||||
<resources>
|
<resources>
|
||||||
<include location="KCC.qrc"/>
|
<include location="KCC.qrc"/>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
2
kcc.iss
2
kcc.iss
@@ -1,5 +1,5 @@
|
|||||||
#define MyAppName "Kindle Comic Converter"
|
#define MyAppName "Kindle Comic Converter"
|
||||||
#define MyAppVersion "5.1"
|
#define MyAppVersion "5.2"
|
||||||
#define MyAppPublisher "Ciro Mattia Gonano, Paweł Jastrzębski"
|
#define MyAppPublisher "Ciro Mattia Gonano, Paweł Jastrzębski"
|
||||||
#define MyAppURL "http://kcc.iosphe.re/"
|
#define MyAppURL "http://kcc.iosphe.re/"
|
||||||
#define MyAppExeName "KCC.exe"
|
#define MyAppExeName "KCC.exe"
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ from distutils.version import StrictVersion
|
|||||||
from xml.sax.saxutils import escape
|
from xml.sax.saxutils import escape
|
||||||
from platform import platform
|
from platform import platform
|
||||||
from raven import Client
|
from raven import Client
|
||||||
from .shared import md5Checksum, HTMLStripper, sanitizeTrace
|
from .shared import md5Checksum, HTMLStripper, sanitizeTrace, saferRemove
|
||||||
from . import __version__
|
from . import __version__
|
||||||
from . import comic2ebook
|
from . import comic2ebook
|
||||||
from . import metadata
|
from . import metadata
|
||||||
@@ -257,7 +257,7 @@ class WorkerThread(QtCore.QThread):
|
|||||||
elif GUI.rotateBox.checkState() == 2:
|
elif GUI.rotateBox.checkState() == 2:
|
||||||
options.splitter = 1
|
options.splitter = 1
|
||||||
if GUI.qualityBox.isChecked():
|
if GUI.qualityBox.isChecked():
|
||||||
options.hqmode = True
|
options.autoscale = True
|
||||||
if GUI.webtoonBox.isChecked():
|
if GUI.webtoonBox.isChecked():
|
||||||
options.webtoon = True
|
options.webtoon = True
|
||||||
if GUI.upscaleBox.checkState() == 1:
|
if GUI.upscaleBox.checkState() == 1:
|
||||||
@@ -328,9 +328,10 @@ class WorkerThread(QtCore.QThread):
|
|||||||
'for more details.', 'error', False)
|
'for more details.', 'error', False)
|
||||||
MW.addTrayMessage.emit('Error during conversion!', 'Critical')
|
MW.addTrayMessage.emit('Error during conversion!', 'Critical')
|
||||||
if not self.conversionAlive:
|
if not self.conversionAlive:
|
||||||
for item in outputPath:
|
if 'outputPath' in locals():
|
||||||
if os.path.exists(item):
|
for item in outputPath:
|
||||||
os.remove(item)
|
if os.path.exists(item):
|
||||||
|
saferRemove(item)
|
||||||
self.clean()
|
self.clean()
|
||||||
return
|
return
|
||||||
if not self.errors:
|
if not self.errors:
|
||||||
@@ -357,9 +358,9 @@ class WorkerThread(QtCore.QThread):
|
|||||||
if not self.conversionAlive:
|
if not self.conversionAlive:
|
||||||
for item in outputPath:
|
for item in outputPath:
|
||||||
if os.path.exists(item):
|
if os.path.exists(item):
|
||||||
os.remove(item)
|
saferRemove(item)
|
||||||
if os.path.exists(item.replace('.epub', '.mobi')):
|
if os.path.exists(item.replace('.epub', '.mobi')):
|
||||||
os.remove(item.replace('.epub', '.mobi'))
|
saferRemove(item.replace('.epub', '.mobi'))
|
||||||
self.clean()
|
self.clean()
|
||||||
return
|
return
|
||||||
if self.kindlegenErrorCode[0] == 0:
|
if self.kindlegenErrorCode[0] == 0:
|
||||||
@@ -380,7 +381,7 @@ class WorkerThread(QtCore.QThread):
|
|||||||
for item in outputPath:
|
for item in outputPath:
|
||||||
GUI.progress.content = ''
|
GUI.progress.content = ''
|
||||||
mobiPath = item.replace('.epub', '.mobi')
|
mobiPath = item.replace('.epub', '.mobi')
|
||||||
os.remove(mobiPath + '_toclean')
|
saferRemove(mobiPath + '_toclean')
|
||||||
if GUI.targetDirectory and GUI.targetDirectory != os.path.dirname(mobiPath):
|
if GUI.targetDirectory and GUI.targetDirectory != os.path.dirname(mobiPath):
|
||||||
try:
|
try:
|
||||||
move(mobiPath, GUI.targetDirectory)
|
move(mobiPath, GUI.targetDirectory)
|
||||||
@@ -392,15 +393,15 @@ class WorkerThread(QtCore.QThread):
|
|||||||
for item in outputPath:
|
for item in outputPath:
|
||||||
comic2ebook.options.covers[outputPath.index(item)][0].saveToKindle(
|
comic2ebook.options.covers[outputPath.index(item)][0].saveToKindle(
|
||||||
k, comic2ebook.options.covers[outputPath.index(item)][1])
|
k, comic2ebook.options.covers[outputPath.index(item)][1])
|
||||||
MW.addMessage.emit('Kindle detected. Uploading covers...', 'info', False)
|
MW.addMessage.emit('Kindle detected. Uploading covers... <b>Done!</b>', 'info', False)
|
||||||
else:
|
else:
|
||||||
GUI.progress.content = ''
|
GUI.progress.content = ''
|
||||||
for item in outputPath:
|
for item in outputPath:
|
||||||
mobiPath = item.replace('.epub', '.mobi')
|
mobiPath = item.replace('.epub', '.mobi')
|
||||||
if os.path.exists(mobiPath):
|
if os.path.exists(mobiPath):
|
||||||
os.remove(mobiPath)
|
saferRemove(mobiPath)
|
||||||
if os.path.exists(mobiPath + '_toclean'):
|
if os.path.exists(mobiPath + '_toclean'):
|
||||||
os.remove(mobiPath + '_toclean')
|
saferRemove(mobiPath + '_toclean')
|
||||||
MW.addMessage.emit('Failed to process MOBI file!', 'error', False)
|
MW.addMessage.emit('Failed to process MOBI file!', 'error', False)
|
||||||
MW.addTrayMessage.emit('Failed to process MOBI file!', 'Critical')
|
MW.addTrayMessage.emit('Failed to process MOBI file!', 'Critical')
|
||||||
else:
|
else:
|
||||||
@@ -408,9 +409,9 @@ class WorkerThread(QtCore.QThread):
|
|||||||
epubSize = (os.path.getsize(self.kindlegenErrorCode[2])) // 1024 // 1024
|
epubSize = (os.path.getsize(self.kindlegenErrorCode[2])) // 1024 // 1024
|
||||||
for item in outputPath:
|
for item in outputPath:
|
||||||
if os.path.exists(item):
|
if os.path.exists(item):
|
||||||
os.remove(item)
|
saferRemove(item)
|
||||||
if os.path.exists(item.replace('.epub', '.mobi')):
|
if os.path.exists(item.replace('.epub', '.mobi')):
|
||||||
os.remove(item.replace('.epub', '.mobi'))
|
saferRemove(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.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] != '':
|
||||||
@@ -602,7 +603,9 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
GUI.upscaleBox.setEnabled(False)
|
GUI.upscaleBox.setEnabled(False)
|
||||||
GUI.upscaleBox.setChecked(True)
|
GUI.upscaleBox.setChecked(True)
|
||||||
else:
|
else:
|
||||||
GUI.qualityBox.setEnabled(True)
|
profile = GUI.profiles[str(GUI.deviceBox.currentText())]
|
||||||
|
if profile['PVOptions']:
|
||||||
|
GUI.qualityBox.setEnabled(True)
|
||||||
GUI.mangaBox.setEnabled(True)
|
GUI.mangaBox.setEnabled(True)
|
||||||
GUI.rotateBox.setEnabled(True)
|
GUI.rotateBox.setEnabled(True)
|
||||||
GUI.upscaleBox.setEnabled(True)
|
GUI.upscaleBox.setEnabled(True)
|
||||||
@@ -628,9 +631,9 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
self.changeFormat()
|
self.changeFormat()
|
||||||
GUI.gammaSlider.setValue(0)
|
GUI.gammaSlider.setValue(0)
|
||||||
self.changeGamma(0)
|
self.changeGamma(0)
|
||||||
GUI.qualityBox.setEnabled(profile['Quality'])
|
GUI.qualityBox.setEnabled(profile['PVOptions'])
|
||||||
GUI.upscaleBox.setChecked(profile['DefaultUpscale'])
|
GUI.upscaleBox.setChecked(profile['DefaultUpscale'])
|
||||||
if not profile['Quality']:
|
if not profile['PVOptions']:
|
||||||
GUI.qualityBox.setChecked(False)
|
GUI.qualityBox.setChecked(False)
|
||||||
if str(GUI.deviceBox.currentText()) == 'Other':
|
if str(GUI.deviceBox.currentText()) == 'Other':
|
||||||
self.addMessage('<a href="https://github.com/ciromattia/kcc/wiki/NonKindle-devices">'
|
self.addMessage('<a href="https://github.com/ciromattia/kcc/wiki/NonKindle-devices">'
|
||||||
@@ -642,7 +645,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
GUI.formatBox.setCurrentIndex(outputFormat)
|
GUI.formatBox.setCurrentIndex(outputFormat)
|
||||||
else:
|
else:
|
||||||
GUI.formatBox.setCurrentIndex(profile['DefaultFormat'])
|
GUI.formatBox.setCurrentIndex(profile['DefaultFormat'])
|
||||||
GUI.qualityBox.setEnabled(profile['Quality'])
|
GUI.qualityBox.setEnabled(profile['PVOptions'])
|
||||||
|
|
||||||
def stripTags(self, html):
|
def stripTags(self, html):
|
||||||
s = HTMLStripper()
|
s = HTMLStripper()
|
||||||
@@ -883,47 +886,49 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
if self.windowSize == '0x0':
|
if self.windowSize == '0x0':
|
||||||
MW.resize(500, 500)
|
MW.resize(500, 500)
|
||||||
elif sys.platform.startswith('darwin'):
|
elif sys.platform.startswith('darwin'):
|
||||||
GUI.deviceBox.setMinimumSize(QtCore.QSize(0, 0))
|
for element in ['editorButton', 'wikiButton', 'directoryButton', 'clearButton', 'fileButton', 'deviceBox',
|
||||||
GUI.formatBox.setMinimumSize(QtCore.QSize(0, 0))
|
'convertButton', 'formatBox']:
|
||||||
GUI.directoryButton.setMinimumSize(QtCore.QSize(190, 0))
|
eval('GUI.' + element).setMinimumSize(QtCore.QSize(0, 0))
|
||||||
GUI.fileButton.setMinimumSize(QtCore.QSize(190, 0))
|
|
||||||
GUI.gridLayout.setContentsMargins(-1, -1, -1, -1)
|
GUI.gridLayout.setContentsMargins(-1, -1, -1, -1)
|
||||||
GUI.toolWidget.setMinimumSize(QtCore.QSize(0, 0))
|
for element in ['gridLayout_2', 'gridLayout_3', 'gridLayout_4', 'horizontalLayout', 'horizontalLayout_2']:
|
||||||
|
eval('GUI.' + element).setContentsMargins(-1, 0, -1, 0)
|
||||||
if self.windowSize == '0x0':
|
if self.windowSize == '0x0':
|
||||||
MW.resize(500, 500)
|
MW.resize(500, 500)
|
||||||
|
|
||||||
self.profiles = {
|
self.profiles = {
|
||||||
"Kindle Oasis": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle Oasis": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': True, 'Label': 'KV'},
|
'DefaultUpscale': True, 'Label': 'KV'},
|
||||||
"Kindle Voyage": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle Voyage": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': True, 'Label': 'KV'},
|
'DefaultUpscale': True, 'Label': 'KV'},
|
||||||
"Kindle PW 3": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle PW 3": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': True, 'Label': 'KV'},
|
'DefaultUpscale': True, 'Label': 'KV'},
|
||||||
"Kindle PW 1/2": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle PW 1/2": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': False, 'Label': 'KPW'},
|
'DefaultUpscale': False, 'Label': 'KPW'},
|
||||||
"Kindle": {'Quality': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle": {'PVOptions': True, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': False, 'Label': 'K45'},
|
'DefaultUpscale': False, 'Label': 'K45'},
|
||||||
"Kindle DX/DXG": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 2,
|
"Kindle DX/DXG": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 2,
|
||||||
'DefaultUpscale': False, 'Label': 'KDX'},
|
'DefaultUpscale': False, 'Label': 'KDX'},
|
||||||
"Kobo Mini/Touch": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
"Kobo Mini/Touch": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
||||||
'DefaultUpscale': False, 'Label': 'KoMT'},
|
'DefaultUpscale': False, 'Label': 'KoMT'},
|
||||||
"Kobo Glo": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
"Kobo Glo": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
||||||
'DefaultUpscale': False, 'Label': 'KoG'},
|
'DefaultUpscale': False, 'Label': 'KoG'},
|
||||||
"Kobo Glo HD": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
"Kobo Glo HD": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
||||||
'DefaultUpscale': False, 'Label': 'KoGHD'},
|
'DefaultUpscale': False, 'Label': 'KoGHD'},
|
||||||
"Kobo Aura": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
"Kobo Aura": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
||||||
'DefaultUpscale': False, 'Label': 'KoA'},
|
'DefaultUpscale': False, 'Label': 'KoA'},
|
||||||
"Kobo Aura HD": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
"Kobo Aura HD": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
||||||
'DefaultUpscale': True, 'Label': 'KoAHD'},
|
'DefaultUpscale': True, 'Label': 'KoAHD'},
|
||||||
"Kobo Aura H2O": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
"Kobo Aura H2O": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
||||||
'DefaultUpscale': True, 'Label': 'KoAH2O'},
|
'DefaultUpscale': True, 'Label': 'KoAH2O'},
|
||||||
"Other": {'Quality': False, 'ForceExpert': True, 'DefaultFormat': 1,
|
"Kobo Aura ONE": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 1,
|
||||||
|
'DefaultUpscale': True, 'Label': 'KoAO'},
|
||||||
|
"Other": {'PVOptions': False, 'ForceExpert': True, 'DefaultFormat': 1,
|
||||||
'DefaultUpscale': False, 'Label': 'OTHER'},
|
'DefaultUpscale': False, 'Label': 'OTHER'},
|
||||||
"Kindle 1": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle 1": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': False, 'Label': 'K1'},
|
'DefaultUpscale': False, 'Label': 'K1'},
|
||||||
"Kindle 2": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle 2": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': False, 'Label': 'K2'},
|
'DefaultUpscale': False, 'Label': 'K2'},
|
||||||
"Kindle 3": {'Quality': False, 'ForceExpert': False, 'DefaultFormat': 0,
|
"Kindle 3": {'PVOptions': False, 'ForceExpert': False, 'DefaultFormat': 0,
|
||||||
'DefaultUpscale': False, 'Label': 'K3'},
|
'DefaultUpscale': False, 'Label': 'K3'},
|
||||||
}
|
}
|
||||||
profilesGUI = [
|
profilesGUI = [
|
||||||
@@ -933,6 +938,7 @@ class KCCGUI(KCC_ui.Ui_mainWindow):
|
|||||||
"Kindle PW 1/2",
|
"Kindle PW 1/2",
|
||||||
"Kindle",
|
"Kindle",
|
||||||
"Separator",
|
"Separator",
|
||||||
|
"Kobo Aura ONE",
|
||||||
"Kobo Aura H2O",
|
"Kobo Aura H2O",
|
||||||
"Kobo Aura HD",
|
"Kobo Aura HD",
|
||||||
"Kobo Aura",
|
"Kobo Aura",
|
||||||
|
|||||||
170
kcc/KCC_ui.py
170
kcc/KCC_ui.py
@@ -11,7 +11,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
|
|||||||
class Ui_mainWindow(object):
|
class Ui_mainWindow(object):
|
||||||
def setupUi(self, mainWindow):
|
def setupUi(self, mainWindow):
|
||||||
mainWindow.setObjectName("mainWindow")
|
mainWindow.setObjectName("mainWindow")
|
||||||
mainWindow.resize(450, 450)
|
mainWindow.resize(450, 400)
|
||||||
icon = QtGui.QIcon()
|
icon = QtGui.QIcon()
|
||||||
icon.addPixmap(QtGui.QPixmap(":/Icon/icons/comic2ebook.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
icon.addPixmap(QtGui.QPixmap(":/Icon/icons/comic2ebook.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
mainWindow.setWindowIcon(icon)
|
mainWindow.setWindowIcon(icon)
|
||||||
@@ -20,27 +20,6 @@ class Ui_mainWindow(object):
|
|||||||
self.gridLayout = QtWidgets.QGridLayout(self.centralWidget)
|
self.gridLayout = QtWidgets.QGridLayout(self.centralWidget)
|
||||||
self.gridLayout.setContentsMargins(-1, -1, -1, 5)
|
self.gridLayout.setContentsMargins(-1, -1, -1, 5)
|
||||||
self.gridLayout.setObjectName("gridLayout")
|
self.gridLayout.setObjectName("gridLayout")
|
||||||
self.directoryButton = QtWidgets.QPushButton(self.centralWidget)
|
|
||||||
self.directoryButton.setMinimumSize(QtCore.QSize(130, 30))
|
|
||||||
icon1 = QtGui.QIcon()
|
|
||||||
icon1.addPixmap(QtGui.QPixmap(":/Other/icons/folder_new.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
|
||||||
self.directoryButton.setIcon(icon1)
|
|
||||||
self.directoryButton.setObjectName("directoryButton")
|
|
||||||
self.gridLayout.addWidget(self.directoryButton, 3, 0, 1, 1)
|
|
||||||
self.clearButton = QtWidgets.QPushButton(self.centralWidget)
|
|
||||||
self.clearButton.setMinimumSize(QtCore.QSize(0, 30))
|
|
||||||
icon2 = QtGui.QIcon()
|
|
||||||
icon2.addPixmap(QtGui.QPixmap(":/Other/icons/clear.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
|
||||||
self.clearButton.setIcon(icon2)
|
|
||||||
self.clearButton.setObjectName("clearButton")
|
|
||||||
self.gridLayout.addWidget(self.clearButton, 3, 1, 1, 1)
|
|
||||||
self.fileButton = QtWidgets.QPushButton(self.centralWidget)
|
|
||||||
self.fileButton.setMinimumSize(QtCore.QSize(130, 30))
|
|
||||||
icon3 = QtGui.QIcon()
|
|
||||||
icon3.addPixmap(QtGui.QPixmap(":/Other/icons/document_new.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
|
||||||
self.fileButton.setIcon(icon3)
|
|
||||||
self.fileButton.setObjectName("fileButton")
|
|
||||||
self.gridLayout.addWidget(self.fileButton, 3, 2, 1, 1)
|
|
||||||
self.progressBar = QtWidgets.QProgressBar(self.centralWidget)
|
self.progressBar = QtWidgets.QProgressBar(self.centralWidget)
|
||||||
self.progressBar.setMinimumSize(QtCore.QSize(0, 30))
|
self.progressBar.setMinimumSize(QtCore.QSize(0, 30))
|
||||||
font = QtGui.QFont()
|
font = QtGui.QFont()
|
||||||
@@ -50,33 +29,14 @@ class Ui_mainWindow(object):
|
|||||||
self.progressBar.setVisible(False)
|
self.progressBar.setVisible(False)
|
||||||
self.progressBar.setAlignment(QtCore.Qt.AlignJustify|QtCore.Qt.AlignVCenter)
|
self.progressBar.setAlignment(QtCore.Qt.AlignJustify|QtCore.Qt.AlignVCenter)
|
||||||
self.progressBar.setObjectName("progressBar")
|
self.progressBar.setObjectName("progressBar")
|
||||||
self.gridLayout.addWidget(self.progressBar, 1, 0, 1, 3)
|
self.gridLayout.addWidget(self.progressBar, 1, 0, 1, 2)
|
||||||
self.deviceBox = QtWidgets.QComboBox(self.centralWidget)
|
|
||||||
self.deviceBox.setMinimumSize(QtCore.QSize(0, 28))
|
|
||||||
self.deviceBox.setObjectName("deviceBox")
|
|
||||||
self.gridLayout.addWidget(self.deviceBox, 4, 0, 1, 1)
|
|
||||||
self.convertButton = QtWidgets.QPushButton(self.centralWidget)
|
|
||||||
self.convertButton.setMinimumSize(QtCore.QSize(0, 30))
|
|
||||||
font = QtGui.QFont()
|
|
||||||
font.setBold(True)
|
|
||||||
font.setWeight(75)
|
|
||||||
self.convertButton.setFont(font)
|
|
||||||
icon4 = QtGui.QIcon()
|
|
||||||
icon4.addPixmap(QtGui.QPixmap(":/Other/icons/convert.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
|
||||||
self.convertButton.setIcon(icon4)
|
|
||||||
self.convertButton.setObjectName("convertButton")
|
|
||||||
self.gridLayout.addWidget(self.convertButton, 4, 1, 1, 1)
|
|
||||||
self.formatBox = QtWidgets.QComboBox(self.centralWidget)
|
|
||||||
self.formatBox.setMinimumSize(QtCore.QSize(0, 28))
|
|
||||||
self.formatBox.setObjectName("formatBox")
|
|
||||||
self.gridLayout.addWidget(self.formatBox, 4, 2, 1, 1)
|
|
||||||
self.jobList = QtWidgets.QListWidget(self.centralWidget)
|
self.jobList = QtWidgets.QListWidget(self.centralWidget)
|
||||||
self.jobList.setStyleSheet("QListWidget#jobList {background:#ffffff;background-image:url(:/Other/icons/list_background.png);background-position:center center;background-repeat:no-repeat;}")
|
self.jobList.setStyleSheet("QListWidget#jobList {background:#ffffff;background-image:url(:/Other/icons/list_background.png);background-position:center center;background-repeat:no-repeat;}")
|
||||||
self.jobList.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)
|
self.jobList.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)
|
||||||
self.jobList.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
|
self.jobList.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
|
||||||
self.jobList.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
|
self.jobList.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
|
||||||
self.jobList.setObjectName("jobList")
|
self.jobList.setObjectName("jobList")
|
||||||
self.gridLayout.addWidget(self.jobList, 2, 0, 1, 3)
|
self.gridLayout.addWidget(self.jobList, 2, 0, 1, 2)
|
||||||
self.customWidget = QtWidgets.QWidget(self.centralWidget)
|
self.customWidget = QtWidgets.QWidget(self.centralWidget)
|
||||||
self.customWidget.setVisible(False)
|
self.customWidget.setVisible(False)
|
||||||
self.customWidget.setObjectName("customWidget")
|
self.customWidget.setObjectName("customWidget")
|
||||||
@@ -107,7 +67,7 @@ class Ui_mainWindow(object):
|
|||||||
self.heightBox.setMaximum(3840)
|
self.heightBox.setMaximum(3840)
|
||||||
self.heightBox.setObjectName("heightBox")
|
self.heightBox.setObjectName("heightBox")
|
||||||
self.gridLayout_3.addWidget(self.heightBox, 0, 3, 1, 1)
|
self.gridLayout_3.addWidget(self.heightBox, 0, 3, 1, 1)
|
||||||
self.gridLayout.addWidget(self.customWidget, 7, 0, 1, 3)
|
self.gridLayout.addWidget(self.customWidget, 6, 0, 1, 2)
|
||||||
self.optionWidget = QtWidgets.QWidget(self.centralWidget)
|
self.optionWidget = QtWidgets.QWidget(self.centralWidget)
|
||||||
self.optionWidget.setObjectName("optionWidget")
|
self.optionWidget.setObjectName("optionWidget")
|
||||||
self.gridLayout_2 = QtWidgets.QGridLayout(self.optionWidget)
|
self.gridLayout_2 = QtWidgets.QGridLayout(self.optionWidget)
|
||||||
@@ -117,6 +77,7 @@ class Ui_mainWindow(object):
|
|||||||
self.mangaBox.setObjectName("mangaBox")
|
self.mangaBox.setObjectName("mangaBox")
|
||||||
self.gridLayout_2.addWidget(self.mangaBox, 0, 0, 1, 1)
|
self.gridLayout_2.addWidget(self.mangaBox, 0, 0, 1, 1)
|
||||||
self.rotateBox = QtWidgets.QCheckBox(self.optionWidget)
|
self.rotateBox = QtWidgets.QCheckBox(self.optionWidget)
|
||||||
|
self.rotateBox.setTristate(True)
|
||||||
self.rotateBox.setObjectName("rotateBox")
|
self.rotateBox.setObjectName("rotateBox")
|
||||||
self.gridLayout_2.addWidget(self.rotateBox, 0, 1, 1, 1)
|
self.gridLayout_2.addWidget(self.rotateBox, 0, 1, 1, 1)
|
||||||
self.qualityBox = QtWidgets.QCheckBox(self.optionWidget)
|
self.qualityBox = QtWidgets.QCheckBox(self.optionWidget)
|
||||||
@@ -126,12 +87,14 @@ class Ui_mainWindow(object):
|
|||||||
self.webtoonBox.setObjectName("webtoonBox")
|
self.webtoonBox.setObjectName("webtoonBox")
|
||||||
self.gridLayout_2.addWidget(self.webtoonBox, 1, 0, 1, 1)
|
self.gridLayout_2.addWidget(self.webtoonBox, 1, 0, 1, 1)
|
||||||
self.upscaleBox = QtWidgets.QCheckBox(self.optionWidget)
|
self.upscaleBox = QtWidgets.QCheckBox(self.optionWidget)
|
||||||
|
self.upscaleBox.setTristate(True)
|
||||||
self.upscaleBox.setObjectName("upscaleBox")
|
self.upscaleBox.setObjectName("upscaleBox")
|
||||||
self.gridLayout_2.addWidget(self.upscaleBox, 1, 1, 1, 1)
|
self.gridLayout_2.addWidget(self.upscaleBox, 1, 1, 1, 1)
|
||||||
self.gammaBox = QtWidgets.QCheckBox(self.optionWidget)
|
self.gammaBox = QtWidgets.QCheckBox(self.optionWidget)
|
||||||
self.gammaBox.setObjectName("gammaBox")
|
self.gammaBox.setObjectName("gammaBox")
|
||||||
self.gridLayout_2.addWidget(self.gammaBox, 1, 2, 1, 1)
|
self.gridLayout_2.addWidget(self.gammaBox, 1, 2, 1, 1)
|
||||||
self.borderBox = QtWidgets.QCheckBox(self.optionWidget)
|
self.borderBox = QtWidgets.QCheckBox(self.optionWidget)
|
||||||
|
self.borderBox.setTristate(True)
|
||||||
self.borderBox.setObjectName("borderBox")
|
self.borderBox.setObjectName("borderBox")
|
||||||
self.gridLayout_2.addWidget(self.borderBox, 2, 0, 1, 1)
|
self.gridLayout_2.addWidget(self.borderBox, 2, 0, 1, 1)
|
||||||
self.noDitheringBox = QtWidgets.QCheckBox(self.optionWidget)
|
self.noDitheringBox = QtWidgets.QCheckBox(self.optionWidget)
|
||||||
@@ -140,7 +103,7 @@ class Ui_mainWindow(object):
|
|||||||
self.colorBox = QtWidgets.QCheckBox(self.optionWidget)
|
self.colorBox = QtWidgets.QCheckBox(self.optionWidget)
|
||||||
self.colorBox.setObjectName("colorBox")
|
self.colorBox.setObjectName("colorBox")
|
||||||
self.gridLayout_2.addWidget(self.colorBox, 2, 2, 1, 1)
|
self.gridLayout_2.addWidget(self.colorBox, 2, 2, 1, 1)
|
||||||
self.gridLayout.addWidget(self.optionWidget, 5, 0, 1, 3)
|
self.gridLayout.addWidget(self.optionWidget, 4, 0, 1, 2)
|
||||||
self.gammaWidget = QtWidgets.QWidget(self.centralWidget)
|
self.gammaWidget = QtWidgets.QWidget(self.centralWidget)
|
||||||
self.gammaWidget.setVisible(False)
|
self.gammaWidget.setVisible(False)
|
||||||
self.gammaWidget.setObjectName("gammaWidget")
|
self.gammaWidget.setObjectName("gammaWidget")
|
||||||
@@ -156,7 +119,7 @@ class Ui_mainWindow(object):
|
|||||||
self.gammaSlider.setOrientation(QtCore.Qt.Horizontal)
|
self.gammaSlider.setOrientation(QtCore.Qt.Horizontal)
|
||||||
self.gammaSlider.setObjectName("gammaSlider")
|
self.gammaSlider.setObjectName("gammaSlider")
|
||||||
self.horizontalLayout_2.addWidget(self.gammaSlider)
|
self.horizontalLayout_2.addWidget(self.gammaSlider)
|
||||||
self.gridLayout.addWidget(self.gammaWidget, 6, 0, 1, 3)
|
self.gridLayout.addWidget(self.gammaWidget, 5, 0, 1, 2)
|
||||||
self.toolWidget = QtWidgets.QWidget(self.centralWidget)
|
self.toolWidget = QtWidgets.QWidget(self.centralWidget)
|
||||||
self.toolWidget.setObjectName("toolWidget")
|
self.toolWidget.setObjectName("toolWidget")
|
||||||
self.horizontalLayout = QtWidgets.QHBoxLayout(self.toolWidget)
|
self.horizontalLayout = QtWidgets.QHBoxLayout(self.toolWidget)
|
||||||
@@ -164,19 +127,78 @@ class Ui_mainWindow(object):
|
|||||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||||
self.editorButton = QtWidgets.QPushButton(self.toolWidget)
|
self.editorButton = QtWidgets.QPushButton(self.toolWidget)
|
||||||
self.editorButton.setMinimumSize(QtCore.QSize(0, 30))
|
self.editorButton.setMinimumSize(QtCore.QSize(0, 30))
|
||||||
icon5 = QtGui.QIcon()
|
icon1 = QtGui.QIcon()
|
||||||
icon5.addPixmap(QtGui.QPixmap(":/Other/icons/editor.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
icon1.addPixmap(QtGui.QPixmap(":/Other/icons/editor.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
self.editorButton.setIcon(icon5)
|
self.editorButton.setIcon(icon1)
|
||||||
self.editorButton.setObjectName("editorButton")
|
self.editorButton.setObjectName("editorButton")
|
||||||
self.horizontalLayout.addWidget(self.editorButton)
|
self.horizontalLayout.addWidget(self.editorButton)
|
||||||
self.wikiButton = QtWidgets.QPushButton(self.toolWidget)
|
self.wikiButton = QtWidgets.QPushButton(self.toolWidget)
|
||||||
self.wikiButton.setMinimumSize(QtCore.QSize(0, 30))
|
self.wikiButton.setMinimumSize(QtCore.QSize(0, 30))
|
||||||
icon6 = QtGui.QIcon()
|
icon2 = QtGui.QIcon()
|
||||||
icon6.addPixmap(QtGui.QPixmap(":/Other/icons/wiki.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
icon2.addPixmap(QtGui.QPixmap(":/Other/icons/wiki.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
self.wikiButton.setIcon(icon6)
|
self.wikiButton.setIcon(icon2)
|
||||||
self.wikiButton.setObjectName("wikiButton")
|
self.wikiButton.setObjectName("wikiButton")
|
||||||
self.horizontalLayout.addWidget(self.wikiButton)
|
self.horizontalLayout.addWidget(self.wikiButton)
|
||||||
self.gridLayout.addWidget(self.toolWidget, 0, 0, 1, 3)
|
self.gridLayout.addWidget(self.toolWidget, 0, 0, 1, 2)
|
||||||
|
self.buttonWidget = QtWidgets.QWidget(self.centralWidget)
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.buttonWidget.sizePolicy().hasHeightForWidth())
|
||||||
|
self.buttonWidget.setSizePolicy(sizePolicy)
|
||||||
|
self.buttonWidget.setObjectName("buttonWidget")
|
||||||
|
self.gridLayout_4 = QtWidgets.QGridLayout(self.buttonWidget)
|
||||||
|
self.gridLayout_4.setContentsMargins(0, 0, 0, 0)
|
||||||
|
self.gridLayout_4.setObjectName("gridLayout_4")
|
||||||
|
self.directoryButton = QtWidgets.QPushButton(self.buttonWidget)
|
||||||
|
self.directoryButton.setMinimumSize(QtCore.QSize(0, 30))
|
||||||
|
icon3 = QtGui.QIcon()
|
||||||
|
icon3.addPixmap(QtGui.QPixmap(":/Other/icons/folder_new.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
|
self.directoryButton.setIcon(icon3)
|
||||||
|
self.directoryButton.setObjectName("directoryButton")
|
||||||
|
self.gridLayout_4.addWidget(self.directoryButton, 0, 0, 1, 1)
|
||||||
|
self.fileButton = QtWidgets.QPushButton(self.buttonWidget)
|
||||||
|
self.fileButton.setMinimumSize(QtCore.QSize(0, 30))
|
||||||
|
icon4 = QtGui.QIcon()
|
||||||
|
icon4.addPixmap(QtGui.QPixmap(":/Other/icons/document_new.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
|
self.fileButton.setIcon(icon4)
|
||||||
|
self.fileButton.setObjectName("fileButton")
|
||||||
|
self.gridLayout_4.addWidget(self.fileButton, 0, 3, 1, 1)
|
||||||
|
self.deviceBox = QtWidgets.QComboBox(self.buttonWidget)
|
||||||
|
self.deviceBox.setMinimumSize(QtCore.QSize(0, 28))
|
||||||
|
self.deviceBox.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToMinimumContentsLength)
|
||||||
|
self.deviceBox.setObjectName("deviceBox")
|
||||||
|
self.gridLayout_4.addWidget(self.deviceBox, 1, 0, 1, 1)
|
||||||
|
self.formatBox = QtWidgets.QComboBox(self.buttonWidget)
|
||||||
|
self.formatBox.setMinimumSize(QtCore.QSize(0, 28))
|
||||||
|
self.formatBox.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToMinimumContentsLength)
|
||||||
|
self.formatBox.setObjectName("formatBox")
|
||||||
|
self.gridLayout_4.addWidget(self.formatBox, 1, 3, 1, 1)
|
||||||
|
self.convertButton = QtWidgets.QPushButton(self.buttonWidget)
|
||||||
|
self.convertButton.setMinimumSize(QtCore.QSize(0, 30))
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setBold(True)
|
||||||
|
font.setWeight(75)
|
||||||
|
self.convertButton.setFont(font)
|
||||||
|
icon5 = QtGui.QIcon()
|
||||||
|
icon5.addPixmap(QtGui.QPixmap(":/Other/icons/convert.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
|
self.convertButton.setIcon(icon5)
|
||||||
|
self.convertButton.setObjectName("convertButton")
|
||||||
|
self.gridLayout_4.addWidget(self.convertButton, 1, 2, 1, 1)
|
||||||
|
self.clearButton = QtWidgets.QPushButton(self.buttonWidget)
|
||||||
|
self.clearButton.setMinimumSize(QtCore.QSize(0, 30))
|
||||||
|
icon6 = QtGui.QIcon()
|
||||||
|
icon6.addPixmap(QtGui.QPixmap(":/Other/icons/clear.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
|
self.clearButton.setIcon(icon6)
|
||||||
|
self.clearButton.setObjectName("clearButton")
|
||||||
|
self.gridLayout_4.addWidget(self.clearButton, 0, 2, 1, 1)
|
||||||
|
self.directoryButton.raise_()
|
||||||
|
self.clearButton.raise_()
|
||||||
|
self.fileButton.raise_()
|
||||||
|
self.deviceBox.raise_()
|
||||||
|
self.convertButton.raise_()
|
||||||
|
self.formatBox.raise_()
|
||||||
|
self.gridLayout.addWidget(self.buttonWidget, 3, 0, 1, 2)
|
||||||
mainWindow.setCentralWidget(self.centralWidget)
|
mainWindow.setCentralWidget(self.centralWidget)
|
||||||
self.statusBar = QtWidgets.QStatusBar(mainWindow)
|
self.statusBar = QtWidgets.QStatusBar(mainWindow)
|
||||||
self.statusBar.setSizeGripEnabled(False)
|
self.statusBar.setSizeGripEnabled(False)
|
||||||
@@ -185,19 +207,30 @@ class Ui_mainWindow(object):
|
|||||||
|
|
||||||
self.retranslateUi(mainWindow)
|
self.retranslateUi(mainWindow)
|
||||||
QtCore.QMetaObject.connectSlotsByName(mainWindow)
|
QtCore.QMetaObject.connectSlotsByName(mainWindow)
|
||||||
|
mainWindow.setTabOrder(self.convertButton, self.clearButton)
|
||||||
|
mainWindow.setTabOrder(self.clearButton, self.directoryButton)
|
||||||
|
mainWindow.setTabOrder(self.directoryButton, self.fileButton)
|
||||||
|
mainWindow.setTabOrder(self.fileButton, self.deviceBox)
|
||||||
|
mainWindow.setTabOrder(self.deviceBox, self.formatBox)
|
||||||
|
mainWindow.setTabOrder(self.formatBox, self.mangaBox)
|
||||||
|
mainWindow.setTabOrder(self.mangaBox, self.rotateBox)
|
||||||
|
mainWindow.setTabOrder(self.rotateBox, self.qualityBox)
|
||||||
|
mainWindow.setTabOrder(self.qualityBox, self.webtoonBox)
|
||||||
|
mainWindow.setTabOrder(self.webtoonBox, self.upscaleBox)
|
||||||
|
mainWindow.setTabOrder(self.upscaleBox, self.gammaBox)
|
||||||
|
mainWindow.setTabOrder(self.gammaBox, self.borderBox)
|
||||||
|
mainWindow.setTabOrder(self.borderBox, self.noDitheringBox)
|
||||||
|
mainWindow.setTabOrder(self.noDitheringBox, self.colorBox)
|
||||||
|
mainWindow.setTabOrder(self.colorBox, self.editorButton)
|
||||||
|
mainWindow.setTabOrder(self.editorButton, self.wikiButton)
|
||||||
|
mainWindow.setTabOrder(self.wikiButton, self.jobList)
|
||||||
|
mainWindow.setTabOrder(self.jobList, self.gammaSlider)
|
||||||
|
mainWindow.setTabOrder(self.gammaSlider, self.widthBox)
|
||||||
|
mainWindow.setTabOrder(self.widthBox, self.heightBox)
|
||||||
|
|
||||||
def retranslateUi(self, mainWindow):
|
def retranslateUi(self, mainWindow):
|
||||||
_translate = QtCore.QCoreApplication.translate
|
_translate = QtCore.QCoreApplication.translate
|
||||||
mainWindow.setWindowTitle(_translate("mainWindow", "Kindle Comic Converter"))
|
mainWindow.setWindowTitle(_translate("mainWindow", "Kindle Comic Converter"))
|
||||||
self.directoryButton.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Add directory containing JPG, PNG or GIF files to queue.<br/><span style=\" font-weight:600;\">CBR, CBZ and CB7 files inside will not be processed!</span></p></body></html>"))
|
|
||||||
self.directoryButton.setText(_translate("mainWindow", "Add directory"))
|
|
||||||
self.clearButton.setText(_translate("mainWindow", "Clear list"))
|
|
||||||
self.fileButton.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Add CBR, CBZ, CB7 or PDF file to queue.</p></body></html>"))
|
|
||||||
self.fileButton.setText(_translate("mainWindow", "Add file"))
|
|
||||||
self.deviceBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Target device.</p></body></html>"))
|
|
||||||
self.convertButton.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Shift+Click to select the output directory.</p></body></html>"))
|
|
||||||
self.convertButton.setText(_translate("mainWindow", "Convert"))
|
|
||||||
self.formatBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Output format.</p></body></html>"))
|
|
||||||
self.hLabel.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Resolution of target device.</p></body></html>"))
|
self.hLabel.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Resolution of target device.</p></body></html>"))
|
||||||
self.hLabel.setText(_translate("mainWindow", "Custom height:"))
|
self.hLabel.setText(_translate("mainWindow", "Custom height:"))
|
||||||
self.widthBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Resolution of target device.</p></body></html>"))
|
self.widthBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Resolution of target device.</p></body></html>"))
|
||||||
@@ -208,8 +241,8 @@ class Ui_mainWindow(object):
|
|||||||
self.mangaBox.setText(_translate("mainWindow", "Manga mode"))
|
self.mangaBox.setText(_translate("mainWindow", "Manga mode"))
|
||||||
self.rotateBox.setToolTip(_translate("mainWindow", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Split<br/></span>Double page spreads will be cut into two separate pages.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Rotate and split<br/></span>Double page spreads will be displayed twice. First rotated and then split. </p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Rotate<br/></span>Double page spreads will be rotated.</p></body></html>"))
|
self.rotateBox.setToolTip(_translate("mainWindow", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Split<br/></span>Double page spreads will be cut into two separate pages.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Rotate and split<br/></span>Double page spreads will be displayed twice. First rotated and then split. </p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Rotate<br/></span>Double page spreads will be rotated.</p></body></html>"))
|
||||||
self.rotateBox.setText(_translate("mainWindow", "Spread splitter"))
|
self.rotateBox.setText(_translate("mainWindow", "Spread splitter"))
|
||||||
self.qualityBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>High quality Panel View.<br/>Require source files with bigger resolution than target device.<br/><span style=\" font-weight:600;\">Highly impact size of output file!</span></p></body></html>"))
|
self.qualityBox.setToolTip(_translate("mainWindow", "<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;\">Checked - 2 panels<br/></span>Zoom only the top and bottom of the page.</p></body></html>"))
|
||||||
self.qualityBox.setText(_translate("mainWindow", "HQ zoom"))
|
self.qualityBox.setText(_translate("mainWindow", "Panel View 4/2"))
|
||||||
self.webtoonBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Enable special parsing mode for Korean Webtoons.</p></body></html>"))
|
self.webtoonBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Enable special parsing mode for Korean Webtoons.</p></body></html>"))
|
||||||
self.webtoonBox.setText(_translate("mainWindow", "Webtoon mode"))
|
self.webtoonBox.setText(_translate("mainWindow", "Webtoon mode"))
|
||||||
self.upscaleBox.setToolTip(_translate("mainWindow", "<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>"))
|
self.upscaleBox.setToolTip(_translate("mainWindow", "<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>"))
|
||||||
@@ -225,5 +258,14 @@ class Ui_mainWindow(object):
|
|||||||
self.gammaLabel.setText(_translate("mainWindow", "Gamma: Auto"))
|
self.gammaLabel.setText(_translate("mainWindow", "Gamma: Auto"))
|
||||||
self.editorButton.setText(_translate("mainWindow", "Editor"))
|
self.editorButton.setText(_translate("mainWindow", "Editor"))
|
||||||
self.wikiButton.setText(_translate("mainWindow", "Wiki"))
|
self.wikiButton.setText(_translate("mainWindow", "Wiki"))
|
||||||
|
self.directoryButton.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Add directory containing JPG, PNG or GIF files to queue.<br/><span style=\" font-weight:600;\">CBR, CBZ and CB7 files inside will not be processed!</span></p></body></html>"))
|
||||||
|
self.directoryButton.setText(_translate("mainWindow", "Add directory"))
|
||||||
|
self.fileButton.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Add CBR, CBZ, CB7 or PDF file to queue.</p></body></html>"))
|
||||||
|
self.fileButton.setText(_translate("mainWindow", "Add file"))
|
||||||
|
self.deviceBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Target device.</p></body></html>"))
|
||||||
|
self.formatBox.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Output format.</p></body></html>"))
|
||||||
|
self.convertButton.setToolTip(_translate("mainWindow", "<html><head/><body><p style=\'white-space:pre\'>Shift+Click to select the output directory.</p></body></html>"))
|
||||||
|
self.convertButton.setText(_translate("mainWindow", "Convert"))
|
||||||
|
self.clearButton.setText(_translate("mainWindow", "Clear list"))
|
||||||
|
|
||||||
from . import KCC_rc
|
from . import KCC_rc
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
__version__ = '5.1'
|
__version__ = '5.2'
|
||||||
__license__ = 'ISC'
|
__license__ = 'ISC'
|
||||||
__copyright__ = '2012-2016, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
|
__copyright__ = '2012-2016, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ try:
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
walk = os.walk
|
walk = os.walk
|
||||||
from . import rarfile
|
from . import rarfile
|
||||||
from .shared import check7ZFile as is_7zfile, saferReplace
|
from .shared import check7ZFile as is_7zfile, saferReplace, saferRemove
|
||||||
|
|
||||||
|
|
||||||
class CBxArchive:
|
class CBxArchive:
|
||||||
@@ -66,7 +66,7 @@ class CBxArchive:
|
|||||||
for root, dirnames, filenames in walk(targetdir):
|
for root, dirnames, filenames in walk(targetdir):
|
||||||
for filename in filenames:
|
for filename in filenames:
|
||||||
if filename.startswith('__MACOSX') or filename.endswith('.DS_Store') or filename.endswith('humbs.db'):
|
if filename.startswith('__MACOSX') or filename.endswith('.DS_Store') or filename.endswith('humbs.db'):
|
||||||
os.remove(os.path.join(root, filename))
|
saferRemove(os.path.join(root, filename))
|
||||||
|
|
||||||
def extractCB7(self, targetdir):
|
def extractCB7(self, targetdir):
|
||||||
# Workaround for some wide UTF-8 + Popen abnormalities
|
# Workaround for some wide UTF-8 + Popen abnormalities
|
||||||
@@ -80,7 +80,7 @@ class CBxArchive:
|
|||||||
if b"Everything is Ok" in line:
|
if b"Everything is Ok" in line:
|
||||||
extracted = True
|
extracted = True
|
||||||
if sys.platform.startswith('darwin'):
|
if sys.platform.startswith('darwin'):
|
||||||
os.remove(self.origFileName)
|
saferRemove(self.origFileName)
|
||||||
if not extracted:
|
if not extracted:
|
||||||
raise OSError
|
raise OSError
|
||||||
|
|
||||||
|
|||||||
@@ -64,7 +64,10 @@ def main(argv=None):
|
|||||||
if len(args) == 0:
|
if len(args) == 0:
|
||||||
parser.print_help()
|
parser.print_help()
|
||||||
return 0
|
return 0
|
||||||
sources = set([source for arg in args for source in glob(arg)])
|
if sys.platform.startswith('win'):
|
||||||
|
sources = set([source for arg in args for source in glob(arg)])
|
||||||
|
else:
|
||||||
|
sources = set(args)
|
||||||
if len(sources) == 0:
|
if len(sources) == 0:
|
||||||
print('No matching files found.')
|
print('No matching files found.')
|
||||||
return 1
|
return 1
|
||||||
@@ -92,8 +95,6 @@ def buildHTML(path, imgfile, imgfilepath):
|
|||||||
additionalStyle = 'background-color:#FFFFFF;'
|
additionalStyle = 'background-color:#FFFFFF;'
|
||||||
htmlpath = ''
|
htmlpath = ''
|
||||||
postfix = ''
|
postfix = ''
|
||||||
size = ''
|
|
||||||
imgfilepv = ''
|
|
||||||
backref = 1
|
backref = 1
|
||||||
head = path
|
head = path
|
||||||
while True:
|
while True:
|
||||||
@@ -119,21 +120,16 @@ def buildHTML(path, imgfile, imgfilepath):
|
|||||||
"<body style=\"background-image: ",
|
"<body style=\"background-image: ",
|
||||||
"url('", "../" * backref, "Images/", postfix, imgfile, "'); " + additionalStyle + "\">\n"])
|
"url('", "../" * backref, "Images/", postfix, imgfile, "'); " + additionalStyle + "\">\n"])
|
||||||
if options.iskindle and options.panelview:
|
if options.iskindle and options.panelview:
|
||||||
if options.hqmode:
|
sizeTmp = Image.open(os.path.join(head, "Images", postfix, imgfile)).size
|
||||||
imgfilepv = list(os.path.splitext(imgfile))
|
if options.autoscale:
|
||||||
imgfilepv[0] += "-hq"
|
size = (getPanelViewResolution(sizeTmp, deviceres))
|
||||||
imgfilepv = "".join(imgfilepv)
|
else:
|
||||||
if os.path.isfile(os.path.join(head, "Images", postfix, imgfilepv)):
|
|
||||||
size = Image.open(os.path.join(head, "Images", postfix, imgfilepv)).size
|
|
||||||
if not options.hqmode or not size:
|
|
||||||
imgfilepv = imgfile
|
|
||||||
sizeTmp = Image.open(os.path.join(head, "Images", postfix, imgfilepv)).size
|
|
||||||
size = (int(sizeTmp[0] * 1.5), int(sizeTmp[1] * 1.5))
|
size = (int(sizeTmp[0] * 1.5), int(sizeTmp[1] * 1.5))
|
||||||
if size[0] <= deviceres[0]:
|
if size[0] - deviceres[0] < deviceres[0] * 0.01:
|
||||||
noHorizontalPV = True
|
noHorizontalPV = True
|
||||||
else:
|
else:
|
||||||
noHorizontalPV = False
|
noHorizontalPV = False
|
||||||
if size[1] <= deviceres[1]:
|
if size[1] - deviceres[1] < deviceres[1] * 0.01:
|
||||||
noVerticalPV = True
|
noVerticalPV = True
|
||||||
else:
|
else:
|
||||||
noVerticalPV = False
|
noVerticalPV = False
|
||||||
@@ -190,7 +186,7 @@ def buildHTML(path, imgfile, imgfilepath):
|
|||||||
for box in boxes:
|
for box in boxes:
|
||||||
f.writelines(["<div class=\"PV-P\" id=\"" + box + "-P\" style=\"" + additionalStyle + "\">\n",
|
f.writelines(["<div class=\"PV-P\" id=\"" + box + "-P\" style=\"" + additionalStyle + "\">\n",
|
||||||
"<img style=\"" + boxStyles[box] + "\" src=\"", "../" * backref, "Images/", postfix,
|
"<img style=\"" + boxStyles[box] + "\" src=\"", "../" * backref, "Images/", postfix,
|
||||||
imgfilepv, "\" width=\"" + str(size[0]) + "\" height=\"" + str(size[1]) + "\"/>\n",
|
imgfile, "\" width=\"" + str(size[0]) + "\" height=\"" + str(size[1]) + "\"/>\n",
|
||||||
"</div>\n"])
|
"</div>\n"])
|
||||||
f.writelines(["</body>\n",
|
f.writelines(["</body>\n",
|
||||||
"</html>\n"])
|
"</html>\n"])
|
||||||
@@ -333,29 +329,6 @@ def buildOPF(dstdir, title, filelist, cover=None):
|
|||||||
f.write("</manifest>\n<spine page-progression-direction=\"rtl\" toc=\"ncx\">\n")
|
f.write("</manifest>\n<spine page-progression-direction=\"rtl\" toc=\"ncx\">\n")
|
||||||
else:
|
else:
|
||||||
f.write("</manifest>\n<spine page-progression-direction=\"ltr\" toc=\"ncx\">\n")
|
f.write("</manifest>\n<spine page-progression-direction=\"ltr\" toc=\"ncx\">\n")
|
||||||
# if options.iskindle and options.profile != 'Custom':
|
|
||||||
# if options.righttoleft:
|
|
||||||
# nextflow = 'right'
|
|
||||||
# else:
|
|
||||||
# nextflow = 'left'
|
|
||||||
# for entry in reflist:
|
|
||||||
# if '-kcc-b' in entry:
|
|
||||||
# if options.righttoleft:
|
|
||||||
# f.write("<itemref idref=\"page_" + entry + "\" properties=\"page-spread-right\"/>\n")
|
|
||||||
# else:
|
|
||||||
# f.write("<itemref idref=\"page_" + entry + "\" properties=\"page-spread-left\"/>\n")
|
|
||||||
# elif '-kcc-c' in entry:
|
|
||||||
# if options.righttoleft:
|
|
||||||
# f.write("<itemref idref=\"page_" + entry + "\" properties=\"page-spread-left\"/>\n")
|
|
||||||
# else:
|
|
||||||
# f.write("<itemref idref=\"page_" + entry + "\" properties=\"page-spread-right\"/>\n")
|
|
||||||
# else:
|
|
||||||
# f.write("<itemref idref=\"page_" + entry + "\" properties=\"facing-page-" + nextflow + "\"/>\n")
|
|
||||||
# if nextflow == 'right':
|
|
||||||
# nextflow = 'left'
|
|
||||||
# else:
|
|
||||||
# nextflow = 'right'
|
|
||||||
# else:
|
|
||||||
for entry in reflist:
|
for entry in reflist:
|
||||||
f.write("<itemref idref=\"page_" + entry + "\"/>\n")
|
f.write("<itemref idref=\"page_" + entry + "\"/>\n")
|
||||||
f.write("</spine>\n</package>\n")
|
f.write("</spine>\n</package>\n")
|
||||||
@@ -457,17 +430,15 @@ def buildEPUB(path, chapterNames, tomeNumber):
|
|||||||
chapter = False
|
chapter = False
|
||||||
dirnames, filenames = walkSort(dirnames, filenames)
|
dirnames, filenames = walkSort(dirnames, filenames)
|
||||||
for afile in filenames:
|
for afile in filenames:
|
||||||
filename = getImageFileName(afile)
|
filelist.append(buildHTML(dirpath, afile, os.path.join(dirpath, afile)))
|
||||||
if not filename[0].endswith('-hq'):
|
if not chapter:
|
||||||
filelist.append(buildHTML(dirpath, afile, os.path.join(dirpath, afile)))
|
chapterlist.append((dirpath.replace('Images', 'Text'), filelist[-1][1]))
|
||||||
if not chapter:
|
chapter = True
|
||||||
chapterlist.append((dirpath.replace('Images', 'Text'), filelist[-1][1]))
|
if cover is None:
|
||||||
chapter = True
|
cover = os.path.join(os.path.join(path, 'OEBPS', 'Images'),
|
||||||
if cover is None:
|
'cover' + getImageFileName(filelist[-1][1])[1])
|
||||||
cover = os.path.join(os.path.join(path, 'OEBPS', 'Images'),
|
options.covers.append((image.Cover(os.path.join(filelist[-1][0], filelist[-1][1]), cover, options,
|
||||||
'cover' + getImageFileName(filelist[-1][1])[1])
|
tomeNumber), options.uuid))
|
||||||
options.covers.append((image.Cover(os.path.join(filelist[-1][0], filelist[-1][1]), cover, options,
|
|
||||||
tomeNumber), options.uuid))
|
|
||||||
# Overwrite chapternames if tree is flat and ComicInfo.xml has bookmarks
|
# Overwrite chapternames if tree is flat and ComicInfo.xml has bookmarks
|
||||||
if not chapterNames and options.chapters:
|
if not chapterNames and options.chapters:
|
||||||
chapterlist = []
|
chapterlist = []
|
||||||
@@ -545,10 +516,10 @@ 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(i[0], i[1], i[2], i[3], i[4], opt)
|
img = image.ComicPage(i[0], i[1], i[2], i[3], i[4], opt)
|
||||||
if opt.cropping > 0 and not opt.webtoon:
|
|
||||||
img.cropWhiteSpace(opt.croppingp)
|
|
||||||
if opt.cropping == 2 and not opt.webtoon:
|
if opt.cropping == 2 and not opt.webtoon:
|
||||||
img.cutPageNumber(opt.croppingpn)
|
img.cropPageNumber(opt.croppingp)
|
||||||
|
if opt.cropping > 0 and not opt.webtoon:
|
||||||
|
img.cropMargin(opt.croppingp)
|
||||||
img.autocontrastImage()
|
img.autocontrastImage()
|
||||||
img.resizeImage()
|
img.resizeImage()
|
||||||
if opt.forcepng and not opt.forcecolor:
|
if opt.forcepng and not opt.forcecolor:
|
||||||
@@ -650,7 +621,7 @@ def getComicInfo(path, originalPath):
|
|||||||
try:
|
try:
|
||||||
xml = metadata.MetadataParser(xmlPath)
|
xml = metadata.MetadataParser(xmlPath)
|
||||||
except Exception:
|
except Exception:
|
||||||
os.remove(xmlPath)
|
saferRemove(xmlPath)
|
||||||
return
|
return
|
||||||
options.authors = []
|
options.authors = []
|
||||||
if defaultTitle:
|
if defaultTitle:
|
||||||
@@ -675,7 +646,7 @@ def getComicInfo(path, originalPath):
|
|||||||
options.chapters = xml.data['Bookmarks']
|
options.chapters = xml.data['Bookmarks']
|
||||||
if xml.data['Summary']:
|
if xml.data['Summary']:
|
||||||
options.summary = escape(xml.data['Summary'])
|
options.summary = escape(xml.data['Summary'])
|
||||||
os.remove(xmlPath)
|
saferRemove(xmlPath)
|
||||||
|
|
||||||
|
|
||||||
def getCoversFromMCB(mangaID):
|
def getCoversFromMCB(mangaID):
|
||||||
@@ -701,6 +672,11 @@ def getDirectorySize(start_path='.'):
|
|||||||
return total_size
|
return total_size
|
||||||
|
|
||||||
|
|
||||||
|
def getPanelViewResolution(imageSize, deviceRes):
|
||||||
|
scale = float(deviceRes[0]) / float(imageSize[0])
|
||||||
|
return int(deviceRes[0]), int(scale * imageSize[1])
|
||||||
|
|
||||||
|
|
||||||
def getPanelViewSize(deviceres, size):
|
def getPanelViewSize(deviceres, size):
|
||||||
x = int(deviceres[0] / 2 - size[0] / 2) / deviceres[0] * 100
|
x = int(deviceres[0] / 2 - size[0] / 2) / deviceres[0] * 100
|
||||||
y = int(deviceres[1] / 2 - size[1] / 2) / deviceres[1] * 100
|
y = int(deviceres[1] / 2 - size[1] / 2) / deviceres[1] * 100
|
||||||
@@ -957,9 +933,11 @@ def makeParser():
|
|||||||
|
|
||||||
mainOptions.add_option("-p", "--profile", action="store", dest="profile", default="KV",
|
mainOptions.add_option("-p", "--profile", action="store", dest="profile", default="KV",
|
||||||
help="Device profile (Available options: K1, K2, K3, K45, KDX, KPW, KV, KoMT, KoG, KoGHD,"
|
help="Device profile (Available options: K1, K2, K3, K45, KDX, KPW, KV, KoMT, KoG, KoGHD,"
|
||||||
" KoA, KoAHD, KoAH2O) [Default=KV]")
|
" KoA, KoAHD, KoAH2O, KoAO) [Default=KV]")
|
||||||
mainOptions.add_option("-m", "--manga-style", action="store_true", dest="righttoleft", default=False,
|
mainOptions.add_option("-m", "--manga-style", action="store_true", dest="righttoleft", default=False,
|
||||||
help="Manga style (right-to-left reading and splitting)")
|
help="Manga style (right-to-left reading and splitting)")
|
||||||
|
mainOptions.add_option("-2", "--two-panel", action="store_true", dest="autoscale", default=False,
|
||||||
|
help="Display two not four panels in Panel View mode")
|
||||||
mainOptions.add_option("-w", "--webtoon", action="store_true", dest="webtoon", default=False,
|
mainOptions.add_option("-w", "--webtoon", action="store_true", dest="webtoon", default=False,
|
||||||
help="Webtoon processing mode"),
|
help="Webtoon processing mode"),
|
||||||
|
|
||||||
@@ -980,8 +958,10 @@ def makeParser():
|
|||||||
help="Double page parsing mode. 0: Split 1: Rotate 2: Both [Default=0]")
|
help="Double page parsing mode. 0: Split 1: Rotate 2: Both [Default=0]")
|
||||||
processingOptions.add_option("-g", "--gamma", type="float", dest="gamma", default="0.0",
|
processingOptions.add_option("-g", "--gamma", type="float", dest="gamma", default="0.0",
|
||||||
help="Apply gamma correction to linearize the image [Default=Auto]")
|
help="Apply gamma correction to linearize the image [Default=Auto]")
|
||||||
processingOptions.add_option("--hq", action="store_true", dest="hqmode", default=False,
|
processingOptions.add_option("-c", "--cropping", type="int", dest="cropping", default="2",
|
||||||
help="Enable high quality Panel View")
|
help="Set cropping mode. 0: Disabled 1: Margins 2: Margins + page numbers [Default=2]")
|
||||||
|
processingOptions.add_option("--cp", "--croppingpower", type="float", dest="croppingp", default="1.0",
|
||||||
|
help="Set cropping power [Default=1.0]")
|
||||||
processingOptions.add_option("--blackborders", action="store_true", dest="black_borders", default=False,
|
processingOptions.add_option("--blackborders", action="store_true", dest="black_borders", default=False,
|
||||||
help="Disable autodetection and force black borders")
|
help="Disable autodetection and force black borders")
|
||||||
processingOptions.add_option("--whiteborders", action="store_true", dest="white_borders", default=False,
|
processingOptions.add_option("--whiteborders", action="store_true", dest="white_borders", default=False,
|
||||||
@@ -990,12 +970,6 @@ def makeParser():
|
|||||||
help="Don't convert images to grayscale")
|
help="Don't convert images to grayscale")
|
||||||
processingOptions.add_option("--forcepng", action="store_true", dest="forcepng", default=False,
|
processingOptions.add_option("--forcepng", action="store_true", dest="forcepng", default=False,
|
||||||
help="Create PNG files instead JPEG")
|
help="Create PNG files instead JPEG")
|
||||||
processingOptions.add_option("--cropping", type="int", dest="cropping", default="2",
|
|
||||||
help="Set cropping mode. 0: Disabled 1: Margins 2: Margins + page numbers [Default=2]")
|
|
||||||
processingOptions.add_option("--croppingpower", type="float", dest="croppingp", default="0.1",
|
|
||||||
help="Set margin cropping threshold [Default=0.1]")
|
|
||||||
processingOptions.add_option("--croppingpowerpage", type="float", dest="croppingpn", default="5.0",
|
|
||||||
help="Set page number cropping threshold [Default=5.0]")
|
|
||||||
|
|
||||||
customProfileOptions.add_option("--customwidth", type="int", dest="customwidth", default=0,
|
customProfileOptions.add_option("--customwidth", type="int", dest="customwidth", default=0,
|
||||||
help="Replace screen width provided by device profile")
|
help="Replace screen width provided by device profile")
|
||||||
@@ -1021,7 +995,7 @@ def checkOptions():
|
|||||||
if options.format == 'Auto':
|
if options.format == 'Auto':
|
||||||
if options.profile in ['K1', 'K2', 'K3', 'K45', 'KPW', 'KV']:
|
if options.profile in ['K1', 'K2', 'K3', 'K45', 'KPW', 'KV']:
|
||||||
options.format = 'MOBI'
|
options.format = 'MOBI'
|
||||||
elif options.profile in ['OTHER', 'KoMT', 'KoG', 'KoGHD', 'KoA', 'KoAHD', 'KoAH2O']:
|
elif options.profile in ['OTHER', 'KoMT', 'KoG', 'KoGHD', 'KoA', 'KoAHD', 'KoAH2O', 'KoAO']:
|
||||||
options.format = 'EPUB'
|
options.format = 'EPUB'
|
||||||
elif options.profile in ['KDX']:
|
elif options.profile in ['KDX']:
|
||||||
options.format = 'CBZ'
|
options.format = 'CBZ'
|
||||||
@@ -1037,20 +1011,16 @@ def checkOptions():
|
|||||||
# Older Kindle don't need higher resolution files due lack of Panel View.
|
# Older Kindle don't need higher resolution files due lack of Panel View.
|
||||||
if options.profile == 'K1' or options.profile == 'K2' or options.profile == 'K3' or options.profile == 'KDX':
|
if options.profile == 'K1' or options.profile == 'K2' or options.profile == 'K3' or options.profile == 'KDX':
|
||||||
options.panelview = False
|
options.panelview = False
|
||||||
options.hqmode = False
|
|
||||||
# Webtoon mode mandatory options
|
# Webtoon mode mandatory options
|
||||||
if options.webtoon:
|
if options.webtoon:
|
||||||
options.panelview = False
|
options.panelview = False
|
||||||
options.hqmode = False
|
|
||||||
options.righttoleft = False
|
options.righttoleft = False
|
||||||
options.upscale = True
|
options.upscale = True
|
||||||
# Disable all Kindle features for other e-readers
|
# Disable all Kindle features for other e-readers
|
||||||
if options.profile == 'OTHER':
|
if options.profile == 'OTHER':
|
||||||
options.panelview = False
|
options.panelview = False
|
||||||
options.hqmode = False
|
|
||||||
if 'Ko' in options.profile:
|
if 'Ko' in options.profile:
|
||||||
options.panelview = False
|
options.panelview = False
|
||||||
options.hqmode = False
|
|
||||||
# CBZ files on Kindle DX/DXG support higher resolution
|
# CBZ files on Kindle DX/DXG support higher resolution
|
||||||
if options.profile == 'KDX' and options.format == 'CBZ':
|
if options.profile == 'KDX' and options.format == 'CBZ':
|
||||||
options.customheight = 1200
|
options.customheight = 1200
|
||||||
@@ -1063,7 +1033,7 @@ def checkOptions():
|
|||||||
if options.customheight != 0:
|
if options.customheight != 0:
|
||||||
Y = options.customheight
|
Y = options.customheight
|
||||||
newProfile = ("Custom", (int(X), int(Y)), image.ProfileData.Palette16,
|
newProfile = ("Custom", (int(X), int(Y)), image.ProfileData.Palette16,
|
||||||
image.ProfileData.Profiles[options.profile][3], (int(int(X) * 1.5), int(int(Y) * 1.5)))
|
image.ProfileData.Profiles[options.profile][3])
|
||||||
image.ProfileData.Profiles["Custom"] = newProfile
|
image.ProfileData.Profiles["Custom"] = newProfile
|
||||||
options.profile = "Custom"
|
options.profile = "Custom"
|
||||||
options.profileData = image.ProfileData.Profiles[options.profile]
|
options.profileData = image.ProfileData.Profiles[options.profile]
|
||||||
@@ -1181,7 +1151,6 @@ def makeBook(source, qtGUI=None):
|
|||||||
if not GUI and options.format == 'MOBI':
|
if not GUI and options.format == 'MOBI':
|
||||||
print("Creating MOBI files...")
|
print("Creating MOBI files...")
|
||||||
work = []
|
work = []
|
||||||
k = kindle.Kindle()
|
|
||||||
for i in filepath:
|
for i in filepath:
|
||||||
work.append([i])
|
work.append([i])
|
||||||
output = makeMOBI(work, GUI)
|
output = makeMOBI(work, GUI)
|
||||||
@@ -1190,6 +1159,7 @@ def makeBook(source, qtGUI=None):
|
|||||||
print('Error: KindleGen failed to create MOBI!')
|
print('Error: KindleGen failed to create MOBI!')
|
||||||
print(errors)
|
print(errors)
|
||||||
return filepath
|
return filepath
|
||||||
|
k = kindle.Kindle()
|
||||||
if k.path and k.coverSupport:
|
if k.path and k.coverSupport:
|
||||||
print("Kindle detected. Uploading covers...")
|
print("Kindle detected. Uploading covers...")
|
||||||
for i in filepath:
|
for i in filepath:
|
||||||
@@ -1198,14 +1168,14 @@ def makeBook(source, qtGUI=None):
|
|||||||
print('Error: Failed to tweak KindleGen output!')
|
print('Error: Failed to tweak KindleGen output!')
|
||||||
return filepath
|
return filepath
|
||||||
else:
|
else:
|
||||||
os.remove(i.replace('.epub', '.mobi') + '_toclean')
|
saferRemove(i.replace('.epub', '.mobi') + '_toclean')
|
||||||
if k.path and k.coverSupport:
|
if k.path and k.coverSupport:
|
||||||
options.covers[filepath.index(i)][0].saveToKindle(k, options.covers[filepath.index(i)][1])
|
options.covers[filepath.index(i)][0].saveToKindle(k, options.covers[filepath.index(i)][1])
|
||||||
return filepath
|
return filepath
|
||||||
|
|
||||||
|
|
||||||
def makeMOBIFix(item, uuid):
|
def makeMOBIFix(item, uuid):
|
||||||
os.remove(item)
|
saferRemove(item)
|
||||||
mobiPath = item.replace('.epub', '.mobi')
|
mobiPath = item.replace('.epub', '.mobi')
|
||||||
move(mobiPath, mobiPath + '_toclean')
|
move(mobiPath, mobiPath + '_toclean')
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ from shutil import rmtree, copytree, move
|
|||||||
from optparse import OptionParser, OptionGroup
|
from optparse import OptionParser, OptionGroup
|
||||||
from multiprocessing import Pool
|
from multiprocessing import Pool
|
||||||
from PIL import Image, ImageStat, ImageOps
|
from PIL import Image, ImageStat, ImageOps
|
||||||
from .shared import getImageFileName, walkLevel, walkSort
|
from .shared import getImageFileName, walkLevel, walkSort, saferRemove
|
||||||
try:
|
try:
|
||||||
from PyQt5 import QtCore
|
from PyQt5 import QtCore
|
||||||
except ImportError:
|
except ImportError:
|
||||||
@@ -77,7 +77,7 @@ def mergeDirectory(work):
|
|||||||
img = ImageOps.fit(img, (targetWidth, img.size[1]), method=Image.BICUBIC, centering=(0.5, 0.5))
|
img = ImageOps.fit(img, (targetWidth, img.size[1]), method=Image.BICUBIC, centering=(0.5, 0.5))
|
||||||
result.paste(img, (0, y))
|
result.paste(img, (0, y))
|
||||||
y += img.size[1]
|
y += img.size[1]
|
||||||
os.remove(i)
|
saferRemove(i)
|
||||||
savePath = os.path.split(imagesValid[0])
|
savePath = os.path.split(imagesValid[0])
|
||||||
result.save(os.path.join(savePath[0], os.path.splitext(savePath[1])[0] + '.png'), 'PNG')
|
result.save(os.path.join(savePath[0], os.path.splitext(savePath[1])[0] + '.png'), 'PNG')
|
||||||
except Exception:
|
except Exception:
|
||||||
@@ -203,7 +203,7 @@ def splitImage(work):
|
|||||||
targetHeight += panels[panel][2]
|
targetHeight += panels[panel][2]
|
||||||
newPage.save(os.path.join(path, fileExpanded[0] + '-' + str(pageNumber) + '.png'), 'PNG')
|
newPage.save(os.path.join(path, fileExpanded[0] + '-' + str(pageNumber) + '.png'), 'PNG')
|
||||||
pageNumber += 1
|
pageNumber += 1
|
||||||
os.remove(filePath)
|
saferRemove(filePath)
|
||||||
except Exception:
|
except Exception:
|
||||||
return str(sys.exc_info()[1])
|
return str(sys.exc_info()[1])
|
||||||
|
|
||||||
@@ -275,7 +275,7 @@ def main(argv=None, qtGUI=None):
|
|||||||
pagenumber += 1
|
pagenumber += 1
|
||||||
work.append([root, name, options])
|
work.append([root, name, options])
|
||||||
else:
|
else:
|
||||||
os.remove(os.path.join(root, name))
|
saferRemove(os.path.join(root, name))
|
||||||
if GUI:
|
if GUI:
|
||||||
GUI.progressBarTick.emit('Splitting images')
|
GUI.progressBarTick.emit('Splitting images')
|
||||||
GUI.progressBarTick.emit(str(pagenumber))
|
GUI.progressBarTick.emit(str(pagenumber))
|
||||||
|
|||||||
228
kcc/image.py
228
kcc/image.py
@@ -1,5 +1,6 @@
|
|||||||
# Copyright (C) 2010 Alex Yatskov
|
# Copyright (C) 2010 Alex Yatskov
|
||||||
# Copyright (C) 2011 Stanislav (proDOOMman) Kosolapov <prodoomman@gmail.com>
|
# Copyright (C) 2011 Stanislav (proDOOMman) Kosolapov <prodoomman@gmail.com>
|
||||||
|
# Copyright (c) 2016 Alberto Planas <aplanas@gmail.com>
|
||||||
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||||
# Copyright (c) 2013-2016 Pawel Jastrzebski <pawelj@iosphe.re>
|
# Copyright (c) 2013-2016 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
#
|
#
|
||||||
@@ -20,7 +21,7 @@ import os
|
|||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from urllib.request import Request, urlopen
|
from urllib.request import Request, urlopen
|
||||||
from urllib.parse import quote
|
from urllib.parse import quote
|
||||||
from PIL import Image, ImageOps, ImageStat, ImageChops
|
from PIL import Image, ImageOps, ImageStat, ImageChops, ImageFilter
|
||||||
from .shared import md5Checksum
|
from .shared import md5Checksum
|
||||||
from . import __version__
|
from . import __version__
|
||||||
|
|
||||||
@@ -77,20 +78,21 @@ class ProfileData:
|
|||||||
]
|
]
|
||||||
|
|
||||||
Profiles = {
|
Profiles = {
|
||||||
'K1': ("Kindle 1", (600, 670), Palette4, 1.8, (900, 1005)),
|
'K1': ("Kindle 1", (600, 670), Palette4, 1.8),
|
||||||
'K2': ("Kindle 2", (600, 670), Palette15, 1.8, (900, 1005)),
|
'K2': ("Kindle 2", (600, 670), Palette15, 1.8),
|
||||||
'K3': ("Kindle", (600, 800), Palette16, 1.8, (900, 1200)),
|
'K3': ("Kindle", (600, 800), Palette16, 1.8),
|
||||||
'K45': ("Kindle", (600, 800), Palette16, 1.8, (900, 1200)),
|
'K45': ("Kindle", (600, 800), Palette16, 1.8),
|
||||||
'KDX': ("Kindle DX/DXG", (824, 1000), Palette16, 1.8, (1236, 1500)),
|
'KDX': ("Kindle DX/DXG", (824, 1000), Palette16, 1.8),
|
||||||
'KPW': ("Kindle Paperwhite 1/2", (758, 1024), Palette16, 1.8, (1137, 1536)),
|
'KPW': ("Kindle Paperwhite 1/2", (758, 1024), Palette16, 1.8),
|
||||||
'KV': ("Kindle Paperwhite 3/Voyage/Oasis", (1072, 1448), Palette16, 1.8, (1608, 2172)),
|
'KV': ("Kindle Paperwhite 3/Voyage/Oasis", (1072, 1448), Palette16, 1.8),
|
||||||
'KoMT': ("Kobo Mini/Touch", (600, 800), Palette16, 1.8, (900, 1200)),
|
'KoMT': ("Kobo Mini/Touch", (600, 800), Palette16, 1.8),
|
||||||
'KoG': ("Kobo Glo", (768, 1024), Palette16, 1.8, (1152, 1536)),
|
'KoG': ("Kobo Glo", (768, 1024), Palette16, 1.8),
|
||||||
'KoGHD': ("Kobo Glo HD", (1072, 1448), Palette16, 1.8, (1608, 2172)),
|
'KoGHD': ("Kobo Glo HD", (1072, 1448), Palette16, 1.8),
|
||||||
'KoA': ("Kobo Aura", (758, 1024), Palette16, 1.8, (1137, 1536)),
|
'KoA': ("Kobo Aura", (758, 1024), Palette16, 1.8),
|
||||||
'KoAHD': ("Kobo Aura HD", (1080, 1440), Palette16, 1.8, (1620, 2160)),
|
'KoAHD': ("Kobo Aura HD", (1080, 1440), Palette16, 1.8),
|
||||||
'KoAH2O': ("Kobo Aura H2O", (1080, 1430), Palette16, 1.8, (1620, 2145)),
|
'KoAH2O': ("Kobo Aura H2O", (1080, 1430), Palette16, 1.8),
|
||||||
'OTHER': ("Other", (0, 0), Palette16, 1.8, (0, 0)),
|
'KoAO': ("Kobo Aura ONE", (1404, 1872), Palette16, 1.8),
|
||||||
|
'OTHER': ("Other", (0, 0), Palette16, 1.8),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -104,8 +106,6 @@ class ComicPageParser:
|
|||||||
self.color = self.colorCheck()
|
self.color = self.colorCheck()
|
||||||
self.fill = self.fillCheck()
|
self.fill = self.fillCheck()
|
||||||
self.splitCheck()
|
self.splitCheck()
|
||||||
if self.opt.hqmode:
|
|
||||||
self.sizeCheck()
|
|
||||||
|
|
||||||
def getImageHistogram(self, image):
|
def getImageHistogram(self, image):
|
||||||
histogram = image.histogram()
|
histogram = image.histogram()
|
||||||
@@ -204,29 +204,16 @@ class ComicPageParser:
|
|||||||
else:
|
else:
|
||||||
return 'white'
|
return 'white'
|
||||||
|
|
||||||
def sizeCheck(self):
|
|
||||||
additionalPayload = []
|
|
||||||
width, height = self.image.size
|
|
||||||
dstwidth, dstheight = self.size
|
|
||||||
for work in self.payload:
|
|
||||||
if width > dstwidth and height > dstheight:
|
|
||||||
additionalPayload.append([work[0] + '+', work[1], work[2].copy(), work[3], work[4]])
|
|
||||||
self.payload = self.payload + additionalPayload
|
|
||||||
|
|
||||||
|
|
||||||
class ComicPage:
|
class ComicPage:
|
||||||
def __init__(self, mode, path, image, color, fill, options):
|
def __init__(self, mode, path, image, color, fill, options):
|
||||||
self.opt = options
|
self.opt = options
|
||||||
_, self.size, self.palette, self.gamma, self.panelviewsize = self.opt.profileData
|
_, self.size, self.palette, self.gamma = self.opt.profileData
|
||||||
self.image = image
|
self.image = image
|
||||||
self.color = color
|
self.color = color
|
||||||
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])
|
||||||
if '+' in mode:
|
|
||||||
self.hqMode = True
|
|
||||||
else:
|
|
||||||
self.hqMode = False
|
|
||||||
if 'N' in mode:
|
if 'N' in mode:
|
||||||
self.targetPath = os.path.join(path[0], os.path.splitext(path[1])[0]) + '-KCC'
|
self.targetPath = os.path.join(path[0], os.path.splitext(path[1])[0]) + '-KCC'
|
||||||
elif 'R' in mode:
|
elif 'R' in mode:
|
||||||
@@ -246,8 +233,6 @@ class ComicPage:
|
|||||||
flags.append('Rotated')
|
flags.append('Rotated')
|
||||||
if self.fill != 'white':
|
if self.fill != 'white':
|
||||||
flags.append('BlackFill')
|
flags.append('BlackFill')
|
||||||
if self.hqMode:
|
|
||||||
self.targetPath += '-HQ'
|
|
||||||
if self.opt.forcepng:
|
if self.opt.forcepng:
|
||||||
self.targetPath += '.png'
|
self.targetPath += '.png'
|
||||||
self.image.save(self.targetPath, 'PNG', optimize=1)
|
self.image.save(self.targetPath, 'PNG', optimize=1)
|
||||||
@@ -281,128 +266,69 @@ class ComicPage:
|
|||||||
self.image = self.image.quantize(palette=palImg)
|
self.image = self.image.quantize(palette=palImg)
|
||||||
|
|
||||||
def resizeImage(self):
|
def resizeImage(self):
|
||||||
if self.hqMode:
|
if self.image.size[0] <= self.size[0] and self.image.size[1] <= self.size[1]:
|
||||||
size = (self.panelviewsize[0], self.panelviewsize[1])
|
method = Image.BICUBIC
|
||||||
if self.image.size[0] > size[0] or self.image.size[1] > size[1]:
|
|
||||||
self.image.thumbnail(size, Image.LANCZOS)
|
|
||||||
else:
|
else:
|
||||||
size = (self.size[0], self.size[1])
|
method = Image.LANCZOS
|
||||||
if self.image.size[0] <= size[0] and self.image.size[1] <= size[1]:
|
if self.opt.stretch:
|
||||||
method = Image.BICUBIC
|
self.image = self.image.resize(self.size, method)
|
||||||
|
elif self.image.size[0] <= self.size[0] and self.image.size[1] <= self.size[1] and not self.opt.upscale:
|
||||||
|
if self.opt.format == 'CBZ':
|
||||||
|
borderw = int((self.size[0] - self.image.size[0]) / 2)
|
||||||
|
borderh = int((self.size[1] - self.image.size[1]) / 2)
|
||||||
|
self.image = ImageOps.expand(self.image, border=(borderw, borderh), fill=self.fill)
|
||||||
|
if self.image.size[0] != self.size[0] or self.image.size[1] != self.size[1]:
|
||||||
|
self.image = ImageOps.fit(self.image, self.size, method=Image.BICUBIC, centering=(0.5, 0.5))
|
||||||
|
else:
|
||||||
|
if self.opt.format == 'CBZ':
|
||||||
|
ratioDev = float(self.size[0]) / float(self.size[1])
|
||||||
|
if (float(self.image.size[0]) / float(self.image.size[1])) < ratioDev:
|
||||||
|
diff = int(self.image.size[1] * ratioDev) - self.image.size[0]
|
||||||
|
self.image = ImageOps.expand(self.image, border=(int(diff / 2), 0), fill=self.fill)
|
||||||
|
elif (float(self.image.size[0]) / float(self.image.size[1])) > ratioDev:
|
||||||
|
diff = int(self.image.size[0] / ratioDev) - self.image.size[1]
|
||||||
|
self.image = ImageOps.expand(self.image, border=(0, int(diff / 2)), fill=self.fill)
|
||||||
|
self.image = ImageOps.fit(self.image, self.size, method=method, centering=(0.5, 0.5))
|
||||||
else:
|
else:
|
||||||
method = Image.LANCZOS
|
hpercent = self.size[1] / float(self.image.size[1])
|
||||||
if self.opt.stretch:
|
wsize = int((float(self.image.size[0]) * float(hpercent)))
|
||||||
self.image = self.image.resize(size, method)
|
self.image = self.image.resize((wsize, self.size[1]), method)
|
||||||
elif self.image.size[0] <= size[0] and self.image.size[1] <= size[1] and not self.opt.upscale:
|
if self.image.size[0] > self.size[0] or self.image.size[1] > self.size[1]:
|
||||||
if self.opt.format == 'CBZ':
|
self.image.thumbnail(self.size, Image.LANCZOS)
|
||||||
borderw = int((size[0] - self.image.size[0]) / 2)
|
|
||||||
borderh = int((size[1] - self.image.size[1]) / 2)
|
|
||||||
self.image = ImageOps.expand(self.image, border=(borderw, borderh), fill=self.fill)
|
|
||||||
if self.image.size[0] != size[0] or self.image.size[1] != size[1]:
|
|
||||||
self.image = ImageOps.fit(self.image, size, method=Image.BICUBIC, centering=(0.5, 0.5))
|
|
||||||
else:
|
|
||||||
if self.opt.format == 'CBZ':
|
|
||||||
ratioDev = float(size[0]) / float(size[1])
|
|
||||||
if (float(self.image.size[0]) / float(self.image.size[1])) < ratioDev:
|
|
||||||
diff = int(self.image.size[1] * ratioDev) - self.image.size[0]
|
|
||||||
self.image = ImageOps.expand(self.image, border=(int(diff / 2), 0), fill=self.fill)
|
|
||||||
elif (float(self.image.size[0]) / float(self.image.size[1])) > ratioDev:
|
|
||||||
diff = int(self.image.size[0] / ratioDev) - self.image.size[1]
|
|
||||||
self.image = ImageOps.expand(self.image, border=(0, int(diff / 2)), fill=self.fill)
|
|
||||||
self.image = ImageOps.fit(self.image, size, method=method, centering=(0.5, 0.5))
|
|
||||||
else:
|
|
||||||
hpercent = size[1] / float(self.image.size[1])
|
|
||||||
wsize = int((float(self.image.size[0]) * float(hpercent)))
|
|
||||||
self.image = self.image.resize((wsize, size[1]), method)
|
|
||||||
if self.image.size[0] > size[0] or self.image.size[1] > size[1]:
|
|
||||||
self.image.thumbnail(size, Image.LANCZOS)
|
|
||||||
|
|
||||||
def cutPageNumber(self, fixedThreshold):
|
def getBoundingBox(self, tmpImg):
|
||||||
if ImageChops.invert(self.image).getbbox() is not None:
|
min_margin = [int(0.005 * i + 0.5) for i in tmpImg.size]
|
||||||
widthImg, heightImg = self.image.size
|
max_margin = [int(0.1 * i + 0.5) for i in tmpImg.size]
|
||||||
delta = 2
|
bbox = tmpImg.getbbox()
|
||||||
diff = delta
|
bbox = (
|
||||||
if ImageStat.Stat(self.image).var[0] < 2 * fixedThreshold:
|
max(0, min(max_margin[0], bbox[0] - min_margin[0])),
|
||||||
return self.image
|
max(0, min(max_margin[1], bbox[1] - min_margin[1])),
|
||||||
while ImageStat.Stat(self.image.crop((0, heightImg - diff, widthImg, heightImg))).var[0] < fixedThreshold\
|
min(tmpImg.size[0],
|
||||||
and diff < heightImg:
|
max(tmpImg.size[0] - max_margin[0], bbox[2] + min_margin[0])),
|
||||||
diff += delta
|
min(tmpImg.size[1],
|
||||||
diff -= delta
|
max(tmpImg.size[1] - max_margin[1], bbox[3] + min_margin[1])),
|
||||||
pageNumberCut1 = diff
|
)
|
||||||
if diff < delta:
|
return bbox
|
||||||
diff = delta
|
|
||||||
oldStat = ImageStat.Stat(self.image.crop((0, heightImg - diff, widthImg, heightImg))).var[0]
|
|
||||||
diff += delta
|
|
||||||
while ImageStat.Stat(self.image.crop((0, heightImg - diff, widthImg, heightImg))).var[0] - oldStat > 0\
|
|
||||||
and diff < heightImg // 4:
|
|
||||||
oldStat = ImageStat.Stat(self.image.crop((0, heightImg - diff, widthImg, heightImg))).var[0]
|
|
||||||
diff += delta
|
|
||||||
diff -= delta
|
|
||||||
pageNumberCut2 = diff
|
|
||||||
diff += delta
|
|
||||||
oldStat = ImageStat.Stat(self.image.crop((0, heightImg - diff, widthImg,
|
|
||||||
heightImg - pageNumberCut2))).var[0]
|
|
||||||
while ImageStat.Stat(self.image.crop((0, heightImg - diff, widthImg, heightImg - pageNumberCut2))).var[0]\
|
|
||||||
< fixedThreshold + oldStat and diff < heightImg // 4:
|
|
||||||
diff += delta
|
|
||||||
diff -= delta
|
|
||||||
pageNumberCut3 = diff
|
|
||||||
delta = 5
|
|
||||||
diff = delta
|
|
||||||
while ImageStat.Stat(self.image.crop((0, heightImg - pageNumberCut2, diff, heightImg))).var[0]\
|
|
||||||
< fixedThreshold and diff < widthImg:
|
|
||||||
diff += delta
|
|
||||||
diff -= delta
|
|
||||||
pageNumberX1 = diff
|
|
||||||
diff = delta
|
|
||||||
while ImageStat.Stat(self.image.crop((widthImg - diff, heightImg - pageNumberCut2,
|
|
||||||
widthImg, heightImg))).var[0] < fixedThreshold and diff < widthImg:
|
|
||||||
diff += delta
|
|
||||||
diff -= delta
|
|
||||||
pageNumberX2 = widthImg - diff
|
|
||||||
if pageNumberCut3 - pageNumberCut1 > 2 * delta\
|
|
||||||
and float(pageNumberX2 - pageNumberX1) / float(pageNumberCut2 - pageNumberCut1) <= 9.0\
|
|
||||||
and ImageStat.Stat(self.image.crop((0, heightImg - pageNumberCut3, widthImg, heightImg))).var[0]\
|
|
||||||
/ ImageStat.Stat(self.image).var[0] < 0.1\
|
|
||||||
and pageNumberCut3 < heightImg / 4 - delta:
|
|
||||||
diff = pageNumberCut3
|
|
||||||
else:
|
|
||||||
diff = pageNumberCut1
|
|
||||||
self.image = self.image.crop((0, 0, widthImg, heightImg - diff))
|
|
||||||
|
|
||||||
def cropWhiteSpace(self, fixedThreshold):
|
def cropPageNumber(self, power):
|
||||||
if ImageChops.invert(self.image).getbbox() is not None:
|
if self.fill != 'white':
|
||||||
widthImg, heightImg = self.image.size
|
tmpImg = self.image.convert(mode='L')
|
||||||
delta = 10
|
else:
|
||||||
diff = delta
|
tmpImg = ImageOps.invert(self.image.convert(mode='L'))
|
||||||
# top
|
tmpImg = tmpImg.point(lambda x: x and 255)
|
||||||
while ImageStat.Stat(self.image.crop((0, 0, widthImg, diff))).var[0] < fixedThreshold and diff < heightImg:
|
tmpImg = tmpImg.filter(ImageFilter.MinFilter(size=3))
|
||||||
diff += delta
|
tmpImg = tmpImg.filter(ImageFilter.GaussianBlur(radius=5))
|
||||||
diff -= delta
|
tmpImg = tmpImg.point(lambda x: (x >= 48 * power) and x)
|
||||||
self.image = self.image.crop((0, diff, widthImg, heightImg))
|
self.image = self.image.crop(tmpImg.getbbox()) if tmpImg.getbbox() else self.image
|
||||||
widthImg, heightImg = self.image.size
|
|
||||||
diff = delta
|
def cropMargin(self, power):
|
||||||
# left
|
if self.fill != 'white':
|
||||||
while ImageStat.Stat(self.image.crop((0, 0, diff, heightImg))).var[0] < fixedThreshold and diff < widthImg:
|
tmpImg = self.image.convert(mode='L')
|
||||||
diff += delta
|
else:
|
||||||
diff -= delta
|
tmpImg = ImageOps.invert(self.image.convert(mode='L'))
|
||||||
self.image = self.image.crop((diff, 0, widthImg, heightImg))
|
tmpImg = tmpImg.filter(ImageFilter.GaussianBlur(radius=3))
|
||||||
widthImg, heightImg = self.image.size
|
tmpImg = tmpImg.point(lambda x: (x >= 16 * power) and x)
|
||||||
diff = delta
|
self.image = self.image.crop(self.getBoundingBox(tmpImg)) if tmpImg.getbbox() else self.image
|
||||||
# down
|
|
||||||
while ImageStat.Stat(self.image.crop((0, heightImg - diff, widthImg, heightImg))).var[0] < fixedThreshold\
|
|
||||||
and diff < heightImg:
|
|
||||||
diff += delta
|
|
||||||
diff -= delta
|
|
||||||
self.image = self.image.crop((0, 0, widthImg, heightImg - diff))
|
|
||||||
widthImg, heightImg = self.image.size
|
|
||||||
diff = delta
|
|
||||||
# right
|
|
||||||
while ImageStat.Stat(self.image.crop((widthImg - diff, 0, widthImg, heightImg))).var[0] < fixedThreshold\
|
|
||||||
and diff < widthImg:
|
|
||||||
diff += delta
|
|
||||||
diff -= delta
|
|
||||||
self.image = self.image.crop((0, 0, widthImg - diff, heightImg))
|
|
||||||
|
|
||||||
|
|
||||||
class Cover:
|
class Cover:
|
||||||
|
|||||||
@@ -144,8 +144,7 @@ def removeFromZIP(zipfname, *filenames):
|
|||||||
|
|
||||||
def sanitizeTrace(traceback):
|
def sanitizeTrace(traceback):
|
||||||
return ''.join(format_tb(traceback))\
|
return ''.join(format_tb(traceback))\
|
||||||
.replace('C:\\Users\\pawel\\Documents\\Projekty\\KCC\\', '') \
|
.replace('C:\\Users\\Pawel\\Documents\\Projekty\\KCC\\', '') \
|
||||||
.replace('C:\\Users\\Paweł\\Documents\\Projekty\\KCC\\', '') \
|
|
||||||
.replace('C:\\Python35\\', '')\
|
.replace('C:\\Python35\\', '')\
|
||||||
.replace('c:\\python35\\', '')
|
.replace('c:\\python35\\', '')
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ Name=Kindle Comic Converter
|
|||||||
GenericName=Kindle Comic Converter
|
GenericName=Kindle Comic Converter
|
||||||
Comment=Comic and Manga converter for e-book readers
|
Comment=Comic and Manga converter for e-book readers
|
||||||
Icon=/usr/share/kindlecomicconverter/comic2ebook.png
|
Icon=/usr/share/kindlecomicconverter/comic2ebook.png
|
||||||
Exec=/usr/bin/kcc
|
Exec=/usr/bin/kcc %f
|
||||||
Terminal=false
|
Terminal=false
|
||||||
Categories=Graphics;
|
Categories=Graphics;
|
||||||
MimeType=application/zip;application/x-rar;application/x-7z-compressed;
|
MimeType=application/zip;application/x-rar;application/x-7z-compressed;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>MacOS/Kindle Comic Converter</string>
|
<string>MacOS/Kindle Comic Converter</string>
|
||||||
<key>CFBundleGetInfoString</key>
|
<key>CFBundleGetInfoString</key>
|
||||||
<string>KindleComicConverter 5.1, written 2012-2016 by Ciro Mattia Gonano and Pawel Jastrzebski</string>
|
<string>KindleComicConverter 5.2, written 2012-2016 by Ciro Mattia Gonano and Pawel Jastrzebski</string>
|
||||||
<key>CFBundleIconFile</key>
|
<key>CFBundleIconFile</key>
|
||||||
<string>comic2ebook.icns</string>
|
<string>comic2ebook.icns</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
@@ -21,11 +21,11 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>5.1</string>
|
<string>5.2.0</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>5.1</string>
|
<string>5.2.0</string>
|
||||||
<key>LSEnvironment</key>
|
<key>LSEnvironment</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>PATH</key>
|
<key>PATH</key>
|
||||||
|
|||||||
Reference in New Issue
Block a user