1
0
mirror of https://github.com/ciromattia/kcc synced 2026-04-15 13:38:46 +00:00

Compare commits

...

191 Commits
3.5 ... 4.1

Author SHA1 Message Date
Paweł Jastrzębski
5450502c2a Updated README 2014-06-08 07:52:19 +02:00
Paweł Jastrzębski
c976b06413 Make sure that KindleGen have execute permissions 2014-06-05 07:37:32 +02:00
Paweł Jastrzębski
b6facda95b Updated OS X libraries 2014-06-04 10:00:45 +02:00
Paweł Jastrzębski
3f608eb602 Version bump 2014-06-03 19:26:24 +02:00
Paweł Jastrzębski
104cd04994 Fixed title parsing 2014-06-02 20:31:48 +02:00
Paweł Jastrzębski
b323204628 Added additional cover processing 2014-06-02 19:55:20 +02:00
Paweł Jastrzębski
56195d301d Tweaked merge 2014-05-29 22:01:21 +02:00
Paweł Jastrzębski
287723ca6f Updated UnRAR 2014-05-29 21:56:14 +02:00
Paweł Jastrzębski
90490149c7 Merge branch 'theaquamarine-kindlegen' 2014-05-29 18:54:38 +02:00
blue
2210f484df Use makeBook to create book from GUI
Call comic2ebook.makeBook() rather than comic2ebook.main()
2014-05-29 18:28:38 +02:00
blue
d5502e85b0 Use makeParser() for options in KCC_gui
KCC_gui now uses comic2ebook.makeParser() and setting global variable
in comic2ebook to handle options for ebook creation.
2014-05-29 18:28:33 +02:00
blue
59b26cfc8b Split comic2ebook.py main in two again
Now has main() which initialises the program and makeParser() which
sets up the option parser.
2014-05-29 18:28:27 +02:00
blue
a722e5fa49 Split comic2ebook.py main in two
Now has main() which initialises program and makeBook which does the
actual work.
2014-05-29 18:28:14 +02:00
Paweł Jastrzębski
fce3072dca Updated to Python 3.4 and PyQt 5.3 (close #94) 2014-05-29 18:23:28 +02:00
Paweł Jastrzębski
f53cdf9cd7 Implemented new DualMetaFix version 2014-05-28 06:57:37 +02:00
Paweł Jastrzębski
de74318c69 Replaced cx_Freeze with py2exe 2014-05-25 11:08:28 +02:00
Paweł Jastrzębski
b137e69510 Dependency tweak 2014-05-25 07:29:03 +02:00
Paweł Jastrzębski
888663fa4c Miscellaneous processing tweaks 2014-05-18 09:09:38 +02:00
Paweł Jastrzębski
8a2ba96ac5 Tiny tweaks for Linux 2014-05-17 19:12:54 +02:00
Paweł Jastrzębski
cb6b0e0a7b Updated tooltips 2014-05-15 19:38:34 +02:00
Paweł Jastrzębski
49d2a7fbab Changed domain 2014-05-14 20:23:12 +02:00
Paweł Jastrzębski
3d84b27d58 Fixed tiny bugs 2014-05-05 18:32:46 +02:00
Paweł Jastrzębski
e98a23d0c0 Updated README 2014-05-05 12:08:15 +02:00
Paweł Jastrzębski
7f80dacea8 Finished implementation of DualMetaFix 2014-05-05 10:42:16 +02:00
Paweł Jastrzębski
6efb3dcef3 Preliminary implementation of DualMetaFix 2014-05-04 21:45:03 +02:00
Paweł Jastrzębski
942a828b7e Revert "Changed output extension to AZW3"
This reverts commit 64b199ef74.
2014-05-04 21:37:26 +02:00
Paweł Jastrzębski
df5ee1badf Overhauled dependency check 2014-04-30 20:38:23 +02:00
Paweł Jastrzębski
e3ab28642d Re-enabled tray icon on Linux 2014-04-30 20:11:25 +02:00
Ciro Mattia Gonano
a1831c45d5 Revert to ISC License 2014-04-30 03:00:03 +02:00
Paweł Jastrzębski
52bea9957a Updated README 2014-04-29 13:12:27 +02:00
Paweł Jastrzębski
a71339ec34 Changed license to GNU General Public License v3 (GPL-3) 2014-04-29 13:00:32 +02:00
Paweł Jastrzębski
c5f09c44b8 Bumped a little MOBI file size limit 2014-04-24 22:11:37 +02:00
Paweł Jastrzębski
64b199ef74 Changed output extension to AZW3
This is cosmetic change. All profiles for new Kindle models already created KF8/AZW3 files but used generic extension.
2014-04-21 08:39:16 +02:00
Paweł Jastrzębski
8dd0b0e694 Tweaked whitespace cropping + other small tweaks 2014-04-18 11:47:51 +02:00
Paweł Jastrzębski
181a2e8ab4 GUI tweak: Fixed rounding 2014-04-17 18:46:25 +02:00
Paweł Jastrzębski
3fdff845b7 Tiny code cleanup 2014-04-10 13:42:29 +02:00
Paweł Jastrzębski
2ee5dc310b Fixed No optimization mode (close #88) 2014-04-08 13:10:34 +02:00
Paweł Jastrzębski
f32e9560b5 Fixed Linux/OSX crash 2014-03-26 10:23:20 +01:00
Paweł Jastrzębski
621827c1c2 Performance tweaks for Windows 2014-03-22 11:16:25 +01:00
Paweł Jastrzębski
dc312f36c2 Updated OSX libs 2014-03-19 10:14:56 +01:00
Paweł Jastrzębski
4573ff6ec2 README update 2014-03-19 09:25:45 +01:00
Paweł Jastrzębski
d77498405b Updated to psutil 2.0 2014-03-13 21:58:15 +01:00
Paweł Jastrzębski
e491fca445 Version bump + README update 2014-03-13 21:26:26 +01:00
Paweł Jastrzębski
d22ee1a488 Tweaked HQ mode 2014-02-18 12:56:27 +01:00
Paweł Jastrzębski
7ebcccd8a2 Replaced os.rename with atomic os.replace
This should eliminate last problems with file locks on Windows
2014-02-13 18:35:17 +01:00
Paweł Jastrzębski
9a691c3c63 Windows: Fixed sys.stdout and sys.stderr 2014-02-06 11:45:37 +01:00
Paweł Jastrzębski
2b04a0298e Windows: Fixed abnormalities with version check
CX_Freeze working very, very strange with Python 3.3.3
2014-02-02 08:56:50 +01:00
Paweł Jastrzębski
9867f63d00 Version bump + README update 2014-02-01 19:13:03 +01:00
Paweł Jastrzębski
866f8898be Windows: Hopefully fixed all problems with file locks 2014-02-01 18:11:16 +01:00
Paweł Jastrzębski
9f2ac7a176 Windows: Truncated tracebacks 2014-02-01 16:14:23 +01:00
Paweł Jastrzębski
634213f380 WebToons: Improved performance of directory merger 2014-02-01 14:09:25 +01:00
Paweł Jastrzębski
ce82b5ec66 Tweaked margin color detection 2014-01-31 11:15:03 +01:00
Moshev
062b239f2f Fixed errors in image.py introduced from the different handling of division between python 2 and 3 2014-01-29 08:14:00 +01:00
Paweł Jastrzębski
f5f5c05f1e Merge pull request #82 from ciromattia/python3
Python3 + Qt5
2014-01-28 03:11:33 -08:00
Paweł Jastrzębski
a229ba44bf README update 2014-01-28 12:10:33 +01:00
Paweł Jastrzębski
27e5cc3b00 Removed redundant output 2014-01-27 20:51:13 +01:00
Paweł Jastrzębski
63d752280a Margin color detection tweaks 2014-01-26 10:25:26 +01:00
Paweł Jastrzębski
60b7a90589 Improved Panel View logic 2014-01-25 17:46:10 +01:00
Paweł Jastrzębski
63413fa4ba GUI: Link to important tips appear now 5 times 2014-01-25 10:57:18 +01:00
Paweł Jastrzębski
3a536df626 Code cleanup 2014-01-25 10:42:38 +01:00
Paweł Jastrzębski
35bc4a2987 Added MD5 check to update mechanism 2014-01-24 22:54:16 +01:00
Paweł Jastrzębski
3bb8cc7778 Great Index: Using MD5 checksums instead file paths.
Performance impact is negligible, it simplify the code and is much more error resistant.
2014-01-24 22:43:24 +01:00
Paweł Jastrzębski
bd53c6108d Great Index: Slugification fix 2014-01-24 09:08:39 +01:00
Paweł Jastrzębski
3d8bcb4020 Image flags are not part of filename anymore 2014-01-23 18:06:14 +01:00
Paweł Jastrzębski
162c146bed Windows: Fixed possible problems with file locks
OSX: Tweaked last fix
2014-01-23 11:23:58 +01:00
Paweł Jastrzębski
e4750fc965 OSX: Fixed 7zip parsing 2014-01-22 21:02:06 +01:00
Paweł Jastrzębski
ebe7d910de Reverting setup changes 2014-01-22 17:43:19 +01:00
Paweł Jastrzębski
aa96381eb5 Added experimental Linux setup 2014-01-22 16:47:55 +01:00
Paweł Jastrzębski
a2b9b5aa8b Linux/OSX: Drag&Drop fix 2014-01-21 22:02:15 +01:00
Paweł Jastrzębski
1e5bfc9f66 OSX: Fixed file association (close #65) 2014-01-21 18:09:22 +01:00
Paweł Jastrzębski
25a68ebdea Reformated tooltips 2014-01-21 10:57:54 +01:00
Paweł Jastrzębski
786d2a9e1f Added option to select output directory 2014-01-20 22:26:50 +01:00
Paweł Jastrzębski
4133cd21ba Linux: Completly disabled QSystemTrayIcon
Not showing tray was not enought. Even creating object cause instability.
2014-01-20 21:26:18 +01:00
Paweł Jastrzębski
237ef728e1 Hotfixed cx_freeze packing 2014-01-20 12:07:26 +01:00
Paweł Jastrzębski
991bf5d4a9 Miscellaneous tweaks 2014-01-20 11:58:15 +01:00
Paweł Jastrzębski
aa8b78b4e4 Autoupdater for Windows (#68) 2014-01-20 11:16:25 +01:00
Paweł Jastrzębski
c2e6a0b791 README update 2014-01-19 10:53:00 +01:00
Paweł Jastrzębski
42cf9e099f Updated Linux installer 2014-01-18 12:24:16 +01:00
Paweł Jastrzębski
d99064596a Detect Python 2 + README update 2014-01-18 12:15:45 +01:00
Paweł Jastrzębski
b1e7a88353 Removing QFileDialog hack
Now when KCC support drag&drop we can return to native dialog.
2014-01-18 11:14:14 +01:00
Paweł Jastrzębski
f8610e1cd7 Linux: Disabling systray icon 2014-01-18 10:20:43 +01:00
Paweł Jastrzębski
562dad02fa Miscellaneous GUI tweaks 2014-01-18 09:51:17 +01:00
Paweł Jastrzębski
66b867c1ca Various multi-os tweaks 2014-01-17 19:37:35 +01:00
Paweł Jastrzębski
b46ada9596 Drag & drop for OSX and Linux 2014-01-17 16:19:54 +01:00
Paweł Jastrzębski
aaa2de81fc Updated Inno Setup 2014-01-17 14:37:58 +01:00
Paweł Jastrzębski
b0c6315fee Updated Windows setup + OSX fix 2014-01-17 12:34:05 +01:00
Paweł Jastrzębski
509d78c0a6 Updated OSX setup 2014-01-17 12:25:20 +01:00
Paweł Jastrzębski
65ef77bace Improved NCX creation (close #79) 2014-01-17 09:31:51 +01:00
Paweł Jastrzębski
170064853c Added drag & drop support 2014-01-16 22:11:06 +01:00
Paweł Jastrzębski
c7e9d883fa Manga mode is now always available (close #78) 2014-01-16 19:17:49 +01:00
Paweł Jastrzębski
a8521dbc9a Fixed multi-instance lock 2014-01-16 18:49:51 +01:00
Paweł Jastrzębski
0f44629273 Dropping unnecessary debug 2014-01-16 13:56:37 +01:00
Paweł Jastrzębski
f12361e7cf kindlesplit: Python3 update 2014-01-16 13:37:36 +01:00
Paweł Jastrzębski
450076e6e8 pdfjpgextract: Python3 update 2014-01-16 12:48:04 +01:00
Paweł Jastrzębski
6d445ae151 Fully implemented new slugify library 2014-01-16 12:34:36 +01:00
Paweł Jastrzębski
921511dcf2 Full UTF-8 awareness (close #74)
Tested only on Windows. But he had the biggest problems with it.
2014-01-16 11:40:49 +01:00
Paweł Jastrzębski
d76a624a82 Bucket #3 2014-01-16 08:48:29 +01:00
Paweł Jastrzębski
cf3df581e1 Moved dependiences check out of module 2014-01-15 14:58:45 +01:00
Paweł Jastrzębski
87009f27a6 Preliminary QT5 update 2014-01-15 14:09:40 +01:00
Paweł Jastrzębski
cccbd36463 And one more bucket... 2014-01-15 11:32:29 +01:00
Paweł Jastrzębski
19b438844d Bucket of various tweaks 2014-01-15 10:24:31 +01:00
Paweł Jastrzębski
878e92b527 Added proper startup scripts
Hacks that allow standalone startup of script inside module are messy.
2014-01-15 10:23:44 +01:00
Paweł Jastrzębski
116dce09fd Updated rarfile 2014-01-15 10:00:05 +01:00
Paweł Jastrzębski
3af30faee9 Merge branch 'master' into python3 2014-01-15 09:33:35 +01:00
Paweł Jastrzębski
cf0b6b3484 README update + Version bump 2014-01-14 15:57:52 +01:00
Paweł Jastrzębski
96a8c1d354 Fixed problems with HQ mode (close #77) 2014-01-14 15:54:08 +01:00
Paweł Jastrzębski
20712b6c42 README update + Version bump 2014-01-13 23:20:55 +01:00
Paweł Jastrzębski
84d836bf0e Temporary disabling HQ output for Kobo 2014-01-13 23:18:18 +01:00
Paweł Jastrzębski
d944d6385e Updated VCRedist packages 2014-01-13 14:28:37 +01:00
Paweł Jastrzębski
a38013eabc README update + Version bump 2014-01-13 14:03:43 +01:00
Paweł Jastrzębski
def9e42a61 Yet another Last™ update of margin color detection algorithm 2014-01-11 16:31:49 +01:00
Paweł Jastrzębski
34aaeab8b1 Fixed GUI bug 2014-01-07 17:52:51 +01:00
Paweł Jastrzębski
eaff6cc633 Replaced shutil.make_archive 2014-01-07 17:33:47 +01:00
Paweł Jastrzębski
54f48d2156 Fixed stretching images smaller than device screen 2014-01-07 13:27:36 +01:00
Paweł Jastrzębski
42d845cf07 Image resize fix 2014-01-05 17:09:32 +01:00
Paweł Jastrzębski
e5e53d3aa7 Fixed GUI logic 2014-01-05 13:55:42 +01:00
Paweł Jastrzębski
f952634971 Refactored detection of corrupted files 2014-01-05 13:46:08 +01:00
Paweł Jastrzębski
19ff6a51cc WebToon splitter improvements 2014-01-05 13:41:53 +01:00
Paweł Jastrzębski
8fbe558f65 Updated to Pillow 2.3.0 2014-01-05 12:13:38 +01:00
Paweł Jastrzębski
6bdb0ab942 Panel View improvements 2013-12-30 18:39:53 +01:00
Paweł Jastrzębski
7656a85708 Tweaked KindleGen warning 2013-12-29 17:13:17 +01:00
Paweł Jastrzębski
d016bade8e Bundling VCRedist with Windows installer 2013-12-29 10:01:17 +01:00
Paweł Jastrzębski
3cc99c6221 Margin autodetection improvements 2013-12-28 12:08:33 +01:00
Paweł Jastrzębski
93f5d105cf Updated README 2013-12-28 11:04:01 +01:00
Paweł Jastrzębski
c1c44bdf88 Reverting output extension changes 2013-12-28 10:19:43 +01:00
Paweł Jastrzębski
72132ea908 GUI: Tweaked profile logic 2013-12-28 09:06:10 +01:00
Paweł Jastrzębski
29f901f92a Fixed PDF queue (close #73) 2013-12-28 08:30:37 +01:00
Paweł Jastrzębski
22b7258aa3 GUI: Refactored profile logic 2013-12-27 14:42:22 +01:00
Paweł Jastrzębski
c0f788bd67 Added preliminary support for Kobo devices 2013-12-27 09:51:15 +01:00
Paweł Jastrzębski
8f10e93c08 Fixed KindleGen error handling 2013-12-24 13:47:06 +01:00
Paweł Jastrzębski
4a473e3716 Changed output extension 2013-12-20 09:22:15 +01:00
Ciro Mattia Gonano
89d31cb8e5 Merge master into python3 2013-12-16 22:37:37 +01:00
Paweł Jastrzębski
80b65b12b7 Updated tooltips 2013-12-13 19:22:52 +01:00
Paweł Jastrzębski
e835502837 Version Bump 2013-12-07 20:08:20 +01:00
Paweł Jastrzębski
5bcdc78725 Fixed Panel View bugs 2013-12-07 14:50:37 +01:00
Paweł Jastrzębski
acb4dfad8f Fixex PNG hotfix 2013-12-07 09:52:20 +01:00
Paweł Jastrzębski
7f5de29174 Version Bump 2013-12-06 23:33:04 +01:00
Paweł Jastrzębski
11007402cd Fixed PNG output (sigh!) 2013-12-06 23:27:58 +01:00
Paweł Jastrzębski
0cf92fc48f Fixed psutil detection 2013-12-06 17:58:39 +01:00
Paweł Jastrzębski
953942ca00 Fixed tray icon owner 2013-12-06 17:42:11 +01:00
Paweł Jastrzębski
c46ca8b507 Updated README + Minor tweaks 2013-12-06 17:18:20 +01:00
Paweł Jastrzębski
48d3bee225 Upscaling is now default on Kindle Fire HD/HDX models 2013-12-05 19:49:29 +01:00
Paweł Jastrzębski
3b0e5cc309 Panel View support overhaul - Round 2 2013-12-05 15:41:47 +01:00
Paweł Jastrzębski
e5be31f9d5 TrayIcon: Clicking it now properly unminimize window 2013-12-04 19:04:54 +01:00
Paweł Jastrzębski
17ea85c31f Overhauled Panel View support 2013-12-04 18:32:32 +01:00
Paweł Jastrzębski
572e1422bf Gamma auto mode is now even more automatic 2013-12-04 18:30:19 +01:00
Ciro Mattia Gonano
af263073b5 Update README.md 2013-12-04 11:42:45 +01:00
Ciro Mattia Gonano
7facf2d620 Re-add text link for bitcoin 2013-12-04 11:42:26 +01:00
Ciro Mattia Gonano
eef3ff434b Added BountySource link and reformatted Donations section 2013-12-04 11:08:04 +01:00
Ciro Mattia Gonano
fa94e18a6a Merge branch 'master' into python3 2013-12-04 10:15:25 +01:00
Ciro Mattia Gonano
c680cfd5c5 Update README.md 2013-11-27 12:40:01 +01:00
Paweł Jastrzębski
3e8469611d Updated README 2013-11-25 10:41:30 +01:00
Paweł Jastrzębski
39ab475156 Updated README 2013-11-25 10:38:20 +01:00
Ciro Mattia Gonano
636de67a17 Update README.md 2013-11-25 10:14:56 +01:00
Ciro Mattia Gonano
d80c18f652 Add OS X 10.7 build download link 2013-11-25 10:14:23 +01:00
Ciro Mattia Gonano
9f68e009f1 Merge branch 'master' into python3 2013-11-19 12:49:58 +01:00
Paweł Jastrzębski
557bd2bbbf Added separate resolution for Kindle DX/DXG CBZ output (close #71) 2013-11-19 08:46:13 +01:00
Ciro Mattia Gonano
d33c53b691 Version 4.0 - first draft for Python3 conversion 2013-11-14 15:49:46 +01:00
Paweł Jastrzębski
ddd223c2ec Code cleanup 2013-11-13 11:27:26 +01:00
Paweł Jastrzębski
50f5b600b1 OS specific tweaks to status bar style 2013-11-12 14:46:32 +01:00
Paweł Jastrzębski
d94df8390a Added status bar with links 2013-11-12 14:32:38 +01:00
Paweł Jastrzębski
8b33331929 Disabled systray icon on OSX (close #70) 2013-11-12 13:18:27 +01:00
Paweł Jastrzębski
86a9dde1eb Added simple tray icon (close #69) 2013-11-12 12:13:57 +01:00
Ciro Mattia Gonano
33dec77063 Merge remote-tracking branch 'origin/master' 2013-11-11 11:52:04 +01:00
Ciro Mattia Gonano
fe06e2fa19 Version bump 2013-11-11 11:51:46 +01:00
Paweł Jastrzębski
7b5e3eaafd Updated README 2013-11-11 11:30:00 +01:00
Paweł Jastrzębski
0a30f1ffb9 Implemented OSX PATH change to Windows code too + minor tweaks 2013-11-09 20:09:34 +01:00
Paweł Jastrzębski
8687604d26 Tweak for Windows development environment 2013-11-08 18:19:58 +01:00
Ciro Mattia Gonano
0a9fd6c439 Merge branch 'master' of github.com:ciromattia/kcc 2013-11-08 17:21:42 +01:00
Paweł Jastrzębski
c95a9395de Optimization of ProgressThread 2013-11-08 17:13:41 +01:00
Paweł Jastrzębski
77066d7a9f Optimization of ProgressThread 2013-11-08 17:06:06 +01:00
Paweł Jastrzębski
c8e5b7de9a Implemented new method to detect border color in non-webtoon comics 2013-11-08 16:55:43 +01:00
Ciro Mattia Gonano
3e11a88a7c Bundle 7za and unrar for OSX too. 2013-11-08 15:32:22 +01:00
Paweł Jastrzębski
a7e4968836 GUI tweaks 2013-11-08 15:11:33 +01:00
Paweł Jastrzębski
6d9e2d3c03 Added Linux build script 2013-11-07 22:53:28 +01:00
Paweł Jastrzębski
0789e7a353 Updated README 2013-11-07 13:53:37 +01:00
Ciro Mattia Gonano
ff97a85552 KCC available from 10.6+ 2013-11-07 12:57:39 +01:00
Ciro Mattia Gonano
33cfd92cef Remove 10.8 limit 2013-11-07 12:14:03 +01:00
Paweł Jastrzębski
58513ef59f Updated Inno Setup script 2013-11-07 07:58:03 +01:00
Paweł Jastrzębski
6056e3e767 Updated OSX setup 2013-11-06 18:44:14 +01:00
Paweł Jastrzębski
1b1ed7c4ab Improved error messages about missing dependencies 2013-11-06 13:49:12 +01:00
Paweł Jastrzębski
5b44e4bddd Moved to psutil Popen 2013-11-06 11:41:19 +01:00
Paweł Jastrzębski
54592969a4 Optimized imports 2013-11-06 11:14:01 +01:00
Paweł Jastrzębski
38007ab3d5 Number of KindleGen threads is now dynamic 2013-11-06 11:08:14 +01:00
Paweł Jastrzębski
bdd10c7617 Tweaked KindleGen/KindleUnpack multiprocessing 2013-11-05 16:11:14 +01:00
Paweł Jastrzębski
c0f4bc021a Tweaked ComicRack metadata parser 2013-11-04 20:08:54 +01:00
Paweł Jastrzębski
34d6af93a6 Refactored KindleGen/KindleUnpack handling 2013-11-04 17:07:10 +01:00
Paweł Jastrzębski
0df481dabb Added ComicRack metadata parser 2013-11-03 09:29:13 +01:00
Paweł Jastrzębski
55c5b91411 README update 2013-10-31 14:04:06 +01:00
Paweł Jastrzębski
be745f4602 README update 2013-10-31 13:50:40 +01:00
Paweł Jastrzębski
8bf5ad0f12 Fixed headers 2013-10-30 11:50:32 +01:00
31 changed files with 5635 additions and 4701 deletions

8
.gitignore vendored
View File

@@ -2,11 +2,11 @@
*.cbz
*.cbr
.idea
.DS_Store
Thumbs.db
build
dist
Output
test
solaio
kindlegen*
UnRAR*
7za*
.DS_Store
Thumbs.db

View File

@@ -7,19 +7,19 @@
<x>0</x>
<y>0</y>
<width>420</width>
<height>380</height>
<height>397</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>420</width>
<height>380</height>
<height>397</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>420</width>
<height>380</height>
<height>397</height>
</size>
</property>
<property name="font">
@@ -27,9 +27,6 @@
<pointsize>9</pointsize>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="windowTitle">
<string>Kindle Comic Converter</string>
</property>
@@ -74,7 +71,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Disable image optimizations.</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Disable image optimizations.&lt;br/&gt;Input images must be already resized.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>No optimisation</string>
@@ -113,7 +110,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable auto-splitting of webtoons like &lt;span style=&quot; font-style:italic;&quot;&gt;Tower of God&lt;/span&gt; or &lt;span style=&quot; font-style:italic;&quot;&gt;Noblesse&lt;/span&gt;.&lt;br/&gt;Pages with a low width, high height and vertical panel flow.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable auto-splitting of webtoons like &lt;span style=&quot; font-style:italic;&quot;&gt;Tower of God&lt;/span&gt; or &lt;span style=&quot; font-style:italic;&quot;&gt;Noblesse&lt;/span&gt;.&lt;br/&gt;This mode was created for pages with a low width, high height and vertical panel flow.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Webtoon mode</string>
@@ -131,7 +128,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Create PNG files instead JPEG.&lt;br/&gt;Quality increase is not noticeable on most of devices.&lt;br/&gt;Output files &lt;span style=&quot; font-weight:600;&quot;&gt;might&lt;/span&gt; be smaller.&lt;br/&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;MOBI conversion will be much slower.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Create PNG files instead JPEG.&lt;br/&gt;Quality increase is not noticeable on most of devices.&lt;br/&gt;Output files &lt;span style=&quot; font-weight:600;&quot;&gt;might&lt;/span&gt; be smaller.&lt;br/&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;MOBI conversion will be much slower.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>PNG output</string>
@@ -170,7 +167,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Disable splitting and rotation.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Disable splitting and rotation.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>No split/rotate</string>
@@ -198,7 +195,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Target device.</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Target device.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
<widget class="QComboBox" name="FormatBox">
@@ -220,7 +217,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Output format.</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Output format.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
<widget class="QPushButton" name="ConvertButton">
@@ -243,6 +240,9 @@
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Shift+Click to select the output directory.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Convert</string>
</property>
@@ -362,7 +362,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Enable right-to-left reading.</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Enable right-to-left reading.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Manga mode</string>
@@ -386,13 +386,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Sans'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-weight:600; text-decoration: underline;&quot;&gt;Unchecked - Normal quality mode&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-style:italic;&quot;&gt;Use it when Panel View support is not needed.&lt;/span&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-weight:600; text-decoration: underline;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2';&quot;&gt;- Maximum quality when zoom is not enabled.&lt;br /&gt;- Poor quality when zoom is enabled.&lt;br /&gt;- Lowest file size.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-weight:600; text-decoration: underline;&quot;&gt;Indeterminate - High quality mode&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-style:italic;&quot;&gt;Not zoomed image &lt;/span&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-weight:600; font-style:italic;&quot;&gt;might &lt;/span&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-style:italic;&quot;&gt;be a little blurry.&lt;/span&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-weight:600; text-decoration: underline;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2';&quot;&gt;- Medium/High quality when zoom is not enabled.&lt;br /&gt;- Maximum quality when zoom is enabled.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-weight:600; text-decoration: underline;&quot;&gt;Checked - Ultra quality mode&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-style:italic;&quot;&gt;Maximum possible quality.&lt;/span&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-weight:600; text-decoration: underline;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2';&quot;&gt;- Maximum quality when zoom is not enabled.&lt;br /&gt;- Maximum quality when zoom is enabled.&lt;br /&gt;- Very high file size.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Unchecked - Normal quality mode&lt;/span&gt;&lt;br/&gt;Maximal quality of images but very poor magnification quality.&lt;br/&gt;Use it only when zoom is not needed or output files needs to be small.&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Indeterminate - High quality mode&lt;/span&gt;&lt;br/&gt;In most cases high quality of images and magnification.&lt;br/&gt;Overall quality highly depends on the resolution of source files.&lt;br/&gt;On Kindle models older than Paperwhite non-zoomed images might be a little blurred.&lt;br/&gt;&lt;br/&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Checked - Ultra quality mode&lt;/span&gt;&lt;br/&gt;Highest possible quality. Output files will be big.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>High/Ultra quality</string>
@@ -419,7 +413,7 @@ p, li { white-space: pre-wrap; }
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Disable page spliting.&lt;br/&gt;They will be rotated instead.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Disable splitting of two-page spreads.&lt;br/&gt;They will be rotated instead.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Horizontal mode</string>
@@ -546,9 +540,6 @@ p, li { white-space: pre-wrap; }
<family>DejaVu Sans</family>
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;When converting color images setting this option to 1.0 &lt;span style=&quot; font-weight:600;&quot;&gt;might&lt;/span&gt; improve readability.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Gamma: Auto</string>
</property>
@@ -570,9 +561,6 @@ p, li { white-space: pre-wrap; }
<property name="focusPolicy">
<enum>Qt::ClickFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;When converting color images setting this option to 1.0 &lt;span style=&quot; font-weight:600;&quot;&gt;might&lt;/span&gt; improve readability.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="maximum">
<number>500</number>
</property>
@@ -644,7 +632,7 @@ p, li { white-space: pre-wrap; }
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Do not convert images to grayscale.</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Don't convert images to grayscale.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Color mode</string>
@@ -673,7 +661,7 @@ p, li { white-space: pre-wrap; }
</font>
</property>
<property name="toolTip">
<string>Resolution of target device.</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Resolution of target device.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Custom width: </string>
@@ -706,10 +694,10 @@ p, li { white-space: pre-wrap; }
<bool>false</bool>
</property>
<property name="toolTip">
<string>Resolution of target device.</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Resolution of target device.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="inputMask">
<string>0000; </string>
<string>0000</string>
</property>
<property name="maxLength">
<number>4</number>
@@ -724,7 +712,7 @@ p, li { white-space: pre-wrap; }
</font>
</property>
<property name="toolTip">
<string>Resolution of target device.</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Resolution of target device.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Custom height: </string>
@@ -757,10 +745,10 @@ p, li { white-space: pre-wrap; }
<bool>false</bool>
</property>
<property name="toolTip">
<string>Resolution of target device.</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Resolution of target device.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="inputMask">
<string>0000; </string>
<string>0000</string>
</property>
<property name="maxLength">
<number>4</number>
@@ -785,6 +773,17 @@ p, li { white-space: pre-wrap; }
<zorder>OptionsExpert</zorder>
<zorder>ProgressBar</zorder>
</widget>
<widget class="QStatusBar" name="statusBar">
<property name="font">
<font>
<family>DejaVu Sans</family>
<pointsize>8</pointsize>
</font>
</property>
<property name="sizeGripEnabled">
<bool>false</bool>
</property>
</widget>
<action name="ActionBasic">
<property name="checkable">
<bool>true</bool>

View File

@@ -7,19 +7,19 @@
<x>0</x>
<y>0</y>
<width>420</width>
<height>380</height>
<height>397</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>420</width>
<height>380</height>
<height>397</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>420</width>
<height>380</height>
<height>397</height>
</size>
</property>
<property name="font">
@@ -27,9 +27,6 @@
<pointsize>9</pointsize>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="windowTitle">
<string>Kindle Comic Converter</string>
</property>
@@ -72,7 +69,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Disable image optimizations.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Disable image optimizations.&lt;br/&gt;Input images must be already resized.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>No optimisation</string>
@@ -91,7 +88,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt; font-weight:600; text-decoration: underline;&quot;&gt;Unchecked - Nothing&lt;br/&gt;&lt;/span&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Images smaller than device resolution will not be resized.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt; font-weight:600; text-decoration: underline;&quot;&gt;Indeterminate - Stretching&lt;br/&gt;&lt;/span&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Images smaller than device resolution will be resized. Aspect ratio will be not preserved.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt; font-weight:600; text-decoration: underline;&quot;&gt;Checked - Upscaling&lt;br/&gt;&lt;/span&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Images smaller than device resolution will be resized. Aspect ratio will be preserved.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Unchecked - Nothing&lt;br/&gt;&lt;/span&gt;Images smaller than device resolution will not be resized.&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Indeterminate - Stretching&lt;br/&gt;&lt;/span&gt;Images smaller than device resolution will be resized. Aspect ratio will be not preserved.&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Checked - Upscaling&lt;br/&gt;&lt;/span&gt;Images smaller than device resolution will be resized. Aspect ratio will be preserved.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Stretch/Upscale</string>
@@ -113,7 +110,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Enable auto-splitting of webtoons like &lt;/span&gt;&lt;span style=&quot; font-size:12pt; font-style:italic;&quot;&gt;Tower of God&lt;/span&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt; or &lt;/span&gt;&lt;span style=&quot; font-size:12pt; font-style:italic;&quot;&gt;Noblesse&lt;/span&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;.&lt;br/&gt;Pages with a low width, high height and vertical panel flow.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable auto-splitting of webtoons like &lt;span style=&quot; font-style:italic;&quot;&gt;Tower of God &lt;/span&gt;or &lt;span style=&quot; font-style:italic;&quot;&gt;Noblesse&lt;/span&gt;.&lt;br/&gt;This mode was created for pages with a low width, high height and vertical panel flow.&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Webtoon mode</string>
@@ -132,7 +129,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Create PNG files instead JPEG.&lt;br/&gt;Quality increase is not noticeable on most of devices.&lt;br/&gt;Output files &lt;/span&gt;&lt;span style=&quot; font-size:12pt; font-weight:600;&quot;&gt;might&lt;/span&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt; be smaller.&lt;br/&gt;&lt;/span&gt;&lt;span style=&quot; font-size:12pt; font-weight:600;&quot;&gt;MOBI conversion will be much slower.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Create PNG files instead JPEG.&lt;br/&gt;Quality increase is not noticeable on most of devices.&lt;br/&gt;Output files &lt;span style=&quot; font-weight:600;&quot;&gt;might&lt;/span&gt; be smaller.&lt;br/&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;MOBI conversion will be much slower.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>PNG output</string>
@@ -151,7 +148,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt; font-weight:600; text-decoration: underline;&quot;&gt;Unchecked - Autodetection&lt;br/&gt;&lt;/span&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Color of margins fill will be detected automatically.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt; font-weight:600; text-decoration: underline;&quot;&gt;Indeterminate - White&lt;br/&gt;&lt;/span&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Margins will be filled with white color.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt; font-weight:600; text-decoration: underline;&quot;&gt;Checked - Black&lt;br/&gt;&lt;/span&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Margins will be filled with black color.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Unchecked - Autodetection&lt;br/&gt;&lt;/span&gt;Color of margins fill will be detected automatically.&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Indeterminate - White&lt;br/&gt;&lt;/span&gt;Margins will be filled with white color.&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Checked - Black&lt;br/&gt;&lt;/span&gt;Margins will be filled with black color.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>W/B margins</string>
@@ -173,7 +170,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Disable splitting and rotation.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Disable splitting and rotation.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>No split/rotate</string>
@@ -201,7 +198,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Target device.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Target device.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
<widget class="QComboBox" name="FormatBox">
@@ -223,7 +220,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Output format.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Output format.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
<widget class="QPushButton" name="ConvertButton">
@@ -246,6 +243,9 @@
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Shift+Click to select the output directory.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Convert</string>
</property>
@@ -366,7 +366,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Enable right-to-left reading.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Enable right-to-left reading.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Manga mode</string>
@@ -391,7 +391,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot;font-size:12pt; font-weight:600; text-decoration: underline;&quot;&gt;Unchecked - Normal quality mode&lt;br/&gt;&lt;/span&gt;&lt;span style=&quot;font-size:12pt; font-style:italic;&quot;&gt;Use it when Panel View support is not needed.&lt;/span&gt;&lt;span style=&quot;font-size:12pt; font-weight:600; text-decoration: underline;&quot;&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style=&quot;font-size:12pt;&quot;&gt;- Maximum quality when zoom is not enabled.&lt;br/&gt;- Poor quality when zoom is enabled.&lt;br/&gt;- Lowest file size.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size:12pt; font-weight:600; text-decoration: underline;&quot;&gt;Indeterminate - High quality mode&lt;br/&gt;&lt;/span&gt;&lt;span style=&quot;font-size:12pt; font-style:italic;&quot;&gt;Not zoomed image &lt;/span&gt;&lt;span style=&quot;font-size:12pt; font-weight:600; font-style:italic;&quot;&gt;might &lt;/span&gt;&lt;span style=&quot;font-size:12pt; font-style:italic;&quot;&gt;be a little blurry.&lt;/span&gt;&lt;span style=&quot;font-size:12pt; font-weight:600; text-decoration: underline;&quot;&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style=&quot;font-size:12pt;&quot;&gt;- Medium/High quality when zoom is not enabled.&lt;br/&gt;- Maximum quality when zoom is enabled.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size:12pt; font-weight:600; text-decoration: underline;&quot;&gt;Checked - Ultra quality mode&lt;br/&gt;&lt;/span&gt;&lt;span style=&quot;font-size:12pt; font-style:italic;&quot;&gt;Maximum possible quality.&lt;/span&gt;&lt;span style=&quot;font-size:12pt; font-weight:600; text-decoration: underline;&quot;&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style=&quot;font-size:12pt;&quot;&gt;- Maximum quality when zoom is not enabled.&lt;br/&gt;- Maximum quality when zoom is enabled.&lt;br/&gt;- Very high file size.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Unchecked - Normal quality mode&lt;/span&gt;&lt;br/&gt;Maximal quality of images but very poor magnification quality.&lt;br/&gt;Use it only when zoom is not needed or output files needs to be small.&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Indeterminate - High quality mode&lt;/span&gt;&lt;br/&gt;In most cases high quality of images and magnification.&lt;br/&gt;Overall quality highly depends on the resolution of source files.&lt;br/&gt;On Kindle models older than Paperwhite non-zoomed images might be a little blurred.&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Checked - Ultra quality mode&lt;/span&gt;&lt;br/&gt;Highest possible quality. Output files will be big.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>High/Ultra quality</string>
@@ -419,7 +419,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Disable page spliting.&lt;br/&gt;They will be rotated instead.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Disable splitting of two-page spreads.&lt;br/&gt;They will be rotated instead.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Horizontal mode</string>
@@ -546,9 +546,6 @@
<bold>false</bold>
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;When converting color images setting this option to 1.0 &lt;/span&gt;&lt;span style=&quot; font-size:12pt; font-weight:600;&quot;&gt;might&lt;/span&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt; improve readability.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Gamma: Auto</string>
</property>
@@ -570,9 +567,6 @@
<property name="focusPolicy">
<enum>Qt::ClickFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;When converting color images setting this option to 1.0 &lt;/span&gt;&lt;span style=&quot; font-size:12pt; font-weight:600;&quot;&gt;might&lt;/span&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt; improve readability.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="maximum">
<number>500</number>
</property>
@@ -590,7 +584,7 @@
<x>10</x>
<y>10</y>
<width>401</width>
<height>35</height>
<height>29</height>
</rect>
</property>
<property name="font">
@@ -601,9 +595,6 @@
<bold>true</bold>
</font>
</property>
<property name="autoFillBackground">
<bool>true</bool>
</property>
<property name="value">
<number>0</number>
</property>
@@ -648,7 +639,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Do not convert images to grayscale.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Don't convert images to grayscale.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Color mode</string>
@@ -680,7 +671,7 @@
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Resolution of target device.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Resolution of target device.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Custom width: </string>
@@ -714,10 +705,10 @@
<bool>false</bool>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Resolution of target device.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Resolution of target device.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="inputMask">
<string>0000; </string>
<string>0000</string>
</property>
<property name="maxLength">
<number>4</number>
@@ -735,7 +726,7 @@
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Resolution of target device.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Resolution of target device.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Custom height: </string>
@@ -769,10 +760,10 @@
<bool>false</bool>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Resolution of target device.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Resolution of target device.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="inputMask">
<string>0000; </string>
<string>0000</string>
</property>
<property name="maxLength">
<number>4</number>
@@ -797,6 +788,17 @@
<zorder>OptionsAdvancedGamma</zorder>
<zorder>OptionsExpert</zorder>
</widget>
<widget class="QStatusBar" name="statusBar">
<property name="font">
<font>
<family>Aharoni</family>
<pointsize>8</pointsize>
</font>
</property>
<property name="sizeGripEnabled">
<bool>false</bool>
</property>
</widget>
<action name="ActionBasic">
<property name="checkable">
<bool>true</bool>

View File

@@ -3,6 +3,7 @@
<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>

67
KCC.ui
View File

@@ -7,19 +7,19 @@
<x>0</x>
<y>0</y>
<width>420</width>
<height>380</height>
<height>397</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>420</width>
<height>380</height>
<height>397</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>420</width>
<height>380</height>
<height>397</height>
</size>
</property>
<property name="font">
@@ -27,9 +27,6 @@
<pointsize>9</pointsize>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="windowTitle">
<string>Kindle Comic Converter</string>
</property>
@@ -68,7 +65,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Disable image optimizations.</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Disable image optimizations.&lt;br/&gt;Input images must be already resized.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>No optimisation</string>
@@ -97,7 +94,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable auto-splitting of webtoons like &lt;span style=&quot; font-style:italic;&quot;&gt;Tower of God&lt;/span&gt; or &lt;span style=&quot; font-style:italic;&quot;&gt;Noblesse&lt;/span&gt;.&lt;br/&gt;Pages with a low width, high height and vertical panel flow.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style=&quot;white-space:pre&quot;&gt;Enable auto-splitting of webtoons like &lt;span style=&quot; font-style:italic;&quot;&gt;Tower of God&lt;/span&gt; or &lt;span style=&quot; font-style:italic;&quot;&gt;Noblesse&lt;/span&gt;.&lt;br/&gt;This mode is created for pages with a low width, high height and vertical panel flow.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Webtoon mode</string>
@@ -110,7 +107,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Create PNG files instead JPEG.&lt;br/&gt;Quality increase is not noticeable on most of devices.&lt;br/&gt;Output files &lt;span style=&quot; font-weight:600;&quot;&gt;might&lt;/span&gt; be smaller.&lt;br/&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;MOBI conversion will be much slower.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Create PNG files instead JPEG.&lt;br/&gt;Quality increase is not noticeable on most of devices.&lt;br/&gt;Output files &lt;span style=&quot; font-weight:600;&quot;&gt;might&lt;/span&gt; be smaller.&lt;br/&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;MOBI conversion will be much slower.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>PNG output</string>
@@ -139,7 +136,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Disable splitting and rotation.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Disable splitting and rotation.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>No split/rotate</string>
@@ -166,7 +163,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Target device.</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Target device.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
<widget class="QComboBox" name="FormatBox">
@@ -187,7 +184,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Output format.</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Output format.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
<widget class="QPushButton" name="ConvertButton">
@@ -209,6 +206,9 @@
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Shift+Click to select the output directory.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Convert</string>
</property>
@@ -319,7 +319,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Enable right-to-left reading.</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Enable right-to-left reading.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Manga mode</string>
@@ -338,13 +338,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Unchecked - Normal quality mode&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;Use it when Panel View support is not needed.&lt;/span&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;&lt;br /&gt;&lt;/span&gt;- Maximum quality when zoom is not enabled.&lt;br /&gt;- Poor quality when zoom is enabled.&lt;br /&gt;- Lowest file size.&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Indeterminate - High quality mode&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;Not zoomed image &lt;/span&gt;&lt;span style=&quot; font-weight:600; font-style:italic;&quot;&gt;might &lt;/span&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;be &lt;/span&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;a little blurry.&lt;/span&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;&lt;br /&gt;&lt;/span&gt;- Medium/High quality when zoom is not enabled.&lt;br /&gt;- Maximum quality when zoom is enabled.&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Checked - Ultra quality mode&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;Maximum possible quality.&lt;/span&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;&lt;br /&gt;&lt;/span&gt;- Maximum quality when zoom is not enabled.&lt;br /&gt;- Maximum quality when zoom is enabled.&lt;br /&gt;- Very high file size.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style=&quot;white-space:pre&quot;&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Unchecked - Normal quality mode&lt;br/&gt;&lt;/span&gt;Maximal quality of images but very poor magnification quality.&lt;br/&gt;Use it only when zoom is not needed or output files needs to be small.&lt;/p&gt;&lt;p style=&quot;white-space:pre&quot;&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Indeterminate - High quality mode&lt;br/&gt;&lt;/span&gt;In most cases high quality of images and magnification.&lt;br/&gt;Overall quality highly depends on the resolution of source files.&lt;br/&gt;On Kindle models older than Paperwhite non-zoomed images might be a little blurred.&lt;/p&gt;&lt;p style=&quot;white-space:pre&quot;&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Checked - Ultra quality mode&lt;br/&gt;&lt;/span&gt;Highest possible quality. Output files will be big.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>High/Ultra quality</string>
@@ -366,7 +360,7 @@ p, li { white-space: pre-wrap; }
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Disable page spliting.&lt;br/&gt;They will be rotated instead.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Disable splitting of two-page spreads.&lt;br/&gt;They will be rotated instead.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Horizontal mode</string>
@@ -472,9 +466,6 @@ p, li { white-space: pre-wrap; }
<height>40</height>
</rect>
</property>
<property name="toolTip">
<string>When converting color images setting this option to 1.0 MIGHT improve readability.</string>
</property>
<property name="text">
<string>Gamma: Auto</string>
</property>
@@ -491,9 +482,6 @@ p, li { white-space: pre-wrap; }
<property name="focusPolicy">
<enum>Qt::ClickFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;When converting color images setting this option to 1.0 &lt;span style=&quot; font-weight:600;&quot;&gt;might&lt;/span&gt; improve readability.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="maximum">
<number>500</number>
</property>
@@ -558,7 +546,7 @@ p, li { white-space: pre-wrap; }
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Do not convert images to grayscale.</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Don't convert images to grayscale.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Color mode</string>
@@ -577,7 +565,7 @@ p, li { white-space: pre-wrap; }
<item row="0" column="0">
<widget class="QLabel" name="wLabel">
<property name="toolTip">
<string>Resolution of target device.</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Resolution of target device.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Custom width: </string>
@@ -605,10 +593,10 @@ p, li { white-space: pre-wrap; }
<bool>false</bool>
</property>
<property name="toolTip">
<string>Resolution of target device.</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Resolution of target device.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="inputMask">
<string>0000; </string>
<string>0000</string>
</property>
<property name="maxLength">
<number>4</number>
@@ -618,7 +606,7 @@ p, li { white-space: pre-wrap; }
<item row="0" column="2">
<widget class="QLabel" name="hLabel">
<property name="toolTip">
<string>Resolution of target device.</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Resolution of target device.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Custom height: </string>
@@ -646,10 +634,10 @@ p, li { white-space: pre-wrap; }
<bool>false</bool>
</property>
<property name="toolTip">
<string>Resolution of target device.</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p style='white-space:pre'&gt;Resolution of target device.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="inputMask">
<string>0000; </string>
<string>0000</string>
</property>
<property name="maxLength">
<number>4</number>
@@ -674,6 +662,17 @@ p, li { white-space: pre-wrap; }
<zorder>OptionsExpert</zorder>
<zorder>ProgressBar</zorder>
</widget>
<widget class="QStatusBar" name="statusBar">
<property name="font">
<font>
<family>MS Shell Dlg 2</family>
<pointsize>8</pointsize>
</font>
</property>
<property name="sizeGripEnabled">
<bool>false</bool>
</property>
</widget>
<action name="ActionBasic">
<property name="checkable">
<bool>true</bool>

View File

@@ -1,7 +1,7 @@
ISC LICENSE
Copyright (c) 2013 Ciro Mattia Gonano <ciromattia@gmail.com>
Copyright (c) 2013 Paweł Jastrzębski <pawelj@vulturis.eu>
Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
Copyright (c) 2013-2014 Paweł Jastrzębski <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

198
README.md
View File

@@ -1,6 +1,6 @@
# KCC
**KindleComicConverter** is a Python app to convert comic files or folders to ePub or Panel View MOBI.
**Kindle Comic Converter** is a Python app to convert comic 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
actually a comic to EPUB converter that every e-reader owner can happily use**_.
It can also optionally optimize images by applying a number of transformations.
@@ -8,69 +8,74 @@ It can also optionally optimize images by applying a number of transformations.
### 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.
Amazon's tool is for comic publishers and involves a lot of manual effort, while **KCC** is for comic readers.
If you want to read some comments over *Amazon's KC2* you can take a look at [this](http://www.mobileread.com/forums/showthread.php?t=207461&page=7#96) and [that](http://www.mobileread.com/forums/showthread.php?t=211047) threads on Mobileread.
_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
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 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)!
### Donations
If you find **KCC** valuable you can consider donating to the authors:
* Ciro Mattia Gonano [![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=D8WNYNPBGDAS2)
* Paweł Jastrzębski [![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=YTTJ4LK2JDHPS)
- Ciro Mattia Gonano:
- [![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=D8WNYNPBGDAS2)
- [![Flattr this](http://api.flattr.com/button/flattr-badge-large.png)](http://flattr.com/thing/2260449/ciromattiakcc-on-GitHub)
- Paweł Jastrzębski:
- [![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=YTTJ4LK2JDHPS)
- Bitcoin: 1W15wwqsfd7wbaZ6wvSJf1LW1bz6q5L8b
## BINARY RELEASES
You can find the latest released binary at the following links:
- **Win64:** [http://kcc.vulturis.eu/Win64/](http://kcc.vulturis.eu/Win64/)
- **Win32:** [http://kcc.vulturis.eu/Win32/](http://kcc.vulturis.eu/Win32/)
- **OS X:** [http://kcc.vulturis.eu/OSX/](http://kcc.vulturis.eu/OSX/)
- **Linux:** Just download sourcecode and launch: `python kcc.py`
- **Windows:** [http://kcc.iosphe.re/Windows/](http://kcc.iosphe.re/Windows/)
- **Linux:** [http://kcc.iosphe.re/Linux/](http://kcc.iosphe.re/Linux/)
- **OS X (10.8+):** [http://kcc.iosphe.re/OSX/](http://kcc.iosphe.re/OSX/)
## INPUT FORMATS
**KCC** can understand and convert, at the moment, the following file types:
- PNG, JPG, GIF, TIFF, BMP
- Folders
**KCC** can understand and convert, at the moment, the following input types:
- Folders containing: PNG, JPG, GIF, TIFF or BMP files
- CBZ, ZIP
- CBR, RAR *(With `unrar` executable)*
- CB7, 7Z *(With `7za` executable)*
- PDF *(Extracting only contained JPG images)*
## OPTIONAL REQUIREMENTS
- [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)*
- [7za](http://www.7-zip.org/download.html) *(For 7z/CB7 support)*
### For compiling/running from source:
- Python 2.7 - Included in MacOS and Linux, follow the [official documentation](http://www.python.org/getit/windows/) to install on Windows.
- PyQt4 - Please refer to official documentation for installing into your system.
- [Pillow](http://pypi.python.org/pypi/Pillow/) 2.2.1+ - For comic optimizations. Please refer to official documentation for installing into your system.
- **To build OS X release a modified QT is required:** [Patch](https://github.com/ciromattia/kcc/blob/master/other/QT-4.8.5-QListWidget.patch)
### For running from source:
- Python 3.3+
- [PyQt5](http://www.riverbankcomputing.co.uk/software/pyqt/download5) 5.2.0+
- [Pillow](http://pypi.python.org/pypi/Pillow/) 2.3.0+
- [psutil](https://pypi.python.org/pypi/psutil) 2.0+
- [python-slugify](http://pypi.python.org/pypi/python-slugify)
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 - [py2exe](https://pypi.python.org/pypi/py2exe) 0.9.2+
- OS X - [py2app](https://bitbucket.org/ronaldoussoren/py2app) 0.8.0+
## USAGE
### Important tips:
* Use high quality source files. **This little detail have a major impact on the final result.**
* Read tooltip of _High/Ultra quality_ option. There are many important informations there.
* When converting images smaller than device resolution remember to enable upscaling.
* Panel View (auto zooming every part of page) can be disabled directly on Kindle. There is no KCC option to do that.
* If you're converting color images and the end result is not satisfactory, experiment with gamma correction option (check 1.0 setting first).
* Check our [wiki](https://github.com/ciromattia/kcc/wiki/Other-devices) for a list of tested Non-Kindle E-Readers.
* The first image found will be set as the comic's cover.
* All files/directories will be added to EPUB in alphabetical order.
* Output MOBI file should be uploaded via USB. Other methods might corrupt it.
### GUI
Should be pretty self-explanatory. All options have detailed informations in tooltips.
After completed conversion you should find ready file alongside the original input file (same directory).
### Standalone `comic2ebook.py` usage:
Please check [our wiki](https://github.com/ciromattia/kcc/wiki/) for more details.
### Standalone `kcc-c2e.py` usage:
```
Usage: comic2ebook.py [options] comic_file|comic_folder
Usage: kcc-c2e [options] comic_file|comic_folder
Options:
MAIN:
-p PROFILE, --profile=PROFILE
Device profile (Choose one among K1, K2, K345, KDX, KHD, KF, KFHD, KFHD8, KFHDX, KFHDX8, KFA) [Default=KHD]
Device profile (Choose one among K1, K2, K345, KDX, KHD, KF, KFHD, KFHD8, KFHDX, KFHDX8, KFA, KoMT, KoG, KoA, KoAHD) [Default=KHD]
-q QUALITY, --quality=QUALITY
Quality of Panel View. 0 - Normal 1 - High 2 - Ultra [Default=0]
-m, --manga-style Manga style (Right-to-left reading and splitting)
@@ -104,20 +109,20 @@ Options:
Replace screen height provided by device profile
OTHER:
-v, --verbose Verbose output
-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:
MANDATORY:
-y HEIGHT, --height=HEIGHT
Height of the target device screen
-i, --in-place Overwrite source directory
-m, --merge Combine every directory into a single image before splitting
OTHER:
-d, --debug Create debug file for every splitted image
@@ -125,52 +130,55 @@ Options:
```
## 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:
- `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 &copy; 2005-2011 **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.
## SAMPLE FILES CREATED BY KCC
* [Kindle Paperwhite](http://kcc.vulturis.eu/Samples/Ubunchu!-KPW.mobi)
* [Kindle](http://kcc.vulturis.eu/Samples/Ubunchu!-K345.mobi)
* [Kindle DX/DXG](http://kcc.vulturis.eu/Samples/Ubunchu!-KDX.mobi)
* [Kindle Fire](http://kcc.vulturis.eu/Samples/Ubunchu!-KF.mobi)
* [Kindle Fire HD](http://kcc.vulturis.eu/Samples/Ubunchu!-KFHD.mobi)
* [Kindle Fire HD 8.9"](http://kcc.vulturis.eu/Samples/Ubunchu!-KFHD8.mobi)
* [Kindle Fire HDX](http://kcc.vulturis.eu/Samples/Ubunchu!-KFHDX.mobi)
* [Kindle Fire HDX 8.9"](http://kcc.vulturis.eu/Samples/Ubunchu!-KFHDX8.mobi)
* [Kindle Paperwhite](http://kcc.iosphe.re/Samples/Ubunchu!-KPW.mobi)
* [Kindle](http://kcc.iosphe.re/Samples/Ubunchu!-K345.mobi)
* [Kindle DX/DXG](http://kcc.iosphe.re/Samples/Ubunchu!-KDX.mobi)
* [Kindle Fire HD](http://kcc.iosphe.re/Samples/Ubunchu!-KFHD.mobi)
* [Kindle Fire HD 8.9"](http://kcc.iosphe.re/Samples/Ubunchu!-KFHD8.mobi)
* [Kindle Fire HDX](http://kcc.iosphe.re/Samples/Ubunchu!-KFHDX.mobi)
* [Kindle Fire HDX 8.9"](http://kcc.iosphe.re/Samples/Ubunchu!-KFHDX8.mobi)
* [Kobo Mini/Touch](http://kcc.iosphe.re/Samples/Ubunchu!-KoMT.cbz)
* [Kobo Glow](http://kcc.iosphe.re/Samples/Ubunchu!-KoG.cbz)
* [Kobo Aura](http://kcc.iosphe.re/Samples/Ubunchu!-KoA.cbz)
* [Kobo Aura HD](http://kcc.iosphe.re/Samples/Ubunchu!-KoAHD.cbz)
## CHANGELOG
####1.00
####1.0
* Initial version
####1.10
####1.1
* Added support for CBZ/CBR files in comic2ebook.py
####1.11
* Added support for CBZ/CBR files in KindleComicConverter
####1.1.1
* Added support for CBZ/CBR files in Kindle Comic Converter
####1.20
####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.30
####1.3
* Fixed an issue in OPF generation for device resolution
* Reworked options system (call with -h option to get the inline help)
####1.40
####1.4
* Added some options for controlling image optimization
* Further optimization (ImageOps, page numbering cut, autocontrast)
####1.41
####1.4.1
* Fixed a serious bug on resizing when img ratio was bigger than device one
####1.50
####1.5
* Added subfolder support for multiple chapters.
####2.0
@@ -179,7 +187,7 @@ The app relies and includes the following scripts/binaries:
####2.1
* Added basic error reporting
#### 2.2:
####2.2:
* Added (valid!) ePub 2.0 output
* Rename .zip files to .cbz to avoid overwriting
@@ -284,7 +292,71 @@ The app relies and includes the following scripts/binaries:
* Improved multiprocessing speed
* GUI tweaks and minor bug fixes
## COPYRIGHT
####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
Copyright (c) 2012-2013 Ciro Mattia Gonano and Paweł Jastrzębski.
####3.6.1:
* Fixed PNG output
####3.6.2:
* Fixed previous PNG output fix
* Fixed Panel View anomalies
####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.7.1:
* Hotfixed Kobo profiles
####3.7.2:
* Fixed problems with HQ mode
####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
####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.2:
* Fixed some Windows and OSX specific bugs
* Fixed problem with marigns when using HQ mode
####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
## KNOWN ISSUES
Please check [wiki page](https://github.com/ciromattia/kcc/wiki/Known-issues).
## COPYRIGHT
Copyright (c) 2012-2014 Ciro Mattia Gonano and Paweł Jastrzębski.
**KCC** is released under ISC LICENSE; see LICENSE.txt for further details.

BIN
icons/Kobo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

72
kcc-c2e.py Executable file
View File

@@ -0,0 +1,72 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013-2014 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.
__version__ = '4.1'
__license__ = 'ISC'
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
__docformat__ = 'restructuredtext en'
import sys
if sys.version_info[0] != 3:
print('ERROR: This is Python 3 script!')
exit(1)
# Dependency check
missing = []
try:
# noinspection PyUnresolvedReferences
import psutil
if tuple(map(int, ('2.0.0'.split(".")))) > tuple(map(int, psutil.version_info)):
missing.append('psutil 2.0.0+')
except ImportError:
missing.append('psutil 2.0.0+')
try:
# noinspection PyUnresolvedReferences
import PIL
if tuple(map(int, ('2.3.0'.split(".")))) > tuple(map(int, (PIL.PILLOW_VERSION.split(".")))):
missing.append('Pillow 2.3.0+')
except ImportError:
missing.append('Pillow 2.3.0+')
try:
# noinspection PyUnresolvedReferences
import slugify
except ImportError:
missing.append('python-slugify')
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 kcc.comic2ebook import main, Copyright
if __name__ == "__main__":
freeze_support()
Copyright()
main(sys.argv[1:])
sys.exit(0)

60
kcc-c2p.py Executable file
View File

@@ -0,0 +1,60 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013-2014 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.
__version__ = '4.1'
__license__ = 'ISC'
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
__docformat__ = 'restructuredtext en'
import sys
if sys.version_info[0] != 3:
print('ERROR: This is Python 3 script!')
exit(1)
# Dependency check
missing = []
try:
# noinspection PyUnresolvedReferences
import PIL
if tuple(map(int, ('2.3.0'.split(".")))) > tuple(map(int, (PIL.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 kcc.comic2panel import main, Copyright
if __name__ == "__main__":
freeze_support()
Copyright()
main(sys.argv[1:])
sys.exit(0)

66
kcc.iss
View File

@@ -1,7 +1,7 @@
#define MyAppName "Kindle Comic Converter"
#define MyAppVersion "3.5"
#define MyAppVersion "4.1"
#define MyAppPublisher "Ciro Mattia Gonano, Paweł Jastrzębski"
#define MyAppURL "http://kcc.vulturis.eu/"
#define MyAppURL "http://kcc.iosphe.re/"
#define MyAppExeName "KCC.exe"
[Setup]
@@ -12,6 +12,7 @@ AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
AppCopyright=Copyright (C) 2012-2014 Ciro Mattia Gonano and Paweł Jastrzębski
DefaultDirName={pf}\{#MyAppName}
DefaultGroupName={#MyAppName}
AllowNoIcons=yes
@@ -28,6 +29,7 @@ UninstallDisplayName={#MyAppName}
UninstallDisplayIcon={app}\{#MyAppExeName}
ChangesAssociations=True
InfoAfterFile=other\InstallWarning.rtf
SignTool=SignTool /d $q{#MyAppName}$q /du $q{#MyAppURL}$q $f
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
@@ -40,53 +42,17 @@ Name: "CB7association"; Description: "CB7"; GroupDescription: "File associations
[Files]
; x64 files
Source: "build\exe.win-amd64-2.7\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
Source: "build\exe.win-amd64-2.7\_ctypes.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
Source: "build\exe.win-amd64-2.7\_hashlib.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
Source: "build\exe.win-amd64-2.7\_multiprocessing.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
Source: "build\exe.win-amd64-2.7\_socket.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
Source: "build\exe.win-amd64-2.7\_ssl.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
Source: "build\exe.win-amd64-2.7\bz2.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
Source: "build\exe.win-amd64-2.7\LIBEAY32.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
Source: "build\exe.win-amd64-2.7\library.zip"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
Source: "build\exe.win-amd64-2.7\PIL._imaging.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
Source: "build\exe.win-amd64-2.7\PIL._imagingft.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
Source: "build\exe.win-amd64-2.7\pyexpat.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
Source: "build\exe.win-amd64-2.7\PyQt4.QtCore.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
Source: "build\exe.win-amd64-2.7\PyQt4.QtGui.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
Source: "build\exe.win-amd64-2.7\PyQt4.QtNetwork.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
Source: "build\exe.win-amd64-2.7\python27.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
Source: "build\exe.win-amd64-2.7\QtCore4.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
Source: "build\exe.win-amd64-2.7\QtGui4.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
Source: "build\exe.win-amd64-2.7\QtNetwork4.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
Source: "build\exe.win-amd64-2.7\select.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
Source: "build\exe.win-amd64-2.7\sip.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
Source: "build\exe.win-amd64-2.7\SSLEAY32.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
Source: "build\exe.win-amd64-2.7\unicodedata.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
Source: "dist_64\imageformats\*"; DestDir: "{app}\imageformats\"; Flags: ignoreversion; Check: Is64BitInstallMode
Source: "dist_64\platforms\*"; DestDir: "{app}\platforms\"; Flags: ignoreversion; Check: Is64BitInstallMode
Source: "dist_64\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
Source: "dist_64\*.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
Source: "other\vcredist_x64.exe"; DestDir: "{tmp}"; Flags: ignoreversion deleteafterinstall; Check: Is64BitInstallMode
; x86 files
Source: "build\exe.win32-2.7\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion solidbreak; Check: not Is64BitInstallMode
Source: "build\exe.win32-2.7\_ctypes.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
Source: "build\exe.win32-2.7\_hashlib.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
Source: "build\exe.win32-2.7\_multiprocessing.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
Source: "build\exe.win32-2.7\_socket.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
Source: "build\exe.win32-2.7\_ssl.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
Source: "build\exe.win32-2.7\bz2.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
Source: "build\exe.win32-2.7\LIBEAY32.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
Source: "build\exe.win32-2.7\library.zip"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
Source: "build\exe.win32-2.7\PIL._imaging.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
Source: "build\exe.win32-2.7\PIL._imagingft.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
Source: "build\exe.win32-2.7\pyexpat.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
Source: "build\exe.win32-2.7\PyQt4.QtCore.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
Source: "build\exe.win32-2.7\PyQt4.QtGui.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
Source: "build\exe.win32-2.7\PyQt4.QtNetwork.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
Source: "build\exe.win32-2.7\python27.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
Source: "build\exe.win32-2.7\QtCore4.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
Source: "build\exe.win32-2.7\QtGui4.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
Source: "build\exe.win32-2.7\QtNetwork4.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
Source: "build\exe.win32-2.7\select.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
Source: "build\exe.win32-2.7\sip.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
Source: "build\exe.win32-2.7\SSLEAY32.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
Source: "build\exe.win32-2.7\unicodedata.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
Source: "dist\imageformats\*"; DestDir: "{app}\imageformats\"; Flags: ignoreversion; Check: not Is64BitInstallMode
Source: "dist\platforms\*"; DestDir: "{app}\platforms\"; Flags: ignoreversion; Check: not Is64BitInstallMode
Source: "dist\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
Source: "dist\*.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
Source: "other\vcredist_x86.exe"; DestDir: "{tmp}"; Flags: ignoreversion deleteafterinstall; Check: not Is64BitInstallMode
; Common files
Source: "LICENSE.txt"; DestDir: "{app}"; Flags: ignoreversion solidbreak
Source: "other\Additional-LICENSE.txt"; DestDir: "{app}"; Flags: ignoreversion
@@ -99,7 +65,9 @@ Name: "{group}\Readme"; Filename: "https://github.com/ciromattia/kcc#kcc"
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall
Filename: "{tmp}\vcredist_x64.exe"; Parameters: "/passive /Q:a /c:""msiexec /qb /i vcredist.msi"" "; StatusMsg: "Installing Microsoft Visual C++ 2010 Redistributable Package..."; Check: Is64BitInstallMode
Filename: "{tmp}\vcredist_x86.exe"; Parameters: "/passive /Q:a /c:""msiexec /qb /i vcredist.msi"" "; StatusMsg: "Installing Microsoft Visual C++ 2010 Redistributable Package..."; Check: not Is64BitInstallMode
[Messages]
WelcomeLabel1=Welcome to the KCC Setup Wizard

166
kcc.py Normal file → Executable file
View File

@@ -1,8 +1,8 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (c) 2012-2013 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013 Pawel Jastrzebski <pawelj@vulturis.eu>
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013-2014 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
@@ -18,62 +18,126 @@
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
__version__ = '3.5'
__version__ = '4.1'
__license__ = 'ISC'
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
__docformat__ = 'restructuredtext en'
import sys
import os
try:
#noinspection PyUnresolvedReferences
from PyQt4 import QtCore, QtGui, QtNetwork
except ImportError:
print "ERROR: PyQT4 is not installed!"
if sys.version_info[0] != 3:
print('ERROR: This is Python 3 script!')
exit(1)
from kcc import KCC_gui
# Dependency check
missing = []
try:
# noinspection PyUnresolvedReferences
from PyQt5 import QtCore, QtNetwork, QtWidgets
if tuple(map(int, ('5.2.0'.split(".")))) > tuple(map(int, (QtCore.qVersion().split(".")))):
missing.append('PyQt5 5.2.0+')
except ImportError:
missing.append('PyQt5 5.2.0+')
try:
# noinspection PyUnresolvedReferences
import psutil
if tuple(map(int, ('2.0.0'.split(".")))) > tuple(map(int, psutil.version_info)):
missing.append('psutil 2.0.0+')
except ImportError:
missing.append('psutil 2.0.0+')
try:
# noinspection PyUnresolvedReferences
import PIL
if tuple(map(int, ('2.3.0'.split(".")))) > tuple(map(int, (PIL.PILLOW_VERSION.split(".")))):
missing.append('Pillow 2.3.0+')
except ImportError:
missing.append('Pillow 2.3.0+')
try:
# noinspection PyUnresolvedReferences
import slugify
except ImportError:
missing.append('python-slugify')
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
if sys.platform.startswith('darwin'):
# Workaround Finder-launched app PATH evaluation
os.environ['PATH'] = '/usr/local/bin:' + os.environ['PATH']
from kcc import KCC_ui_osx as KCC_ui
elif sys.platform.startswith('linux'):
from kcc import KCC_ui_linux as KCC_ui
else:
# Workaround for Windows file association mechanism
if 'RESOURCEPATH' 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']
elif sys.platform.startswith('win'):
if getattr(sys, 'frozen', False):
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:
os.environ['PATH'] = os.path.dirname(os.path.abspath(__file__)) + '/other/;' + os.environ['PATH']
os.chdir(os.path.dirname(os.path.abspath(__file__)))
from kcc import KCC_ui
# Implementing detection of already running KCC instance and forwarding argv to it
class QApplicationMessaging(QtGui.QApplication):
class QApplicationMessaging(QtWidgets.QApplication):
messageFromOtherInstance = QtCore.pyqtSignal(bytes)
def __init__(self, argv):
QtGui.QApplication.__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
if not self._memory.create(1):
raise RuntimeError(self._memory.errorString().toLocal8Bit().data())
self._memory.create(1)
self._key = 'KCC'
self._timeout = 1000
self._server = QtNetwork.QLocalServer(self)
if not self.isRunning():
# noinspection PyUnresolvedReferences
self._server.newConnection.connect(self.handleMessage)
self._server.listen(self._key)
def shutdown(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.emit(QtCore.SIGNAL('messageFromOtherInstance'), socket.readAll().data().decode('utf8'))
self.messageFromOtherInstance.emit(socket.readAll().data())
def sendMessage(self, message):
if self.isRunning():
@@ -81,33 +145,39 @@ class QApplicationMessaging(QtGui.QApplication):
socket.connectToServer(self._key, QtCore.QIODevice.WriteOnly)
if not socket.waitForConnected(self._timeout):
return False
socket.write(message.encode('utf8'))
# noinspection PyArgumentList
socket.write(bytes(message, 'UTF-8'))
if not socket.waitForBytesWritten(self._timeout):
return False
socket.disconnectFromServer()
return True
return False
freeze_support()
APP = QApplicationMessaging(sys.argv)
if APP.isRunning():
# 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__":
freeze_support()
KCCAplication = QApplicationMessaging(sys.argv)
if KCCAplication.isRunning():
if len(sys.argv) > 1:
KCCAplication.sendMessage(sys.argv[1])
sys.exit(0)
else:
KCCAplication.sendMessage('ARISE')
sys.exit(0)
KCCWindow = QMainWindowKCC()
KCCUI = KCC_gui.KCCGUI(KCCAplication, KCCWindow)
if len(sys.argv) > 1:
APP.sendMessage(sys.argv[1].decode(sys.getfilesystemencoding()))
sys.exit(0)
else:
messageBox = QtGui.QMessageBox()
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(':/Icon/icons/comic2ebook.png'), QtGui.QIcon.Normal, QtGui.QIcon.Off)
messageBox.setWindowIcon(icon)
QtGui.QMessageBox.critical(messageBox, 'KCC - Error', 'KCC is already running!', QtGui.QMessageBox.Ok)
sys.exit(1)
KCC = QtGui.QMainWindow()
UI = KCC_ui.Ui_KCC()
UI.setupUi(KCC)
GUI = KCC_gui.Ui_KCC(UI, KCC, APP)
KCC.setWindowTitle("Kindle Comic Converter " + __version__)
KCC.show()
KCC.raise_()
if len(sys.argv) > 1:
GUI.handleMessage(sys.argv[1].decode(sys.getfilesystemencoding()))
sys.exit(APP.exec_())
KCCUI.handleMessage(sys.argv[1])
sys.exit(KCCAplication.exec_())

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -2,94 +2,79 @@
# Form implementation generated from reading ui file 'KCC.ui'
#
# Created: Sat Oct 12 11:28:00 2013
# by: PyQt4 UI code generator 4.10.3
# Created: Sun May 18 09:08:27 2014
# by: PyQt5 UI code generator 5.2.1
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s
try:
_encoding = QtGui.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_KCC(object):
def setupUi(self, KCC):
KCC.setObjectName(_fromUtf8("KCC"))
KCC.resize(420, 380)
KCC.setMinimumSize(QtCore.QSize(420, 380))
KCC.setMaximumSize(QtCore.QSize(420, 380))
KCC.setObjectName("KCC")
KCC.resize(420, 397)
KCC.setMinimumSize(QtCore.QSize(420, 397))
KCC.setMaximumSize(QtCore.QSize(420, 397))
font = QtGui.QFont()
font.setPointSize(9)
KCC.setFont(font)
KCC.setFocusPolicy(QtCore.Qt.NoFocus)
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(_fromUtf8(":/Icon/icons/comic2ebook.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon.addPixmap(QtGui.QPixmap(":/Icon/icons/comic2ebook.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
KCC.setWindowIcon(icon)
KCC.setLocale(QtCore.QLocale(QtCore.QLocale.C, QtCore.QLocale.AnyCountry))
self.Form = QtGui.QWidget(KCC)
self.Form.setObjectName(_fromUtf8("Form"))
self.OptionsAdvanced = QtGui.QFrame(self.Form)
self.Form = QtWidgets.QWidget(KCC)
self.Form.setObjectName("Form")
self.OptionsAdvanced = QtWidgets.QFrame(self.Form)
self.OptionsAdvanced.setEnabled(True)
self.OptionsAdvanced.setGeometry(QtCore.QRect(10, 254, 421, 61))
font = QtGui.QFont()
font.setPointSize(9)
self.OptionsAdvanced.setFont(font)
self.OptionsAdvanced.setObjectName(_fromUtf8("OptionsAdvanced"))
self.gridLayout = QtGui.QGridLayout(self.OptionsAdvanced)
self.OptionsAdvanced.setObjectName("OptionsAdvanced")
self.gridLayout = QtWidgets.QGridLayout(self.OptionsAdvanced)
self.gridLayout.setContentsMargins(9, -1, -1, -1)
self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
self.ProcessingBox = QtGui.QCheckBox(self.OptionsAdvanced)
self.gridLayout.setObjectName("gridLayout")
self.ProcessingBox = QtWidgets.QCheckBox(self.OptionsAdvanced)
self.ProcessingBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.ProcessingBox.setObjectName(_fromUtf8("ProcessingBox"))
self.ProcessingBox.setObjectName("ProcessingBox")
self.gridLayout.addWidget(self.ProcessingBox, 1, 0, 1, 1)
self.UpscaleBox = QtGui.QCheckBox(self.OptionsAdvanced)
self.UpscaleBox = QtWidgets.QCheckBox(self.OptionsAdvanced)
self.UpscaleBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.UpscaleBox.setTristate(True)
self.UpscaleBox.setObjectName(_fromUtf8("UpscaleBox"))
self.UpscaleBox.setObjectName("UpscaleBox")
self.gridLayout.addWidget(self.UpscaleBox, 1, 1, 1, 1)
self.WebtoonBox = QtGui.QCheckBox(self.OptionsAdvanced)
self.WebtoonBox = QtWidgets.QCheckBox(self.OptionsAdvanced)
self.WebtoonBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.WebtoonBox.setObjectName(_fromUtf8("WebtoonBox"))
self.WebtoonBox.setObjectName("WebtoonBox")
self.gridLayout.addWidget(self.WebtoonBox, 3, 1, 1, 1)
self.NoDitheringBox = QtGui.QCheckBox(self.OptionsAdvanced)
self.NoDitheringBox = QtWidgets.QCheckBox(self.OptionsAdvanced)
self.NoDitheringBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.NoDitheringBox.setObjectName(_fromUtf8("NoDitheringBox"))
self.NoDitheringBox.setObjectName("NoDitheringBox")
self.gridLayout.addWidget(self.NoDitheringBox, 3, 2, 1, 1)
self.BorderBox = QtGui.QCheckBox(self.OptionsAdvanced)
self.BorderBox = QtWidgets.QCheckBox(self.OptionsAdvanced)
self.BorderBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.BorderBox.setTristate(True)
self.BorderBox.setObjectName(_fromUtf8("BorderBox"))
self.BorderBox.setObjectName("BorderBox")
self.gridLayout.addWidget(self.BorderBox, 3, 0, 1, 1)
self.NoRotateBox = QtGui.QCheckBox(self.OptionsAdvanced)
self.NoRotateBox = QtWidgets.QCheckBox(self.OptionsAdvanced)
self.NoRotateBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.NoRotateBox.setObjectName(_fromUtf8("NoRotateBox"))
self.NoRotateBox.setObjectName("NoRotateBox")
self.gridLayout.addWidget(self.NoRotateBox, 1, 2, 1, 1)
self.DeviceBox = QtGui.QComboBox(self.Form)
self.DeviceBox = QtWidgets.QComboBox(self.Form)
self.DeviceBox.setGeometry(QtCore.QRect(10, 200, 141, 31))
font = QtGui.QFont()
font.setPointSize(8)
self.DeviceBox.setFont(font)
self.DeviceBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.DeviceBox.setObjectName(_fromUtf8("DeviceBox"))
self.FormatBox = QtGui.QComboBox(self.Form)
self.DeviceBox.setObjectName("DeviceBox")
self.FormatBox = QtWidgets.QComboBox(self.Form)
self.FormatBox.setGeometry(QtCore.QRect(260, 200, 151, 31))
font = QtGui.QFont()
font.setPointSize(8)
self.FormatBox.setFont(font)
self.FormatBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.FormatBox.setObjectName(_fromUtf8("FormatBox"))
self.ConvertButton = QtGui.QPushButton(self.Form)
self.FormatBox.setObjectName("FormatBox")
self.ConvertButton = QtWidgets.QPushButton(self.Form)
self.ConvertButton.setGeometry(QtCore.QRect(160, 200, 91, 32))
font = QtGui.QFont()
font.setPointSize(9)
@@ -98,99 +83,99 @@ class Ui_KCC(object):
self.ConvertButton.setFont(font)
self.ConvertButton.setFocusPolicy(QtCore.Qt.NoFocus)
icon1 = QtGui.QIcon()
icon1.addPixmap(QtGui.QPixmap(_fromUtf8(":/Other/icons/convert.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon1.addPixmap(QtGui.QPixmap(":/Other/icons/convert.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.ConvertButton.setIcon(icon1)
self.ConvertButton.setObjectName(_fromUtf8("ConvertButton"))
self.DirectoryButton = QtGui.QPushButton(self.Form)
self.ConvertButton.setObjectName("ConvertButton")
self.DirectoryButton = QtWidgets.QPushButton(self.Form)
self.DirectoryButton.setGeometry(QtCore.QRect(10, 160, 141, 32))
font = QtGui.QFont()
font.setPointSize(8)
self.DirectoryButton.setFont(font)
self.DirectoryButton.setFocusPolicy(QtCore.Qt.NoFocus)
icon2 = QtGui.QIcon()
icon2.addPixmap(QtGui.QPixmap(_fromUtf8(":/Other/icons/folder_new.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon2.addPixmap(QtGui.QPixmap(":/Other/icons/folder_new.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.DirectoryButton.setIcon(icon2)
self.DirectoryButton.setObjectName(_fromUtf8("DirectoryButton"))
self.FileButton = QtGui.QPushButton(self.Form)
self.DirectoryButton.setObjectName("DirectoryButton")
self.FileButton = QtWidgets.QPushButton(self.Form)
self.FileButton.setGeometry(QtCore.QRect(260, 160, 151, 32))
font = QtGui.QFont()
font.setPointSize(8)
self.FileButton.setFont(font)
self.FileButton.setFocusPolicy(QtCore.Qt.NoFocus)
icon3 = QtGui.QIcon()
icon3.addPixmap(QtGui.QPixmap(_fromUtf8(":/Other/icons/document_new.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon3.addPixmap(QtGui.QPixmap(":/Other/icons/document_new.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.FileButton.setIcon(icon3)
self.FileButton.setObjectName(_fromUtf8("FileButton"))
self.ClearButton = QtGui.QPushButton(self.Form)
self.FileButton.setObjectName("FileButton")
self.ClearButton = QtWidgets.QPushButton(self.Form)
self.ClearButton.setGeometry(QtCore.QRect(160, 160, 91, 32))
font = QtGui.QFont()
font.setPointSize(8)
self.ClearButton.setFont(font)
self.ClearButton.setFocusPolicy(QtCore.Qt.NoFocus)
icon4 = QtGui.QIcon()
icon4.addPixmap(QtGui.QPixmap(_fromUtf8(":/Other/icons/clear.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon4.addPixmap(QtGui.QPixmap(":/Other/icons/clear.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.ClearButton.setIcon(icon4)
self.ClearButton.setObjectName(_fromUtf8("ClearButton"))
self.OptionsBasic = QtGui.QFrame(self.Form)
self.ClearButton.setObjectName("ClearButton")
self.OptionsBasic = QtWidgets.QFrame(self.Form)
self.OptionsBasic.setGeometry(QtCore.QRect(10, 230, 421, 41))
font = QtGui.QFont()
font.setPointSize(9)
self.OptionsBasic.setFont(font)
self.OptionsBasic.setObjectName(_fromUtf8("OptionsBasic"))
self.MangaBox = QtGui.QCheckBox(self.OptionsBasic)
self.OptionsBasic.setObjectName("OptionsBasic")
self.MangaBox = QtWidgets.QCheckBox(self.OptionsBasic)
self.MangaBox.setGeometry(QtCore.QRect(9, 10, 130, 18))
self.MangaBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.MangaBox.setObjectName(_fromUtf8("MangaBox"))
self.QualityBox = QtGui.QCheckBox(self.OptionsBasic)
self.MangaBox.setObjectName("MangaBox")
self.QualityBox = QtWidgets.QCheckBox(self.OptionsBasic)
self.QualityBox.setGeometry(QtCore.QRect(282, 10, 130, 18))
self.QualityBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.QualityBox.setTristate(True)
self.QualityBox.setObjectName(_fromUtf8("QualityBox"))
self.RotateBox = QtGui.QCheckBox(self.OptionsBasic)
self.QualityBox.setObjectName("QualityBox")
self.RotateBox = QtWidgets.QCheckBox(self.OptionsBasic)
self.RotateBox.setGeometry(QtCore.QRect(145, 10, 130, 18))
self.RotateBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.RotateBox.setObjectName(_fromUtf8("RotateBox"))
self.JobList = QtGui.QListWidget(self.Form)
self.RotateBox.setObjectName("RotateBox")
self.JobList = QtWidgets.QListWidget(self.Form)
self.JobList.setGeometry(QtCore.QRect(10, 50, 401, 101))
self.JobList.setFocusPolicy(QtCore.Qt.NoFocus)
self.JobList.setStyleSheet(_fromUtf8("QListWidget#JobList {background:#ffffff;background-image:url(:/Other/icons/list_background.png);background-position:center center;background-repeat:no-repeat;}QScrollBar:vertical{border:1px solid #999;background:#FFF;width:5px;margin:0}QScrollBar::handle:vertical{background:DarkGray;min-height:0}QScrollBar::add-line:vertical{height:0;background:DarkGray;subcontrol-position:bottom;subcontrol-origin:margin}QScrollBar::sub-line:vertical{height:0;background:DarkGray;subcontrol-position:top;subcontrol-origin:margin}QScrollBar:horizontal{border:1px solid #999;background:#FFF;height:5px;margin:0}QScrollBar::handle:horizontal{background:DarkGray;min-width:0}QScrollBar::add-line:horizontal{width:0;background:DarkGray;subcontrol-position:bottom;subcontrol-origin:margin}QScrollBar::sub-line:horizontal{width:0;background:DarkGray;subcontrol-position:top;subcontrol-origin:margin}"))
self.JobList.setStyleSheet("QListWidget#JobList {background:#ffffff;background-image:url(:/Other/icons/list_background.png);background-position:center center;background-repeat:no-repeat;}QScrollBar:vertical{border:1px solid #999;background:#FFF;width:5px;margin:0}QScrollBar::handle:vertical{background:DarkGray;min-height:0}QScrollBar::add-line:vertical{height:0;background:DarkGray;subcontrol-position:bottom;subcontrol-origin:margin}QScrollBar::sub-line:vertical{height:0;background:DarkGray;subcontrol-position:top;subcontrol-origin:margin}QScrollBar:horizontal{border:1px solid #999;background:#FFF;height:5px;margin:0}QScrollBar::handle:horizontal{background:DarkGray;min-width:0}QScrollBar::add-line:horizontal{width:0;background:DarkGray;subcontrol-position:bottom;subcontrol-origin:margin}QScrollBar::sub-line:horizontal{width:0;background:DarkGray;subcontrol-position:top;subcontrol-origin:margin}")
self.JobList.setProperty("showDropIndicator", False)
self.JobList.setSelectionMode(QtGui.QAbstractItemView.NoSelection)
self.JobList.setVerticalScrollMode(QtGui.QAbstractItemView.ScrollPerPixel)
self.JobList.setHorizontalScrollMode(QtGui.QAbstractItemView.ScrollPerPixel)
self.JobList.setObjectName(_fromUtf8("JobList"))
self.BasicModeButton = QtGui.QPushButton(self.Form)
self.JobList.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)
self.JobList.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
self.JobList.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
self.JobList.setObjectName("JobList")
self.BasicModeButton = QtWidgets.QPushButton(self.Form)
self.BasicModeButton.setGeometry(QtCore.QRect(10, 10, 195, 32))
font = QtGui.QFont()
font.setPointSize(9)
self.BasicModeButton.setFont(font)
self.BasicModeButton.setFocusPolicy(QtCore.Qt.NoFocus)
self.BasicModeButton.setObjectName(_fromUtf8("BasicModeButton"))
self.AdvModeButton = QtGui.QPushButton(self.Form)
self.BasicModeButton.setObjectName("BasicModeButton")
self.AdvModeButton = QtWidgets.QPushButton(self.Form)
self.AdvModeButton.setGeometry(QtCore.QRect(217, 10, 195, 32))
font = QtGui.QFont()
font.setPointSize(9)
self.AdvModeButton.setFont(font)
self.AdvModeButton.setFocusPolicy(QtCore.Qt.NoFocus)
self.AdvModeButton.setObjectName(_fromUtf8("AdvModeButton"))
self.OptionsAdvancedGamma = QtGui.QFrame(self.Form)
self.AdvModeButton.setObjectName("AdvModeButton")
self.OptionsAdvancedGamma = QtWidgets.QFrame(self.Form)
self.OptionsAdvancedGamma.setEnabled(True)
self.OptionsAdvancedGamma.setGeometry(QtCore.QRect(10, 305, 401, 41))
font = QtGui.QFont()
font.setPointSize(9)
self.OptionsAdvancedGamma.setFont(font)
self.OptionsAdvancedGamma.setObjectName(_fromUtf8("OptionsAdvancedGamma"))
self.GammaLabel = QtGui.QLabel(self.OptionsAdvancedGamma)
self.OptionsAdvancedGamma.setObjectName("OptionsAdvancedGamma")
self.GammaLabel = QtWidgets.QLabel(self.OptionsAdvancedGamma)
self.GammaLabel.setGeometry(QtCore.QRect(15, 0, 100, 40))
self.GammaLabel.setObjectName(_fromUtf8("GammaLabel"))
self.GammaSlider = QtGui.QSlider(self.OptionsAdvancedGamma)
self.GammaLabel.setObjectName("GammaLabel")
self.GammaSlider = QtWidgets.QSlider(self.OptionsAdvancedGamma)
self.GammaSlider.setGeometry(QtCore.QRect(110, 10, 270, 22))
self.GammaSlider.setFocusPolicy(QtCore.Qt.ClickFocus)
self.GammaSlider.setMaximum(500)
self.GammaSlider.setSingleStep(5)
self.GammaSlider.setOrientation(QtCore.Qt.Horizontal)
self.GammaSlider.setObjectName(_fromUtf8("GammaSlider"))
self.ProgressBar = QtGui.QProgressBar(self.Form)
self.GammaSlider.setObjectName("GammaSlider")
self.ProgressBar = QtWidgets.QProgressBar(self.Form)
self.ProgressBar.setGeometry(QtCore.QRect(10, 10, 401, 31))
font = QtGui.QFont()
font.setPointSize(10)
@@ -199,28 +184,28 @@ class Ui_KCC(object):
self.ProgressBar.setFont(font)
self.ProgressBar.setProperty("value", 0)
self.ProgressBar.setAlignment(QtCore.Qt.AlignJustify|QtCore.Qt.AlignVCenter)
self.ProgressBar.setFormat(_fromUtf8(""))
self.ProgressBar.setObjectName(_fromUtf8("ProgressBar"))
self.OptionsExpert = QtGui.QFrame(self.Form)
self.ProgressBar.setFormat("")
self.ProgressBar.setObjectName("ProgressBar")
self.OptionsExpert = QtWidgets.QFrame(self.Form)
self.OptionsExpert.setGeometry(QtCore.QRect(10, 337, 421, 41))
font = QtGui.QFont()
font.setPointSize(9)
self.OptionsExpert.setFont(font)
self.OptionsExpert.setObjectName(_fromUtf8("OptionsExpert"))
self.ColorBox = QtGui.QCheckBox(self.OptionsExpert)
self.OptionsExpert.setObjectName("OptionsExpert")
self.ColorBox = QtWidgets.QCheckBox(self.OptionsExpert)
self.ColorBox.setGeometry(QtCore.QRect(9, 11, 130, 18))
self.ColorBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.ColorBox.setObjectName(_fromUtf8("ColorBox"))
self.OptionsExpertInternal = QtGui.QFrame(self.OptionsExpert)
self.ColorBox.setObjectName("ColorBox")
self.OptionsExpertInternal = QtWidgets.QFrame(self.OptionsExpert)
self.OptionsExpertInternal.setGeometry(QtCore.QRect(100, 0, 295, 40))
self.OptionsExpertInternal.setObjectName(_fromUtf8("OptionsExpertInternal"))
self.gridLayout_2 = QtGui.QGridLayout(self.OptionsExpertInternal)
self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2"))
self.wLabel = QtGui.QLabel(self.OptionsExpertInternal)
self.wLabel.setObjectName(_fromUtf8("wLabel"))
self.OptionsExpertInternal.setObjectName("OptionsExpertInternal")
self.gridLayout_2 = QtWidgets.QGridLayout(self.OptionsExpertInternal)
self.gridLayout_2.setObjectName("gridLayout_2")
self.wLabel = QtWidgets.QLabel(self.OptionsExpertInternal)
self.wLabel.setObjectName("wLabel")
self.gridLayout_2.addWidget(self.wLabel, 0, 0, 1, 1)
self.customWidth = QtGui.QLineEdit(self.OptionsExpertInternal)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
self.customWidth = QtWidgets.QLineEdit(self.OptionsExpertInternal)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.customWidth.sizePolicy().hasHeightForWidth())
@@ -229,13 +214,13 @@ class Ui_KCC(object):
self.customWidth.setFocusPolicy(QtCore.Qt.ClickFocus)
self.customWidth.setAcceptDrops(False)
self.customWidth.setMaxLength(4)
self.customWidth.setObjectName(_fromUtf8("customWidth"))
self.customWidth.setObjectName("customWidth")
self.gridLayout_2.addWidget(self.customWidth, 0, 1, 1, 1)
self.hLabel = QtGui.QLabel(self.OptionsExpertInternal)
self.hLabel.setObjectName(_fromUtf8("hLabel"))
self.hLabel = QtWidgets.QLabel(self.OptionsExpertInternal)
self.hLabel.setObjectName("hLabel")
self.gridLayout_2.addWidget(self.hLabel, 0, 2, 1, 1)
self.customHeight = QtGui.QLineEdit(self.OptionsExpertInternal)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
self.customHeight = QtWidgets.QLineEdit(self.OptionsExpertInternal)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.customHeight.sizePolicy().hasHeightForWidth())
@@ -244,19 +229,27 @@ class Ui_KCC(object):
self.customHeight.setFocusPolicy(QtCore.Qt.ClickFocus)
self.customHeight.setAcceptDrops(False)
self.customHeight.setMaxLength(4)
self.customHeight.setObjectName(_fromUtf8("customHeight"))
self.customHeight.setObjectName("customHeight")
self.gridLayout_2.addWidget(self.customHeight, 0, 3, 1, 1)
KCC.setCentralWidget(self.Form)
self.ActionBasic = QtGui.QAction(KCC)
self.statusBar = QtWidgets.QStatusBar(KCC)
font = QtGui.QFont()
font.setFamily("MS Shell Dlg 2")
font.setPointSize(8)
self.statusBar.setFont(font)
self.statusBar.setSizeGripEnabled(False)
self.statusBar.setObjectName("statusBar")
KCC.setStatusBar(self.statusBar)
self.ActionBasic = QtWidgets.QAction(KCC)
self.ActionBasic.setCheckable(True)
self.ActionBasic.setChecked(False)
font = QtGui.QFont()
font.setPointSize(9)
self.ActionBasic.setFont(font)
self.ActionBasic.setObjectName(_fromUtf8("ActionBasic"))
self.ActionAdvanced = QtGui.QAction(KCC)
self.ActionBasic.setObjectName("ActionBasic")
self.ActionAdvanced = QtWidgets.QAction(KCC)
self.ActionAdvanced.setCheckable(True)
self.ActionAdvanced.setObjectName(_fromUtf8("ActionAdvanced"))
self.ActionAdvanced.setObjectName("ActionAdvanced")
self.retranslateUi(KCC)
QtCore.QMetaObject.connectSlotsByName(KCC)
@@ -265,53 +258,47 @@ class Ui_KCC(object):
KCC.setTabOrder(self.ConvertButton, self.ClearButton)
def retranslateUi(self, KCC):
KCC.setWindowTitle(_translate("KCC", "Kindle Comic Converter", None))
self.ProcessingBox.setToolTip(_translate("KCC", "Disable image optimizations.", None))
self.ProcessingBox.setText(_translate("KCC", "No optimisation", None))
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>", None))
self.UpscaleBox.setText(_translate("KCC", "Stretch/Upscale", None))
self.WebtoonBox.setToolTip(_translate("KCC", "<html><head/><body><p>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>", None))
self.WebtoonBox.setText(_translate("KCC", "Webtoon mode", None))
self.NoDitheringBox.setToolTip(_translate("KCC", "<html><head/><body><p>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>", None))
self.NoDitheringBox.setText(_translate("KCC", "PNG output", None))
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>", None))
self.BorderBox.setText(_translate("KCC", "W/B margins", None))
self.NoRotateBox.setToolTip(_translate("KCC", "<html><head/><body><p>Disable splitting and rotation.</p></body></html>", None))
self.NoRotateBox.setText(_translate("KCC", "No split/rotate", None))
self.DeviceBox.setToolTip(_translate("KCC", "Target device.", None))
self.FormatBox.setToolTip(_translate("KCC", "Output format.", None))
self.ConvertButton.setText(_translate("KCC", "Convert", None))
self.DirectoryButton.setText(_translate("KCC", "Add directory", None))
self.FileButton.setText(_translate("KCC", "Add file", None))
self.ClearButton.setText(_translate("KCC", "Clear list", None))
self.MangaBox.setToolTip(_translate("KCC", "Enable right-to-left reading.", None))
self.MangaBox.setText(_translate("KCC", "Manga mode", None))
self.QualityBox.setToolTip(_translate("KCC", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n"
"</style></head><body style=\" font-family:\'MS Shell Dlg 2\'; font-size:8pt; font-weight:400; font-style:normal;\">\n"
"<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><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>\n"
"<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><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 </span><span style=\" font-style:italic;\">a little blurry.</span><span style=\" font-weight:600; text-decoration: underline;\"><br /></span>- Medium/High quality when zoom is not enabled.<br />- Maximum quality when zoom is enabled.</p>\n"
"<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><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>", None))
self.QualityBox.setText(_translate("KCC", "High/Ultra quality", None))
self.RotateBox.setToolTip(_translate("KCC", "<html><head/><body><p>Disable page spliting.<br/>They will be rotated instead.</p></body></html>", None))
self.RotateBox.setText(_translate("KCC", "Horizontal mode", None))
self.BasicModeButton.setText(_translate("KCC", "Basic", None))
self.AdvModeButton.setText(_translate("KCC", "Advanced", None))
self.GammaLabel.setToolTip(_translate("KCC", "When converting color images setting this option to 1.0 MIGHT improve readability.", None))
self.GammaLabel.setText(_translate("KCC", "Gamma: Auto", None))
self.GammaSlider.setToolTip(_translate("KCC", "<html><head/><body><p>When converting color images setting this option to 1.0 <span style=\" font-weight:600;\">might</span> improve readability.</p></body></html>", None))
self.ColorBox.setToolTip(_translate("KCC", "Do not convert images to grayscale.", None))
self.ColorBox.setText(_translate("KCC", "Color mode", None))
self.wLabel.setToolTip(_translate("KCC", "Resolution of target device.", None))
self.wLabel.setText(_translate("KCC", "Custom width: ", None))
self.customWidth.setToolTip(_translate("KCC", "Resolution of target device.", None))
self.customWidth.setInputMask(_translate("KCC", "0000; ", None))
self.hLabel.setToolTip(_translate("KCC", "Resolution of target device.", None))
self.hLabel.setText(_translate("KCC", "Custom height: ", None))
self.customHeight.setToolTip(_translate("KCC", "Resolution of target device.", None))
self.customHeight.setInputMask(_translate("KCC", "0000; ", None))
self.ActionBasic.setText(_translate("KCC", "Basic", None))
self.ActionAdvanced.setText(_translate("KCC", "Advanced", None))
_translate = QtCore.QCoreApplication.translate
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.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.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/>This mode is created for pages with a low width, high height and vertical panel flow.</p></body></html>"))
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.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.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.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.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.setText(_translate("KCC", "Convert"))
self.DirectoryButton.setText(_translate("KCC", "Add directory"))
self.FileButton.setText(_translate("KCC", "Add file"))
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.setText(_translate("KCC", "Manga mode"))
self.QualityBox.setToolTip(_translate("KCC", "<html><head/><body><p style=\"white-space:pre\"><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Normal quality mode<br/></span>Maximal quality of images but very poor magnification quality.<br/>Use it only when zoom is not needed or output files needs to be small.</p><p style=\"white-space:pre\"><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - High quality mode<br/></span>In most cases high quality of images and magnification.<br/>Overall quality highly depends on the resolution of source files.<br/>On Kindle models older than Paperwhite non-zoomed images might be a little blurred.</p><p style=\"white-space:pre\"><span style=\" font-weight:600; text-decoration: underline;\">Checked - Ultra quality mode<br/></span>Highest possible quality. Output files will be big.</p></body></html>"))
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.setText(_translate("KCC", "Horizontal mode"))
self.BasicModeButton.setText(_translate("KCC", "Basic"))
self.AdvModeButton.setText(_translate("KCC", "Advanced"))
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.setText(_translate("KCC", "Color mode"))
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.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.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.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.ActionBasic.setText(_translate("KCC", "Basic"))
self.ActionAdvanced.setText(_translate("KCC", "Advanced"))
import KCC_rc
from . import KCC_rc

View File

@@ -2,330 +2,323 @@
# Form implementation generated from reading ui file 'KCC-Linux.ui'
#
# Created: Sat Oct 12 11:28:11 2013
# by: PyQt4 UI code generator 4.10.3
# Created: Sun May 18 09:08:37 2014
# by: PyQt5 UI code generator 5.2.1
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s
try:
_encoding = QtGui.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_KCC(object):
def setupUi(self, KCC):
KCC.setObjectName(_fromUtf8("KCC"))
KCC.resize(420, 380)
KCC.setMinimumSize(QtCore.QSize(420, 380))
KCC.setMaximumSize(QtCore.QSize(420, 380))
KCC.setObjectName("KCC")
KCC.resize(420, 397)
KCC.setMinimumSize(QtCore.QSize(420, 397))
KCC.setMaximumSize(QtCore.QSize(420, 397))
font = QtGui.QFont()
font.setPointSize(9)
KCC.setFont(font)
KCC.setFocusPolicy(QtCore.Qt.NoFocus)
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(_fromUtf8(":/Icon/icons/comic2ebook.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon.addPixmap(QtGui.QPixmap(":/Icon/icons/comic2ebook.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
KCC.setWindowIcon(icon)
KCC.setLocale(QtCore.QLocale(QtCore.QLocale.C, QtCore.QLocale.AnyCountry))
self.Form = QtGui.QWidget(KCC)
self.Form.setObjectName(_fromUtf8("Form"))
self.OptionsAdvanced = QtGui.QFrame(self.Form)
self.Form = QtWidgets.QWidget(KCC)
self.Form.setObjectName("Form")
self.OptionsAdvanced = QtWidgets.QFrame(self.Form)
self.OptionsAdvanced.setEnabled(True)
self.OptionsAdvanced.setGeometry(QtCore.QRect(1, 254, 421, 61))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setFamily("DejaVu Sans")
font.setPointSize(9)
self.OptionsAdvanced.setFont(font)
self.OptionsAdvanced.setObjectName(_fromUtf8("OptionsAdvanced"))
self.gridLayout = QtGui.QGridLayout(self.OptionsAdvanced)
self.OptionsAdvanced.setObjectName("OptionsAdvanced")
self.gridLayout = QtWidgets.QGridLayout(self.OptionsAdvanced)
self.gridLayout.setContentsMargins(9, -1, -1, -1)
self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
self.ProcessingBox = QtGui.QCheckBox(self.OptionsAdvanced)
self.gridLayout.setObjectName("gridLayout")
self.ProcessingBox = QtWidgets.QCheckBox(self.OptionsAdvanced)
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setFamily("DejaVu Sans")
self.ProcessingBox.setFont(font)
self.ProcessingBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.ProcessingBox.setObjectName(_fromUtf8("ProcessingBox"))
self.ProcessingBox.setObjectName("ProcessingBox")
self.gridLayout.addWidget(self.ProcessingBox, 1, 0, 1, 1)
self.UpscaleBox = QtGui.QCheckBox(self.OptionsAdvanced)
self.UpscaleBox = QtWidgets.QCheckBox(self.OptionsAdvanced)
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setFamily("DejaVu Sans")
self.UpscaleBox.setFont(font)
self.UpscaleBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.UpscaleBox.setTristate(True)
self.UpscaleBox.setObjectName(_fromUtf8("UpscaleBox"))
self.UpscaleBox.setObjectName("UpscaleBox")
self.gridLayout.addWidget(self.UpscaleBox, 1, 1, 1, 1)
self.WebtoonBox = QtGui.QCheckBox(self.OptionsAdvanced)
self.WebtoonBox = QtWidgets.QCheckBox(self.OptionsAdvanced)
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setFamily("DejaVu Sans")
self.WebtoonBox.setFont(font)
self.WebtoonBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.WebtoonBox.setObjectName(_fromUtf8("WebtoonBox"))
self.WebtoonBox.setObjectName("WebtoonBox")
self.gridLayout.addWidget(self.WebtoonBox, 3, 1, 1, 1)
self.NoDitheringBox = QtGui.QCheckBox(self.OptionsAdvanced)
self.NoDitheringBox = QtWidgets.QCheckBox(self.OptionsAdvanced)
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setFamily("DejaVu Sans")
self.NoDitheringBox.setFont(font)
self.NoDitheringBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.NoDitheringBox.setObjectName(_fromUtf8("NoDitheringBox"))
self.NoDitheringBox.setObjectName("NoDitheringBox")
self.gridLayout.addWidget(self.NoDitheringBox, 3, 2, 1, 1)
self.BorderBox = QtGui.QCheckBox(self.OptionsAdvanced)
self.BorderBox = QtWidgets.QCheckBox(self.OptionsAdvanced)
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setFamily("DejaVu Sans")
self.BorderBox.setFont(font)
self.BorderBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.BorderBox.setTristate(True)
self.BorderBox.setObjectName(_fromUtf8("BorderBox"))
self.BorderBox.setObjectName("BorderBox")
self.gridLayout.addWidget(self.BorderBox, 3, 0, 1, 1)
self.NoRotateBox = QtGui.QCheckBox(self.OptionsAdvanced)
self.NoRotateBox = QtWidgets.QCheckBox(self.OptionsAdvanced)
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setFamily("DejaVu Sans")
self.NoRotateBox.setFont(font)
self.NoRotateBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.NoRotateBox.setObjectName(_fromUtf8("NoRotateBox"))
self.NoRotateBox.setObjectName("NoRotateBox")
self.gridLayout.addWidget(self.NoRotateBox, 1, 2, 1, 1)
self.DeviceBox = QtGui.QComboBox(self.Form)
self.DeviceBox = QtWidgets.QComboBox(self.Form)
self.DeviceBox.setGeometry(QtCore.QRect(10, 200, 141, 31))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setFamily("DejaVu Sans")
font.setPointSize(8)
self.DeviceBox.setFont(font)
self.DeviceBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.DeviceBox.setObjectName(_fromUtf8("DeviceBox"))
self.FormatBox = QtGui.QComboBox(self.Form)
self.DeviceBox.setObjectName("DeviceBox")
self.FormatBox = QtWidgets.QComboBox(self.Form)
self.FormatBox.setGeometry(QtCore.QRect(260, 200, 151, 31))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setFamily("DejaVu Sans")
font.setPointSize(8)
self.FormatBox.setFont(font)
self.FormatBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.FormatBox.setObjectName(_fromUtf8("FormatBox"))
self.ConvertButton = QtGui.QPushButton(self.Form)
self.FormatBox.setObjectName("FormatBox")
self.ConvertButton = QtWidgets.QPushButton(self.Form)
self.ConvertButton.setGeometry(QtCore.QRect(160, 200, 91, 32))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setFamily("DejaVu Sans")
font.setPointSize(9)
font.setBold(True)
font.setWeight(75)
self.ConvertButton.setFont(font)
self.ConvertButton.setFocusPolicy(QtCore.Qt.NoFocus)
icon1 = QtGui.QIcon()
icon1.addPixmap(QtGui.QPixmap(_fromUtf8(":/Other/icons/convert.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon1.addPixmap(QtGui.QPixmap(":/Other/icons/convert.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.ConvertButton.setIcon(icon1)
self.ConvertButton.setObjectName(_fromUtf8("ConvertButton"))
self.DirectoryButton = QtGui.QPushButton(self.Form)
self.ConvertButton.setObjectName("ConvertButton")
self.DirectoryButton = QtWidgets.QPushButton(self.Form)
self.DirectoryButton.setGeometry(QtCore.QRect(10, 160, 141, 32))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setFamily("DejaVu Sans")
font.setPointSize(8)
self.DirectoryButton.setFont(font)
self.DirectoryButton.setFocusPolicy(QtCore.Qt.NoFocus)
icon2 = QtGui.QIcon()
icon2.addPixmap(QtGui.QPixmap(_fromUtf8(":/Other/icons/folder_new.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon2.addPixmap(QtGui.QPixmap(":/Other/icons/folder_new.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.DirectoryButton.setIcon(icon2)
self.DirectoryButton.setObjectName(_fromUtf8("DirectoryButton"))
self.FileButton = QtGui.QPushButton(self.Form)
self.DirectoryButton.setObjectName("DirectoryButton")
self.FileButton = QtWidgets.QPushButton(self.Form)
self.FileButton.setGeometry(QtCore.QRect(260, 160, 151, 32))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setFamily("DejaVu Sans")
font.setPointSize(8)
self.FileButton.setFont(font)
self.FileButton.setFocusPolicy(QtCore.Qt.NoFocus)
icon3 = QtGui.QIcon()
icon3.addPixmap(QtGui.QPixmap(_fromUtf8(":/Other/icons/document_new.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon3.addPixmap(QtGui.QPixmap(":/Other/icons/document_new.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.FileButton.setIcon(icon3)
self.FileButton.setObjectName(_fromUtf8("FileButton"))
self.ClearButton = QtGui.QPushButton(self.Form)
self.FileButton.setObjectName("FileButton")
self.ClearButton = QtWidgets.QPushButton(self.Form)
self.ClearButton.setGeometry(QtCore.QRect(160, 160, 91, 32))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setFamily("DejaVu Sans")
font.setPointSize(8)
self.ClearButton.setFont(font)
self.ClearButton.setFocusPolicy(QtCore.Qt.NoFocus)
icon4 = QtGui.QIcon()
icon4.addPixmap(QtGui.QPixmap(_fromUtf8(":/Other/icons/clear.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon4.addPixmap(QtGui.QPixmap(":/Other/icons/clear.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.ClearButton.setIcon(icon4)
self.ClearButton.setObjectName(_fromUtf8("ClearButton"))
self.OptionsBasic = QtGui.QFrame(self.Form)
self.ClearButton.setObjectName("ClearButton")
self.OptionsBasic = QtWidgets.QFrame(self.Form)
self.OptionsBasic.setGeometry(QtCore.QRect(1, 230, 421, 41))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setFamily("DejaVu Sans")
font.setPointSize(9)
self.OptionsBasic.setFont(font)
self.OptionsBasic.setObjectName(_fromUtf8("OptionsBasic"))
self.MangaBox = QtGui.QCheckBox(self.OptionsBasic)
self.OptionsBasic.setObjectName("OptionsBasic")
self.MangaBox = QtWidgets.QCheckBox(self.OptionsBasic)
self.MangaBox.setGeometry(QtCore.QRect(9, 10, 130, 18))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setFamily("DejaVu Sans")
self.MangaBox.setFont(font)
self.MangaBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.MangaBox.setObjectName(_fromUtf8("MangaBox"))
self.QualityBox = QtGui.QCheckBox(self.OptionsBasic)
self.MangaBox.setObjectName("MangaBox")
self.QualityBox = QtWidgets.QCheckBox(self.OptionsBasic)
self.QualityBox.setGeometry(QtCore.QRect(282, 10, 135, 18))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setFamily("DejaVu Sans")
self.QualityBox.setFont(font)
self.QualityBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.QualityBox.setTristate(True)
self.QualityBox.setObjectName(_fromUtf8("QualityBox"))
self.RotateBox = QtGui.QCheckBox(self.OptionsBasic)
self.QualityBox.setObjectName("QualityBox")
self.RotateBox = QtWidgets.QCheckBox(self.OptionsBasic)
self.RotateBox.setGeometry(QtCore.QRect(145, 10, 130, 18))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setFamily("DejaVu Sans")
self.RotateBox.setFont(font)
self.RotateBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.RotateBox.setObjectName(_fromUtf8("RotateBox"))
self.JobList = QtGui.QListWidget(self.Form)
self.RotateBox.setObjectName("RotateBox")
self.JobList = QtWidgets.QListWidget(self.Form)
self.JobList.setGeometry(QtCore.QRect(10, 50, 401, 101))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setFamily("DejaVu Sans")
font.setPointSize(8)
font.setItalic(False)
self.JobList.setFont(font)
self.JobList.setFocusPolicy(QtCore.Qt.NoFocus)
self.JobList.setStyleSheet(_fromUtf8("QListWidget#JobList {background:#ffffff;background-image:url(:/Other/icons/list_background.png);background-position:center center;background-repeat:no-repeat;}QScrollBar:vertical{border:1px solid #999;background:#FFF;width:5px;margin:0}QScrollBar::handle:vertical{background:DarkGray;min-height:0}QScrollBar::add-line:vertical{height:0;background:DarkGray;subcontrol-position:bottom;subcontrol-origin:margin}QScrollBar::sub-line:vertical{height:0;background:DarkGray;subcontrol-position:top;subcontrol-origin:margin}QScrollBar:horizontal{border:1px solid #999;background:#FFF;height:5px;margin:0}QScrollBar::handle:horizontal{background:DarkGray;min-width:0}QScrollBar::add-line:horizontal{width:0;background:DarkGray;subcontrol-position:bottom;subcontrol-origin:margin}QScrollBar::sub-line:horizontal{width:0;background:DarkGray;subcontrol-position:top;subcontrol-origin:margin}"))
self.JobList.setStyleSheet("QListWidget#JobList {background:#ffffff;background-image:url(:/Other/icons/list_background.png);background-position:center center;background-repeat:no-repeat;}QScrollBar:vertical{border:1px solid #999;background:#FFF;width:5px;margin:0}QScrollBar::handle:vertical{background:DarkGray;min-height:0}QScrollBar::add-line:vertical{height:0;background:DarkGray;subcontrol-position:bottom;subcontrol-origin:margin}QScrollBar::sub-line:vertical{height:0;background:DarkGray;subcontrol-position:top;subcontrol-origin:margin}QScrollBar:horizontal{border:1px solid #999;background:#FFF;height:5px;margin:0}QScrollBar::handle:horizontal{background:DarkGray;min-width:0}QScrollBar::add-line:horizontal{width:0;background:DarkGray;subcontrol-position:bottom;subcontrol-origin:margin}QScrollBar::sub-line:horizontal{width:0;background:DarkGray;subcontrol-position:top;subcontrol-origin:margin}")
self.JobList.setProperty("showDropIndicator", False)
self.JobList.setSelectionMode(QtGui.QAbstractItemView.NoSelection)
self.JobList.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)
self.JobList.setIconSize(QtCore.QSize(18, 18))
self.JobList.setVerticalScrollMode(QtGui.QAbstractItemView.ScrollPerPixel)
self.JobList.setHorizontalScrollMode(QtGui.QAbstractItemView.ScrollPerPixel)
self.JobList.setObjectName(_fromUtf8("JobList"))
self.BasicModeButton = QtGui.QPushButton(self.Form)
self.JobList.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
self.JobList.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
self.JobList.setObjectName("JobList")
self.BasicModeButton = QtWidgets.QPushButton(self.Form)
self.BasicModeButton.setGeometry(QtCore.QRect(10, 10, 195, 32))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setFamily("DejaVu Sans")
font.setPointSize(9)
self.BasicModeButton.setFont(font)
self.BasicModeButton.setFocusPolicy(QtCore.Qt.NoFocus)
self.BasicModeButton.setObjectName(_fromUtf8("BasicModeButton"))
self.AdvModeButton = QtGui.QPushButton(self.Form)
self.BasicModeButton.setObjectName("BasicModeButton")
self.AdvModeButton = QtWidgets.QPushButton(self.Form)
self.AdvModeButton.setGeometry(QtCore.QRect(217, 10, 195, 32))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setFamily("DejaVu Sans")
font.setPointSize(9)
self.AdvModeButton.setFont(font)
self.AdvModeButton.setFocusPolicy(QtCore.Qt.NoFocus)
self.AdvModeButton.setObjectName(_fromUtf8("AdvModeButton"))
self.OptionsAdvancedGamma = QtGui.QFrame(self.Form)
self.AdvModeButton.setObjectName("AdvModeButton")
self.OptionsAdvancedGamma = QtWidgets.QFrame(self.Form)
self.OptionsAdvancedGamma.setEnabled(True)
self.OptionsAdvancedGamma.setGeometry(QtCore.QRect(10, 305, 401, 41))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setFamily("DejaVu Sans")
font.setPointSize(9)
self.OptionsAdvancedGamma.setFont(font)
self.OptionsAdvancedGamma.setObjectName(_fromUtf8("OptionsAdvancedGamma"))
self.GammaLabel = QtGui.QLabel(self.OptionsAdvancedGamma)
self.OptionsAdvancedGamma.setObjectName("OptionsAdvancedGamma")
self.GammaLabel = QtWidgets.QLabel(self.OptionsAdvancedGamma)
self.GammaLabel.setGeometry(QtCore.QRect(15, 0, 100, 40))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setFamily("DejaVu Sans")
self.GammaLabel.setFont(font)
self.GammaLabel.setObjectName(_fromUtf8("GammaLabel"))
self.GammaSlider = QtGui.QSlider(self.OptionsAdvancedGamma)
self.GammaLabel.setObjectName("GammaLabel")
self.GammaSlider = QtWidgets.QSlider(self.OptionsAdvancedGamma)
self.GammaSlider.setGeometry(QtCore.QRect(110, 10, 275, 22))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setFamily("DejaVu Sans")
self.GammaSlider.setFont(font)
self.GammaSlider.setFocusPolicy(QtCore.Qt.ClickFocus)
self.GammaSlider.setMaximum(500)
self.GammaSlider.setSingleStep(5)
self.GammaSlider.setOrientation(QtCore.Qt.Horizontal)
self.GammaSlider.setObjectName(_fromUtf8("GammaSlider"))
self.ProgressBar = QtGui.QProgressBar(self.Form)
self.GammaSlider.setObjectName("GammaSlider")
self.ProgressBar = QtWidgets.QProgressBar(self.Form)
self.ProgressBar.setGeometry(QtCore.QRect(10, 10, 401, 31))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setFamily("DejaVu Sans")
font.setPointSize(10)
font.setBold(True)
font.setWeight(75)
self.ProgressBar.setFont(font)
self.ProgressBar.setProperty("value", 0)
self.ProgressBar.setAlignment(QtCore.Qt.AlignJustify|QtCore.Qt.AlignVCenter)
self.ProgressBar.setFormat(_fromUtf8(""))
self.ProgressBar.setObjectName(_fromUtf8("ProgressBar"))
self.OptionsExpert = QtGui.QFrame(self.Form)
self.ProgressBar.setFormat("")
self.ProgressBar.setObjectName("ProgressBar")
self.OptionsExpert = QtWidgets.QFrame(self.Form)
self.OptionsExpert.setGeometry(QtCore.QRect(1, 337, 421, 41))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setFamily("DejaVu Sans")
font.setPointSize(9)
self.OptionsExpert.setFont(font)
self.OptionsExpert.setObjectName(_fromUtf8("OptionsExpert"))
self.ColorBox = QtGui.QCheckBox(self.OptionsExpert)
self.OptionsExpert.setObjectName("OptionsExpert")
self.ColorBox = QtWidgets.QCheckBox(self.OptionsExpert)
self.ColorBox.setGeometry(QtCore.QRect(9, 11, 130, 18))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setFamily("DejaVu Sans")
self.ColorBox.setFont(font)
self.ColorBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.ColorBox.setObjectName(_fromUtf8("ColorBox"))
self.OptionsExpertInternal = QtGui.QFrame(self.OptionsExpert)
self.ColorBox.setObjectName("ColorBox")
self.OptionsExpertInternal = QtWidgets.QFrame(self.OptionsExpert)
self.OptionsExpertInternal.setGeometry(QtCore.QRect(105, 0, 295, 40))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setFamily("DejaVu Sans")
self.OptionsExpertInternal.setFont(font)
self.OptionsExpertInternal.setObjectName(_fromUtf8("OptionsExpertInternal"))
self.gridLayout_2 = QtGui.QGridLayout(self.OptionsExpertInternal)
self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2"))
self.wLabel = QtGui.QLabel(self.OptionsExpertInternal)
self.OptionsExpertInternal.setObjectName("OptionsExpertInternal")
self.gridLayout_2 = QtWidgets.QGridLayout(self.OptionsExpertInternal)
self.gridLayout_2.setObjectName("gridLayout_2")
self.wLabel = QtWidgets.QLabel(self.OptionsExpertInternal)
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setFamily("DejaVu Sans")
self.wLabel.setFont(font)
self.wLabel.setObjectName(_fromUtf8("wLabel"))
self.wLabel.setObjectName("wLabel")
self.gridLayout_2.addWidget(self.wLabel, 0, 0, 1, 1)
self.customWidth = QtGui.QLineEdit(self.OptionsExpertInternal)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
self.customWidth = QtWidgets.QLineEdit(self.OptionsExpertInternal)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.customWidth.sizePolicy().hasHeightForWidth())
self.customWidth.setSizePolicy(sizePolicy)
self.customWidth.setMaximumSize(QtCore.QSize(40, 16777215))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setFamily("DejaVu Sans")
self.customWidth.setFont(font)
self.customWidth.setFocusPolicy(QtCore.Qt.ClickFocus)
self.customWidth.setAcceptDrops(False)
self.customWidth.setMaxLength(4)
self.customWidth.setObjectName(_fromUtf8("customWidth"))
self.customWidth.setObjectName("customWidth")
self.gridLayout_2.addWidget(self.customWidth, 0, 1, 1, 1)
self.hLabel = QtGui.QLabel(self.OptionsExpertInternal)
self.hLabel = QtWidgets.QLabel(self.OptionsExpertInternal)
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setFamily("DejaVu Sans")
self.hLabel.setFont(font)
self.hLabel.setObjectName(_fromUtf8("hLabel"))
self.hLabel.setObjectName("hLabel")
self.gridLayout_2.addWidget(self.hLabel, 0, 2, 1, 1)
self.customHeight = QtGui.QLineEdit(self.OptionsExpertInternal)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
self.customHeight = QtWidgets.QLineEdit(self.OptionsExpertInternal)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.customHeight.sizePolicy().hasHeightForWidth())
self.customHeight.setSizePolicy(sizePolicy)
self.customHeight.setMaximumSize(QtCore.QSize(40, 16777215))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setFamily("DejaVu Sans")
self.customHeight.setFont(font)
self.customHeight.setFocusPolicy(QtCore.Qt.ClickFocus)
self.customHeight.setAcceptDrops(False)
self.customHeight.setMaxLength(4)
self.customHeight.setObjectName(_fromUtf8("customHeight"))
self.customHeight.setObjectName("customHeight")
self.gridLayout_2.addWidget(self.customHeight, 0, 3, 1, 1)
KCC.setCentralWidget(self.Form)
self.ActionBasic = QtGui.QAction(KCC)
self.statusBar = QtWidgets.QStatusBar(KCC)
font = QtGui.QFont()
font.setFamily("DejaVu Sans")
font.setPointSize(8)
self.statusBar.setFont(font)
self.statusBar.setSizeGripEnabled(False)
self.statusBar.setObjectName("statusBar")
KCC.setStatusBar(self.statusBar)
self.ActionBasic = QtWidgets.QAction(KCC)
self.ActionBasic.setCheckable(True)
self.ActionBasic.setChecked(False)
font = QtGui.QFont()
self.ActionBasic.setFont(font)
self.ActionBasic.setObjectName(_fromUtf8("ActionBasic"))
self.ActionAdvanced = QtGui.QAction(KCC)
self.ActionBasic.setObjectName("ActionBasic")
self.ActionAdvanced = QtWidgets.QAction(KCC)
self.ActionAdvanced.setCheckable(True)
self.ActionAdvanced.setObjectName(_fromUtf8("ActionAdvanced"))
self.ActionAdvanced.setObjectName("ActionAdvanced")
self.retranslateUi(KCC)
QtCore.QMetaObject.connectSlotsByName(KCC)
@@ -334,53 +327,47 @@ class Ui_KCC(object):
KCC.setTabOrder(self.ConvertButton, self.ClearButton)
def retranslateUi(self, KCC):
KCC.setWindowTitle(_translate("KCC", "Kindle Comic Converter", None))
self.ProcessingBox.setToolTip(_translate("KCC", "Disable image optimizations.", None))
self.ProcessingBox.setText(_translate("KCC", "No optimisation", None))
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>", None))
self.UpscaleBox.setText(_translate("KCC", "Stretch/Upscale", None))
self.WebtoonBox.setToolTip(_translate("KCC", "<html><head/><body><p>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>", None))
self.WebtoonBox.setText(_translate("KCC", "Webtoon mode", None))
self.NoDitheringBox.setToolTip(_translate("KCC", "<html><head/><body><p>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>", None))
self.NoDitheringBox.setText(_translate("KCC", "PNG output", None))
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>", None))
self.BorderBox.setText(_translate("KCC", "W/B margins", None))
self.NoRotateBox.setToolTip(_translate("KCC", "<html><head/><body><p>Disable splitting and rotation.</p></body></html>", None))
self.NoRotateBox.setText(_translate("KCC", "No split/rotate", None))
self.DeviceBox.setToolTip(_translate("KCC", "Target device.", None))
self.FormatBox.setToolTip(_translate("KCC", "Output format.", None))
self.ConvertButton.setText(_translate("KCC", "Convert", None))
self.DirectoryButton.setText(_translate("KCC", "Add directory", None))
self.FileButton.setText(_translate("KCC", "Add file", None))
self.ClearButton.setText(_translate("KCC", "Clear list", None))
self.MangaBox.setToolTip(_translate("KCC", "Enable right-to-left reading.", None))
self.MangaBox.setText(_translate("KCC", "Manga mode", None))
self.QualityBox.setToolTip(_translate("KCC", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n"
"</style></head><body style=\" font-family:\'Sans\'; font-size:9pt; font-weight:400; font-style:normal;\">\n"
"<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-weight:600; text-decoration: underline;\">Unchecked - Normal quality mode<br /></span><span style=\" font-family:\'MS Shell Dlg 2\'; font-style:italic;\">Use it when Panel View support is not needed.</span><span style=\" font-family:\'MS Shell Dlg 2\'; font-weight:600; text-decoration: underline;\"><br /></span><span style=\" font-family:\'MS Shell Dlg 2\';\">- Maximum quality when zoom is not enabled.<br />- Poor quality when zoom is enabled.<br />- Lowest file size.</span></p>\n"
"<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-weight:600; text-decoration: underline;\">Indeterminate - High quality mode<br /></span><span style=\" font-family:\'MS Shell Dlg 2\'; font-style:italic;\">Not zoomed image </span><span style=\" font-family:\'MS Shell Dlg 2\'; font-weight:600; font-style:italic;\">might </span><span style=\" font-family:\'MS Shell Dlg 2\'; font-style:italic;\">be a little blurry.</span><span style=\" font-family:\'MS Shell Dlg 2\'; font-weight:600; text-decoration: underline;\"><br /></span><span style=\" font-family:\'MS Shell Dlg 2\';\">- Medium/High quality when zoom is not enabled.<br />- Maximum quality when zoom is enabled.</span></p>\n"
"<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-weight:600; text-decoration: underline;\">Checked - Ultra quality mode<br /></span><span style=\" font-family:\'MS Shell Dlg 2\'; font-style:italic;\">Maximum possible quality.</span><span style=\" font-family:\'MS Shell Dlg 2\'; font-weight:600; text-decoration: underline;\"><br /></span><span style=\" font-family:\'MS Shell Dlg 2\';\">- Maximum quality when zoom is not enabled.<br />- Maximum quality when zoom is enabled.<br />- Very high file size.</span></p></body></html>", None))
self.QualityBox.setText(_translate("KCC", "High/Ultra quality", None))
self.RotateBox.setToolTip(_translate("KCC", "<html><head/><body><p>Disable page spliting.<br/>They will be rotated instead.</p></body></html>", None))
self.RotateBox.setText(_translate("KCC", "Horizontal mode", None))
self.BasicModeButton.setText(_translate("KCC", "Basic", None))
self.AdvModeButton.setText(_translate("KCC", "Advanced", None))
self.GammaLabel.setToolTip(_translate("KCC", "<html><head/><body><p>When converting color images setting this option to 1.0 <span style=\" font-weight:600;\">might</span> improve readability.</p></body></html>", None))
self.GammaLabel.setText(_translate("KCC", "Gamma: Auto", None))
self.GammaSlider.setToolTip(_translate("KCC", "<html><head/><body><p>When converting color images setting this option to 1.0 <span style=\" font-weight:600;\">might</span> improve readability.</p></body></html>", None))
self.ColorBox.setToolTip(_translate("KCC", "Do not convert images to grayscale.", None))
self.ColorBox.setText(_translate("KCC", "Color mode", None))
self.wLabel.setToolTip(_translate("KCC", "Resolution of target device.", None))
self.wLabel.setText(_translate("KCC", "Custom width: ", None))
self.customWidth.setToolTip(_translate("KCC", "Resolution of target device.", None))
self.customWidth.setInputMask(_translate("KCC", "0000; ", None))
self.hLabel.setToolTip(_translate("KCC", "Resolution of target device.", None))
self.hLabel.setText(_translate("KCC", "Custom height: ", None))
self.customHeight.setToolTip(_translate("KCC", "Resolution of target device.", None))
self.customHeight.setInputMask(_translate("KCC", "0000; ", None))
self.ActionBasic.setText(_translate("KCC", "Basic", None))
self.ActionAdvanced.setText(_translate("KCC", "Advanced", None))
_translate = QtCore.QCoreApplication.translate
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.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.setText(_translate("KCC", "Stretch/Upscale"))
self.WebtoonBox.setToolTip(_translate("KCC", "<html><head/><body><p>Enable auto-splitting of webtoons like <span style=\" font-style:italic;\">Tower of God</span> or <span style=\" font-style:italic;\">Noblesse</span>.<br/>This mode was created for pages with a low width, high height and vertical panel flow.</p></body></html>"))
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.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.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.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.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.setText(_translate("KCC", "Convert"))
self.DirectoryButton.setText(_translate("KCC", "Add directory"))
self.FileButton.setText(_translate("KCC", "Add file"))
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.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</span><br/>Maximal quality of images but very poor magnification quality.<br/>Use it only when zoom is not needed or output files needs to be small.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - High quality mode</span><br/>In most cases high quality of images and magnification.<br/>Overall quality highly depends on the resolution of source files.<br/>On Kindle models older than Paperwhite non-zoomed images might be a little blurred.<br/><br/><span style=\" font-weight:600; text-decoration: underline;\">Checked - Ultra quality mode</span><br/>Highest possible quality. Output files will be big.</p></body></html>"))
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.setText(_translate("KCC", "Horizontal mode"))
self.BasicModeButton.setText(_translate("KCC", "Basic"))
self.AdvModeButton.setText(_translate("KCC", "Advanced"))
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.setText(_translate("KCC", "Color mode"))
self.wLabel.setToolTip(_translate("KCC", "<html><head/><body><p>Resolution of target device.</p></body></html>"))
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.setInputMask(_translate("KCC", "0000"))
self.hLabel.setToolTip(_translate("KCC", "<html><head/><body><p>Resolution of target device.</p></body></html>"))
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.setInputMask(_translate("KCC", "0000"))
self.ActionBasic.setText(_translate("KCC", "Basic"))
self.ActionAdvanced.setText(_translate("KCC", "Advanced"))
import KCC_rc
from . import KCC_rc

View File

@@ -2,354 +2,346 @@
# Form implementation generated from reading ui file 'KCC-OSX.ui'
#
# Created: Sat Oct 12 11:28:19 2013
# by: PyQt4 UI code generator 4.10.3
# Created: Sun May 18 09:08:44 2014
# by: PyQt5 UI code generator 5.2.1
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s
try:
_encoding = QtGui.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_KCC(object):
def setupUi(self, KCC):
KCC.setObjectName(_fromUtf8("KCC"))
KCC.resize(420, 380)
KCC.setMinimumSize(QtCore.QSize(420, 380))
KCC.setMaximumSize(QtCore.QSize(420, 380))
KCC.setObjectName("KCC")
KCC.resize(420, 397)
KCC.setMinimumSize(QtCore.QSize(420, 397))
KCC.setMaximumSize(QtCore.QSize(420, 397))
font = QtGui.QFont()
font.setPointSize(9)
KCC.setFont(font)
KCC.setFocusPolicy(QtCore.Qt.NoFocus)
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(_fromUtf8(":/Icon/icons/comic2ebook.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon.addPixmap(QtGui.QPixmap(":/Icon/icons/comic2ebook.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
KCC.setWindowIcon(icon)
KCC.setLocale(QtCore.QLocale(QtCore.QLocale.C, QtCore.QLocale.AnyCountry))
self.Form = QtGui.QWidget(KCC)
self.Form.setObjectName(_fromUtf8("Form"))
self.OptionsAdvanced = QtGui.QFrame(self.Form)
self.Form = QtWidgets.QWidget(KCC)
self.Form.setObjectName("Form")
self.OptionsAdvanced = QtWidgets.QFrame(self.Form)
self.OptionsAdvanced.setEnabled(True)
self.OptionsAdvanced.setGeometry(QtCore.QRect(4, 253, 421, 61))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setFamily("Lucida Grande")
font.setPointSize(9)
self.OptionsAdvanced.setFont(font)
self.OptionsAdvanced.setObjectName(_fromUtf8("OptionsAdvanced"))
self.gridLayout = QtGui.QGridLayout(self.OptionsAdvanced)
self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
self.ProcessingBox = QtGui.QCheckBox(self.OptionsAdvanced)
self.OptionsAdvanced.setObjectName("OptionsAdvanced")
self.gridLayout = QtWidgets.QGridLayout(self.OptionsAdvanced)
self.gridLayout.setObjectName("gridLayout")
self.ProcessingBox = QtWidgets.QCheckBox(self.OptionsAdvanced)
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setFamily("Lucida Grande")
font.setPointSize(12)
self.ProcessingBox.setFont(font)
self.ProcessingBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.ProcessingBox.setObjectName(_fromUtf8("ProcessingBox"))
self.ProcessingBox.setObjectName("ProcessingBox")
self.gridLayout.addWidget(self.ProcessingBox, 1, 0, 1, 1)
self.UpscaleBox = QtGui.QCheckBox(self.OptionsAdvanced)
self.UpscaleBox = QtWidgets.QCheckBox(self.OptionsAdvanced)
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setFamily("Lucida Grande")
font.setPointSize(12)
self.UpscaleBox.setFont(font)
self.UpscaleBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.UpscaleBox.setTristate(True)
self.UpscaleBox.setObjectName(_fromUtf8("UpscaleBox"))
self.UpscaleBox.setObjectName("UpscaleBox")
self.gridLayout.addWidget(self.UpscaleBox, 1, 1, 1, 1)
self.WebtoonBox = QtGui.QCheckBox(self.OptionsAdvanced)
self.WebtoonBox = QtWidgets.QCheckBox(self.OptionsAdvanced)
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setFamily("Lucida Grande")
font.setPointSize(12)
self.WebtoonBox.setFont(font)
self.WebtoonBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.WebtoonBox.setObjectName(_fromUtf8("WebtoonBox"))
self.WebtoonBox.setObjectName("WebtoonBox")
self.gridLayout.addWidget(self.WebtoonBox, 3, 1, 1, 1)
self.NoDitheringBox = QtGui.QCheckBox(self.OptionsAdvanced)
self.NoDitheringBox = QtWidgets.QCheckBox(self.OptionsAdvanced)
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setFamily("Lucida Grande")
font.setPointSize(12)
self.NoDitheringBox.setFont(font)
self.NoDitheringBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.NoDitheringBox.setObjectName(_fromUtf8("NoDitheringBox"))
self.NoDitheringBox.setObjectName("NoDitheringBox")
self.gridLayout.addWidget(self.NoDitheringBox, 3, 2, 1, 1)
self.BorderBox = QtGui.QCheckBox(self.OptionsAdvanced)
self.BorderBox = QtWidgets.QCheckBox(self.OptionsAdvanced)
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setFamily("Lucida Grande")
font.setPointSize(12)
self.BorderBox.setFont(font)
self.BorderBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.BorderBox.setTristate(True)
self.BorderBox.setObjectName(_fromUtf8("BorderBox"))
self.BorderBox.setObjectName("BorderBox")
self.gridLayout.addWidget(self.BorderBox, 3, 0, 1, 1)
self.NoRotateBox = QtGui.QCheckBox(self.OptionsAdvanced)
self.NoRotateBox = QtWidgets.QCheckBox(self.OptionsAdvanced)
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setFamily("Lucida Grande")
font.setPointSize(12)
self.NoRotateBox.setFont(font)
self.NoRotateBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.NoRotateBox.setObjectName(_fromUtf8("NoRotateBox"))
self.NoRotateBox.setObjectName("NoRotateBox")
self.gridLayout.addWidget(self.NoRotateBox, 1, 2, 1, 1)
self.DeviceBox = QtGui.QComboBox(self.Form)
self.DeviceBox = QtWidgets.QComboBox(self.Form)
self.DeviceBox.setGeometry(QtCore.QRect(8, 201, 151, 34))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setFamily("Lucida Grande")
font.setPointSize(11)
self.DeviceBox.setFont(font)
self.DeviceBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.DeviceBox.setObjectName(_fromUtf8("DeviceBox"))
self.FormatBox = QtGui.QComboBox(self.Form)
self.DeviceBox.setObjectName("DeviceBox")
self.FormatBox = QtWidgets.QComboBox(self.Form)
self.FormatBox.setGeometry(QtCore.QRect(262, 201, 152, 34))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setFamily("Lucida Grande")
font.setPointSize(11)
self.FormatBox.setFont(font)
self.FormatBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.FormatBox.setObjectName(_fromUtf8("FormatBox"))
self.ConvertButton = QtGui.QPushButton(self.Form)
self.FormatBox.setObjectName("FormatBox")
self.ConvertButton = QtWidgets.QPushButton(self.Form)
self.ConvertButton.setGeometry(QtCore.QRect(160, 200, 101, 41))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setFamily("Lucida Grande")
font.setPointSize(11)
font.setBold(True)
font.setWeight(75)
self.ConvertButton.setFont(font)
self.ConvertButton.setFocusPolicy(QtCore.Qt.NoFocus)
icon1 = QtGui.QIcon()
icon1.addPixmap(QtGui.QPixmap(_fromUtf8(":/Other/icons/convert.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon1.addPixmap(QtGui.QPixmap(":/Other/icons/convert.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.ConvertButton.setIcon(icon1)
self.ConvertButton.setObjectName(_fromUtf8("ConvertButton"))
self.DirectoryButton = QtGui.QPushButton(self.Form)
self.ConvertButton.setObjectName("ConvertButton")
self.DirectoryButton = QtWidgets.QPushButton(self.Form)
self.DirectoryButton.setGeometry(QtCore.QRect(5, 160, 156, 41))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setFamily("Lucida Grande")
font.setPointSize(11)
self.DirectoryButton.setFont(font)
self.DirectoryButton.setFocusPolicy(QtCore.Qt.NoFocus)
icon2 = QtGui.QIcon()
icon2.addPixmap(QtGui.QPixmap(_fromUtf8(":/Other/icons/folder_new.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon2.addPixmap(QtGui.QPixmap(":/Other/icons/folder_new.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.DirectoryButton.setIcon(icon2)
self.DirectoryButton.setObjectName(_fromUtf8("DirectoryButton"))
self.FileButton = QtGui.QPushButton(self.Form)
self.DirectoryButton.setObjectName("DirectoryButton")
self.FileButton = QtWidgets.QPushButton(self.Form)
self.FileButton.setGeometry(QtCore.QRect(260, 160, 157, 41))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setFamily("Lucida Grande")
font.setPointSize(11)
self.FileButton.setFont(font)
self.FileButton.setFocusPolicy(QtCore.Qt.NoFocus)
icon3 = QtGui.QIcon()
icon3.addPixmap(QtGui.QPixmap(_fromUtf8(":/Other/icons/document_new.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon3.addPixmap(QtGui.QPixmap(":/Other/icons/document_new.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.FileButton.setIcon(icon3)
self.FileButton.setObjectName(_fromUtf8("FileButton"))
self.ClearButton = QtGui.QPushButton(self.Form)
self.FileButton.setObjectName("FileButton")
self.ClearButton = QtWidgets.QPushButton(self.Form)
self.ClearButton.setGeometry(QtCore.QRect(160, 160, 101, 41))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setFamily("Lucida Grande")
font.setPointSize(11)
self.ClearButton.setFont(font)
self.ClearButton.setFocusPolicy(QtCore.Qt.NoFocus)
icon4 = QtGui.QIcon()
icon4.addPixmap(QtGui.QPixmap(_fromUtf8(":/Other/icons/clear.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
icon4.addPixmap(QtGui.QPixmap(":/Other/icons/clear.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.ClearButton.setIcon(icon4)
self.ClearButton.setObjectName(_fromUtf8("ClearButton"))
self.OptionsBasic = QtGui.QFrame(self.Form)
self.ClearButton.setObjectName("ClearButton")
self.OptionsBasic = QtWidgets.QFrame(self.Form)
self.OptionsBasic.setGeometry(QtCore.QRect(5, 233, 421, 41))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setFamily("Lucida Grande")
font.setPointSize(12)
self.OptionsBasic.setFont(font)
self.OptionsBasic.setObjectName(_fromUtf8("OptionsBasic"))
self.MangaBox = QtGui.QCheckBox(self.OptionsBasic)
self.OptionsBasic.setObjectName("OptionsBasic")
self.MangaBox = QtWidgets.QCheckBox(self.OptionsBasic)
self.MangaBox.setGeometry(QtCore.QRect(9, 10, 130, 18))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setFamily("Lucida Grande")
font.setPointSize(12)
self.MangaBox.setFont(font)
self.MangaBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.MangaBox.setObjectName(_fromUtf8("MangaBox"))
self.QualityBox = QtGui.QCheckBox(self.OptionsBasic)
self.MangaBox.setObjectName("MangaBox")
self.QualityBox = QtWidgets.QCheckBox(self.OptionsBasic)
self.QualityBox.setGeometry(QtCore.QRect(282, 10, 135, 18))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setFamily("Lucida Grande")
font.setPointSize(12)
self.QualityBox.setFont(font)
self.QualityBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.QualityBox.setTristate(True)
self.QualityBox.setObjectName(_fromUtf8("QualityBox"))
self.RotateBox = QtGui.QCheckBox(self.OptionsBasic)
self.QualityBox.setObjectName("QualityBox")
self.RotateBox = QtWidgets.QCheckBox(self.OptionsBasic)
self.RotateBox.setGeometry(QtCore.QRect(145, 10, 130, 18))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setFamily("Lucida Grande")
font.setPointSize(12)
self.RotateBox.setFont(font)
self.RotateBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.RotateBox.setObjectName(_fromUtf8("RotateBox"))
self.JobList = QtGui.QListWidget(self.Form)
self.RotateBox.setObjectName("RotateBox")
self.JobList = QtWidgets.QListWidget(self.Form)
self.JobList.setGeometry(QtCore.QRect(10, 50, 401, 101))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setFamily("Lucida Grande")
font.setPointSize(11)
self.JobList.setFont(font)
self.JobList.setFocusPolicy(QtCore.Qt.NoFocus)
self.JobList.setStyleSheet(_fromUtf8("QListWidget#JobList {background:#ffffff;background-image:url(:/Other/icons/list_background.png);background-position:center center;background-repeat:no-repeat;}QScrollBar:vertical{border:1px solid #999;background:#FFF;width:5px;margin:0}QScrollBar::handle:vertical{background:DarkGray;min-height:0}QScrollBar::add-line:vertical{height:0;background:DarkGray;subcontrol-position:bottom;subcontrol-origin:margin}QScrollBar::sub-line:vertical{height:0;background:DarkGray;subcontrol-position:top;subcontrol-origin:margin}QScrollBar:horizontal{border:1px solid #999;background:#FFF;height:5px;margin:0}QScrollBar::handle:horizontal{background:DarkGray;min-width:0}QScrollBar::add-line:horizontal{width:0;background:DarkGray;subcontrol-position:bottom;subcontrol-origin:margin}QScrollBar::sub-line:horizontal{width:0;background:DarkGray;subcontrol-position:top;subcontrol-origin:margin}"))
self.JobList.setStyleSheet("QListWidget#JobList {background:#ffffff;background-image:url(:/Other/icons/list_background.png);background-position:center center;background-repeat:no-repeat;}QScrollBar:vertical{border:1px solid #999;background:#FFF;width:5px;margin:0}QScrollBar::handle:vertical{background:DarkGray;min-height:0}QScrollBar::add-line:vertical{height:0;background:DarkGray;subcontrol-position:bottom;subcontrol-origin:margin}QScrollBar::sub-line:vertical{height:0;background:DarkGray;subcontrol-position:top;subcontrol-origin:margin}QScrollBar:horizontal{border:1px solid #999;background:#FFF;height:5px;margin:0}QScrollBar::handle:horizontal{background:DarkGray;min-width:0}QScrollBar::add-line:horizontal{width:0;background:DarkGray;subcontrol-position:bottom;subcontrol-origin:margin}QScrollBar::sub-line:horizontal{width:0;background:DarkGray;subcontrol-position:top;subcontrol-origin:margin}")
self.JobList.setProperty("showDropIndicator", False)
self.JobList.setSelectionMode(QtGui.QAbstractItemView.NoSelection)
self.JobList.setVerticalScrollMode(QtGui.QAbstractItemView.ScrollPerPixel)
self.JobList.setHorizontalScrollMode(QtGui.QAbstractItemView.ScrollPerPixel)
self.JobList.setObjectName(_fromUtf8("JobList"))
self.BasicModeButton = QtGui.QPushButton(self.Form)
self.JobList.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)
self.JobList.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
self.JobList.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
self.JobList.setObjectName("JobList")
self.BasicModeButton = QtWidgets.QPushButton(self.Form)
self.BasicModeButton.setGeometry(QtCore.QRect(5, 10, 210, 41))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setFamily("Lucida Grande")
font.setPointSize(12)
font.setBold(False)
font.setWeight(50)
self.BasicModeButton.setFont(font)
self.BasicModeButton.setFocusPolicy(QtCore.Qt.NoFocus)
self.BasicModeButton.setObjectName(_fromUtf8("BasicModeButton"))
self.AdvModeButton = QtGui.QPushButton(self.Form)
self.BasicModeButton.setObjectName("BasicModeButton")
self.AdvModeButton = QtWidgets.QPushButton(self.Form)
self.AdvModeButton.setGeometry(QtCore.QRect(207, 10, 210, 41))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setFamily("Lucida Grande")
font.setPointSize(12)
font.setBold(False)
font.setWeight(50)
self.AdvModeButton.setFont(font)
self.AdvModeButton.setFocusPolicy(QtCore.Qt.NoFocus)
self.AdvModeButton.setObjectName(_fromUtf8("AdvModeButton"))
self.OptionsAdvancedGamma = QtGui.QFrame(self.Form)
self.AdvModeButton.setObjectName("AdvModeButton")
self.OptionsAdvancedGamma = QtWidgets.QFrame(self.Form)
self.OptionsAdvancedGamma.setEnabled(True)
self.OptionsAdvancedGamma.setGeometry(QtCore.QRect(5, 303, 401, 41))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setFamily("Lucida Grande")
font.setPointSize(9)
self.OptionsAdvancedGamma.setFont(font)
self.OptionsAdvancedGamma.setObjectName(_fromUtf8("OptionsAdvancedGamma"))
self.GammaLabel = QtGui.QLabel(self.OptionsAdvancedGamma)
self.OptionsAdvancedGamma.setObjectName("OptionsAdvancedGamma")
self.GammaLabel = QtWidgets.QLabel(self.OptionsAdvancedGamma)
self.GammaLabel.setGeometry(QtCore.QRect(20, 0, 100, 40))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setFamily("Lucida Grande")
font.setPointSize(12)
font.setBold(False)
font.setWeight(50)
self.GammaLabel.setFont(font)
self.GammaLabel.setObjectName(_fromUtf8("GammaLabel"))
self.GammaSlider = QtGui.QSlider(self.OptionsAdvancedGamma)
self.GammaLabel.setObjectName("GammaLabel")
self.GammaSlider = QtWidgets.QSlider(self.OptionsAdvancedGamma)
self.GammaSlider.setGeometry(QtCore.QRect(110, 10, 290, 22))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setFamily("Lucida Grande")
self.GammaSlider.setFont(font)
self.GammaSlider.setFocusPolicy(QtCore.Qt.ClickFocus)
self.GammaSlider.setMaximum(500)
self.GammaSlider.setSingleStep(5)
self.GammaSlider.setOrientation(QtCore.Qt.Horizontal)
self.GammaSlider.setObjectName(_fromUtf8("GammaSlider"))
self.ProgressBar = QtGui.QProgressBar(self.Form)
self.ProgressBar.setGeometry(QtCore.QRect(10, 10, 401, 35))
self.GammaSlider.setObjectName("GammaSlider")
self.ProgressBar = QtWidgets.QProgressBar(self.Form)
self.ProgressBar.setGeometry(QtCore.QRect(10, 10, 401, 29))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setFamily("Lucida Grande")
font.setPointSize(10)
font.setBold(True)
font.setWeight(75)
self.ProgressBar.setFont(font)
self.ProgressBar.setAutoFillBackground(True)
self.ProgressBar.setProperty("value", 0)
self.ProgressBar.setAlignment(QtCore.Qt.AlignJustify|QtCore.Qt.AlignVCenter)
self.ProgressBar.setFormat(_fromUtf8(""))
self.ProgressBar.setObjectName(_fromUtf8("ProgressBar"))
self.OptionsExpert = QtGui.QFrame(self.Form)
self.ProgressBar.setFormat("")
self.ProgressBar.setObjectName("ProgressBar")
self.OptionsExpert = QtWidgets.QFrame(self.Form)
self.OptionsExpert.setGeometry(QtCore.QRect(5, 335, 421, 41))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setFamily("Lucida Grande")
font.setPointSize(9)
self.OptionsExpert.setFont(font)
self.OptionsExpert.setObjectName(_fromUtf8("OptionsExpert"))
self.ColorBox = QtGui.QCheckBox(self.OptionsExpert)
self.OptionsExpert.setObjectName("OptionsExpert")
self.ColorBox = QtWidgets.QCheckBox(self.OptionsExpert)
self.ColorBox.setGeometry(QtCore.QRect(9, 11, 130, 18))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setFamily("Lucida Grande")
font.setPointSize(12)
self.ColorBox.setFont(font)
self.ColorBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.ColorBox.setObjectName(_fromUtf8("ColorBox"))
self.OptionsExpertInternal = QtGui.QFrame(self.OptionsExpert)
self.ColorBox.setObjectName("ColorBox")
self.OptionsExpertInternal = QtWidgets.QFrame(self.OptionsExpert)
self.OptionsExpertInternal.setGeometry(QtCore.QRect(95, 0, 315, 40))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setFamily("Lucida Grande")
self.OptionsExpertInternal.setFont(font)
self.OptionsExpertInternal.setObjectName(_fromUtf8("OptionsExpertInternal"))
self.gridLayout_2 = QtGui.QGridLayout(self.OptionsExpertInternal)
self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2"))
self.wLabel = QtGui.QLabel(self.OptionsExpertInternal)
self.OptionsExpertInternal.setObjectName("OptionsExpertInternal")
self.gridLayout_2 = QtWidgets.QGridLayout(self.OptionsExpertInternal)
self.gridLayout_2.setObjectName("gridLayout_2")
self.wLabel = QtWidgets.QLabel(self.OptionsExpertInternal)
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setFamily("Lucida Grande")
font.setPointSize(12)
font.setBold(False)
font.setWeight(50)
self.wLabel.setFont(font)
self.wLabel.setObjectName(_fromUtf8("wLabel"))
self.wLabel.setObjectName("wLabel")
self.gridLayout_2.addWidget(self.wLabel, 0, 0, 1, 1)
self.customWidth = QtGui.QLineEdit(self.OptionsExpertInternal)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
self.customWidth = QtWidgets.QLineEdit(self.OptionsExpertInternal)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.customWidth.sizePolicy().hasHeightForWidth())
self.customWidth.setSizePolicy(sizePolicy)
self.customWidth.setMaximumSize(QtCore.QSize(45, 16777215))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setFamily("Lucida Grande")
font.setPointSize(12)
self.customWidth.setFont(font)
self.customWidth.setFocusPolicy(QtCore.Qt.ClickFocus)
self.customWidth.setAcceptDrops(False)
self.customWidth.setMaxLength(4)
self.customWidth.setObjectName(_fromUtf8("customWidth"))
self.customWidth.setObjectName("customWidth")
self.gridLayout_2.addWidget(self.customWidth, 0, 1, 1, 1)
self.hLabel = QtGui.QLabel(self.OptionsExpertInternal)
self.hLabel = QtWidgets.QLabel(self.OptionsExpertInternal)
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setFamily("Lucida Grande")
font.setPointSize(12)
font.setBold(False)
font.setWeight(50)
self.hLabel.setFont(font)
self.hLabel.setObjectName(_fromUtf8("hLabel"))
self.hLabel.setObjectName("hLabel")
self.gridLayout_2.addWidget(self.hLabel, 0, 2, 1, 1)
self.customHeight = QtGui.QLineEdit(self.OptionsExpertInternal)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed)
self.customHeight = QtWidgets.QLineEdit(self.OptionsExpertInternal)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.customHeight.sizePolicy().hasHeightForWidth())
self.customHeight.setSizePolicy(sizePolicy)
self.customHeight.setMaximumSize(QtCore.QSize(45, 16777215))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setFamily("Lucida Grande")
font.setPointSize(12)
self.customHeight.setFont(font)
self.customHeight.setFocusPolicy(QtCore.Qt.ClickFocus)
self.customHeight.setAcceptDrops(False)
self.customHeight.setMaxLength(4)
self.customHeight.setObjectName(_fromUtf8("customHeight"))
self.customHeight.setObjectName("customHeight")
self.gridLayout_2.addWidget(self.customHeight, 0, 3, 1, 1)
KCC.setCentralWidget(self.Form)
self.ActionBasic = QtGui.QAction(KCC)
self.statusBar = QtWidgets.QStatusBar(KCC)
font = QtGui.QFont()
font.setFamily("Aharoni")
font.setPointSize(8)
self.statusBar.setFont(font)
self.statusBar.setSizeGripEnabled(False)
self.statusBar.setObjectName("statusBar")
KCC.setStatusBar(self.statusBar)
self.ActionBasic = QtWidgets.QAction(KCC)
self.ActionBasic.setCheckable(True)
self.ActionBasic.setChecked(False)
font = QtGui.QFont()
font.setPointSize(9)
self.ActionBasic.setFont(font)
self.ActionBasic.setObjectName(_fromUtf8("ActionBasic"))
self.ActionAdvanced = QtGui.QAction(KCC)
self.ActionBasic.setObjectName("ActionBasic")
self.ActionAdvanced = QtWidgets.QAction(KCC)
self.ActionAdvanced.setCheckable(True)
self.ActionAdvanced.setObjectName(_fromUtf8("ActionAdvanced"))
self.ActionAdvanced.setObjectName("ActionAdvanced")
self.retranslateUi(KCC)
QtCore.QMetaObject.connectSlotsByName(KCC)
@@ -358,47 +350,47 @@ class Ui_KCC(object):
KCC.setTabOrder(self.ConvertButton, self.ClearButton)
def retranslateUi(self, KCC):
KCC.setWindowTitle(_translate("KCC", "Kindle Comic Converter", None))
self.ProcessingBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Disable image optimizations.</span></p></body></html>", None))
self.ProcessingBox.setText(_translate("KCC", "No optimisation", None))
self.UpscaleBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt; font-weight:600; text-decoration: underline;\">Unchecked - Nothing<br/></span><span style=\" font-size:12pt;\">Images smaller than device resolution will not be resized.</span></p><p><span style=\" font-size:12pt; font-weight:600; text-decoration: underline;\">Indeterminate - Stretching<br/></span><span style=\" font-size:12pt;\">Images smaller than device resolution will be resized. Aspect ratio will be not preserved.</span></p><p><span style=\" font-size:12pt; font-weight:600; text-decoration: underline;\">Checked - Upscaling<br/></span><span style=\" font-size:12pt;\">Images smaller than device resolution will be resized. Aspect ratio will be preserved.</span></p></body></html>", None))
self.UpscaleBox.setText(_translate("KCC", "Stretch/Upscale", None))
self.WebtoonBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Enable auto-splitting of webtoons like </span><span style=\" font-size:12pt; font-style:italic;\">Tower of God</span><span style=\" font-size:12pt;\"> or </span><span style=\" font-size:12pt; font-style:italic;\">Noblesse</span><span style=\" font-size:12pt;\">.<br/>Pages with a low width, high height and vertical panel flow.</span></p></body></html>", None))
self.WebtoonBox.setText(_translate("KCC", "Webtoon mode", None))
self.NoDitheringBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Create PNG files instead JPEG.<br/>Quality increase is not noticeable on most of devices.<br/>Output files </span><span style=\" font-size:12pt; font-weight:600;\">might</span><span style=\" font-size:12pt;\"> be smaller.<br/></span><span style=\" font-size:12pt; font-weight:600;\">MOBI conversion will be much slower.</span></p></body></html>", None))
self.NoDitheringBox.setText(_translate("KCC", "PNG output", None))
self.BorderBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt; font-weight:600; text-decoration: underline;\">Unchecked - Autodetection<br/></span><span style=\" font-size:12pt;\">Color of margins fill will be detected automatically.</span></p><p><span style=\" font-size:12pt; font-weight:600; text-decoration: underline;\">Indeterminate - White<br/></span><span style=\" font-size:12pt;\">Margins will be filled with white color.</span></p><p><span style=\" font-size:12pt; font-weight:600; text-decoration: underline;\">Checked - Black<br/></span><span style=\" font-size:12pt;\">Margins will be filled with black color.</span></p></body></html>", None))
self.BorderBox.setText(_translate("KCC", "W/B margins", None))
self.NoRotateBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Disable splitting and rotation.</span></p></body></html>", None))
self.NoRotateBox.setText(_translate("KCC", "No split/rotate", None))
self.DeviceBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Target device.</span></p></body></html>", None))
self.FormatBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Output format.</span></p></body></html>", None))
self.ConvertButton.setText(_translate("KCC", "Convert", None))
self.DirectoryButton.setText(_translate("KCC", "Add directory", None))
self.FileButton.setText(_translate("KCC", "Add file", None))
self.ClearButton.setText(_translate("KCC", "Clear list", None))
self.MangaBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Enable right-to-left reading.</span></p></body></html>", None))
self.MangaBox.setText(_translate("KCC", "Manga mode", None))
self.QualityBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\"font-size:12pt; font-weight:600; text-decoration: underline;\">Unchecked - Normal quality mode<br/></span><span style=\"font-size:12pt; font-style:italic;\">Use it when Panel View support is not needed.</span><span style=\"font-size:12pt; font-weight:600; text-decoration: underline;\"><br/></span><span style=\"font-size:12pt;\">- Maximum quality when zoom is not enabled.<br/>- Poor quality when zoom is enabled.<br/>- Lowest file size.</span></p><p><span style=\"font-size:12pt; font-weight:600; text-decoration: underline;\">Indeterminate - High quality mode<br/></span><span style=\"font-size:12pt; font-style:italic;\">Not zoomed image </span><span style=\"font-size:12pt; font-weight:600; font-style:italic;\">might </span><span style=\"font-size:12pt; font-style:italic;\">be a little blurry.</span><span style=\"font-size:12pt; font-weight:600; text-decoration: underline;\"><br/></span><span style=\"font-size:12pt;\">- Medium/High quality when zoom is not enabled.<br/>- Maximum quality when zoom is enabled.</span></p><p><span style=\"font-size:12pt; font-weight:600; text-decoration: underline;\">Checked - Ultra quality mode<br/></span><span style=\"font-size:12pt; font-style:italic;\">Maximum possible quality.</span><span style=\"font-size:12pt; font-weight:600; text-decoration: underline;\"><br/></span><span style=\"font-size:12pt;\">- Maximum quality when zoom is not enabled.<br/>- Maximum quality when zoom is enabled.<br/>- Very high file size.</span></p></body></html>", None))
self.QualityBox.setText(_translate("KCC", "High/Ultra quality", None))
self.RotateBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Disable page spliting.<br/>They will be rotated instead.</span></p></body></html>", None))
self.RotateBox.setText(_translate("KCC", "Horizontal mode", None))
self.BasicModeButton.setText(_translate("KCC", "Basic", None))
self.AdvModeButton.setText(_translate("KCC", "Advanced", None))
self.GammaLabel.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">When converting color images setting this option to 1.0 </span><span style=\" font-size:12pt; font-weight:600;\">might</span><span style=\" font-size:12pt;\"> improve readability.</span></p></body></html>", None))
self.GammaLabel.setText(_translate("KCC", "Gamma: Auto", None))
self.GammaSlider.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">When converting color images setting this option to 1.0 </span><span style=\" font-size:12pt; font-weight:600;\">might</span><span style=\" font-size:12pt;\"> improve readability.</span></p></body></html>", None))
self.ColorBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Do not convert images to grayscale.</span></p></body></html>", None))
self.ColorBox.setText(_translate("KCC", "Color mode", None))
self.wLabel.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Resolution of target device.</span></p></body></html>", None))
self.wLabel.setText(_translate("KCC", "Custom width: ", None))
self.customWidth.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Resolution of target device.</span></p></body></html>", None))
self.customWidth.setInputMask(_translate("KCC", "0000; ", None))
self.hLabel.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Resolution of target device.</span></p></body></html>", None))
self.hLabel.setText(_translate("KCC", "Custom height: ", None))
self.customHeight.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Resolution of target device.</span></p></body></html>", None))
self.customHeight.setInputMask(_translate("KCC", "0000; ", None))
self.ActionBasic.setText(_translate("KCC", "Basic", None))
self.ActionAdvanced.setText(_translate("KCC", "Advanced", None))
_translate = QtCore.QCoreApplication.translate
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.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.setText(_translate("KCC", "Stretch/Upscale"))
self.WebtoonBox.setToolTip(_translate("KCC", "<html><head/><body><p>Enable auto-splitting of webtoons like <span style=\" font-style:italic;\">Tower of God </span>or <span style=\" font-style:italic;\">Noblesse</span>.<br/>This mode was created for pages with a low width, high height and vertical panel flow.</p><p><br/></p></body></html>"))
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.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.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.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.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.setText(_translate("KCC", "Convert"))
self.DirectoryButton.setText(_translate("KCC", "Add directory"))
self.FileButton.setText(_translate("KCC", "Add file"))
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.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</span><br/>Maximal quality of images but very poor magnification quality.<br/>Use it only when zoom is not needed or output files needs to be small.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - High quality mode</span><br/>In most cases high quality of images and magnification.<br/>Overall quality highly depends on the resolution of source files.<br/>On Kindle models older than Paperwhite non-zoomed images might be a little blurred.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Ultra quality mode</span><br/>Highest possible quality. Output files will be big.</p></body></html>"))
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.setText(_translate("KCC", "Horizontal mode"))
self.BasicModeButton.setText(_translate("KCC", "Basic"))
self.AdvModeButton.setText(_translate("KCC", "Advanced"))
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.setText(_translate("KCC", "Color mode"))
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.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.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.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.ActionBasic.setText(_translate("KCC", "Basic"))
self.ActionAdvanced.setText(_translate("KCC", "Advanced"))
import KCC_rc
from . import KCC_rc

View File

@@ -1,4 +1,4 @@
__version__ = '3.5'
__version__ = '4.1'
__license__ = 'ISC'
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
__docformat__ = 'restructuredtext en'

View File

@@ -1,5 +1,5 @@
# Copyright (c) 2012-2013 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013 Pawel Jastrzebski <pawelj@vulturis.eu>
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013-2014 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
@@ -15,21 +15,24 @@
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
#
__license__ = 'ISC'
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
__docformat__ = 'restructuredtext en'
import sys
import os
import zipfile
import rarfile
import locale
from subprocess import Popen, STDOUT, PIPE
from zipfile import is_zipfile, ZipFile
from subprocess import STDOUT, PIPE
from psutil import Popen
from shutil import move, copy
from . import rarfile
class CBxArchive:
def __init__(self, origFileName):
self.origFileName = origFileName
if zipfile.is_zipfile(origFileName):
if is_zipfile(origFileName):
self.compressor = 'zip'
elif rarfile.is_rarfile(origFileName):
self.compressor = 'rar'
@@ -42,7 +45,7 @@ class CBxArchive:
return self.compressor is not None
def extractCBZ(self, targetdir):
cbzFile = zipfile.ZipFile(self.origFileName)
cbzFile = ZipFile(self.origFileName)
filelist = []
for f in cbzFile.namelist():
if f.startswith('__MACOSX') or f.endswith('.DS_Store') or f.endswith('thumbs.db'):
@@ -50,14 +53,14 @@ class CBxArchive:
elif f.endswith('/'):
try:
os.makedirs(os.path.join(targetdir, f))
except StandardError:
except Exception:
pass # the dir exists so we are going to extract the images only.
else:
filelist.append(f)
cbzFile.extractall(targetdir, filelist)
def extractCBR(self, targetdir):
cbrFile = rarfile.RarFile(self.origFileName.encode(locale.getpreferredencoding()))
cbrFile = rarfile.RarFile(self.origFileName)
filelist = []
for f in cbrFile.namelist():
if f.startswith('__MACOSX') or f.endswith('.DS_Store') or f.endswith('thumbs.db'):
@@ -65,25 +68,29 @@ class CBxArchive:
elif f.endswith('/'):
try:
os.makedirs(os.path.join(targetdir, f))
except StandardError:
except Exception:
pass # the dir exists so we are going to extract the images only.
else:
filelist.append(f.encode(locale.getpreferredencoding()))
filelist.append(f)
cbrFile.extractall(targetdir, filelist)
def extractCB7(self, targetdir):
output = Popen('7za x "' + self.origFileName.encode(locale.getpreferredencoding()) +
'" -xr!__MACOSX -xr!.DS_Store -xr!thumbs.db -o"' + targetdir + '"',
stdout=PIPE, stderr=STDOUT, shell=True)
# Workaround for some wide UTF-8 + Popen abnormalities
if sys.platform.startswith('darwin'):
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')
output = Popen('7za x "' + self.origFileName + '" -xr!__MACOSX -xr!.DS_Store -xr!thumbs.db -o"'
+ targetdir + '"', stdout=PIPE, stderr=STDOUT, shell=True)
extracted = False
for line in output.stdout:
if "Everything is Ok" in line:
if b"Everything is Ok" in line:
extracted = True
if sys.platform.startswith('darwin'):
os.remove(self.origFileName)
if not extracted:
raise OSError
def extract(self, targetdir):
print "\n" + targetdir + "\n"
if self.compressor == 'rar':
self.extractCBR(targetdir)
elif self.compressor == 'zip':
@@ -91,9 +98,14 @@ class CBxArchive:
elif self.compressor == '7z':
self.extractCB7(targetdir)
adir = os.listdir(targetdir)
if 'ComicInfo.xml' in adir:
adir.remove('ComicInfo.xml')
if len(adir) == 1 and os.path.isdir(os.path.join(targetdir, adir[0])):
import shutil
for f in os.listdir(os.path.join(targetdir, adir[0])):
shutil.move(os.path.join(targetdir, adir[0], f), targetdir)
# 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)):
os.replace(os.path.join(targetdir, adir[0], f), os.path.join(targetdir, adir[0], f + '-A'))
f += '-A'
move(os.path.join(targetdir, adir[0], f), targetdir)
os.rmdir(os.path.join(targetdir, adir[0]))
return targetdir

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,7 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2012-2013 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013 Pawel Jastrzebski <pawelj@vulturis.eu>
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013-2014 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
@@ -18,49 +17,75 @@
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
#
__version__ = '3.5'
__version__ = '4.1'
__license__ = 'ISC'
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
__docformat__ = 'restructuredtext en'
import os
import sys
from shutil import rmtree, copytree, move
from optparse import OptionParser, OptionGroup
from multiprocessing import Pool, freeze_support
from multiprocessing import Pool
from PIL import Image, ImageStat
from .shared import getImageFileName, walkLevel
try:
#noinspection PyUnresolvedReferences
from PIL import Image, ImageStat
if tuple(map(int, ('2.2.1'.split(".")))) > tuple(map(int, (Image.PILLOW_VERSION.split(".")))):
print "ERROR: Pillow 2.2.1 or newer is required!"
exit(1)
except ImportError:
print "ERROR: Pillow is not installed!"
exit(1)
try:
from PyQt4 import QtCore
from PyQt5 import QtCore
except ImportError:
QtCore = None
def getImageFileName(imgfile):
filename = os.path.splitext(imgfile)
if filename[0].startswith('.') or\
(filename[1].lower() != '.png' and
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 filename
def mergeDirectory_tick(output):
if output:
mergeWorkerOutput.append(output)
mergeWorkerPool.terminate()
if GUI:
GUI.progressBarTick.emit('tick')
if not GUI.conversionAlive:
mergeWorkerPool.terminate()
def mergeDirectory(work):
try:
directory = work[0]
images = []
imagesClear = []
sizes = []
h = 0
for root, dirs, files in walkLevel(directory, 0):
for name in files:
if getImageFileName(name) is not None:
i = Image.open(os.path.join(root, name))
images.append([os.path.join(root, name), i.size[0], i.size[1]])
sizes.append(i.size[0])
if len(images) > 0:
mw = max(set(sizes), key=sizes.count)
for i in images:
if i[1] == mw:
h += i[2]
imagesClear.append(i[0])
# Silently drop directories that contain too many images
if h > 262144:
return None
result = Image.new('RGB', (mw, h))
y = 0
for i in imagesClear:
img = Image.open(i)
img = img.convert('RGB')
result.paste(img, (0, y))
y += img.size[1]
os.remove(i)
savePath = os.path.split(imagesClear[0])
result.save(os.path.join(savePath[0], os.path.splitext(savePath[1])[0] + '.png'), 'PNG')
except Exception:
return str(sys.exc_info()[1])
def sanitizePanelSize(panel, opt):
newPanels = []
if panel[2] > 8 * opt.height:
diff = (panel[2] / 8)
diff = int(panel[2] / 8)
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*6, panel[1] - diff*5, diff])
@@ -70,14 +95,14 @@ def sanitizePanelSize(panel, opt):
newPanels.append([panel[1] - diff*2, panel[1] - diff, diff])
newPanels.append([panel[1] - diff, panel[1], diff])
elif panel[2] > 4 * opt.height:
diff = (panel[2] / 4)
diff = int(panel[2] / 4)
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*2, panel[1] - diff, diff])
newPanels.append([panel[1] - diff, panel[1], diff])
elif panel[2] > 2 * opt.height:
newPanels.append([panel[0], panel[1] - (panel[2] / 2), (panel[2] / 2)])
newPanels.append([panel[1] - (panel[2] / 2), panel[1], (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)])
else:
newPanels = [panel]
return newPanels
@@ -88,7 +113,7 @@ def splitImage_tick(output):
splitWorkerOutput.append(output)
splitWorkerPool.terminate()
if GUI:
GUI.emit(QtCore.SIGNAL("progressBarTick"))
GUI.progressBarTick.emit('tick')
if not GUI.conversionAlive:
splitWorkerPool.terminate()
@@ -99,27 +124,11 @@ def splitImage(work):
path = work[0]
name = work[1]
opt = work[2]
# Harcoded opttions
# Hardcoded options
threshold = 1.0
delta = 15
print ".",
fileExpanded = os.path.splitext(name)
filePath = os.path.join(path, name)
# Detect corrupted files
try:
Image.open(filePath)
except IOError:
raise RuntimeError('Cannot read image file %s' % filePath)
try:
image = Image.open(filePath)
image.verify()
except:
raise RuntimeError('Image file %s is corrupted' % filePath)
try:
image = Image.open(filePath)
image.load()
except:
raise RuntimeError('Image file %s is corrupted' % filePath)
image = Image.open(filePath)
image = image.convert('RGB')
widthImg, heightImg = image.size
@@ -194,24 +203,25 @@ def splitImage(work):
str(pageNumber) + '.png'), 'PNG')
pageNumber += 1
os.remove(filePath)
except StandardError:
except Exception:
return str(sys.exc_info()[1])
def Copyright():
print ('comic2panel v%(__version__)s. '
'Written 2013 by Ciro Mattia Gonano and Pawel Jastrzebski.' % globals())
print(('comic2panel v%(__version__)s. Written by Ciro Mattia Gonano and Pawel Jastrzebski.' % globals()))
def main(argv=None, qtGUI=None):
global options, GUI, splitWorkerPool, splitWorkerOutput
parser = OptionParser(usage="Usage: %prog [options] comic_folder", add_help_option=False)
global options, GUI, splitWorkerPool, splitWorkerOutput, mergeWorkerPool, mergeWorkerOutput
parser = OptionParser(usage="Usage: kcc-c2p [options] comic_folder", add_help_option=False)
mainOptions = OptionGroup(parser, "MANDATORY")
otherOptions = OptionGroup(parser, "OTHER")
mainOptions.add_option("-y", "--height", type="int", dest="height", default=0,
help="Height of the target device screen")
mainOptions.add_option("-i", "--in-place", action="store_true", dest="inPlace", default=False,
help="Overwrite source directory")
mainOptions.add_option("-m", "--merge", action="store_true", dest="merge", default=False,
help="Combine every directory into a single image before splitting")
otherOptions.add_option("-d", "--debug", action="store_true", dest="debug", default=False,
help="Create debug file for every splitted image")
otherOptions.add_option("-h", "--help", action="help",
@@ -229,14 +239,38 @@ def main(argv=None, qtGUI=None):
if options.height > 0:
options.sourceDir = args[0]
options.targetDir = args[0] + "-Splitted"
print "\nSplitting images..."
if os.path.isdir(options.sourceDir):
rmtree(options.targetDir, True)
copytree(options.sourceDir, options.targetDir)
work = []
pagenumber = 0
pagenumber = 1
splitWorkerOutput = []
splitWorkerPool = Pool()
if options.merge:
print("\nMerging images...")
directoryNumer = 1
mergeWork = []
mergeWorkerOutput = []
mergeWorkerPool = Pool()
mergeWork.append([options.targetDir])
for root, dirs, files in os.walk(options.targetDir, False):
for directory in dirs:
directoryNumer += 1
mergeWork.append([os.path.join(root, directory)])
if GUI:
GUI.progressBarTick.emit('Combining images')
GUI.progressBarTick.emit(str(directoryNumer))
for i in mergeWork:
mergeWorkerPool.apply_async(func=mergeDirectory, args=(i, ), callback=mergeDirectory_tick)
mergeWorkerPool.close()
mergeWorkerPool.join()
if GUI and not GUI.conversionAlive:
rmtree(options.targetDir, True)
raise UserWarning("Conversion interrupted.")
if len(mergeWorkerOutput) > 0:
rmtree(options.targetDir, True)
raise RuntimeError("One of workers crashed. Cause: " + mergeWorkerOutput[0])
print("\nSplitting images...")
for root, dirs, files in os.walk(options.targetDir, False):
for name in files:
if getImageFileName(name) is not None:
@@ -245,7 +279,9 @@ def main(argv=None, qtGUI=None):
else:
os.remove(os.path.join(root, name))
if GUI:
GUI.emit(QtCore.SIGNAL("progressBarTick"), pagenumber)
GUI.progressBarTick.emit('Splitting images')
GUI.progressBarTick.emit(str(pagenumber))
GUI.progressBarTick.emit('tick')
if len(work) > 0:
for i in work:
splitWorkerPool.apply_async(func=splitImage, args=(i, ), callback=splitImage_tick)
@@ -266,11 +302,4 @@ def main(argv=None, qtGUI=None):
else:
raise UserWarning("Provided path is not a directory.")
else:
raise UserWarning("Target height is not set.")
if __name__ == "__main__":
freeze_support()
Copyright()
main(sys.argv[1:])
sys.exit(0)
raise UserWarning("Target height is not set.")

184
kcc/dualmetafix.py Normal file
View File

@@ -0,0 +1,184 @@
# -*- coding: utf-8 -*-
#
# Based on initial version of DualMetaFix. Copyright (C) 2013 Kevin Hendricks
# Changes for KCC Copyright (C) 2014 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()

View File

@@ -1,7 +1,7 @@
# Copyright (C) 2010 Alex Yatskov
# Copyright (C) 2011 Stanislav (proDOOMman) Kosolapov <prodoomman@gmail.com>
# Copyright (C) 2012-2013 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (C) 2013 Pawel Jastrzebski <pawelj@vulturis.eu>
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013-2014 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
@@ -17,19 +17,13 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
__license__ = 'ISC'
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
__docformat__ = 'restructuredtext en'
import os
try:
# noinspection PyUnresolvedReferences
from PIL import Image, ImageOps, ImageStat, ImageChops
if tuple(map(int, ('2.2.1'.split(".")))) > tuple(map(int, (Image.PILLOW_VERSION.split(".")))):
print "ERROR: Pillow 2.2.1 or newer is required!"
exit(1)
except ImportError:
print "ERROR: Pillow is not installed!"
exit(1)
from functools import reduce
from PIL import Image, ImageOps, ImageStat, ImageChops
from .shared import md5Checksum
class ProfileData:
@@ -94,113 +88,84 @@ class ProfileData:
'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)),
'KoG': ("Kobo Glow", (768, 1024), Palette16, 1.8, (1152, 1536)),
'KoA': ("Kobo Aura", (758, 1024), Palette16, 1.8, (1137, 1536)),
'KoAHD': ("Kobo Aura HD", (1080, 1440), Palette16, 1.8, (1620, 2160)),
'KFA': ("Kindle for Android", (0, 0), PalleteNull, 1.0, (0, 0)),
'OTHER': ("Other", (0, 0), Palette16, 1.8, (0, 0)),
}
ProfileLabels = {
"Kindle 1": 'K1',
"Kindle 2": 'K2',
"Kindle": 'K345',
"Kindle Paperwhite": 'KHD',
"Kindle DX/DXG": 'KDX',
"Kindle Fire": 'KF',
"K. Fire HD 7\"": 'KFHD',
"K. Fire HD 8.9\"": 'KFHD8',
"K. Fire HDX 7\"": 'KFHDX',
"K. Fire HDX 8.9\"": 'KFHDX8',
"Kindle for Android": 'KFA',
"Other": 'OTHER'
}
ProfileLabelsGUI = [
"Kindle Paperwhite",
"Kindle",
"Separator",
"K. Fire HD 7\"",
"K. Fire HD 8.9\"",
"K. Fire HDX 7\"",
"K. Fire HDX 8.9\"",
"Separator",
"Kindle for Android",
"Other",
"Separator",
"Kindle 1",
"Kindle 2",
"Kindle DX/DXG",
"Kindle Fire"
]
class ComicPage:
def __init__(self, source, device):
def __init__(self, source, device, fill=None):
try:
self.profile_label, self.size, self.palette, self.gamma, self.panelviewsize = device
except KeyError:
raise RuntimeError('Unexpected output device %s' % device)
# Detect corrupted files - Phase 2
try:
self.origFileName = source
self.filename = os.path.basename(self.origFileName)
self.image = Image.open(source)
except IOError:
raise RuntimeError('Cannot read image file %s' % source)
# Detect corrupted files - Phase 3
try:
self.image = Image.open(source)
self.image.verify()
except:
raise RuntimeError('Image file %s is corrupted' % source)
# Detect corrupted files - Phase 4
try:
self.image = Image.open(source)
self.image.load()
except:
raise RuntimeError('Image file %s is corrupted' % source)
self.origFileName = source
self.filename = os.path.basename(self.origFileName)
self.image = Image.open(source)
self.image = self.image.convert('RGB')
self.color = self.isImageColor()
self.rotated = None
self.border = None
self.noHPV = None
self.noVPV = None
self.fill = None
self.noPV = None
self.purge = False
self.hq = False
if fill:
self.fill = fill
else:
self.fill = None
def saveToDir(self, targetdir, forcepng, color, wipe):
def saveToDir(self, targetdir, forcepng, color):
try:
suffix = ""
if not color and not forcepng:
self.image = self.image.convert('L')
if self.rotated:
suffix += "_kccrot"
if wipe:
os.remove(os.path.join(targetdir, self.filename))
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:
suffix += "_kcchq"
if self.noHPV:
suffix += "_kccnh"
if self.noVPV:
suffix += "_kccnv"
if self.border:
suffix += "_kccx" + str(self.border[0]) + "_kccy" + str(self.border[1])
if forcepng:
self.image.save(os.path.join(targetdir, os.path.splitext(self.filename)[0] + suffix + ".png"), "PNG",
optimize=1)
else:
self.image.save(os.path.join(targetdir, os.path.splitext(self.filename)[0] + suffix + ".jpg"), "JPEG",
optimize=1)
return None
except IOError as e:
raise RuntimeError('Cannot write image in directory %s: %s' % (targetdir, e))
def optimizeImage(self, gamma):
if gamma < 0.1:
gamma = self.gamma
if self.gamma != 1.0 and self.color:
gamma = 1.0
if gamma == 1.0:
self.image = ImageOps.autocontrast(self.image)
else:
self.image = ImageOps.autocontrast(Image.eval(self.image, lambda a: 255 * (a / 255.) ** gamma))
def quantizeImage(self):
colors = len(self.palette) / 3
colors = len(self.palette) // 3
if colors < 256:
self.palette += self.palette[:3] * (256 - colors)
palImg = Image.new('P', (1, 1))
@@ -210,84 +175,98 @@ class ComicPage:
# Quantize is deprecated but new function call it internally anyway...
self.image = self.image.quantize(palette=palImg)
def calculateBorderPercent(self, x, img, isWidth):
if isWidth:
return int(round(float(x)/float(img.image.size[0]), 4) * 10000 * 1.5)
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
if self.fill == 'white':
# Only already saved files can have P mode. So we can break color quantization.
if sourceImage.image.mode == 'P':
sourceImage.image = sourceImage.image.convert('RGB')
border = ImageChops.invert(sourceImage.image).getbbox()
else:
border = sourceImage.image.getbbox()
if border is not None:
if isHQ:
multiplier = 1.0
else:
multiplier = 1.5
self.border = [self.calculateBorderPercent(border[0], sourceImage, True),
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
if int((border[3] - border[1]) * multiplier) < self.size[1]:
self.noVPV = True
else:
self.border = [0, 0, 0, 0]
self.noHPV = True
self.noVPV = True
def resizeImage(self, upscale=False, stretch=False, bordersColor=None, qualityMode=0):
# High-quality downscaling filter
method = Image.ANTIALIAS
if bordersColor:
fill = bordersColor
else:
fill = self.fill
# Set target size
if qualityMode == 0:
size = (self.size[0], self.size[1])
generateBorder = True
elif qualityMode == 1 and not stretch and not upscale and self.image.size[0] <=\
self.size[0] and self.image.size[1] <= self.size[1]:
size = (self.size[0], self.size[1])
elif qualityMode == 1:
# Forcing upscale to make sure that margins will be not too big
if not stretch:
upscale = True
size = (self.panelviewsize[0], self.panelviewsize[1])
generateBorder = True
elif qualityMode == 2 and not stretch and not upscale and self.image.size[0] <=\
self.size[0] and self.image.size[1] <= self.size[1]:
self.purge = True
return self.image
else:
self.hq = True
size = (self.panelviewsize[0], self.panelviewsize[1])
generateBorder = False
# If image is smaller than screen and upscale is off - Just expand it
if self.image.size[0] <= self.size[0] and self.image.size[1] <= self.size[1]:
if not upscale:
borderw = (self.size[0] - self.image.size[0]) / 2
borderh = (self.size[1] - self.image.size[1]) / 2
self.image = ImageOps.expand(self.image, border=(borderw, borderh), fill=fill)
if generateBorder:
if (self.image.size[0]-(2*borderw))*1.5 < self.size[0]:
self.noHPV = True
if (self.image.size[1]-(2*borderh))*1.5 < self.size[1]:
self.noVPV = True
self.border = [int(round(float(borderw)/float(self.image.size[0])*100, 2)*100*1.5),
int(round(float(borderh)/float(self.image.size[1])*100, 2)*100*1.5)]
return self.image
else:
# Cubic spline interpolation in a 4x4 environment
method = Image.BICUBIC
# If stretching is on - Resize without other considerations
if stretch:
if self.image.size[0] <= size[0] and self.image.size[1] <= size[1]:
method = Image.BICUBIC
else:
method = Image.ANTIALIAS
self.image = self.image.resize(size, method)
if generateBorder:
if fill == 'white':
border = ImageOps.invert(self.image).getbbox()
else:
border = self.image.getbbox()
if border is not None:
if (border[2]-border[0])*1.5 < self.size[0]:
self.noHPV = True
if (border[3]-border[1])*1.5 < self.size[1]:
self.noVPV = True
self.border = [int(round(float(border[0])/float(self.image.size[0])*100, 2)*100*1.5),
int(round(float(border[1])/float(self.image.size[1])*100, 2)*100*1.5)]
else:
self.border = [0, 0]
self.noHPV = True
self.noVPV = True
return self.image
# 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:
borderw = int((size[0] - self.image.size[0]) / 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
if self.image.size[0] <= self.size[0] and self.image.size[1] <= self.size[1]:
self.noPV = True
self.image = ImageOps.expand(self.image, border=(borderw, borderh), fill=fill)
# 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]:
self.image = ImageOps.fit(self.image, size, method=Image.BICUBIC, centering=(0.5, 0.5))
return self.image
# Otherwise - Upscale/Downscale
ratioDev = float(self.size[0]) / float(self.size[1])
ratioDev = float(size[0]) / float(size[1])
if (float(self.image.size[0]) / float(self.image.size[1])) < ratioDev:
diff = int(self.image.size[1] * ratioDev) - self.image.size[0]
self.image = ImageOps.expand(self.image, border=(diff / 2, 0), fill=fill)
self.image = ImageOps.expand(self.image, border=(int(diff / 2), 0), fill=fill)
elif (float(self.image.size[0]) / float(self.image.size[1])) > ratioDev:
diff = int(self.image.size[0] / ratioDev) - self.image.size[1]
self.image = ImageOps.expand(self.image, border=(0, diff / 2), fill=fill)
self.image = ImageOps.expand(self.image, border=(0, int(diff / 2)), fill=fill)
if self.image.size[0] <= size[0] and self.image.size[1] <= size[1]:
method = Image.BICUBIC
else:
method = Image.ANTIALIAS
self.image = ImageOps.fit(self.image, size, method=method, centering=(0.5, 0.5))
if generateBorder:
if fill == 'white':
border = ImageOps.invert(self.image).getbbox()
else:
border = self.image.getbbox()
if border is not None:
if (border[2]-border[0])*1.5 < self.size[0]:
self.noHPV = True
if (border[3]-border[1])*1.5 < self.size[1]:
self.noVPV = True
self.border = [int(round(float(border[0])/float(self.image.size[0])*100, 2)*100*1.5),
int(round(float(border[1])/float(self.image.size[1])*100, 2)*100*1.5)]
else:
self.border = [0, 0]
self.noHPV = True
self.noVPV = True
return self.image
def splitPage(self, targetdir, righttoleft=False, rotate=False):
@@ -303,15 +282,15 @@ class ComicPage:
self.rotated = False
if width > height:
# Source is landscape, so split by the width
leftbox = (0, 0, width / 2, height)
rightbox = (width / 2, 0, width, height)
leftbox = (0, 0, int(width / 2), height)
rightbox = (int(width / 2), 0, width, height)
else:
# Source is portrait and target is landscape, so split by the height
leftbox = (0, 0, width, height / 2)
rightbox = (0, height / 2, width, height)
leftbox = (0, 0, width, int(height / 2))
rightbox = (0, int(height / 2), width, height)
filename = os.path.splitext(self.filename)
fileone = targetdir + '/' + filename[0] + '_kcca' + filename[1]
filetwo = targetdir + '/' + filename[0] + '_kccb' + filename[1]
fileone = targetdir + '/' + filename[0] + '-A' + filename[1]
filetwo = targetdir + '/' + filename[0] + '-B' + filename[1]
try:
if righttoleft:
pageone = self.image.crop(rightbox)
@@ -321,7 +300,6 @@ class ComicPage:
pagetwo = self.image.crop(rightbox)
pageone.save(fileone)
pagetwo.save(filetwo)
os.remove(self.origFileName)
except IOError as e:
raise RuntimeError('Cannot write image in directory %s: %s' % (targetdir, e))
return fileone, filetwo
@@ -347,7 +325,7 @@ class ComicPage:
oldStat = ImageStat.Stat(self.image.crop((0, heightImg - diff, widthImg, heightImg))).var[0]
diff += delta
while ImageStat.Stat(self.image.crop((0, heightImg - diff, widthImg, heightImg))).var[0] - oldStat > 0\
and diff < heightImg / 4:
and diff < heightImg // 4:
oldStat = ImageStat.Stat(self.image.crop((0, heightImg - diff, widthImg, heightImg))).var[0]
diff += delta
diff -= delta
@@ -356,7 +334,7 @@ class ComicPage:
oldStat = ImageStat.Stat(self.image.crop((0, heightImg - diff, widthImg,
heightImg - pageNumberCut2))).var[0]
while ImageStat.Stat(self.image.crop((0, heightImg - diff, widthImg, heightImg - pageNumberCut2))).var[0]\
< fixedThreshold + oldStat and diff < heightImg / 4:
< fixedThreshold + oldStat and diff < heightImg // 4:
diff += delta
diff -= delta
pageNumberCut3 = diff
@@ -384,27 +362,28 @@ class ComicPage:
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:
widthImg, heightImg = self.image.size
delta = 10
diff = delta
fixedThreshold = 0.1
# 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
self.image = self.image.crop((0, diff, widthImg, heightImg))
widthImg, heightImg = self.image.size
diff = delta
# 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
self.image = self.image.crop((diff, 0, widthImg, heightImg))
widthImg, heightImg = self.image.size
diff = delta
# 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:
diff += delta
diff -= delta
@@ -412,7 +391,7 @@ class ComicPage:
widthImg, heightImg = self.image.size
diff = delta
# 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:
diff += delta
diff -= delta
@@ -428,37 +407,97 @@ class ComicPage:
RBGW.append(histogram[i] + histogram[256 + i] + histogram[512 + i])
white = 0
black = 0
for i in range(245, 256):
for i in range(251, 256):
white += RBGW[i]
for i in range(11):
for i in range(5):
black += RBGW[i]
if black > white and black > pixelCount*0.5:
return True
if black > pixelCount*0.8 and white == 0:
return 1
elif white > pixelCount*0.8 and black == 0:
return -1
else:
return False
def getImageFill(self, isWebToon):
def getImageFill(self, webtoon):
fill = 0
if isWebToon or self.rotated:
fill += self.getImageHistogram(self.image.crop((0, 0, self.image.size[0], 5)))
fill += self.getImageHistogram(self.image.crop((0, self.image.size[1]-5, self.image.size[0],
self.image.size[1])))
if not webtoon and not self.rotated:
# Search for horizontal solid lines
startY = 0
while startY < self.image.size[1]:
if startY + 5 > self.image.size[1]:
startY = self.image.size[1] - 5
checkSolid = self.getImageHistogram(self.image.crop((0, startY, self.image.size[0], startY+5)))
if checkSolid:
fill += checkSolid
startY += 5
else:
fill += self.getImageHistogram(self.image.crop((0, 0, 5, self.image.size[1])))
fill += self.getImageHistogram(self.image.crop((self.image.size[0]-5, 0, self.image.size[0],
self.image.size[1])))
if fill == 2:
# Search for vertical solid lines
startX = 0
while startX < self.image.size[0]:
if startX + 5 > self.image.size[0]:
startX = self.image.size[0] - 5
checkSolid = self.getImageHistogram(self.image.crop((startX, 0, startX+5, self.image.size[1])))
if checkSolid:
fill += checkSolid
startX += 5
if fill > 0:
self.fill = 'black'
elif fill == 0:
self.fill = 'white'
else:
fill = 0
fill += self.getImageHistogram(self.image.crop((0, 0, 5, 5)))
fill += self.getImageHistogram(self.image.crop((self.image.size[0]-5, 0, self.image.size[0], 5)))
fill += self.getImageHistogram(self.image.crop((0, self.image.size[1]-5, 5, self.image.size[1])))
fill += self.getImageHistogram(self.image.crop((self.image.size[0]-5, self.image.size[1]-5,
self.image.size[0], self.image.size[1])))
if fill > 1:
self.fill = 'black'
self.fill = 'white'
def isImageColor(self):
v = ImageStat.Stat(self.image).var
isMonochromatic = reduce(lambda x, y: x and y < 0.005, v, True)
if isMonochromatic:
# Monochromatic
return False
else:
if len(v) == 3:
maxmin = abs(max(v) - min(v))
if maxmin > 1000:
# Color
return True
elif maxmin > 100:
# Probably color
return True
else:
# Grayscale
return False
elif len(v) == 1:
# Black and white
return False
else:
self.fill = 'white'
# Detection failed
return False
class Cover:
def __init__(self, source, target):
self.source = source
self.target = target
self.image = Image.open(source)
self.image = self.image.convert('RGB')
self.process()
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 process(self):
self.image = self.trim()
def save(self):
try:
if os.path.splitext(self.source)[1].lower() == '.png':
self.image.save(self.target, "PNG", optimize=1)
else:
self.image.save(self.target, "JPEG", optimize=1)
except IOError:
raise RuntimeError('Failed to save cover')

View File

@@ -1,384 +0,0 @@
# 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
# Copyright (C) 2013 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/>.
__license__ = 'ISC'
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
__docformat__ = 'restructuredtext en'
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('\0' * lpad)
datalst.append(datain[zerosecstart: secstart])
datalst.append(datain[secend:])
dataout = "".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('\0' * lpad)
datalst.append(datain[zerosecstart:firstsecstart])
datalst.append(datain[lastsecend:])
dataout = "".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('\0' * lpad)
datalst.append(datain[zerosecstart:secstart])
datalst.append(secdata)
datalst.append(datain[secstart:])
dataout = "".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, '')
# 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

View File

@@ -1,5 +1,5 @@
# Copyright (c) 2012-2013 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013 Pawel Jastrzebski <pawelj@vulturis.eu>
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013-2014 Pawel Jastrzebski <pawelj@iosphe.re>
#
# Based upon the code snippet by Ned Batchelder
# (http://nedbatchelder.com/blog/200712/extracting_jpgs_from_pdfs.html)
@@ -20,55 +20,53 @@
#
__license__ = 'ISC'
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
__docformat__ = 'restructuredtext en'
import os
from random import choice
from string import ascii_uppercase, digits
class PdfJpgExtract:
def __init__(self, origFileName):
self.origFileName = origFileName
self.filename = os.path.splitext(origFileName)
self.path = self.filename[0] + "-KCC-TMP"
# noinspection PyUnusedLocal
self.path = self.filename[0] + "-KCC-TMP-" + ''.join(choice(ascii_uppercase + digits) for x in range(3))
def getPath(self):
return self.path
def extract(self):
pdf = file(self.origFileName, "rb").read()
startmark = "\xff\xd8"
pdf = open(self.origFileName, "rb").read()
startmark = b"\xff\xd8"
startfix = 0
endmark = "\xff\xd9"
endmark = b"\xff\xd9"
endfix = 2
i = 0
njpg = 0
os.makedirs(self.path)
while True:
istream = pdf.find("stream", i)
istream = pdf.find(b"stream", i)
if istream < 0:
break
istart = pdf.find(startmark, istream, istream + 20)
if istart < 0:
i = istream + 20
continue
iend = pdf.find("endstream", istart)
iend = pdf.find(b"endstream", istart)
if iend < 0:
raise Exception("Didn't find end of stream!")
iend = pdf.find(endmark, iend - 20)
if iend < 0:
raise Exception("Didn't find end of JPG!")
istart += startfix
iend += endfix
print "JPG %d from %d to %d" % (njpg, istart, iend)
jpg = pdf[istart:iend]
jpgfile = file(self.path + "/jpg%d.jpg" % njpg, "wb")
jpgfile = open(self.path + "/jpg%d.jpg" % njpg, "wb")
jpgfile.write(jpg)
jpgfile.close()
njpg += 1
i = iend
return self.path, njpg

View File

@@ -108,6 +108,8 @@ if sys.hexversion < 0x3000000:
# py2.6 has broken bytes()
def bytes(s, enc):
return str(s)
else:
unicode = str
# see if compat bytearray() is needed
try:
@@ -188,10 +190,6 @@ NEED_COMMENTS = 1
#: whether to convert comments to unicode strings
UNICODE_COMMENTS = 0
#: When RAR is corrupt, stopping on bad header is better
#: On unknown/misparsed RAR headers reporting is better
REPORT_BAD_HEADER = 0
#: Convert RAR time tuple into datetime() object
USE_DATETIME = 0
@@ -340,9 +338,11 @@ class RarSignalExit(RarExecError):
"""Unrar exited with signal"""
def is_rarfile(fn):
def is_rarfile(xfile):
'''Check quickly whether file is rar archive.'''
buf = open(fn, "rb").read(len(RAR_ID))
fd = XFile(xfile)
buf = fd.read(len(RAR_ID))
fd.close()
return buf == RAR_ID
@@ -453,11 +453,12 @@ class RarFile(object):
'''Parse RAR structure, provide access to files in archive.
'''
#: Archive comment. Byte string or None. Use UNICODE_COMMENTS
#: Archive comment. Byte string or None. Use :data:`UNICODE_COMMENTS`
#: to get automatic decoding to unicode.
comment = None
def __init__(self, rarfile, mode="r", charset=None, info_callback=None, crc_check = True):
def __init__(self, rarfile, mode="r", charset=None, info_callback=None,
crc_check = True, errors = "stop"):
"""Open and parse a RAR archive.
Parameters:
@@ -472,6 +473,9 @@ class RarFile(object):
debug callback, gets to see all archive entries.
crc_check
set to False to disable CRC checks
errors
Either "stop" to quietly stop parsing on errors,
or "strict" to raise errors. Default is "stop".
"""
self.rarfile = rarfile
self.comment = None
@@ -485,6 +489,13 @@ class RarFile(object):
self._crc_check = crc_check
self._vol_list = []
if errors == "stop":
self._strict = False
elif errors == "strict":
self._strict = True
else:
raise ValueError("Invalid value for 'errors' parameter.")
self._main = None
if mode != "r":
@@ -548,8 +559,9 @@ class RarFile(object):
'''Returns file-like object (:class:`RarExtFile`),
from where the data can be read.
The object implements io.RawIOBase interface, so it can
be further wrapped with io.BufferedReader and io.TextIOWrapper.
The object implements :class:`io.RawIOBase` interface, so it can
be further wrapped with :class:`io.BufferedReader`
and :class:`io.TextIOWrapper`.
On older Python where io module is not available, it implements
only .read(), .seek(), .tell() and .close() methods.
@@ -588,16 +600,19 @@ class RarFile(object):
psw = None
# is temp write usable?
if not USE_EXTRACT_HACK or not self._main:
use_hack = 1
if not self._main:
use_hack = 0
elif self._main.flags & (RAR_MAIN_SOLID | RAR_MAIN_PASSWORD):
use_hack = 0
elif inf.flags & (RAR_FILE_SPLIT_BEFORE | RAR_FILE_SPLIT_AFTER):
use_hack = 0
elif is_filelike(self.rarfile):
pass
elif inf.file_size > HACK_SIZE_LIMIT:
use_hack = 0
else:
use_hack = 1
elif not USE_EXTRACT_HACK:
use_hack = 0
# now extract
if inf.compress_type == RAR_M0 and (inf.flags & RAR_FILE_PASSWORD) == 0:
@@ -610,7 +625,7 @@ class RarFile(object):
def read(self, fname, psw = None):
"""Return uncompressed data for archive entry.
For longer files using .open() may be better idea.
For longer files using :meth:`RarFile.open` may be better idea.
Parameters:
@@ -641,7 +656,7 @@ class RarFile(object):
Parameters:
member
filename or RarInfo instance
filename or :class:`RarInfo` instance
path
optional destination path
pwd
@@ -661,7 +676,7 @@ class RarFile(object):
path
optional destination path
members
optional filename or RarInfo instance list to extract
optional filename or :class:`RarInfo` instance list to extract
pwd
optional password to use
"""
@@ -687,10 +702,23 @@ class RarFile(object):
output = p.communicate()[0]
check_returncode(p, output)
def strerror(self):
"""Return error string if parsing failed,
or None if no problems.
"""
return self._parse_error
##
## private methods
##
def _set_error(self, msg, *args):
if args:
msg = msg % args
self._parse_error = msg
if self._strict:
raise BadRarFile(msg)
# store entry
def _process_entry(self, item):
if item.type == RAR_BLOCK_FILE:
@@ -738,7 +766,7 @@ class RarFile(object):
self._fd = None
def _parse_real(self):
fd = open(self.rarfile, "rb")
fd = XFile(self.rarfile)
self._fd = fd
id = fd.read(len(RAR_ID))
if id != RAR_ID:
@@ -757,9 +785,13 @@ class RarFile(object):
if not h:
if more_vols:
volume += 1
volfile = self._next_volname(volfile)
fd.close()
fd = open(volfile, "rb")
try:
volfile = self._next_volname(volfile)
fd = XFile(volfile)
except IOError:
self._set_error("Cannot open next volume: %s", volfile)
break
self._fd = fd
more_vols = 0
endarc = 0
@@ -824,8 +856,7 @@ class RarFile(object):
# now read actual header
return self._parse_block_header(fd)
except struct.error:
if REPORT_BAD_HEADER:
raise BadRarFile('Broken header in RAR file')
self._set_error('Broken header in RAR file')
return None
# common header
@@ -852,8 +883,7 @@ class RarFile(object):
# unexpected EOF?
if len(h.header_data) != h.header_size:
if REPORT_BAD_HEADER:
raise BadRarFile('Unexpected EOF when reading header')
self._set_error('Unexpected EOF when reading header')
return None
# block has data assiciated with it?
@@ -896,18 +926,9 @@ class RarFile(object):
if h.header_crc == calc_crc:
return h
# need to panic?
if REPORT_BAD_HEADER:
xlen = len(crcdat)
crcdat = h.header_data[2:]
msg = 'Header CRC error (%02x): exp=%x got=%x (xlen = %d)' % ( h.type, h.header_crc, calc_crc, xlen )
xlen = len(crcdat)
while xlen >= S_BLK_HDR.size - 2:
crc = crc32(crcdat[:xlen]) & 0xFFFF
if crc == h.header_crc:
msg += ' / crc match, xlen = %d' % xlen
xlen -= 1
raise BadRarFile(msg)
# header parsing failed.
self._set_error('Header CRC error (%02x): exp=%x got=%x (xlen = %d)',
h.type, h.header_crc, calc_crc, len(crcdat))
# instead panicing, send eof
return None
@@ -1053,6 +1074,8 @@ class RarFile(object):
# given current vol name, construct next one
def _next_volname(self, volfile):
if is_filelike(volfile):
raise IOError("Working on single FD")
if self._main.flags & RAR_MAIN_NEWNUMBERING:
return self._next_newvol(volfile)
return self._next_oldvol(volfile)
@@ -1093,7 +1116,7 @@ class RarFile(object):
BSIZE = 32*1024
size = inf.compress_size + inf.header_size
rf = open(inf.volume_file, "rb", 0)
rf = XFile(inf.volume_file, 0)
rf.seek(inf.header_offset)
tmpfd, tmpname = mkstemp(suffix='.rar')
@@ -1125,7 +1148,7 @@ class RarFile(object):
def _read_comment_v3(self, inf, psw=None):
# read data
rf = open(inf.volume_file, "rb")
rf = XFile(inf.volume_file)
rf.seek(inf.file_offset)
data = rf.read(inf.compress_size)
rf.close()
@@ -1146,6 +1169,8 @@ class RarFile(object):
# extract using unrar
def _open_unrar(self, rarfile, inf, psw = None, tmpfile = None):
if is_filelike(rarfile):
raise ValueError("Cannot use unrar directly on memory buffer")
cmd = [UNRAR_TOOL] + list(OPEN_ARGS)
if psw is not None:
cmd.append("-p" + psw)
@@ -1553,7 +1578,7 @@ class DirectReader(RarExtFile):
RarExtFile._open(self)
self.volfile = self.inf.volume_file
self.fd = open(self.volfile, "rb", 0)
self.fd = XFile(self.volfile, 0)
self.fd.seek(self.inf.header_offset, 0)
self.cur = self.rf._parse_header(self.fd)
self.cur_avail = self.cur.add_size
@@ -1705,10 +1730,47 @@ class HeaderDecrypt:
return res
# handle (filename|filelike) object
class XFile(object):
__slots__ = ('_fd', '_need_close')
def __init__(self, xfile, bufsize = 1024):
if is_filelike(xfile):
self._need_close = False
self._fd = xfile
self._fd.seek(0)
else:
self._need_close = True
self._fd = open(xfile, 'rb', bufsize)
def read(self, n=None):
return self._fd.read(n)
def tell(self):
return self._fd.tell()
def seek(self, ofs, whence=0):
return self._fd.seek(ofs, whence)
def readinto(self, dst):
return self._fd.readinto(dst)
def close(self):
if self._need_close:
self._fd.close()
def __enter__(self):
return self
def __exit__(self, typ, val, tb):
self.close()
##
## Utility functions
##
def is_filelike(obj):
if isinstance(obj, str) or isinstance(obj, unicode):
return False
res = True
for a in ('read', 'tell', 'seek'):
res = res and hasattr(obj, a)
if not res:
raise ValueError("Invalid object passed as file")
return True
def rar3_s2k(psw, salt):
"""String-to-key hash for RAR3."""
@@ -1874,4 +1936,3 @@ def check_returncode(p, out):
msg = "%s [%d]" % (exc.__doc__, p.returncode)
raise exc(msg)

60
kcc/shared.py Normal file
View File

@@ -0,0 +1,60 @@
# Copyright (c) 2012-2014 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013-2014 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.
#
__license__ = 'ISC'
__copyright__ = '2012-2014, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@iosphe.re>'
__docformat__ = 'restructuredtext en'
import os
from hashlib import md5
def getImageFileName(imgfile):
filename = os.path.splitext(imgfile)
if filename[0].startswith('.') or\
(filename[1].lower() != '.png' and
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 filename
def walkLevel(some_dir, level=1):
some_dir = some_dir.rstrip(os.path.sep)
assert os.path.isdir(some_dir)
num_sep = some_dir.count(os.path.sep)
for root, dirs, files in os.walk(some_dir):
yield root, dirs, files
num_sep_this = root.count(os.path.sep)
if num_sep + level <= num_sep_this:
del dirs[:]
def md5Checksum(filePath):
with open(filePath, 'rb') as fh:
m = md5()
while True:
data = fh.read(8192)
if not data:
break
m.update(data)
return m.hexdigest()

View File

@@ -1,35 +0,0 @@
--- qt-4.8.5/src/gui/kernel/qwidget_mac.mm 2013-06-07 07:16:59.000000000 +0200
+++ qt-4.8.5-fix/src/gui/kernel/qwidget_mac.mm 2013-10-11 23:00:15.000000000 +0200
@@ -4715,15 +4715,13 @@ void QWidgetPrivate::scroll_sys(int dx,
}
// Scroll the whole widget if qscrollRect is not valid:
- QRect validScrollRect = qscrollRect.isValid() ? qscrollRect : q->rect();
- validScrollRect &= clipRect();
+ QRect validScrollRect = qscrollRect.isValid() ? qscrollRect : QRect(0, 0, q->width(), q->height());
// If q is overlapped by other widgets, we cannot just blit pixels since
// this will move overlapping widgets as well. In case we just update:
const bool overlapped = isOverlapped(validScrollRect.translated(data.crect.topLeft()));
const bool accelerateScroll = accelEnv && isOpaque && !overlapped;
const bool isAlien = (q->internalWinId() == 0);
- const QPoint scrollDelta(dx, dy);
// If qscrollRect is valid, we are _not_ supposed to scroll q's children (as documented).
// But we do scroll children (and the whole of q) if qscrollRect is invalid. This case is
@@ -4745,7 +4743,6 @@ void QWidgetPrivate::scroll_sys(int dx,
}else {
update_sys(qscrollRect);
}
- return;
}
#ifdef QT_MAC_USE_COCOA
@@ -4762,6 +4759,7 @@ void QWidgetPrivate::scroll_sys(int dx,
// moved when the parent is scrolled. All directly or indirectly moved
// children will receive a move event before the function call returns.
QWidgetList movedChildren;
+ const QPoint scrollDelta(dx, dy);
if (scrollChildren) {
QObjectList children = q->children();

3
other/qt.conf Normal file
View File

@@ -0,0 +1,3 @@
; Qt Configuration file
[Paths]
Plugins = PlugIns

125
setup.py Normal file → Executable file
View File

@@ -1,16 +1,20 @@
#!/usr/bin/env python3
"""
cx_Freeze build script for KCC.
cx_Freeze/py2app build script for KCC.
Usage (Mac OS X):
python setup.py py2app
Usage (Windows):
python setup.py build
python setup.py py2exe
"""
from sys import platform
from sys import platform, version_info
if version_info[0] != 3:
print('ERROR: This is Python 3 script!')
exit(1)
NAME = "KindleComicConverter"
VERSION = "3.5"
VERSION = "4.1"
MAIN = "kcc.py"
if platform == "darwin":
@@ -22,70 +26,111 @@ if platform == "darwin":
py2app=dict(
argv_emulation=True,
iconfile='icons/comic2ebook.icns',
includes=['PIL', 'sip', 'PyQt4', 'PyQt4.QtCore', 'PyQt4.QtGui', 'PyQt4.QtNetwork'],
excludes=['PyQt4.QtDeclarative', 'PyQt4.QtDesigner', 'PyQt4.QtHelp', 'PyQt4.QtMultimedia',
'PyQt4.QtOpenGL', 'PyQt4.QtScript', 'PyQt4.QtScriptTools', 'PyQt4.QtSql', 'PyQt4.QtSvg',
'PyQt4.QtXmlPatterns', 'PyQt4.QtXml', 'PyQt4.QtWebKit', 'PyQt4.QtTest'],
resources=['LICENSE.txt', 'other/Additional-LICENSE.txt'],
includes=['PIL', 'sip', 'PyQt5', 'PyQt5.QtCore', 'PyQt5.QtGui', 'PyQt5.QtNetwork', 'PyQt5.QtWidgets',
'PyQt5.QtPrintSupport'],
resources=['LICENSE.txt', 'other/qt.conf', 'other/Additional-LICENSE.txt', 'other/unrar', 'other/7za'],
plist=dict(
CFBundleName=NAME,
CFBundleShortVersionString=VERSION,
CFBundleGetInfoString=NAME + " " + VERSION +
", written 2012-2013 by Ciro Mattia Gonano and Pawel Jastrzebski",
", written 2012-2014 by Ciro Mattia Gonano and Pawel Jastrzebski",
CFBundleExecutable=NAME,
CFBundleIdentifier='com.github.ciromattia.kcc',
CFBundleSignature='dplt',
CFBundleDocumentTypes=[
dict(
CFBundleTypeExtensions=['cbz', 'cbr', 'cb7', 'zip', 'rar', '7z', 'pdf'],
CFBundleTypeName='Comics',
CFBundleTypeIconFile='comic2ebook.icns',
CFBundleTypeRole='Viewer',
CFBundleTypeRole='Editor',
)
],
LSMinimumSystemVersion='10.8.0',
LSEnvironment=dict(
PATH='/usr/local/bin:/usr/bin:/bin'
),
NSHumanReadableCopyright='ISC License (ISCL)'
)
)
)
)
elif platform == "win32":
from cx_Freeze import setup, Executable
base = "Win32GUI"
# noinspection PyUnresolvedReferences
import py2exe
import platform as arch
from distutils.core import setup
if arch.architecture()[0] == '64bit':
suffix = '_64'
else:
suffix = ''
additional_files = [('imageformats', ['C:\Python34' + suffix +
'\Lib\site-packages\PyQt5\plugins\imageformats\qgif.dll',
'C:\Python34' + suffix +
'\Lib\site-packages\PyQt5\plugins\imageformats\qico.dll',
'C:\Python34' + suffix +
'\Lib\site-packages\PyQt5\plugins\imageformats\qjpeg.dll',
'C:\Python34' + suffix +
'\Lib\site-packages\PyQt5\plugins\imageformats\qmng.dll',
'C:\Python34' + suffix +
'\Lib\site-packages\PyQt5\plugins\imageformats\qsvg.dll',
'C:\Python34' + suffix +
'\Lib\site-packages\PyQt5\plugins\imageformats\qtga.dll',
'C:\Python34' + suffix +
'\Lib\site-packages\PyQt5\plugins\imageformats\qtiff.dll',
'C:\Python34' + suffix +
'\Lib\site-packages\PyQt5\plugins\imageformats\qwbmp.dll']),
('platforms', ['C:\Python34' + suffix +
'\Lib\site-packages\PyQt5\plugins\platforms\qminimal.dll',
'C:\Python34' + suffix +
'\Lib\site-packages\PyQt5\plugins\platforms\qoffscreen.dll',
'C:\Python34' + suffix +
'\Lib\site-packages\PyQt5\plugins\platforms\qwindows.dll']),
('', ['LICENSE.txt',
'other\\7za.exe',
'other\\UnRAR.exe',
'other\\Additional-LICENSE.txt',
'other\\7za.exe',
'C:\Python34' + suffix + '\Lib\site-packages\PyQt5\libEGL.dll'])]
extra_options = dict(
options={"build_exe": {"include_files": ['LICENSE.txt',
['other/UnRAR.exe', 'UnRAR.exe'],
['other/7za.exe', '7za.exe'],
['other/Additional-LICENSE.txt', 'Additional-LICENSE.txt']
], "compressed": True}},
executables=[Executable(MAIN,
base=base,
targetName="KCC.exe",
icon="icons/comic2ebook.ico",
copyDependentFiles=True,
appendScriptToExe=True,
appendScriptToLibrary=False,
compress=True)])
options={'py2exe': {"bundle_files": 2,
"dll_excludes": ["tcl85.dll", "tk85.dll"],
"dist_dir": "dist" + suffix,
"compressed": True,
"includes": ["sip"],
"excludes": ["tkinter"],
"optimize": 2}},
windows=[{"script": "kcc.py",
"dest_base": "KCC",
"version": VERSION,
"copyright": "Ciro Mattia Gonano, Pawel Jastrzebski © 2014",
"legal_copyright": "ISC License (ISCL)",
"product_version": VERSION,
"product_name": "Kindle Comic Converter",
"file_description": "Kindle Comic Converter",
"icon_resources": [(1, "icons\comic2ebook.ico")]}],
zipfile=None,
data_files=additional_files)
else:
from cx_Freeze import setup, Executable
extra_options = dict(
options={"build_exe": {"include_files": ['LICENSE.txt',
['other/Additional-LICENSE.txt', 'Additional-LICENSE.txt']
], "compressed": True}},
executables=[Executable(MAIN,
icon="icons/comic2ebook.png",
copyDependentFiles=True,
appendScriptToExe=True,
appendScriptToLibrary=False,
compress=True)])
print('Please use setup.sh to build Linux package.')
exit()
#noinspection PyUnboundLocalVariable
setup(
name=NAME,
version=VERSION,
author="Ciro Mattia Gonano, Pawel Jastrzebski",
author_email="ciromattia@gmail.com, pawelj@vulturis.eu",
description="A tool to convert comics (CBR/CBZ/PDFs/image folders) to MOBI.",
author_email="ciromattia@gmail.com, pawelj@iosphe.re",
description="Kindle Comic Converter",
license="ISC License (ISCL)",
keywords="kindle comic mobipocket mobi cbz cbr manga",
url="http://github.com/ciromattia/kcc",
packages=['kcc'], requires=['Pillow'],
**extra_options
)
if platform == "darwin":
from os import chmod, makedirs
from shutil import copyfile
makedirs('dist/' + NAME + '.app/Contents/PlugIns/platforms')
copyfile('other/libqcocoa.dylib', 'dist/' + NAME + '.app/Contents/PlugIns/platforms/libqcocoa.dylib')
chmod('dist/' + NAME + '.app/Contents/Resources/unrar', 0o777)
chmod('dist/' + NAME + '.app/Contents/Resources/7za', 0o777)

25
setup.sh Executable file
View File

@@ -0,0 +1,25 @@
#!/bin/bash
# Linux Python package build script
VERSION="4.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