1
0
mirror of https://github.com/ciromattia/kcc synced 2026-04-18 06:58:58 +00:00

Compare commits

...

83 Commits
3.5 ... 3.7.2

Author SHA1 Message Date
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
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
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
Paweł Jastrzębski
557bd2bbbf Added separate resolution for Kindle DX/DXG CBZ output (close #71) 2013-11-19 08:46:13 +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
23 changed files with 1447 additions and 690 deletions

8
.gitignore vendored
View File

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

View File

@@ -7,19 +7,19 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>420</width> <width>420</width>
<height>380</height> <height>397</height>
</rect> </rect>
</property> </property>
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>420</width> <width>420</width>
<height>380</height> <height>397</height>
</size> </size>
</property> </property>
<property name="maximumSize"> <property name="maximumSize">
<size> <size>
<width>420</width> <width>420</width>
<height>380</height> <height>397</height>
</size> </size>
</property> </property>
<property name="font"> <property name="font">
@@ -27,9 +27,6 @@
<pointsize>9</pointsize> <pointsize>9</pointsize>
</font> </font>
</property> </property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="windowTitle"> <property name="windowTitle">
<string>Kindle Comic Converter</string> <string>Kindle Comic Converter</string>
</property> </property>
@@ -391,7 +388,7 @@
p, li { white-space: pre-wrap; } 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;/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;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;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;br /&gt;&lt;/span&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-style:italic;&quot;&gt;Smaller images might be forcefully upscaled in this mode.&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> &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>
</property> </property>
<property name="text"> <property name="text">
@@ -419,7 +416,7 @@ p, li { white-space: pre-wrap; }
<enum>Qt::NoFocus</enum> <enum>Qt::NoFocus</enum>
</property> </property>
<property name="toolTip"> <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&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>
<property name="text"> <property name="text">
<string>Horizontal mode</string> <string>Horizontal mode</string>
@@ -546,9 +543,6 @@ p, li { white-space: pre-wrap; }
<family>DejaVu Sans</family> <family>DejaVu Sans</family>
</font> </font>
</property> </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"> <property name="text">
<string>Gamma: Auto</string> <string>Gamma: Auto</string>
</property> </property>
@@ -570,9 +564,6 @@ p, li { white-space: pre-wrap; }
<property name="focusPolicy"> <property name="focusPolicy">
<enum>Qt::ClickFocus</enum> <enum>Qt::ClickFocus</enum>
</property> </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"> <property name="maximum">
<number>500</number> <number>500</number>
</property> </property>
@@ -644,7 +635,7 @@ p, li { white-space: pre-wrap; }
<enum>Qt::NoFocus</enum> <enum>Qt::NoFocus</enum>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Do not convert images to grayscale.</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Don't convert images to grayscale.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
<property name="text"> <property name="text">
<string>Color mode</string> <string>Color mode</string>
@@ -785,6 +776,17 @@ p, li { white-space: pre-wrap; }
<zorder>OptionsExpert</zorder> <zorder>OptionsExpert</zorder>
<zorder>ProgressBar</zorder> <zorder>ProgressBar</zorder>
</widget> </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"> <action name="ActionBasic">
<property name="checkable"> <property name="checkable">
<bool>true</bool> <bool>true</bool>

View File

@@ -7,19 +7,19 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>420</width> <width>420</width>
<height>380</height> <height>397</height>
</rect> </rect>
</property> </property>
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>420</width> <width>420</width>
<height>380</height> <height>397</height>
</size> </size>
</property> </property>
<property name="maximumSize"> <property name="maximumSize">
<size> <size>
<width>420</width> <width>420</width>
<height>380</height> <height>397</height>
</size> </size>
</property> </property>
<property name="font"> <property name="font">
@@ -27,9 +27,6 @@
<pointsize>9</pointsize> <pointsize>9</pointsize>
</font> </font>
</property> </property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="windowTitle"> <property name="windowTitle">
<string>Kindle Comic Converter</string> <string>Kindle Comic Converter</string>
</property> </property>
@@ -391,7 +388,7 @@
<enum>Qt::NoFocus</enum> <enum>Qt::NoFocus</enum>
</property> </property>
<property name="toolTip"> <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-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;br/&gt;Smaller images might be forcefully upscaled in this mode.&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>
</property> </property>
<property name="text"> <property name="text">
<string>High/Ultra quality</string> <string>High/Ultra quality</string>
@@ -419,7 +416,7 @@
<enum>Qt::NoFocus</enum> <enum>Qt::NoFocus</enum>
</property> </property>
<property name="toolTip"> <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&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Disable splitting of two-page spreads.&lt;br/&gt;They will be rotated instead.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
<property name="text"> <property name="text">
<string>Horizontal mode</string> <string>Horizontal mode</string>
@@ -546,9 +543,6 @@
<bold>false</bold> <bold>false</bold>
</font> </font>
</property> </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"> <property name="text">
<string>Gamma: Auto</string> <string>Gamma: Auto</string>
</property> </property>
@@ -570,9 +564,6 @@
<property name="focusPolicy"> <property name="focusPolicy">
<enum>Qt::ClickFocus</enum> <enum>Qt::ClickFocus</enum>
</property> </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"> <property name="maximum">
<number>500</number> <number>500</number>
</property> </property>
@@ -648,7 +639,7 @@
<enum>Qt::NoFocus</enum> <enum>Qt::NoFocus</enum>
</property> </property>
<property name="toolTip"> <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&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Don't convert images to grayscale.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
<property name="text"> <property name="text">
<string>Color mode</string> <string>Color mode</string>
@@ -797,6 +788,17 @@
<zorder>OptionsAdvancedGamma</zorder> <zorder>OptionsAdvancedGamma</zorder>
<zorder>OptionsExpert</zorder> <zorder>OptionsExpert</zorder>
</widget> </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"> <action name="ActionBasic">
<property name="checkable"> <property name="checkable">
<bool>true</bool> <bool>true</bool>

View File

@@ -3,6 +3,7 @@
<file>icons/comic2ebook.png</file> <file>icons/comic2ebook.png</file>
</qresource> </qresource>
<qresource prefix="Devices"> <qresource prefix="Devices">
<file>icons/Kobo.png</file>
<file>icons/Other.png</file> <file>icons/Other.png</file>
<file>icons/Kindle.png</file> <file>icons/Kindle.png</file>
</qresource> </qresource>

32
KCC.ui
View File

@@ -7,19 +7,19 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>420</width> <width>420</width>
<height>380</height> <height>397</height>
</rect> </rect>
</property> </property>
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>420</width> <width>420</width>
<height>380</height> <height>397</height>
</size> </size>
</property> </property>
<property name="maximumSize"> <property name="maximumSize">
<size> <size>
<width>420</width> <width>420</width>
<height>380</height> <height>397</height>
</size> </size>
</property> </property>
<property name="font"> <property name="font">
@@ -27,9 +27,6 @@
<pointsize>9</pointsize> <pointsize>9</pointsize>
</font> </font>
</property> </property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="windowTitle"> <property name="windowTitle">
<string>Kindle Comic Converter</string> <string>Kindle Comic Converter</string>
</property> </property>
@@ -343,7 +340,7 @@
p, li { white-space: pre-wrap; } 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;/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;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;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 a little blurry.&lt;br /&gt;Smaller images might be forcefully upscaled in this mode.&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> &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>
</property> </property>
<property name="text"> <property name="text">
@@ -366,7 +363,7 @@ p, li { white-space: pre-wrap; }
<enum>Qt::NoFocus</enum> <enum>Qt::NoFocus</enum>
</property> </property>
<property name="toolTip"> <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&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>
<property name="text"> <property name="text">
<string>Horizontal mode</string> <string>Horizontal mode</string>
@@ -472,9 +469,6 @@ p, li { white-space: pre-wrap; }
<height>40</height> <height>40</height>
</rect> </rect>
</property> </property>
<property name="toolTip">
<string>When converting color images setting this option to 1.0 MIGHT improve readability.</string>
</property>
<property name="text"> <property name="text">
<string>Gamma: Auto</string> <string>Gamma: Auto</string>
</property> </property>
@@ -491,9 +485,6 @@ p, li { white-space: pre-wrap; }
<property name="focusPolicy"> <property name="focusPolicy">
<enum>Qt::ClickFocus</enum> <enum>Qt::ClickFocus</enum>
</property> </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"> <property name="maximum">
<number>500</number> <number>500</number>
</property> </property>
@@ -558,7 +549,7 @@ p, li { white-space: pre-wrap; }
<enum>Qt::NoFocus</enum> <enum>Qt::NoFocus</enum>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Do not convert images to grayscale.</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Don't convert images to grayscale.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
<property name="text"> <property name="text">
<string>Color mode</string> <string>Color mode</string>
@@ -674,6 +665,17 @@ p, li { white-space: pre-wrap; }
<zorder>OptionsExpert</zorder> <zorder>OptionsExpert</zorder>
<zorder>ProgressBar</zorder> <zorder>ProgressBar</zorder>
</widget> </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"> <action name="ActionBasic">
<property name="checkable"> <property name="checkable">
<bool>true</bool> <bool>true</bool>

114
README.md
View File

@@ -1,6 +1,6 @@
# KCC # 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 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**_. 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. It can also optionally optimize images by applying a number of transformations.
@@ -8,60 +8,51 @@ It can also optionally optimize images by applying a number of transformations.
### A word of warning ### A word of warning
**KCC** _is not_ [Amazon's Kindle Comic Creator](http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1001103761) nor is in any way endorsed by Amazon. **KCC** _is not_ [Amazon's Kindle Comic Creator](http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1001103761) nor is in any way endorsed by Amazon.
Amazon's tool is for comic publishers and involves a lot of manual effort, while **KCC** is for comic readers. Amazon's tool is for comic publishers and involves a lot of manual effort, while **KCC** is for comic 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: 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) [![Flattr this](http://api.flattr.com/button/flattr-badge-large.png)](http://flattr.com/thing/2260449/ciromattiakcc-on-GitHub)
* 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) [![1W15wwqsfd7wbaZ6wvSJf1LW1bz6q5L8b](http://s30.postimg.org/6z3kwvdlp/BC_Rnd.png)](bitcoin:1W15wwqsfd7wbaZ6wvSJf1LW1bz6q5L8b?label=KCC) [1W15wwqsfd7wbaZ6wvSJf1LW1bz6q5L8b](bitcoin:1W15wwqsfd7wbaZ6wvSJf1LW1bz6q5L8b?label=KCC)
* 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)
## BINARY RELEASES ## BINARY RELEASES
You can find the latest released binary at the following links: You can find the latest released binary at the following links:
- **Win64:** [http://kcc.vulturis.eu/Win64/](http://kcc.vulturis.eu/Win64/) - **Windows:** [http://kcc.vulturis.eu/Windows/](http://kcc.vulturis.eu/Windows/)
- **Win32:** [http://kcc.vulturis.eu/Win32/](http://kcc.vulturis.eu/Win32/) - **Linux:** [http://kcc.vulturis.eu/Linux/](http://kcc.vulturis.eu/Linux/)
- **OS X:** [http://kcc.vulturis.eu/OSX/](http://kcc.vulturis.eu/OSX/) - **OS X 10.8+:** [http://kcc.vulturis.eu/OSX/](http://kcc.vulturis.eu/OSX/)
- **Linux:** Just download sourcecode and launch: `python kcc.py`
## INPUT FORMATS ## INPUT FORMATS
**KCC** can understand and convert, at the moment, the following file types: **KCC** can understand and convert, at the moment, the following input types:
- PNG, JPG, GIF, TIFF, BMP - Folders containing: PNG, JPG, GIF, TIFF or BMP files
- Folders
- CBZ, ZIP - CBZ, ZIP
- CBR, RAR *(With `unrar` executable)* - CBR, RAR *(With `unrar` executable)*
- CB7, 7Z *(With `7za` executable)* - CB7, 7Z *(With `7za` executable)*
- PDF *(Extracting only contained JPG images)* - PDF *(Extracting only contained JPG images)*
## OPTIONAL REQUIREMENTS ## 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)* - [UnRAR](http://www.rarlab.com/download.htm) *(For CBR/RAR support)*
- [7za](http://www.7-zip.org/download.html) *(For 7z/CB7 support)* - [7za](http://www.7-zip.org/download.html) *(For 7z/CB7 support)*
### For compiling/running from source: ### 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. - 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. - [PyQt4](http://www.riverbankcomputing.co.uk/software/pyqt/download) - 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. - [Pillow](http://pypi.python.org/pypi/Pillow/) 2.3.0+ - 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) - [Psutil](https://code.google.com/p/psutil/) - Please refer to official documentation for installing into your system.
- **To build OS X release you need a modified QT:** [patch](https://github.com/ciromattia/kcc/blob/master/other/QT-4.8.5-QListWidget.patch)
## USAGE ## 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. 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). After completed conversion you should find ready file alongside the original input file (same directory).
Please check [our wiki](https://github.com/ciromattia/kcc/wiki/) for more details.
### Standalone `comic2ebook.py` usage: ### Standalone `comic2ebook.py` usage:
``` ```
@@ -70,7 +61,7 @@ Usage: comic2ebook.py [options] comic_file|comic_folder
Options: Options:
MAIN: MAIN:
-p PROFILE, --profile=PROFILE -p PROFILE, --profile=PROFILE
Device profile (Choose one among K1, K2, K345, KDX, KHD, KF, KFHD, KFHD8, KFHDX, KFHDX8, KFA) [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 -q QUALITY, --quality=QUALITY
Quality of Panel View. 0 - Normal 1 - High 2 - Ultra [Default=0] Quality of Panel View. 0 - Normal 1 - High 2 - Ultra [Default=0]
-m, --manga-style Manga style (Right-to-left reading and splitting) -m, --manga-style Manga style (Right-to-left reading and splitting)
@@ -118,6 +109,7 @@ Options:
-y HEIGHT, --height=HEIGHT -y HEIGHT, --height=HEIGHT
Height of the target device screen Height of the target device screen
-i, --in-place Overwrite source directory -i, --in-place Overwrite source directory
-m, --merge Combine every directory into a single image before splitting
OTHER: OTHER:
-d, --debug Create debug file for every splitted image -d, --debug Create debug file for every splitted image
@@ -140,37 +132,40 @@ The app relies and includes the following scripts/binaries:
* [Kindle Paperwhite](http://kcc.vulturis.eu/Samples/Ubunchu!-KPW.mobi) * [Kindle Paperwhite](http://kcc.vulturis.eu/Samples/Ubunchu!-KPW.mobi)
* [Kindle](http://kcc.vulturis.eu/Samples/Ubunchu!-K345.mobi) * [Kindle](http://kcc.vulturis.eu/Samples/Ubunchu!-K345.mobi)
* [Kindle DX/DXG](http://kcc.vulturis.eu/Samples/Ubunchu!-KDX.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](http://kcc.vulturis.eu/Samples/Ubunchu!-KFHD.mobi)
* [Kindle Fire HD 8.9"](http://kcc.vulturis.eu/Samples/Ubunchu!-KFHD8.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](http://kcc.vulturis.eu/Samples/Ubunchu!-KFHDX.mobi)
* [Kindle Fire HDX 8.9"](http://kcc.vulturis.eu/Samples/Ubunchu!-KFHDX8.mobi) * [Kindle Fire HDX 8.9"](http://kcc.vulturis.eu/Samples/Ubunchu!-KFHDX8.mobi)
* [Kobo Mini/Touch](http://kcc.vulturis.eu/Samples/Ubunchu!-KoMT.cbz)
* [Kobo Glow](http://kcc.vulturis.eu/Samples/Ubunchu!-KoG.cbz)
* [Kobo Aura](http://kcc.vulturis.eu/Samples/Ubunchu!-KoA.cbz)
* [Kobo Aura HD](http://kcc.vulturis.eu/Samples/Ubunchu!-KoAHD.cbz)
## CHANGELOG ## CHANGELOG
####1.00 ####1.0
* Initial version * Initial version
####1.10 ####1.1
* Added support for CBZ/CBR files in comic2ebook.py * Added support for CBZ/CBR files in comic2ebook.py
####1.11 ####1.1.1
* Added support for CBZ/CBR files in KindleComicConverter * 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! * 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 * Fixed an issue in OPF generation for device resolution
* Reworked options system (call with -h option to get the inline help) * Reworked options system (call with -h option to get the inline help)
####1.40 ####1.4
* Added some options for controlling image optimization * Added some options for controlling image optimization
* Further optimization (ImageOps, page numbering cut, autocontrast) * 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 * Fixed a serious bug on resizing when img ratio was bigger than device one
####1.50 ####1.5
* Added subfolder support for multiple chapters. * Added subfolder support for multiple chapters.
####2.0 ####2.0
@@ -179,7 +174,7 @@ The app relies and includes the following scripts/binaries:
####2.1 ####2.1
* Added basic error reporting * Added basic error reporting
#### 2.2: ####2.2:
* Added (valid!) ePub 2.0 output * Added (valid!) ePub 2.0 output
* Rename .zip files to .cbz to avoid overwriting * Rename .zip files to .cbz to avoid overwriting
@@ -284,6 +279,39 @@ The app relies and includes the following scripts/binaries:
* Improved multiprocessing speed * Improved multiprocessing speed
* GUI tweaks and minor bug fixes * GUI tweaks and minor bug fixes
####3.6:
* Increased quality of Panel View zoom
* Creation of multipart MOBI output is now faster on machines with 4GB+ RAM
* Automatic gamma correction now distinguishes color and grayscale images
* Added ComicRack metadata parser
* Implemented new method to detect border color in non-webtoon comics
* Upscaling is now enabled by default for Kindle Fire HD/HDX
* Windows nad Linux releases now have tray icon
* Fixed Kindle Fire HDX 7" output
* Increased target resolution for Kindle DX/DXG CBZ output
####3.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
## COPYRIGHT ## COPYRIGHT
Copyright (c) 2012-2013 Ciro Mattia Gonano and Paweł Jastrzębski. Copyright (c) 2012-2013 Ciro Mattia Gonano and Paweł Jastrzębski.

BIN
icons/Kobo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

10
kcc.iss
View File

@@ -1,5 +1,5 @@
#define MyAppName "Kindle Comic Converter" #define MyAppName "Kindle Comic Converter"
#define MyAppVersion "3.5" #define MyAppVersion "3.7.2"
#define MyAppPublisher "Ciro Mattia Gonano, Paweł Jastrzębski" #define MyAppPublisher "Ciro Mattia Gonano, Paweł Jastrzębski"
#define MyAppURL "http://kcc.vulturis.eu/" #define MyAppURL "http://kcc.vulturis.eu/"
#define MyAppExeName "KCC.exe" #define MyAppExeName "KCC.exe"
@@ -12,6 +12,7 @@ AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL} AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL} AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL} AppUpdatesURL={#MyAppURL}
AppCopyright=Copyright (C) 2012-2013 Ciro Mattia Gonano and Paweł Jastrzębski
DefaultDirName={pf}\{#MyAppName} DefaultDirName={pf}\{#MyAppName}
DefaultGroupName={#MyAppName} DefaultGroupName={#MyAppName}
AllowNoIcons=yes AllowNoIcons=yes
@@ -28,6 +29,7 @@ UninstallDisplayName={#MyAppName}
UninstallDisplayIcon={app}\{#MyAppExeName} UninstallDisplayIcon={app}\{#MyAppExeName}
ChangesAssociations=True ChangesAssociations=True
InfoAfterFile=other\InstallWarning.rtf InfoAfterFile=other\InstallWarning.rtf
SignTool=SignTool /d $q{#MyAppName}$q /du $q{#MyAppURL}$q $f
[Languages] [Languages]
Name: "english"; MessagesFile: "compiler:Default.isl" Name: "english"; MessagesFile: "compiler:Default.isl"
@@ -63,6 +65,8 @@ Source: "build\exe.win-amd64-2.7\select.pyd"; DestDir: "{app}"; Flags: ignorever
Source: "build\exe.win-amd64-2.7\sip.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\SSLEAY32.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
Source: "build\exe.win-amd64-2.7\unicodedata.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode Source: "build\exe.win-amd64-2.7\unicodedata.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
Source: "build\exe.win-amd64-2.7\_psutil_mswindows.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
Source: "other\vcredist_x64.exe"; DestDir: "{tmp}"; Flags: ignoreversion deleteafterinstall; Check: Is64BitInstallMode
; x86 files ; x86 files
Source: "build\exe.win32-2.7\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion solidbreak; Check: not Is64BitInstallMode 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\_ctypes.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
@@ -87,6 +91,8 @@ Source: "build\exe.win32-2.7\select.pyd"; DestDir: "{app}"; Flags: ignoreversion
Source: "build\exe.win32-2.7\sip.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\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: "build\exe.win32-2.7\unicodedata.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
Source: "build\exe.win32-2.7\_psutil_mswindows.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
Source: "other\vcredist_x86.exe"; DestDir: "{tmp}"; Flags: ignoreversion deleteafterinstall; Check: not Is64BitInstallMode
; Common files ; Common files
Source: "LICENSE.txt"; DestDir: "{app}"; Flags: ignoreversion solidbreak Source: "LICENSE.txt"; DestDir: "{app}"; Flags: ignoreversion solidbreak
Source: "other\Additional-LICENSE.txt"; DestDir: "{app}"; Flags: ignoreversion Source: "other\Additional-LICENSE.txt"; DestDir: "{app}"; Flags: ignoreversion
@@ -100,6 +106,8 @@ Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks:
[Run] [Run]
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
Filename: "{tmp}\vcredist_x64.exe"; Parameters: "/passive /Q:a /c:""msiexec /qb /i vcredist.msi"" "; StatusMsg: "Installing Microsoft Visual C++ 2008 Redistributable Package..."; Check: Is64BitInstallMode
Filename: "{tmp}\vcredist_x86.exe"; Parameters: "/passive /Q:a /c:""msiexec /qb /i vcredist.msi"" "; StatusMsg: "Installing Microsoft Visual C++ 2008 Redistributable Package..."; Check: not Is64BitInstallMode
[Messages] [Messages]
WelcomeLabel1=Welcome to the KCC Setup Wizard WelcomeLabel1=Welcome to the KCC Setup Wizard

47
kcc.py
View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/env python2
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (c) 2012-2013 Ciro Mattia Gonano <ciromattia@gmail.com> # Copyright (c) 2012-2013 Ciro Mattia Gonano <ciromattia@gmail.com>
@@ -18,7 +18,7 @@
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE. # PERFORMANCE OF THIS SOFTWARE.
__version__ = '3.5' __version__ = '3.7.2'
__license__ = 'ISC' __license__ = 'ISC'
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>' __copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
@@ -26,26 +26,32 @@ __docformat__ = 'restructuredtext en'
import sys import sys
import os import os
try: try:
#noinspection PyUnresolvedReferences # noinspection PyUnresolvedReferences
from PyQt4 import QtCore, QtGui, QtNetwork from PyQt4 import QtCore, QtGui, QtNetwork
except ImportError: except ImportError:
print "ERROR: PyQT4 is not installed!" print "ERROR: PyQT4 is not installed!"
if sys.platform.startswith('linux'):
import Tkinter
import tkMessageBox
importRoot = Tkinter.Tk()
importRoot.withdraw()
tkMessageBox.showerror("KCC - Error", "PyQT4 is not installed!")
exit(1) exit(1)
from kcc import KCC_gui from kcc import KCC_gui
from multiprocessing import freeze_support from multiprocessing import freeze_support
# OS specific PATH variable workarounds
if sys.platform.startswith('darwin'): if sys.platform.startswith('darwin'):
# Workaround Finder-launched app PATH evaluation if 'RESOURCEPATH' in os.environ:
os.environ['PATH'] = '/usr/local/bin:' + os.environ['PATH'] os.environ['PATH'] = os.environ['RESOURCEPATH'] + ':' + os.environ['PATH']
from kcc import KCC_ui_osx as KCC_ui else:
elif sys.platform.startswith('linux'): os.environ['PATH'] = os.path.dirname(os.path.abspath(__file__)) + '/other/:' + os.environ['PATH']
from kcc import KCC_ui_linux as KCC_ui elif sys.platform.startswith('win'):
else:
# Workaround for Windows file association mechanism
if getattr(sys, 'frozen', False): if getattr(sys, 'frozen', False):
os.chdir(os.path.dirname(os.path.abspath(sys.executable))) os.chdir(os.path.dirname(os.path.abspath(sys.executable)))
else: else:
os.environ['PATH'] = os.path.dirname(os.path.abspath(__file__)) + '/other/;' + os.environ['PATH']
os.chdir(os.path.dirname(os.path.abspath(__file__))) os.chdir(os.path.dirname(os.path.abspath(__file__)))
from kcc import KCC_ui
# Implementing detection of already running KCC instance and forwarding argv to it # Implementing detection of already running KCC instance and forwarding argv to it
@@ -89,10 +95,10 @@ class QApplicationMessaging(QtGui.QApplication):
return False return False
freeze_support() freeze_support()
APP = QApplicationMessaging(sys.argv) KCCAplication = QApplicationMessaging(sys.argv)
if APP.isRunning(): if KCCAplication.isRunning():
if len(sys.argv) > 1: if len(sys.argv) > 1:
APP.sendMessage(sys.argv[1].decode(sys.getfilesystemencoding())) KCCAplication.sendMessage(sys.argv[1].decode(sys.getfilesystemencoding()))
sys.exit(0) sys.exit(0)
else: else:
messageBox = QtGui.QMessageBox() messageBox = QtGui.QMessageBox()
@@ -101,13 +107,8 @@ if APP.isRunning():
messageBox.setWindowIcon(icon) messageBox.setWindowIcon(icon)
QtGui.QMessageBox.critical(messageBox, 'KCC - Error', 'KCC is already running!', QtGui.QMessageBox.Ok) QtGui.QMessageBox.critical(messageBox, 'KCC - Error', 'KCC is already running!', QtGui.QMessageBox.Ok)
sys.exit(1) sys.exit(1)
KCC = QtGui.QMainWindow() KCCWindow = QtGui.QMainWindow()
UI = KCC_ui.Ui_KCC() KCCUI = KCC_gui.KCCGUI(KCCAplication, KCCWindow)
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: if len(sys.argv) > 1:
GUI.handleMessage(sys.argv[1].decode(sys.getfilesystemencoding())) KCCUI.handleMessage(sys.argv[1].decode(sys.getfilesystemencoding()))
sys.exit(APP.exec_()) sys.exit(KCCAplication.exec_())

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
# Resource object code # Resource object code
# #
# Created: N 6. paź 13:26:15 2013 # Created: Pt 27. gru 09:24:15 2013
# by: The Resource Compiler for PyQt (Qt v4.8.5) # by: The Resource Compiler for PyQt (Qt v4.8.5)
# #
# WARNING! All changes made in this file will be lost! # WARNING! All changes made in this file will be lost!
@@ -8358,6 +8358,158 @@ qt_resource_data = "\
\x5f\x00\xdc\x06\xf0\x91\x73\xee\x3b\x8e\x03\x82\x20\x08\x82\x20\ \x5f\x00\xdc\x06\xf0\x91\x73\xee\x3b\x8e\x03\x82\x20\x08\x82\x20\
\x08\x82\x20\x08\x82\x20\x08\x62\x23\xf8\x1f\x8e\x96\x1e\x7d\x49\ \x08\x82\x20\x08\x82\x20\x08\x62\x23\xf8\x1f\x8e\x96\x1e\x7d\x49\
\xfc\xce\x76\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\ \xfc\xce\x76\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
\x00\x00\x09\x54\
\x89\
\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
\x00\x00\x80\x00\x00\x00\x80\x08\x06\x00\x00\x00\xc3\x3e\x61\xcb\
\x00\x00\x09\x1b\x49\x44\x41\x54\x78\xda\xed\x9d\x7f\x8c\x14\x67\
\x19\xc7\x3f\xef\xec\xec\x71\xcb\x1d\x72\x77\xd8\xbb\x63\x0f\x7a\
\xb6\x0d\x28\x98\x6a\xea\x4a\x8c\xa5\x35\xa9\x56\x62\xa2\x89\x11\
\x88\xd4\xc6\x98\x02\x96\x06\x42\x4d\xda\x44\x8b\xda\x54\x8d\x36\
\xd5\xc4\x68\x62\xa9\x50\x51\x92\xca\x1f\x4d\x2d\xa8\x69\x54\x1a\
\xff\xb0\x92\xa0\xa9\xe0\x24\x10\x8b\x28\x1c\xe5\xc7\x71\x2c\x5c\
\xe1\xe0\x7e\x71\x77\xbb\x33\xf3\xfa\x47\xef\x70\x6f\xd9\x99\xdb\
\xe3\x6e\x77\xe7\xc7\xf3\x4d\x36\x7b\xb7\xb7\xb7\x33\xfb\x3c\x9f\
\xf7\x79\x9e\xf7\xc7\xcc\x0b\x22\x91\x48\x24\x12\x89\x44\x22\x91\
\x48\x24\x12\x89\x44\x22\x91\x28\xfa\x52\x41\x38\x89\x4c\x26\xd3\
\x01\xac\x02\x3a\x81\xf9\x31\xb2\xff\x75\xe0\x3c\xf0\x57\xcb\xb2\
\x8e\xc7\x0e\x80\x4c\x26\xb3\x0c\xf8\x21\xf0\x39\xc0\x88\x79\x63\
\x3c\x04\x7c\xc3\xb2\xac\x03\xd5\x3c\x68\xa2\x86\xce\x5f\x03\xfc\
\x09\xb8\x3b\x28\x91\xa8\xc6\xea\x00\xbe\x92\x4e\xa7\x73\xd9\x6c\
\xf6\x60\xa4\x01\xc8\x64\x32\x0f\x00\xbf\x07\xea\xc5\xef\x37\x45\
\xe4\x07\xd3\xe9\xf4\xe5\x6c\x36\x7b\x38\x92\x29\x20\x93\xc9\xa4\
\x80\x13\xc0\x22\xf1\xb7\xa7\xc6\x80\xe5\x96\x65\xbd\x5d\xe9\x03\
\xd5\x22\xef\x3e\x2a\xce\x9f\x52\x73\x80\x6f\x56\xe3\x40\xb5\x00\
\x60\xad\xf8\xb7\x2c\x7d\x21\x93\xc9\x24\xa2\x08\xc0\x3d\xe2\xdb\
\xb2\xb4\x60\xbc\x5b\x1c\x1d\x00\x32\x99\x4c\x03\xd0\x28\xbe\x2d\
\x5b\x6d\x51\x8b\x00\x49\xf1\x69\xb0\xec\x65\x88\x8d\xe3\x2d\x33\
\x48\x27\x93\x4a\xa5\xe8\xec\x2c\x2f\xed\x29\xf5\x6e\x0f\xd6\x30\
\x0c\x94\x52\x68\xad\x27\x3d\x82\xae\x91\x91\x11\xce\x9e\x3d\x2b\
\x00\x14\x6a\xc9\x92\x25\xec\xdc\xb9\x33\x16\x2d\xef\xe8\xd1\xa3\
\x6c\xde\xbc\x59\x00\x98\x89\x26\xa2\x40\xb1\xc2\x10\x01\x24\x05\
\xcc\x82\xe3\x0b\x01\x98\x48\x03\x85\x3f\x0b\x08\x11\x04\x40\x29\
\x35\x09\x80\x62\x08\x0a\x23\x80\x80\x10\x31\x00\x26\x1c\x5e\x0c\
\x81\xd7\x7b\x0b\x1d\x2f\x10\x44\x2c\x02\x78\x39\xbe\x54\x6a\x70\
\x5d\x57\x20\x08\x3b\x00\xa5\x5a\xbf\x57\x31\x58\x98\x02\x26\xba\
\x8a\x5a\x6b\x5c\xd7\x15\x08\x8a\x64\x44\xcd\xf9\xa5\x5e\x9b\xf8\
\x3f\xc3\x30\x6e\x8c\x1b\x88\x42\x12\x01\xa6\xeb\x7c\xbf\x82\x50\
\xba\x8b\x21\x03\xa0\xd8\xf9\xb7\xd2\x72\x6f\x14\x83\xae\x83\x32\
\x12\x32\x6e\x10\x16\x00\xa6\x72\xfe\x74\x60\x50\x4a\xa1\xc7\x9d\
\x3f\xf1\x59\xa5\x86\x8d\xe3\x08\x82\x19\x34\xa7\xfb\xf5\xfb\x8b\
\x5b\xed\xb4\x21\x28\x70\xf0\x74\x41\x88\xea\xa8\x63\xa0\x00\x30\
\x0c\xa3\xac\xae\xde\xad\x16\x71\xc5\x10\x14\x7e\x56\x21\x0c\x85\
\xf5\xc3\x74\x8e\x15\x46\x18\x02\x1d\x01\xbc\x46\xfa\x66\x7a\x0c\
\x2f\x08\x8a\x8b\x47\xaf\x88\x54\x1c\x49\xc2\x9c\x46\x02\x19\x01\
\x26\x0c\xfb\xef\x1e\x87\xbd\x87\xf2\x8c\xd9\x35\x34\xaa\xc6\x7b\
\xed\xb4\x9e\x78\xd2\x93\x5e\x9b\xf4\x3b\x30\xc7\x54\xac\x59\x61\
\xb2\x2c\x6d\x08\x00\x7e\x2d\xb3\x30\x05\x1c\xef\x71\xf8\xea\xaf\
\x46\x22\x53\x6c\xfd\xf9\x2d\x87\x17\xd7\xcf\x09\x1c\x04\x81\x43\
\x72\x22\xec\xbe\x7a\x28\x1f\xb9\x8a\x7b\xdf\x61\x3b\x70\xe7\x14\
\x18\x00\x8a\x73\x67\x4d\xc3\x7e\x85\x14\xc4\xef\x14\xa8\x08\x20\
\x63\xf5\x31\x2f\x02\x67\x6b\xd6\xce\x9d\xe2\xdf\x0d\x99\x0a\x08\
\x36\x00\x33\x91\xe3\xc2\x86\x95\x39\x96\xb6\xe9\x92\x8e\x3f\x91\
\x75\xd8\x75\x30\x89\x69\xca\x0a\xf5\xc0\x01\x30\x1b\xe1\xdf\xd5\
\x70\x7b\xb3\xcb\xf2\x76\xb7\x24\x00\xa3\xa3\x36\xb9\xbe\x33\x98\
\xb7\x2d\x05\x65\xc6\x1e\x00\x23\x88\x00\x54\xb6\x0e\x70\x41\xbb\
\xe4\xfa\xba\xfe\xdf\x91\x17\x00\x02\x28\x5d\x31\xca\xc6\x9f\x1d\
\x72\x57\xfe\x0b\x6e\x5e\x00\x88\x95\x0a\xeb\x0c\xed\x90\xbb\xda\
\x05\xda\x11\x00\x82\x17\x00\x2a\x14\x02\x8a\x7b\x00\xda\x25\xd7\
\x77\x32\xb6\xe9\x40\xae\x0d\xbc\x91\x0e\xfe\x53\xf1\x74\xa0\x02\
\x78\x2b\x24\x01\xa0\x30\x12\xc4\x30\x1d\x08\x00\x31\x4f\x07\x02\
\x40\x8d\xd2\x81\x00\x10\x8a\x74\xe0\xa2\xc7\xe3\x81\xd7\x23\xec\
\x92\xa1\x30\x0f\xe5\xf3\x0e\x1f\x6d\xee\xe6\xae\xce\x85\xe0\xb3\
\x34\xed\xd2\x35\x9b\x83\x6f\xd7\x13\xd6\x4b\x0d\x04\x80\x52\x01\
\x40\xc3\xa7\x3e\xd4\xc8\xf7\x1f\x6e\x63\x2c\xef\x3d\x87\xdf\xd3\
\x67\xb3\x71\x7b\x37\x24\xe7\x61\xbe\xe7\x76\x01\x20\x2a\xce\x5f\
\xfc\xde\x3a\xbe\xb5\xb6\x95\xa1\x51\xef\xc9\x29\x17\xd8\xfa\x8b\
\x9e\x77\x67\x1e\x73\x83\xe4\xfb\xcf\x92\x9c\xdf\x19\xba\xef\x2b\
\x35\x40\x91\x16\x36\x27\x79\x61\x53\x1a\xc7\x67\x62\xd2\x76\x34\
\x1b\x7e\xd6\x3d\x09\x10\x9d\x1f\x24\x7f\xcd\xff\xc6\x9e\x1a\x59\
\x10\x12\x68\x35\x37\x9a\x6c\xdf\x94\xc6\x4c\x78\x27\x74\x57\xc3\
\xb6\x3d\x59\x7a\xfb\xed\xa2\xbc\xaf\xd0\xf6\x08\xf6\xc0\x39\x89\
\x00\x61\x94\x52\xf0\x93\xf5\x0b\x49\xd5\x79\x9b\xc4\x50\xf0\xec\
\xde\x5e\x8e\x9f\x1f\xf3\x2c\xfa\xdc\xdc\x20\xf9\xfe\x33\x02\x40\
\x98\x94\x30\x14\x2f\x6e\x5e\x44\x7b\x93\xe9\xeb\xfc\xe7\xf6\xf5\
\x72\xf0\xf8\xd0\xd4\x75\x44\x7e\x88\xfc\xb5\xd3\x02\x40\x18\xe4\
\xb8\xf0\xd4\xea\xdb\xe8\x68\x49\x7a\x2e\x25\xab\x33\x15\xfb\xde\
\xec\xe7\xc0\xb1\x61\xcc\xb2\xd6\x93\x29\xb4\x7d\x1d\x7b\xa0\x5b\
\x00\x08\xba\x9e\x5e\xdb\xca\x7d\xcb\x1a\x7c\xdf\xf3\xbb\x7f\x0c\
\xb0\xf3\xf5\x2b\xd3\xee\xeb\xbb\xb9\x81\xc0\xa7\x83\xd8\x02\x90\
\xb3\x35\x1b\x1f\x6c\xe1\x13\x1f\x6c\xc0\x6b\x01\x52\xc2\x50\x1c\
\x3a\x79\x9d\x9f\xef\xbf\xec\x5b\x18\x86\x39\x1d\xc4\x12\x80\xbc\
\xa3\xf9\x6c\x66\x1e\x5f\xbc\xb7\xc9\x33\xec\x1b\x0a\xba\xb2\x63\
\x3c\xf3\xf2\xc5\x99\x96\x97\x81\x4e\x07\xf1\x03\x40\xc3\xfd\xcb\
\x1b\x79\x6a\x75\x2b\xb6\xcf\xfa\xf1\x2b\x83\x0e\x8f\xed\x38\x4f\
\x62\x96\xd6\x90\xbb\xb9\x01\xec\xc1\xf3\x02\x40\x8d\x7d\x4f\x6b\
\x93\xc9\xb7\xd7\xb6\x32\x96\xf7\x76\xbe\xd6\xb0\x75\x57\x0f\x49\
\x33\xfa\x17\x10\xc4\x6a\x28\x58\x6b\xe8\x58\x90\xc4\x6f\xd1\x71\
\xde\xd6\xac\xdf\x7e\x9e\xab\x43\x0e\x71\xb8\x97\x54\xec\x52\x80\
\x9f\xf3\xeb\xeb\x14\x4f\xbf\x7c\x89\xab\x43\x36\x71\xb9\x91\x58\
\xec\x00\xf0\x73\xec\x58\x5e\xb3\xe5\x33\x2d\xbe\xb5\x81\x00\x10\
\x72\xe7\x5f\xee\xb7\x71\x3c\x1c\xac\x35\xdc\xd1\x5a\xc7\x8e\xc7\
\x16\x49\x04\x88\x24\x00\x40\xf7\xe5\x3c\x3f\x7d\xed\x1d\xea\x3d\
\xc6\xfc\x5d\x0d\x77\xb6\xd5\xf1\xdd\x75\xed\x8c\xe4\x5c\x01\xa0\
\x76\xce\x52\x15\xa3\xe0\x0f\xff\x1c\xe4\xf9\x3f\xbe\xe3\x3b\xb8\
\x73\xef\x07\xe6\xf2\xbd\x87\xda\x7d\xa7\x85\x05\x80\x90\x6a\x4e\
\x52\xf1\x9b\xbf\xf5\xf3\xda\xa1\x01\xcf\x4b\xc5\x73\xb6\xe6\x81\
\xbb\x1b\x79\xe4\x93\xcd\x44\xb9\x24\x88\xed\x50\x70\x9d\xa9\x78\
\x61\xff\x65\xde\xf8\xd7\x90\xe7\x60\x8f\xed\x68\xbe\x74\x7f\x13\
\x0f\xdd\xd7\xe4\x59\x37\x08\x00\x95\x4c\xd8\x55\xd0\x0f\xf6\xf6\
\xf2\xc6\x5b\x43\x9e\x45\x9f\xd6\xb0\xe9\xd3\x2d\xac\xfd\x78\x13\
\x51\xbc\x79\x49\xa0\x00\x98\x6a\x13\x88\x4a\x45\x82\x1f\xfd\xb6\
\x97\x33\xbd\x39\xcf\x74\x30\x66\x6b\x1e\x5d\xd5\xc2\x47\xee\x4a\
\xe1\xba\x02\x40\xc5\x54\xcb\xfb\x03\x3d\xbe\xeb\x02\xa7\x7b\x73\
\x3e\xe7\x06\xcf\x3e\xdc\xce\xc7\x96\xce\x15\x00\x2a\x1d\x01\x6a\
\x21\xc7\xd5\x3c\xb9\x3b\xcb\x85\x3e\xef\x2b\x82\x34\xf0\xcc\xba\
\x56\x96\x2f\xae\x8f\x4c\x3a\x90\x08\x50\xa0\xd1\xbc\xcb\x13\xbb\
\x2f\x70\x7d\xcc\xf5\x2c\x41\x0c\xa5\x78\xee\xcb\xed\xb4\x35\x99\
\x91\x80\x20\x90\x45\x60\x2d\x41\x18\x1c\x71\x59\xff\x7c\x37\xc3\
\x63\xde\xc9\xde\x4c\x28\x76\x6d\x59\x44\x5b\x93\x29\x00\x54\x8e\
\x82\x5a\xa5\x21\x18\x1a\x75\xd9\xb6\x27\xeb\xdb\xc2\xcd\x84\xe2\
\xc7\x8f\xa4\x69\x98\x63\x84\xfa\x1a\x41\x59\x15\xec\xa1\xae\x8b\
\x39\xb6\xee\xea\xf1\xed\xff\x2f\x98\x97\x60\xf7\xe3\x8b\x99\x5b\
\x67\x08\x00\xb3\x1f\x00\x6e\xb5\x5d\x29\x52\x49\x97\xc6\x7a\xe3\
\xe6\x47\x2a\xe1\xbb\xee\xbf\x78\x18\xe2\xf4\xa5\x1c\xdb\xf6\x5c\
\x64\x5e\xca\x28\xfd\x79\xf5\x06\x0b\x9b\x4d\x5e\xfa\xda\x62\x92\
\x65\xac\x19\x0c\xe2\xfc\x52\xe4\x16\x84\x24\x13\x9a\x27\x5e\x49\
\x32\xd2\x77\x0a\xed\xe4\x6e\x32\xbb\x99\xa0\x7c\x08\x14\x1c\x3b\
\x37\xca\x3d\x4f\x9e\x9c\xf2\x7d\x8d\xf5\xe1\x8c\x02\x91\x5c\x11\
\x94\xaa\x4f\x92\x4a\xbf\x9f\x7c\xdf\x09\xb4\x3b\xb3\x3b\x74\x2b\
\x05\xf3\x52\xd1\xcd\x94\x11\xae\x01\x14\xc9\xe6\x25\xa8\x84\xdc\
\x12\x36\xbe\x45\xa0\x32\x48\xce\xbf\x13\x65\xc8\x55\xf0\xa1\x00\
\xa0\x70\x24\xb0\x3e\x39\x4b\x25\x93\x61\x92\x6c\x59\x1a\x08\x08\
\x82\xb8\xca\x38\xb0\x00\xac\x59\x31\x9b\x0e\x1b\x4f\x07\x46\x6d\
\xd3\xc1\xea\x95\x6d\x52\x04\x96\x03\x80\x52\x8a\xe5\x1d\x26\xbf\
\xdc\x68\xb0\xf7\x70\x9e\xb1\xd9\xda\x69\xc5\x5d\x8a\x3d\x7c\xb1\
\x3a\x5f\xa6\x60\x14\x29\x69\x2a\x56\xaf\x6c\xe3\xc3\x77\x34\x04\
\x6e\x43\x8c\x40\x6f\x1b\xb7\xac\x23\xc1\x77\x16\x27\x3d\xff\x7e\
\x6b\x9a\x3f\x73\xc7\x4e\x75\x1e\x5a\xa3\xb5\x03\x2a\x31\x69\x63\
\x4a\x37\x80\x73\xc9\x32\x12\x78\x2b\xfd\x42\x5f\xdf\x6b\xb4\x76\
\x27\x45\x80\xe2\x9d\x49\x05\x00\x1f\xe3\xf9\xbd\x16\xf4\xfd\x84\
\x26\x1c\x9d\xb7\x1d\x30\xcc\x40\x3b\x3e\xd0\x00\xf8\x19\xae\x5a\
\x06\x2d\xde\xbc\xc2\xef\xb9\xf0\x7c\x95\x52\x98\xa6\xe9\xf9\x77\
\x29\x02\xa7\x11\x01\x8a\xb7\x68\xf5\x7a\xbd\x78\x9b\xd7\x89\xdf\
\x67\x6a\xf4\x72\x21\x98\x4e\x44\x13\x00\xca\x34\x58\xb9\x3b\x78\
\x7b\x39\xa3\x56\xc6\x2f\x6c\xed\x41\x6f\xfd\x81\x03\x60\x3a\x2d\
\x48\x05\xe8\xda\x2d\x5d\xa2\xe0\xab\xce\xfe\x47\x11\x07\xa0\x94\
\x71\x55\xc0\x2e\xda\x2b\x15\xb5\xc2\xe2\xfc\x50\x00\xe0\x05\x41\
\xd0\x8c\x1b\xd6\x2d\xe4\x43\x33\x4b\xe2\x65\xe0\xa0\x44\x84\xb0\
\x6e\x79\x1b\xfa\x69\x32\xd9\x6b\x38\x42\x00\x0c\x0f\x0f\x73\xe4\
\xc8\x91\x58\x18\xbe\xab\xab\x4b\x00\x28\xd6\xa9\x53\xa7\xd8\xb2\
\x65\x8b\x34\xcb\x2a\x4a\xe6\x02\x04\x00\x91\x00\x20\x12\x00\x44\
\x02\x80\x48\x00\x10\x09\x00\x22\x01\xa0\x82\x92\x61\xbb\x80\xd9\
\xab\xda\x00\x0c\x02\xb6\xf8\xb5\x6c\x5d\x8b\x14\x00\x96\x65\xb9\
\xc0\x39\xf1\x6b\x59\x72\xaa\x61\xab\x5a\xd4\x00\xfb\xc5\xb7\x65\
\xe9\xef\x96\x65\xf5\x47\x11\x80\x1d\xe3\x74\x8b\xfc\xb5\x3d\x92\
\xbd\x00\xcb\xb2\x8e\x55\xeb\xcb\x85\x58\x7f\x01\x5e\x8d\x72\x37\
\xf0\xeb\xc0\xeb\xe2\xe7\x92\x3a\x0e\xac\xb3\x2c\xab\x2a\x3d\xa6\
\x44\x2d\xbe\x61\x36\x9b\x75\xd3\xe9\xf4\x2b\x40\x03\xb0\xa2\x56\
\xe7\x11\xc0\x2e\xdf\x5e\xe0\xf3\x96\x65\x5d\xad\xd6\x41\x6b\xbe\
\x9e\x2a\x93\xc9\x2c\x01\x36\x00\xab\x80\xf7\x01\x4d\x31\x72\xfa\
\x30\xd0\x0d\x1c\x00\x7e\x6d\x59\xd6\x9b\xd2\x0e\x44\x22\x91\x48\
\x24\x12\x89\x44\x22\x91\x48\x24\x12\x89\x44\x15\xd1\xff\x00\x56\
\x1c\x01\xcd\xc9\x01\xf3\xd5\x00\x00\x00\x00\x49\x45\x4e\x44\xae\
\x42\x60\x82\
" "
qt_resource_name = "\ qt_resource_name = "\
@@ -8442,33 +8594,38 @@ qt_resource_name = "\
\x0e\xc5\xfa\x07\ \x0e\xc5\xfa\x07\
\x00\x4f\ \x00\x4f\
\x00\x74\x00\x68\x00\x65\x00\x72\x00\x2e\x00\x70\x00\x6e\x00\x67\ \x00\x74\x00\x68\x00\x65\x00\x72\x00\x2e\x00\x70\x00\x6e\x00\x67\
\x00\x08\
\x05\x92\x5d\x07\
\x00\x4b\
\x00\x6f\x00\x62\x00\x6f\x00\x2e\x00\x70\x00\x6e\x00\x67\
" "
qt_resource_struct = "\ qt_resource_struct = "\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x05\x00\x00\x00\x01\ \x00\x00\x00\x00\x00\x02\x00\x00\x00\x05\x00\x00\x00\x01\
\x00\x00\x00\x28\x00\x02\x00\x00\x00\x01\x00\x00\x00\x17\ \x00\x00\x00\x28\x00\x02\x00\x00\x00\x01\x00\x00\x00\x18\
\x00\x00\x00\x36\x00\x02\x00\x00\x00\x01\x00\x00\x00\x11\ \x00\x00\x00\x36\x00\x02\x00\x00\x00\x01\x00\x00\x00\x12\
\x00\x00\x00\x46\x00\x02\x00\x00\x00\x01\x00\x00\x00\x0d\ \x00\x00\x00\x46\x00\x02\x00\x00\x00\x01\x00\x00\x00\x0e\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x0a\ \x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x0a\
\x00\x00\x00\x14\x00\x02\x00\x00\x00\x01\x00\x00\x00\x06\ \x00\x00\x00\x14\x00\x02\x00\x00\x00\x01\x00\x00\x00\x06\
\x00\x00\x00\x58\x00\x02\x00\x00\x00\x03\x00\x00\x00\x07\ \x00\x00\x00\x58\x00\x02\x00\x00\x00\x03\x00\x00\x00\x07\
\x00\x00\x01\x94\x00\x00\x00\x00\x00\x01\x00\x01\xad\xa7\ \x00\x00\x01\x94\x00\x00\x00\x00\x00\x01\x00\x01\xad\xa7\
\x00\x00\x01\x7e\x00\x00\x00\x00\x00\x01\x00\x01\x91\x58\ \x00\x00\x01\x7e\x00\x00\x00\x00\x00\x01\x00\x01\x91\x58\
\x00\x00\x01\xaa\x00\x00\x00\x00\x00\x01\x00\x01\xcc\xe3\ \x00\x00\x01\xaa\x00\x00\x00\x00\x00\x01\x00\x01\xcc\xe3\
\x00\x00\x00\x58\x00\x02\x00\x00\x00\x02\x00\x00\x00\x0b\ \x00\x00\x00\x58\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0b\
\x00\x00\x01\xf0\x00\x00\x00\x00\x00\x01\x00\x02\x07\xc9\
\x00\x00\x01\xbe\x00\x00\x00\x00\x00\x01\x00\x01\xf6\xde\ \x00\x00\x01\xbe\x00\x00\x00\x00\x00\x01\x00\x01\xf6\xde\
\x00\x00\x01\xd8\x00\x00\x00\x00\x00\x01\x00\x02\x01\xe5\ \x00\x00\x01\xd8\x00\x00\x00\x00\x00\x01\x00\x02\x01\xe5\
\x00\x00\x00\x58\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0e\ \x00\x00\x00\x58\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0f\
\x00\x00\x00\x7e\x00\x00\x00\x00\x00\x01\x00\x00\x09\x5d\ \x00\x00\x00\x7e\x00\x00\x00\x00\x00\x01\x00\x00\x09\x5d\
\x00\x00\x00\x68\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ \x00\x00\x00\x68\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
\x00\x00\x00\x9a\x00\x00\x00\x00\x00\x01\x00\x00\x1e\x9a\ \x00\x00\x00\x9a\x00\x00\x00\x00\x00\x01\x00\x00\x1e\x9a\
\x00\x00\x00\x58\x00\x02\x00\x00\x00\x05\x00\x00\x00\x12\ \x00\x00\x00\x58\x00\x02\x00\x00\x00\x05\x00\x00\x00\x13\
\x00\x00\x01\x38\x00\x00\x00\x00\x00\x01\x00\x00\x6a\x71\ \x00\x00\x01\x38\x00\x00\x00\x00\x00\x01\x00\x00\x6a\x71\
\x00\x00\x01\x0c\x00\x00\x00\x00\x00\x01\x00\x00\x46\x38\ \x00\x00\x01\x0c\x00\x00\x00\x00\x00\x01\x00\x00\x46\x38\
\x00\x00\x00\xce\x00\x00\x00\x00\x00\x01\x00\x00\x37\xa3\ \x00\x00\x00\xce\x00\x00\x00\x00\x00\x01\x00\x00\x37\xa3\
\x00\x00\x00\xb2\x00\x00\x00\x00\x00\x01\x00\x00\x2b\x3a\ \x00\x00\x00\xb2\x00\x00\x00\x00\x00\x01\x00\x00\x2b\x3a\
\x00\x00\x00\xe6\x00\x00\x00\x00\x00\x01\x00\x00\x3c\x02\ \x00\x00\x00\xe6\x00\x00\x00\x00\x00\x01\x00\x00\x3c\x02\
\x00\x00\x00\x58\x00\x02\x00\x00\x00\x01\x00\x00\x00\x18\ \x00\x00\x00\x58\x00\x02\x00\x00\x00\x01\x00\x00\x00\x19\
\x00\x00\x01\x5a\x00\x00\x00\x00\x00\x01\x00\x00\x73\xc8\ \x00\x00\x01\x5a\x00\x00\x00\x00\x00\x01\x00\x00\x73\xc8\
" "

View File

@@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'KCC.ui' # Form implementation generated from reading ui file 'KCC.ui'
# #
# Created: Sat Oct 12 11:28:00 2013 # Created: Tue Jan 14 15:50:02 2014
# by: PyQt4 UI code generator 4.10.3 # by: PyQt4 UI code generator 4.10.3
# #
# WARNING! All changes made in this file will be lost! # WARNING! All changes made in this file will be lost!
@@ -26,13 +26,12 @@ except AttributeError:
class Ui_KCC(object): class Ui_KCC(object):
def setupUi(self, KCC): def setupUi(self, KCC):
KCC.setObjectName(_fromUtf8("KCC")) KCC.setObjectName(_fromUtf8("KCC"))
KCC.resize(420, 380) KCC.resize(420, 397)
KCC.setMinimumSize(QtCore.QSize(420, 380)) KCC.setMinimumSize(QtCore.QSize(420, 397))
KCC.setMaximumSize(QtCore.QSize(420, 380)) KCC.setMaximumSize(QtCore.QSize(420, 397))
font = QtGui.QFont() font = QtGui.QFont()
font.setPointSize(9) font.setPointSize(9)
KCC.setFont(font) KCC.setFont(font)
KCC.setFocusPolicy(QtCore.Qt.NoFocus)
icon = QtGui.QIcon() icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(_fromUtf8(":/Icon/icons/comic2ebook.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) icon.addPixmap(QtGui.QPixmap(_fromUtf8(":/Icon/icons/comic2ebook.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
KCC.setWindowIcon(icon) KCC.setWindowIcon(icon)
@@ -247,6 +246,14 @@ class Ui_KCC(object):
self.customHeight.setObjectName(_fromUtf8("customHeight")) self.customHeight.setObjectName(_fromUtf8("customHeight"))
self.gridLayout_2.addWidget(self.customHeight, 0, 3, 1, 1) self.gridLayout_2.addWidget(self.customHeight, 0, 3, 1, 1)
KCC.setCentralWidget(self.Form) KCC.setCentralWidget(self.Form)
self.statusBar = QtGui.QStatusBar(KCC)
font = QtGui.QFont()
font.setFamily(_fromUtf8("MS Shell Dlg 2"))
font.setPointSize(8)
self.statusBar.setFont(font)
self.statusBar.setSizeGripEnabled(False)
self.statusBar.setObjectName(_fromUtf8("statusBar"))
KCC.setStatusBar(self.statusBar)
self.ActionBasic = QtGui.QAction(KCC) self.ActionBasic = QtGui.QAction(KCC)
self.ActionBasic.setCheckable(True) self.ActionBasic.setCheckable(True)
self.ActionBasic.setChecked(False) self.ActionBasic.setChecked(False)
@@ -291,17 +298,15 @@ class Ui_KCC(object):
"p, li { white-space: pre-wrap; }\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" "</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;\">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;\">Indeterminate - High quality mode<br /></span><span style=\" font-style:italic;\">Not zoomed image </span><span style=\" font-weight:600; font-style:italic;\">might </span><span style=\" font-style:italic;\">be a little blurry.<br />Smaller images might be forcefully upscaled in this mode.</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)) "<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.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.setToolTip(_translate("KCC", "<html><head/><body><p>Disable splitting of two-page spreads.<br/>They will be rotated instead.</p></body></html>", None))
self.RotateBox.setText(_translate("KCC", "Horizontal mode", None)) self.RotateBox.setText(_translate("KCC", "Horizontal mode", None))
self.BasicModeButton.setText(_translate("KCC", "Basic", None)) self.BasicModeButton.setText(_translate("KCC", "Basic", None))
self.AdvModeButton.setText(_translate("KCC", "Advanced", 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.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", "<html><head/><body><p>Don\'t convert images to grayscale.</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.ColorBox.setText(_translate("KCC", "Color mode", None))
self.wLabel.setToolTip(_translate("KCC", "Resolution of target device.", None)) self.wLabel.setToolTip(_translate("KCC", "Resolution of target device.", None))
self.wLabel.setText(_translate("KCC", "Custom width: ", None)) self.wLabel.setText(_translate("KCC", "Custom width: ", None))

View File

@@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'KCC-Linux.ui' # Form implementation generated from reading ui file 'KCC-Linux.ui'
# #
# Created: Sat Oct 12 11:28:11 2013 # Created: Tue Jan 14 15:50:14 2014
# by: PyQt4 UI code generator 4.10.3 # by: PyQt4 UI code generator 4.10.3
# #
# WARNING! All changes made in this file will be lost! # WARNING! All changes made in this file will be lost!
@@ -26,13 +26,12 @@ except AttributeError:
class Ui_KCC(object): class Ui_KCC(object):
def setupUi(self, KCC): def setupUi(self, KCC):
KCC.setObjectName(_fromUtf8("KCC")) KCC.setObjectName(_fromUtf8("KCC"))
KCC.resize(420, 380) KCC.resize(420, 397)
KCC.setMinimumSize(QtCore.QSize(420, 380)) KCC.setMinimumSize(QtCore.QSize(420, 397))
KCC.setMaximumSize(QtCore.QSize(420, 380)) KCC.setMaximumSize(QtCore.QSize(420, 397))
font = QtGui.QFont() font = QtGui.QFont()
font.setPointSize(9) font.setPointSize(9)
KCC.setFont(font) KCC.setFont(font)
KCC.setFocusPolicy(QtCore.Qt.NoFocus)
icon = QtGui.QIcon() icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(_fromUtf8(":/Icon/icons/comic2ebook.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) icon.addPixmap(QtGui.QPixmap(_fromUtf8(":/Icon/icons/comic2ebook.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
KCC.setWindowIcon(icon) KCC.setWindowIcon(icon)
@@ -317,6 +316,14 @@ class Ui_KCC(object):
self.customHeight.setObjectName(_fromUtf8("customHeight")) self.customHeight.setObjectName(_fromUtf8("customHeight"))
self.gridLayout_2.addWidget(self.customHeight, 0, 3, 1, 1) self.gridLayout_2.addWidget(self.customHeight, 0, 3, 1, 1)
KCC.setCentralWidget(self.Form) KCC.setCentralWidget(self.Form)
self.statusBar = QtGui.QStatusBar(KCC)
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setPointSize(8)
self.statusBar.setFont(font)
self.statusBar.setSizeGripEnabled(False)
self.statusBar.setObjectName(_fromUtf8("statusBar"))
KCC.setStatusBar(self.statusBar)
self.ActionBasic = QtGui.QAction(KCC) self.ActionBasic = QtGui.QAction(KCC)
self.ActionBasic.setCheckable(True) self.ActionBasic.setCheckable(True)
self.ActionBasic.setChecked(False) self.ActionBasic.setChecked(False)
@@ -360,17 +367,15 @@ class Ui_KCC(object):
"p, li { white-space: pre-wrap; }\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" "</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;\">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;\">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.<br /></span><span style=\" font-family:\'MS Shell Dlg 2\'; font-style:italic;\">Smaller images might be forcefully upscaled in this mode.</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)) "<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.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.setToolTip(_translate("KCC", "<html><head/><body><p>Disable splitting of two-page spreads.<br/>They will be rotated instead.</p></body></html>", None))
self.RotateBox.setText(_translate("KCC", "Horizontal mode", None)) self.RotateBox.setText(_translate("KCC", "Horizontal mode", None))
self.BasicModeButton.setText(_translate("KCC", "Basic", None)) self.BasicModeButton.setText(_translate("KCC", "Basic", None))
self.AdvModeButton.setText(_translate("KCC", "Advanced", 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.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", "<html><head/><body><p>Don\'t convert images to grayscale.</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.ColorBox.setText(_translate("KCC", "Color mode", None))
self.wLabel.setToolTip(_translate("KCC", "Resolution of target device.", None)) self.wLabel.setToolTip(_translate("KCC", "Resolution of target device.", None))
self.wLabel.setText(_translate("KCC", "Custom width: ", None)) self.wLabel.setText(_translate("KCC", "Custom width: ", None))

View File

@@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'KCC-OSX.ui' # Form implementation generated from reading ui file 'KCC-OSX.ui'
# #
# Created: Sat Oct 12 11:28:19 2013 # Created: Tue Jan 14 15:50:25 2014
# by: PyQt4 UI code generator 4.10.3 # by: PyQt4 UI code generator 4.10.3
# #
# WARNING! All changes made in this file will be lost! # WARNING! All changes made in this file will be lost!
@@ -26,13 +26,12 @@ except AttributeError:
class Ui_KCC(object): class Ui_KCC(object):
def setupUi(self, KCC): def setupUi(self, KCC):
KCC.setObjectName(_fromUtf8("KCC")) KCC.setObjectName(_fromUtf8("KCC"))
KCC.resize(420, 380) KCC.resize(420, 397)
KCC.setMinimumSize(QtCore.QSize(420, 380)) KCC.setMinimumSize(QtCore.QSize(420, 397))
KCC.setMaximumSize(QtCore.QSize(420, 380)) KCC.setMaximumSize(QtCore.QSize(420, 397))
font = QtGui.QFont() font = QtGui.QFont()
font.setPointSize(9) font.setPointSize(9)
KCC.setFont(font) KCC.setFont(font)
KCC.setFocusPolicy(QtCore.Qt.NoFocus)
icon = QtGui.QIcon() icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(_fromUtf8(":/Icon/icons/comic2ebook.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off) icon.addPixmap(QtGui.QPixmap(_fromUtf8(":/Icon/icons/comic2ebook.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
KCC.setWindowIcon(icon) KCC.setWindowIcon(icon)
@@ -340,6 +339,14 @@ class Ui_KCC(object):
self.customHeight.setObjectName(_fromUtf8("customHeight")) self.customHeight.setObjectName(_fromUtf8("customHeight"))
self.gridLayout_2.addWidget(self.customHeight, 0, 3, 1, 1) self.gridLayout_2.addWidget(self.customHeight, 0, 3, 1, 1)
KCC.setCentralWidget(self.Form) KCC.setCentralWidget(self.Form)
self.statusBar = QtGui.QStatusBar(KCC)
font = QtGui.QFont()
font.setFamily(_fromUtf8("Aharoni"))
font.setPointSize(8)
self.statusBar.setFont(font)
self.statusBar.setSizeGripEnabled(False)
self.statusBar.setObjectName(_fromUtf8("statusBar"))
KCC.setStatusBar(self.statusBar)
self.ActionBasic = QtGui.QAction(KCC) self.ActionBasic = QtGui.QAction(KCC)
self.ActionBasic.setCheckable(True) self.ActionBasic.setCheckable(True)
self.ActionBasic.setChecked(False) self.ActionBasic.setChecked(False)
@@ -379,16 +386,14 @@ class Ui_KCC(object):
self.ClearButton.setText(_translate("KCC", "Clear list", 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.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.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.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.<br/>Smaller images might be forcefully upscaled in this mode.</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.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.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Disable splitting of two-page spreads.<br/>They will be rotated instead.</span></p></body></html>", None))
self.RotateBox.setText(_translate("KCC", "Horizontal mode", None)) self.RotateBox.setText(_translate("KCC", "Horizontal mode", None))
self.BasicModeButton.setText(_translate("KCC", "Basic", None)) self.BasicModeButton.setText(_translate("KCC", "Basic", None))
self.AdvModeButton.setText(_translate("KCC", "Advanced", 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.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;\">Don\'t convert images to grayscale.</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.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.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.wLabel.setText(_translate("KCC", "Custom width: ", None))

View File

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

View File

@@ -23,7 +23,21 @@ import os
import zipfile import zipfile
import rarfile import rarfile
import locale import locale
from subprocess import Popen, STDOUT, PIPE from sys import platform
from subprocess import STDOUT, PIPE
try:
# noinspection PyUnresolvedReferences
from psutil import Popen
except ImportError:
print "ERROR: Psutil is not installed!"
if platform.startswith('linux'):
import Tkinter
import tkMessageBox
importRoot = Tkinter.Tk()
importRoot.withdraw()
tkMessageBox.showerror("KCC - Error", "Psutil is not installed!")
exit(1)
from shutil import move
class CBxArchive: class CBxArchive:
@@ -91,9 +105,10 @@ class CBxArchive:
elif self.compressor == '7z': elif self.compressor == '7z':
self.extractCB7(targetdir) self.extractCB7(targetdir)
adir = os.listdir(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])): 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])): for f in os.listdir(os.path.join(targetdir, adir[0])):
shutil.move(os.path.join(targetdir, adir[0], f), targetdir) move(os.path.join(targetdir, adir[0], f), targetdir)
os.rmdir(os.path.join(targetdir, adir[0])) os.rmdir(os.path.join(targetdir, adir[0]))
return targetdir return targetdir

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/env python2
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (c) 2012-2013 Ciro Mattia Gonano <ciromattia@gmail.com> # Copyright (c) 2012-2013 Ciro Mattia Gonano <ciromattia@gmail.com>
@@ -18,20 +18,45 @@
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE. # PERFORMANCE OF THIS SOFTWARE.
# #
__version__ = '3.5' __version__ = '3.7.2'
__license__ = 'ISC' __license__ = 'ISC'
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>' __copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
import os import os
import sys import sys
import tempfile
import re import re
import stat import stat
import string import string
from shutil import move, copyfile, copytree, rmtree, make_archive import unicodedata
import zipfile
from tempfile import mkdtemp
from shutil import move, copyfile, copytree, rmtree
from optparse import OptionParser, OptionGroup from optparse import OptionParser, OptionGroup
from multiprocessing import Pool, freeze_support from multiprocessing import Pool, freeze_support
from xml.dom.minidom import parse
from uuid import uuid4
try:
# noinspection PyUnresolvedReferences
from PIL import Image
if tuple(map(int, ('2.3.0'.split(".")))) > tuple(map(int, (Image.PILLOW_VERSION.split(".")))):
print "ERROR: Pillow 2.3.0 or newer is required!"
if sys.platform.startswith('linux'):
import Tkinter
import tkMessageBox
importRoot = Tkinter.Tk()
importRoot.withdraw()
tkMessageBox.showerror("KCC - Error", "Pillow 2.3.0 or newer is required!")
exit(1)
except ImportError:
print "ERROR: Pillow is not installed!"
if sys.platform.startswith('linux'):
import Tkinter
import tkMessageBox
importRoot = Tkinter.Tk()
importRoot.withdraw()
tkMessageBox.showerror("KCC - Error", "Pillow 2.3.0 or newer is required!")
exit(1)
try: try:
from PyQt4 import QtCore from PyQt4 import QtCore
except ImportError: except ImportError:
@@ -49,6 +74,10 @@ def buildHTML(path, imgfile):
rotatedPage = True rotatedPage = True
else: else:
rotatedPage = False rotatedPage = False
if "_kccnpv" in str(filename):
noPV = True
else:
noPV = False
if "_kccnh" in str(filename): if "_kccnh" in str(filename):
noHorizontalPV = True noHorizontalPV = True
else: else:
@@ -86,7 +115,7 @@ def buildHTML(path, imgfile):
"<div><img src=\"", "../" * backref, "Images/", postfix, imgfile, "\" alt=\"", "<div><img src=\"", "../" * backref, "Images/", postfix, imgfile, "\" alt=\"",
imgfile, "\" class=\"singlePage\"/></div>\n" imgfile, "\" class=\"singlePage\"/></div>\n"
]) ])
if options.panelview: if options.panelview and not noPV:
if not noHorizontalPV and not noVerticalPV: if not noHorizontalPV and not noVerticalPV:
if rotatedPage: if rotatedPage:
if options.righttoleft: if options.righttoleft:
@@ -102,9 +131,9 @@ def buildHTML(path, imgfile):
elif noHorizontalPV and not noVerticalPV: elif noHorizontalPV and not noVerticalPV:
if rotatedPage: if rotatedPage:
if options.righttoleft: if options.righttoleft:
order = [2, 1]
else:
order = [1, 2] order = [1, 2]
else:
order = [2, 1]
else: else:
order = [1, 2] order = [1, 2]
boxes = ["BoxT", "BoxB"] boxes = ["BoxT", "BoxB"]
@@ -126,35 +155,48 @@ def buildHTML(path, imgfile):
"}'></a></div>\n"]) "}'></a></div>\n"])
if options.quality == 2: if options.quality == 2:
imgfilepv = string.split(imgfile, ".") imgfilepv = string.split(imgfile, ".")
imgfilepv[0] = imgfilepv[0].split("_kccx")[0].replace("_kccnh", "").replace("_kccnv", "") imgfilepv[0] = imgfilepv[0].split("_kccxl")[0].replace("_kccnh", "").replace("_kccnv", "")
imgfilepv[0] += "_kcchq" imgfilepv[0] += "_kcchq"
imgfilepv = string.join(imgfilepv, ".") imgfilepv = string.join(imgfilepv, ".")
else: else:
imgfilepv = imgfile imgfilepv = imgfile
if "_kccx" in filename[0]: if "_kccxl" in filename[0]:
xy = string.split(filename[0], "_kccx")[1] borders = filename[0].split('_kccxl')[1]
x = string.split(xy, "_kccy")[0].lstrip("0") borders = re.findall('[0-9]{1,6}', borders)
y = string.split(xy, "_kccy")[1].lstrip("0") xl = borders[0].lstrip("0")
if x != "": yu = borders[1].lstrip("0")
x = "-" + str(float(x)/100) + "%" xr = borders[2].lstrip("0")
yd = borders[3].lstrip("0")
if xl != "":
xl = "-" + str(float(xl)/100) + "%"
else: else:
x = "0%" xl = "0%"
if y != "": if xr != "":
y = "-" + str(float(y)/100) + "%" xr = "-" + str(float(xr)/100) + "%"
else: else:
y = "0%" xr = "0%"
if yu != "":
yu = "-" + str(float(yu)/100) + "%"
else:
yu = "0%"
if yd != "":
yd = "-" + str(float(yd)/100) + "%"
else:
yd = "0%"
else: else:
x = "0%" xl = "0%"
y = "0%" yu = "0%"
boxStyles = {"BoxTL": "left:" + x + ";top:" + y + ";", xr = "0%"
"BoxTR": "right:" + x + ";top:" + y + ";", yd = "0%"
"BoxBL": "left:" + x + ";bottom:" + y + ";", boxStyles = {"BoxTL": "left:" + xl + ";top:" + yu + ";",
"BoxBR": "right:" + x + ";bottom:" + y + ";", "BoxTR": "right:" + xr + ";top:" + yu + ";",
"BoxT": "left:-25%;top:" + y + ";", "BoxBL": "left:" + xl + ";bottom:" + yd + ";",
"BoxB": "left:-25%;bottom:" + y + ";", "BoxBR": "right:" + xr + ";bottom:" + yd + ";",
"BoxL": "left:" + x + ";top:-25%;", "BoxT": "left:-25%;top:" + yu + ";",
"BoxR": "right:" + x + ";top:-25%;", "BoxB": "left:-25%;bottom:" + yd + ";",
"BoxC": "right:-25%;top:-25%;" "BoxL": "left:" + xl + ";top:-25%;",
"BoxR": "right:" + xr + ";top:-25%;",
"BoxC": "left:-25%;top:-25%;"
} }
for box in boxes: for box in boxes:
f.writelines(["<div id=\"" + box + "-Panel-Parent\" class=\"target-mag-parent\"><div id=\"", f.writelines(["<div id=\"" + box + "-Panel-Parent\" class=\"target-mag-parent\"><div id=\"",
@@ -168,7 +210,6 @@ def buildHTML(path, imgfile):
def buildNCX(dstdir, title, chapters): def buildNCX(dstdir, title, chapters):
from uuid import uuid4
options.uuid = str(uuid4()) options.uuid = str(uuid4())
options.uuid = options.uuid.encode('utf-8') options.uuid = options.uuid.encode('utf-8')
ncxfile = os.path.join(dstdir, 'OEBPS', 'toc.ncx') ncxfile = os.path.join(dstdir, 'OEBPS', 'toc.ncx')
@@ -216,9 +257,10 @@ def buildOPF(dstdir, title, filelist, cover=None):
"xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n", "xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n",
"<dc:title>", title.encode('utf-8'), "</dc:title>\n", "<dc:title>", title.encode('utf-8'), "</dc:title>\n",
"<dc:language>en-US</dc:language>\n", "<dc:language>en-US</dc:language>\n",
"<dc:identifier id=\"BookID\" opf:scheme=\"UUID\">", options.uuid, "</dc:identifier>\n", "<dc:identifier id=\"BookID\" opf:scheme=\"UUID\">", options.uuid, "</dc:identifier>\n"])
"<dc:Creator>KCC</dc:Creator>\n", for author in options.authors:
"<meta name=\"generator\" content=\"KindleComicConverter-" + __version__ + "\"/>\n", f.writelines(["<dc:creator>", author.encode('utf-8'), "</dc:creator>\n"])
f.writelines(["<meta name=\"generator\" content=\"KindleComicConverter-" + __version__ + "\"/>\n",
"<meta name=\"RegionMagnification\" content=\"true\"/>\n", "<meta name=\"RegionMagnification\" content=\"true\"/>\n",
"<meta name=\"region-mag\" content=\"true\"/>\n", "<meta name=\"region-mag\" content=\"true\"/>\n",
"<meta name=\"cover\" content=\"cover\"/>\n", "<meta name=\"cover\" content=\"cover\"/>\n",
@@ -264,9 +306,6 @@ def buildOPF(dstdir, title, filelist, cover=None):
f.write("</spine>\n<guide>\n</guide>\n</package>\n") f.write("</spine>\n<guide>\n</guide>\n</package>\n")
f.close() f.close()
os.mkdir(os.path.join(dstdir, 'META-INF')) os.mkdir(os.path.join(dstdir, 'META-INF'))
f = open(os.path.join(dstdir, 'mimetype'), 'w')
f.write('application/epub+zip')
f.close()
f = open(os.path.join(dstdir, 'META-INF', 'container.xml'), 'w') f = open(os.path.join(dstdir, 'META-INF', 'container.xml'), 'w')
f.writelines(["<?xml version=\"1.0\"?>\n", f.writelines(["<?xml version=\"1.0\"?>\n",
"<container version=\"1.0\" xmlns=\"urn:oasis:names:tc:opendocument:xmlns:container\">\n", "<container version=\"1.0\" xmlns=\"urn:oasis:names:tc:opendocument:xmlns:container\">\n",
@@ -292,17 +331,24 @@ def getImageFileName(imgfile):
return filename return filename
def applyImgOptimization(img, opt, overrideQuality=5): def applyImgOptimization(img, opt, hqImage=None):
img.getImageFill(opt.webtoon) if not img.fill:
img.getImageFill(opt.webtoon)
if not opt.webtoon: if not opt.webtoon:
img.cropWhiteSpace(10.0) img.cropWhiteSpace(10.0)
if opt.cutpagenumbers and not opt.webtoon: if opt.cutpagenumbers and not opt.webtoon:
img.cutPageNumber() img.cutPageNumber()
img.optimizeImage(opt.gamma) img.optimizeImage(opt.gamma)
if overrideQuality != 5: if hqImage:
img.resizeImage(opt.upscale, opt.stretch, opt.bordersColor, overrideQuality) img.resizeImage(opt.upscale, opt.stretch, opt.bordersColor, 0)
img.calculateBorder(hqImage, True)
else: else:
img.resizeImage(opt.upscale, opt.stretch, opt.bordersColor, opt.quality) img.resizeImage(opt.upscale, opt.stretch, opt.bordersColor, opt.quality)
if opt.panelview:
if opt.quality == 0:
img.calculateBorder(img)
elif opt.quality == 1:
img.calculateBorder(img, True)
if opt.forcepng and not opt.forcecolor: if opt.forcepng and not opt.forcecolor:
img.quantizeImage() img.quantizeImage()
@@ -374,21 +420,21 @@ def fileImgProcess(work):
applyImgOptimization(img1, opt) applyImgOptimization(img1, opt)
img1.saveToDir(dirpath, opt.forcepng, opt.forcecolor, wipe) img1.saveToDir(dirpath, opt.forcepng, opt.forcecolor, wipe)
if opt.quality == 2: if opt.quality == 2:
img3 = image.ComicPage(split[0], opt.profileData) img0b = image.ComicPage(split[0], opt.profileData, img0.fill)
applyImgOptimization(img3, opt, 0) applyImgOptimization(img0b, opt, img0)
img3.saveToDir(dirpath, opt.forcepng, opt.forcecolor, True) img0b.saveToDir(dirpath, opt.forcepng, opt.forcecolor, True)
img4 = image.ComicPage(split[1], opt.profileData) img1b = image.ComicPage(split[1], opt.profileData, img1.fill)
applyImgOptimization(img4, opt, 0) applyImgOptimization(img1b, opt, img1)
img4.saveToDir(dirpath, opt.forcepng, opt.forcecolor, True) img1b.saveToDir(dirpath, opt.forcepng, opt.forcecolor, True)
else: else:
applyImgOptimization(img, opt) applyImgOptimization(img, opt)
img.saveToDir(dirpath, opt.forcepng, opt.forcecolor, wipe) img.saveToDir(dirpath, opt.forcepng, opt.forcecolor, wipe)
if opt.quality == 2: if opt.quality == 2:
img2 = image.ComicPage(os.path.join(dirpath, afile), opt.profileData) img2 = image.ComicPage(os.path.join(dirpath, afile), opt.profileData, img.fill)
if img.rotated: if img.rotated:
img2.image = img2.image.rotate(90) img2.image = img2.image.rotate(90)
img2.rotated = True img2.rotated = True
applyImgOptimization(img2, opt, 0) applyImgOptimization(img2, opt, img)
img2.saveToDir(dirpath, opt.forcepng, opt.forcecolor, True) img2.saveToDir(dirpath, opt.forcepng, opt.forcecolor, True)
except StandardError: except StandardError:
return str(sys.exc_info()[1]) return str(sys.exc_info()[1])
@@ -535,7 +581,7 @@ def getWorkFolder(afile):
if len(afile) > 240: if len(afile) > 240:
raise UserWarning("Path is too long.") raise UserWarning("Path is too long.")
if os.path.isdir(afile): if os.path.isdir(afile):
workdir = tempfile.mkdtemp('', 'KCC-TMP-') workdir = mkdtemp('', 'KCC-TMP-')
try: try:
os.rmdir(workdir) # needed for copytree() fails if dst already exists os.rmdir(workdir) # needed for copytree() fails if dst already exists
fullPath = os.path.join(workdir, 'OEBPS', 'Images') fullPath = os.path.join(workdir, 'OEBPS', 'Images')
@@ -554,7 +600,7 @@ def getWorkFolder(afile):
rmtree(path, True) rmtree(path, True)
raise UserWarning("Failed to extract images.") raise UserWarning("Failed to extract images.")
else: else:
workdir = tempfile.mkdtemp('', 'KCC-TMP-') workdir = mkdtemp('', 'KCC-TMP-')
cbx = cbxarchive.CBxArchive(afile) cbx = cbxarchive.CBxArchive(afile)
if cbx.isCbxFile(): if cbx.isCbxFile():
try: try:
@@ -573,9 +619,59 @@ def getWorkFolder(afile):
return path return path
def checkComicInfo(path, originalPath):
xmlPath = os.path.join(path, 'ComicInfo.xml')
options.authors = ['KCC']
titleSuffix = ''
if options.title == 'defaulttitle':
defaultTitle = True
if os.path.isdir(originalPath):
options.title = os.path.basename(originalPath)
else:
options.title = os.path.splitext(os.path.basename(originalPath))[0]
else:
defaultTitle = False
if os.path.exists(xmlPath):
try:
xml = parse(xmlPath)
except StandardError:
os.remove(xmlPath)
return
options.authors = []
if defaultTitle:
if len(xml.getElementsByTagName('Series')) != 0:
options.title = xml.getElementsByTagName('Series')[0].firstChild.nodeValue
if len(xml.getElementsByTagName('Volume')) != 0:
titleSuffix += ' V' + xml.getElementsByTagName('Volume')[0].firstChild.nodeValue
if len(xml.getElementsByTagName('Number')) != 0:
titleSuffix += ' #' + xml.getElementsByTagName('Number')[0].firstChild.nodeValue
options.title += titleSuffix
if len(xml.getElementsByTagName('Writer')) != 0:
authorsTemp = string.split(xml.getElementsByTagName('Writer')[0].firstChild.nodeValue, ', ')
for author in authorsTemp:
options.authors.append(author)
if len(xml.getElementsByTagName('Penciller')) != 0:
authorsTemp = string.split(xml.getElementsByTagName('Penciller')[0].firstChild.nodeValue, ', ')
for author in authorsTemp:
options.authors.append(author)
if len(xml.getElementsByTagName('Inker')) != 0:
authorsTemp = string.split(xml.getElementsByTagName('Inker')[0].firstChild.nodeValue, ', ')
for author in authorsTemp:
options.authors.append(author)
if len(xml.getElementsByTagName('Colorist')) != 0:
authorsTemp = string.split(xml.getElementsByTagName('Colorist')[0].firstChild.nodeValue, ', ')
for author in authorsTemp:
options.authors.append(author)
if len(options.authors) > 0:
options.authors = list(set(options.authors))
options.authors.sort()
else:
options.authors = ['KCC']
os.remove(xmlPath)
def slugify(value): def slugify(value):
# Normalizes string, converts to lowercase, removes non-alpha characters and converts spaces to hyphens. # Normalizes string, converts to lowercase, removes non-alpha characters and converts spaces to hyphens.
import unicodedata
if isinstance(value, str): if isinstance(value, str):
#noinspection PyArgumentList #noinspection PyArgumentList
value = unicodedata.normalize('NFKD', unicode(value, 'latin1')).encode('ascii', 'ignore') value = unicodedata.normalize('NFKD', unicode(value, 'latin1')).encode('ascii', 'ignore')
@@ -614,9 +710,6 @@ def sanitizeTreeBeforeConversion(filetree):
for root, dirs, files in os.walk(filetree, False): for root, dirs, files in os.walk(filetree, False):
for name in files: for name in files:
os.chmod(os.path.join(root, name), stat.S_IWRITE | stat.S_IREAD) os.chmod(os.path.join(root, name), stat.S_IWRITE | stat.S_IREAD)
# Detect corrupted files - Phase 1
if os.path.getsize(os.path.join(root, name)) == 0:
os.remove(os.path.join(root, name))
for name in dirs: for name in dirs:
os.chmod(os.path.join(root, name), stat.S_IWRITE | stat.S_IREAD | stat.S_IEXEC) os.chmod(os.path.join(root, name), stat.S_IWRITE | stat.S_IREAD | stat.S_IEXEC)
@@ -631,7 +724,7 @@ def getDirectorySize(start_path='.'):
def createNewTome(): def createNewTome():
tomePathRoot = tempfile.mkdtemp('', 'KCC-TMP-') tomePathRoot = mkdtemp('', 'KCC-TMP-')
tomePath = os.path.join(tomePathRoot, 'OEBPS', 'Images') tomePath = os.path.join(tomePathRoot, 'OEBPS', 'Images')
os.makedirs(tomePath) os.makedirs(tomePath)
return tomePath, tomePathRoot return tomePath, tomePathRoot
@@ -772,6 +865,40 @@ def preSplitDirectory(path):
return [path] return [path]
def detectCorruption(tmpPath, orgPath):
for root, dirs, files in os.walk(tmpPath, False):
for name in files:
if getImageFileName(name) is not None:
path = os.path.join(root, name)
pathOrg = os.path.join(orgPath, name)
if os.path.getsize(path) == 0:
rmtree(os.path.join(tmpPath, '..', '..'), True)
raise RuntimeError('Image file %s is corrupted.' % pathOrg)
try:
img = Image.open(path)
img.verify()
img = Image.open(path)
img.load()
except:
rmtree(os.path.join(tmpPath, '..', '..'), True)
raise RuntimeError('Image file %s is corrupted.' % pathOrg)
def makeZIP(zipFilename, baseDir, isEPUB=False):
zipFilename = os.path.abspath(zipFilename) + '.zip'
zipOutput = zipfile.ZipFile(zipFilename, 'w', zipfile.ZIP_DEFLATED)
if isEPUB:
zipOutput.writestr('mimetype', 'application/epub+zip', zipfile.ZIP_STORED)
for dirpath, dirnames, filenames in os.walk(baseDir):
for name in filenames:
path = os.path.normpath(os.path.join(dirpath, name))
aPath = os.path.normpath(os.path.join(dirpath.replace(baseDir, ''), name))
if os.path.isfile(path):
zipOutput.write(path, aPath)
zipOutput.close()
return zipFilename
def Copyright(): def Copyright():
print ('comic2ebook v%(__version__)s. ' print ('comic2ebook v%(__version__)s. '
'Written 2013 by Ciro Mattia Gonano and Pawel Jastrzebski.' % globals()) 'Written 2013 by Ciro Mattia Gonano and Pawel Jastrzebski.' % globals())
@@ -792,7 +919,7 @@ def main(argv=None, qtGUI=None):
otherOptions = OptionGroup(parser, "OTHER") otherOptions = OptionGroup(parser, "OTHER")
mainOptions.add_option("-p", "--profile", action="store", dest="profile", default="KHD", mainOptions.add_option("-p", "--profile", action="store", dest="profile", default="KHD",
help="Device profile (Choose one among K1, K2, K345, KDX, KHD, KF, KFHD, KFHD8, KFHDX," help="Device profile (Choose one among K1, K2, K345, KDX, KHD, KF, KFHD, KFHD8, KFHDX,"
" KFHDX8, KFA) [Default=KHD]") " KFHDX8, KFA, KoMT, KoG, KoA, KoAHD) [Default=KHD]")
mainOptions.add_option("-q", "--quality", type="int", dest="quality", default="0", mainOptions.add_option("-q", "--quality", type="int", dest="quality", default="0",
help="Quality of Panel View. 0 - Normal 1 - High 2 - Ultra [Default=0]") help="Quality of Panel View. 0 - Normal 1 - High 2 - Ultra [Default=0]")
mainOptions.add_option("-m", "--manga-style", action="store_true", dest="righttoleft", default=False, mainOptions.add_option("-m", "--manga-style", action="store_true", dest="righttoleft", default=False,
@@ -853,13 +980,13 @@ def main(argv=None, qtGUI=None):
parser.print_help() parser.print_help()
return return
path = getWorkFolder(args[0]) path = getWorkFolder(args[0])
detectCorruption(path + "/OEBPS/Images/", args[0])
checkComicInfo(path + "/OEBPS/Images/", args[0])
if options.webtoon: if options.webtoon:
if GUI:
GUI.emit(QtCore.SIGNAL("progressBarTick"), 'status', 'Splitting images')
if options.customheight > 0: if options.customheight > 0:
comic2panel.main(['-y ' + str(options.customheight), '-i', path], qtGUI) comic2panel.main(['-y ' + str(options.customheight), '-i', '-m', path], qtGUI)
else: else:
comic2panel.main(['-y ' + str(image.ProfileData.Profiles[options.profile][1][1]), '-i', path], qtGUI) comic2panel.main(['-y ' + str(image.ProfileData.Profiles[options.profile][1][1]), '-i', '-m', path], qtGUI)
if options.imgproc: if options.imgproc:
print "\nProcessing images..." print "\nProcessing images..."
if GUI: if GUI:
@@ -879,19 +1006,13 @@ def main(argv=None, qtGUI=None):
GUI.emit(QtCore.SIGNAL("progressBarTick"), 'status', 'Compressing CBZ files') GUI.emit(QtCore.SIGNAL("progressBarTick"), 'status', 'Compressing CBZ files')
else: else:
GUI.emit(QtCore.SIGNAL("progressBarTick"), 'status', 'Compressing EPUB files') GUI.emit(QtCore.SIGNAL("progressBarTick"), 'status', 'Compressing EPUB files')
GUI.emit(QtCore.SIGNAL("progressBarTick"), len(tomes)) GUI.emit(QtCore.SIGNAL("progressBarTick"), len(tomes) + 1)
GUI.emit(QtCore.SIGNAL("progressBarTick"))
options.baseTitle = options.title
for tome in tomes: for tome in tomes:
if GUI:
GUI.emit(QtCore.SIGNAL("progressBarTick"))
if os.path.isdir(args[0]):
barePath = os.path.basename(args[0])
else:
barePath = os.path.splitext(os.path.basename(args[0]))[0]
if len(tomes) > 1: if len(tomes) > 1:
tomeNumber += 1 tomeNumber += 1
options.title = barePath + ' ' + str(tomeNumber) options.title = options.baseTitle + ' [' + str(tomeNumber) + '/' + str(len(tomes)) + ']'
elif options.title == 'defaulttitle':
options.title = barePath
if options.cbzoutput: if options.cbzoutput:
# if CBZ output wanted, compress all images and return filepath # if CBZ output wanted, compress all images and return filepath
print "\nCreating CBZ file..." print "\nCreating CBZ file..."
@@ -899,7 +1020,7 @@ def main(argv=None, qtGUI=None):
filepath.append(getOutputFilename(args[0], options.output, '.cbz', ' ' + str(tomeNumber))) filepath.append(getOutputFilename(args[0], options.output, '.cbz', ' ' + str(tomeNumber)))
else: else:
filepath.append(getOutputFilename(args[0], options.output, '.cbz', '')) filepath.append(getOutputFilename(args[0], options.output, '.cbz', ''))
make_archive(tome + '_comic', 'zip', tome + '/OEBPS/Images') makeZIP(tome + '_comic', tome + '/OEBPS/Images')
else: else:
print "\nCreating EPUB structure..." print "\nCreating EPUB structure..."
genEpubStruct(tome) genEpubStruct(tome)
@@ -908,9 +1029,11 @@ def main(argv=None, qtGUI=None):
filepath.append(getOutputFilename(args[0], options.output, '.epub', ' ' + str(tomeNumber))) filepath.append(getOutputFilename(args[0], options.output, '.epub', ' ' + str(tomeNumber)))
else: else:
filepath.append(getOutputFilename(args[0], options.output, '.epub', '')) filepath.append(getOutputFilename(args[0], options.output, '.epub', ''))
make_archive(tome + '_comic', 'zip', tome) makeZIP(tome + '_comic', tome, True)
move(tome + '_comic.zip', filepath[-1]) move(tome + '_comic.zip', filepath[-1])
rmtree(tome, True) rmtree(tome, True)
if GUI:
GUI.emit(QtCore.SIGNAL("progressBarTick"))
return filepath return filepath
@@ -964,10 +1087,18 @@ def checkOptions():
if options.profile == 'OTHER': if options.profile == 'OTHER':
options.panelview = False options.panelview = False
options.quality = 0 options.quality = 0
if 'Ko' in options.profile:
options.panelview = False
# Kobo models can't use ultra quality mode
if options.quality == 2:
options.quality = 1
# Kindle for Android profile require target resolution. # Kindle for Android profile require target resolution.
if options.profile == 'KFA' and (options.customwidth == 0 or options.customheight == 0): if options.profile == 'KFA' and (options.customwidth == 0 or options.customheight == 0):
print "ERROR: Kindle for Android profile require --customwidth and --customheight options!" print "ERROR: Kindle for Android profile require --customwidth and --customheight options!"
sys.exit(1) sys.exit(1)
# CBZ files on Kindle DX/DXG support higher resolution
if options.profile == 'KDX' and options.cbzoutput:
options.customheight = 1200
# Override profile data # Override profile data
if options.customwidth != 0 or options.customheight != 0: if options.customwidth != 0 or options.customheight != 0:
X = image.ProfileData.Profiles[options.profile][1][0] X = image.ProfileData.Profiles[options.profile][1][0]

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/env python2
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (c) 2012-2013 Ciro Mattia Gonano <ciromattia@gmail.com> # Copyright (c) 2012-2013 Ciro Mattia Gonano <ciromattia@gmail.com>
@@ -18,7 +18,7 @@
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR # TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE. # PERFORMANCE OF THIS SOFTWARE.
# #
__version__ = '3.5' __version__ = '3.7.2'
__license__ = 'ISC' __license__ = 'ISC'
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>' __copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
@@ -29,13 +29,25 @@ from shutil import rmtree, copytree, move
from optparse import OptionParser, OptionGroup from optparse import OptionParser, OptionGroup
from multiprocessing import Pool, freeze_support from multiprocessing import Pool, freeze_support
try: try:
#noinspection PyUnresolvedReferences # noinspection PyUnresolvedReferences
from PIL import Image, ImageStat from PIL import Image, ImageStat
if tuple(map(int, ('2.2.1'.split(".")))) > tuple(map(int, (Image.PILLOW_VERSION.split(".")))): if tuple(map(int, ('2.3.0'.split(".")))) > tuple(map(int, (Image.PILLOW_VERSION.split(".")))):
print "ERROR: Pillow 2.2.1 or newer is required!" print "ERROR: Pillow 2.3.0 or newer is required!"
if sys.platform.startswith('linux'):
import Tkinter
import tkMessageBox
importRoot = Tkinter.Tk()
importRoot.withdraw()
tkMessageBox.showerror("KCC - Error", "Pillow 2.3.0 or newer is required!")
exit(1) exit(1)
except ImportError: except ImportError:
print "ERROR: Pillow is not installed!" print "ERROR: Pillow is not installed!"
if sys.platform.startswith('linux'):
import Tkinter
import tkMessageBox
importRoot = Tkinter.Tk()
importRoot.withdraw()
tkMessageBox.showerror("KCC - Error", "Pillow 2.3.0 or newer is required!")
exit(1) exit(1)
try: try:
from PyQt4 import QtCore from PyQt4 import QtCore
@@ -57,6 +69,59 @@ def getImageFileName(imgfile):
return filename 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 mergeDirectory_tick(output):
if output:
mergeWorkerOutput.append(output)
mergeWorkerPool.terminate()
if GUI:
GUI.emit(QtCore.SIGNAL("progressBarTick"))
if not GUI.conversionAlive:
mergeWorkerPool.terminate()
def mergeDirectory(work):
try:
directory = work[0]
images = []
imagesClear = []
sizes = []
for root, dirs, files in walkLevel(directory, 0):
for name in files:
if getImageFileName(name) is not None:
images.append([Image.open(os.path.join(root, name)), os.path.join(root, name)])
if len(images) > 0:
for i in images:
sizes.append(i[0].size[0])
mw = max(set(sizes), key=sizes.count)
for i in images:
if i[0].size[0] == mw:
i[0] = i[0].convert('RGB')
imagesClear.append(i)
h = sum(i[0].size[1] for i in imagesClear)
result = Image.new('RGB', (mw, h))
y = 0
for i in imagesClear:
result.paste(i[0], (0, y))
y += i[0].size[1]
for i in imagesClear:
os.remove(i[1])
savePath = os.path.split(imagesClear[0][1])
result.save(os.path.join(savePath[0], os.path.splitext(savePath[1])[0] + '.png'), 'PNG')
except StandardError:
return str(sys.exc_info()[1])
def sanitizePanelSize(panel, opt): def sanitizePanelSize(panel, opt):
newPanels = [] newPanels = []
if panel[2] > 8 * opt.height: if panel[2] > 8 * opt.height:
@@ -105,21 +170,6 @@ def splitImage(work):
print ".", print ".",
fileExpanded = os.path.splitext(name) fileExpanded = os.path.splitext(name)
filePath = os.path.join(path, 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.open(filePath)
image = image.convert('RGB') image = image.convert('RGB')
widthImg, heightImg = image.size widthImg, heightImg = image.size
@@ -204,7 +254,7 @@ def Copyright():
def main(argv=None, qtGUI=None): def main(argv=None, qtGUI=None):
global options, GUI, splitWorkerPool, splitWorkerOutput global options, GUI, splitWorkerPool, splitWorkerOutput, mergeWorkerPool, mergeWorkerOutput
parser = OptionParser(usage="Usage: %prog [options] comic_folder", add_help_option=False) parser = OptionParser(usage="Usage: %prog [options] comic_folder", add_help_option=False)
mainOptions = OptionGroup(parser, "MANDATORY") mainOptions = OptionGroup(parser, "MANDATORY")
otherOptions = OptionGroup(parser, "OTHER") otherOptions = OptionGroup(parser, "OTHER")
@@ -212,6 +262,8 @@ def main(argv=None, qtGUI=None):
help="Height of the target device screen") help="Height of the target device screen")
mainOptions.add_option("-i", "--in-place", action="store_true", dest="inPlace", default=False, mainOptions.add_option("-i", "--in-place", action="store_true", dest="inPlace", default=False,
help="Overwrite source directory") 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, otherOptions.add_option("-d", "--debug", action="store_true", dest="debug", default=False,
help="Create debug file for every splitted image") help="Create debug file for every splitted image")
otherOptions.add_option("-h", "--help", action="help", otherOptions.add_option("-h", "--help", action="help",
@@ -237,6 +289,29 @@ def main(argv=None, qtGUI=None):
pagenumber = 0 pagenumber = 0
splitWorkerOutput = [] splitWorkerOutput = []
splitWorkerPool = Pool() splitWorkerPool = Pool()
if options.merge:
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.emit(QtCore.SIGNAL("progressBarTick"), 'status', 'Combining images')
GUI.emit(QtCore.SIGNAL("progressBarTick"), 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])
for root, dirs, files in os.walk(options.targetDir, False): for root, dirs, files in os.walk(options.targetDir, False):
for name in files: for name in files:
if getImageFileName(name) is not None: if getImageFileName(name) is not None:
@@ -245,7 +320,9 @@ def main(argv=None, qtGUI=None):
else: else:
os.remove(os.path.join(root, name)) os.remove(os.path.join(root, name))
if GUI: if GUI:
GUI.emit(QtCore.SIGNAL("progressBarTick"), 'status', 'Splitting images')
GUI.emit(QtCore.SIGNAL("progressBarTick"), pagenumber) GUI.emit(QtCore.SIGNAL("progressBarTick"), pagenumber)
GUI.emit(QtCore.SIGNAL("progressBarTick"))
if len(work) > 0: if len(work) > 0:
for i in work: for i in work:
splitWorkerPool.apply_async(func=splitImage, args=(i, ), callback=splitImage_tick) splitWorkerPool.apply_async(func=splitImage, args=(i, ), callback=splitImage_tick)

View File

@@ -21,14 +21,27 @@ __copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jas
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
import os import os
from sys import platform
try: try:
# noinspection PyUnresolvedReferences # noinspection PyUnresolvedReferences
from PIL import Image, ImageOps, ImageStat, ImageChops from PIL import Image, ImageOps, ImageStat, ImageChops
if tuple(map(int, ('2.2.1'.split(".")))) > tuple(map(int, (Image.PILLOW_VERSION.split(".")))): if tuple(map(int, ('2.3.0'.split(".")))) > tuple(map(int, (Image.PILLOW_VERSION.split(".")))):
print "ERROR: Pillow 2.2.1 or newer is required!" print "ERROR: Pillow 2.3.0 or newer is required!"
if platform.startswith('linux'):
import Tkinter
import tkMessageBox
importRoot = Tkinter.Tk()
importRoot.withdraw()
tkMessageBox.showerror("KCC - Error", "Pillow 2.3.0 or newer is required!")
exit(1) exit(1)
except ImportError: except ImportError:
print "ERROR: Pillow is not installed!" print "ERROR: Pillow is not installed!"
if platform.startswith('linux'):
import Tkinter
import tkMessageBox
importRoot = Tkinter.Tk()
importRoot.withdraw()
tkMessageBox.showerror("KCC - Error", "Pillow 2.3.0 or newer is required!")
exit(1) exit(1)
@@ -94,76 +107,35 @@ class ProfileData:
'KFHD8': ("K. Fire HD 8.9\"", (1200, 1920), PalleteNull, 1.0, (1800, 2880)), '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)), '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)), '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)), 'KFA': ("Kindle for Android", (0, 0), PalleteNull, 1.0, (0, 0)),
'OTHER': ("Other", (0, 0), Palette16, 1.8, (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: class ComicPage:
def __init__(self, source, device): def __init__(self, source, device, fill=None):
try: try:
self.profile_label, self.size, self.palette, self.gamma, self.panelviewsize = device self.profile_label, self.size, self.palette, self.gamma, self.panelviewsize = device
except KeyError: except KeyError:
raise RuntimeError('Unexpected output device %s' % device) raise RuntimeError('Unexpected output device %s' % device)
# Detect corrupted files - Phase 2 self.origFileName = source
try: self.filename = os.path.basename(self.origFileName)
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.image = Image.open(source) self.image = Image.open(source)
self.image = self.image.convert('RGB') self.image = self.image.convert('RGB')
self.rotated = None self.rotated = None
self.border = None self.border = None
self.noHPV = None self.noHPV = None
self.noVPV = None self.noVPV = None
self.fill = None self.noPV = None
self.purge = False
if fill:
self.fill = fill
else:
self.fill = None
def saveToDir(self, targetdir, forcepng, color, wipe): def saveToDir(self, targetdir, forcepng, color, wipe):
try: try:
@@ -176,24 +148,31 @@ class ComicPage:
os.remove(os.path.join(targetdir, self.filename)) os.remove(os.path.join(targetdir, self.filename))
else: else:
suffix += "_kcchq" suffix += "_kcchq"
if self.noHPV: if self.noPV:
suffix += "_kccnh" suffix += "_kccnpv"
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: else:
self.image.save(os.path.join(targetdir, os.path.splitext(self.filename)[0] + suffix + ".jpg"), "JPEG", if self.noHPV:
optimize=1) suffix += "_kccnh"
if self.noVPV:
suffix += "_kccnv"
if self.border:
suffix += "_kccxl" + str(self.border[0]) + "_kccyu" + str(self.border[1]) + "_kccxr" +\
str(self.border[2]) + "_kccyd" + str(self.border[3])
if not self.purge:
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)
except IOError as e: except IOError as e:
raise RuntimeError('Cannot write image in directory %s: %s' % (targetdir, e)) raise RuntimeError('Cannot write image in directory %s: %s' % (targetdir, e))
def optimizeImage(self, gamma): def optimizeImage(self, gamma):
if gamma < 0.1: if gamma < 0.1:
gamma = self.gamma gamma = self.gamma
if self.gamma != 1.0 and self.isImageColor(self.image):
gamma = 1.0
if gamma == 1.0: if gamma == 1.0:
self.image = ImageOps.autocontrast(self.image) self.image = ImageOps.autocontrast(self.image)
else: else:
@@ -210,84 +189,88 @@ class ComicPage:
# Quantize is deprecated but new function call it internally anyway... # Quantize is deprecated but new function call it internally anyway...
self.image = self.image.quantize(palette=palImg) self.image = self.image.quantize(palette=palImg)
def calculateBorderPercent(self, x, img, isWidth):
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:
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): def resizeImage(self, upscale=False, stretch=False, bordersColor=None, qualityMode=0):
# High-quality downscaling filter
method = Image.ANTIALIAS
if bordersColor: if bordersColor:
fill = bordersColor fill = bordersColor
else: else:
fill = self.fill fill = self.fill
# Set target size
if qualityMode == 0: if qualityMode == 0:
size = (self.size[0], self.size[1]) size = (self.size[0], self.size[1])
generateBorder = True
elif qualityMode == 1:
size = (self.panelviewsize[0], self.panelviewsize[1])
generateBorder = True
else: else:
size = (self.panelviewsize[0], self.panelviewsize[1]) size = (self.panelviewsize[0], self.panelviewsize[1])
generateBorder = False # If image is small and HQ mode is on we have to force upscaling. Otherwise non-zoomed image will be distorted
# If image is smaller than screen and upscale is off - Just expand it if self.image.size[0] <= size[0] and self.image.size[1] <= size[1] and qualityMode == 1 and not stretch:
if self.image.size[0] <= self.size[0] and self.image.size[1] <= self.size[1]: upscale = True
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 stretching is on - Resize without other considerations
if stretch: 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) self.image = self.image.resize(size, method)
if generateBorder: return self.image
if fill == 'white': # If image is smaller than target resolution and upscale is off - Just expand it by adding margins
border = ImageOps.invert(self.image).getbbox() if self.image.size[0] <= size[0] and self.image.size[1] <= size[1] and not upscale:
else: borderw = (size[0] - self.image.size[0]) / 2
border = self.image.getbbox() borderh = (size[1] - self.image.size[1]) / 2
if border is not None: # PV is disabled when source image is smaller than device screen and upscale is off - So we drop HQ image
if (border[2]-border[0])*1.5 < self.size[0]: if qualityMode == 2 and self.image.size[0] <= self.size[0] and self.image.size[1] <= self.size[1]:
self.noHPV = True self.purge = True
if (border[3]-border[1])*1.5 < self.size[1]: self.image = ImageOps.expand(self.image, border=(borderw, borderh), fill=fill)
self.noVPV = True # Border can't be float so sometimes image might be 1px too small/large
self.border = [int(round(float(border[0])/float(self.image.size[0])*100, 2)*100*1.5), if self.image.size[0] != size[0] or self.image.size[1] != size[1]:
int(round(float(border[1])/float(self.image.size[1])*100, 2)*100*1.5)] self.image = ImageOps.fit(self.image, size, method=Image.BICUBIC, centering=(0.5, 0.5))
else:
self.border = [0, 0]
self.noHPV = True
self.noVPV = True
return self.image return self.image
# Otherwise - Upscale/Downscale # 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: if (float(self.image.size[0]) / float(self.image.size[1])) < ratioDev:
diff = int(self.image.size[1] * ratioDev) - self.image.size[0] 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=(diff / 2, 0), fill=fill)
elif (float(self.image.size[0]) / float(self.image.size[1])) > ratioDev: elif (float(self.image.size[0]) / float(self.image.size[1])) > ratioDev:
diff = int(self.image.size[0] / ratioDev) - self.image.size[1] 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, 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)) 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 return self.image
def splitPage(self, targetdir, righttoleft=False, rotate=False): def splitPage(self, targetdir, righttoleft=False, rotate=False):
@@ -428,37 +411,61 @@ class ComicPage:
RBGW.append(histogram[i] + histogram[256 + i] + histogram[512 + i]) RBGW.append(histogram[i] + histogram[256 + i] + histogram[512 + i])
white = 0 white = 0
black = 0 black = 0
for i in range(245, 256): for i in range(251, 256):
white += RBGW[i] white += RBGW[i]
for i in range(11): for i in range(5):
black += RBGW[i] black += RBGW[i]
if black > white and black > pixelCount*0.5: if black > pixelCount*0.8 and white == 0:
return True return 1
elif white > pixelCount*0.8 and black == 0:
return -1
else: else:
return False return False
def getImageFill(self, isWebToon): def getImageFill(self, webtoon):
fill = 0 fill = 0
if isWebToon or self.rotated: if not webtoon and not self.rotated:
fill += self.getImageHistogram(self.image.crop((0, 0, self.image.size[0], 5))) # Search for horizontal solid lines
fill += self.getImageHistogram(self.image.crop((0, self.image.size[1]-5, self.image.size[0], startY = 0
self.image.size[1]))) while startY < self.image.size[1]:
checkSolid = self.getImageHistogram(self.image.crop((0, startY, self.image.size[0], startY+1)))
if checkSolid:
fill += checkSolid
startY += 1
else: else:
fill += self.getImageHistogram(self.image.crop((0, 0, 5, self.image.size[1]))) # Search for vertical solid lines
fill += self.getImageHistogram(self.image.crop((self.image.size[0]-5, 0, self.image.size[0], startX = 0
self.image.size[1]))) while startX < self.image.size[0]:
if fill == 2: checkSolid = self.getImageHistogram(self.image.crop((startX, 0, startX+1, self.image.size[1])))
if checkSolid:
fill += checkSolid
startX += 1
if fill > 0:
self.fill = 'black' self.fill = 'black'
elif fill == 0:
self.fill = 'white'
else: else:
fill = 0 self.fill = 'white'
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))) def isImageColor(self, image):
fill += self.getImageHistogram(self.image.crop((0, self.image.size[1]-5, 5, self.image.size[1]))) v = ImageStat.Stat(image).var
fill += self.getImageHistogram(self.image.crop((self.image.size[0]-5, self.image.size[1]-5, isMonochromatic = reduce(lambda x, y: x and y < 0.005, v, True)
self.image.size[0], self.image.size[1]))) if isMonochromatic:
if fill > 1: # Monochromatic
self.fill = 'black' 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: else:
self.fill = 'white' # Detection failed
return False

View File

@@ -1,6 +1,6 @@
# Based on initial version of KindleUnpack. Copyright (C) 2009 Charles M. Hannum <root@ihack.net> # 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 # Improvements Copyright (C) 2009-2012 P. Durrant, K. Hendricks, S. Siebert, fandrieu, DiapDealer, nickredding
# Copyright (C) 2013 Pawel Jastrzebski <pawelj@vulturis.eu> # Changes for KCC Copyright (C) 2013 Pawel Jastrzebski <pawelj@vulturis.eu>
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
@@ -15,10 +15,6 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
__license__ = 'ISC'
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
__docformat__ = 'restructuredtext en'
import struct import struct
# from uuid import uuid4 # from uuid import uuid4

View File

@@ -24,13 +24,16 @@ __copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jas
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
import os import os
from random import choice
from string import ascii_uppercase, digits
class PdfJpgExtract: class PdfJpgExtract:
def __init__(self, origFileName): def __init__(self, origFileName):
self.origFileName = origFileName self.origFileName = origFileName
self.filename = os.path.splitext(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): def getPath(self):
return self.path return self.path
@@ -63,7 +66,6 @@ class PdfJpgExtract:
istart += startfix istart += startfix
iend += endfix iend += endfix
print "JPG %d from %d to %d" % (njpg, istart, iend)
jpg = pdf[istart:iend] jpg = pdf[istart:iend]
jpgfile = file(self.path + "/jpg%d.jpg" % njpg, "wb") jpgfile = file(self.path + "/jpg%d.jpg" % njpg, "wb")
jpgfile.write(jpg) jpgfile.write(jpg)

View File

@@ -1,3 +1,4 @@
#!/usr/bin/env python2
""" """
cx_Freeze build script for KCC. cx_Freeze build script for KCC.
@@ -10,7 +11,7 @@ Usage (Windows):
from sys import platform from sys import platform
NAME = "KindleComicConverter" NAME = "KindleComicConverter"
VERSION = "3.5" VERSION = "3.7.2"
MAIN = "kcc.py" MAIN = "kcc.py"
if platform == "darwin": if platform == "darwin":
@@ -23,10 +24,11 @@ if platform == "darwin":
argv_emulation=True, argv_emulation=True,
iconfile='icons/comic2ebook.icns', iconfile='icons/comic2ebook.icns',
includes=['PIL', 'sip', 'PyQt4', 'PyQt4.QtCore', 'PyQt4.QtGui', 'PyQt4.QtNetwork'], includes=['PIL', 'sip', 'PyQt4', 'PyQt4.QtCore', 'PyQt4.QtGui', 'PyQt4.QtNetwork'],
qt_plugins=[],
excludes=['PyQt4.QtDeclarative', 'PyQt4.QtDesigner', 'PyQt4.QtHelp', 'PyQt4.QtMultimedia', excludes=['PyQt4.QtDeclarative', 'PyQt4.QtDesigner', 'PyQt4.QtHelp', 'PyQt4.QtMultimedia',
'PyQt4.QtOpenGL', 'PyQt4.QtScript', 'PyQt4.QtScriptTools', 'PyQt4.QtSql', 'PyQt4.QtSvg', 'PyQt4.QtOpenGL', 'PyQt4.QtScript', 'PyQt4.QtScriptTools', 'PyQt4.QtSql', 'PyQt4.QtSvg',
'PyQt4.QtXmlPatterns', 'PyQt4.QtXml', 'PyQt4.QtWebKit', 'PyQt4.QtTest'], 'PyQt4.QtXmlPatterns', 'PyQt4.QtXml', 'PyQt4.QtWebKit', 'PyQt4.QtTest', 'Tkinter'],
resources=['LICENSE.txt', 'other/Additional-LICENSE.txt'], resources=['LICENSE.txt', 'other/Additional-LICENSE.txt', 'other/unrar', 'other/7za'],
plist=dict( plist=dict(
CFBundleName=NAME, CFBundleName=NAME,
CFBundleShortVersionString=VERSION, CFBundleShortVersionString=VERSION,
@@ -42,6 +44,10 @@ if platform == "darwin":
CFBundleTypeRole='Viewer', CFBundleTypeRole='Viewer',
) )
], ],
LSMinimumSystemVersion='10.8.0',
LSEnvironment=dict(
PATH='/usr/local/bin:/usr/bin:/bin'
),
NSHumanReadableCopyright='ISC License (ISCL)' NSHumanReadableCopyright='ISC License (ISCL)'
) )
) )
@@ -55,7 +61,8 @@ elif platform == "win32":
['other/UnRAR.exe', 'UnRAR.exe'], ['other/UnRAR.exe', 'UnRAR.exe'],
['other/7za.exe', '7za.exe'], ['other/7za.exe', '7za.exe'],
['other/Additional-LICENSE.txt', 'Additional-LICENSE.txt'] ['other/Additional-LICENSE.txt', 'Additional-LICENSE.txt']
], "compressed": True}}, ], "compressed": True,
"excludes": ['Tkinter']}},
executables=[Executable(MAIN, executables=[Executable(MAIN,
base=base, base=base,
targetName="KCC.exe", targetName="KCC.exe",
@@ -65,18 +72,10 @@ elif platform == "win32":
appendScriptToLibrary=False, appendScriptToLibrary=False,
compress=True)]) compress=True)])
else: else:
from cx_Freeze import setup, Executable print 'Please use setup.sh to build Linux package.'
extra_options = dict( exit()
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)])
#noinspection PyUnboundLocalVariable
setup( setup(
name=NAME, name=NAME,
version=VERSION, version=VERSION,
@@ -89,3 +88,8 @@ setup(
packages=['kcc'], requires=['Pillow'], packages=['kcc'], requires=['Pillow'],
**extra_options **extra_options
) )
if platform == "darwin":
from os import chmod
chmod('dist/' + NAME + '.app/Contents/Resources/unrar', 0777)
chmod('dist/' + NAME + '.app/Contents/Resources/7za', 0777)

12
setup.sh Normal file
View File

@@ -0,0 +1,12 @@
#!/bin/bash
# Linux Python package build script
VERSION="3.7.2"
cp kcc.py __main__.py
zip kcc.zip __main__.py kcc/*.py
echo "#!/usr/bin/env python2" > kcc-bin
cat kcc.zip >> kcc-bin
chmod +x kcc-bin
tar --xform s:^.*/:: --xform s/kcc-bin/kcc/ --xform s/comic2ebook/kcc/ -czf KindleComicConverter_linux_$VERSION.tar.gz kcc-bin LICENSE.txt icons/comic2ebook.png
rm __main__.py kcc.zip kcc-bin