mirror of
https://github.com/ciromattia/kcc
synced 2026-04-15 13:38:46 +00:00
Compare commits
179 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eab63a0f74 | ||
|
|
2128104db7 | ||
|
|
c6179b0064 | ||
|
|
1d4319be2e | ||
|
|
f5a738e2d4 | ||
|
|
477d834a91 | ||
|
|
c8698f6d99 | ||
|
|
0988601842 | ||
|
|
57e9637c81 | ||
|
|
a7440e06a9 | ||
|
|
a9ed1e7610 | ||
|
|
b1bc140ad3 | ||
|
|
9014ed53d4 | ||
|
|
cad05904f3 | ||
|
|
10386d8af3 | ||
|
|
c991feb9ce | ||
|
|
d26eb7cdcd | ||
|
|
351084b703 | ||
|
|
e861e7f6e8 | ||
|
|
370c9d4df7 | ||
|
|
8e5704683c | ||
|
|
c65e1c8dea | ||
|
|
677622c103 | ||
|
|
af0ebb85a0 | ||
|
|
8af029ac92 | ||
|
|
a268e12a90 | ||
|
|
d621335e6c | ||
|
|
ec1d9c2d93 | ||
|
|
85b9dbbf83 | ||
|
|
feeced44bf | ||
|
|
cbea18398b | ||
|
|
4c9857f14d | ||
|
|
6b58ef4557 | ||
|
|
24d697c965 | ||
|
|
8b07d4eb69 | ||
|
|
e6c5ac915f | ||
|
|
b22e4757a3 | ||
|
|
91b06016bb | ||
|
|
5631391245 | ||
|
|
c33887b7b7 | ||
|
|
8d82f58f09 | ||
|
|
36985f5169 | ||
|
|
9d190c1585 | ||
|
|
3834850317 | ||
|
|
84fc23b979 | ||
|
|
77748afdbd | ||
|
|
431e2ffaf2 | ||
|
|
16df4cd083 | ||
|
|
1aa34347c1 | ||
|
|
561af90b06 | ||
|
|
00d239e1d8 | ||
|
|
26bd2d3ed0 | ||
|
|
e7aa49b70c | ||
|
|
da41edc2f1 | ||
|
|
ecbf60fb28 | ||
|
|
57b571b6c2 | ||
|
|
44bdc0245b | ||
|
|
1ec07fe4ec | ||
|
|
5f8f7e0919 | ||
|
|
f404b9090d | ||
|
|
68521f7c63 | ||
|
|
f5dd813c4c | ||
|
|
7924c492b3 | ||
|
|
2fc21c33e2 | ||
|
|
cb76504acb | ||
|
|
db6b0eddfe | ||
|
|
7d529a2acc | ||
|
|
ad3ff35aaa | ||
|
|
c62eeeb712 | ||
|
|
5a36a13105 | ||
|
|
12684d6562 | ||
|
|
c5f68ae12a | ||
|
|
7bd9c766cc | ||
|
|
c6b1417d9c | ||
|
|
98bf28a713 | ||
|
|
f2d6d5b458 | ||
|
|
5de492ffb6 | ||
|
|
5c2c6ed825 | ||
|
|
c2730ab01c | ||
|
|
bfba66d47d | ||
|
|
b5bc2f8e00 | ||
|
|
917eaef548 | ||
|
|
3187ebb054 | ||
|
|
b9276e9ede | ||
|
|
147d815057 | ||
|
|
180123fee2 | ||
|
|
2768e622f2 | ||
|
|
b629b45d46 | ||
|
|
f66c83425c | ||
|
|
68b4b7114d | ||
|
|
36f8c82eaf | ||
|
|
bd665c3261 | ||
|
|
94586fa590 | ||
|
|
89806dfcfc | ||
|
|
c9eb73ab90 | ||
|
|
2edcc0369a | ||
|
|
bc0a52b848 | ||
|
|
5ae72bf06d | ||
|
|
24c32643c1 | ||
|
|
40b988f964 | ||
|
|
ac794eff85 | ||
|
|
eaa387a9d6 | ||
|
|
d0f5d6dac4 | ||
|
|
b174534c1c | ||
|
|
19d486a4ee | ||
|
|
652762b709 | ||
|
|
e6df87f8fd | ||
|
|
1a9cd0beb5 | ||
|
|
108e351126 | ||
|
|
dfe3e10470 | ||
|
|
787ad9fa66 | ||
|
|
f10e8869a9 | ||
|
|
715ada328f | ||
|
|
56f23ab488 | ||
|
|
996af59e00 | ||
|
|
37aa84c4aa | ||
|
|
50574632e6 | ||
|
|
0afb9e8c0b | ||
|
|
7511c7eed6 | ||
|
|
836a4146f9 | ||
|
|
15a240ccea | ||
|
|
0722ddf8b0 | ||
|
|
b3159b94e7 | ||
|
|
ef5207c990 | ||
|
|
db77d89817 | ||
|
|
4571fadadb | ||
|
|
94f56238ae | ||
|
|
5efb5d6dbb | ||
|
|
623f615dd9 | ||
|
|
39fbbc42b3 | ||
|
|
99405ab8a6 | ||
|
|
aadfca8306 | ||
|
|
5450502c2a | ||
|
|
c976b06413 | ||
|
|
b6facda95b | ||
|
|
3f608eb602 | ||
|
|
104cd04994 | ||
|
|
b323204628 | ||
|
|
56195d301d | ||
|
|
287723ca6f | ||
|
|
90490149c7 | ||
|
|
2210f484df | ||
|
|
d5502e85b0 | ||
|
|
59b26cfc8b | ||
|
|
a722e5fa49 | ||
|
|
fce3072dca | ||
|
|
f53cdf9cd7 | ||
|
|
de74318c69 | ||
|
|
b137e69510 | ||
|
|
888663fa4c | ||
|
|
8a2ba96ac5 | ||
|
|
cb6b0e0a7b | ||
|
|
49d2a7fbab | ||
|
|
3d84b27d58 | ||
|
|
e98a23d0c0 | ||
|
|
7f80dacea8 | ||
|
|
6efb3dcef3 | ||
|
|
942a828b7e | ||
|
|
df5ee1badf | ||
|
|
e3ab28642d | ||
|
|
a1831c45d5 | ||
|
|
52bea9957a | ||
|
|
a71339ec34 | ||
|
|
c5f09c44b8 | ||
|
|
64b199ef74 | ||
|
|
8dd0b0e694 | ||
|
|
181a2e8ab4 | ||
|
|
3fdff845b7 | ||
|
|
2ee5dc310b | ||
|
|
f32e9560b5 | ||
|
|
621827c1c2 | ||
|
|
dc312f36c2 | ||
|
|
4573ff6ec2 | ||
|
|
d77498405b | ||
|
|
e491fca445 | ||
|
|
d22ee1a488 | ||
|
|
7ebcccd8a2 | ||
|
|
9a691c3c63 | ||
|
|
2b04a0298e |
27
KCC.qrc
27
KCC.qrc
@@ -1,27 +0,0 @@
|
|||||||
<RCC>
|
|
||||||
<qresource prefix="Icon">
|
|
||||||
<file>icons/comic2ebook.png</file>
|
|
||||||
</qresource>
|
|
||||||
<qresource prefix="Devices">
|
|
||||||
<file>icons/Kobo.png</file>
|
|
||||||
<file>icons/Other.png</file>
|
|
||||||
<file>icons/Kindle.png</file>
|
|
||||||
</qresource>
|
|
||||||
<qresource prefix="Formats">
|
|
||||||
<file>icons/CBZ.png</file>
|
|
||||||
<file>icons/EPUB.png</file>
|
|
||||||
<file>icons/MOBI.png</file>
|
|
||||||
</qresource>
|
|
||||||
<qresource prefix="Status">
|
|
||||||
<file>icons/error.png</file>
|
|
||||||
<file>icons/info.png</file>
|
|
||||||
<file>icons/warning.png</file>
|
|
||||||
</qresource>
|
|
||||||
<qresource prefix="Other">
|
|
||||||
<file>icons/list_background.png</file>
|
|
||||||
<file>icons/clear.png</file>
|
|
||||||
<file>icons/convert.png</file>
|
|
||||||
<file>icons/document_new.png</file>
|
|
||||||
<file>icons/folder_new.png</file>
|
|
||||||
</qresource>
|
|
||||||
</RCC>
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
ISC LICENSE
|
ISC LICENSE
|
||||||
|
|
||||||
Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||||
Copyright (c) 2013-2014 Paweł Jastrzębski <pawelj@vulturis.eu>
|
Copyright (c) 2013-2015 Paweł Jastrzębski <pawelj@iosphe.re>
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for
|
Permission to use, copy, modify, and/or distribute this software for
|
||||||
any purpose with or without fee is hereby granted, provided that the
|
any purpose with or without fee is hereby granted, provided that the
|
||||||
|
|||||||
542
README.md
542
README.md
@@ -1,60 +1,61 @@
|
|||||||
# KCC
|
# KCC
|
||||||
|
|
||||||
**Kindle Comic Converter** is a Python app to convert comic files or folders to ePub, Panel View MOBI or E-Ink optimized CBZ.
|
**Kindle Comic Converter** is a Python app to convert comic/manga files or folders to EPUB, Panel View MOBI or E-Ink optimized CBZ.
|
||||||
It was initally developed for Kindle but since v2.2 it outputs valid ePub 2.0 so _**despite its name, KCC is
|
It was initially developed for Kindle but since version 4.6 it outputs valid EPUB 3.0 so _**despite its name, KCC is
|
||||||
actually a comic to EPUB converter that every e-reader owner can happily use**_.
|
actually a comic/manga to EPUB converter that every e-reader owner can happily use**_.
|
||||||
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 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 ;-)
|
||||||
|
|
||||||
### Issues / new features / donations
|
### Issues / new features / donations
|
||||||
If you have general questions about usage, feedback etc. please [post it here](http://www.mobileread.com/forums/showthread.php?t=207461).
|
If you have general questions about usage, feedback etc. please [post it here](http://www.mobileread.com/forums/showthread.php?t=207461).
|
||||||
If you have some **technical** problems using KCC please [file an issue here](https://github.com/ciromattia/kcc/issues/new).
|
If you have some **technical** problems using KCC please [file an issue here](https://github.com/ciromattia/kcc/issues/new).
|
||||||
If you can fix an open issue, fork & make a pull request.
|
If you can fix an open issue, fork & make a pull request.
|
||||||
If you want more chances an issue is fixes or your wanted feature added, consider [placing a bounty](https://www.bountysource.com/trackers/65571-ciromattia-kcc)!
|
|
||||||
|
|
||||||
If you find **KCC** valuable you can consider donating to the authors:
|
If you find **KCC** valuable you can consider donating to the authors:
|
||||||
* Ciro Mattia Gonano: [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=D8WNYNPBGDAS2) [](http://flattr.com/thing/2260449/ciromattiakcc-on-GitHub)
|
- Ciro Mattia Gonano:
|
||||||
* Paweł Jastrzębski: [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=YTTJ4LK2JDHPS) [](bitcoin:1W15wwqsfd7wbaZ6wvSJf1LW1bz6q5L8b?label=KCC) [1W15wwqsfd7wbaZ6wvSJf1LW1bz6q5L8b](bitcoin:1W15wwqsfd7wbaZ6wvSJf1LW1bz6q5L8b?label=KCC)
|
- [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=D8WNYNPBGDAS2)
|
||||||
|
- [](http://flattr.com/thing/2260449/ciromattiakcc-on-GitHub)
|
||||||
|
- Paweł Jastrzębski:
|
||||||
|
- [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=YTTJ4LK2JDHPS)
|
||||||
|
- Bitcoin: 1W15wwqsfd7wbaZ6wvSJf1LW1bz6q5L8b
|
||||||
|
|
||||||
## BINARY RELEASES
|
## BINARY RELEASES
|
||||||
You can find the latest released binary at the following links:
|
You can find the latest released binary at the following links:
|
||||||
- **Windows:** [http://kcc.vulturis.eu/Windows/](http://kcc.vulturis.eu/Windows/)
|
- **Windows (Vista or newer):** [http://kcc.iosphe.re/Windows/](http://kcc.iosphe.re/Windows/)
|
||||||
- **Linux:** [http://kcc.vulturis.eu/Linux/](http://kcc.vulturis.eu/Linux/)
|
- **Linux:** [http://kcc.iosphe.re/Linux/](http://kcc.iosphe.re/Linux/)
|
||||||
- **OS X (10.8+):** [http://kcc.vulturis.eu/OSX/](http://kcc.vulturis.eu/OSX/)
|
- **OS X (10.8+):** [http://kcc.iosphe.re/OSX/](http://kcc.iosphe.re/OSX/)
|
||||||
|
|
||||||
## INPUT FORMATS
|
## DEPENDENCIES
|
||||||
**KCC** can understand and convert, at the moment, the following input types:
|
Following software is required to run Linux version of **KCC** and/or bare sources:
|
||||||
- Folders containing: PNG, JPG, GIF, TIFF or BMP files
|
- Python 3.3+
|
||||||
- CBZ, ZIP
|
- [PyQt](http://www.riverbankcomputing.co.uk/software/pyqt/download5) 5.4.0+
|
||||||
- CBR, RAR *(With `unrar` executable)*
|
- [Pillow](http://pypi.python.org/pypi/Pillow/) 2.8.2+
|
||||||
- CB7, 7Z *(With `7za` executable)*
|
- [psutil](https://pypi.python.org/pypi/psutil) 3.0.0+
|
||||||
- PDF *(Extracting only contained JPG images)*
|
- [python-slugify](http://pypi.python.org/pypi/python-slugify) 1.1.3+
|
||||||
|
- [scandir](https://pypi.python.org/pypi/scandir) 1.1.0+
|
||||||
|
|
||||||
## OPTIONAL REQUIREMENTS
|
On Debian based distributions these two commands should install all needed dependencies:
|
||||||
|
```
|
||||||
|
sudo apt-get install python3 python3-dev python3-pip python3-pyqt5 libpng-dev libjpeg-dev p7zip-full unrar
|
||||||
|
sudo pip3 install pillow python-slugify psutil scandir
|
||||||
|
```
|
||||||
|
|
||||||
|
### Optional dependencies
|
||||||
- [KindleGen](http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000765211) v2.9+ in a directory reachable by your _PATH_ or in _KCC_ directory *(For MOBI generation)*
|
- [KindleGen](http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000765211) v2.9+ in a directory reachable by your _PATH_ or in _KCC_ directory *(For MOBI generation)*
|
||||||
- [UnRAR](http://www.rarlab.com/download.htm) *(For CBR/RAR support)*
|
- [UnRAR](http://www.rarlab.com/download.htm) *(For CBR/RAR support)*
|
||||||
- [7za](http://www.7-zip.org/download.html) *(For 7z/CB7 support)*
|
- [7za](http://www.7-zip.org/download.html) *(For 7z/CB7 support)*
|
||||||
|
|
||||||
### For running from source:
|
## INPUT FORMATS
|
||||||
- Python 3.3
|
**KCC** can understand and convert, at the moment, the following input types:
|
||||||
- [PyQt5](http://www.riverbankcomputing.co.uk/software/pyqt/download5)
|
- Folders containing: PNG, JPG or GIF files
|
||||||
- [Pillow](http://pypi.python.org/pypi/Pillow/) 2.3.0+
|
- CBZ, ZIP
|
||||||
- [psutil](https://pypi.python.org/pypi/psutil)
|
- CBR, RAR *(With `unrar` executable)*
|
||||||
- [python-slugify](http://pypi.python.org/pypi/python-slugify)
|
- CB7, 7Z *(With `7za` executable)*
|
||||||
|
- PDF *(Only extracting JPG images)*
|
||||||
On Debian based distributions these two commands should install all dependencies:
|
|
||||||
```
|
|
||||||
sudo apt-get install python3 python3-dev python3-pip python3-pyqt5 libtiff-dev libpng-dev libjpeg-dev p7zip-full unrar
|
|
||||||
sudo pip3 install pillow python-slugify psutil
|
|
||||||
```
|
|
||||||
|
|
||||||
### For freezing code:
|
|
||||||
- Windows - [cx_Freeze](https://bitbucket.org/anthony_tuininga/cx_freeze) version 4.3.2 with [this](https://bitbucket.org/anthony_tuininga/cx_freeze/pull-request/29/conversions-to-support-untranslated-wide) patchset.
|
|
||||||
- OS X - [py2app](https://bitbucket.org/ronaldoussoren/py2app) HEAD version.
|
|
||||||
|
|
||||||
## USAGE
|
## USAGE
|
||||||
|
|
||||||
@@ -63,15 +64,18 @@ After completed conversion you should find ready file alongside the original inp
|
|||||||
|
|
||||||
Please check [our wiki](https://github.com/ciromattia/kcc/wiki/) for more details.
|
Please check [our wiki](https://github.com/ciromattia/kcc/wiki/) for more details.
|
||||||
|
|
||||||
### Standalone `comic2ebook.py` usage:
|
CLI version of **KCC** is intended for power users. It is not idiot-proof like GUI :-)
|
||||||
|
|
||||||
|
### Standalone `kcc-c2e.py` usage:
|
||||||
|
|
||||||
```
|
```
|
||||||
Usage: comic2ebook.py [options] comic_file|comic_folder
|
Usage: kcc-c2e [options] comic_file|comic_folder
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
MAIN:
|
MAIN:
|
||||||
-p PROFILE, --profile=PROFILE
|
-p PROFILE, --profile=PROFILE
|
||||||
Device profile (Choose one among K1, K2, K345, KDX, KHD, KF, KFHD, KFHD8, KFHDX, KFHDX8, KFA, KoMT, KoG, KoA, KoAHD) [Default=KHD]
|
Device profile (Available options: K1, K2, K345, KDX,
|
||||||
|
KPW, KV, KoMT, KoG, KoGHD, KoA, KoAHD, KoAH2O) [Default=KV]
|
||||||
-q QUALITY, --quality=QUALITY
|
-q QUALITY, --quality=QUALITY
|
||||||
Quality of Panel View. 0 - Normal 1 - High 2 - Ultra [Default=0]
|
Quality of Panel View. 0 - Normal 1 - High 2 - Ultra [Default=0]
|
||||||
-m, --manga-style Manga style (Right-to-left reading and splitting)
|
-m, --manga-style Manga style (Right-to-left reading and splitting)
|
||||||
@@ -82,7 +86,9 @@ Options:
|
|||||||
Output generated file to specified directory or file
|
Output generated file to specified directory or file
|
||||||
-t TITLE, --title=TITLE
|
-t TITLE, --title=TITLE
|
||||||
Comic title [Default=filename or directory name]
|
Comic title [Default=filename or directory name]
|
||||||
--cbz-output Outputs a CBZ archive and does not generate EPUB
|
-f FORMAT, --format=FORMAT
|
||||||
|
Output format (Available options: Auto, MOBI,
|
||||||
|
EPUB, CBZ) [Default=Auto]
|
||||||
--batchsplit Split output into multiple files
|
--batchsplit Split output into multiple files
|
||||||
|
|
||||||
PROCESSING:
|
PROCESSING:
|
||||||
@@ -108,10 +114,10 @@ Options:
|
|||||||
-h, --help Show this help message and exit
|
-h, --help Show this help message and exit
|
||||||
```
|
```
|
||||||
|
|
||||||
### Standalone `comic2panel.py` usage:
|
### Standalone `kcc-c2p.py` usage:
|
||||||
|
|
||||||
```
|
```
|
||||||
Usage: comic2panel.py [options] comic_folder
|
Usage: kcc-c2p [options] comic_folder
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
MANDATORY:
|
MANDATORY:
|
||||||
@@ -126,138 +132,184 @@ Options:
|
|||||||
```
|
```
|
||||||
|
|
||||||
## CREDITS
|
## CREDITS
|
||||||
**KCC** is made by [Ciro Mattia Gonano](http://github.com/ciromattia) and [Paweł Jastrzębski](http://github.com/AcidWeb)
|
**KCC** is made by [Ciro Mattia Gonano](http://github.com/ciromattia) and [Paweł Jastrzębski](http://github.com/AcidWeb).
|
||||||
|
|
||||||
This script born as a cross-platform alternative to `KindleComicParser` by **Dc5e** (published [here](http://www.mobileread.com/forums/showthread.php?t=192783))
|
This script born as a cross-platform alternative to `KindleComicParser` by **Dc5e** (published [here](http://www.mobileread.com/forums/showthread.php?t=192783)).
|
||||||
|
|
||||||
The app relies and includes the following scripts/binaries:
|
The app relies and includes the following scripts:
|
||||||
|
|
||||||
- `KindleUnpack` script by Charles **M. Hannum, P. Durrant, K. Hendricks, S. Siebert, fandrieu, DiapDealer, nickredding**. Released with GPLv3 License.
|
- `DualMetaFix` script by **K. Hendricks**. Released with GPL-3 License.
|
||||||
- `rarfile.py` script © 2005-2011 **Marko Kreen** <markokr@gmail.com>. Released with ISC License.
|
- `rarfile.py` script © 2005-2014 **Marko Kreen** <markokr@gmail.com>. Released with ISC License.
|
||||||
- `image.py` class from **Alex Yatskov**'s [Mangle](http://foosoft.net/mangle/) with subsequent [proDOOMman](https://github.com/proDOOMman/Mangle)'s and [Birua](https://github.com/Birua/Mangle)'s patches.
|
- `image.py` class from **Alex Yatskov**'s [Mangle](https://github.com/FooSoft/mangle/) with subsequent [proDOOMman](https://github.com/proDOOMman/Mangle)'s and [Birua](https://github.com/Birua/Mangle)'s patches.
|
||||||
- Icon is by **Nikolay Verin** ([http://ncrow.deviantart.com/](http://ncrow.deviantart.com/)) and released under [CC BY-NC-SA 3.0](http://creativecommons.org/licenses/by-nc-sa/3.0/) License.
|
- Icon is by **Nikolay Verin** ([http://ncrow.deviantart.com/](http://ncrow.deviantart.com/)) and released under [CC BY-NC-SA 3.0](http://creativecommons.org/licenses/by-nc-sa/3.0/) License.
|
||||||
|
|
||||||
## SAMPLE FILES CREATED BY KCC
|
## SAMPLE FILES CREATED BY KCC
|
||||||
* [Kindle Paperwhite](http://kcc.vulturis.eu/Samples/Ubunchu!-KPW.mobi)
|
* [Kindle Paperwhite 3 / Voyage](http://kcc.iosphe.re/Samples/Ubunchu!-KV.mobi)
|
||||||
* [Kindle](http://kcc.vulturis.eu/Samples/Ubunchu!-K345.mobi)
|
* [Kindle Paperwhite 1 / 2](http://kcc.iosphe.re/Samples/Ubunchu!-KPW.mobi)
|
||||||
* [Kindle DX/DXG](http://kcc.vulturis.eu/Samples/Ubunchu!-KDX.mobi)
|
* [Kindle](http://kcc.iosphe.re/Samples/Ubunchu!-K345.mobi)
|
||||||
* [Kindle Fire HD](http://kcc.vulturis.eu/Samples/Ubunchu!-KFHD.mobi)
|
* [Kindle DX/DXG](http://kcc.iosphe.re/Samples/Ubunchu!-KDX.cbz)
|
||||||
* [Kindle Fire HD 8.9"](http://kcc.vulturis.eu/Samples/Ubunchu!-KFHD8.mobi)
|
* [Kobo Mini/Touch](http://kcc.iosphe.re/Samples/Ubunchu-KoMT.kepub.epub)
|
||||||
* [Kindle Fire HDX](http://kcc.vulturis.eu/Samples/Ubunchu!-KFHDX.mobi)
|
* [Kobo Glo](http://kcc.iosphe.re/Samples/Ubunchu-KoG.kepub.epub)
|
||||||
* [Kindle Fire HDX 8.9"](http://kcc.vulturis.eu/Samples/Ubunchu!-KFHDX8.mobi)
|
* [Kobo Glo HD](http://kcc.iosphe.re/Samples/Ubunchu-KoGHD.kepub.epub)
|
||||||
* [Kobo Mini/Touch](http://kcc.vulturis.eu/Samples/Ubunchu!-KoMT.cbz)
|
* [Kobo Aura](http://kcc.iosphe.re/Samples/Ubunchu-KoA.kepub.epub)
|
||||||
* [Kobo Glow](http://kcc.vulturis.eu/Samples/Ubunchu!-KoG.cbz)
|
* [Kobo Aura HD](http://kcc.iosphe.re/Samples/Ubunchu-KoAHD.kepub.epub)
|
||||||
* [Kobo Aura](http://kcc.vulturis.eu/Samples/Ubunchu!-KoA.cbz)
|
* [Kobo Aura H2O](http://kcc.iosphe.re/Samples/Ubunchu-KoAH2O.kepub.epub)
|
||||||
* [Kobo Aura HD](http://kcc.vulturis.eu/Samples/Ubunchu!-KoAHD.cbz)
|
|
||||||
|
|
||||||
## CHANGELOG
|
## CHANGELOG
|
||||||
####1.0
|
####4.6.4:
|
||||||
* Initial version
|
* Fixed multiple Windows specific problems
|
||||||
|
|
||||||
####1.1
|
|
||||||
* Added support for CBZ/CBR files in comic2ebook.py
|
|
||||||
|
|
||||||
####1.1.1
|
|
||||||
* Added support for CBZ/CBR files in Kindle Comic Converter
|
|
||||||
|
|
||||||
####1.2
|
|
||||||
* Comic optimizations! Split pages not target-oriented (landscape with portrait target or portrait with landscape target), add palette and other image optimizations from Mangle. WARNING: PIL is required for all image mangling!
|
|
||||||
|
|
||||||
####1.3
|
|
||||||
* Fixed an issue in OPF generation for device resolution
|
|
||||||
* Reworked options system (call with -h option to get the inline help)
|
|
||||||
|
|
||||||
####1.4
|
|
||||||
* Added some options for controlling image optimization
|
|
||||||
* Further optimization (ImageOps, page numbering cut, autocontrast)
|
|
||||||
|
|
||||||
####1.4.1
|
|
||||||
* Fixed a serious bug on resizing when img ratio was bigger than device one
|
|
||||||
|
|
||||||
####1.5
|
|
||||||
* Added subfolder support for multiple chapters.
|
|
||||||
|
|
||||||
####2.0
|
|
||||||
* GUI! AppleScript is gone and Tk is used to provide cross-platform GUI support.
|
|
||||||
|
|
||||||
####2.1
|
|
||||||
* Added basic error reporting
|
|
||||||
|
|
||||||
####2.2:
|
|
||||||
* Added (valid!) ePub 2.0 output
|
|
||||||
* Rename .zip files to .cbz to avoid overwriting
|
|
||||||
|
|
||||||
####2.3
|
|
||||||
* Fixed win32 ePub generation, folder handling, filenames with spaces and subfolders
|
|
||||||
|
|
||||||
####2.4
|
|
||||||
* Use temporary directory as workdir (fixes converting from external volumes and zipfiles renaming)
|
|
||||||
* Fixed "add folders" from GUI.
|
|
||||||
|
|
||||||
####2.5
|
|
||||||
* Added --black-borders option to set added borders black when page's ratio is not the device's one (#11).
|
|
||||||
* Fixes epub containing zipped itself (#10)
|
|
||||||
|
|
||||||
####2.6
|
|
||||||
* Added --rotate option to rotate landscape images instead of splitting them (#16, #24)
|
|
||||||
* Added --output option to customize ePub output dir/file (#22)
|
|
||||||
* Add rendition:layout and rendition:orientation ePub meta tags (supported by new kindlegen 2.8)
|
|
||||||
* Fixed natural sorting for files (#18)
|
|
||||||
|
|
||||||
####2.7
|
|
||||||
* Lots of GUI improvements (#27, #13)
|
|
||||||
* Added gamma support within --gamma option (defaults to profile-specified gamma) (#26, #27)
|
|
||||||
* Added --nodithering option to prevent dithering optimizations (#27)
|
|
||||||
* Epub margins support (#30)
|
|
||||||
* Fixed no file added if file has no spaces on Windows (#25)
|
|
||||||
* Gracefully exit if unrar missing (#15)
|
|
||||||
* Do not call kindlegen if source epub is bigger than 320MB (#17)
|
|
||||||
* Get filetype from magic number (#14)
|
|
||||||
* PDF conversion works again
|
|
||||||
|
|
||||||
####2.8
|
|
||||||
* Updated rarfile library
|
|
||||||
* Panel View support + HQ support (#36) - new option: --nopanelviewhq
|
|
||||||
* Split profiles for K4NT and K4T
|
|
||||||
* Rewrite of Landscape Mode support (huge readability improvement for KPW)
|
|
||||||
* Upscale use now BILINEAR method
|
|
||||||
* Added generic CSS file
|
|
||||||
* Optimized archive extraction for zip/rar files (#40)
|
|
||||||
|
|
||||||
####2.9
|
|
||||||
* Added support for generating a plain CBZ (skipping all the EPUB/Mobi generation) (#45)
|
|
||||||
* Prevent output file overwriting the source one: if a duplicate name is detected, append _kcc to the name
|
|
||||||
* Rarfile library updated to 2.6
|
|
||||||
* Added GIF, TIFF and BMP to supported formats (#42)
|
|
||||||
* Filenames slugifications (#28, #31, #9, #8)
|
|
||||||
|
|
||||||
####2.10:
|
|
||||||
* Multiprocessing support
|
|
||||||
* Kindle Fire support (color ePub/Mobi)
|
|
||||||
* Panel View support for horizontal content
|
|
||||||
* Fixed panel order for horizontal pages when --rotate is enabled
|
|
||||||
* Disabled cropping and page number cutting for blank pages
|
|
||||||
* Fixed some slugify issues with specific file naming conventions (#50, #51)
|
|
||||||
|
|
||||||
####3.0:
|
|
||||||
* New QT GUI
|
|
||||||
* Merge with AWKCC
|
|
||||||
* Added ultra quality mode
|
|
||||||
* Added support for custom width/height
|
|
||||||
* Added option to disable color conversion
|
|
||||||
|
|
||||||
####3.1:
|
|
||||||
* Added profile: Kindle for Android
|
|
||||||
* Add file/directory dialogs now support multiselect
|
|
||||||
* Many small fixes and tweaks
|
|
||||||
|
|
||||||
####3.2:
|
|
||||||
* Too big EPUB files are now splitted before conversion to MOBI
|
|
||||||
* Added experimental parser of manga webtoons
|
|
||||||
* Improved error handling
|
* Improved error handling
|
||||||
|
* Improved color detection algorithm
|
||||||
|
* New, slimmer OS X release
|
||||||
|
|
||||||
####3.2.1:
|
####4.6.3:
|
||||||
* Hotfixed crash occurring on OS with Russian locale
|
* Implemented remote bug reporting
|
||||||
|
* Minor bug fixes and GUI tweaks
|
||||||
|
|
||||||
|
####4.6.2:
|
||||||
|
* Fixed critical MOBI header bug
|
||||||
|
* Fixed metadata encoding error
|
||||||
|
|
||||||
|
####4.6.1:
|
||||||
|
* Fixed KEPUB TOC generator
|
||||||
|
* Added warning about too small input files
|
||||||
|
* ComicRack Summary metadata field is now parsed
|
||||||
|
* Small tweaks of KEPUB output
|
||||||
|
|
||||||
|
####4.6:
|
||||||
|
* KEPUB is now default output for all Kobo profiles
|
||||||
|
* EPUB output now produce fully valid EPUB 3.0.1
|
||||||
|
* Added profile for Kindle Paperwhite 3
|
||||||
|
* Dropped official support of all Kindle Fire models and Kindle for Android
|
||||||
|
* Other minor tweaks
|
||||||
|
|
||||||
|
####4.5.1:
|
||||||
|
* Added Kobo Glo HD profile
|
||||||
|
* Fixed RAR/CBR parsing anomalies
|
||||||
|
* Minor bug fixes and tweaks
|
||||||
|
|
||||||
|
####4.5:
|
||||||
|
* Added simple ComicRack metadata editor
|
||||||
|
* Re-enabled Manga Cover Database support
|
||||||
|
* ComicRack bookmarks are now parsed
|
||||||
|
* Fixed glitches in Kindle Voyage profile
|
||||||
|
* Fixed problems with directory locks on Windows
|
||||||
|
* Fixed sorting anomalies
|
||||||
|
* Improved conversion speed
|
||||||
|
|
||||||
|
####4.4.1:
|
||||||
|
* Fixed problems with OSX GUI
|
||||||
|
* Added one missing DLL to Windows installer
|
||||||
|
|
||||||
|
####4.4:
|
||||||
|
* Improved speed and quality of conversion
|
||||||
|
* Added RAR5 support
|
||||||
|
* Dropped BMP and TIFF support
|
||||||
|
* Fixed some WebToon mode bugs
|
||||||
|
* Fixed CBR parsing on OSX
|
||||||
|
|
||||||
|
####4.3.1:
|
||||||
|
* Fixed Kindle Voyage profile
|
||||||
|
* Fixed some bugs in OS X release
|
||||||
|
* CLI version now support multiple input files at once
|
||||||
|
* Disabled MCB support
|
||||||
|
* Other minor tweaks
|
||||||
|
|
||||||
|
####4.3:
|
||||||
|
* Added profiles for Kindle Voyage and Kobo Aura H2O
|
||||||
|
* Added missing features to CLI version
|
||||||
|
* Other minor bug fixes
|
||||||
|
|
||||||
|
####4.2.1:
|
||||||
|
* Improved margin color detection
|
||||||
|
* Fixed random crashes of MOBI processing step
|
||||||
|
* Fixed resizing problems in high quality mode
|
||||||
|
* Fixed some MCD support bugs
|
||||||
|
* Default output format for Kindle DX is now CBZ
|
||||||
|
|
||||||
|
####4.2:
|
||||||
|
* Added [Manga Cover Database](http://manga.joentjuh.nl/) support
|
||||||
|
* Officially dropped Windows XP support
|
||||||
|
* Fixed _Other_ profile
|
||||||
|
* Fixed problems with page order on stock KOBO CBZ reader
|
||||||
|
* Many other small bug fixes and tweaks
|
||||||
|
|
||||||
|
####4.1:
|
||||||
|
* Thanks to code contributed by Kevin Hendricks speed of MOBI creation was greatly increased
|
||||||
|
* Improved performance on Windows
|
||||||
|
* Improved MOBI splitting and changed maximal size of output file
|
||||||
|
* Fixed _No optimization_ mode
|
||||||
|
* Multiple small tweaks nad minor bug fixes
|
||||||
|
|
||||||
|
####4.0.2:
|
||||||
|
* Fixed some Windows and OSX specific bugs
|
||||||
|
* Fixed problem with marigns when using HQ mode
|
||||||
|
|
||||||
|
####4.0.1:
|
||||||
|
* Fixed file lock problems that plagued some Windows users
|
||||||
|
* Fixed content server failing to start on Windows
|
||||||
|
* Improved performance of WebToon splitter
|
||||||
|
* Tweaked margin color detection
|
||||||
|
|
||||||
|
####4.0:
|
||||||
|
* KCC now use Python 3.3 and Qt 5.2
|
||||||
|
* Full UTF-8 awareness
|
||||||
|
* CBZ output now support Manga mode
|
||||||
|
* Improved Panel View support and margin color detection
|
||||||
|
* Added drag&drop support
|
||||||
|
* Output directory can be now selected
|
||||||
|
* Windows release now have auto-updater
|
||||||
|
* Names of chapters on Kindle should be now more user friendly
|
||||||
|
* Fixed OSX file association support
|
||||||
|
* Many extensive internal changes and tweaks
|
||||||
|
|
||||||
|
####3.7.2:
|
||||||
|
* Fixed problems with HQ mode
|
||||||
|
|
||||||
|
####3.7.1:
|
||||||
|
* Hotfixed Kobo profiles
|
||||||
|
|
||||||
|
####3.7:
|
||||||
|
* Added profiles for KOBO devices
|
||||||
|
* Improved Panel View support
|
||||||
|
* Improved WebToon splitter
|
||||||
|
* Improved margin color autodetection
|
||||||
|
* Tweaked EPUB output
|
||||||
|
* Fixed stretching option
|
||||||
|
* GUI tweaks and minor bugfixes
|
||||||
|
|
||||||
|
####3.6.2:
|
||||||
|
* Fixed previous PNG output fix
|
||||||
|
* Fixed Panel View anomalies
|
||||||
|
|
||||||
|
####3.6.1:
|
||||||
|
* Fixed PNG output
|
||||||
|
|
||||||
|
####3.6:
|
||||||
|
* Increased quality of Panel View zoom
|
||||||
|
* Creation of multipart MOBI output is now faster on machines with 4GB+ RAM
|
||||||
|
* Automatic gamma correction now distinguishes color and grayscale images
|
||||||
|
* Added ComicRack metadata parser
|
||||||
|
* Implemented new method to detect border color in non-webtoon comics
|
||||||
|
* Upscaling is now enabled by default for Kindle Fire HD/HDX
|
||||||
|
* Windows nad Linux releases now have tray icon
|
||||||
|
* Fixed Kindle Fire HDX 7" output
|
||||||
|
* Increased target resolution for Kindle DX/DXG CBZ output
|
||||||
|
|
||||||
|
####3.5:
|
||||||
|
* Added simple content server - Converted files can be now delivered wireless
|
||||||
|
* Added proper Windows installer
|
||||||
|
* Improved multiprocessing speed
|
||||||
|
* GUI tweaks and minor bug fixes
|
||||||
|
|
||||||
|
####3.4:
|
||||||
|
* Improved PNG output
|
||||||
|
* Increased quality of upscaling
|
||||||
|
* Added support of file association - KCC can now open CBZ, CBR, CB7, ZIP, RAR, 7Z and PDF files directly
|
||||||
|
* Paths that contain UTF-8 characters are now supported
|
||||||
|
* Migrated to new version of Pillow library
|
||||||
|
* Merged DX and DXG profiles
|
||||||
|
* Many other minor bug fixes and GUI tweaks
|
||||||
|
|
||||||
####3.3:
|
####3.3:
|
||||||
* Margins are now automatically omitted in Panel View mode
|
* Margins are now automatically omitted in Panel View mode
|
||||||
@@ -273,75 +325,125 @@ The app relies and includes the following scripts/binaries:
|
|||||||
* Windows release is now bundled with UnRAR and 7za
|
* Windows release is now bundled with UnRAR and 7za
|
||||||
* Small GUI tweaks
|
* Small GUI tweaks
|
||||||
|
|
||||||
####3.4:
|
####3.2:
|
||||||
* Improved PNG output
|
* Too big EPUB files are now splitted before conversion to MOBI
|
||||||
* Increased quality of upscaling
|
* Added experimental parser of manga webtoons
|
||||||
* Added support of file association - KCC can now open CBZ, CBR, CB7, ZIP, RAR, 7Z and PDF files directly
|
* Improved error handling
|
||||||
* Paths that contain UTF-8 characters are now supported
|
|
||||||
* Migrated to new version of Pillow library
|
|
||||||
* Merged DX and DXG profiles
|
|
||||||
* Many other minor bug fixes and GUI tweaks
|
|
||||||
|
|
||||||
####3.5:
|
####3.2.1:
|
||||||
* Added simple content server - Converted files can be now delivered wireless
|
* Hotfixed crash occurring on OS with Russian locale
|
||||||
* Added proper Windows installer
|
|
||||||
* Improved multiprocessing speed
|
|
||||||
* GUI tweaks and minor bug fixes
|
|
||||||
|
|
||||||
####3.6:
|
####3.1:
|
||||||
* Increased quality of Panel View zoom
|
* Added profile: Kindle for Android
|
||||||
* Creation of multipart MOBI output is now faster on machines with 4GB+ RAM
|
* Add file/directory dialogs now support multiselect
|
||||||
* Automatic gamma correction now distinguishes color and grayscale images
|
* Many small fixes and tweaks
|
||||||
* Added ComicRack metadata parser
|
|
||||||
* Implemented new method to detect border color in non-webtoon comics
|
|
||||||
* Upscaling is now enabled by default for Kindle Fire HD/HDX
|
|
||||||
* Windows nad Linux releases now have tray icon
|
|
||||||
* Fixed Kindle Fire HDX 7" output
|
|
||||||
* Increased target resolution for Kindle DX/DXG CBZ output
|
|
||||||
|
|
||||||
####3.6.1:
|
####3.0:
|
||||||
* Fixed PNG output
|
* New QT GUI
|
||||||
|
* Merge with AWKCC
|
||||||
|
* Added ultra quality mode
|
||||||
|
* Added support for custom width/height
|
||||||
|
* Added option to disable color conversion
|
||||||
|
|
||||||
####3.6.2:
|
####2.10:
|
||||||
* Fixed previous PNG output fix
|
* Multiprocessing support
|
||||||
* Fixed Panel View anomalies
|
* Kindle Fire support (color EPUB/MOBI)
|
||||||
|
* Panel View support for horizontal content
|
||||||
|
* Fixed panel order for horizontal pages when --rotate is enabled
|
||||||
|
* Disabled cropping and page number cutting for blank pages
|
||||||
|
* Fixed some slugify issues with specific file naming conventions (#50, #51)
|
||||||
|
|
||||||
####3.7:
|
####2.9
|
||||||
* Added profiles for KOBO devices
|
* Added support for generating a plain CBZ (skipping all the EPUB/MOBI generation) (#45)
|
||||||
* Improved Panel View support
|
* Prevent output file overwriting the source one: if a duplicate name is detected, append _kcc to the name
|
||||||
* Improved WebToon splitter
|
* Rarfile library updated to 2.6
|
||||||
* Improved margin color autodetection
|
* Added GIF, TIFF and BMP to supported formats (#42)
|
||||||
* Tweaked EPUB output
|
* Filenames slugifications (#28, #31, #9, #8)
|
||||||
* Fixed stretching option
|
|
||||||
* GUI tweaks and minor bugfixes
|
|
||||||
|
|
||||||
####3.7.1:
|
####2.8
|
||||||
* Hotfixed Kobo profiles
|
* Updated rarfile library
|
||||||
|
* Panel View support + HQ support (#36) - new option: --nopanelviewhq
|
||||||
|
* Split profiles for K4NT and K4T
|
||||||
|
* Rewrite of Landscape Mode support (huge readability improvement for KPW)
|
||||||
|
* Upscale use now BILINEAR method
|
||||||
|
* Added generic CSS file
|
||||||
|
* Optimized archive extraction for zip/rar files (#40)
|
||||||
|
|
||||||
####3.7.2:
|
####2.7
|
||||||
* Fixed problems with HQ mode
|
* Lots of GUI improvements (#27, #13)
|
||||||
|
* Added gamma support within --gamma option (defaults to profile-specified gamma) (#26, #27)
|
||||||
|
* Added --nodithering option to prevent dithering optimizations (#27)
|
||||||
|
* EPUB margins support (#30)
|
||||||
|
* Fixed no file added if file has no spaces on Windows (#25)
|
||||||
|
* Gracefully exit if unrar missing (#15)
|
||||||
|
* Do not call kindlegen if source EPUB is bigger than 320MB (#17)
|
||||||
|
* Get filetype from magic number (#14)
|
||||||
|
* PDF conversion works again
|
||||||
|
|
||||||
####4.0:
|
####2.6
|
||||||
* KCC now use Python 3.3 and Qt 5.2
|
* Added --rotate option to rotate landscape images instead of splitting them (#16, #24)
|
||||||
* Full UTF-8 awareness
|
* Added --output option to customize EPUB output dir/file (#22)
|
||||||
* CBZ output now support Manga mode
|
* Add rendition:layout and rendition:orientation EPUB meta tags (supported by new kindlegen 2.8)
|
||||||
* Improved Panel View support and margin color detection
|
* Fixed natural sorting for files (#18)
|
||||||
* Added drag&drop support
|
|
||||||
* Output directory can be now selected
|
|
||||||
* Windows release now have auto-updater
|
|
||||||
* Names of chapters on Kindle should be now more user friendly
|
|
||||||
* Fixed OSX file association support
|
|
||||||
* Many extensive internal changes and tweaks
|
|
||||||
|
|
||||||
####4.0.1:
|
####2.5
|
||||||
* Fixed file lock problems that plagued some Windows users
|
* Added --black-borders option to set added borders black when page's ratio is not the device's one (#11).
|
||||||
* Fixed content server failing to start on Windows
|
* Fixes EPUB containing zipped itself (#10)
|
||||||
* Improved performance of WebToon splitter
|
|
||||||
* Tweaked margin color detection
|
####2.4
|
||||||
|
* Use temporary directory as workdir (fixes converting from external volumes and zipfiles renaming)
|
||||||
|
* Fixed "add folders" from GUI.
|
||||||
|
|
||||||
|
####2.3
|
||||||
|
* Fixed win32 EPUB generation, folder handling, filenames with spaces and subfolders
|
||||||
|
|
||||||
|
####2.2:
|
||||||
|
* Added (valid!) EPUB 2.0 output
|
||||||
|
* Rename .zip files to .cbz to avoid overwriting
|
||||||
|
|
||||||
|
####2.1
|
||||||
|
* Added basic error reporting
|
||||||
|
|
||||||
|
####2.0
|
||||||
|
* GUI! AppleScript is gone and Tk is used to provide cross-platform GUI support.
|
||||||
|
|
||||||
|
####1.5
|
||||||
|
* Added subfolder support for multiple chapters.
|
||||||
|
|
||||||
|
####1.4.1
|
||||||
|
* Fixed a serious bug on resizing when img ratio was bigger than device one
|
||||||
|
|
||||||
|
####1.4
|
||||||
|
* Added some options for controlling image optimization
|
||||||
|
* Further optimization (ImageOps, page numbering cut, autocontrast)
|
||||||
|
|
||||||
|
####1.3
|
||||||
|
* Fixed an issue in OPF generation for device resolution
|
||||||
|
* Reworked options system (call with -h option to get the inline help)
|
||||||
|
|
||||||
|
####1.2
|
||||||
|
* Comic optimizations! Split pages not target-oriented (landscape with portrait target or portrait with landscape target), add palette and other image optimizations from Mangle. WARNING: PIL is required for all image mangling!
|
||||||
|
|
||||||
|
####1.1.1
|
||||||
|
* Added support for CBZ/CBR files in Kindle Comic Converter
|
||||||
|
|
||||||
|
####1.1
|
||||||
|
* Added support for CBZ/CBR files in comic2ebook.py
|
||||||
|
|
||||||
|
####1.0
|
||||||
|
* Initial version
|
||||||
|
|
||||||
|
## PRIVACY
|
||||||
|
**KCC** is initiating internet connections in three cases:
|
||||||
|
* During startup - Version check
|
||||||
|
* When MCD metadata are used - Cover download
|
||||||
|
* When error occurs - Automatic reporting
|
||||||
|
|
||||||
|
Error report include **KCC** version, OS version and content of error message.
|
||||||
|
|
||||||
## KNOWN ISSUES
|
## KNOWN ISSUES
|
||||||
Please check [wiki page](https://github.com/ciromattia/kcc/wiki/Known-issues).
|
Please check [wiki page](https://github.com/ciromattia/kcc/wiki/Known-issues).
|
||||||
|
|
||||||
## COPYRIGHT
|
## COPYRIGHT
|
||||||
Copyright (c) 2012-2014 Ciro Mattia Gonano and Paweł Jastrzębski.
|
Copyright (c) 2012-2015 Ciro Mattia Gonano and Paweł Jastrzębski.
|
||||||
**KCC** is released under ISC LICENSE; see LICENSE.txt for further details.
|
**KCC** is released under ISC LICENSE; see LICENSE.txt for further details.
|
||||||
|
|||||||
@@ -71,7 +71,7 @@
|
|||||||
<enum>Qt::NoFocus</enum>
|
<enum>Qt::NoFocus</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p style='white-space:pre'>Disable image optimizations.<br/>Input images must be already resized.</p></body></html></string>
|
<string><html><head/><body><p style='white-space:pre'>Disable image optimizations.<br/><span style=" font-weight:600;">Input images must be already resized.</span></p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>No optimisation</string>
|
<string>No optimisation</string>
|
||||||
@@ -110,7 +110,7 @@
|
|||||||
<enum>Qt::NoFocus</enum>
|
<enum>Qt::NoFocus</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p style='white-space:pre'>Enable auto-splitting of webtoons like <span style=" font-style:italic;">Tower of God</span> or <span style=" font-style:italic;">Noblesse</span>.<br/>Pages with a low width, high height and vertical panel flow.</p></body></html></string>
|
<string><html><head/><body><p style='white-space:pre'>Enable special parsing mode for WebToons.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Webtoon mode</string>
|
<string>Webtoon mode</string>
|
||||||
@@ -167,7 +167,7 @@
|
|||||||
<enum>Qt::NoFocus</enum>
|
<enum>Qt::NoFocus</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p style='white-space:pre'>Disable splitting and rotation.</p></body></html></string>
|
<string><html><head/><body><p style='white-space:pre'>Disable page splitting and rotation.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>No split/rotate</string>
|
<string>No split/rotate</string>
|
||||||
@@ -241,7 +241,7 @@
|
|||||||
<enum>Qt::NoFocus</enum>
|
<enum>Qt::NoFocus</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p style='white-space:pre'>Shift+Click to select the output directory.</p></body></html></string>
|
<string><html><head/><body><p style='white-space:pre'>Shift+Click to select the output directory.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Convert</string>
|
<string>Convert</string>
|
||||||
@@ -269,6 +269,9 @@
|
|||||||
<property name="focusPolicy">
|
<property name="focusPolicy">
|
||||||
<enum>Qt::NoFocus</enum>
|
<enum>Qt::NoFocus</enum>
|
||||||
</property>
|
</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">
|
<property name="text">
|
||||||
<string>Add directory</string>
|
<string>Add directory</string>
|
||||||
</property>
|
</property>
|
||||||
@@ -295,6 +298,9 @@
|
|||||||
<property name="focusPolicy">
|
<property name="focusPolicy">
|
||||||
<enum>Qt::NoFocus</enum>
|
<enum>Qt::NoFocus</enum>
|
||||||
</property>
|
</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">
|
<property name="text">
|
||||||
<string>Add file</string>
|
<string>Add file</string>
|
||||||
</property>
|
</property>
|
||||||
@@ -386,7 +392,7 @@
|
|||||||
<enum>Qt::NoFocus</enum>
|
<enum>Qt::NoFocus</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p><span style=" font-weight:600; text-decoration: underline;">Unchecked - Normal quality mode<br/></span><span style=" font-style:italic;">Use it when Panel View support is not needed.<br/></span>- Maximum quality when zoom is not enabled.<br/>- Poor quality when zoom is enabled.<br/>- Lowest file size.</p><p><span style=" font-weight:600; text-decoration: underline;">Indeterminate - High quality mode<br/></span><span style=" font-style:italic;">Not zoomed images </span><span style=" font-weight:600; font-style:italic;">might</span><span style=" font-style:italic;"> be blurry.<br/></span>- High quality when zoom is not enabled.<br/>- Maximum quality when zoom is enabled.</p><p><span style=" font-weight:600; text-decoration: underline;">Checked - Ultra quality mode<br/></span><span style=" font-style:italic;">Maximum possible quality.<br/></span>- Maximum quality when zoom is not enabled.<br/>- Maximum quality when zoom is enabled.<br/>- Very high file size.</p></body></html></string>
|
<string><html><head/><body><p style='white-space:pre'>Quality of Panel View/zoom. Highly impact size of output file.<br/><span style=" font-weight:600;">This option control only quality of magnification!</span></p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>High/Ultra quality</string>
|
<string>High/Ultra quality</string>
|
||||||
@@ -457,19 +463,13 @@
|
|||||||
<height>18</height>
|
<height>18</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="verticalScrollMode">
|
|
||||||
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
|
||||||
</property>
|
|
||||||
<property name="horizontalScrollMode">
|
|
||||||
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
|
||||||
</property>
|
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QPushButton" name="BasicModeButton">
|
<widget class="QPushButton" name="BasicModeButton">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>10</x>
|
<x>10</x>
|
||||||
<y>10</y>
|
<y>10</y>
|
||||||
<width>195</width>
|
<width>141</width>
|
||||||
<height>32</height>
|
<height>32</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
@@ -489,9 +489,9 @@
|
|||||||
<widget class="QPushButton" name="AdvModeButton">
|
<widget class="QPushButton" name="AdvModeButton">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>217</x>
|
<x>260</x>
|
||||||
<y>10</y>
|
<y>10</y>
|
||||||
<width>195</width>
|
<width>151</width>
|
||||||
<height>32</height>
|
<height>32</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
@@ -661,7 +661,7 @@
|
|||||||
</font>
|
</font>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p>Resolution of target device.</p></body></html></string>
|
<string><html><head/><body><p style='white-space:pre'>Resolution of target device.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Custom width: </string>
|
<string>Custom width: </string>
|
||||||
@@ -694,7 +694,7 @@
|
|||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p>Resolution of target device.</p></body></html></string>
|
<string><html><head/><body><p style='white-space:pre'>Resolution of target device.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="inputMask">
|
<property name="inputMask">
|
||||||
<string>0000</string>
|
<string>0000</string>
|
||||||
@@ -712,7 +712,7 @@
|
|||||||
</font>
|
</font>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p>Resolution of target device.</p></body></html></string>
|
<string><html><head/><body><p style='white-space:pre'>Resolution of target device.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Custom height: </string>
|
<string>Custom height: </string>
|
||||||
@@ -745,7 +745,7 @@
|
|||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p>Resolution of target device.</p></body></html></string>
|
<string><html><head/><body><p style='white-space:pre'>Resolution of target device.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="inputMask">
|
<property name="inputMask">
|
||||||
<string>0000</string>
|
<string>0000</string>
|
||||||
@@ -758,6 +758,32 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="QPushButton" name="EditorButton">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>160</x>
|
||||||
|
<y>10</y>
|
||||||
|
<width>91</width>
|
||||||
|
<height>32</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>DejaVu Sans</family>
|
||||||
|
<pointsize>9</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="focusPolicy">
|
||||||
|
<enum>Qt::NoFocus</enum>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Editor</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="KCC.qrc">
|
||||||
|
<normaloff>:/Other/icons/editor.png</normaloff>:/Other/icons/editor.png</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
<zorder>OptionsAdvanced</zorder>
|
<zorder>OptionsAdvanced</zorder>
|
||||||
<zorder>DeviceBox</zorder>
|
<zorder>DeviceBox</zorder>
|
||||||
<zorder>FormatBox</zorder>
|
<zorder>FormatBox</zorder>
|
||||||
@@ -771,6 +797,7 @@
|
|||||||
<zorder>AdvModeButton</zorder>
|
<zorder>AdvModeButton</zorder>
|
||||||
<zorder>OptionsAdvancedGamma</zorder>
|
<zorder>OptionsAdvancedGamma</zorder>
|
||||||
<zorder>OptionsExpert</zorder>
|
<zorder>OptionsExpert</zorder>
|
||||||
|
<zorder>EditorButton</zorder>
|
||||||
<zorder>ProgressBar</zorder>
|
<zorder>ProgressBar</zorder>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QStatusBar" name="statusBar">
|
<widget class="QStatusBar" name="statusBar">
|
||||||
@@ -69,7 +69,7 @@
|
|||||||
<enum>Qt::NoFocus</enum>
|
<enum>Qt::NoFocus</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p style='white-space:pre'>Disable image optimizations.<br/>Input images must be already resized.</p></body></html></string>
|
<string><html><head/><body><p style='white-space:pre'>Disable image optimizations.<br/><span style=" font-weight:600;">Input images must be already resized.</span></p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>No optimisation</string>
|
<string>No optimisation</string>
|
||||||
@@ -110,7 +110,7 @@
|
|||||||
<enum>Qt::NoFocus</enum>
|
<enum>Qt::NoFocus</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p style='white-space:pre'>Enable auto-splitting of webtoons like <span style=" font-style:italic;">Tower of God</span> or <span style=" font-style:italic;">Noblesse</span>.<br/>Pages with a low width, high height and vertical panel flow.</p></body></html></string>
|
<string><html><head/><body><p style='white-space:pre'>Enable special parsing mode for WebToons.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Webtoon mode</string>
|
<string>Webtoon mode</string>
|
||||||
@@ -170,7 +170,7 @@
|
|||||||
<enum>Qt::NoFocus</enum>
|
<enum>Qt::NoFocus</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p style='white-space:pre'>Disable splitting and rotation.</p></body></html></string>
|
<string><html><head/><body><p style='white-space:pre'>Disable page splitting and rotation.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>No split/rotate</string>
|
<string>No split/rotate</string>
|
||||||
@@ -220,7 +220,7 @@
|
|||||||
<enum>Qt::NoFocus</enum>
|
<enum>Qt::NoFocus</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p style='white-space:pre'>Output format.</p></body></html></string>
|
<string><html><head/><body><p style='white-space:pre'>Output format.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QPushButton" name="ConvertButton">
|
<widget class="QPushButton" name="ConvertButton">
|
||||||
@@ -244,7 +244,7 @@
|
|||||||
<enum>Qt::NoFocus</enum>
|
<enum>Qt::NoFocus</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p style='white-space:pre'>Shift+Click to select the output directory.</p></body></html></string>
|
<string><html><head/><body><p style='white-space:pre'>Shift+Click to select the output directory.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Convert</string>
|
<string>Convert</string>
|
||||||
@@ -272,6 +272,9 @@
|
|||||||
<property name="focusPolicy">
|
<property name="focusPolicy">
|
||||||
<enum>Qt::NoFocus</enum>
|
<enum>Qt::NoFocus</enum>
|
||||||
</property>
|
</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">
|
<property name="text">
|
||||||
<string>Add directory</string>
|
<string>Add directory</string>
|
||||||
</property>
|
</property>
|
||||||
@@ -298,6 +301,9 @@
|
|||||||
<property name="focusPolicy">
|
<property name="focusPolicy">
|
||||||
<enum>Qt::NoFocus</enum>
|
<enum>Qt::NoFocus</enum>
|
||||||
</property>
|
</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">
|
<property name="text">
|
||||||
<string>Add file</string>
|
<string>Add file</string>
|
||||||
</property>
|
</property>
|
||||||
@@ -391,7 +397,7 @@
|
|||||||
<enum>Qt::NoFocus</enum>
|
<enum>Qt::NoFocus</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p><span style=" font-weight:600; text-decoration: underline;">Unchecked - Normal quality mode<br/></span><span style=" font-style:italic;">Use it when Panel View support is not needed.<br/></span>- Maximum quality when zoom is not enabled.<br/>- Poor quality when zoom is enabled.<br/>- Lowest file size.</p><p><span style=" font-weight:600; text-decoration: underline;">Indeterminate - High quality mode<br/></span><span style=" font-style:italic;">Not zoomed image </span><span style=" font-weight:600; font-style:italic;">might</span><span style=" font-style:italic;"> be a little blurry.<br/></span>- High quality when zoom is not enabled.<br/>- Maximum quality when zoom is enabled.</p><p><span style=" font-weight:600; text-decoration: underline;">Checked - Ultra quality mode<br/></span><span style=" font-style:italic;">Maximum possible quality.<br/></span>- Maximum quality when zoom is not enabled.<br/>- Maximum quality when zoom is enabled.<br/>- Very high file size.</p></body></html></string>
|
<string><html><head/><body><p style='white-space:pre'>Quality of Panel View/zoom. Highly impact size of output file.<br/><span style=" font-weight:600;">This option control only quality of magnification!</span></p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>High/Ultra quality</string>
|
<string>High/Ultra quality</string>
|
||||||
@@ -468,7 +474,7 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>5</x>
|
<x>5</x>
|
||||||
<y>10</y>
|
<y>10</y>
|
||||||
<width>210</width>
|
<width>156</width>
|
||||||
<height>41</height>
|
<height>41</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
@@ -490,9 +496,9 @@
|
|||||||
<widget class="QPushButton" name="AdvModeButton">
|
<widget class="QPushButton" name="AdvModeButton">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>207</x>
|
<x>260</x>
|
||||||
<y>10</y>
|
<y>10</y>
|
||||||
<width>210</width>
|
<width>156</width>
|
||||||
<height>41</height>
|
<height>41</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
@@ -773,9 +779,34 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="QPushButton" name="EditorButton">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>160</x>
|
||||||
|
<y>10</y>
|
||||||
|
<width>101</width>
|
||||||
|
<height>41</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Lucida Grande</family>
|
||||||
|
<pointsize>12</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="focusPolicy">
|
||||||
|
<enum>Qt::NoFocus</enum>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Editor</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="KCC.qrc">
|
||||||
|
<normaloff>:/Other/icons/editor.png</normaloff>:/Other/icons/editor.png</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
<zorder>BasicModeButton</zorder>
|
<zorder>BasicModeButton</zorder>
|
||||||
<zorder>AdvModeButton</zorder>
|
<zorder>AdvModeButton</zorder>
|
||||||
<zorder>ProgressBar</zorder>
|
|
||||||
<zorder>JobList</zorder>
|
<zorder>JobList</zorder>
|
||||||
<zorder>OptionsAdvanced</zorder>
|
<zorder>OptionsAdvanced</zorder>
|
||||||
<zorder>DeviceBox</zorder>
|
<zorder>DeviceBox</zorder>
|
||||||
@@ -787,6 +818,8 @@
|
|||||||
<zorder>OptionsBasic</zorder>
|
<zorder>OptionsBasic</zorder>
|
||||||
<zorder>OptionsAdvancedGamma</zorder>
|
<zorder>OptionsAdvancedGamma</zorder>
|
||||||
<zorder>OptionsExpert</zorder>
|
<zorder>OptionsExpert</zorder>
|
||||||
|
<zorder>EditorButton</zorder>
|
||||||
|
<zorder>ProgressBar</zorder>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QStatusBar" name="statusBar">
|
<widget class="QStatusBar" name="statusBar">
|
||||||
<property name="font">
|
<property name="font">
|
||||||
28
gui/KCC.qrc
Normal file
28
gui/KCC.qrc
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<RCC>
|
||||||
|
<qresource prefix="Icon">
|
||||||
|
<file>../icons/comic2ebook.png</file>
|
||||||
|
</qresource>
|
||||||
|
<qresource prefix="Devices">
|
||||||
|
<file>../icons/Kobo.png</file>
|
||||||
|
<file>../icons/Other.png</file>
|
||||||
|
<file>../icons/Kindle.png</file>
|
||||||
|
</qresource>
|
||||||
|
<qresource prefix="Formats">
|
||||||
|
<file>../icons/CBZ.png</file>
|
||||||
|
<file>../icons/EPUB.png</file>
|
||||||
|
<file>../icons/MOBI.png</file>
|
||||||
|
</qresource>
|
||||||
|
<qresource prefix="Status">
|
||||||
|
<file>../icons/error.png</file>
|
||||||
|
<file>../icons/info.png</file>
|
||||||
|
<file>../icons/warning.png</file>
|
||||||
|
</qresource>
|
||||||
|
<qresource prefix="Other">
|
||||||
|
<file>../icons/editor.png</file>
|
||||||
|
<file>../icons/list_background.png</file>
|
||||||
|
<file>../icons/clear.png</file>
|
||||||
|
<file>../icons/convert.png</file>
|
||||||
|
<file>../icons/document_new.png</file>
|
||||||
|
<file>../icons/folder_new.png</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
||||||
@@ -65,7 +65,7 @@
|
|||||||
<enum>Qt::NoFocus</enum>
|
<enum>Qt::NoFocus</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p style='white-space:pre'>Disable image optimizations.<br/>Input images must be already resized.</p></body></html></string>
|
<string><html><head/><body><p style='white-space:pre'>Disable image optimizations.<br/><span style=" font-weight:600;">Input images must be already resized.</span></p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>No optimisation</string>
|
<string>No optimisation</string>
|
||||||
@@ -94,7 +94,7 @@
|
|||||||
<enum>Qt::NoFocus</enum>
|
<enum>Qt::NoFocus</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p style='white-space:pre'>Enable auto-splitting of webtoons like <span style=" font-style:italic;">Tower of God</span> or <span style=" font-style:italic;">Noblesse</span>.<br/>Pages with a low width, high height and vertical panel flow.</p></body></html></string>
|
<string><html><head/><body><p style='white-space:pre'>Enable special parsing mode for WebToons.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Webtoon mode</string>
|
<string>Webtoon mode</string>
|
||||||
@@ -136,7 +136,7 @@
|
|||||||
<enum>Qt::NoFocus</enum>
|
<enum>Qt::NoFocus</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p style='white-space:pre'>Disable splitting and rotation.</p></body></html></string>
|
<string><html><head/><body><p style='white-space:pre'>Disable page splitting and rotation.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>No split/rotate</string>
|
<string>No split/rotate</string>
|
||||||
@@ -234,6 +234,9 @@
|
|||||||
<property name="focusPolicy">
|
<property name="focusPolicy">
|
||||||
<enum>Qt::NoFocus</enum>
|
<enum>Qt::NoFocus</enum>
|
||||||
</property>
|
</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">
|
<property name="text">
|
||||||
<string>Add directory</string>
|
<string>Add directory</string>
|
||||||
</property>
|
</property>
|
||||||
@@ -259,6 +262,9 @@
|
|||||||
<property name="focusPolicy">
|
<property name="focusPolicy">
|
||||||
<enum>Qt::NoFocus</enum>
|
<enum>Qt::NoFocus</enum>
|
||||||
</property>
|
</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">
|
<property name="text">
|
||||||
<string>Add file</string>
|
<string>Add file</string>
|
||||||
</property>
|
</property>
|
||||||
@@ -338,7 +344,7 @@
|
|||||||
<enum>Qt::NoFocus</enum>
|
<enum>Qt::NoFocus</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string><html><head/><body><p><span style=" font-weight:600; text-decoration: underline;">Unchecked - Normal quality mode<br/></span><span style=" font-style:italic;">Use it when Panel View support is not needed.</span><span style=" font-weight:600; text-decoration: underline;"><br/></span>- Maximum quality when zoom is not enabled.<br/>- Poor quality when zoom is enabled.<br/>- Lowest file size.</p><p><span style=" font-weight:600; text-decoration: underline;">Indeterminate - High quality mode<br/></span><span style=" font-style:italic;">Not zoomed images </span><span style=" font-weight:600; font-style:italic;">might </span><span style=" font-style:italic;">be blurry.</span><span style=" font-weight:600; text-decoration: underline;"><br/></span>- High quality when zoom is not enabled.<br/>- Maximum quality when zoom is enabled.</p><p><span style=" font-weight:600; text-decoration: underline;">Checked - Ultra quality mode<br/></span><span style=" font-style:italic;">Maximum possible quality.</span><span style=" font-weight:600; text-decoration: underline;"><br/></span>- Maximum quality when zoom is not enabled.<br/>- Maximum quality when zoom is enabled.<br/>- Very high file size.</p></body></html></string>
|
<string><html><head/><body><p style='white-space:pre'>Quality of Panel View/zoom. Highly impact size of output file.<br/><span style=" font-weight:600;">This option control only quality of magnification!</span></p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>High/Ultra quality</string>
|
<string>High/Ultra quality</string>
|
||||||
@@ -403,7 +409,7 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>10</x>
|
<x>10</x>
|
||||||
<y>10</y>
|
<y>10</y>
|
||||||
<width>195</width>
|
<width>141</width>
|
||||||
<height>32</height>
|
<height>32</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
@@ -422,9 +428,9 @@
|
|||||||
<widget class="QPushButton" name="AdvModeButton">
|
<widget class="QPushButton" name="AdvModeButton">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>217</x>
|
<x>261</x>
|
||||||
<y>10</y>
|
<y>10</y>
|
||||||
<width>195</width>
|
<width>151</width>
|
||||||
<height>32</height>
|
<height>32</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
@@ -647,6 +653,31 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="QPushButton" name="EditorButton">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>160</x>
|
||||||
|
<y>10</y>
|
||||||
|
<width>91</width>
|
||||||
|
<height>32</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>9</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="focusPolicy">
|
||||||
|
<enum>Qt::NoFocus</enum>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Editor</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="KCC.qrc">
|
||||||
|
<normaloff>:/Other/icons/editor.png</normaloff>:/Other/icons/editor.png</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
<zorder>OptionsAdvanced</zorder>
|
<zorder>OptionsAdvanced</zorder>
|
||||||
<zorder>DeviceBox</zorder>
|
<zorder>DeviceBox</zorder>
|
||||||
<zorder>FormatBox</zorder>
|
<zorder>FormatBox</zorder>
|
||||||
@@ -660,6 +691,7 @@
|
|||||||
<zorder>AdvModeButton</zorder>
|
<zorder>AdvModeButton</zorder>
|
||||||
<zorder>OptionsAdvancedGamma</zorder>
|
<zorder>OptionsAdvancedGamma</zorder>
|
||||||
<zorder>OptionsExpert</zorder>
|
<zorder>OptionsExpert</zorder>
|
||||||
|
<zorder>EditorButton</zorder>
|
||||||
<zorder>ProgressBar</zorder>
|
<zorder>ProgressBar</zorder>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QStatusBar" name="statusBar">
|
<widget class="QStatusBar" name="statusBar">
|
||||||
226
gui/MetaEditor-Linux.ui
Normal file
226
gui/MetaEditor-Linux.ui
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>MetaEditorDialog</class>
|
||||||
|
<widget class="QDialog" name="MetaEditorDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>400</width>
|
||||||
|
<height>320</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>400</width>
|
||||||
|
<height>320</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>400</width>
|
||||||
|
<height>320</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Metadata editor</string>
|
||||||
|
</property>
|
||||||
|
<property name="windowIcon">
|
||||||
|
<iconset resource="KCC.qrc">
|
||||||
|
<normaloff>:/Icon/icons/comic2ebook.png</normaloff>:/Icon/icons/comic2ebook.png</iconset>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="horizontalLayoutWidget">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>10</x>
|
||||||
|
<y>280</y>
|
||||||
|
<width>381</width>
|
||||||
|
<height>31</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="StatusLabel">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>10</pointsize>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">color: rgb(255, 0, 0);</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="OKButton">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Save</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="KCC.qrc">
|
||||||
|
<normaloff>:/Other/icons/convert.png</normaloff>:/Other/icons/convert.png</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="CancelButton">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Cancel</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="KCC.qrc">
|
||||||
|
<normaloff>:/Other/icons/clear.png</normaloff>:/Other/icons/clear.png</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QFrame" name="EditorFrame">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>10</x>
|
||||||
|
<y>10</y>
|
||||||
|
<width>381</width>
|
||||||
|
<height>271</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="formLayoutWidget">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>381</width>
|
||||||
|
<height>266</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<layout class="QFormLayout" name="formLayout">
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Series:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLineEdit" name="SeriesLine"/>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Volume:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QLineEdit" name="VolumeLine"/>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>Number:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="QLineEdit" name="NumberLine"/>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="0">
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="text">
|
||||||
|
<string>Writer:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="1">
|
||||||
|
<widget class="QLineEdit" name="WriterLine"/>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="0">
|
||||||
|
<widget class="QLabel" name="label_5">
|
||||||
|
<property name="text">
|
||||||
|
<string>Penciller:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="1">
|
||||||
|
<widget class="QLineEdit" name="PencillerLine"/>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="0">
|
||||||
|
<widget class="QLabel" name="label_6">
|
||||||
|
<property name="text">
|
||||||
|
<string>Inker:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="1">
|
||||||
|
<widget class="QLineEdit" name="InkerLine"/>
|
||||||
|
</item>
|
||||||
|
<item row="7" column="0">
|
||||||
|
<widget class="QLabel" name="label_7">
|
||||||
|
<property name="text">
|
||||||
|
<string>Colorist:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="7" column="1">
|
||||||
|
<widget class="QLineEdit" name="ColoristLine"/>
|
||||||
|
</item>
|
||||||
|
<item row="8" column="0">
|
||||||
|
<widget class="QLabel" name="label_8">
|
||||||
|
<property name="text">
|
||||||
|
<string><html><head/><body><p><a href="https://github.com/ciromattia/kcc/wiki/Manga-Cover-Database-support"><span style=" text-decoration: underline; color:#0000ff;">MUid:</span></a></p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="textFormat">
|
||||||
|
<enum>Qt::RichText</enum>
|
||||||
|
</property>
|
||||||
|
<property name="openExternalLinks">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="8" column="1">
|
||||||
|
<widget class="QLineEdit" name="MUidLine"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<zorder>horizontalLayoutWidget</zorder>
|
||||||
|
<zorder>EditorFrame</zorder>
|
||||||
|
<zorder>StatusLabel</zorder>
|
||||||
|
</widget>
|
||||||
|
<resources>
|
||||||
|
<include location="KCC.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
226
gui/MetaEditor-OSX.ui
Normal file
226
gui/MetaEditor-OSX.ui
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>MetaEditorDialog</class>
|
||||||
|
<widget class="QDialog" name="MetaEditorDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>400</width>
|
||||||
|
<height>295</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>400</width>
|
||||||
|
<height>295</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>400</width>
|
||||||
|
<height>295</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Metadata editor</string>
|
||||||
|
</property>
|
||||||
|
<property name="windowIcon">
|
||||||
|
<iconset resource="KCC.qrc">
|
||||||
|
<normaloff>:/Icon/icons/comic2ebook.png</normaloff>:/Icon/icons/comic2ebook.png</iconset>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="horizontalLayoutWidget">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>10</x>
|
||||||
|
<y>260</y>
|
||||||
|
<width>381</width>
|
||||||
|
<height>32</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="StatusLabel">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<pointsize>10</pointsize>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">color: rgb(255, 0, 0);</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="OKButton">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Save</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="KCC.qrc">
|
||||||
|
<normaloff>:/Other/icons/convert.png</normaloff>:/Other/icons/convert.png</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="CancelButton">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Cancel</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="KCC.qrc">
|
||||||
|
<normaloff>:/Other/icons/clear.png</normaloff>:/Other/icons/clear.png</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QFrame" name="EditorFrame">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>10</x>
|
||||||
|
<y>10</y>
|
||||||
|
<width>381</width>
|
||||||
|
<height>251</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="formLayoutWidget">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>381</width>
|
||||||
|
<height>250</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<layout class="QFormLayout" name="formLayout">
|
||||||
|
<property name="fieldGrowthPolicy">
|
||||||
|
<enum>QFormLayout::ExpandingFieldsGrow</enum>
|
||||||
|
</property>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Series:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLineEdit" name="SeriesLine"/>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Volume:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QLineEdit" name="VolumeLine"/>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>Number:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="QLineEdit" name="NumberLine"/>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="0">
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="text">
|
||||||
|
<string>Writer:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="1">
|
||||||
|
<widget class="QLineEdit" name="WriterLine"/>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="0">
|
||||||
|
<widget class="QLabel" name="label_5">
|
||||||
|
<property name="text">
|
||||||
|
<string>Penciller:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="1">
|
||||||
|
<widget class="QLineEdit" name="PencillerLine"/>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="0">
|
||||||
|
<widget class="QLabel" name="label_6">
|
||||||
|
<property name="text">
|
||||||
|
<string>Inker:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="1">
|
||||||
|
<widget class="QLineEdit" name="InkerLine"/>
|
||||||
|
</item>
|
||||||
|
<item row="7" column="0">
|
||||||
|
<widget class="QLabel" name="label_7">
|
||||||
|
<property name="text">
|
||||||
|
<string>Colorist:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="7" column="1">
|
||||||
|
<widget class="QLineEdit" name="ColoristLine"/>
|
||||||
|
</item>
|
||||||
|
<item row="8" column="0">
|
||||||
|
<widget class="QLabel" name="label_8">
|
||||||
|
<property name="text">
|
||||||
|
<string><html><head/><body><p><a href="https://github.com/ciromattia/kcc/wiki/Manga-Cover-Database-support"><span style=" text-decoration: underline; color:#0000ff;">MUid:</span></a></p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="textFormat">
|
||||||
|
<enum>Qt::RichText</enum>
|
||||||
|
</property>
|
||||||
|
<property name="openExternalLinks">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="8" column="1">
|
||||||
|
<widget class="QLineEdit" name="MUidLine"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<resources>
|
||||||
|
<include location="KCC.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
222
gui/MetaEditor.ui
Normal file
222
gui/MetaEditor.ui
Normal file
@@ -0,0 +1,222 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>MetaEditorDialog</class>
|
||||||
|
<widget class="QDialog" name="MetaEditorDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>400</width>
|
||||||
|
<height>260</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>400</width>
|
||||||
|
<height>260</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>400</width>
|
||||||
|
<height>260</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Metadata editor</string>
|
||||||
|
</property>
|
||||||
|
<property name="windowIcon">
|
||||||
|
<iconset resource="KCC.qrc">
|
||||||
|
<normaloff>:/Icon/icons/comic2ebook.png</normaloff>:/Icon/icons/comic2ebook.png</iconset>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="horizontalLayoutWidget">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>10</x>
|
||||||
|
<y>220</y>
|
||||||
|
<width>381</width>
|
||||||
|
<height>31</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="StatusLabel">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">color: rgb(255, 0, 0);</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="OKButton">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Save</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="KCC.qrc">
|
||||||
|
<normaloff>:/Other/icons/convert.png</normaloff>:/Other/icons/convert.png</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="CancelButton">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Cancel</string>
|
||||||
|
</property>
|
||||||
|
<property name="icon">
|
||||||
|
<iconset resource="KCC.qrc">
|
||||||
|
<normaloff>:/Other/icons/clear.png</normaloff>:/Other/icons/clear.png</iconset>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QFrame" name="EditorFrame">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>10</x>
|
||||||
|
<y>10</y>
|
||||||
|
<width>381</width>
|
||||||
|
<height>211</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="formLayoutWidget">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>381</width>
|
||||||
|
<height>211</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<layout class="QFormLayout" name="formLayout">
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Series:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLineEdit" name="SeriesLine"/>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Volume:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QLineEdit" name="VolumeLine"/>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>Number:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="QLineEdit" name="NumberLine"/>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="0">
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="text">
|
||||||
|
<string>Writer:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="1">
|
||||||
|
<widget class="QLineEdit" name="WriterLine"/>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="0">
|
||||||
|
<widget class="QLabel" name="label_5">
|
||||||
|
<property name="text">
|
||||||
|
<string>Penciller:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="1">
|
||||||
|
<widget class="QLineEdit" name="PencillerLine"/>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="0">
|
||||||
|
<widget class="QLabel" name="label_6">
|
||||||
|
<property name="text">
|
||||||
|
<string>Inker:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="1">
|
||||||
|
<widget class="QLineEdit" name="InkerLine"/>
|
||||||
|
</item>
|
||||||
|
<item row="7" column="0">
|
||||||
|
<widget class="QLabel" name="label_7">
|
||||||
|
<property name="text">
|
||||||
|
<string>Colorist:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="7" column="1">
|
||||||
|
<widget class="QLineEdit" name="ColoristLine"/>
|
||||||
|
</item>
|
||||||
|
<item row="8" column="0">
|
||||||
|
<widget class="QLabel" name="label_8">
|
||||||
|
<property name="text">
|
||||||
|
<string><html><head/><body><p><a href="https://github.com/ciromattia/kcc/wiki/Manga-Cover-Database-support"><span style=" text-decoration: underline; color:#0000ff;">MUid:</span></a></p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="textFormat">
|
||||||
|
<enum>Qt::RichText</enum>
|
||||||
|
</property>
|
||||||
|
<property name="openExternalLinks">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="8" column="1">
|
||||||
|
<widget class="QLineEdit" name="MUidLine"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<resources>
|
||||||
|
<include location="KCC.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
BIN
icons/WizardOSX.png
Normal file
BIN
icons/WizardOSX.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 328 KiB |
BIN
icons/editor.png
Normal file
BIN
icons/editor.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
47
kcc-c2e.py
47
kcc-c2e.py
@@ -2,7 +2,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||||
# Copyright (c) 2013-2014 Pawel Jastrzebski <pawelj@vulturis.eu>
|
# Copyright (c) 2013-2015 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
#
|
#
|
||||||
# Permission to use, copy, modify, and/or distribute this software for
|
# Permission to use, copy, modify, and/or distribute this software for
|
||||||
# any purpose with or without fee is hereby granted, provided that the
|
# any purpose with or without fee is hereby granted, provided that the
|
||||||
@@ -18,53 +18,20 @@
|
|||||||
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
# PERFORMANCE OF THIS SOFTWARE.
|
# PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
__version__ = '4.0.1'
|
|
||||||
__license__ = 'ISC'
|
|
||||||
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
|
|
||||||
__docformat__ = 'restructuredtext en'
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
if sys.version_info[0] != 3:
|
if sys.version_info[0] != 3:
|
||||||
print('ERROR: This is Python 3 script!')
|
print('ERROR: This is Python 3 script!')
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
# Dependiences check
|
from kcc.shared import dependencyCheck
|
||||||
missing = []
|
dependencyCheck(2)
|
||||||
try:
|
|
||||||
# noinspection PyUnresolvedReferences
|
|
||||||
from psutil import TOTAL_PHYMEM, Popen
|
|
||||||
except ImportError:
|
|
||||||
missing.append('psutil')
|
|
||||||
try:
|
|
||||||
# noinspection PyUnresolvedReferences
|
|
||||||
from slugify import slugify
|
|
||||||
except ImportError:
|
|
||||||
missing.append('python-slugify')
|
|
||||||
try:
|
|
||||||
# noinspection PyUnresolvedReferences
|
|
||||||
from PIL import Image, ImageOps, ImageStat, ImageChops
|
|
||||||
if tuple(map(int, ('2.3.0'.split(".")))) > tuple(map(int, (Image.PILLOW_VERSION.split(".")))):
|
|
||||||
missing.append('Pillow 2.3.0+')
|
|
||||||
except ImportError:
|
|
||||||
missing.append('Pillow 2.3.0+')
|
|
||||||
if len(missing) > 0:
|
|
||||||
try:
|
|
||||||
# noinspection PyUnresolvedReferences
|
|
||||||
import tkinter
|
|
||||||
# noinspection PyUnresolvedReferences
|
|
||||||
import tkinter.messagebox
|
|
||||||
importRoot = tkinter.Tk()
|
|
||||||
importRoot.withdraw()
|
|
||||||
tkinter.messagebox.showerror('KCC - Error', 'ERROR: ' + ', '.join(missing) + ' is not installed!')
|
|
||||||
except ImportError:
|
|
||||||
print('ERROR: ' + ', '.join(missing) + ' is not installed!')
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
from multiprocessing import freeze_support
|
from multiprocessing import freeze_support
|
||||||
from kcc.comic2ebook import main, Copyright
|
from kcc import __version__
|
||||||
|
from kcc.comic2ebook import main
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
freeze_support()
|
freeze_support()
|
||||||
Copyright()
|
print('comic2ebook v' + __version__ + ' - Written by Ciro Mattia Gonano and Pawel Jastrzebski.')
|
||||||
main(sys.argv[1:])
|
main(sys.argv[1:])
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|||||||
37
kcc-c2p.py
37
kcc-c2p.py
@@ -2,7 +2,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||||
# Copyright (c) 2013-2014 Pawel Jastrzebski <pawelj@vulturis.eu>
|
# Copyright (c) 2013-2015 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
#
|
#
|
||||||
# Permission to use, copy, modify, and/or distribute this software for
|
# Permission to use, copy, modify, and/or distribute this software for
|
||||||
# any purpose with or without fee is hereby granted, provided that the
|
# any purpose with or without fee is hereby granted, provided that the
|
||||||
@@ -23,38 +23,15 @@ if sys.version_info[0] != 3:
|
|||||||
print('ERROR: This is Python 3 script!')
|
print('ERROR: This is Python 3 script!')
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
__version__ = '4.0.1'
|
from kcc.shared import dependencyCheck
|
||||||
__license__ = 'ISC'
|
dependencyCheck(1)
|
||||||
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
|
|
||||||
__docformat__ = 'restructuredtext en'
|
|
||||||
|
|
||||||
# Dependiences check
|
|
||||||
missing = []
|
|
||||||
try:
|
|
||||||
# noinspection PyUnresolvedReferences
|
|
||||||
from PIL import Image, ImageOps, ImageStat, ImageChops
|
|
||||||
if tuple(map(int, ('2.3.0'.split(".")))) > tuple(map(int, (Image.PILLOW_VERSION.split(".")))):
|
|
||||||
missing.append('Pillow 2.3.0+')
|
|
||||||
except ImportError:
|
|
||||||
missing.append('Pillow 2.3.0+')
|
|
||||||
if len(missing) > 0:
|
|
||||||
try:
|
|
||||||
# noinspection PyUnresolvedReferences
|
|
||||||
import tkinter
|
|
||||||
# noinspection PyUnresolvedReferences
|
|
||||||
import tkinter.messagebox
|
|
||||||
importRoot = tkinter.Tk()
|
|
||||||
importRoot.withdraw()
|
|
||||||
tkinter.messagebox.showerror('KCC - Error', 'ERROR: ' + ', '.join(missing) + ' is not installed!')
|
|
||||||
except ImportError:
|
|
||||||
print('ERROR: ' + ', '.join(missing) + ' is not installed!')
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
from multiprocessing import freeze_support
|
from multiprocessing import freeze_support
|
||||||
from kcc.comic2panel import main, Copyright
|
from kcc import __version__
|
||||||
|
from kcc.comic2panel import main
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
freeze_support()
|
freeze_support()
|
||||||
Copyright()
|
print('comic2panel v' + __version__ + ' - Written by Ciro Mattia Gonano and Pawel Jastrzebski.')
|
||||||
main(sys.argv[1:])
|
main(sys.argv[1:])
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|||||||
69
kcc.iss
69
kcc.iss
@@ -1,7 +1,7 @@
|
|||||||
#define MyAppName "Kindle Comic Converter"
|
#define MyAppName "Kindle Comic Converter"
|
||||||
#define MyAppVersion "4.0.1"
|
#define MyAppVersion "4.6.4"
|
||||||
#define MyAppPublisher "Ciro Mattia Gonano, Paweł Jastrzębski"
|
#define MyAppPublisher "Ciro Mattia Gonano, Paweł Jastrzębski"
|
||||||
#define MyAppURL "http://kcc.vulturis.eu/"
|
#define MyAppURL "http://kcc.iosphe.re/"
|
||||||
#define MyAppExeName "KCC.exe"
|
#define MyAppExeName "KCC.exe"
|
||||||
|
|
||||||
[Setup]
|
[Setup]
|
||||||
@@ -12,7 +12,7 @@ AppPublisher={#MyAppPublisher}
|
|||||||
AppPublisherURL={#MyAppURL}
|
AppPublisherURL={#MyAppURL}
|
||||||
AppSupportURL={#MyAppURL}
|
AppSupportURL={#MyAppURL}
|
||||||
AppUpdatesURL={#MyAppURL}
|
AppUpdatesURL={#MyAppURL}
|
||||||
AppCopyright=Copyright (C) 2012-2014 Ciro Mattia Gonano and Paweł Jastrzębski
|
AppCopyright=Copyright (C) 2012-2015 Ciro Mattia Gonano and Paweł Jastrzębski
|
||||||
DefaultDirName={pf}\{#MyAppName}
|
DefaultDirName={pf}\{#MyAppName}
|
||||||
DefaultGroupName={#MyAppName}
|
DefaultGroupName={#MyAppName}
|
||||||
AllowNoIcons=yes
|
AllowNoIcons=yes
|
||||||
@@ -30,6 +30,7 @@ UninstallDisplayIcon={app}\{#MyAppExeName}
|
|||||||
ChangesAssociations=True
|
ChangesAssociations=True
|
||||||
InfoAfterFile=other\InstallWarning.rtf
|
InfoAfterFile=other\InstallWarning.rtf
|
||||||
SignTool=SignTool /d $q{#MyAppName}$q /du $q{#MyAppURL}$q $f
|
SignTool=SignTool /d $q{#MyAppName}$q /du $q{#MyAppURL}$q $f
|
||||||
|
MinVersion=0,6.0
|
||||||
|
|
||||||
[Languages]
|
[Languages]
|
||||||
Name: "english"; MessagesFile: "compiler:Default.isl"
|
Name: "english"; MessagesFile: "compiler:Default.isl"
|
||||||
@@ -42,18 +43,14 @@ Name: "CB7association"; Description: "CB7"; GroupDescription: "File associations
|
|||||||
|
|
||||||
[Files]
|
[Files]
|
||||||
; x64 files
|
; x64 files
|
||||||
Source: "build\exe.win-amd64-3.3\imageformats\*"; DestDir: "{app}\imageformats\"; Flags: ignoreversion; Check: Is64BitInstallMode
|
Source: "dist_64\platforms\*"; DestDir: "{app}\platforms\"; Flags: ignoreversion; Check: Is64BitInstallMode
|
||||||
Source: "build\exe.win-amd64-3.3\platforms\*"; DestDir: "{app}\platforms\"; Flags: ignoreversion; Check: Is64BitInstallMode
|
Source: "dist_64\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
|
||||||
Source: "build\exe.win-amd64-3.3\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
|
Source: "dist_64\*.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
|
||||||
Source: "build\exe.win-amd64-3.3\*.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
|
|
||||||
Source: "build\exe.win-amd64-3.3\*.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
|
|
||||||
Source: "other\vcredist_x64.exe"; DestDir: "{tmp}"; Flags: ignoreversion deleteafterinstall; Check: Is64BitInstallMode
|
Source: "other\vcredist_x64.exe"; DestDir: "{tmp}"; Flags: ignoreversion deleteafterinstall; Check: Is64BitInstallMode
|
||||||
; x86 files
|
; x86 files
|
||||||
Source: "build\exe.win32-3.3\imageformats\*"; DestDir: "{app}\imageformats\"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
Source: "dist\platforms\*"; DestDir: "{app}\platforms\"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
||||||
Source: "build\exe.win32-3.3\platforms\*"; DestDir: "{app}\platforms\"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
Source: "dist\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
||||||
Source: "build\exe.win32-3.3\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
Source: "dist\*.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
||||||
Source: "build\exe.win32-3.3\*.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
|
||||||
Source: "build\exe.win32-3.3\*.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
|
||||||
Source: "other\vcredist_x86.exe"; DestDir: "{tmp}"; Flags: ignoreversion deleteafterinstall; Check: not Is64BitInstallMode
|
Source: "other\vcredist_x86.exe"; DestDir: "{tmp}"; Flags: ignoreversion deleteafterinstall; Check: not Is64BitInstallMode
|
||||||
; Common files
|
; Common files
|
||||||
Source: "LICENSE.txt"; DestDir: "{app}"; Flags: ignoreversion solidbreak
|
Source: "LICENSE.txt"; DestDir: "{app}"; Flags: ignoreversion solidbreak
|
||||||
@@ -88,3 +85,49 @@ Root: HKCR; SubKey: ".cb7"; ValueType: string; ValueData: "KCCCB7"; Flags: unins
|
|||||||
Root: HKCR; SubKey: "KCCCB7"; ValueType: string; ValueData: "KCC 7z Archive"; Flags: uninsdeletekey; Tasks: CB7association
|
Root: HKCR; SubKey: "KCCCB7"; ValueType: string; ValueData: "KCC 7z Archive"; Flags: uninsdeletekey; Tasks: CB7association
|
||||||
Root: HKCR; SubKey: "KCCCB7\Shell\Open\Command"; ValueType: string; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey; Tasks: CB7association
|
Root: HKCR; SubKey: "KCCCB7\Shell\Open\Command"; ValueType: string; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey; Tasks: CB7association
|
||||||
Root: HKCR; Subkey: "KCCCB7\DefaultIcon"; ValueType: string; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletevalue; Tasks: CB7association
|
Root: HKCR; Subkey: "KCCCB7\DefaultIcon"; ValueType: string; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletevalue; Tasks: CB7association
|
||||||
|
|
||||||
|
[Code]
|
||||||
|
function GetUninstallString(): String;
|
||||||
|
var
|
||||||
|
sUnInstPath: String;
|
||||||
|
sUnInstallString: String;
|
||||||
|
begin
|
||||||
|
sUnInstPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{#emit SetupSetting("AppId")}_is1');
|
||||||
|
sUnInstallString := '';
|
||||||
|
if not RegQueryStringValue(HKLM, sUnInstPath, 'UninstallString', sUnInstallString) then
|
||||||
|
RegQueryStringValue(HKCU, sUnInstPath, 'UninstallString', sUnInstallString);
|
||||||
|
Result := sUnInstallString;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function IsUpgrade(): Boolean;
|
||||||
|
begin
|
||||||
|
Result := (GetUninstallString() <> '');
|
||||||
|
end;
|
||||||
|
|
||||||
|
function UnInstallOldVersion(): Integer;
|
||||||
|
var
|
||||||
|
sUnInstallString: String;
|
||||||
|
iResultCode: Integer;
|
||||||
|
begin
|
||||||
|
Result := 0;
|
||||||
|
sUnInstallString := GetUninstallString();
|
||||||
|
if sUnInstallString <> '' then begin
|
||||||
|
sUnInstallString := RemoveQuotes(sUnInstallString);
|
||||||
|
if Exec(sUnInstallString, '/SILENT /NORESTART /SUPPRESSMSGBOXES','', SW_HIDE, ewWaitUntilTerminated, iResultCode) then
|
||||||
|
Result := 3
|
||||||
|
else
|
||||||
|
Result := 2;
|
||||||
|
end else
|
||||||
|
Result := 1;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure CurStepChanged(CurStep: TSetupStep);
|
||||||
|
begin
|
||||||
|
if (CurStep=ssInstall) then
|
||||||
|
begin
|
||||||
|
if (IsUpgrade()) then
|
||||||
|
begin
|
||||||
|
UnInstallOldVersion();
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
151
kcc.py
151
kcc.py
@@ -2,7 +2,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||||
# Copyright (c) 2013-2014 Pawel Jastrzebski <pawelj@vulturis.eu>
|
# Copyright (c) 2013-2015 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
#
|
#
|
||||||
# Permission to use, copy, modify, and/or distribute this software for
|
# Permission to use, copy, modify, and/or distribute this software for
|
||||||
# any purpose with or without fee is hereby granted, provided that the
|
# any purpose with or without fee is hereby granted, provided that the
|
||||||
@@ -18,151 +18,52 @@
|
|||||||
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
# PERFORMANCE OF THIS SOFTWARE.
|
# PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
__version__ = '4.0.1'
|
|
||||||
__license__ = 'ISC'
|
|
||||||
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
|
|
||||||
__docformat__ = 'restructuredtext en'
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
if sys.version_info[0] != 3:
|
if sys.version_info[0] != 3:
|
||||||
print('ERROR: This is Python 3 script!')
|
print('ERROR: This is Python 3 script!')
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
# Dependiences check
|
|
||||||
missing = []
|
|
||||||
try:
|
|
||||||
# noinspection PyUnresolvedReferences
|
|
||||||
from PyQt5 import QtCore, QtGui, QtNetwork, QtWidgets
|
|
||||||
except ImportError:
|
|
||||||
missing.append('PyQt5')
|
|
||||||
try:
|
|
||||||
# noinspection PyUnresolvedReferences
|
|
||||||
from psutil import TOTAL_PHYMEM, Popen
|
|
||||||
except ImportError:
|
|
||||||
missing.append('psutil')
|
|
||||||
try:
|
|
||||||
# noinspection PyUnresolvedReferences
|
|
||||||
from slugify import slugify
|
|
||||||
except ImportError:
|
|
||||||
missing.append('python-slugify')
|
|
||||||
try:
|
|
||||||
# noinspection PyUnresolvedReferences
|
|
||||||
from PIL import Image, ImageOps, ImageStat, ImageChops
|
|
||||||
if tuple(map(int, ('2.3.0'.split(".")))) > tuple(map(int, (Image.PILLOW_VERSION.split(".")))):
|
|
||||||
missing.append('Pillow 2.3.0+')
|
|
||||||
except ImportError:
|
|
||||||
missing.append('Pillow 2.3.0+')
|
|
||||||
if len(missing) > 0:
|
|
||||||
try:
|
|
||||||
# noinspection PyUnresolvedReferences
|
|
||||||
import tkinter
|
|
||||||
# noinspection PyUnresolvedReferences
|
|
||||||
import tkinter.messagebox
|
|
||||||
importRoot = tkinter.Tk()
|
|
||||||
importRoot.withdraw()
|
|
||||||
tkinter.messagebox.showerror('KCC - Error', 'ERROR: ' + ', '.join(missing) + ' is not installed!')
|
|
||||||
except ImportError:
|
|
||||||
print('ERROR: ' + ', '.join(missing) + ' is not installed!')
|
|
||||||
exit(1)
|
|
||||||
|
|
||||||
import os
|
|
||||||
from multiprocessing import freeze_support
|
|
||||||
from kcc import KCC_gui
|
|
||||||
|
|
||||||
# OS specific PATH variable workarounds
|
# OS specific PATH variable workarounds
|
||||||
|
import os
|
||||||
if sys.platform.startswith('darwin'):
|
if sys.platform.startswith('darwin'):
|
||||||
if 'RESOURCEPATH' in os.environ:
|
if 'RESOURCEPATH' not in os.environ:
|
||||||
os.environ['PATH'] = os.environ['RESOURCEPATH'] + ':' + os.environ['PATH']
|
|
||||||
else:
|
|
||||||
os.environ['PATH'] = os.path.dirname(os.path.abspath(__file__)) + '/other/:' + os.environ['PATH']
|
os.environ['PATH'] = os.path.dirname(os.path.abspath(__file__)) + '/other/:' + os.environ['PATH']
|
||||||
|
else:
|
||||||
|
os.environ['PATH'] = './../Resources:/usr/local/bin:/usr/bin:/bin'
|
||||||
elif sys.platform.startswith('win'):
|
elif sys.platform.startswith('win'):
|
||||||
if getattr(sys, 'frozen', False):
|
if getattr(sys, 'frozen', False):
|
||||||
os.chdir(os.path.dirname(os.path.abspath(sys.executable)))
|
os.chdir(os.path.dirname(os.path.abspath(sys.executable)))
|
||||||
|
|
||||||
|
# Implementing dummy stdout and stderr for frozen Windows release
|
||||||
|
class FakeSTD(object):
|
||||||
|
def write(self, string):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def flush(self):
|
||||||
|
pass
|
||||||
|
sys.stdout = FakeSTD()
|
||||||
|
sys.stderr = FakeSTD()
|
||||||
else:
|
else:
|
||||||
os.environ['PATH'] = os.path.dirname(os.path.abspath(__file__)) + '/other/;' + os.environ['PATH']
|
os.environ['PATH'] = os.path.dirname(os.path.abspath(__file__)) + '/other/;' + os.environ['PATH']
|
||||||
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
|
from kcc.shared import dependencyCheck
|
||||||
|
dependencyCheck(3)
|
||||||
|
|
||||||
# Implementing detection of already running KCC instance and forwarding argv to it
|
from multiprocessing import freeze_support
|
||||||
class QApplicationMessaging(QtWidgets.QApplication):
|
from kcc import KCC_gui
|
||||||
messageFromOtherInstance = QtCore.pyqtSignal(bytes)
|
|
||||||
|
|
||||||
def __init__(self, argv):
|
|
||||||
QtWidgets.QApplication.__init__(self, argv)
|
|
||||||
self._memory = QtCore.QSharedMemory(self)
|
|
||||||
self._memory.setKey('KCC')
|
|
||||||
if self._memory.attach():
|
|
||||||
self._running = True
|
|
||||||
else:
|
|
||||||
self._running = False
|
|
||||||
self._memory.create(1)
|
|
||||||
self._key = 'KCC'
|
|
||||||
self._timeout = 1000
|
|
||||||
self._server = QtNetwork.QLocalServer(self)
|
|
||||||
if not self.isRunning():
|
|
||||||
self._server.newConnection.connect(self.handleMessage)
|
|
||||||
self._server.listen(self._key)
|
|
||||||
|
|
||||||
def __del__(self):
|
|
||||||
if self._memory.isAttached():
|
|
||||||
self._memory.detach()
|
|
||||||
self._server.close()
|
|
||||||
|
|
||||||
def event(self, e):
|
|
||||||
if e.type() == QtCore.QEvent.FileOpen:
|
|
||||||
# noinspection PyArgumentList
|
|
||||||
self.messageFromOtherInstance.emit(bytes(e.file(), 'UTF-8'))
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return QtWidgets.QApplication.event(self, e)
|
|
||||||
|
|
||||||
def isRunning(self):
|
|
||||||
return self._running
|
|
||||||
|
|
||||||
def handleMessage(self):
|
|
||||||
socket = self._server.nextPendingConnection()
|
|
||||||
if socket.waitForReadyRead(self._timeout):
|
|
||||||
self.messageFromOtherInstance.emit(socket.readAll().data())
|
|
||||||
|
|
||||||
def sendMessage(self, message):
|
|
||||||
if self.isRunning():
|
|
||||||
socket = QtNetwork.QLocalSocket(self)
|
|
||||||
socket.connectToServer(self._key, QtCore.QIODevice.WriteOnly)
|
|
||||||
if not socket.waitForConnected(self._timeout):
|
|
||||||
return False
|
|
||||||
# noinspection PyArgumentList
|
|
||||||
socket.write(bytes(message, 'UTF-8'))
|
|
||||||
if not socket.waitForBytesWritten(self._timeout):
|
|
||||||
return False
|
|
||||||
socket.disconnectFromServer()
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
# Adding signals to QMainWindow
|
|
||||||
class QMainWindowKCC(QtWidgets.QMainWindow):
|
|
||||||
progressBarTick = QtCore.pyqtSignal(str)
|
|
||||||
modeConvert = QtCore.pyqtSignal(int)
|
|
||||||
addMessage = QtCore.pyqtSignal(str, str, bool)
|
|
||||||
addTrayMessage = QtCore.pyqtSignal(str, str)
|
|
||||||
showDialog = QtCore.pyqtSignal(str, str)
|
|
||||||
hideProgressBar = QtCore.pyqtSignal()
|
|
||||||
forceShutdown = QtCore.pyqtSignal()
|
|
||||||
dialogAnswer = QtCore.pyqtSignal(int)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
freeze_support()
|
freeze_support()
|
||||||
KCCAplication = QApplicationMessaging(sys.argv)
|
KCCAplication = KCC_gui.QApplicationMessaging(sys.argv)
|
||||||
if KCCAplication.isRunning():
|
if KCCAplication.isRunning():
|
||||||
if len(sys.argv) > 1:
|
if len(sys.argv) > 1:
|
||||||
KCCAplication.sendMessage(sys.argv[1])
|
KCCAplication.sendMessage(sys.argv[1])
|
||||||
sys.exit(0)
|
|
||||||
else:
|
else:
|
||||||
KCCAplication.sendMessage('ARISE')
|
KCCAplication.sendMessage('ARISE')
|
||||||
sys.exit(0)
|
else:
|
||||||
KCCWindow = QMainWindowKCC()
|
KCCWindow = KCC_gui.QMainWindowKCC()
|
||||||
KCCUI = KCC_gui.KCCGUI(KCCAplication, KCCWindow)
|
KCCUI = KCC_gui.KCCGUI(KCCAplication, KCCWindow)
|
||||||
if len(sys.argv) > 1:
|
if len(sys.argv) > 1:
|
||||||
KCCUI.handleMessage(sys.argv[1])
|
KCCUI.handleMessage(sys.argv[1])
|
||||||
sys.exit(KCCAplication.exec_())
|
sys.exit(KCCAplication.exec_())
|
||||||
|
|||||||
147
kcc/KCC_MetaEditor_ui.py
Normal file
147
kcc/KCC_MetaEditor_ui.py
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Form implementation generated from reading ui file 'MetaEditor.ui'
|
||||||
|
#
|
||||||
|
# Created: Sun Feb 8 11:52:00 2015
|
||||||
|
# by: PyQt5 UI code generator 5.4
|
||||||
|
#
|
||||||
|
# WARNING! All changes made in this file will be lost!
|
||||||
|
|
||||||
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
class Ui_MetaEditorDialog(object):
|
||||||
|
def setupUi(self, MetaEditorDialog):
|
||||||
|
MetaEditorDialog.setObjectName("MetaEditorDialog")
|
||||||
|
MetaEditorDialog.resize(400, 260)
|
||||||
|
MetaEditorDialog.setMinimumSize(QtCore.QSize(400, 260))
|
||||||
|
MetaEditorDialog.setMaximumSize(QtCore.QSize(400, 260))
|
||||||
|
icon = QtGui.QIcon()
|
||||||
|
icon.addPixmap(QtGui.QPixmap(":/Icon/icons/comic2ebook.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
|
MetaEditorDialog.setWindowIcon(icon)
|
||||||
|
self.horizontalLayoutWidget = QtWidgets.QWidget(MetaEditorDialog)
|
||||||
|
self.horizontalLayoutWidget.setGeometry(QtCore.QRect(10, 220, 381, 31))
|
||||||
|
self.horizontalLayoutWidget.setObjectName("horizontalLayoutWidget")
|
||||||
|
self.horizontalLayout = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget)
|
||||||
|
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||||
|
self.StatusLabel = QtWidgets.QLabel(self.horizontalLayoutWidget)
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.StatusLabel.sizePolicy().hasHeightForWidth())
|
||||||
|
self.StatusLabel.setSizePolicy(sizePolicy)
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setBold(True)
|
||||||
|
font.setWeight(75)
|
||||||
|
self.StatusLabel.setFont(font)
|
||||||
|
self.StatusLabel.setStyleSheet("color: rgb(255, 0, 0);")
|
||||||
|
self.StatusLabel.setObjectName("StatusLabel")
|
||||||
|
self.horizontalLayout.addWidget(self.StatusLabel)
|
||||||
|
self.OKButton = QtWidgets.QPushButton(self.horizontalLayoutWidget)
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.OKButton.sizePolicy().hasHeightForWidth())
|
||||||
|
self.OKButton.setSizePolicy(sizePolicy)
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setBold(True)
|
||||||
|
font.setWeight(75)
|
||||||
|
self.OKButton.setFont(font)
|
||||||
|
icon1 = QtGui.QIcon()
|
||||||
|
icon1.addPixmap(QtGui.QPixmap(":/Other/icons/convert.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
|
self.OKButton.setIcon(icon1)
|
||||||
|
self.OKButton.setObjectName("OKButton")
|
||||||
|
self.horizontalLayout.addWidget(self.OKButton)
|
||||||
|
self.CancelButton = QtWidgets.QPushButton(self.horizontalLayoutWidget)
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.CancelButton.sizePolicy().hasHeightForWidth())
|
||||||
|
self.CancelButton.setSizePolicy(sizePolicy)
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setBold(True)
|
||||||
|
font.setWeight(75)
|
||||||
|
self.CancelButton.setFont(font)
|
||||||
|
icon2 = QtGui.QIcon()
|
||||||
|
icon2.addPixmap(QtGui.QPixmap(":/Other/icons/clear.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
|
self.CancelButton.setIcon(icon2)
|
||||||
|
self.CancelButton.setObjectName("CancelButton")
|
||||||
|
self.horizontalLayout.addWidget(self.CancelButton)
|
||||||
|
self.EditorFrame = QtWidgets.QFrame(MetaEditorDialog)
|
||||||
|
self.EditorFrame.setGeometry(QtCore.QRect(10, 10, 381, 211))
|
||||||
|
self.EditorFrame.setObjectName("EditorFrame")
|
||||||
|
self.formLayoutWidget = QtWidgets.QWidget(self.EditorFrame)
|
||||||
|
self.formLayoutWidget.setGeometry(QtCore.QRect(0, 0, 381, 211))
|
||||||
|
self.formLayoutWidget.setObjectName("formLayoutWidget")
|
||||||
|
self.formLayout = QtWidgets.QFormLayout(self.formLayoutWidget)
|
||||||
|
self.formLayout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
self.formLayout.setObjectName("formLayout")
|
||||||
|
self.label = QtWidgets.QLabel(self.formLayoutWidget)
|
||||||
|
self.label.setObjectName("label")
|
||||||
|
self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label)
|
||||||
|
self.SeriesLine = QtWidgets.QLineEdit(self.formLayoutWidget)
|
||||||
|
self.SeriesLine.setObjectName("SeriesLine")
|
||||||
|
self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.SeriesLine)
|
||||||
|
self.label_2 = QtWidgets.QLabel(self.formLayoutWidget)
|
||||||
|
self.label_2.setObjectName("label_2")
|
||||||
|
self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_2)
|
||||||
|
self.VolumeLine = QtWidgets.QLineEdit(self.formLayoutWidget)
|
||||||
|
self.VolumeLine.setObjectName("VolumeLine")
|
||||||
|
self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.VolumeLine)
|
||||||
|
self.label_3 = QtWidgets.QLabel(self.formLayoutWidget)
|
||||||
|
self.label_3.setObjectName("label_3")
|
||||||
|
self.formLayout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.label_3)
|
||||||
|
self.NumberLine = QtWidgets.QLineEdit(self.formLayoutWidget)
|
||||||
|
self.NumberLine.setObjectName("NumberLine")
|
||||||
|
self.formLayout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.NumberLine)
|
||||||
|
self.label_4 = QtWidgets.QLabel(self.formLayoutWidget)
|
||||||
|
self.label_4.setObjectName("label_4")
|
||||||
|
self.formLayout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.label_4)
|
||||||
|
self.WriterLine = QtWidgets.QLineEdit(self.formLayoutWidget)
|
||||||
|
self.WriterLine.setObjectName("WriterLine")
|
||||||
|
self.formLayout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.WriterLine)
|
||||||
|
self.label_5 = QtWidgets.QLabel(self.formLayoutWidget)
|
||||||
|
self.label_5.setObjectName("label_5")
|
||||||
|
self.formLayout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.label_5)
|
||||||
|
self.PencillerLine = QtWidgets.QLineEdit(self.formLayoutWidget)
|
||||||
|
self.PencillerLine.setObjectName("PencillerLine")
|
||||||
|
self.formLayout.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.PencillerLine)
|
||||||
|
self.label_6 = QtWidgets.QLabel(self.formLayoutWidget)
|
||||||
|
self.label_6.setObjectName("label_6")
|
||||||
|
self.formLayout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.label_6)
|
||||||
|
self.InkerLine = QtWidgets.QLineEdit(self.formLayoutWidget)
|
||||||
|
self.InkerLine.setObjectName("InkerLine")
|
||||||
|
self.formLayout.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.InkerLine)
|
||||||
|
self.label_7 = QtWidgets.QLabel(self.formLayoutWidget)
|
||||||
|
self.label_7.setObjectName("label_7")
|
||||||
|
self.formLayout.setWidget(7, QtWidgets.QFormLayout.LabelRole, self.label_7)
|
||||||
|
self.ColoristLine = QtWidgets.QLineEdit(self.formLayoutWidget)
|
||||||
|
self.ColoristLine.setObjectName("ColoristLine")
|
||||||
|
self.formLayout.setWidget(7, QtWidgets.QFormLayout.FieldRole, self.ColoristLine)
|
||||||
|
self.label_8 = QtWidgets.QLabel(self.formLayoutWidget)
|
||||||
|
self.label_8.setTextFormat(QtCore.Qt.RichText)
|
||||||
|
self.label_8.setOpenExternalLinks(True)
|
||||||
|
self.label_8.setObjectName("label_8")
|
||||||
|
self.formLayout.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.label_8)
|
||||||
|
self.MUidLine = QtWidgets.QLineEdit(self.formLayoutWidget)
|
||||||
|
self.MUidLine.setObjectName("MUidLine")
|
||||||
|
self.formLayout.setWidget(8, QtWidgets.QFormLayout.FieldRole, self.MUidLine)
|
||||||
|
|
||||||
|
self.retranslateUi(MetaEditorDialog)
|
||||||
|
QtCore.QMetaObject.connectSlotsByName(MetaEditorDialog)
|
||||||
|
|
||||||
|
def retranslateUi(self, MetaEditorDialog):
|
||||||
|
_translate = QtCore.QCoreApplication.translate
|
||||||
|
MetaEditorDialog.setWindowTitle(_translate("MetaEditorDialog", "Metadata editor"))
|
||||||
|
self.OKButton.setText(_translate("MetaEditorDialog", "Save"))
|
||||||
|
self.CancelButton.setText(_translate("MetaEditorDialog", "Cancel"))
|
||||||
|
self.label.setText(_translate("MetaEditorDialog", "Series:"))
|
||||||
|
self.label_2.setText(_translate("MetaEditorDialog", "Volume:"))
|
||||||
|
self.label_3.setText(_translate("MetaEditorDialog", "Number:"))
|
||||||
|
self.label_4.setText(_translate("MetaEditorDialog", "Writer:"))
|
||||||
|
self.label_5.setText(_translate("MetaEditorDialog", "Penciller:"))
|
||||||
|
self.label_6.setText(_translate("MetaEditorDialog", "Inker:"))
|
||||||
|
self.label_7.setText(_translate("MetaEditorDialog", "Colorist:"))
|
||||||
|
self.label_8.setText(_translate("MetaEditorDialog", "<html><head/><body><p><a href=\"https://github.com/ciromattia/kcc/wiki/Manga-Cover-Database-support\"><span style=\" text-decoration: underline; color:#0000ff;\">MUid:</span></a></p></body></html>"))
|
||||||
|
|
||||||
|
from . import KCC_rc
|
||||||
148
kcc/KCC_MetaEditor_ui_linux.py
Normal file
148
kcc/KCC_MetaEditor_ui_linux.py
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Form implementation generated from reading ui file 'gui/MetaEditor.ui'
|
||||||
|
#
|
||||||
|
# Created: Sun Feb 8 03:24:23 2015
|
||||||
|
# by: PyQt5 UI code generator 5.2.1
|
||||||
|
#
|
||||||
|
# WARNING! All changes made in this file will be lost!
|
||||||
|
|
||||||
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
class Ui_MetaEditorDialog(object):
|
||||||
|
def setupUi(self, MetaEditorDialog):
|
||||||
|
MetaEditorDialog.setObjectName("MetaEditorDialog")
|
||||||
|
MetaEditorDialog.resize(400, 320)
|
||||||
|
MetaEditorDialog.setMinimumSize(QtCore.QSize(400, 320))
|
||||||
|
MetaEditorDialog.setMaximumSize(QtCore.QSize(400, 320))
|
||||||
|
icon = QtGui.QIcon()
|
||||||
|
icon.addPixmap(QtGui.QPixmap(":/Icon/icons/comic2ebook.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
|
MetaEditorDialog.setWindowIcon(icon)
|
||||||
|
self.horizontalLayoutWidget = QtWidgets.QWidget(MetaEditorDialog)
|
||||||
|
self.horizontalLayoutWidget.setGeometry(QtCore.QRect(10, 280, 381, 31))
|
||||||
|
self.horizontalLayoutWidget.setObjectName("horizontalLayoutWidget")
|
||||||
|
self.horizontalLayout = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget)
|
||||||
|
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||||
|
self.StatusLabel = QtWidgets.QLabel(self.horizontalLayoutWidget)
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.StatusLabel.sizePolicy().hasHeightForWidth())
|
||||||
|
self.StatusLabel.setSizePolicy(sizePolicy)
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setPointSize(10)
|
||||||
|
font.setBold(True)
|
||||||
|
font.setWeight(75)
|
||||||
|
self.StatusLabel.setFont(font)
|
||||||
|
self.StatusLabel.setStyleSheet("color: rgb(255, 0, 0);")
|
||||||
|
self.StatusLabel.setObjectName("StatusLabel")
|
||||||
|
self.horizontalLayout.addWidget(self.StatusLabel)
|
||||||
|
self.OKButton = QtWidgets.QPushButton(self.horizontalLayoutWidget)
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.OKButton.sizePolicy().hasHeightForWidth())
|
||||||
|
self.OKButton.setSizePolicy(sizePolicy)
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setBold(True)
|
||||||
|
font.setWeight(75)
|
||||||
|
self.OKButton.setFont(font)
|
||||||
|
icon1 = QtGui.QIcon()
|
||||||
|
icon1.addPixmap(QtGui.QPixmap(":/Other/icons/convert.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
|
self.OKButton.setIcon(icon1)
|
||||||
|
self.OKButton.setObjectName("OKButton")
|
||||||
|
self.horizontalLayout.addWidget(self.OKButton)
|
||||||
|
self.CancelButton = QtWidgets.QPushButton(self.horizontalLayoutWidget)
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.CancelButton.sizePolicy().hasHeightForWidth())
|
||||||
|
self.CancelButton.setSizePolicy(sizePolicy)
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setBold(True)
|
||||||
|
font.setWeight(75)
|
||||||
|
self.CancelButton.setFont(font)
|
||||||
|
icon2 = QtGui.QIcon()
|
||||||
|
icon2.addPixmap(QtGui.QPixmap(":/Other/icons/clear.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
|
self.CancelButton.setIcon(icon2)
|
||||||
|
self.CancelButton.setObjectName("CancelButton")
|
||||||
|
self.horizontalLayout.addWidget(self.CancelButton)
|
||||||
|
self.EditorFrame = QtWidgets.QFrame(MetaEditorDialog)
|
||||||
|
self.EditorFrame.setGeometry(QtCore.QRect(10, 10, 381, 271))
|
||||||
|
self.EditorFrame.setObjectName("EditorFrame")
|
||||||
|
self.formLayoutWidget = QtWidgets.QWidget(self.EditorFrame)
|
||||||
|
self.formLayoutWidget.setGeometry(QtCore.QRect(0, 0, 381, 266))
|
||||||
|
self.formLayoutWidget.setObjectName("formLayoutWidget")
|
||||||
|
self.formLayout = QtWidgets.QFormLayout(self.formLayoutWidget)
|
||||||
|
self.formLayout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
self.formLayout.setObjectName("formLayout")
|
||||||
|
self.label = QtWidgets.QLabel(self.formLayoutWidget)
|
||||||
|
self.label.setObjectName("label")
|
||||||
|
self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label)
|
||||||
|
self.SeriesLine = QtWidgets.QLineEdit(self.formLayoutWidget)
|
||||||
|
self.SeriesLine.setObjectName("SeriesLine")
|
||||||
|
self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.SeriesLine)
|
||||||
|
self.label_2 = QtWidgets.QLabel(self.formLayoutWidget)
|
||||||
|
self.label_2.setObjectName("label_2")
|
||||||
|
self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_2)
|
||||||
|
self.VolumeLine = QtWidgets.QLineEdit(self.formLayoutWidget)
|
||||||
|
self.VolumeLine.setObjectName("VolumeLine")
|
||||||
|
self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.VolumeLine)
|
||||||
|
self.label_3 = QtWidgets.QLabel(self.formLayoutWidget)
|
||||||
|
self.label_3.setObjectName("label_3")
|
||||||
|
self.formLayout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.label_3)
|
||||||
|
self.NumberLine = QtWidgets.QLineEdit(self.formLayoutWidget)
|
||||||
|
self.NumberLine.setObjectName("NumberLine")
|
||||||
|
self.formLayout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.NumberLine)
|
||||||
|
self.label_4 = QtWidgets.QLabel(self.formLayoutWidget)
|
||||||
|
self.label_4.setObjectName("label_4")
|
||||||
|
self.formLayout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.label_4)
|
||||||
|
self.WriterLine = QtWidgets.QLineEdit(self.formLayoutWidget)
|
||||||
|
self.WriterLine.setObjectName("WriterLine")
|
||||||
|
self.formLayout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.WriterLine)
|
||||||
|
self.label_5 = QtWidgets.QLabel(self.formLayoutWidget)
|
||||||
|
self.label_5.setObjectName("label_5")
|
||||||
|
self.formLayout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.label_5)
|
||||||
|
self.PencillerLine = QtWidgets.QLineEdit(self.formLayoutWidget)
|
||||||
|
self.PencillerLine.setObjectName("PencillerLine")
|
||||||
|
self.formLayout.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.PencillerLine)
|
||||||
|
self.label_6 = QtWidgets.QLabel(self.formLayoutWidget)
|
||||||
|
self.label_6.setObjectName("label_6")
|
||||||
|
self.formLayout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.label_6)
|
||||||
|
self.InkerLine = QtWidgets.QLineEdit(self.formLayoutWidget)
|
||||||
|
self.InkerLine.setObjectName("InkerLine")
|
||||||
|
self.formLayout.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.InkerLine)
|
||||||
|
self.label_7 = QtWidgets.QLabel(self.formLayoutWidget)
|
||||||
|
self.label_7.setObjectName("label_7")
|
||||||
|
self.formLayout.setWidget(7, QtWidgets.QFormLayout.LabelRole, self.label_7)
|
||||||
|
self.ColoristLine = QtWidgets.QLineEdit(self.formLayoutWidget)
|
||||||
|
self.ColoristLine.setObjectName("ColoristLine")
|
||||||
|
self.formLayout.setWidget(7, QtWidgets.QFormLayout.FieldRole, self.ColoristLine)
|
||||||
|
self.label_8 = QtWidgets.QLabel(self.formLayoutWidget)
|
||||||
|
self.label_8.setTextFormat(QtCore.Qt.RichText)
|
||||||
|
self.label_8.setOpenExternalLinks(True)
|
||||||
|
self.label_8.setObjectName("label_8")
|
||||||
|
self.formLayout.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.label_8)
|
||||||
|
self.MUidLine = QtWidgets.QLineEdit(self.formLayoutWidget)
|
||||||
|
self.MUidLine.setObjectName("MUidLine")
|
||||||
|
self.formLayout.setWidget(8, QtWidgets.QFormLayout.FieldRole, self.MUidLine)
|
||||||
|
|
||||||
|
self.retranslateUi(MetaEditorDialog)
|
||||||
|
QtCore.QMetaObject.connectSlotsByName(MetaEditorDialog)
|
||||||
|
|
||||||
|
def retranslateUi(self, MetaEditorDialog):
|
||||||
|
_translate = QtCore.QCoreApplication.translate
|
||||||
|
MetaEditorDialog.setWindowTitle(_translate("MetaEditorDialog", "Metadata editor"))
|
||||||
|
self.OKButton.setText(_translate("MetaEditorDialog", "Save"))
|
||||||
|
self.CancelButton.setText(_translate("MetaEditorDialog", "Cancel"))
|
||||||
|
self.label.setText(_translate("MetaEditorDialog", "Series:"))
|
||||||
|
self.label_2.setText(_translate("MetaEditorDialog", "Volume:"))
|
||||||
|
self.label_3.setText(_translate("MetaEditorDialog", "Number:"))
|
||||||
|
self.label_4.setText(_translate("MetaEditorDialog", "Writer:"))
|
||||||
|
self.label_5.setText(_translate("MetaEditorDialog", "Penciller:"))
|
||||||
|
self.label_6.setText(_translate("MetaEditorDialog", "Inker:"))
|
||||||
|
self.label_7.setText(_translate("MetaEditorDialog", "Colorist:"))
|
||||||
|
self.label_8.setText(_translate("MetaEditorDialog", "<html><head/><body><p><a href=\"https://github.com/ciromattia/kcc/wiki/Manga-Cover-Database-support\"><span style=\" text-decoration: underline; color:#0000ff;\">MUid:</span></a></p></body></html>"))
|
||||||
|
|
||||||
|
from . import KCC_rc
|
||||||
149
kcc/KCC_MetaEditor_ui_osx.py
Normal file
149
kcc/KCC_MetaEditor_ui_osx.py
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Form implementation generated from reading ui file '/Users/pawelj/Documents/KCC/gui/MetaEditor.ui'
|
||||||
|
#
|
||||||
|
# Created: Sun Feb 8 12:47:09 2015
|
||||||
|
# by: PyQt5 UI code generator 5.4
|
||||||
|
#
|
||||||
|
# WARNING! All changes made in this file will be lost!
|
||||||
|
|
||||||
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||||
|
|
||||||
|
class Ui_MetaEditorDialog(object):
|
||||||
|
def setupUi(self, MetaEditorDialog):
|
||||||
|
MetaEditorDialog.setObjectName("MetaEditorDialog")
|
||||||
|
MetaEditorDialog.resize(400, 295)
|
||||||
|
MetaEditorDialog.setMinimumSize(QtCore.QSize(400, 295))
|
||||||
|
MetaEditorDialog.setMaximumSize(QtCore.QSize(400, 295))
|
||||||
|
icon = QtGui.QIcon()
|
||||||
|
icon.addPixmap(QtGui.QPixmap(":/Icon/icons/comic2ebook.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
|
MetaEditorDialog.setWindowIcon(icon)
|
||||||
|
self.horizontalLayoutWidget = QtWidgets.QWidget(MetaEditorDialog)
|
||||||
|
self.horizontalLayoutWidget.setGeometry(QtCore.QRect(10, 260, 381, 32))
|
||||||
|
self.horizontalLayoutWidget.setObjectName("horizontalLayoutWidget")
|
||||||
|
self.horizontalLayout = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget)
|
||||||
|
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||||
|
self.StatusLabel = QtWidgets.QLabel(self.horizontalLayoutWidget)
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.StatusLabel.sizePolicy().hasHeightForWidth())
|
||||||
|
self.StatusLabel.setSizePolicy(sizePolicy)
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setPointSize(10)
|
||||||
|
font.setBold(True)
|
||||||
|
font.setWeight(75)
|
||||||
|
self.StatusLabel.setFont(font)
|
||||||
|
self.StatusLabel.setStyleSheet("color: rgb(255, 0, 0);")
|
||||||
|
self.StatusLabel.setObjectName("StatusLabel")
|
||||||
|
self.horizontalLayout.addWidget(self.StatusLabel)
|
||||||
|
self.OKButton = QtWidgets.QPushButton(self.horizontalLayoutWidget)
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.OKButton.sizePolicy().hasHeightForWidth())
|
||||||
|
self.OKButton.setSizePolicy(sizePolicy)
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setBold(True)
|
||||||
|
font.setWeight(75)
|
||||||
|
self.OKButton.setFont(font)
|
||||||
|
icon1 = QtGui.QIcon()
|
||||||
|
icon1.addPixmap(QtGui.QPixmap(":/Other/icons/convert.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
|
self.OKButton.setIcon(icon1)
|
||||||
|
self.OKButton.setObjectName("OKButton")
|
||||||
|
self.horizontalLayout.addWidget(self.OKButton)
|
||||||
|
self.CancelButton = QtWidgets.QPushButton(self.horizontalLayoutWidget)
|
||||||
|
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.CancelButton.sizePolicy().hasHeightForWidth())
|
||||||
|
self.CancelButton.setSizePolicy(sizePolicy)
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setBold(True)
|
||||||
|
font.setWeight(75)
|
||||||
|
self.CancelButton.setFont(font)
|
||||||
|
icon2 = QtGui.QIcon()
|
||||||
|
icon2.addPixmap(QtGui.QPixmap(":/Other/icons/clear.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
|
self.CancelButton.setIcon(icon2)
|
||||||
|
self.CancelButton.setObjectName("CancelButton")
|
||||||
|
self.horizontalLayout.addWidget(self.CancelButton)
|
||||||
|
self.EditorFrame = QtWidgets.QFrame(MetaEditorDialog)
|
||||||
|
self.EditorFrame.setGeometry(QtCore.QRect(10, 10, 381, 251))
|
||||||
|
self.EditorFrame.setObjectName("EditorFrame")
|
||||||
|
self.formLayoutWidget = QtWidgets.QWidget(self.EditorFrame)
|
||||||
|
self.formLayoutWidget.setGeometry(QtCore.QRect(0, 0, 381, 250))
|
||||||
|
self.formLayoutWidget.setObjectName("formLayoutWidget")
|
||||||
|
self.formLayout = QtWidgets.QFormLayout(self.formLayoutWidget)
|
||||||
|
self.formLayout.setContentsMargins(0, 0, 0, 0)
|
||||||
|
self.formLayout.setFieldGrowthPolicy(QtWidgets.QFormLayout.ExpandingFieldsGrow)
|
||||||
|
self.formLayout.setObjectName("formLayout")
|
||||||
|
self.label = QtWidgets.QLabel(self.formLayoutWidget)
|
||||||
|
self.label.setObjectName("label")
|
||||||
|
self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label)
|
||||||
|
self.SeriesLine = QtWidgets.QLineEdit(self.formLayoutWidget)
|
||||||
|
self.SeriesLine.setObjectName("SeriesLine")
|
||||||
|
self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.SeriesLine)
|
||||||
|
self.label_2 = QtWidgets.QLabel(self.formLayoutWidget)
|
||||||
|
self.label_2.setObjectName("label_2")
|
||||||
|
self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_2)
|
||||||
|
self.VolumeLine = QtWidgets.QLineEdit(self.formLayoutWidget)
|
||||||
|
self.VolumeLine.setObjectName("VolumeLine")
|
||||||
|
self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.VolumeLine)
|
||||||
|
self.label_3 = QtWidgets.QLabel(self.formLayoutWidget)
|
||||||
|
self.label_3.setObjectName("label_3")
|
||||||
|
self.formLayout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.label_3)
|
||||||
|
self.NumberLine = QtWidgets.QLineEdit(self.formLayoutWidget)
|
||||||
|
self.NumberLine.setObjectName("NumberLine")
|
||||||
|
self.formLayout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.NumberLine)
|
||||||
|
self.label_4 = QtWidgets.QLabel(self.formLayoutWidget)
|
||||||
|
self.label_4.setObjectName("label_4")
|
||||||
|
self.formLayout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.label_4)
|
||||||
|
self.WriterLine = QtWidgets.QLineEdit(self.formLayoutWidget)
|
||||||
|
self.WriterLine.setObjectName("WriterLine")
|
||||||
|
self.formLayout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.WriterLine)
|
||||||
|
self.label_5 = QtWidgets.QLabel(self.formLayoutWidget)
|
||||||
|
self.label_5.setObjectName("label_5")
|
||||||
|
self.formLayout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.label_5)
|
||||||
|
self.PencillerLine = QtWidgets.QLineEdit(self.formLayoutWidget)
|
||||||
|
self.PencillerLine.setObjectName("PencillerLine")
|
||||||
|
self.formLayout.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.PencillerLine)
|
||||||
|
self.label_6 = QtWidgets.QLabel(self.formLayoutWidget)
|
||||||
|
self.label_6.setObjectName("label_6")
|
||||||
|
self.formLayout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.label_6)
|
||||||
|
self.InkerLine = QtWidgets.QLineEdit(self.formLayoutWidget)
|
||||||
|
self.InkerLine.setObjectName("InkerLine")
|
||||||
|
self.formLayout.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.InkerLine)
|
||||||
|
self.label_7 = QtWidgets.QLabel(self.formLayoutWidget)
|
||||||
|
self.label_7.setObjectName("label_7")
|
||||||
|
self.formLayout.setWidget(7, QtWidgets.QFormLayout.LabelRole, self.label_7)
|
||||||
|
self.ColoristLine = QtWidgets.QLineEdit(self.formLayoutWidget)
|
||||||
|
self.ColoristLine.setObjectName("ColoristLine")
|
||||||
|
self.formLayout.setWidget(7, QtWidgets.QFormLayout.FieldRole, self.ColoristLine)
|
||||||
|
self.label_8 = QtWidgets.QLabel(self.formLayoutWidget)
|
||||||
|
self.label_8.setTextFormat(QtCore.Qt.RichText)
|
||||||
|
self.label_8.setOpenExternalLinks(True)
|
||||||
|
self.label_8.setObjectName("label_8")
|
||||||
|
self.formLayout.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.label_8)
|
||||||
|
self.MUidLine = QtWidgets.QLineEdit(self.formLayoutWidget)
|
||||||
|
self.MUidLine.setObjectName("MUidLine")
|
||||||
|
self.formLayout.setWidget(8, QtWidgets.QFormLayout.FieldRole, self.MUidLine)
|
||||||
|
|
||||||
|
self.retranslateUi(MetaEditorDialog)
|
||||||
|
QtCore.QMetaObject.connectSlotsByName(MetaEditorDialog)
|
||||||
|
|
||||||
|
def retranslateUi(self, MetaEditorDialog):
|
||||||
|
_translate = QtCore.QCoreApplication.translate
|
||||||
|
MetaEditorDialog.setWindowTitle(_translate("MetaEditorDialog", "Metadata editor"))
|
||||||
|
self.OKButton.setText(_translate("MetaEditorDialog", "Save"))
|
||||||
|
self.CancelButton.setText(_translate("MetaEditorDialog", "Cancel"))
|
||||||
|
self.label.setText(_translate("MetaEditorDialog", "Series:"))
|
||||||
|
self.label_2.setText(_translate("MetaEditorDialog", "Volume:"))
|
||||||
|
self.label_3.setText(_translate("MetaEditorDialog", "Number:"))
|
||||||
|
self.label_4.setText(_translate("MetaEditorDialog", "Writer:"))
|
||||||
|
self.label_5.setText(_translate("MetaEditorDialog", "Penciller:"))
|
||||||
|
self.label_6.setText(_translate("MetaEditorDialog", "Inker:"))
|
||||||
|
self.label_7.setText(_translate("MetaEditorDialog", "Colorist:"))
|
||||||
|
self.label_8.setText(_translate("MetaEditorDialog", "<html><head/><body><p><a href=\"https://github.com/ciromattia/kcc/wiki/Manga-Cover-Database-support\"><span style=\" text-decoration: underline; color:#0000ff;\">MUid:</span></a></p></body></html>"))
|
||||||
|
|
||||||
|
from . import KCC_rc
|
||||||
682
kcc/KCC_gui.py
682
kcc/KCC_gui.py
File diff suppressed because it is too large
Load Diff
7166
kcc/KCC_rc.py
7166
kcc/KCC_rc.py
File diff suppressed because it is too large
Load Diff
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
# Form implementation generated from reading ui file 'KCC.ui'
|
# Form implementation generated from reading ui file 'KCC.ui'
|
||||||
#
|
#
|
||||||
# Created: Sat Jan 25 17:36:53 2014
|
# Created: Sun Feb 8 09:50:43 2015
|
||||||
# by: PyQt5 UI code generator 5.2
|
# by: PyQt5 UI code generator 5.4
|
||||||
#
|
#
|
||||||
# WARNING! All changes made in this file will be lost!
|
# WARNING! All changes made in this file will be lost!
|
||||||
|
|
||||||
@@ -145,14 +145,14 @@ class Ui_KCC(object):
|
|||||||
self.JobList.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
|
self.JobList.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
|
||||||
self.JobList.setObjectName("JobList")
|
self.JobList.setObjectName("JobList")
|
||||||
self.BasicModeButton = QtWidgets.QPushButton(self.Form)
|
self.BasicModeButton = QtWidgets.QPushButton(self.Form)
|
||||||
self.BasicModeButton.setGeometry(QtCore.QRect(10, 10, 195, 32))
|
self.BasicModeButton.setGeometry(QtCore.QRect(10, 10, 141, 32))
|
||||||
font = QtGui.QFont()
|
font = QtGui.QFont()
|
||||||
font.setPointSize(9)
|
font.setPointSize(9)
|
||||||
self.BasicModeButton.setFont(font)
|
self.BasicModeButton.setFont(font)
|
||||||
self.BasicModeButton.setFocusPolicy(QtCore.Qt.NoFocus)
|
self.BasicModeButton.setFocusPolicy(QtCore.Qt.NoFocus)
|
||||||
self.BasicModeButton.setObjectName("BasicModeButton")
|
self.BasicModeButton.setObjectName("BasicModeButton")
|
||||||
self.AdvModeButton = QtWidgets.QPushButton(self.Form)
|
self.AdvModeButton = QtWidgets.QPushButton(self.Form)
|
||||||
self.AdvModeButton.setGeometry(QtCore.QRect(217, 10, 195, 32))
|
self.AdvModeButton.setGeometry(QtCore.QRect(261, 10, 151, 32))
|
||||||
font = QtGui.QFont()
|
font = QtGui.QFont()
|
||||||
font.setPointSize(9)
|
font.setPointSize(9)
|
||||||
self.AdvModeButton.setFont(font)
|
self.AdvModeButton.setFont(font)
|
||||||
@@ -231,6 +231,16 @@ class Ui_KCC(object):
|
|||||||
self.customHeight.setMaxLength(4)
|
self.customHeight.setMaxLength(4)
|
||||||
self.customHeight.setObjectName("customHeight")
|
self.customHeight.setObjectName("customHeight")
|
||||||
self.gridLayout_2.addWidget(self.customHeight, 0, 3, 1, 1)
|
self.gridLayout_2.addWidget(self.customHeight, 0, 3, 1, 1)
|
||||||
|
self.EditorButton = QtWidgets.QPushButton(self.Form)
|
||||||
|
self.EditorButton.setGeometry(QtCore.QRect(160, 10, 91, 32))
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setPointSize(9)
|
||||||
|
self.EditorButton.setFont(font)
|
||||||
|
self.EditorButton.setFocusPolicy(QtCore.Qt.NoFocus)
|
||||||
|
icon5 = QtGui.QIcon()
|
||||||
|
icon5.addPixmap(QtGui.QPixmap(":/Other/icons/editor.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
|
self.EditorButton.setIcon(icon5)
|
||||||
|
self.EditorButton.setObjectName("EditorButton")
|
||||||
KCC.setCentralWidget(self.Form)
|
KCC.setCentralWidget(self.Form)
|
||||||
self.statusBar = QtWidgets.QStatusBar(KCC)
|
self.statusBar = QtWidgets.QStatusBar(KCC)
|
||||||
font = QtGui.QFont()
|
font = QtGui.QFont()
|
||||||
@@ -260,28 +270,30 @@ class Ui_KCC(object):
|
|||||||
def retranslateUi(self, KCC):
|
def retranslateUi(self, KCC):
|
||||||
_translate = QtCore.QCoreApplication.translate
|
_translate = QtCore.QCoreApplication.translate
|
||||||
KCC.setWindowTitle(_translate("KCC", "Kindle Comic Converter"))
|
KCC.setWindowTitle(_translate("KCC", "Kindle Comic Converter"))
|
||||||
self.ProcessingBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Disable image optimizations.<br/>Input images must be already resized.</p></body></html>"))
|
self.ProcessingBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Disable image optimizations.<br/><span style=\" font-weight:600;\">Input images must be already resized.</span></p></body></html>"))
|
||||||
self.ProcessingBox.setText(_translate("KCC", "No optimisation"))
|
self.ProcessingBox.setText(_translate("KCC", "No optimisation"))
|
||||||
self.UpscaleBox.setToolTip(_translate("KCC", "<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("KCC", "<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.setText(_translate("KCC", "Stretch/Upscale"))
|
self.UpscaleBox.setText(_translate("KCC", "Stretch/Upscale"))
|
||||||
self.WebtoonBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Enable auto-splitting of webtoons like <span style=\" font-style:italic;\">Tower of God</span> or <span style=\" font-style:italic;\">Noblesse</span>.<br/>Pages with a low width, high height and vertical panel flow.</p></body></html>"))
|
self.WebtoonBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Enable special parsing mode for WebToons.</p></body></html>"))
|
||||||
self.WebtoonBox.setText(_translate("KCC", "Webtoon mode"))
|
self.WebtoonBox.setText(_translate("KCC", "Webtoon mode"))
|
||||||
self.NoDitheringBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Create PNG files instead JPEG.<br/>Quality increase is not noticeable on most of devices.<br/>Output files <span style=\" font-weight:600;\">might</span> be smaller.<br/><span style=\" font-weight:600;\">MOBI conversion will be much slower.</span></p></body></html>"))
|
self.NoDitheringBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Create PNG files instead JPEG.<br/>Quality increase is not noticeable on most of devices.<br/>Output files <span style=\" font-weight:600;\">might</span> be smaller.<br/><span style=\" font-weight:600;\">MOBI conversion will be much slower.</span></p></body></html>"))
|
||||||
self.NoDitheringBox.setText(_translate("KCC", "PNG output"))
|
self.NoDitheringBox.setText(_translate("KCC", "PNG output"))
|
||||||
self.BorderBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Autodetection<br/></span>Color of margins fill will be detected automatically.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - White<br/></span>Margins will be filled with white color.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Black<br/></span>Margins will be filled with black color.</p></body></html>"))
|
self.BorderBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Autodetection<br/></span>Color of margins fill will be detected automatically.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - White<br/></span>Margins will be filled with white color.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Black<br/></span>Margins will be filled with black color.</p></body></html>"))
|
||||||
self.BorderBox.setText(_translate("KCC", "W/B margins"))
|
self.BorderBox.setText(_translate("KCC", "W/B margins"))
|
||||||
self.NoRotateBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Disable splitting and rotation.</p></body></html>"))
|
self.NoRotateBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Disable page splitting and rotation.</p></body></html>"))
|
||||||
self.NoRotateBox.setText(_translate("KCC", "No split/rotate"))
|
self.NoRotateBox.setText(_translate("KCC", "No split/rotate"))
|
||||||
self.DeviceBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Target device.</p></body></html>"))
|
self.DeviceBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Target device.</p></body></html>"))
|
||||||
self.FormatBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Output format.</p></body></html>"))
|
self.FormatBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Output format.</p></body></html>"))
|
||||||
self.ConvertButton.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Shift+Click to select the output directory.</p></body></html>"))
|
self.ConvertButton.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Shift+Click to select the output directory.</p></body></html>"))
|
||||||
self.ConvertButton.setText(_translate("KCC", "Convert"))
|
self.ConvertButton.setText(_translate("KCC", "Convert"))
|
||||||
|
self.DirectoryButton.setToolTip(_translate("KCC", "<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("KCC", "Add directory"))
|
self.DirectoryButton.setText(_translate("KCC", "Add directory"))
|
||||||
|
self.FileButton.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Add CBR, CBZ, CB7 or PDF file to queue.</p></body></html>"))
|
||||||
self.FileButton.setText(_translate("KCC", "Add file"))
|
self.FileButton.setText(_translate("KCC", "Add file"))
|
||||||
self.ClearButton.setText(_translate("KCC", "Clear list"))
|
self.ClearButton.setText(_translate("KCC", "Clear list"))
|
||||||
self.MangaBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Enable right-to-left reading.</p></body></html>"))
|
self.MangaBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Enable right-to-left reading.</p></body></html>"))
|
||||||
self.MangaBox.setText(_translate("KCC", "Manga mode"))
|
self.MangaBox.setText(_translate("KCC", "Manga mode"))
|
||||||
self.QualityBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Normal quality mode<br/></span><span style=\" font-style:italic;\">Use it when Panel View support is not needed.</span><span style=\" font-weight:600; text-decoration: underline;\"><br/></span>- Maximum quality when zoom is not enabled.<br/>- Poor quality when zoom is enabled.<br/>- Lowest file size.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - High quality mode<br/></span><span style=\" font-style:italic;\">Not zoomed images </span><span style=\" font-weight:600; font-style:italic;\">might </span><span style=\" font-style:italic;\">be blurry.</span><span style=\" font-weight:600; text-decoration: underline;\"><br/></span>- High quality when zoom is not enabled.<br/>- Maximum quality when zoom is enabled.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Ultra quality mode<br/></span><span style=\" font-style:italic;\">Maximum possible quality.</span><span style=\" font-weight:600; text-decoration: underline;\"><br/></span>- Maximum quality when zoom is not enabled.<br/>- Maximum quality when zoom is enabled.<br/>- Very high file size.</p></body></html>"))
|
self.QualityBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Quality of Panel View/zoom. Highly impact size of output file.<br/><span style=\" font-weight:600;\">This option control only quality of magnification!</span></p></body></html>"))
|
||||||
self.QualityBox.setText(_translate("KCC", "High/Ultra quality"))
|
self.QualityBox.setText(_translate("KCC", "High/Ultra quality"))
|
||||||
self.RotateBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Disable splitting of two-page spreads.<br/>They will be rotated instead.</p></body></html>"))
|
self.RotateBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Disable splitting of two-page spreads.<br/>They will be rotated instead.</p></body></html>"))
|
||||||
self.RotateBox.setText(_translate("KCC", "Horizontal mode"))
|
self.RotateBox.setText(_translate("KCC", "Horizontal mode"))
|
||||||
@@ -298,6 +310,7 @@ class Ui_KCC(object):
|
|||||||
self.hLabel.setText(_translate("KCC", "Custom height: "))
|
self.hLabel.setText(_translate("KCC", "Custom height: "))
|
||||||
self.customHeight.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Resolution of target device.</p></body></html>"))
|
self.customHeight.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Resolution of target device.</p></body></html>"))
|
||||||
self.customHeight.setInputMask(_translate("KCC", "0000"))
|
self.customHeight.setInputMask(_translate("KCC", "0000"))
|
||||||
|
self.EditorButton.setText(_translate("KCC", "Editor"))
|
||||||
self.ActionBasic.setText(_translate("KCC", "Basic"))
|
self.ActionBasic.setText(_translate("KCC", "Basic"))
|
||||||
self.ActionAdvanced.setText(_translate("KCC", "Advanced"))
|
self.ActionAdvanced.setText(_translate("KCC", "Advanced"))
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
# Form implementation generated from reading ui file 'KCC-Linux.ui'
|
# Form implementation generated from reading ui file 'gui/KCC-Linux.ui'
|
||||||
#
|
#
|
||||||
# Created: Sat Jan 25 17:37:02 2014
|
# Created: Sun Feb 8 03:10:09 2015
|
||||||
# by: PyQt5 UI code generator 5.2
|
# by: PyQt5 UI code generator 5.2.1
|
||||||
#
|
#
|
||||||
# WARNING! All changes made in this file will be lost!
|
# WARNING! All changes made in this file will be lost!
|
||||||
|
|
||||||
@@ -182,11 +182,9 @@ class Ui_KCC(object):
|
|||||||
self.JobList.setProperty("showDropIndicator", False)
|
self.JobList.setProperty("showDropIndicator", False)
|
||||||
self.JobList.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)
|
self.JobList.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)
|
||||||
self.JobList.setIconSize(QtCore.QSize(18, 18))
|
self.JobList.setIconSize(QtCore.QSize(18, 18))
|
||||||
self.JobList.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
|
|
||||||
self.JobList.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
|
|
||||||
self.JobList.setObjectName("JobList")
|
self.JobList.setObjectName("JobList")
|
||||||
self.BasicModeButton = QtWidgets.QPushButton(self.Form)
|
self.BasicModeButton = QtWidgets.QPushButton(self.Form)
|
||||||
self.BasicModeButton.setGeometry(QtCore.QRect(10, 10, 195, 32))
|
self.BasicModeButton.setGeometry(QtCore.QRect(10, 10, 141, 32))
|
||||||
font = QtGui.QFont()
|
font = QtGui.QFont()
|
||||||
font.setFamily("DejaVu Sans")
|
font.setFamily("DejaVu Sans")
|
||||||
font.setPointSize(9)
|
font.setPointSize(9)
|
||||||
@@ -194,7 +192,7 @@ class Ui_KCC(object):
|
|||||||
self.BasicModeButton.setFocusPolicy(QtCore.Qt.NoFocus)
|
self.BasicModeButton.setFocusPolicy(QtCore.Qt.NoFocus)
|
||||||
self.BasicModeButton.setObjectName("BasicModeButton")
|
self.BasicModeButton.setObjectName("BasicModeButton")
|
||||||
self.AdvModeButton = QtWidgets.QPushButton(self.Form)
|
self.AdvModeButton = QtWidgets.QPushButton(self.Form)
|
||||||
self.AdvModeButton.setGeometry(QtCore.QRect(217, 10, 195, 32))
|
self.AdvModeButton.setGeometry(QtCore.QRect(260, 10, 151, 32))
|
||||||
font = QtGui.QFont()
|
font = QtGui.QFont()
|
||||||
font.setFamily("DejaVu Sans")
|
font.setFamily("DejaVu Sans")
|
||||||
font.setPointSize(9)
|
font.setPointSize(9)
|
||||||
@@ -301,6 +299,17 @@ class Ui_KCC(object):
|
|||||||
self.customHeight.setMaxLength(4)
|
self.customHeight.setMaxLength(4)
|
||||||
self.customHeight.setObjectName("customHeight")
|
self.customHeight.setObjectName("customHeight")
|
||||||
self.gridLayout_2.addWidget(self.customHeight, 0, 3, 1, 1)
|
self.gridLayout_2.addWidget(self.customHeight, 0, 3, 1, 1)
|
||||||
|
self.EditorButton = QtWidgets.QPushButton(self.Form)
|
||||||
|
self.EditorButton.setGeometry(QtCore.QRect(160, 10, 91, 32))
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setFamily("DejaVu Sans")
|
||||||
|
font.setPointSize(9)
|
||||||
|
self.EditorButton.setFont(font)
|
||||||
|
self.EditorButton.setFocusPolicy(QtCore.Qt.NoFocus)
|
||||||
|
icon5 = QtGui.QIcon()
|
||||||
|
icon5.addPixmap(QtGui.QPixmap(":/Other/icons/editor.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
|
self.EditorButton.setIcon(icon5)
|
||||||
|
self.EditorButton.setObjectName("EditorButton")
|
||||||
KCC.setCentralWidget(self.Form)
|
KCC.setCentralWidget(self.Form)
|
||||||
self.statusBar = QtWidgets.QStatusBar(KCC)
|
self.statusBar = QtWidgets.QStatusBar(KCC)
|
||||||
font = QtGui.QFont()
|
font = QtGui.QFont()
|
||||||
@@ -329,28 +338,30 @@ class Ui_KCC(object):
|
|||||||
def retranslateUi(self, KCC):
|
def retranslateUi(self, KCC):
|
||||||
_translate = QtCore.QCoreApplication.translate
|
_translate = QtCore.QCoreApplication.translate
|
||||||
KCC.setWindowTitle(_translate("KCC", "Kindle Comic Converter"))
|
KCC.setWindowTitle(_translate("KCC", "Kindle Comic Converter"))
|
||||||
self.ProcessingBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Disable image optimizations.<br/>Input images must be already resized.</p></body></html>"))
|
self.ProcessingBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Disable image optimizations.<br/><span style=\" font-weight:600;\">Input images must be already resized.</span></p></body></html>"))
|
||||||
self.ProcessingBox.setText(_translate("KCC", "No optimisation"))
|
self.ProcessingBox.setText(_translate("KCC", "No optimisation"))
|
||||||
self.UpscaleBox.setToolTip(_translate("KCC", "<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("KCC", "<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.setText(_translate("KCC", "Stretch/Upscale"))
|
self.UpscaleBox.setText(_translate("KCC", "Stretch/Upscale"))
|
||||||
self.WebtoonBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Enable auto-splitting of webtoons like <span style=\" font-style:italic;\">Tower of God</span> or <span style=\" font-style:italic;\">Noblesse</span>.<br/>Pages with a low width, high height and vertical panel flow.</p></body></html>"))
|
self.WebtoonBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Enable special parsing mode for WebToons.</p></body></html>"))
|
||||||
self.WebtoonBox.setText(_translate("KCC", "Webtoon mode"))
|
self.WebtoonBox.setText(_translate("KCC", "Webtoon mode"))
|
||||||
self.NoDitheringBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Create PNG files instead JPEG.<br/>Quality increase is not noticeable on most of devices.<br/>Output files <span style=\" font-weight:600;\">might</span> be smaller.<br/><span style=\" font-weight:600;\">MOBI conversion will be much slower.</span></p></body></html>"))
|
self.NoDitheringBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Create PNG files instead JPEG.<br/>Quality increase is not noticeable on most of devices.<br/>Output files <span style=\" font-weight:600;\">might</span> be smaller.<br/><span style=\" font-weight:600;\">MOBI conversion will be much slower.</span></p></body></html>"))
|
||||||
self.NoDitheringBox.setText(_translate("KCC", "PNG output"))
|
self.NoDitheringBox.setText(_translate("KCC", "PNG output"))
|
||||||
self.BorderBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Autodetection<br/></span>Color of margins fill will be detected automatically.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - White<br/></span>Margins will be filled with white color.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Black<br/></span>Margins will be filled with black color.</p></body></html>"))
|
self.BorderBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Autodetection<br/></span>Color of margins fill will be detected automatically.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - White<br/></span>Margins will be filled with white color.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Black<br/></span>Margins will be filled with black color.</p></body></html>"))
|
||||||
self.BorderBox.setText(_translate("KCC", "W/B margins"))
|
self.BorderBox.setText(_translate("KCC", "W/B margins"))
|
||||||
self.NoRotateBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Disable splitting and rotation.</p></body></html>"))
|
self.NoRotateBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Disable page splitting and rotation.</p></body></html>"))
|
||||||
self.NoRotateBox.setText(_translate("KCC", "No split/rotate"))
|
self.NoRotateBox.setText(_translate("KCC", "No split/rotate"))
|
||||||
self.DeviceBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Target device.</p></body></html>"))
|
self.DeviceBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Target device.</p></body></html>"))
|
||||||
self.FormatBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Output format.</p></body></html>"))
|
self.FormatBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Output format.</p></body></html>"))
|
||||||
self.ConvertButton.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Shift+Click to select the output directory.</p></body></html>"))
|
self.ConvertButton.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Shift+Click to select the output directory.</p></body></html>"))
|
||||||
self.ConvertButton.setText(_translate("KCC", "Convert"))
|
self.ConvertButton.setText(_translate("KCC", "Convert"))
|
||||||
|
self.DirectoryButton.setToolTip(_translate("KCC", "<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("KCC", "Add directory"))
|
self.DirectoryButton.setText(_translate("KCC", "Add directory"))
|
||||||
|
self.FileButton.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Add CBR, CBZ, CB7 or PDF file to queue.</p></body></html>"))
|
||||||
self.FileButton.setText(_translate("KCC", "Add file"))
|
self.FileButton.setText(_translate("KCC", "Add file"))
|
||||||
self.ClearButton.setText(_translate("KCC", "Clear list"))
|
self.ClearButton.setText(_translate("KCC", "Clear list"))
|
||||||
self.MangaBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Enable right-to-left reading.</p></body></html>"))
|
self.MangaBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Enable right-to-left reading.</p></body></html>"))
|
||||||
self.MangaBox.setText(_translate("KCC", "Manga mode"))
|
self.MangaBox.setText(_translate("KCC", "Manga mode"))
|
||||||
self.QualityBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Normal quality mode<br/></span><span style=\" font-style:italic;\">Use it when Panel View support is not needed.<br/></span>- Maximum quality when zoom is not enabled.<br/>- Poor quality when zoom is enabled.<br/>- Lowest file size.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - High quality mode<br/></span><span style=\" font-style:italic;\">Not zoomed images </span><span style=\" font-weight:600; font-style:italic;\">might</span><span style=\" font-style:italic;\"> be blurry.<br/></span>- High quality when zoom is not enabled.<br/>- Maximum quality when zoom is enabled.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Ultra quality mode<br/></span><span style=\" font-style:italic;\">Maximum possible quality.<br/></span>- Maximum quality when zoom is not enabled.<br/>- Maximum quality when zoom is enabled.<br/>- Very high file size.</p></body></html>"))
|
self.QualityBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Quality of Panel View/zoom. Highly impact size of output file.<br/><span style=\" font-weight:600;\">This option control only quality of magnification!</span></p></body></html>"))
|
||||||
self.QualityBox.setText(_translate("KCC", "High/Ultra quality"))
|
self.QualityBox.setText(_translate("KCC", "High/Ultra quality"))
|
||||||
self.RotateBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Disable splitting of two-page spreads.<br/>They will be rotated instead.</p></body></html>"))
|
self.RotateBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Disable splitting of two-page spreads.<br/>They will be rotated instead.</p></body></html>"))
|
||||||
self.RotateBox.setText(_translate("KCC", "Horizontal mode"))
|
self.RotateBox.setText(_translate("KCC", "Horizontal mode"))
|
||||||
@@ -359,14 +370,15 @@ class Ui_KCC(object):
|
|||||||
self.GammaLabel.setText(_translate("KCC", "Gamma: Auto"))
|
self.GammaLabel.setText(_translate("KCC", "Gamma: Auto"))
|
||||||
self.ColorBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Don\'t convert images to grayscale.</p></body></html>"))
|
self.ColorBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Don\'t convert images to grayscale.</p></body></html>"))
|
||||||
self.ColorBox.setText(_translate("KCC", "Color mode"))
|
self.ColorBox.setText(_translate("KCC", "Color mode"))
|
||||||
self.wLabel.setToolTip(_translate("KCC", "<html><head/><body><p>Resolution of target device.</p></body></html>"))
|
self.wLabel.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Resolution of target device.</p></body></html>"))
|
||||||
self.wLabel.setText(_translate("KCC", "Custom width: "))
|
self.wLabel.setText(_translate("KCC", "Custom width: "))
|
||||||
self.customWidth.setToolTip(_translate("KCC", "<html><head/><body><p>Resolution of target device.</p></body></html>"))
|
self.customWidth.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Resolution of target device.</p></body></html>"))
|
||||||
self.customWidth.setInputMask(_translate("KCC", "0000"))
|
self.customWidth.setInputMask(_translate("KCC", "0000"))
|
||||||
self.hLabel.setToolTip(_translate("KCC", "<html><head/><body><p>Resolution of target device.</p></body></html>"))
|
self.hLabel.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Resolution of target device.</p></body></html>"))
|
||||||
self.hLabel.setText(_translate("KCC", "Custom height: "))
|
self.hLabel.setText(_translate("KCC", "Custom height: "))
|
||||||
self.customHeight.setToolTip(_translate("KCC", "<html><head/><body><p>Resolution of target device.</p></body></html>"))
|
self.customHeight.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Resolution of target device.</p></body></html>"))
|
||||||
self.customHeight.setInputMask(_translate("KCC", "0000"))
|
self.customHeight.setInputMask(_translate("KCC", "0000"))
|
||||||
|
self.EditorButton.setText(_translate("KCC", "Editor"))
|
||||||
self.ActionBasic.setText(_translate("KCC", "Basic"))
|
self.ActionBasic.setText(_translate("KCC", "Basic"))
|
||||||
self.ActionAdvanced.setText(_translate("KCC", "Advanced"))
|
self.ActionAdvanced.setText(_translate("KCC", "Advanced"))
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
# Form implementation generated from reading ui file 'KCC-OSX.ui'
|
# Form implementation generated from reading ui file '/Users/pawelj/Documents/KCC/gui/KCC-OSX.ui'
|
||||||
#
|
#
|
||||||
# Created: Sat Jan 25 17:37:10 2014
|
# Created: Sun Feb 8 12:37:33 2015
|
||||||
# by: PyQt5 UI code generator 5.2
|
# by: PyQt5 UI code generator 5.4
|
||||||
#
|
#
|
||||||
# WARNING! All changes made in this file will be lost!
|
# WARNING! All changes made in this file will be lost!
|
||||||
|
|
||||||
@@ -192,7 +192,7 @@ class Ui_KCC(object):
|
|||||||
self.JobList.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
|
self.JobList.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
|
||||||
self.JobList.setObjectName("JobList")
|
self.JobList.setObjectName("JobList")
|
||||||
self.BasicModeButton = QtWidgets.QPushButton(self.Form)
|
self.BasicModeButton = QtWidgets.QPushButton(self.Form)
|
||||||
self.BasicModeButton.setGeometry(QtCore.QRect(5, 10, 210, 41))
|
self.BasicModeButton.setGeometry(QtCore.QRect(5, 10, 156, 41))
|
||||||
font = QtGui.QFont()
|
font = QtGui.QFont()
|
||||||
font.setFamily("Lucida Grande")
|
font.setFamily("Lucida Grande")
|
||||||
font.setPointSize(12)
|
font.setPointSize(12)
|
||||||
@@ -202,7 +202,7 @@ class Ui_KCC(object):
|
|||||||
self.BasicModeButton.setFocusPolicy(QtCore.Qt.NoFocus)
|
self.BasicModeButton.setFocusPolicy(QtCore.Qt.NoFocus)
|
||||||
self.BasicModeButton.setObjectName("BasicModeButton")
|
self.BasicModeButton.setObjectName("BasicModeButton")
|
||||||
self.AdvModeButton = QtWidgets.QPushButton(self.Form)
|
self.AdvModeButton = QtWidgets.QPushButton(self.Form)
|
||||||
self.AdvModeButton.setGeometry(QtCore.QRect(207, 10, 210, 41))
|
self.AdvModeButton.setGeometry(QtCore.QRect(260, 10, 156, 41))
|
||||||
font = QtGui.QFont()
|
font = QtGui.QFont()
|
||||||
font.setFamily("Lucida Grande")
|
font.setFamily("Lucida Grande")
|
||||||
font.setPointSize(12)
|
font.setPointSize(12)
|
||||||
@@ -323,6 +323,17 @@ class Ui_KCC(object):
|
|||||||
self.customHeight.setMaxLength(4)
|
self.customHeight.setMaxLength(4)
|
||||||
self.customHeight.setObjectName("customHeight")
|
self.customHeight.setObjectName("customHeight")
|
||||||
self.gridLayout_2.addWidget(self.customHeight, 0, 3, 1, 1)
|
self.gridLayout_2.addWidget(self.customHeight, 0, 3, 1, 1)
|
||||||
|
self.EditorButton = QtWidgets.QPushButton(self.Form)
|
||||||
|
self.EditorButton.setGeometry(QtCore.QRect(160, 10, 101, 41))
|
||||||
|
font = QtGui.QFont()
|
||||||
|
font.setFamily("Lucida Grande")
|
||||||
|
font.setPointSize(12)
|
||||||
|
self.EditorButton.setFont(font)
|
||||||
|
self.EditorButton.setFocusPolicy(QtCore.Qt.NoFocus)
|
||||||
|
icon5 = QtGui.QIcon()
|
||||||
|
icon5.addPixmap(QtGui.QPixmap(":/Other/icons/editor.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||||
|
self.EditorButton.setIcon(icon5)
|
||||||
|
self.EditorButton.setObjectName("EditorButton")
|
||||||
KCC.setCentralWidget(self.Form)
|
KCC.setCentralWidget(self.Form)
|
||||||
self.statusBar = QtWidgets.QStatusBar(KCC)
|
self.statusBar = QtWidgets.QStatusBar(KCC)
|
||||||
font = QtGui.QFont()
|
font = QtGui.QFont()
|
||||||
@@ -352,28 +363,30 @@ class Ui_KCC(object):
|
|||||||
def retranslateUi(self, KCC):
|
def retranslateUi(self, KCC):
|
||||||
_translate = QtCore.QCoreApplication.translate
|
_translate = QtCore.QCoreApplication.translate
|
||||||
KCC.setWindowTitle(_translate("KCC", "Kindle Comic Converter"))
|
KCC.setWindowTitle(_translate("KCC", "Kindle Comic Converter"))
|
||||||
self.ProcessingBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Disable image optimizations.<br/>Input images must be already resized.</p></body></html>"))
|
self.ProcessingBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Disable image optimizations.<br/><span style=\" font-weight:600;\">Input images must be already resized.</span></p></body></html>"))
|
||||||
self.ProcessingBox.setText(_translate("KCC", "No optimisation"))
|
self.ProcessingBox.setText(_translate("KCC", "No optimisation"))
|
||||||
self.UpscaleBox.setToolTip(_translate("KCC", "<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("KCC", "<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.setText(_translate("KCC", "Stretch/Upscale"))
|
self.UpscaleBox.setText(_translate("KCC", "Stretch/Upscale"))
|
||||||
self.WebtoonBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Enable auto-splitting of webtoons like <span style=\" font-style:italic;\">Tower of God</span> or <span style=\" font-style:italic;\">Noblesse</span>.<br/>Pages with a low width, high height and vertical panel flow.</p></body></html>"))
|
self.WebtoonBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Enable special parsing mode for WebToons.</p></body></html>"))
|
||||||
self.WebtoonBox.setText(_translate("KCC", "Webtoon mode"))
|
self.WebtoonBox.setText(_translate("KCC", "Webtoon mode"))
|
||||||
self.NoDitheringBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Create PNG files instead JPEG.<br/>Quality increase is not noticeable on most of devices.<br/>Output files <span style=\" font-weight:600;\">might</span> be smaller.<br/><span style=\" font-weight:600;\">MOBI conversion will be much slower.</span></p></body></html>"))
|
self.NoDitheringBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Create PNG files instead JPEG.<br/>Quality increase is not noticeable on most of devices.<br/>Output files <span style=\" font-weight:600;\">might</span> be smaller.<br/><span style=\" font-weight:600;\">MOBI conversion will be much slower.</span></p></body></html>"))
|
||||||
self.NoDitheringBox.setText(_translate("KCC", "PNG output"))
|
self.NoDitheringBox.setText(_translate("KCC", "PNG output"))
|
||||||
self.BorderBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Autodetection<br/></span>Color of margins fill will be detected automatically.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - White<br/></span>Margins will be filled with white color.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Black<br/></span>Margins will be filled with black color.</p></body></html>"))
|
self.BorderBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Autodetection<br/></span>Color of margins fill will be detected automatically.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - White<br/></span>Margins will be filled with white color.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Black<br/></span>Margins will be filled with black color.</p></body></html>"))
|
||||||
self.BorderBox.setText(_translate("KCC", "W/B margins"))
|
self.BorderBox.setText(_translate("KCC", "W/B margins"))
|
||||||
self.NoRotateBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Disable splitting and rotation.</p></body></html>"))
|
self.NoRotateBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Disable page splitting and rotation.</p></body></html>"))
|
||||||
self.NoRotateBox.setText(_translate("KCC", "No split/rotate"))
|
self.NoRotateBox.setText(_translate("KCC", "No split/rotate"))
|
||||||
self.DeviceBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Target device.</p></body></html>"))
|
self.DeviceBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Target device.</p></body></html>"))
|
||||||
self.FormatBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Output format.</p></body></html>"))
|
self.FormatBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Output format.</p></body></html>"))
|
||||||
self.ConvertButton.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Shift+Click to select the output directory.</p></body></html>"))
|
self.ConvertButton.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Shift+Click to select the output directory.</p></body></html>"))
|
||||||
self.ConvertButton.setText(_translate("KCC", "Convert"))
|
self.ConvertButton.setText(_translate("KCC", "Convert"))
|
||||||
|
self.DirectoryButton.setToolTip(_translate("KCC", "<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("KCC", "Add directory"))
|
self.DirectoryButton.setText(_translate("KCC", "Add directory"))
|
||||||
|
self.FileButton.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Add CBR, CBZ, CB7 or PDF file to queue.</p></body></html>"))
|
||||||
self.FileButton.setText(_translate("KCC", "Add file"))
|
self.FileButton.setText(_translate("KCC", "Add file"))
|
||||||
self.ClearButton.setText(_translate("KCC", "Clear list"))
|
self.ClearButton.setText(_translate("KCC", "Clear list"))
|
||||||
self.MangaBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Enable right-to-left reading.</p></body></html>"))
|
self.MangaBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Enable right-to-left reading.</p></body></html>"))
|
||||||
self.MangaBox.setText(_translate("KCC", "Manga mode"))
|
self.MangaBox.setText(_translate("KCC", "Manga mode"))
|
||||||
self.QualityBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Normal quality mode<br/></span><span style=\" font-style:italic;\">Use it when Panel View support is not needed.<br/></span>- Maximum quality when zoom is not enabled.<br/>- Poor quality when zoom is enabled.<br/>- Lowest file size.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - High quality mode<br/></span><span style=\" font-style:italic;\">Not zoomed image </span><span style=\" font-weight:600; font-style:italic;\">might</span><span style=\" font-style:italic;\"> be a little blurry.<br/></span>- High quality when zoom is not enabled.<br/>- Maximum quality when zoom is enabled.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Ultra quality mode<br/></span><span style=\" font-style:italic;\">Maximum possible quality.<br/></span>- Maximum quality when zoom is not enabled.<br/>- Maximum quality when zoom is enabled.<br/>- Very high file size.</p></body></html>"))
|
self.QualityBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Quality of Panel View/zoom. Highly impact size of output file.<br/><span style=\" font-weight:600;\">This option control only quality of magnification!</span></p></body></html>"))
|
||||||
self.QualityBox.setText(_translate("KCC", "High/Ultra quality"))
|
self.QualityBox.setText(_translate("KCC", "High/Ultra quality"))
|
||||||
self.RotateBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Disable splitting of two-page spreads.<br/>They will be rotated instead.</p></body></html>"))
|
self.RotateBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Disable splitting of two-page spreads.<br/>They will be rotated instead.</p></body></html>"))
|
||||||
self.RotateBox.setText(_translate("KCC", "Horizontal mode"))
|
self.RotateBox.setText(_translate("KCC", "Horizontal mode"))
|
||||||
@@ -390,6 +403,7 @@ class Ui_KCC(object):
|
|||||||
self.hLabel.setText(_translate("KCC", "Custom height: "))
|
self.hLabel.setText(_translate("KCC", "Custom height: "))
|
||||||
self.customHeight.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Resolution of target device.</p></body></html>"))
|
self.customHeight.setToolTip(_translate("KCC", "<html><head/><body><p style=\'white-space:pre\'>Resolution of target device.</p></body></html>"))
|
||||||
self.customHeight.setInputMask(_translate("KCC", "0000"))
|
self.customHeight.setInputMask(_translate("KCC", "0000"))
|
||||||
|
self.EditorButton.setText(_translate("KCC", "Editor"))
|
||||||
self.ActionBasic.setText(_translate("KCC", "Basic"))
|
self.ActionBasic.setText(_translate("KCC", "Basic"))
|
||||||
self.ActionAdvanced.setText(_translate("KCC", "Advanced"))
|
self.ActionAdvanced.setText(_translate("KCC", "Advanced"))
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
__version__ = '4.0.1'
|
__version__ = '4.6.4'
|
||||||
__license__ = 'ISC'
|
__license__ = 'ISC'
|
||||||
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
|
__copyright__ = '2012-2015, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||||
# Copyright (c) 2013-2014 Pawel Jastrzebski <pawelj@vulturis.eu>
|
# Copyright (c) 2013-2015 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
#
|
#
|
||||||
# Permission to use, copy, modify, and/or distribute this software for
|
# Permission to use, copy, modify, and/or distribute this software for
|
||||||
# any purpose with or without fee is hereby granted, provided that the
|
# any purpose with or without fee is hereby granted, provided that the
|
||||||
@@ -16,17 +16,15 @@
|
|||||||
# PERFORMANCE OF THIS SOFTWARE.
|
# PERFORMANCE OF THIS SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__license__ = 'ISC'
|
|
||||||
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
|
|
||||||
__docformat__ = 'restructuredtext en'
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
from zipfile import is_zipfile, ZipFile
|
from zipfile import is_zipfile, ZipFile
|
||||||
from subprocess import STDOUT, PIPE
|
from subprocess import STDOUT, PIPE
|
||||||
from psutil import Popen
|
from psutil import Popen
|
||||||
from shutil import move, copy
|
from shutil import move, copy
|
||||||
|
from scandir import walk
|
||||||
from . import rarfile
|
from . import rarfile
|
||||||
|
from .shared import check7ZFile as is_7zfile, saferReplace
|
||||||
|
|
||||||
|
|
||||||
class CBxArchive:
|
class CBxArchive:
|
||||||
@@ -36,7 +34,7 @@ class CBxArchive:
|
|||||||
self.compressor = 'zip'
|
self.compressor = 'zip'
|
||||||
elif rarfile.is_rarfile(origFileName):
|
elif rarfile.is_rarfile(origFileName):
|
||||||
self.compressor = 'rar'
|
self.compressor = 'rar'
|
||||||
elif origFileName.endswith('.7z') or origFileName.endswith('.cb7'):
|
elif is_7zfile(origFileName):
|
||||||
self.compressor = '7z'
|
self.compressor = '7z'
|
||||||
else:
|
else:
|
||||||
self.compressor = None
|
self.compressor = None
|
||||||
@@ -48,7 +46,7 @@ class CBxArchive:
|
|||||||
cbzFile = ZipFile(self.origFileName)
|
cbzFile = ZipFile(self.origFileName)
|
||||||
filelist = []
|
filelist = []
|
||||||
for f in cbzFile.namelist():
|
for f in cbzFile.namelist():
|
||||||
if f.startswith('__MACOSX') or f.endswith('.DS_Store') or f.endswith('thumbs.db'):
|
if f.startswith('__MACOSX') or f.endswith('.DS_Store') or f.endswith('humbs.db'):
|
||||||
pass # skip MacOS special files
|
pass # skip MacOS special files
|
||||||
elif f.endswith('/'):
|
elif f.endswith('/'):
|
||||||
try:
|
try:
|
||||||
@@ -61,26 +59,19 @@ class CBxArchive:
|
|||||||
|
|
||||||
def extractCBR(self, targetdir):
|
def extractCBR(self, targetdir):
|
||||||
cbrFile = rarfile.RarFile(self.origFileName)
|
cbrFile = rarfile.RarFile(self.origFileName)
|
||||||
filelist = []
|
cbrFile.extractall(targetdir)
|
||||||
for f in cbrFile.namelist():
|
for root, dirnames, filenames in walk(targetdir):
|
||||||
if f.startswith('__MACOSX') or f.endswith('.DS_Store') or f.endswith('thumbs.db'):
|
for filename in filenames:
|
||||||
pass # skip MacOS special files
|
if filename.startswith('__MACOSX') or filename.endswith('.DS_Store') or filename.endswith('humbs.db'):
|
||||||
elif f.endswith('/'):
|
os.remove(os.path.join(root, filename))
|
||||||
try:
|
|
||||||
os.makedirs(os.path.join(targetdir, f))
|
|
||||||
except Exception:
|
|
||||||
pass # the dir exists so we are going to extract the images only.
|
|
||||||
else:
|
|
||||||
filelist.append(f)
|
|
||||||
cbrFile.extractall(targetdir, filelist)
|
|
||||||
|
|
||||||
def extractCB7(self, targetdir):
|
def extractCB7(self, targetdir):
|
||||||
# Workaround for some wide UTF-8 + Popen abnormalities
|
# Workaround for some wide UTF-8 + Popen abnormalities
|
||||||
if sys.platform.startswith('darwin'):
|
if sys.platform.startswith('darwin'):
|
||||||
copy(self.origFileName, os.path.join(os.path.dirname(self.origFileName), 'TMP_KCC_TMP'))
|
copy(self.origFileName, os.path.join(os.path.dirname(self.origFileName), 'TMP_KCC_TMP'))
|
||||||
self.origFileName = os.path.join(os.path.dirname(self.origFileName), 'TMP_KCC_TMP')
|
self.origFileName = os.path.join(os.path.dirname(self.origFileName), 'TMP_KCC_TMP')
|
||||||
output = Popen('7za x "' + self.origFileName + '" -xr!__MACOSX -xr!.DS_Store -xr!thumbs.db -o"'
|
output = Popen('7za x "' + self.origFileName + '" -xr!__MACOSX -xr!.DS_Store -xr!thumbs.db -xr!Thumbs.db -o"' +
|
||||||
+ targetdir + '"', stdout=PIPE, stderr=STDOUT, shell=True)
|
targetdir + '"', stdout=PIPE, stderr=STDOUT, shell=True)
|
||||||
extracted = False
|
extracted = False
|
||||||
for line in output.stdout:
|
for line in output.stdout:
|
||||||
if b"Everything is Ok" in line:
|
if b"Everything is Ok" in line:
|
||||||
@@ -104,7 +95,7 @@ class CBxArchive:
|
|||||||
for f in os.listdir(os.path.join(targetdir, adir[0])):
|
for f in os.listdir(os.path.join(targetdir, adir[0])):
|
||||||
# If directory names contain UTF-8 chars shutil.move can't clean up the mess alone
|
# If directory names contain UTF-8 chars shutil.move can't clean up the mess alone
|
||||||
if os.path.isdir(os.path.join(targetdir, f)):
|
if os.path.isdir(os.path.join(targetdir, f)):
|
||||||
os.rename(os.path.join(targetdir, adir[0], f), os.path.join(targetdir, adir[0], f + '-A'))
|
saferReplace(os.path.join(targetdir, adir[0], f), os.path.join(targetdir, adir[0], f + '-A'))
|
||||||
f += '-A'
|
f += '-A'
|
||||||
move(os.path.join(targetdir, adir[0], f), targetdir)
|
move(os.path.join(targetdir, adir[0], f), targetdir)
|
||||||
os.rmdir(os.path.join(targetdir, adir[0]))
|
os.rmdir(os.path.join(targetdir, adir[0]))
|
||||||
|
|||||||
1502
kcc/comic2ebook.py
1502
kcc/comic2ebook.py
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||||
# Copyright (c) 2013-2014 Pawel Jastrzebski <pawelj@vulturis.eu>
|
# Copyright (c) 2013-2015 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
#
|
#
|
||||||
# Permission to use, copy, modify, and/or distribute this software for
|
# Permission to use, copy, modify, and/or distribute this software for
|
||||||
# any purpose with or without fee is hereby granted, provided that the
|
# any purpose with or without fee is hereby granted, provided that the
|
||||||
@@ -18,25 +18,21 @@
|
|||||||
# PERFORMANCE OF THIS SOFTWARE.
|
# PERFORMANCE OF THIS SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__version__ = '4.0.1'
|
|
||||||
__license__ = 'ISC'
|
|
||||||
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
|
|
||||||
__docformat__ = 'restructuredtext en'
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from shutil import rmtree, copytree, move
|
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
|
from PIL import Image, ImageStat, ImageOps
|
||||||
from .shared import getImageFileName, walkLevel
|
from scandir import walk
|
||||||
|
from .shared import getImageFileName, walkLevel, walkSort
|
||||||
try:
|
try:
|
||||||
from PyQt5 import QtCore
|
from PyQt5 import QtCore
|
||||||
except ImportError:
|
except ImportError:
|
||||||
QtCore = None
|
QtCore = None
|
||||||
|
|
||||||
|
|
||||||
def mergeDirectory_tick(output):
|
def mergeDirectoryTick(output):
|
||||||
if output:
|
if output:
|
||||||
mergeWorkerOutput.append(output)
|
mergeWorkerOutput.append(output)
|
||||||
mergeWorkerPool.terminate()
|
mergeWorkerPool.terminate()
|
||||||
@@ -50,9 +46,9 @@ def mergeDirectory(work):
|
|||||||
try:
|
try:
|
||||||
directory = work[0]
|
directory = work[0]
|
||||||
images = []
|
images = []
|
||||||
imagesClear = []
|
imagesValid = []
|
||||||
sizes = []
|
sizes = []
|
||||||
h = 0
|
targetHeight = 0
|
||||||
for root, dirs, files in walkLevel(directory, 0):
|
for root, dirs, files in walkLevel(directory, 0):
|
||||||
for name in files:
|
for name in files:
|
||||||
if getImageFileName(name) is not None:
|
if getImageFileName(name) is not None:
|
||||||
@@ -60,23 +56,26 @@ def mergeDirectory(work):
|
|||||||
images.append([os.path.join(root, name), i.size[0], i.size[1]])
|
images.append([os.path.join(root, name), i.size[0], i.size[1]])
|
||||||
sizes.append(i.size[0])
|
sizes.append(i.size[0])
|
||||||
if len(images) > 0:
|
if len(images) > 0:
|
||||||
mw = max(set(sizes), key=sizes.count)
|
targetWidth = max(set(sizes), key=sizes.count)
|
||||||
for i in images:
|
for i in images:
|
||||||
if i[1] == mw:
|
if i[1] <= targetWidth:
|
||||||
h += i[2]
|
targetHeight += i[2]
|
||||||
imagesClear.append(i[0])
|
imagesValid.append(i[0])
|
||||||
# Silently drop directories that contain too many images
|
# Silently drop directories that contain too many images
|
||||||
if h > 262144:
|
# 131072 = GIMP_MAX_IMAGE_SIZE / 4
|
||||||
|
if targetHeight > 131072:
|
||||||
return None
|
return None
|
||||||
result = Image.new('RGB', (mw, h))
|
result = Image.new('RGB', (targetWidth, targetHeight))
|
||||||
y = 0
|
y = 0
|
||||||
for i in imagesClear:
|
for i in imagesValid:
|
||||||
img = Image.open(i)
|
img = Image.open(i)
|
||||||
img = img.convert('RGB')
|
img = img.convert('RGB')
|
||||||
|
if img.size[0] < targetWidth:
|
||||||
|
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)
|
os.remove(i)
|
||||||
savePath = os.path.split(imagesClear[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:
|
||||||
return str(sys.exc_info()[1])
|
return str(sys.exc_info()[1])
|
||||||
@@ -84,23 +83,23 @@ def mergeDirectory(work):
|
|||||||
|
|
||||||
def sanitizePanelSize(panel, opt):
|
def sanitizePanelSize(panel, opt):
|
||||||
newPanels = []
|
newPanels = []
|
||||||
if panel[2] > 8 * opt.height:
|
if panel[2] > 6 * opt.height:
|
||||||
diff = int(panel[2] / 8)
|
diff = int(panel[2] / 8)
|
||||||
newPanels.append([panel[0], panel[1] - diff*7, diff])
|
newPanels.append([panel[0], panel[1] - diff * 7, diff])
|
||||||
newPanels.append([panel[1] - diff*7, panel[1] - diff*6, diff])
|
newPanels.append([panel[1] - diff * 7, panel[1] - diff * 6, diff])
|
||||||
newPanels.append([panel[1] - diff*6, panel[1] - diff*5, diff])
|
newPanels.append([panel[1] - diff * 6, panel[1] - diff * 5, diff])
|
||||||
newPanels.append([panel[1] - diff*5, panel[1] - diff*4, diff])
|
newPanels.append([panel[1] - diff * 5, panel[1] - diff * 4, diff])
|
||||||
newPanels.append([panel[1] - diff*4, panel[1] - diff*3, diff])
|
newPanels.append([panel[1] - diff * 4, panel[1] - diff * 3, diff])
|
||||||
newPanels.append([panel[1] - diff*3, panel[1] - diff*2, diff])
|
newPanels.append([panel[1] - diff * 3, panel[1] - diff * 2, diff])
|
||||||
newPanels.append([panel[1] - diff*2, panel[1] - diff, diff])
|
newPanels.append([panel[1] - diff * 2, panel[1] - diff, diff])
|
||||||
newPanels.append([panel[1] - diff, panel[1], diff])
|
newPanels.append([panel[1] - diff, panel[1], diff])
|
||||||
elif panel[2] > 4 * opt.height:
|
elif panel[2] > 3 * opt.height:
|
||||||
diff = int(panel[2] / 4)
|
diff = int(panel[2] / 4)
|
||||||
newPanels.append([panel[0], panel[1] - diff*3, diff])
|
newPanels.append([panel[0], panel[1] - diff * 3, diff])
|
||||||
newPanels.append([panel[1] - diff*3, panel[1] - diff*2, diff])
|
newPanels.append([panel[1] - diff * 3, panel[1] - diff * 2, diff])
|
||||||
newPanels.append([panel[1] - diff*2, panel[1] - diff, diff])
|
newPanels.append([panel[1] - diff * 2, panel[1] - diff, diff])
|
||||||
newPanels.append([panel[1] - diff, panel[1], diff])
|
newPanels.append([panel[1] - diff, panel[1], diff])
|
||||||
elif panel[2] > 2 * opt.height:
|
elif panel[2] > 1.5 * opt.height:
|
||||||
newPanels.append([panel[0], panel[1] - int(panel[2] / 2), int(panel[2] / 2)])
|
newPanels.append([panel[0], panel[1] - int(panel[2] / 2), int(panel[2] / 2)])
|
||||||
newPanels.append([panel[1] - int(panel[2] / 2), panel[1], int(panel[2] / 2)])
|
newPanels.append([panel[1] - int(panel[2] / 2), panel[1], int(panel[2] / 2)])
|
||||||
else:
|
else:
|
||||||
@@ -108,7 +107,7 @@ def sanitizePanelSize(panel, opt):
|
|||||||
return newPanels
|
return newPanels
|
||||||
|
|
||||||
|
|
||||||
def splitImage_tick(output):
|
def splitImageTick(output):
|
||||||
if output:
|
if output:
|
||||||
splitWorkerOutput.append(output)
|
splitWorkerOutput.append(output)
|
||||||
splitWorkerPool.terminate()
|
splitWorkerPool.terminate()
|
||||||
@@ -118,13 +117,12 @@ def splitImage_tick(output):
|
|||||||
splitWorkerPool.terminate()
|
splitWorkerPool.terminate()
|
||||||
|
|
||||||
|
|
||||||
#noinspection PyUnboundLocalVariable
|
|
||||||
def splitImage(work):
|
def splitImage(work):
|
||||||
try:
|
try:
|
||||||
path = work[0]
|
path = work[0]
|
||||||
name = work[1]
|
name = work[1]
|
||||||
opt = work[2]
|
opt = work[2]
|
||||||
# Harcoded opttions
|
# Hardcoded options
|
||||||
threshold = 1.0
|
threshold = 1.0
|
||||||
delta = 15
|
delta = 15
|
||||||
fileExpanded = os.path.splitext(name)
|
fileExpanded = os.path.splitext(name)
|
||||||
@@ -165,6 +163,7 @@ def splitImage(work):
|
|||||||
for panel in panelsCleaned:
|
for panel in panelsCleaned:
|
||||||
panels.append(panel)
|
panels.append(panel)
|
||||||
if opt.debug:
|
if opt.debug:
|
||||||
|
# noinspection PyUnboundLocalVariable
|
||||||
debugImage.save(os.path.join(path, fileExpanded[0] + '-debug.png'), 'PNG')
|
debugImage.save(os.path.join(path, fileExpanded[0] + '-debug.png'), 'PNG')
|
||||||
|
|
||||||
# Create virtual pages
|
# Create virtual pages
|
||||||
@@ -199,21 +198,16 @@ def splitImage(work):
|
|||||||
panelImg = image.crop([0, panels[panel][0], widthImg, panels[panel][1]])
|
panelImg = image.crop([0, panels[panel][0], widthImg, panels[panel][1]])
|
||||||
newPage.paste(panelImg, (0, targetHeight))
|
newPage.paste(panelImg, (0, targetHeight))
|
||||||
targetHeight += panels[panel][2]
|
targetHeight += panels[panel][2]
|
||||||
newPage.save(os.path.join(path, fileExpanded[0] + '-' +
|
newPage.save(os.path.join(path, fileExpanded[0] + '-' + str(pageNumber) + '.png'), 'PNG')
|
||||||
str(pageNumber) + '.png'), 'PNG')
|
|
||||||
pageNumber += 1
|
pageNumber += 1
|
||||||
os.remove(filePath)
|
os.remove(filePath)
|
||||||
except Exception:
|
except Exception:
|
||||||
return str(sys.exc_info()[1])
|
return str(sys.exc_info()[1])
|
||||||
|
|
||||||
|
|
||||||
def Copyright():
|
|
||||||
print(('comic2panel v%(__version__)s. Written by Ciro Mattia Gonano and Pawel Jastrzebski.' % globals()))
|
|
||||||
|
|
||||||
|
|
||||||
def main(argv=None, qtGUI=None):
|
def main(argv=None, qtGUI=None):
|
||||||
global options, GUI, splitWorkerPool, splitWorkerOutput, mergeWorkerPool, mergeWorkerOutput
|
global options, GUI, splitWorkerPool, splitWorkerOutput, mergeWorkerPool, mergeWorkerOutput
|
||||||
parser = OptionParser(usage="Usage: %prog [options] comic_folder", add_help_option=False)
|
parser = OptionParser(usage="Usage: kcc-c2p [options] comic_folder", add_help_option=False)
|
||||||
mainOptions = OptionGroup(parser, "MANDATORY")
|
mainOptions = OptionGroup(parser, "MANDATORY")
|
||||||
otherOptions = OptionGroup(parser, "OTHER")
|
otherOptions = OptionGroup(parser, "OTHER")
|
||||||
mainOptions.add_option("-y", "--height", type="int", dest="height", default=0,
|
mainOptions.add_option("-y", "--height", type="int", dest="height", default=0,
|
||||||
@@ -253,7 +247,8 @@ def main(argv=None, qtGUI=None):
|
|||||||
mergeWorkerOutput = []
|
mergeWorkerOutput = []
|
||||||
mergeWorkerPool = Pool()
|
mergeWorkerPool = Pool()
|
||||||
mergeWork.append([options.targetDir])
|
mergeWork.append([options.targetDir])
|
||||||
for root, dirs, files in os.walk(options.targetDir, False):
|
for root, dirs, files in walk(options.targetDir, False):
|
||||||
|
dirs, files = walkSort(dirs, files)
|
||||||
for directory in dirs:
|
for directory in dirs:
|
||||||
directoryNumer += 1
|
directoryNumer += 1
|
||||||
mergeWork.append([os.path.join(root, directory)])
|
mergeWork.append([os.path.join(root, directory)])
|
||||||
@@ -261,7 +256,7 @@ def main(argv=None, qtGUI=None):
|
|||||||
GUI.progressBarTick.emit('Combining images')
|
GUI.progressBarTick.emit('Combining images')
|
||||||
GUI.progressBarTick.emit(str(directoryNumer))
|
GUI.progressBarTick.emit(str(directoryNumer))
|
||||||
for i in mergeWork:
|
for i in mergeWork:
|
||||||
mergeWorkerPool.apply_async(func=mergeDirectory, args=(i, ), callback=mergeDirectory_tick)
|
mergeWorkerPool.apply_async(func=mergeDirectory, args=(i, ), callback=mergeDirectoryTick)
|
||||||
mergeWorkerPool.close()
|
mergeWorkerPool.close()
|
||||||
mergeWorkerPool.join()
|
mergeWorkerPool.join()
|
||||||
if GUI and not GUI.conversionAlive:
|
if GUI and not GUI.conversionAlive:
|
||||||
@@ -271,7 +266,7 @@ def main(argv=None, qtGUI=None):
|
|||||||
rmtree(options.targetDir, True)
|
rmtree(options.targetDir, True)
|
||||||
raise RuntimeError("One of workers crashed. Cause: " + mergeWorkerOutput[0])
|
raise RuntimeError("One of workers crashed. Cause: " + mergeWorkerOutput[0])
|
||||||
print("\nSplitting images...")
|
print("\nSplitting images...")
|
||||||
for root, dirs, files in os.walk(options.targetDir, False):
|
for root, dirs, files in walk(options.targetDir, False):
|
||||||
for name in files:
|
for name in files:
|
||||||
if getImageFileName(name) is not None:
|
if getImageFileName(name) is not None:
|
||||||
pagenumber += 1
|
pagenumber += 1
|
||||||
@@ -284,7 +279,7 @@ def main(argv=None, qtGUI=None):
|
|||||||
GUI.progressBarTick.emit('tick')
|
GUI.progressBarTick.emit('tick')
|
||||||
if len(work) > 0:
|
if len(work) > 0:
|
||||||
for i in work:
|
for i in work:
|
||||||
splitWorkerPool.apply_async(func=splitImage, args=(i, ), callback=splitImage_tick)
|
splitWorkerPool.apply_async(func=splitImage, args=(i, ), callback=splitImageTick)
|
||||||
splitWorkerPool.close()
|
splitWorkerPool.close()
|
||||||
splitWorkerPool.join()
|
splitWorkerPool.join()
|
||||||
if GUI and not GUI.conversionAlive:
|
if GUI and not GUI.conversionAlive:
|
||||||
@@ -302,4 +297,4 @@ def main(argv=None, qtGUI=None):
|
|||||||
else:
|
else:
|
||||||
raise UserWarning("Provided path is not a directory.")
|
raise UserWarning("Provided path is not a directory.")
|
||||||
else:
|
else:
|
||||||
raise UserWarning("Target height is not set.")
|
raise UserWarning("Target height is not set.")
|
||||||
|
|||||||
185
kcc/dualmetafix.py
Normal file
185
kcc/dualmetafix.py
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Based on initial version of DualMetaFix. Copyright (C) 2013 Kevin Hendricks
|
||||||
|
# Changes for KCC Copyright (C) 2014-2015 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import struct
|
||||||
|
import mmap
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
|
||||||
|
class DualMetaFixException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# palm database offset constants
|
||||||
|
number_of_pdb_records = 76
|
||||||
|
first_pdb_record = 78
|
||||||
|
|
||||||
|
# important rec0 offsets
|
||||||
|
mobi_header_base = 16
|
||||||
|
mobi_header_length = 20
|
||||||
|
mobi_version = 36
|
||||||
|
title_offset = 84
|
||||||
|
|
||||||
|
|
||||||
|
def getint(data, ofs, sz='L'):
|
||||||
|
i, = struct.unpack_from('>' + sz, data, ofs)
|
||||||
|
return i
|
||||||
|
|
||||||
|
|
||||||
|
def writeint(data, ofs, n, slen='L'):
|
||||||
|
if slen == 'L':
|
||||||
|
return data[:ofs] + struct.pack('>L', n) + data[ofs + 4:]
|
||||||
|
else:
|
||||||
|
return data[:ofs] + struct.pack('>H', n) + data[ofs + 2:]
|
||||||
|
|
||||||
|
|
||||||
|
def getsecaddr(datain, secno):
|
||||||
|
nsec = getint(datain, number_of_pdb_records, 'H')
|
||||||
|
if (secno < 0) | (secno >= nsec):
|
||||||
|
emsg = 'requested section number %d out of range (nsec=%d)' % (secno, nsec)
|
||||||
|
raise DualMetaFixException(emsg)
|
||||||
|
secstart = getint(datain, first_pdb_record + secno * 8)
|
||||||
|
if secno == nsec - 1:
|
||||||
|
secend = len(datain)
|
||||||
|
else:
|
||||||
|
secend = getint(datain, first_pdb_record + (secno + 1) * 8)
|
||||||
|
return secstart, secend
|
||||||
|
|
||||||
|
|
||||||
|
def readsection(datain, secno):
|
||||||
|
secstart, secend = getsecaddr(datain, secno)
|
||||||
|
return datain[secstart:secend]
|
||||||
|
|
||||||
|
|
||||||
|
# overwrite section - must be exact same length as original
|
||||||
|
def replacesection(datain, secno, secdata):
|
||||||
|
secstart, secend = getsecaddr(datain, secno)
|
||||||
|
seclen = secend - secstart
|
||||||
|
if len(secdata) != seclen:
|
||||||
|
raise DualMetaFixException('section length change in replacesection')
|
||||||
|
datain[secstart:secstart + seclen] = secdata
|
||||||
|
|
||||||
|
|
||||||
|
def get_exth_params(rec0):
|
||||||
|
ebase = mobi_header_base + getint(rec0, mobi_header_length)
|
||||||
|
if rec0[ebase:ebase + 4] != b'EXTH':
|
||||||
|
raise DualMetaFixException('EXTH tag not found where expected')
|
||||||
|
elen = getint(rec0, ebase + 4)
|
||||||
|
enum = getint(rec0, ebase + 8)
|
||||||
|
rlen = len(rec0)
|
||||||
|
return ebase, elen, enum, rlen
|
||||||
|
|
||||||
|
|
||||||
|
def add_exth(rec0, exth_num, exth_bytes):
|
||||||
|
ebase, elen, enum, rlen = get_exth_params(rec0)
|
||||||
|
newrecsize = 8 + len(exth_bytes)
|
||||||
|
newrec0 = rec0[0:ebase + 4] + struct.pack('>L', elen + newrecsize) + struct.pack('>L', enum + 1) + \
|
||||||
|
struct.pack('>L', exth_num) + struct.pack('>L', newrecsize) + exth_bytes + rec0[ebase + 12:]
|
||||||
|
newrec0 = writeint(newrec0, title_offset, getint(newrec0, title_offset) + newrecsize)
|
||||||
|
# keep constant record length by removing newrecsize null bytes from end
|
||||||
|
sectail = newrec0[-newrecsize:]
|
||||||
|
if sectail != b'\0' * newrecsize:
|
||||||
|
raise DualMetaFixException('add_exth: trimmed non-null bytes at end of section')
|
||||||
|
newrec0 = newrec0[0:rlen]
|
||||||
|
return newrec0
|
||||||
|
|
||||||
|
|
||||||
|
def read_exth(rec0, exth_num):
|
||||||
|
exth_values = []
|
||||||
|
ebase, elen, enum, rlen = get_exth_params(rec0)
|
||||||
|
ebase += 12
|
||||||
|
while enum > 0:
|
||||||
|
exth_id = getint(rec0, ebase)
|
||||||
|
if exth_id == exth_num:
|
||||||
|
# We might have multiple exths, so build a list.
|
||||||
|
exth_values.append(rec0[ebase + 8:ebase + getint(rec0, ebase + 4)])
|
||||||
|
enum -= 1
|
||||||
|
ebase = ebase + getint(rec0, ebase + 4)
|
||||||
|
return exth_values
|
||||||
|
|
||||||
|
|
||||||
|
def del_exth(rec0, exth_num):
|
||||||
|
ebase, elen, enum, rlen = get_exth_params(rec0)
|
||||||
|
ebase_idx = ebase + 12
|
||||||
|
enum_idx = 0
|
||||||
|
while enum_idx < enum:
|
||||||
|
exth_id = getint(rec0, ebase_idx)
|
||||||
|
exth_size = getint(rec0, ebase_idx + 4)
|
||||||
|
if exth_id == exth_num:
|
||||||
|
newrec0 = rec0
|
||||||
|
newrec0 = writeint(newrec0, title_offset, getint(newrec0, title_offset) - exth_size)
|
||||||
|
newrec0 = newrec0[:ebase_idx] + newrec0[ebase_idx + exth_size:]
|
||||||
|
newrec0 = newrec0[0:ebase + 4] + struct.pack('>L', elen - exth_size) + \
|
||||||
|
struct.pack('>L', enum - 1) + newrec0[ebase + 12:]
|
||||||
|
newrec0 += b'\0' * exth_size
|
||||||
|
if rlen != len(newrec0):
|
||||||
|
raise DualMetaFixException('del_exth: incorrect section size change')
|
||||||
|
return newrec0
|
||||||
|
enum_idx += 1
|
||||||
|
ebase_idx = ebase_idx + exth_size
|
||||||
|
return rec0
|
||||||
|
|
||||||
|
|
||||||
|
class DualMobiMetaFix:
|
||||||
|
def __init__(self, infile, outfile, asin):
|
||||||
|
shutil.copyfile(infile, outfile)
|
||||||
|
f = open(outfile, "r+b")
|
||||||
|
self.datain = mmap.mmap(f.fileno(), 0)
|
||||||
|
self.datain_rec0 = readsection(self.datain, 0)
|
||||||
|
|
||||||
|
# in the first mobi header
|
||||||
|
# add 501 to "EBOK", add 113 as asin, add 504 as asin
|
||||||
|
rec0 = self.datain_rec0
|
||||||
|
rec0 = del_exth(rec0, 501)
|
||||||
|
rec0 = del_exth(rec0, 113)
|
||||||
|
rec0 = del_exth(rec0, 504)
|
||||||
|
rec0 = add_exth(rec0, 501, b'EBOK')
|
||||||
|
rec0 = add_exth(rec0, 113, asin)
|
||||||
|
rec0 = add_exth(rec0, 504, asin)
|
||||||
|
replacesection(self.datain, 0, rec0)
|
||||||
|
|
||||||
|
ver = getint(self.datain_rec0, mobi_version)
|
||||||
|
self.combo = (ver != 8)
|
||||||
|
if not self.combo:
|
||||||
|
return
|
||||||
|
|
||||||
|
exth121 = read_exth(self.datain_rec0, 121)
|
||||||
|
if len(exth121) == 0:
|
||||||
|
self.combo = False
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
# only pay attention to first exth121
|
||||||
|
# (there should only be one)
|
||||||
|
datain_kf8, = struct.unpack_from('>L', exth121[0], 0)
|
||||||
|
if datain_kf8 == 0xffffffff:
|
||||||
|
self.combo = False
|
||||||
|
return
|
||||||
|
self.datain_kfrec0 = readsection(self.datain, datain_kf8)
|
||||||
|
|
||||||
|
# in the second header
|
||||||
|
# add 501 to "EBOK", add 113 as asin, add 504 as asin
|
||||||
|
rec0 = self.datain_kfrec0
|
||||||
|
rec0 = del_exth(rec0, 501)
|
||||||
|
rec0 = del_exth(rec0, 113)
|
||||||
|
rec0 = del_exth(rec0, 504)
|
||||||
|
rec0 = add_exth(rec0, 501, b'EBOK')
|
||||||
|
rec0 = add_exth(rec0, 113, asin)
|
||||||
|
rec0 = add_exth(rec0, 504, asin)
|
||||||
|
replacesection(self.datain, datain_kf8, rec0)
|
||||||
|
|
||||||
|
self.datain.flush()
|
||||||
|
self.datain.close()
|
||||||
395
kcc/image.py
395
kcc/image.py
@@ -1,7 +1,7 @@
|
|||||||
# 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) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||||
# Copyright (c) 2013-2014 Pawel Jastrzebski <pawelj@vulturis.eu>
|
# Copyright (c) 2013-2015 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# This program is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@@ -16,14 +16,14 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
__license__ = 'ISC'
|
|
||||||
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
|
|
||||||
__docformat__ = 'restructuredtext en'
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
from io import BytesIO
|
||||||
|
from urllib.request import Request, urlopen
|
||||||
|
from urllib.parse import quote
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
from PIL import Image, ImageOps, ImageStat, ImageChops
|
from PIL import Image, ImageOps, ImageStat, ImageChops
|
||||||
from .shared import md5Checksum
|
from .shared import md5Checksum
|
||||||
|
from . import __version__
|
||||||
|
|
||||||
|
|
||||||
class ProfileData:
|
class ProfileData:
|
||||||
@@ -81,80 +81,91 @@ class ProfileData:
|
|||||||
'K1': ("Kindle 1", (600, 670), Palette4, 1.8, (900, 1005)),
|
'K1': ("Kindle 1", (600, 670), Palette4, 1.8, (900, 1005)),
|
||||||
'K2': ("Kindle 2", (600, 670), Palette15, 1.8, (900, 1005)),
|
'K2': ("Kindle 2", (600, 670), Palette15, 1.8, (900, 1005)),
|
||||||
'K345': ("Kindle", (600, 800), Palette16, 1.8, (900, 1200)),
|
'K345': ("Kindle", (600, 800), Palette16, 1.8, (900, 1200)),
|
||||||
'KHD': ("Kindle Paperwhite", (758, 1024), Palette16, 1.8, (1137, 1536)),
|
|
||||||
'KDX': ("Kindle DX/DXG", (824, 1000), Palette16, 1.8, (1236, 1500)),
|
'KDX': ("Kindle DX/DXG", (824, 1000), Palette16, 1.8, (1236, 1500)),
|
||||||
'KF': ("Kindle Fire", (600, 1024), PalleteNull, 1.0, (900, 1536)),
|
'KPW': ("Kindle Paperwhite 1/2", (758, 1024), Palette16, 1.8, (1137, 1536)),
|
||||||
'KFHD': ("K. Fire HD 7\"", (800, 1280), PalleteNull, 1.0, (1200, 1920)),
|
'KV': ("Kindle Paperwhite 3/Voyage", (1072, 1448), Palette16, 1.8, (1608, 2172)),
|
||||||
'KFHD8': ("K. Fire HD 8.9\"", (1200, 1920), PalleteNull, 1.0, (1800, 2880)),
|
|
||||||
'KFHDX': ("K. Fire HDX 7\"", (1200, 1920), PalleteNull, 1.0, (1800, 2880)),
|
|
||||||
'KFHDX8': ("K. Fire HDX 8.9\"", (1600, 2560), PalleteNull, 1.0, (2400, 3840)),
|
|
||||||
'KoMT': ("Kobo Mini/Touch", (600, 800), Palette16, 1.8, (900, 1200)),
|
'KoMT': ("Kobo Mini/Touch", (600, 800), Palette16, 1.8, (900, 1200)),
|
||||||
'KoG': ("Kobo Glow", (768, 1024), Palette16, 1.8, (1152, 1536)),
|
'KoG': ("Kobo Glo", (768, 1024), Palette16, 1.8, (1152, 1536)),
|
||||||
|
'KoGHD': ("Kobo Glo HD", (1072, 1448), Palette16, 1.8, (1608, 2172)),
|
||||||
'KoA': ("Kobo Aura", (758, 1024), Palette16, 1.8, (1137, 1536)),
|
'KoA': ("Kobo Aura", (758, 1024), Palette16, 1.8, (1137, 1536)),
|
||||||
'KoAHD': ("Kobo Aura HD", (1080, 1440), Palette16, 1.8, (1620, 2160)),
|
'KoAHD': ("Kobo Aura HD", (1080, 1440), Palette16, 1.8, (1620, 2160)),
|
||||||
'KFA': ("Kindle for Android", (0, 0), PalleteNull, 1.0, (0, 0)),
|
'KoAH2O': ("Kobo Aura H2O", (1080, 1430), Palette16, 1.8, (1620, 2145)),
|
||||||
'OTHER': ("Other", (0, 0), Palette16, 1.8, (0, 0)),
|
'OTHER': ("Other", (0, 0), Palette16, 1.8, (0, 0)),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class ComicPage:
|
class ComicPage:
|
||||||
def __init__(self, source, device, fill=None):
|
def __init__(self, source, options, original=None):
|
||||||
try:
|
try:
|
||||||
self.profile_label, self.size, self.palette, self.gamma, self.panelviewsize = device
|
self.profile_label, self.size, self.palette, self.gamma, self.panelviewsize = options.profileData
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise RuntimeError('Unexpected output device %s' % device)
|
raise RuntimeError('Unexpected output device %s' % options.profileData)
|
||||||
self.origFileName = source
|
self.origFileName = source
|
||||||
self.filename = os.path.basename(self.origFileName)
|
self.filename = os.path.basename(self.origFileName)
|
||||||
self.image = Image.open(source)
|
self.image = Image.open(source)
|
||||||
self.image = self.image.convert('RGB')
|
self.image = self.image.convert('RGB')
|
||||||
self.color = self.isImageColor()
|
self.opt = options
|
||||||
self.rotated = None
|
if original:
|
||||||
self.border = None
|
self.second = True
|
||||||
self.noHPV = None
|
self.rotated = original.rotated
|
||||||
self.noVPV = None
|
self.border = original.border
|
||||||
self.noPV = None
|
self.noHPV = original.noHPV
|
||||||
self.purge = False
|
self.noVPV = original.noVPV
|
||||||
self.hq = False
|
self.noPV = original.noPV
|
||||||
if fill:
|
self.noHQ = original.noHQ
|
||||||
self.fill = fill
|
self.fill = original.fill
|
||||||
|
self.color = original.color
|
||||||
|
if self.rotated:
|
||||||
|
self.image = self.image.rotate(90, Image.BICUBIC, True)
|
||||||
|
self.opt.quality = 0
|
||||||
else:
|
else:
|
||||||
|
self.second = False
|
||||||
|
self.rotated = None
|
||||||
|
self.border = None
|
||||||
|
self.noHPV = None
|
||||||
|
self.noVPV = None
|
||||||
|
self.noPV = None
|
||||||
self.fill = None
|
self.fill = None
|
||||||
|
self.noHQ = False
|
||||||
def saveToDir(self, targetdir, forcepng, color):
|
if options.webtoon:
|
||||||
try:
|
self.color = True
|
||||||
if not self.purge:
|
|
||||||
flags = []
|
|
||||||
filename = os.path.join(targetdir, os.path.splitext(self.filename)[0]) + '-KCC'
|
|
||||||
if not color and not forcepng:
|
|
||||||
self.image = self.image.convert('L')
|
|
||||||
if self.rotated:
|
|
||||||
flags.append('Rotated')
|
|
||||||
if self.hq:
|
|
||||||
flags.append('HighQuality')
|
|
||||||
filename += '-HQ'
|
|
||||||
if self.noPV:
|
|
||||||
flags.append('NoPanelView')
|
|
||||||
else:
|
|
||||||
if self.noHPV:
|
|
||||||
flags.append('NoHorizontalPanelView')
|
|
||||||
if self.noVPV:
|
|
||||||
flags.append('NoVerticalPanelView')
|
|
||||||
if self.border:
|
|
||||||
flags.append("Margins-" + str(self.border[0]) + "-" + str(self.border[1]) + "-"
|
|
||||||
+ str(self.border[2]) + "-" + str(self.border[3]))
|
|
||||||
if forcepng:
|
|
||||||
filename += ".png"
|
|
||||||
self.image.save(filename, "PNG", optimize=1)
|
|
||||||
else:
|
|
||||||
filename += ".jpg"
|
|
||||||
self.image.save(filename, "JPEG", optimize=1)
|
|
||||||
return [md5Checksum(filename), flags]
|
|
||||||
else:
|
else:
|
||||||
return None
|
self.color = self.isImageColor()
|
||||||
|
|
||||||
|
def saveToDir(self, targetdir):
|
||||||
|
try:
|
||||||
|
flags = []
|
||||||
|
filename = os.path.join(targetdir, os.path.splitext(self.filename)[0]) + '-KCC'
|
||||||
|
if not self.opt.forcecolor and not self.opt.forcepng:
|
||||||
|
self.image = self.image.convert('L')
|
||||||
|
if self.rotated:
|
||||||
|
flags.append('Rotated')
|
||||||
|
if self.noPV:
|
||||||
|
flags.append('NoPanelView')
|
||||||
|
else:
|
||||||
|
if self.noHPV:
|
||||||
|
flags.append('NoHorizontalPanelView')
|
||||||
|
if self.noVPV:
|
||||||
|
flags.append('NoVerticalPanelView')
|
||||||
|
if self.border:
|
||||||
|
flags.append('Margins-' + str(self.border[0]) + '-' + str(self.border[1]) + '-' +
|
||||||
|
str(self.border[2]) + '-' + str(self.border[3]))
|
||||||
|
if self.fill != 'white':
|
||||||
|
flags.append('BlackFill')
|
||||||
|
if self.opt.quality == 2:
|
||||||
|
filename += '-HQ'
|
||||||
|
if self.opt.forcepng:
|
||||||
|
filename += '.png'
|
||||||
|
self.image.save(filename, 'PNG', optimize=1)
|
||||||
|
else:
|
||||||
|
filename += '.jpg'
|
||||||
|
self.image.save(filename, 'JPEG', optimize=1, quality=80)
|
||||||
|
return [md5Checksum(filename), flags]
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
raise RuntimeError('Cannot write image in directory %s: %s' % (targetdir, e))
|
raise RuntimeError('Cannot write image in directory %s: %s' % (targetdir, e))
|
||||||
|
|
||||||
def optimizeImage(self, gamma):
|
def autocontrastImage(self):
|
||||||
|
gamma = self.opt.gamma
|
||||||
if gamma < 0.1:
|
if gamma < 0.1:
|
||||||
gamma = self.gamma
|
gamma = self.gamma
|
||||||
if self.gamma != 1.0 and self.color:
|
if self.gamma != 1.0 and self.color:
|
||||||
@@ -175,72 +186,65 @@ class ComicPage:
|
|||||||
# Quantize is deprecated but new function call it internally anyway...
|
# Quantize is deprecated but new function call it internally anyway...
|
||||||
self.image = self.image.quantize(palette=palImg)
|
self.image = self.image.quantize(palette=palImg)
|
||||||
|
|
||||||
def calculateBorderPercent(self, x, img, isWidth):
|
def calculateBorder(self):
|
||||||
if isWidth:
|
if self.noPV:
|
||||||
return int(round(float(x)/float(img.image.size[0]), 4) * 10000 * 1.5)
|
self.border = [0.0, 0.0, 0.0, 0.0]
|
||||||
else:
|
|
||||||
return int(round(float(x)/float(img.image.size[1]), 4) * 10000 * 1.5)
|
|
||||||
|
|
||||||
def calculateBorder(self, sourceImage, isHQ=False):
|
|
||||||
if (isHQ and sourceImage.purge) or self.noPV:
|
|
||||||
self.border = [0, 0, 0, 0]
|
|
||||||
self.noPV = True
|
|
||||||
return
|
return
|
||||||
if self.fill == 'white':
|
if self.fill == 'white':
|
||||||
# Only already saved files can have P mode. So we can break color quantization.
|
border = ImageChops.invert(self.image).getbbox()
|
||||||
if sourceImage.image.mode == 'P':
|
|
||||||
sourceImage.image = sourceImage.image.convert('RGB')
|
|
||||||
border = ImageChops.invert(sourceImage.image).getbbox()
|
|
||||||
else:
|
else:
|
||||||
border = sourceImage.image.getbbox()
|
border = self.image.getbbox()
|
||||||
|
if self.opt.quality == 2:
|
||||||
|
multiplier = 1.0
|
||||||
|
else:
|
||||||
|
multiplier = 1.5
|
||||||
if border is not None:
|
if border is not None:
|
||||||
if isHQ:
|
self.border = [round(float(border[0]) / float(self.image.size[0]) * 150, 3),
|
||||||
multiplier = 1.0
|
round(float(border[1]) / float(self.image.size[1]) * 150, 3),
|
||||||
else:
|
round(float(self.image.size[0] - border[2]) / float(self.image.size[0]) * 150, 3),
|
||||||
multiplier = 1.5
|
round(float(self.image.size[1] - border[3]) / float(self.image.size[1]) * 150, 3)]
|
||||||
self.border = [self.calculateBorderPercent(border[0], sourceImage, True),
|
if int((border[2] - border[0]) * multiplier) < self.size[0] + 10:
|
||||||
self.calculateBorderPercent(border[1], sourceImage, False),
|
|
||||||
self.calculateBorderPercent((sourceImage.image.size[0] - border[2]), sourceImage, True),
|
|
||||||
self.calculateBorderPercent((sourceImage.image.size[1] - border[3]), sourceImage, False)]
|
|
||||||
if int((border[2] - border[0]) * multiplier) < self.size[0]:
|
|
||||||
self.noHPV = True
|
self.noHPV = True
|
||||||
if int((border[3] - border[1]) * multiplier) < self.size[1]:
|
if int((border[3] - border[1]) * multiplier) < self.size[1] + 10:
|
||||||
self.noVPV = True
|
self.noVPV = True
|
||||||
else:
|
else:
|
||||||
self.border = [0, 0, 0, 0]
|
self.border = [0.0, 0.0, 0.0, 0.0]
|
||||||
self.noHPV = True
|
self.noHPV = True
|
||||||
self.noVPV = True
|
self.noVPV = True
|
||||||
|
|
||||||
def resizeImage(self, upscale=False, stretch=False, bordersColor=None, qualityMode=0):
|
def resizeImage(self):
|
||||||
if bordersColor:
|
if self.opt.bordersColor:
|
||||||
fill = bordersColor
|
fill = self.opt.bordersColor
|
||||||
else:
|
else:
|
||||||
fill = self.fill
|
fill = self.fill
|
||||||
# Set target size
|
# Set target size
|
||||||
if qualityMode == 0:
|
if self.opt.quality == 0:
|
||||||
size = (self.size[0], self.size[1])
|
size = (self.size[0], self.size[1])
|
||||||
elif qualityMode == 1 and not stretch and not upscale and self.image.size[0] <=\
|
elif self.opt.quality == 1 and not self.opt.stretch and not self.opt.upscale and self.image.size[0] <=\
|
||||||
self.size[0] and self.image.size[1] <= self.size[1]:
|
self.size[0] and self.image.size[1] <= self.size[1]:
|
||||||
size = (self.size[0], self.size[1])
|
size = (self.size[0], self.size[1])
|
||||||
elif qualityMode == 1:
|
elif self.opt.quality == 1:
|
||||||
|
# Forcing upscale to make sure that margins will be not too big
|
||||||
|
if not self.opt.stretch:
|
||||||
|
self.opt.upscale = True
|
||||||
size = (self.panelviewsize[0], self.panelviewsize[1])
|
size = (self.panelviewsize[0], self.panelviewsize[1])
|
||||||
elif qualityMode == 2 and not stretch and not upscale and self.image.size[0] <=\
|
elif self.opt.quality == 2 and not self.opt.stretch and not self.opt.upscale and self.image.size[0] <=\
|
||||||
self.size[0] and self.image.size[1] <= self.size[1]:
|
self.size[0] and self.image.size[1] <= self.size[1]:
|
||||||
self.purge = True
|
# HQ version will not be needed
|
||||||
return self.image
|
self.noHQ = True
|
||||||
|
return
|
||||||
else:
|
else:
|
||||||
self.hq = True
|
|
||||||
size = (self.panelviewsize[0], self.panelviewsize[1])
|
size = (self.panelviewsize[0], self.panelviewsize[1])
|
||||||
# If stretching is on - Resize without other considerations
|
# If stretching is on - Resize without other considerations
|
||||||
if stretch:
|
if self.opt.stretch:
|
||||||
if self.image.size[0] <= size[0] and self.image.size[1] <= size[1]:
|
if self.image.size[0] <= size[0] and self.image.size[1] <= size[1]:
|
||||||
method = Image.BICUBIC
|
method = Image.BICUBIC
|
||||||
else:
|
else:
|
||||||
method = Image.ANTIALIAS
|
method = Image.LANCZOS
|
||||||
self.image = self.image.resize(size, method)
|
self.image = self.image.resize(size, method)
|
||||||
return self.image
|
return
|
||||||
# If image is smaller than target resolution and upscale is off - Just expand it by adding margins
|
# If image is smaller than target resolution and upscale is off - Just expand it by adding margins
|
||||||
if self.image.size[0] <= size[0] and self.image.size[1] <= size[1] and not upscale:
|
if self.image.size[0] <= size[0] and self.image.size[1] <= size[1] and not self.opt.upscale:
|
||||||
borderw = int((size[0] - self.image.size[0]) / 2)
|
borderw = int((size[0] - self.image.size[0]) / 2)
|
||||||
borderh = int((size[1] - self.image.size[1]) / 2)
|
borderh = int((size[1] - self.image.size[1]) / 2)
|
||||||
# PV is disabled when source image is smaller than device screen and upscale is off
|
# PV is disabled when source image is smaller than device screen and upscale is off
|
||||||
@@ -250,7 +254,7 @@ class ComicPage:
|
|||||||
# Border can't be float so sometimes image might be 1px too small/large
|
# Border can't be float so sometimes image might be 1px too small/large
|
||||||
if self.image.size[0] != size[0] or self.image.size[1] != size[1]:
|
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))
|
self.image = ImageOps.fit(self.image, size, method=Image.BICUBIC, centering=(0.5, 0.5))
|
||||||
return self.image
|
return
|
||||||
# Otherwise - Upscale/Downscale
|
# Otherwise - Upscale/Downscale
|
||||||
ratioDev = float(size[0]) / float(size[1])
|
ratioDev = float(size[0]) / float(size[1])
|
||||||
if (float(self.image.size[0]) / float(self.image.size[1])) < ratioDev:
|
if (float(self.image.size[0]) / float(self.image.size[1])) < ratioDev:
|
||||||
@@ -262,17 +266,17 @@ class ComicPage:
|
|||||||
if self.image.size[0] <= size[0] and self.image.size[1] <= size[1]:
|
if self.image.size[0] <= size[0] and self.image.size[1] <= size[1]:
|
||||||
method = Image.BICUBIC
|
method = Image.BICUBIC
|
||||||
else:
|
else:
|
||||||
method = Image.ANTIALIAS
|
method = Image.LANCZOS
|
||||||
self.image = ImageOps.fit(self.image, size, method=method, centering=(0.5, 0.5))
|
self.image = ImageOps.fit(self.image, size, method=method, centering=(0.5, 0.5))
|
||||||
return self.image
|
return
|
||||||
|
|
||||||
def splitPage(self, targetdir, righttoleft=False, rotate=False):
|
def splitPage(self, targetdir):
|
||||||
width, height = self.image.size
|
width, height = self.image.size
|
||||||
dstwidth, dstheight = self.size
|
dstwidth, dstheight = self.size
|
||||||
# Only split if origin is not oriented the same as target
|
# Only split if origin is not oriented the same as target
|
||||||
if (width > height) != (dstwidth > dstheight):
|
if (width > height) != (dstwidth > dstheight):
|
||||||
if rotate:
|
if self.opt.rotate:
|
||||||
self.image = self.image.rotate(90)
|
self.image = self.image.rotate(90, Image.BICUBIC, True)
|
||||||
self.rotated = True
|
self.rotated = True
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
@@ -285,18 +289,18 @@ class ComicPage:
|
|||||||
# Source is portrait and target is landscape, so split by the height
|
# Source is portrait and target is landscape, so split by the height
|
||||||
leftbox = (0, 0, width, int(height / 2))
|
leftbox = (0, 0, width, int(height / 2))
|
||||||
rightbox = (0, int(height / 2), width, height)
|
rightbox = (0, int(height / 2), width, height)
|
||||||
filename = os.path.splitext(self.filename)
|
filename = os.path.splitext(self.filename)[0]
|
||||||
fileone = targetdir + '/' + filename[0] + '-A' + filename[1]
|
fileone = targetdir + '/' + filename + '-AAA.png'
|
||||||
filetwo = targetdir + '/' + filename[0] + '-B' + filename[1]
|
filetwo = targetdir + '/' + filename + '-BBB.png'
|
||||||
try:
|
try:
|
||||||
if righttoleft:
|
if self.opt.righttoleft:
|
||||||
pageone = self.image.crop(rightbox)
|
pageone = self.image.crop(rightbox)
|
||||||
pagetwo = self.image.crop(leftbox)
|
pagetwo = self.image.crop(leftbox)
|
||||||
else:
|
else:
|
||||||
pageone = self.image.crop(leftbox)
|
pageone = self.image.crop(leftbox)
|
||||||
pagetwo = self.image.crop(rightbox)
|
pagetwo = self.image.crop(rightbox)
|
||||||
pageone.save(fileone)
|
pageone.save(fileone, 'PNG', optimize=1)
|
||||||
pagetwo.save(filetwo)
|
pagetwo.save(filetwo, 'PNG', optimize=1)
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
raise RuntimeError('Cannot write image in directory %s: %s' % (targetdir, e))
|
raise RuntimeError('Cannot write image in directory %s: %s' % (targetdir, e))
|
||||||
return fileone, filetwo
|
return fileone, filetwo
|
||||||
@@ -357,29 +361,29 @@ class ComicPage:
|
|||||||
else:
|
else:
|
||||||
diff = pageNumberCut1
|
diff = pageNumberCut1
|
||||||
self.image = self.image.crop((0, 0, widthImg, heightImg - diff))
|
self.image = self.image.crop((0, 0, widthImg, heightImg - diff))
|
||||||
return self.image
|
|
||||||
|
|
||||||
def cropWhiteSpace(self, threshold):
|
def cropWhiteSpace(self):
|
||||||
if ImageChops.invert(self.image).getbbox() is not None:
|
if ImageChops.invert(self.image).getbbox() is not None:
|
||||||
widthImg, heightImg = self.image.size
|
widthImg, heightImg = self.image.size
|
||||||
delta = 10
|
delta = 10
|
||||||
diff = delta
|
diff = delta
|
||||||
|
fixedThreshold = 0.1
|
||||||
# top
|
# top
|
||||||
while ImageStat.Stat(self.image.crop((0, 0, widthImg, diff))).var[0] < threshold and diff < heightImg:
|
while ImageStat.Stat(self.image.crop((0, 0, widthImg, diff))).var[0] < fixedThreshold and diff < heightImg:
|
||||||
diff += delta
|
diff += delta
|
||||||
diff -= delta
|
diff -= delta
|
||||||
self.image = self.image.crop((0, diff, widthImg, heightImg))
|
self.image = self.image.crop((0, diff, widthImg, heightImg))
|
||||||
widthImg, heightImg = self.image.size
|
widthImg, heightImg = self.image.size
|
||||||
diff = delta
|
diff = delta
|
||||||
# left
|
# left
|
||||||
while ImageStat.Stat(self.image.crop((0, 0, diff, heightImg))).var[0] < threshold and diff < widthImg:
|
while ImageStat.Stat(self.image.crop((0, 0, diff, heightImg))).var[0] < fixedThreshold and diff < widthImg:
|
||||||
diff += delta
|
diff += delta
|
||||||
diff -= delta
|
diff -= delta
|
||||||
self.image = self.image.crop((diff, 0, widthImg, heightImg))
|
self.image = self.image.crop((diff, 0, widthImg, heightImg))
|
||||||
widthImg, heightImg = self.image.size
|
widthImg, heightImg = self.image.size
|
||||||
diff = delta
|
diff = delta
|
||||||
# down
|
# down
|
||||||
while ImageStat.Stat(self.image.crop((0, heightImg - diff, widthImg, heightImg))).var[0] < threshold\
|
while ImageStat.Stat(self.image.crop((0, heightImg - diff, widthImg, heightImg))).var[0] < fixedThreshold\
|
||||||
and diff < heightImg:
|
and diff < heightImg:
|
||||||
diff += delta
|
diff += delta
|
||||||
diff -= delta
|
diff -= delta
|
||||||
@@ -387,81 +391,122 @@ class ComicPage:
|
|||||||
widthImg, heightImg = self.image.size
|
widthImg, heightImg = self.image.size
|
||||||
diff = delta
|
diff = delta
|
||||||
# right
|
# right
|
||||||
while ImageStat.Stat(self.image.crop((widthImg - diff, 0, widthImg, heightImg))).var[0] < threshold\
|
while ImageStat.Stat(self.image.crop((widthImg - diff, 0, widthImg, heightImg))).var[0] < fixedThreshold\
|
||||||
and diff < widthImg:
|
and diff < widthImg:
|
||||||
diff += delta
|
diff += delta
|
||||||
diff -= delta
|
diff -= delta
|
||||||
self.image = self.image.crop((0, 0, widthImg - diff, heightImg))
|
self.image = self.image.crop((0, 0, widthImg - diff, heightImg))
|
||||||
return self.image
|
|
||||||
|
|
||||||
def getImageHistogram(self, image):
|
def getImageHistogram(self, image):
|
||||||
histogram = image.histogram()
|
histogram = image.histogram()
|
||||||
RBGW = []
|
if histogram[0] == 0:
|
||||||
pixelCount = 0
|
|
||||||
for i in range(256):
|
|
||||||
pixelCount += histogram[i] + histogram[256 + i] + histogram[512 + i]
|
|
||||||
RBGW.append(histogram[i] + histogram[256 + i] + histogram[512 + i])
|
|
||||||
white = 0
|
|
||||||
black = 0
|
|
||||||
for i in range(251, 256):
|
|
||||||
white += RBGW[i]
|
|
||||||
for i in range(5):
|
|
||||||
black += RBGW[i]
|
|
||||||
if black > pixelCount*0.8 and white == 0:
|
|
||||||
return 1
|
|
||||||
elif white > pixelCount*0.8 and black == 0:
|
|
||||||
return -1
|
return -1
|
||||||
|
elif histogram[255] == 0:
|
||||||
|
return 1
|
||||||
else:
|
else:
|
||||||
return False
|
return 0
|
||||||
|
|
||||||
def getImageFill(self, webtoon):
|
def getImageFill(self):
|
||||||
fill = 0
|
bw = self.image.convert('L').point(lambda x: 0 if x < 128 else 255, '1')
|
||||||
if not webtoon and not self.rotated:
|
imageBoxA = bw.getbbox()
|
||||||
# Search for horizontal solid lines
|
imageBoxB = ImageChops.invert(bw).getbbox()
|
||||||
|
if imageBoxA is None or imageBoxB is None:
|
||||||
|
surfaceB, surfaceW = 0, 0
|
||||||
|
diff = 0
|
||||||
|
else:
|
||||||
|
surfaceB = (imageBoxA[2] - imageBoxA[0]) * (imageBoxA[3] - imageBoxA[1])
|
||||||
|
surfaceW = (imageBoxB[2] - imageBoxB[0]) * (imageBoxB[3] - imageBoxB[1])
|
||||||
|
diff = ((max(surfaceB, surfaceW) - min(surfaceB, surfaceW)) / min(surfaceB, surfaceW)) * 100
|
||||||
|
if diff > 0.5:
|
||||||
|
if surfaceW < surfaceB:
|
||||||
|
self.fill = 'white'
|
||||||
|
elif surfaceW > surfaceB:
|
||||||
|
self.fill = 'black'
|
||||||
|
else:
|
||||||
|
fill = 0
|
||||||
startY = 0
|
startY = 0
|
||||||
while startY < self.image.size[1]:
|
while startY < bw.size[1]:
|
||||||
if startY + 5 > self.image.size[1]:
|
if startY + 5 > bw.size[1]:
|
||||||
startY = self.image.size[1] - 5
|
startY = bw.size[1] - 5
|
||||||
checkSolid = self.getImageHistogram(self.image.crop((0, startY, self.image.size[0], startY+5)))
|
fill += self.getImageHistogram(bw.crop((0, startY, bw.size[0], startY + 5)))
|
||||||
if checkSolid:
|
|
||||||
fill += checkSolid
|
|
||||||
startY += 5
|
startY += 5
|
||||||
else:
|
|
||||||
# Search for vertical solid lines
|
|
||||||
startX = 0
|
startX = 0
|
||||||
while startX < self.image.size[0]:
|
while startX < bw.size[0]:
|
||||||
if startX + 5 > self.image.size[0]:
|
if startX + 5 > bw.size[0]:
|
||||||
startX = self.image.size[0] - 5
|
startX = bw.size[0] - 5
|
||||||
checkSolid = self.getImageHistogram(self.image.crop((startX, 0, startX+5, self.image.size[1])))
|
fill += self.getImageHistogram(bw.crop((startX, 0, startX + 5, bw.size[1])))
|
||||||
if checkSolid:
|
|
||||||
fill += checkSolid
|
|
||||||
startX += 5
|
startX += 5
|
||||||
if fill > 0:
|
if fill > 0:
|
||||||
self.fill = 'black'
|
self.fill = 'black'
|
||||||
else:
|
else:
|
||||||
self.fill = 'white'
|
self.fill = 'white'
|
||||||
|
|
||||||
def isImageColor(self):
|
def isImageColor(self):
|
||||||
v = ImageStat.Stat(self.image).var
|
img = self.image.copy()
|
||||||
isMonochromatic = reduce(lambda x, y: x and y < 0.005, v, True)
|
bands = img.getbands()
|
||||||
if isMonochromatic:
|
if bands == ('R', 'G', 'B') or bands == ('R', 'G', 'B', 'A'):
|
||||||
# Monochromatic
|
thumb = img.resize((40, 40))
|
||||||
return False
|
SSE, bias = 0, [0, 0, 0]
|
||||||
else:
|
bias = ImageStat.Stat(thumb).mean[:3]
|
||||||
if len(v) == 3:
|
bias = [b - sum(bias) / 3 for b in bias]
|
||||||
maxmin = abs(max(v) - min(v))
|
for pixel in thumb.getdata():
|
||||||
if maxmin > 1000:
|
mu = sum(pixel) / 3
|
||||||
# Color
|
SSE += sum((pixel[i] - mu - bias[i]) * (pixel[i] - mu - bias[i]) for i in [0, 1, 2])
|
||||||
return True
|
MSE = float(SSE) / (40 * 40)
|
||||||
elif maxmin > 100:
|
if MSE <= 22:
|
||||||
# Probably color
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
# Grayscale
|
|
||||||
return False
|
|
||||||
elif len(v) == 1:
|
|
||||||
# Black and white
|
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
# Detection failed
|
return True
|
||||||
return False
|
elif len(bands) == 1:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class Cover:
|
||||||
|
def __init__(self, source, target, opt, tomeNumber):
|
||||||
|
self.options = opt
|
||||||
|
self.source = source
|
||||||
|
self.target = target
|
||||||
|
if tomeNumber == 0:
|
||||||
|
self.tomeNumber = 1
|
||||||
|
else:
|
||||||
|
self.tomeNumber = tomeNumber
|
||||||
|
if self.tomeNumber in self.options.remoteCovers:
|
||||||
|
try:
|
||||||
|
source = urlopen(Request(quote(self.options.remoteCovers[self.tomeNumber]).replace('%3A', ':', 1),
|
||||||
|
headers={'User-Agent': 'KindleComicConverter/' + __version__})).read()
|
||||||
|
self.image = Image.open(BytesIO(source))
|
||||||
|
self.processExternal()
|
||||||
|
except Exception:
|
||||||
|
self.image = Image.open(source)
|
||||||
|
self.processInternal()
|
||||||
|
else:
|
||||||
|
self.image = Image.open(source)
|
||||||
|
self.processInternal()
|
||||||
|
|
||||||
|
def processInternal(self):
|
||||||
|
self.image = self.image.convert('RGB')
|
||||||
|
self.image = self.trim()
|
||||||
|
self.save()
|
||||||
|
|
||||||
|
def processExternal(self):
|
||||||
|
self.image = self.image.convert('RGB')
|
||||||
|
self.image.thumbnail(self.options.profileData[1], Image.LANCZOS)
|
||||||
|
self.save()
|
||||||
|
|
||||||
|
def trim(self):
|
||||||
|
bg = Image.new(self.image.mode, self.image.size, self.image.getpixel((0, 0)))
|
||||||
|
diff = ImageChops.difference(self.image, bg)
|
||||||
|
diff = ImageChops.add(diff, diff, 2.0, -100)
|
||||||
|
bbox = diff.getbbox()
|
||||||
|
if bbox:
|
||||||
|
return self.image.crop(bbox)
|
||||||
|
else:
|
||||||
|
return self.image
|
||||||
|
|
||||||
|
def save(self):
|
||||||
|
try:
|
||||||
|
self.image.save(self.target, "JPEG", optimize=1, quality=80)
|
||||||
|
except IOError:
|
||||||
|
raise RuntimeError('Failed to process downloaded cover.')
|
||||||
|
|||||||
@@ -1,382 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
|
||||||
# Based on initial version of KindleUnpack. Copyright (C) 2009 Charles M. Hannum <root@ihack.net>
|
|
||||||
# Improvements Copyright (C) 2009-2012 P. Durrant, K. Hendricks, S. Siebert, fandrieu, DiapDealer, nickredding
|
|
||||||
# Changes for KCC Copyright (C) 2013-2014 Pawel Jastrzebski <pawelj@vulturis.eu>
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
import struct
|
|
||||||
# from uuid import uuid4
|
|
||||||
|
|
||||||
# important pdb header offsets
|
|
||||||
unique_id_seed = 68
|
|
||||||
number_of_pdb_records = 76
|
|
||||||
|
|
||||||
# important palmdoc header offsets
|
|
||||||
book_length = 4
|
|
||||||
book_record_count = 8
|
|
||||||
first_pdb_record = 78
|
|
||||||
|
|
||||||
# important rec0 offsets
|
|
||||||
length_of_book = 4
|
|
||||||
mobi_header_base = 16
|
|
||||||
mobi_header_length = 20
|
|
||||||
mobi_type = 24
|
|
||||||
mobi_version = 36
|
|
||||||
first_non_text = 80
|
|
||||||
title_offset = 84
|
|
||||||
first_image_record = 108
|
|
||||||
first_content_index = 192
|
|
||||||
last_content_index = 194
|
|
||||||
kf8_last_content_index = 192 # for KF8 mobi headers
|
|
||||||
fcis_index = 200
|
|
||||||
flis_index = 208
|
|
||||||
srcs_index = 224
|
|
||||||
srcs_count = 228
|
|
||||||
primary_index = 244
|
|
||||||
datp_index = 256
|
|
||||||
huffoff = 112
|
|
||||||
hufftbloff = 120
|
|
||||||
|
|
||||||
|
|
||||||
def getint(datain, ofs, sz='L'):
|
|
||||||
i, = struct.unpack_from('>'+sz, datain, ofs)
|
|
||||||
return i
|
|
||||||
|
|
||||||
|
|
||||||
def writeint(datain, ofs, n, length='L'):
|
|
||||||
if length == 'L':
|
|
||||||
return datain[:ofs]+struct.pack('>L', n)+datain[ofs+4:]
|
|
||||||
else:
|
|
||||||
return datain[:ofs]+struct.pack('>H', n)+datain[ofs+2:]
|
|
||||||
|
|
||||||
|
|
||||||
def getsecaddr(datain, secno):
|
|
||||||
nsec = getint(datain, number_of_pdb_records, 'H')
|
|
||||||
assert secno >= 0 & secno < nsec, 'secno %d out of range (nsec=%d)' % (secno, nsec)
|
|
||||||
secstart = getint(datain, first_pdb_record+secno*8)
|
|
||||||
if secno == nsec-1:
|
|
||||||
secend = len(datain)
|
|
||||||
else:
|
|
||||||
secend = getint(datain, first_pdb_record+(secno+1)*8)
|
|
||||||
return secstart, secend
|
|
||||||
|
|
||||||
|
|
||||||
def readsection(datain, secno):
|
|
||||||
secstart, secend = getsecaddr(datain, secno)
|
|
||||||
return datain[secstart:secend]
|
|
||||||
|
|
||||||
|
|
||||||
def writesection(datain, secno, secdata): # overwrite, accounting for different length
|
|
||||||
dataout = deletesectionrange(datain, secno, secno)
|
|
||||||
return insertsection(dataout, secno, secdata)
|
|
||||||
|
|
||||||
|
|
||||||
def nullsection(datain, secno): # make it zero-length without deleting it
|
|
||||||
datalst = []
|
|
||||||
nsec = getint(datain, number_of_pdb_records, 'H')
|
|
||||||
secstart, secend = getsecaddr(datain, secno)
|
|
||||||
zerosecstart, zerosecend = getsecaddr(datain, 0)
|
|
||||||
dif = secend-secstart
|
|
||||||
datalst.append(datain[:first_pdb_record])
|
|
||||||
for i in range(0, secno+1):
|
|
||||||
ofs, flgval = struct.unpack_from('>2L', datain, first_pdb_record+i*8)
|
|
||||||
datalst.append(struct.pack('>L', ofs) + struct.pack('>L', flgval))
|
|
||||||
for i in range(secno+1, nsec):
|
|
||||||
ofs, flgval = struct.unpack_from('>2L', datain, first_pdb_record+i*8)
|
|
||||||
ofs -= dif
|
|
||||||
datalst.append(struct.pack('>L', ofs) + struct.pack('>L', flgval))
|
|
||||||
lpad = zerosecstart - (first_pdb_record + 8*nsec)
|
|
||||||
if lpad > 0:
|
|
||||||
datalst.append(b'\0' * lpad)
|
|
||||||
datalst.append(datain[zerosecstart: secstart])
|
|
||||||
datalst.append(datain[secend:])
|
|
||||||
dataout = b"".join(datalst)
|
|
||||||
return dataout
|
|
||||||
|
|
||||||
|
|
||||||
def deletesectionrange(datain, firstsec, lastsec): # delete a range of sections
|
|
||||||
datalst = []
|
|
||||||
firstsecstart, firstsecend = getsecaddr(datain, firstsec)
|
|
||||||
lastsecstart, lastsecend = getsecaddr(datain, lastsec)
|
|
||||||
zerosecstart, zerosecend = getsecaddr(datain, 0)
|
|
||||||
dif = lastsecend - firstsecstart + 8*(lastsec-firstsec+1)
|
|
||||||
nsec = getint(datain, number_of_pdb_records, 'H')
|
|
||||||
datalst.append(datain[:unique_id_seed])
|
|
||||||
datalst.append(struct.pack('>L', 2*(nsec-(lastsec-firstsec+1))+1))
|
|
||||||
datalst.append(datain[unique_id_seed+4:number_of_pdb_records])
|
|
||||||
datalst.append(struct.pack('>H', nsec-(lastsec-firstsec+1)))
|
|
||||||
newstart = zerosecstart - 8*(lastsec-firstsec+1)
|
|
||||||
for i in range(0, firstsec):
|
|
||||||
ofs, flgval = struct.unpack_from('>2L', datain, first_pdb_record+i*8)
|
|
||||||
ofs -= 8 * (lastsec - firstsec + 1)
|
|
||||||
datalst.append(struct.pack('>L', ofs) + struct.pack('>L', flgval))
|
|
||||||
for i in range(lastsec+1, nsec):
|
|
||||||
ofs, flgval = struct.unpack_from('>2L', datain, first_pdb_record+i*8)
|
|
||||||
ofs -= dif
|
|
||||||
flgval = 2*(i-(lastsec-firstsec+1))
|
|
||||||
datalst.append(struct.pack('>L', ofs) + struct.pack('>L', flgval))
|
|
||||||
lpad = newstart - (first_pdb_record + 8*(nsec - (lastsec - firstsec + 1)))
|
|
||||||
if lpad > 0:
|
|
||||||
datalst.append(b'\0' * lpad)
|
|
||||||
datalst.append(datain[zerosecstart:firstsecstart])
|
|
||||||
datalst.append(datain[lastsecend:])
|
|
||||||
dataout = b"".join(datalst)
|
|
||||||
return dataout
|
|
||||||
|
|
||||||
|
|
||||||
def insertsection(datain, secno, secdata): # insert a new section
|
|
||||||
datalst = []
|
|
||||||
nsec = getint(datain, number_of_pdb_records, 'H')
|
|
||||||
secstart, secend = getsecaddr(datain, secno)
|
|
||||||
zerosecstart, zerosecend = getsecaddr(datain, 0)
|
|
||||||
dif = len(secdata)
|
|
||||||
datalst.append(datain[:unique_id_seed])
|
|
||||||
datalst.append(struct.pack('>L', 2*(nsec+1)+1))
|
|
||||||
datalst.append(datain[unique_id_seed+4:number_of_pdb_records])
|
|
||||||
datalst.append(struct.pack('>H', nsec+1))
|
|
||||||
newstart = zerosecstart + 8
|
|
||||||
for i in range(0, secno):
|
|
||||||
ofs, flgval = struct.unpack_from('>2L', datain, first_pdb_record+i*8)
|
|
||||||
ofs += 8
|
|
||||||
datalst.append(struct.pack('>L', ofs) + struct.pack('>L', flgval))
|
|
||||||
datalst.append(struct.pack('>L', secstart + 8) + struct.pack('>L', (2*secno)))
|
|
||||||
for i in range(secno, nsec):
|
|
||||||
ofs, flgval = struct.unpack_from('>2L', datain, first_pdb_record+i*8)
|
|
||||||
ofs = ofs + dif + 8
|
|
||||||
flgval = 2*(i+1)
|
|
||||||
datalst.append(struct.pack('>L', ofs) + struct.pack('>L', flgval))
|
|
||||||
lpad = newstart - (first_pdb_record + 8*(nsec + 1))
|
|
||||||
if lpad > 0:
|
|
||||||
datalst.append(b'\0' * lpad)
|
|
||||||
datalst.append(datain[zerosecstart:secstart])
|
|
||||||
datalst.append(secdata)
|
|
||||||
datalst.append(datain[secstart:])
|
|
||||||
dataout = b"".join(datalst)
|
|
||||||
return dataout
|
|
||||||
|
|
||||||
|
|
||||||
def insertsectionrange(sectionsource, firstsec, lastsec, sectiontarget, targetsec): # insert a range of sections
|
|
||||||
dataout = sectiontarget
|
|
||||||
for idx in range(lastsec, firstsec-1, -1):
|
|
||||||
dataout = insertsection(dataout, targetsec, readsection(sectionsource, idx))
|
|
||||||
return dataout
|
|
||||||
|
|
||||||
|
|
||||||
def get_exth_params(rec0):
|
|
||||||
ebase = mobi_header_base + getint(rec0, mobi_header_length)
|
|
||||||
elen = getint(rec0, ebase+4)
|
|
||||||
enum = getint(rec0, ebase+8)
|
|
||||||
return ebase, elen, enum
|
|
||||||
|
|
||||||
|
|
||||||
def add_exth(rec0, exth_num, exth_bytes):
|
|
||||||
ebase, elen, enum = get_exth_params(rec0)
|
|
||||||
newrecsize = 8+len(exth_bytes)
|
|
||||||
newrec0 = rec0[0:ebase+4]+struct.pack('>L', elen+newrecsize)+struct.pack('>L', enum+1) +\
|
|
||||||
struct.pack('>L', exth_num) + struct.pack('>L', newrecsize)+exth_bytes+rec0[ebase+12:]
|
|
||||||
newrec0 = writeint(newrec0, title_offset, getint(newrec0, title_offset)+newrecsize)
|
|
||||||
return newrec0
|
|
||||||
|
|
||||||
|
|
||||||
def read_exth(rec0, exth_num):
|
|
||||||
exth_values = []
|
|
||||||
ebase, elen, enum = get_exth_params(rec0)
|
|
||||||
ebase += 12
|
|
||||||
while enum > 0:
|
|
||||||
exth_id = getint(rec0, ebase)
|
|
||||||
if exth_id == exth_num:
|
|
||||||
# We might have multiple exths, so build a list.
|
|
||||||
exth_values.append(rec0[ebase+8:ebase+getint(rec0, ebase+4)])
|
|
||||||
enum -= 1
|
|
||||||
ebase = ebase+getint(rec0, ebase+4)
|
|
||||||
return exth_values
|
|
||||||
|
|
||||||
|
|
||||||
def write_exth(rec0, exth_num, exth_bytes):
|
|
||||||
ebase, elen, enum = get_exth_params(rec0)
|
|
||||||
ebase_idx = ebase+12
|
|
||||||
enum_idx = enum
|
|
||||||
while enum_idx > 0:
|
|
||||||
exth_id = getint(rec0, ebase_idx)
|
|
||||||
if exth_id == exth_num:
|
|
||||||
dif = len(exth_bytes)+8-getint(rec0, ebase_idx+4)
|
|
||||||
newrec0 = rec0
|
|
||||||
if dif != 0:
|
|
||||||
newrec0 = writeint(newrec0, title_offset, getint(newrec0, title_offset)+dif)
|
|
||||||
return newrec0[:ebase+4]+struct.pack('>L', elen+len(exth_bytes)+8-getint(rec0, ebase_idx+4)) +\
|
|
||||||
struct.pack('>L', enum)+rec0[ebase+12:ebase_idx+4] +\
|
|
||||||
struct.pack('>L', len(exth_bytes)+8)+exth_bytes +\
|
|
||||||
rec0[ebase_idx+getint(rec0, ebase_idx+4):]
|
|
||||||
enum_idx -= 1
|
|
||||||
ebase_idx = ebase_idx+getint(rec0, ebase_idx+4)
|
|
||||||
return rec0
|
|
||||||
|
|
||||||
|
|
||||||
def del_exth(rec0, exth_num):
|
|
||||||
ebase, elen, enum = get_exth_params(rec0)
|
|
||||||
ebase_idx = ebase+12
|
|
||||||
enum_idx = 0
|
|
||||||
while enum_idx < enum:
|
|
||||||
exth_id = getint(rec0, ebase_idx)
|
|
||||||
exth_size = getint(rec0, ebase_idx+4)
|
|
||||||
if exth_id == exth_num:
|
|
||||||
newrec0 = rec0
|
|
||||||
newrec0 = writeint(newrec0, title_offset, getint(newrec0, title_offset)-exth_size)
|
|
||||||
newrec0 = newrec0[:ebase_idx]+newrec0[ebase_idx+exth_size:]
|
|
||||||
newrec0 = newrec0[0:ebase+4]+struct.pack('>L', elen-exth_size)+struct.pack('>L', enum-1)+newrec0[ebase+12:]
|
|
||||||
return newrec0
|
|
||||||
enum_idx += 1
|
|
||||||
ebase_idx = ebase_idx+exth_size
|
|
||||||
return rec0
|
|
||||||
|
|
||||||
|
|
||||||
class mobi_split:
|
|
||||||
def __init__(self, infile, newKindle):
|
|
||||||
try:
|
|
||||||
datain = open(infile, 'rb').read()
|
|
||||||
datain_rec0 = readsection(datain, 0)
|
|
||||||
ver = getint(datain_rec0, mobi_version)
|
|
||||||
# fake_asin = str(uuid4())
|
|
||||||
self.combo = (ver != 8)
|
|
||||||
if not self.combo:
|
|
||||||
return
|
|
||||||
exth121 = read_exth(datain_rec0, 121)
|
|
||||||
if len(exth121) == 0:
|
|
||||||
self.combo = False
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
# only pay attention to first exth121
|
|
||||||
# (there should only be one)
|
|
||||||
datain_kf8, = struct.unpack_from('>L', exth121[0], 0)
|
|
||||||
if datain_kf8 == 0xffffffff:
|
|
||||||
self.combo = False
|
|
||||||
return
|
|
||||||
datain_kfrec0 = readsection(datain, datain_kf8)
|
|
||||||
firstimage = getint(datain_rec0, first_image_record)
|
|
||||||
lastimage = getint(datain_rec0, last_content_index, 'H')
|
|
||||||
|
|
||||||
if not newKindle:
|
|
||||||
# create the standalone mobi7
|
|
||||||
num_sec = getint(datain, number_of_pdb_records, 'H')
|
|
||||||
# remove BOUNDARY up to but not including ELF record
|
|
||||||
self.result_file = deletesectionrange(datain, datain_kf8-1, num_sec-2)
|
|
||||||
# check if there are SRCS records and delete them
|
|
||||||
srcs = getint(datain_rec0, srcs_index)
|
|
||||||
num_srcs = getint(datain_rec0, srcs_count)
|
|
||||||
if srcs != 0xffffffff and num_srcs > 0:
|
|
||||||
self.result_file = deletesectionrange(self.result_file, srcs, srcs+num_srcs-1)
|
|
||||||
datain_rec0 = writeint(datain_rec0, srcs_index, 0xffffffff)
|
|
||||||
datain_rec0 = writeint(datain_rec0, srcs_count, 0)
|
|
||||||
# reset the EXTH 121 KF8 Boundary meta data to 0xffffffff
|
|
||||||
datain_rec0 = write_exth(datain_rec0, 121, struct.pack('>L', 0xffffffff))
|
|
||||||
# datain_rec0 = del_exth(datain_rec0,121)
|
|
||||||
# datain_rec0 = del_exth(datain_rec0,534)
|
|
||||||
# don't remove the EXTH 125 KF8 Count of Resources, seems to be present in mobi6 files as well
|
|
||||||
# set the EXTH 129 KF8 Masthead / Cover Image string to the null string
|
|
||||||
datain_rec0 = write_exth(datain_rec0, 129, b'')
|
|
||||||
# don't remove the EXTH 131 KF8 Unidentified Count, seems to be present in mobi6 files as well
|
|
||||||
|
|
||||||
# Make sure we have an ASIN & cdeType set...
|
|
||||||
# if len(read_exth(datain_rec0, 113)) == 0:
|
|
||||||
# datain_rec0 = add_exth(datain_rec0, 113, fake_asin)
|
|
||||||
# if len(read_exth(datain_rec0, 504)) == 0:
|
|
||||||
# datain_rec0 = add_exth(datain_rec0, 504, fake_asin)
|
|
||||||
if len(read_exth(datain_rec0, 501)) == 0:
|
|
||||||
datain_rec0 = add_exth(datain_rec0, 501, b'EBOK')
|
|
||||||
|
|
||||||
# need to reset flags stored in 0x80-0x83
|
|
||||||
# old mobi with exth: 0x50, mobi7 part with exth: 0x1850, mobi8 part with exth: 0x1050
|
|
||||||
# Bit Flags
|
|
||||||
# 0x1000 = Bit 12 indicates if embedded fonts are used or not
|
|
||||||
# 0x0800 = means this Header points to *shared* images/resource/fonts ??
|
|
||||||
# 0x0080 = unknown new flag, why is this now being set by Kindlegen 2.8?
|
|
||||||
# 0x0040 = exth exists
|
|
||||||
# 0x0010 = Not sure but this is always set so far
|
|
||||||
fval, = struct.unpack_from('>L', datain_rec0, 0x80)
|
|
||||||
# need to remove flag 0x0800 for KindlePreviewer 2.8 and unset Bit 12 for embedded fonts
|
|
||||||
fval &= 0x07FF
|
|
||||||
datain_rec0 = datain_rec0[:0x80] + struct.pack('>L', fval) + datain_rec0[0x84:]
|
|
||||||
self.result_file = writesection(self.result_file, 0, datain_rec0)
|
|
||||||
if lastimage == 0xffff:
|
|
||||||
# find the lowest of the next sections and copy up to that.
|
|
||||||
ofs_list = [(kf8_last_content_index, 'L'), (fcis_index, 'L'), (flis_index, 'L'), (datp_index, 'L'),
|
|
||||||
(hufftbloff, 'L')]
|
|
||||||
for ofs, sz in ofs_list:
|
|
||||||
n = getint(datain_kfrec0, ofs, sz)
|
|
||||||
if 0 < n < lastimage:
|
|
||||||
lastimage = n-1
|
|
||||||
|
|
||||||
# Try to null out FONT and RES, but leave the (empty) PDB record so image refs remain valid
|
|
||||||
for i in range(firstimage, lastimage):
|
|
||||||
imgsec = readsection(self.result_file, i)
|
|
||||||
if imgsec[0:4] in ['RESC', 'FONT']:
|
|
||||||
self.result_file = nullsection(self.result_file, i)
|
|
||||||
# mobi7 finished
|
|
||||||
else:
|
|
||||||
# create standalone mobi8
|
|
||||||
self.result_file = deletesectionrange(datain, 0, datain_kf8-1)
|
|
||||||
target = getint(datain_kfrec0, first_image_record)
|
|
||||||
self.result_file = insertsectionrange(datain, firstimage, lastimage, self.result_file, target)
|
|
||||||
datain_kfrec0 = readsection(self.result_file, 0)
|
|
||||||
|
|
||||||
# Only keep the correct EXTH 116 StartOffset, KG 2.5 carries over the one from the mobi7 part,
|
|
||||||
# which then points at garbage in the mobi8 part, and confuses FW 3.4
|
|
||||||
kf8starts = read_exth(datain_kfrec0, 116)
|
|
||||||
# If we have multiple StartOffset, keep only the last one
|
|
||||||
kf8start_count = len(kf8starts)
|
|
||||||
while kf8start_count > 1:
|
|
||||||
kf8start_count -= 1
|
|
||||||
datain_kfrec0 = del_exth(datain_kfrec0, 116)
|
|
||||||
|
|
||||||
# update the EXTH 125 KF8 Count of Images/Fonts/Resources
|
|
||||||
datain_kfrec0 = write_exth(datain_kfrec0, 125, struct.pack('>L', lastimage-firstimage+1))
|
|
||||||
|
|
||||||
# Same dance for the KF8, we want an ASIN & cdeType :)
|
|
||||||
# if len(read_exth(datain_kfrec0, 113)) == 0:
|
|
||||||
# datain_kfrec0 = add_exth(datain_kfrec0, 113, fake_asin)
|
|
||||||
# if len(read_exth(datain_kfrec0, 504)) == 0:
|
|
||||||
# datain_kfrec0 = add_exth(datain_kfrec0, 504, fake_asin)
|
|
||||||
if len(read_exth(datain_kfrec0, 501)) == 0:
|
|
||||||
datain_kfrec0 = add_exth(datain_kfrec0, 501, b'EBOK')
|
|
||||||
|
|
||||||
# need to reset flags stored in 0x80-0x83
|
|
||||||
# old mobi with exth: 0x50, mobi7 part with exth: 0x1850, mobi8 part with exth: 0x1050
|
|
||||||
# standalone mobi8 with exth: 0x0050
|
|
||||||
# Bit Flags
|
|
||||||
# 0x1000 = Bit 12 indicates if embedded fonts are used or not
|
|
||||||
# 0x0800 = means this Header points to *shared* images/resource/fonts ??
|
|
||||||
# 0x0080 = unknown new flag, why is this now being set by Kindlegen 2.8?
|
|
||||||
# 0x0040 = exth exists
|
|
||||||
# 0x0010 = Not sure but this is always set so far
|
|
||||||
fval, = struct.unpack_from('>L', datain_kfrec0, 0x80)
|
|
||||||
fval &= 0x1FFF
|
|
||||||
fval |= 0x0800
|
|
||||||
datain_kfrec0 = datain_kfrec0[:0x80] + struct.pack('>L', fval) + datain_kfrec0[0x84:]
|
|
||||||
|
|
||||||
# properly update other index pointers that have been shifted by the insertion of images
|
|
||||||
ofs_list = [(kf8_last_content_index, 'L'), (fcis_index, 'L'), (flis_index, 'L'), (datp_index, 'L'),
|
|
||||||
(hufftbloff, 'L')]
|
|
||||||
for ofs, sz in ofs_list:
|
|
||||||
n = getint(datain_kfrec0, ofs, sz)
|
|
||||||
if n != 0xffffffff:
|
|
||||||
datain_kfrec0 = writeint(datain_kfrec0, ofs, n+lastimage-firstimage+1, sz)
|
|
||||||
self.result_file = writesection(self.result_file, 0, datain_kfrec0)
|
|
||||||
# mobi8 finished
|
|
||||||
except Exception:
|
|
||||||
raise
|
|
||||||
|
|
||||||
def getResult(self):
|
|
||||||
return self.result_file
|
|
||||||
172
kcc/metadata.py
Normal file
172
kcc/metadata.py
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# Copyright (c) 2013-2015 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, and/or distribute this software for
|
||||||
|
# any purpose with or without fee is hereby granted, provided that the
|
||||||
|
# above copyright notice and this permission notice appear in all
|
||||||
|
# copies.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||||
|
# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||||
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||||
|
# AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
# DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
|
||||||
|
# OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||||
|
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
# PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
import os
|
||||||
|
from xml.dom.minidom import parse, Document
|
||||||
|
from re import compile
|
||||||
|
from zipfile import is_zipfile, ZipFile, ZIP_DEFLATED
|
||||||
|
from subprocess import STDOUT, PIPE
|
||||||
|
from psutil import Popen
|
||||||
|
from tempfile import mkdtemp
|
||||||
|
from shutil import rmtree
|
||||||
|
from .shared import removeFromZIP, check7ZFile as is_7zfile
|
||||||
|
from . import rarfile
|
||||||
|
|
||||||
|
|
||||||
|
class MetadataParser:
|
||||||
|
def __init__(self, source):
|
||||||
|
self.source = source
|
||||||
|
self.data = {'Series': '',
|
||||||
|
'Volume': '',
|
||||||
|
'Number': '',
|
||||||
|
'Writers': [],
|
||||||
|
'Pencillers': [],
|
||||||
|
'Inkers': [],
|
||||||
|
'Colorists': [],
|
||||||
|
'Summary': '',
|
||||||
|
'MUid': '',
|
||||||
|
'Bookmarks': []}
|
||||||
|
self.rawdata = None
|
||||||
|
self.compressor = None
|
||||||
|
if self.source.endswith('.xml'):
|
||||||
|
self.rawdata = parse(self.source)
|
||||||
|
self.parseXML()
|
||||||
|
else:
|
||||||
|
if is_zipfile(self.source):
|
||||||
|
self.compressor = 'zip'
|
||||||
|
with ZipFile(self.source) as zip_file:
|
||||||
|
for member in zip_file.namelist():
|
||||||
|
if member != 'ComicInfo.xml':
|
||||||
|
continue
|
||||||
|
with zip_file.open(member) as xml_file:
|
||||||
|
self.rawdata = parse(xml_file)
|
||||||
|
elif rarfile.is_rarfile(self.source):
|
||||||
|
self.compressor = 'rar'
|
||||||
|
with rarfile.RarFile(self.source) as rar_file:
|
||||||
|
for member in rar_file.namelist():
|
||||||
|
if member != 'ComicInfo.xml':
|
||||||
|
continue
|
||||||
|
with rar_file.open(member) as xml_file:
|
||||||
|
self.rawdata = parse(xml_file)
|
||||||
|
elif is_7zfile(self.source):
|
||||||
|
self.compressor = '7z'
|
||||||
|
workdir = mkdtemp('', 'KCC-')
|
||||||
|
tmpXML = os.path.join(workdir, 'ComicInfo.xml')
|
||||||
|
output = Popen('7za e "' + self.source + '" ComicInfo.xml -o"' + workdir + '"',
|
||||||
|
stdout=PIPE, stderr=STDOUT, shell=True)
|
||||||
|
extracted = False
|
||||||
|
for line in output.stdout:
|
||||||
|
if b"Everything is Ok" in line or b"No files to process" in line:
|
||||||
|
extracted = True
|
||||||
|
if not extracted:
|
||||||
|
rmtree(workdir)
|
||||||
|
raise OSError
|
||||||
|
if os.path.isfile(tmpXML):
|
||||||
|
self.rawdata = parse(tmpXML)
|
||||||
|
rmtree(workdir)
|
||||||
|
else:
|
||||||
|
raise OSError
|
||||||
|
if self.rawdata:
|
||||||
|
self.parseXML()
|
||||||
|
|
||||||
|
def parseXML(self):
|
||||||
|
if len(self.rawdata.getElementsByTagName('Series')) != 0:
|
||||||
|
self.data['Series'] = self.rawdata.getElementsByTagName('Series')[0].firstChild.nodeValue
|
||||||
|
if len(self.rawdata.getElementsByTagName('Volume')) != 0:
|
||||||
|
self.data['Volume'] = self.rawdata.getElementsByTagName('Volume')[0].firstChild.nodeValue
|
||||||
|
if len(self.rawdata.getElementsByTagName('Number')) != 0:
|
||||||
|
self.data['Number'] = self.rawdata.getElementsByTagName('Number')[0].firstChild.nodeValue
|
||||||
|
if len(self.rawdata.getElementsByTagName('Summary')) != 0:
|
||||||
|
self.data['Summary'] = self.rawdata.getElementsByTagName('Summary')[0].firstChild.nodeValue
|
||||||
|
for field in ['Writer', 'Penciller', 'Inker', 'Colorist']:
|
||||||
|
if len(self.rawdata.getElementsByTagName(field)) != 0:
|
||||||
|
for person in self.rawdata.getElementsByTagName(field)[0].firstChild.nodeValue.split(', '):
|
||||||
|
self.data[field + 's'].append(person)
|
||||||
|
self.data[field + 's'] = list(set(self.data[field + 's']))
|
||||||
|
self.data[field + 's'].sort()
|
||||||
|
if len(self.rawdata.getElementsByTagName('ScanInformation')) != 0:
|
||||||
|
coverId = compile('(MCD\\()(\\d+)(\\))')\
|
||||||
|
.search(self.rawdata.getElementsByTagName('ScanInformation')[0].firstChild.nodeValue)
|
||||||
|
if coverId:
|
||||||
|
self.data['MUid'] = coverId.group(2)
|
||||||
|
if len(self.rawdata.getElementsByTagName('Page')) != 0:
|
||||||
|
for page in self.rawdata.getElementsByTagName('Page'):
|
||||||
|
if 'Bookmark' in page.attributes and 'Image' in page.attributes:
|
||||||
|
self.data['Bookmarks'].append((int(page.attributes['Image'].value),
|
||||||
|
page.attributes['Bookmark'].value))
|
||||||
|
|
||||||
|
def saveXML(self):
|
||||||
|
if self.rawdata:
|
||||||
|
root = self.rawdata.getElementsByTagName('ComicInfo')[0]
|
||||||
|
for row in (['Series', self.data['Series']], ['Volume', self.data['Volume']],
|
||||||
|
['Number', self.data['Number']], ['Writer', ', '.join(self.data['Writers'])],
|
||||||
|
['Penciller', ', '.join(self.data['Pencillers'])], ['Inker', ', '.join(self.data['Inkers'])],
|
||||||
|
['Colorist', ', '.join(self.data['Colorists'])], ['Summary', self.data['Summary']],
|
||||||
|
['ScanInformation', 'MCD(' + self.data['MUid'] + ')' if self.data['MUid'] else '']):
|
||||||
|
if self.rawdata.getElementsByTagName(row[0]):
|
||||||
|
node = self.rawdata.getElementsByTagName(row[0])[0]
|
||||||
|
if row[1]:
|
||||||
|
node.firstChild.replaceWholeText(row[1])
|
||||||
|
else:
|
||||||
|
root.removeChild(node)
|
||||||
|
elif row[1]:
|
||||||
|
main = self.rawdata.createElement(row[0])
|
||||||
|
root.appendChild(main)
|
||||||
|
text = self.rawdata.createTextNode(row[1])
|
||||||
|
main.appendChild(text)
|
||||||
|
else:
|
||||||
|
doc = Document()
|
||||||
|
root = doc.createElement('ComicInfo')
|
||||||
|
root.setAttribute('xmlns:xsd', 'http://www.w3.org/2001/XMLSchema')
|
||||||
|
root.setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance')
|
||||||
|
doc.appendChild(root)
|
||||||
|
for row in (['Series', self.data['Series']], ['Volume', self.data['Volume']],
|
||||||
|
['Number', self.data['Number']], ['Writer', ', '.join(self.data['Writers'])],
|
||||||
|
['Penciller', ', '.join(self.data['Pencillers'])], ['Inker', ', '.join(self.data['Inkers'])],
|
||||||
|
['Colorist', ', '.join(self.data['Colorists'])], ['Summary', self.data['Summary']],
|
||||||
|
['ScanInformation', 'MCD(' + self.data['MUid'] + ')' if self.data['MUid'] else '']):
|
||||||
|
if row[1]:
|
||||||
|
main = doc.createElement(row[0])
|
||||||
|
root.appendChild(main)
|
||||||
|
text = doc.createTextNode(row[1])
|
||||||
|
main.appendChild(text)
|
||||||
|
self.rawdata = doc
|
||||||
|
if self.source.endswith('.xml'):
|
||||||
|
with open(self.source, 'w', encoding='utf-8') as f:
|
||||||
|
self.rawdata.writexml(f, encoding='utf-8')
|
||||||
|
else:
|
||||||
|
workdir = mkdtemp('', 'KCC-')
|
||||||
|
tmpXML = os.path.join(workdir, 'ComicInfo.xml')
|
||||||
|
with open(tmpXML, 'w', encoding='utf-8') as f:
|
||||||
|
self.rawdata.writexml(f, encoding='utf-8')
|
||||||
|
if is_zipfile(self.source):
|
||||||
|
removeFromZIP(self.source, 'ComicInfo.xml')
|
||||||
|
with ZipFile(self.source, mode='a', compression=ZIP_DEFLATED) as zip_file:
|
||||||
|
zip_file.write(tmpXML, arcname=tmpXML.split(os.sep)[-1])
|
||||||
|
elif rarfile.is_rarfile(self.source):
|
||||||
|
raise NotImplementedError
|
||||||
|
elif is_7zfile(self.source):
|
||||||
|
output = Popen('7za a "' + self.source + '" "' + tmpXML + '"', stdout=PIPE, stderr=STDOUT, shell=True)
|
||||||
|
extracted = False
|
||||||
|
for line in output.stdout:
|
||||||
|
if b"Everything is Ok" in line:
|
||||||
|
extracted = True
|
||||||
|
if not extracted:
|
||||||
|
rmtree(workdir)
|
||||||
|
raise OSError
|
||||||
|
rmtree(workdir)
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||||
# Copyright (c) 2013-2014 Pawel Jastrzebski <pawelj@vulturis.eu>
|
# Copyright (c) 2013-2015 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
#
|
#
|
||||||
# Based upon the code snippet by Ned Batchelder
|
# Based upon the code snippet by Ned Batchelder
|
||||||
# (http://nedbatchelder.com/blog/200712/extracting_jpgs_from_pdfs.html)
|
# (http://nedbatchelder.com/blog/200712/extracting_jpgs_from_pdfs.html)
|
||||||
@@ -19,10 +19,6 @@
|
|||||||
# PERFORMANCE OF THIS SOFTWARE.
|
# PERFORMANCE OF THIS SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__license__ = 'ISC'
|
|
||||||
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
|
|
||||||
__docformat__ = 'restructuredtext en'
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from random import choice
|
from random import choice
|
||||||
from string import ascii_uppercase, digits
|
from string import ascii_uppercase, digits
|
||||||
@@ -33,7 +29,7 @@ class PdfJpgExtract:
|
|||||||
self.origFileName = origFileName
|
self.origFileName = origFileName
|
||||||
self.filename = os.path.splitext(origFileName)
|
self.filename = os.path.splitext(origFileName)
|
||||||
# noinspection PyUnusedLocal
|
# noinspection PyUnusedLocal
|
||||||
self.path = self.filename[0] + "-KCC-TMP-" + ''.join(choice(ascii_uppercase + digits) for x in range(3))
|
self.path = self.filename[0] + "-KCC-" + ''.join(choice(ascii_uppercase + digits) for x in range(3))
|
||||||
|
|
||||||
def getPath(self):
|
def getPath(self):
|
||||||
return self.path
|
return self.path
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# rarfile.py
|
# rarfile.py
|
||||||
#
|
#
|
||||||
# Copyright (c) 2005-2013 Marko Kreen <markokr@gmail.com>
|
# Copyright (c) 2005-2014 Marko Kreen <markokr@gmail.com>
|
||||||
#
|
#
|
||||||
# Permission to use, copy, modify, and/or distribute this software for any
|
# Permission to use, copy, modify, and/or distribute this software for any
|
||||||
# purpose with or without fee is hereby granted, provided that the above
|
# purpose with or without fee is hereby granted, provided that the above
|
||||||
@@ -74,7 +74,7 @@ For more details, refer to source.
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__version__ = '2.6'
|
__version__ = '2.7-kcc'
|
||||||
|
|
||||||
# export only interesting items
|
# export only interesting items
|
||||||
__all__ = ['is_rarfile', 'RarInfo', 'RarFile', 'RarExtFile']
|
__all__ = ['is_rarfile', 'RarInfo', 'RarFile', 'RarExtFile']
|
||||||
@@ -178,8 +178,25 @@ EXTRACT_ARGS = ('x', '-y', '-idq')
|
|||||||
#: args for testrar()
|
#: args for testrar()
|
||||||
TEST_ARGS = ('t', '-idq')
|
TEST_ARGS = ('t', '-idq')
|
||||||
|
|
||||||
|
#
|
||||||
|
# Allow use of tool that is not compatible with unrar.
|
||||||
|
#
|
||||||
|
# By default use 'bsdtar' which is 'tar' program that
|
||||||
|
# sits on top of libarchive.
|
||||||
|
#
|
||||||
|
# Problems with libarchive RAR backend:
|
||||||
|
# - Does not support solid archives.
|
||||||
|
# - Does not support password-protected archives.
|
||||||
|
#
|
||||||
|
|
||||||
|
ALT_TOOL = 'bsdtar'
|
||||||
|
ALT_OPEN_ARGS = ('-x', '--to-stdout', '-f')
|
||||||
|
ALT_EXTRACT_ARGS = ('-x', '-f')
|
||||||
|
ALT_TEST_ARGS = ('-t', '-f')
|
||||||
|
ALT_CHECK_ARGS = ('--help',)
|
||||||
|
|
||||||
#: whether to speed up decompression by using tmp archive
|
#: whether to speed up decompression by using tmp archive
|
||||||
USE_EXTRACT_HACK = 1
|
USE_EXTRACT_HACK = 0
|
||||||
|
|
||||||
#: limit the filesize for tmp archive usage
|
#: limit the filesize for tmp archive usage
|
||||||
HACK_SIZE_LIMIT = 20*1024*1024
|
HACK_SIZE_LIMIT = 20*1024*1024
|
||||||
@@ -278,6 +295,7 @@ RAR_M5 = 0x35
|
|||||||
##
|
##
|
||||||
|
|
||||||
RAR_ID = bytes("Rar!\x1a\x07\x00", 'ascii')
|
RAR_ID = bytes("Rar!\x1a\x07\x00", 'ascii')
|
||||||
|
RAR5_ID = bytes("Rar!\x1a\x07\x01", 'ascii')
|
||||||
ZERO = bytes("\0", 'ascii')
|
ZERO = bytes("\0", 'ascii')
|
||||||
EMPTY = bytes("", 'ascii')
|
EMPTY = bytes("", 'ascii')
|
||||||
|
|
||||||
@@ -336,14 +354,18 @@ class RarUnknownError(RarExecError):
|
|||||||
"""Unknown exit code"""
|
"""Unknown exit code"""
|
||||||
class RarSignalExit(RarExecError):
|
class RarSignalExit(RarExecError):
|
||||||
"""Unrar exited with signal"""
|
"""Unrar exited with signal"""
|
||||||
|
class RarCannotExec(RarExecError):
|
||||||
|
"""Executable not found."""
|
||||||
|
|
||||||
|
|
||||||
def is_rarfile(xfile):
|
def is_rarfile(xfile):
|
||||||
'''Check quickly whether file is rar archive.'''
|
'''Check quickly whether file is rar archive.'''
|
||||||
fd = XFile(xfile)
|
with open(xfile, 'rb') as fh:
|
||||||
buf = fd.read(len(RAR_ID))
|
buf = fh.read(len(RAR_ID))
|
||||||
fd.close()
|
if buf == RAR_ID or buf == RAR5_ID:
|
||||||
return buf == RAR_ID
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
class RarInfo(object):
|
class RarInfo(object):
|
||||||
@@ -693,10 +715,7 @@ class RarFile(object):
|
|||||||
"""Let 'unrar' test the archive.
|
"""Let 'unrar' test the archive.
|
||||||
"""
|
"""
|
||||||
cmd = [UNRAR_TOOL] + list(TEST_ARGS)
|
cmd = [UNRAR_TOOL] + list(TEST_ARGS)
|
||||||
if self._password is not None:
|
add_password_arg(cmd, self._password)
|
||||||
cmd.append('-p' + self._password)
|
|
||||||
else:
|
|
||||||
cmd.append('-p-')
|
|
||||||
cmd.append(self.rarfile)
|
cmd.append(self.rarfile)
|
||||||
p = custom_popen(cmd)
|
p = custom_popen(cmd)
|
||||||
output = p.communicate()[0]
|
output = p.communicate()[0]
|
||||||
@@ -769,7 +788,7 @@ class RarFile(object):
|
|||||||
fd = XFile(self.rarfile)
|
fd = XFile(self.rarfile)
|
||||||
self._fd = fd
|
self._fd = fd
|
||||||
id = fd.read(len(RAR_ID))
|
id = fd.read(len(RAR_ID))
|
||||||
if id != RAR_ID:
|
if id != RAR_ID and id != RAR5_ID:
|
||||||
raise NotRarFile("Not a Rar archive: "+self.rarfile)
|
raise NotRarFile("Not a Rar archive: "+self.rarfile)
|
||||||
|
|
||||||
volume = 0 # first vol (.rar) is 0
|
volume = 0 # first vol (.rar) is 0
|
||||||
@@ -1172,8 +1191,7 @@ class RarFile(object):
|
|||||||
if is_filelike(rarfile):
|
if is_filelike(rarfile):
|
||||||
raise ValueError("Cannot use unrar directly on memory buffer")
|
raise ValueError("Cannot use unrar directly on memory buffer")
|
||||||
cmd = [UNRAR_TOOL] + list(OPEN_ARGS)
|
cmd = [UNRAR_TOOL] + list(OPEN_ARGS)
|
||||||
if psw is not None:
|
add_password_arg(cmd, psw)
|
||||||
cmd.append("-p" + psw)
|
|
||||||
cmd.append(rarfile)
|
cmd.append(rarfile)
|
||||||
|
|
||||||
# not giving filename avoids encoding related problems
|
# not giving filename avoids encoding related problems
|
||||||
@@ -1205,10 +1223,7 @@ class RarFile(object):
|
|||||||
|
|
||||||
# pasoword
|
# pasoword
|
||||||
psw = psw or self._password
|
psw = psw or self._password
|
||||||
if psw is not None:
|
add_password_arg(cmd, psw)
|
||||||
cmd.append('-p' + psw)
|
|
||||||
else:
|
|
||||||
cmd.append('-p-')
|
|
||||||
|
|
||||||
# rar file
|
# rar file
|
||||||
cmd.append(self.rarfile)
|
cmd.append(self.rarfile)
|
||||||
@@ -1830,10 +1845,7 @@ def rar_decompress(vers, meth, data, declen=0, flags=0, crc=0, psw=None, salt=No
|
|||||||
tmpf.close()
|
tmpf.close()
|
||||||
|
|
||||||
cmd = [UNRAR_TOOL] + list(OPEN_ARGS)
|
cmd = [UNRAR_TOOL] + list(OPEN_ARGS)
|
||||||
if psw is not None and (flags & RAR_FILE_PASSWORD):
|
add_password_arg(cmd, psw, (flags & RAR_FILE_PASSWORD))
|
||||||
cmd.append("-p" + psw)
|
|
||||||
else:
|
|
||||||
cmd.append("-p-")
|
|
||||||
cmd.append(tmpname)
|
cmd.append(tmpname)
|
||||||
|
|
||||||
p = custom_popen(cmd)
|
p = custom_popen(cmd)
|
||||||
@@ -1902,10 +1914,27 @@ def custom_popen(cmd):
|
|||||||
except OSError:
|
except OSError:
|
||||||
ex = sys.exc_info()[1]
|
ex = sys.exc_info()[1]
|
||||||
if ex.errno == errno.ENOENT:
|
if ex.errno == errno.ENOENT:
|
||||||
raise RarExecError("Unrar not installed? (rarfile.UNRAR_TOOL=%r)" % UNRAR_TOOL)
|
raise RarCannotExec("Unrar not installed? (rarfile.UNRAR_TOOL=%r)" % UNRAR_TOOL)
|
||||||
raise
|
raise
|
||||||
return p
|
return p
|
||||||
|
|
||||||
|
def custom_check(cmd, ignore_retcode=False):
|
||||||
|
"""Run command, collect output, raise error if needed."""
|
||||||
|
p = custom_popen(cmd)
|
||||||
|
out, err = p.communicate()
|
||||||
|
if p.returncode and not ignore_retcode:
|
||||||
|
raise RarExecError("Check-run failed")
|
||||||
|
return out
|
||||||
|
|
||||||
|
def add_password_arg(cmd, psw, required=False):
|
||||||
|
"""Append password switch to commandline."""
|
||||||
|
if UNRAR_TOOL == ALT_TOOL:
|
||||||
|
return
|
||||||
|
if psw is not None:
|
||||||
|
cmd.append('-p' + psw)
|
||||||
|
else:
|
||||||
|
cmd.append('-p-')
|
||||||
|
|
||||||
def check_returncode(p, out):
|
def check_returncode(p, out):
|
||||||
"""Raise exception according to unrar exit code"""
|
"""Raise exception according to unrar exit code"""
|
||||||
|
|
||||||
@@ -1920,6 +1949,8 @@ def check_returncode(p, out):
|
|||||||
RarWarning, RarFatalError, RarCRCError, RarLockedArchiveError,
|
RarWarning, RarFatalError, RarCRCError, RarLockedArchiveError,
|
||||||
RarWriteError, RarOpenError, RarUserError, RarMemoryError,
|
RarWriteError, RarOpenError, RarUserError, RarMemoryError,
|
||||||
RarCreateError, RarNoFilesError] # codes from rar.txt
|
RarCreateError, RarNoFilesError] # codes from rar.txt
|
||||||
|
if UNRAR_TOOL == ALT_TOOL:
|
||||||
|
errmap = [None]
|
||||||
if code > 0 and code < len(errmap):
|
if code > 0 and code < len(errmap):
|
||||||
exc = errmap[code]
|
exc = errmap[code]
|
||||||
elif code == 255:
|
elif code == 255:
|
||||||
@@ -1936,3 +1967,24 @@ def check_returncode(p, out):
|
|||||||
msg = "%s [%d]" % (exc.__doc__, p.returncode)
|
msg = "%s [%d]" % (exc.__doc__, p.returncode)
|
||||||
|
|
||||||
raise exc(msg)
|
raise exc(msg)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Check if unrar works
|
||||||
|
#
|
||||||
|
|
||||||
|
try:
|
||||||
|
# does UNRAR_TOOL work?
|
||||||
|
custom_check([UNRAR_TOOL], True)
|
||||||
|
except RarCannotExec:
|
||||||
|
try:
|
||||||
|
# does ALT_TOOL work?
|
||||||
|
custom_check([ALT_TOOL] + list(ALT_CHECK_ARGS), True)
|
||||||
|
# replace config
|
||||||
|
UNRAR_TOOL = ALT_TOOL
|
||||||
|
OPEN_ARGS = ALT_OPEN_ARGS
|
||||||
|
EXTRACT_ARGS = ALT_EXTRACT_ARGS
|
||||||
|
TEST_ARGS = ALT_TEST_ARGS
|
||||||
|
except RarCannotExec:
|
||||||
|
# no usable tool, only uncompressed archives work
|
||||||
|
pass
|
||||||
|
|
||||||
|
|||||||
139
kcc/shared.py
139
kcc/shared.py
@@ -1,5 +1,5 @@
|
|||||||
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||||
# Copyright (c) 2013-2014 Pawel Jastrzebski <pawelj@vulturis.eu>
|
# Copyright (c) 2013-2015 Pawel Jastrzebski <pawelj@iosphe.re>
|
||||||
#
|
#
|
||||||
# Permission to use, copy, modify, and/or distribute this software for
|
# Permission to use, copy, modify, and/or distribute this software for
|
||||||
# any purpose with or without fee is hereby granted, provided that the
|
# any purpose with or without fee is hereby granted, provided that the
|
||||||
@@ -16,33 +16,62 @@
|
|||||||
# PERFORMANCE OF THIS SOFTWARE.
|
# PERFORMANCE OF THIS SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
__license__ = 'ISC'
|
|
||||||
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
|
|
||||||
__docformat__ = 'restructuredtext en'
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from hashlib import md5
|
from hashlib import md5
|
||||||
|
from html.parser import HTMLParser
|
||||||
|
from distutils.version import StrictVersion
|
||||||
|
from time import sleep
|
||||||
|
from shutil import rmtree, move
|
||||||
|
from tempfile import mkdtemp
|
||||||
|
from zipfile import ZipFile, ZIP_DEFLATED
|
||||||
|
from re import split
|
||||||
|
from traceback import format_tb
|
||||||
|
try:
|
||||||
|
from scandir import walk
|
||||||
|
except ImportError:
|
||||||
|
walk = None
|
||||||
|
|
||||||
|
|
||||||
|
class HTMLStripper(HTMLParser):
|
||||||
|
def __init__(self):
|
||||||
|
HTMLParser.__init__(self)
|
||||||
|
self.reset()
|
||||||
|
self.strict = False
|
||||||
|
self.convert_charrefs = True
|
||||||
|
self.fed = []
|
||||||
|
|
||||||
|
def handle_data(self, d):
|
||||||
|
self.fed.append(d)
|
||||||
|
|
||||||
|
def get_data(self):
|
||||||
|
return ''.join(self.fed)
|
||||||
|
|
||||||
|
def error(self, message):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def getImageFileName(imgfile):
|
def getImageFileName(imgfile):
|
||||||
filename = os.path.splitext(imgfile)
|
name, ext = os.path.splitext(imgfile)
|
||||||
if filename[0].startswith('.') or\
|
ext = ext.lower()
|
||||||
(filename[1].lower() != '.png' and
|
if name.startswith('.') or (ext != '.png' and ext != '.jpg' and ext != '.jpeg' and ext != '.gif'):
|
||||||
filename[1].lower() != '.jpg' and
|
|
||||||
filename[1].lower() != '.gif' and
|
|
||||||
filename[1].lower() != '.tif' and
|
|
||||||
filename[1].lower() != '.tiff' and
|
|
||||||
filename[1].lower() != '.bmp' and
|
|
||||||
filename[1].lower() != '.jpeg'):
|
|
||||||
return None
|
return None
|
||||||
return filename
|
return [name, ext]
|
||||||
|
|
||||||
|
|
||||||
|
def walkSort(dirnames, filenames):
|
||||||
|
convert = lambda text: int(text) if text.isdigit() else text
|
||||||
|
alphanum_key = lambda key: [convert(c) for c in split('([0-9]+)', key)]
|
||||||
|
dirnames.sort(key=lambda name: alphanum_key(name.lower()))
|
||||||
|
filenames.sort(key=lambda name: alphanum_key(name.lower()))
|
||||||
|
return dirnames, filenames
|
||||||
|
|
||||||
|
|
||||||
def walkLevel(some_dir, level=1):
|
def walkLevel(some_dir, level=1):
|
||||||
some_dir = some_dir.rstrip(os.path.sep)
|
some_dir = some_dir.rstrip(os.path.sep)
|
||||||
assert os.path.isdir(some_dir)
|
assert os.path.isdir(some_dir)
|
||||||
num_sep = some_dir.count(os.path.sep)
|
num_sep = some_dir.count(os.path.sep)
|
||||||
for root, dirs, files in os.walk(some_dir):
|
for root, dirs, files in walk(some_dir):
|
||||||
|
dirs, files = walkSort(dirs, files)
|
||||||
yield root, dirs, files
|
yield root, dirs, files
|
||||||
num_sep_this = root.count(os.path.sep)
|
num_sep_this = root.count(os.path.sep)
|
||||||
if num_sep + level <= num_sep_this:
|
if num_sep + level <= num_sep_this:
|
||||||
@@ -58,3 +87,81 @@ def md5Checksum(filePath):
|
|||||||
break
|
break
|
||||||
m.update(data)
|
m.update(data)
|
||||||
return m.hexdigest()
|
return m.hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
def check7ZFile(filePath):
|
||||||
|
with open(filePath, 'rb') as fh:
|
||||||
|
header = fh.read(6)
|
||||||
|
return header == b"7z\xbc\xaf'\x1c"
|
||||||
|
|
||||||
|
|
||||||
|
def saferReplace(old, new):
|
||||||
|
for x in range(5):
|
||||||
|
try:
|
||||||
|
os.replace(old, new)
|
||||||
|
except PermissionError:
|
||||||
|
sleep(5)
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
raise PermissionError
|
||||||
|
|
||||||
|
|
||||||
|
def removeFromZIP(zipfname, *filenames):
|
||||||
|
tempdir = mkdtemp('', 'KCC-')
|
||||||
|
try:
|
||||||
|
tempname = os.path.join(tempdir, 'KCC.zip')
|
||||||
|
with ZipFile(zipfname, 'r') as zipread:
|
||||||
|
with ZipFile(tempname, 'w', compression=ZIP_DEFLATED) as zipwrite:
|
||||||
|
for item in zipread.infolist():
|
||||||
|
if item.filename not in filenames:
|
||||||
|
zipwrite.writestr(item, zipread.read(item.filename))
|
||||||
|
move(tempname, zipfname)
|
||||||
|
finally:
|
||||||
|
rmtree(tempdir)
|
||||||
|
|
||||||
|
|
||||||
|
def sanitizeTrace(traceback):
|
||||||
|
return ''.join(format_tb(traceback))\
|
||||||
|
.replace('C:\\Users\\pawel\\Documents\\Projekty\\KCC\\', '')\
|
||||||
|
.replace('C:\\Python34\\', '')\
|
||||||
|
.replace('C:\\Python34_64\\', '')
|
||||||
|
|
||||||
|
|
||||||
|
def dependencyCheck(level):
|
||||||
|
missing = []
|
||||||
|
if level > 2:
|
||||||
|
try:
|
||||||
|
from PyQt5.QtCore import qVersion as qtVersion
|
||||||
|
if StrictVersion('5.4.0') > StrictVersion(qtVersion()):
|
||||||
|
missing.append('PyQt 5.4.0+')
|
||||||
|
except ImportError:
|
||||||
|
missing.append('PyQt 5.4.0+')
|
||||||
|
if level > 1:
|
||||||
|
try:
|
||||||
|
from psutil import __version__ as psutilVersion
|
||||||
|
if StrictVersion('3.0.0') > StrictVersion(psutilVersion):
|
||||||
|
missing.append('psutil 3.0.0+')
|
||||||
|
except ImportError:
|
||||||
|
missing.append('psutil 3.0.0+')
|
||||||
|
try:
|
||||||
|
from slugify import __version__ as slugifyVersion
|
||||||
|
if StrictVersion('1.1.3') > StrictVersion(slugifyVersion):
|
||||||
|
missing.append('python-slugify 1.1.3+')
|
||||||
|
except ImportError:
|
||||||
|
missing.append('python-slugify 1.1.3+')
|
||||||
|
try:
|
||||||
|
from PIL import PILLOW_VERSION as pillowVersion
|
||||||
|
if StrictVersion('2.8.2') > StrictVersion(pillowVersion):
|
||||||
|
missing.append('Pillow 2.8.2+')
|
||||||
|
except ImportError:
|
||||||
|
missing.append('Pillow 2.8.2+')
|
||||||
|
try:
|
||||||
|
from scandir import __version__ as scandirVersion
|
||||||
|
if StrictVersion('1.1') > StrictVersion(scandirVersion):
|
||||||
|
missing.append('scandir 1.1+')
|
||||||
|
except ImportError:
|
||||||
|
missing.append('scandir 1.1+')
|
||||||
|
if len(missing) > 0:
|
||||||
|
print('ERROR: ' + ', '.join(missing) + ' is not installed!')
|
||||||
|
exit(1)
|
||||||
|
|||||||
BIN
other/7za.exe
Normal file
BIN
other/7za.exe
Normal file
Binary file not shown.
BIN
other/UnRAR.exe
Normal file
BIN
other/UnRAR.exe
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
other/unrar
Executable file
BIN
other/unrar
Executable file
Binary file not shown.
10
setup.json
Normal file
10
setup.json
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"title": "Kindle Comic Converter",
|
||||||
|
"icon": "icons/comic2ebook.icns",
|
||||||
|
"background": "icons/WizardOSX.png",
|
||||||
|
"icon-size": 160,
|
||||||
|
"contents": [
|
||||||
|
{ "x": 180, "y": 300, "type": "file", "path": "dist/Kindle Comic Converter.app" },
|
||||||
|
{ "x": 520, "y": 300, "type": "link", "path": "/Applications" }
|
||||||
|
]
|
||||||
|
}
|
||||||
171
setup.py
171
setup.py
@@ -1,24 +1,31 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
cx_Freeze build script for KCC.
|
pip/py2exe/py2app build script for KCC.
|
||||||
|
|
||||||
Usage (Mac OS X):
|
|
||||||
python setup.py py2app
|
|
||||||
|
|
||||||
Usage (Windows):
|
Usage (Windows):
|
||||||
python setup.py build
|
py -3.4 setup.py py2exe
|
||||||
|
|
||||||
|
Usage (Linux):
|
||||||
|
python3 setup.py make_pyz or python3 setup.py install
|
||||||
|
|
||||||
|
Usage (Mac OS X):
|
||||||
|
python3 setup.py py2app
|
||||||
"""
|
"""
|
||||||
from sys import platform, version_info
|
from sys import platform, version_info, argv
|
||||||
|
from kcc import __version__
|
||||||
if version_info[0] != 3:
|
if version_info[0] != 3:
|
||||||
print('ERROR: This is Python 3 script!')
|
print('ERROR: This is Python 3 script!')
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
NAME = "KindleComicConverter"
|
NAME = 'KindleComicConverter'
|
||||||
VERSION = "4.0.1"
|
VERSION = __version__
|
||||||
MAIN = "kcc.py"
|
MAIN = 'kcc.py'
|
||||||
|
extra_options = {}
|
||||||
|
|
||||||
if platform == "darwin":
|
if platform == 'darwin':
|
||||||
from setuptools import setup
|
from setuptools import setup
|
||||||
|
from os import chmod, makedirs, system
|
||||||
|
from shutil import copyfile
|
||||||
extra_options = dict(
|
extra_options = dict(
|
||||||
setup_requires=['py2app'],
|
setup_requires=['py2app'],
|
||||||
app=[MAIN],
|
app=[MAIN],
|
||||||
@@ -26,17 +33,14 @@ if platform == "darwin":
|
|||||||
py2app=dict(
|
py2app=dict(
|
||||||
argv_emulation=True,
|
argv_emulation=True,
|
||||||
iconfile='icons/comic2ebook.icns',
|
iconfile='icons/comic2ebook.icns',
|
||||||
includes=['PIL', 'sip', 'PyQt5', 'PyQt5.QtCore', 'PyQt5.QtGui', 'PyQt5.QtNetwork', 'PyQt5.QtWidgets',
|
includes=['sip'],
|
||||||
'PyQt5.QtPrintSupport'],
|
|
||||||
resources=['LICENSE.txt', 'other/qt.conf', 'other/Additional-LICENSE.txt', 'other/unrar', 'other/7za'],
|
resources=['LICENSE.txt', 'other/qt.conf', 'other/Additional-LICENSE.txt', 'other/unrar', 'other/7za'],
|
||||||
plist=dict(
|
plist=dict(
|
||||||
CFBundleName=NAME,
|
CFBundleName='Kindle Comic Converter',
|
||||||
CFBundleShortVersionString=VERSION,
|
CFBundleShortVersionString=VERSION,
|
||||||
CFBundleGetInfoString=NAME + " " + VERSION +
|
CFBundleGetInfoString=NAME + ' ' + VERSION +
|
||||||
", written 2012-2014 by Ciro Mattia Gonano and Pawel Jastrzebski",
|
', written 2012-2015 by Ciro Mattia Gonano and Pawel Jastrzebski',
|
||||||
CFBundleExecutable=NAME,
|
CFBundleExecutable=NAME,
|
||||||
CFBundleIdentifier='com.github.ciromattia.kcc',
|
|
||||||
CFBundleSignature='dplt',
|
|
||||||
CFBundleDocumentTypes=[
|
CFBundleDocumentTypes=[
|
||||||
dict(
|
dict(
|
||||||
CFBundleTypeExtensions=['cbz', 'cbr', 'cb7', 'zip', 'rar', '7z', 'pdf'],
|
CFBundleTypeExtensions=['cbz', 'cbr', 'cb7', 'zip', 'rar', '7z', 'pdf'],
|
||||||
@@ -47,60 +51,111 @@ if platform == "darwin":
|
|||||||
],
|
],
|
||||||
LSMinimumSystemVersion='10.8.0',
|
LSMinimumSystemVersion='10.8.0',
|
||||||
LSEnvironment=dict(
|
LSEnvironment=dict(
|
||||||
PATH='/usr/local/bin:/usr/bin:/bin'
|
PATH='./../Resources:/usr/local/bin:/usr/bin:/bin'
|
||||||
),
|
),
|
||||||
NSHumanReadableCopyright='ISC License (ISCL)'
|
NSHumanReadableCopyright='ISC License (ISCL)'
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
elif platform == "win32":
|
elif platform == 'win32':
|
||||||
import platform as arch
|
import py2exe
|
||||||
from cx_Freeze import setup, Executable
|
from platform import architecture
|
||||||
if arch.architecture()[0] == '64bit':
|
from distutils.core import setup
|
||||||
library = 'libEGL64.dll'
|
if architecture()[0] == '64bit':
|
||||||
|
suffix = '_64'
|
||||||
else:
|
else:
|
||||||
library = 'libEGL32.dll'
|
suffix = ''
|
||||||
base = "Win32GUI"
|
additional_files = [('platforms', ['C:\Python34' + suffix +
|
||||||
|
'\Lib\site-packages\PyQt5\plugins\platforms\qwindows.dll']),
|
||||||
|
('', ['LICENSE.txt',
|
||||||
|
'other\\7za.exe',
|
||||||
|
'other\\UnRAR.exe',
|
||||||
|
'other\\Additional-LICENSE.txt',
|
||||||
|
'C:\Python34' + suffix + '\Lib\site-packages\PyQt5\libGLESv2.dll',
|
||||||
|
'C:\Python34' + suffix + '\Lib\site-packages\PyQt5\libEGL.dll'])]
|
||||||
extra_options = dict(
|
extra_options = dict(
|
||||||
options={"build_exe": {"optimize": 2,
|
options={'py2exe': {'bundle_files': 1,
|
||||||
"include_files": ['LICENSE.txt',
|
'dist_dir': 'dist' + suffix,
|
||||||
['other/UnRAR.exe', 'UnRAR.exe'],
|
'compressed': True,
|
||||||
['other/7za.exe', '7za.exe'],
|
'includes': ['sip'],
|
||||||
['other/Additional-LICENSE.txt', 'Additional-LICENSE.txt'],
|
'excludes': ['tkinter'],
|
||||||
['other/' + library, 'libEGL.dll']
|
'optimize': 2}},
|
||||||
],
|
windows=[{'script': MAIN,
|
||||||
"copy_dependent_files": True,
|
'dest_base': 'KCC',
|
||||||
"create_shared_zip": False,
|
'version': VERSION,
|
||||||
"append_script_to_exe": True,
|
'copyright': 'Ciro Mattia Gonano, Pawel Jastrzebski © 2012-2015',
|
||||||
"replace_paths": '*=',
|
'legal_copyright': 'ISC License (ISCL)',
|
||||||
"excludes": ['tkinter']}},
|
'product_version': VERSION,
|
||||||
executables=[Executable(MAIN,
|
'product_name': 'Kindle Comic Converter',
|
||||||
base=base,
|
'file_description': 'Kindle Comic Converter',
|
||||||
targetName="KCC.exe",
|
'icon_resources': [(1, 'icons\comic2ebook.ico')]}],
|
||||||
icon="icons/comic2ebook.ico",
|
zipfile=None,
|
||||||
compress=False)])
|
data_files=additional_files)
|
||||||
else:
|
else:
|
||||||
print('Please use setup.sh to build Linux package.')
|
if len(argv) > 1 and argv[1] == 'make_pyz':
|
||||||
exit()
|
from os import system
|
||||||
|
script = '''
|
||||||
|
cp kcc.py __main__.py
|
||||||
|
zip kcc.zip __main__.py kcc/*.py
|
||||||
|
echo "#!/usr/bin/env python3" > kcc-bin
|
||||||
|
cat kcc.zip >> kcc-bin
|
||||||
|
chmod +x kcc-bin
|
||||||
|
|
||||||
|
cp kcc-c2e.py __main__.py
|
||||||
|
zip kcc-c2e.zip __main__.py kcc/*.py
|
||||||
|
echo "#!/usr/bin/env python3" > kcc-c2e-bin
|
||||||
|
cat kcc-c2e.zip >> kcc-c2e-bin
|
||||||
|
chmod +x kcc-c2e-bin
|
||||||
|
|
||||||
|
cp kcc-c2p.py __main__.py
|
||||||
|
zip kcc-c2p.zip __main__.py kcc/*.py
|
||||||
|
echo "#!/usr/bin/env python3" > kcc-c2p-bin
|
||||||
|
cat kcc-c2p.zip >> kcc-c2p-bin
|
||||||
|
chmod +x kcc-c2p-bin
|
||||||
|
|
||||||
|
tar --xform s:^.*/:: --xform s/LICENSE.txt/LICENSE/ --xform s/kcc-bin/kcc/ --xform s/kcc-c2p-bin/kcc-c2p/ \
|
||||||
|
--xform s/kcc-c2e-bin/kcc-c2e/ --xform s/comic2ebook/kcc/ -czf KindleComicConverter_linux_'''\
|
||||||
|
+ VERSION + '''.tar.gz kcc-bin kcc-c2e-bin kcc-c2p-bin LICENSE.txt README.md icons/comic2ebook.png
|
||||||
|
rm __main__.py kcc.zip kcc-c2e.zip kcc-c2p.zip kcc-bin kcc-c2e-bin kcc-c2p-bin
|
||||||
|
'''
|
||||||
|
system("bash -c '%s'" % script)
|
||||||
|
exit(0)
|
||||||
|
else:
|
||||||
|
from setuptools import setup
|
||||||
|
from os import makedirs
|
||||||
|
from shutil import copyfile
|
||||||
|
makedirs('build/_scripts/', exist_ok=True)
|
||||||
|
copyfile('kcc.py', 'build/_scripts/kcc')
|
||||||
|
copyfile('kcc-c2e.py', 'build/_scripts/kcc-c2e')
|
||||||
|
copyfile('kcc-c2p.py', 'build/_scripts/kcc-c2p')
|
||||||
|
extra_options = dict(
|
||||||
|
scripts=['build/_scripts/kcc', 'build/_scripts/kcc-c2e', 'build/_scripts/kcc-c2p'],
|
||||||
|
packages=['kcc'],
|
||||||
|
install_requires=[
|
||||||
|
'Pillow>=2.8.2',
|
||||||
|
'psutil>=3.0.0',
|
||||||
|
'python-slugify>=1.1.3',
|
||||||
|
'scandir>=1.1.0',
|
||||||
|
],
|
||||||
|
zip_safe=False,
|
||||||
|
)
|
||||||
|
|
||||||
#noinspection PyUnboundLocalVariable
|
|
||||||
setup(
|
setup(
|
||||||
name=NAME,
|
name=NAME,
|
||||||
version=VERSION,
|
version=VERSION,
|
||||||
author="Ciro Mattia Gonano, Pawel Jastrzebski",
|
author='Ciro Mattia Gonano, Pawel Jastrzebski',
|
||||||
author_email="ciromattia@gmail.com, pawelj@vulturis.eu",
|
author_email='ciromattia@gmail.com, pawelj@iosphe.re',
|
||||||
description="A tool to convert comics (CBR/CBZ/PDFs/image folders) to MOBI.",
|
description='Comic and manga converter for E-Book readers.',
|
||||||
license="ISC License (ISCL)",
|
license='ISC License (ISCL)',
|
||||||
keywords="kindle comic mobipocket mobi cbz cbr manga",
|
keywords='kindle comic mobipocket mobi cbz cbr manga',
|
||||||
url="http://github.com/ciromattia/kcc",
|
url='http://github.com/ciromattia/kcc',
|
||||||
**extra_options
|
**extra_options
|
||||||
)
|
)
|
||||||
|
|
||||||
if platform == "darwin":
|
if platform == 'darwin':
|
||||||
from os import chmod, makedirs
|
makedirs('dist/Kindle Comic Converter.app/Contents/PlugIns/platforms', exist_ok=True)
|
||||||
from shutil import copyfile
|
copyfile('other/libqcocoa.dylib', 'dist/Kindle Comic Converter.app/Contents/PlugIns/platforms/libqcocoa.dylib')
|
||||||
makedirs('dist/' + NAME + '.app/Contents/PlugIns/platforms')
|
chmod('dist/Kindle Comic Converter.app/Contents/Resources/unrar', 0o777)
|
||||||
copyfile('other/libqcocoa.dylib', 'dist/' + NAME + '.app/Contents/PlugIns/platforms/libqcocoa.dylib')
|
chmod('dist/Kindle Comic Converter.app/Contents/Resources/7za', 0o777)
|
||||||
chmod('dist/' + NAME + '.app/Contents/Resources/unrar', 0o777)
|
system('appdmg setup.json dist/KindleComicConverter_osx_' + VERSION + '.dmg')
|
||||||
chmod('dist/' + NAME + '.app/Contents/Resources/7za', 0o777)
|
|
||||||
|
|||||||
25
setup.sh
25
setup.sh
@@ -1,25 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# Linux Python package build script
|
|
||||||
|
|
||||||
VERSION="4.0.1"
|
|
||||||
|
|
||||||
cp kcc.py __main__.py
|
|
||||||
zip kcc.zip __main__.py kcc/*.py
|
|
||||||
echo "#!/usr/bin/env python3" > kcc-bin
|
|
||||||
cat kcc.zip >> kcc-bin
|
|
||||||
chmod +x kcc-bin
|
|
||||||
|
|
||||||
cp kcc-c2e.py __main__.py
|
|
||||||
zip kcc-c2e.zip __main__.py kcc/*.py
|
|
||||||
echo "#!/usr/bin/env python3" > kcc-c2e-bin
|
|
||||||
cat kcc-c2e.zip >> kcc-c2e-bin
|
|
||||||
chmod +x kcc-c2e-bin
|
|
||||||
|
|
||||||
cp kcc-c2p.py __main__.py
|
|
||||||
zip kcc-c2p.zip __main__.py kcc/*.py
|
|
||||||
echo "#!/usr/bin/env python3" > kcc-c2p-bin
|
|
||||||
cat kcc-c2p.zip >> kcc-c2p-bin
|
|
||||||
chmod +x kcc-c2p-bin
|
|
||||||
|
|
||||||
tar --xform s:^.*/:: --xform s/kcc-bin/kcc/ --xform s/kcc-c2p-bin/kcc-c2p/ --xform s/kcc-c2e-bin/kcc-c2e/ --xform s/comic2ebook/kcc/ -czf KindleComicConverter_linux_$VERSION.tar.gz kcc-bin kcc-c2e-bin kcc-c2p-bin LICENSE.txt icons/comic2ebook.png
|
|
||||||
rm __main__.py kcc.zip kcc-c2e.zip kcc-c2p.zip kcc-bin kcc-c2e-bin kcc-c2p-bin
|
|
||||||
Reference in New Issue
Block a user