1
0
mirror of https://github.com/ciromattia/kcc synced 2026-04-17 06:28:49 +00:00

Compare commits

...

83 Commits
3.0 ... 3.3

Author SHA1 Message Date
Paweł Jastrzębski
143b2a7ff5 Merge branch 'v3.3' 2013-09-29 10:35:20 +02:00
Paweł Jastrzębski
e7b47d28d9 Progress bar don't hide on older Kindle 2013-09-28 23:21:09 +02:00
Paweł Jastrzębski
97b44a89d4 Code cleanup 2013-09-28 19:57:49 +02:00
Paweł Jastrzębski
27e01657b1 Added support for Kindle Fire HDX 2013-09-25 12:33:47 +02:00
Paweł Jastrzębski
43638813d7 Fill detection final, final, final improvements 2013-09-25 11:47:40 +02:00
Paweł Jastrzębski
f781b6785c Fill detection final, final improvements 2013-09-23 18:35:30 +02:00
Paweł Jastrzębski
9168cd4109 Tag goodies made with KCC properly :-) 2013-09-23 17:17:46 +02:00
Paweł Jastrzębski
4c49c6ffc9 False ASIN is breaking thumbnail 2013-09-23 11:31:44 +02:00
Paweł Jastrzębski
4890727692 Replaced KindleStrip with KindleUnpack (close #6) 2013-09-23 10:21:45 +02:00
Paweł Jastrzębski
7907a45ca2 Updated OSX GUI 2013-09-20 11:13:41 +02:00
Paweł Jastrzębski
727bbba815 Linux GUI 2013-09-20 10:39:38 +02:00
Paweł Jastrzębski
877da36e5a Fixed stupid typos 2013-09-19 17:46:08 +02:00
Paweł Jastrzębski
ab8effbc32 Added 7z/CB7 support 2013-09-19 11:01:15 +02:00
Paweł Jastrzębski
a58d98f0dc Updated README and version bump 2013-09-18 12:47:33 +02:00
Paweł Jastrzębski
431cb73e61 GUI tweaks 2013-09-18 12:21:05 +02:00
Paweł Jastrzębski
0ee02f2efd Fill detection final improvements 2013-09-18 10:35:07 +02:00
Paweł Jastrzębski
8d5b2a9e88 General improvements 2013-09-16 17:17:13 +02:00
Paweł Jastrzębski
1085673010 Fill detection improvements 2013-09-16 11:20:42 +02:00
Ciro Mattia Gonano
d327a72749 Switching to PyQt correctly evaluates PATH in OS X.
Fixes #7
2013-09-16 11:12:29 +02:00
Paweł Jastrzębski
74add23c14 Panel View - Proper detection of blank pages 2013-09-16 10:18:26 +02:00
Paweł Jastrzębski
9b400573c8 Automatic matching of Panel View layout 2013-09-15 21:05:53 +02:00
Paweł Jastrzębski
a8c3ef7d00 Margins color detection now handles every file 2013-09-15 16:24:14 +02:00
Paweł Jastrzębski
a484582b70 Merged Kindle 3, 4 and 5 profiles 2013-09-15 15:42:23 +02:00
Paweł Jastrzębski
69b956904c Removed support of Virtual Panel View 2013-09-15 15:02:31 +02:00
Paweł Jastrzębski
6e3888f295 Real Panel View - Ignore margins (close #60) 2013-09-15 13:03:30 +02:00
Paweł Jastrzębski
1bfa0eb9c7 Bundled UnRAR with Windows binary 2013-09-14 17:57:11 +02:00
Paweł Jastrzębski
08a342c909 Webtoon mode tweaks 2013-09-14 17:48:53 +02:00
Paweł Jastrzębski
a28ad2b0c7 Little code cleanup 2013-09-11 15:22:18 +02:00
Paweł Jastrzębski
4c96de9cdf Updated README and version bump 2013-09-06 10:00:08 +02:00
Paweł Jastrzębski
3a645abe6f Hotfix for Russian OS 2013-09-06 09:46:22 +02:00
Paweł Jastrzębski
27bd6f96e7 Webtoon mode improvements 2013-08-19 16:46:27 +02:00
Paweł Jastrzębski
a98fac2e95 Webtoon mode improvements 2013-08-17 16:03:36 +02:00
Paweł Jastrzębski
f645b65a9e Added volume auto-split 2013-08-17 12:01:19 +02:00
Paweł Jastrzębski
6eaf8cc374 comic2panel: Detection of corrupted files 2013-08-16 19:25:26 +02:00
Paweł Jastrzębski
61c0b691ab Webtoon mode improvements 2013-08-16 17:10:18 +02:00
Paweł Jastrzębski
394cefb2de Sanitize job input 2013-08-16 17:09:49 +02:00
Paweł Jastrzębski
30d6a55e3c Webtoon mode improvements 2013-08-16 13:28:27 +02:00
Paweł Jastrzębski
e32018e8f6 Improved cleanup (close #58) 2013-08-15 10:05:03 +02:00
Paweł Jastrzębski
6b002a8475 Webtoon mode improvements 2013-08-15 09:48:50 +02:00
Paweł Jastrzębski
97e23c8f50 Web...toon mode improvements 2013-08-14 09:30:31 +02:00
Paweł Jastrzębski
e558ffd807 Temporary disabling new location of tmp files 2013-08-13 13:33:16 +02:00
Paweł Jastrzębski
71d158ca45 Fixed tmp directories - Need more coffee. 2013-08-13 10:56:49 +02:00
Paweł Jastrzębski
5f8e5e0be9 Fixed tmp directories 2013-08-13 10:48:42 +02:00
Paweł Jastrzębski
ff91eb1407 Webstrip mode improvements 2013-08-13 10:30:53 +02:00
Paweł Jastrzębski
877a859ef4 Fixed abort bug 2013-08-13 09:33:46 +02:00
Paweł Jastrzębski
f8b29cd967 Webstrip mode improvements 2013-08-13 09:25:53 +02:00
Paweł Jastrzębski
3d2554c557 Fixed tmp directories 2013-08-12 16:32:40 +02:00
Paweł Jastrzębski
b7d7204d40 Updated README and version bump 2013-08-12 15:59:32 +02:00
Paweł Jastrzębski
876d26d174 GUI: Added webstrip support 2013-08-12 14:01:57 +02:00
Paweł Jastrzębski
3ccb1a63aa Moved location of temp files 2013-08-12 13:03:03 +02:00
Paweł Jastrzębski
c8bb9b4f5f comic2panel: GUI support and itegration with comic2ebook 2013-08-12 12:59:58 +02:00
Paweł Jastrzębski
723be29118 Updated README 2013-08-11 14:56:26 +02:00
Paweł Jastrzębski
2865915cdf comic2panel: Autodetect border color 2013-08-11 14:47:06 +02:00
Paweł Jastrzębski
d3e0c2bb6e Improved detection of corrupted files 2013-08-11 12:58:34 +02:00
Paweł Jastrzębski
5e7ae73861 Updated README 2013-08-09 15:55:39 +02:00
Paweł Jastrzębski
61206b2169 Help cleanup 2013-08-09 15:25:00 +02:00
Paweł Jastrzębski
92e2a8913b No size limit anymore. KCC now split EPUB files before handling them to KindleGen. 2013-08-08 20:21:05 +02:00
Paweł Jastrzębski
ad827828d7 comic2panel: Fixed processing of last panel 2013-08-05 15:47:56 +02:00
Paweł Jastrzębski
faf16084a3 comic2panel: Multiprocessing support 2013-08-05 15:40:28 +02:00
Paweł Jastrzębski
38d2b55456 Added higly experimental parser of webstrips 2013-08-03 16:17:26 +02:00
Paweł Jastrzębski
abcebc54e8 Updated README 2013-08-03 10:23:45 +02:00
Paweł Jastrzębski
40cb963c99 Improved handling of slugification conflicts 2013-08-02 10:52:51 +02:00
Paweł Jastrzębski
9d267a6cc4 Updated README and version bump 2013-07-22 08:43:35 +02:00
Paweł Jastrzębski
462f24149b Implemented Devernay idea 2013-07-22 08:32:59 +02:00
Paweł Jastrzębski
4744b62f91 Interruption fix 2013-07-21 20:25:14 +02:00
Paweł Jastrzębski
08244e7fdc Conversion can be now interrupted 2013-07-21 20:18:04 +02:00
Paweł Jastrzębski
f64fb1bee1 Multiselect - OSX fix 2013-07-21 19:13:39 +02:00
Paweł Jastrzębski
743c3b2466 Added multiselect to add file/directory dialogs 2013-07-21 18:24:24 +02:00
Paweł Jastrzębski
aefa36fef8 Refactored KindleGen error handling 2013-07-11 13:25:32 +02:00
Paweł Jastrzębski
d7f6503196 Added profile: Kindle for Android 2013-07-11 11:47:18 +02:00
Paweł Jastrzębski
3375b8c898 Don't stop conversion if KindleGen return only warnings 2013-07-11 11:01:35 +02:00
Paweł Jastrzębski
52e5919ccd Bucket of dirty hax to improve readability on Linux/OSX 2013-07-10 09:05:44 +02:00
Paweł Jastrzębski
1c2e57adb6 Updated status messages 2013-07-10 08:50:52 +02:00
Paweł Jastrzębski
2e99d6ee0a Updated status messages 2013-07-10 08:29:14 +02:00
Paweł Jastrzębski
6744815f77 Fixed JobList scroll bars 2013-07-10 08:24:13 +02:00
Paweł Jastrzębski
0ba44ab2d3 HTML tag support for addMessage() 2013-07-10 07:51:19 +02:00
Paweł Jastrzębski
a6006450de Improved upscale/stretch options handling 2013-07-08 11:07:37 +02:00
Paweł Jastrzębski
c20e2ba451 Fixed row alignment (#55) 2013-07-04 15:32:15 +02:00
Paweł Jastrzębski
7a0b387c1c Small tweak of NoSplit option 2013-07-04 15:05:16 +02:00
Ciro Mattia Gonano
fdfe5fbe39 Disable horizontal mode check when "no split/rotate" is checked. 2013-07-04 11:50:20 +02:00
Paweł Jastrzębski
35751efad5 Little tweaks 2013-06-28 00:08:36 +02:00
Mateusz
7005c9e40a Fix misleading message when processing empty directories 2013-06-27 23:40:30 +02:00
Paweł Jastrzębski
118cf25ff7 Older UnRAR exit code is 7 when it is called without parameters 2013-06-27 18:13:39 +02:00
20 changed files with 3244 additions and 873 deletions

2
.gitignore vendored
View File

@@ -7,3 +7,5 @@ dist
kindlegen* kindlegen*
.DS_Store .DS_Store
Thumbs.db Thumbs.db
/UnRAR.exe
/7za.exe

812
KCC-Linux.ui Normal file
View File

@@ -0,0 +1,812 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>KCC</class>
<widget class="QMainWindow" name="KCC">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>420</width>
<height>380</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>420</width>
<height>380</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>420</width>
<height>380</height>
</size>
</property>
<property name="font">
<font>
<pointsize>9</pointsize>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="windowTitle">
<string>Kindle Comic Converter</string>
</property>
<property name="windowIcon">
<iconset resource="KCC.qrc">
<normaloff>:/Icon/icons/comic2ebook.png</normaloff>:/Icon/icons/comic2ebook.png</iconset>
</property>
<property name="locale">
<locale language="C" country="AnyCountry"/>
</property>
<widget class="QWidget" name="Form">
<widget class="QFrame" name="OptionsAdvanced">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>1</x>
<y>254</y>
<width>421</width>
<height>61</height>
</rect>
</property>
<property name="font">
<font>
<family>DejaVu Sans</family>
<pointsize>9</pointsize>
</font>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>9</number>
</property>
<item row="1" column="0">
<widget class="QCheckBox" name="ProcessingBox">
<property name="font">
<font>
<family>DejaVu Sans</family>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Disable image optimizations.</string>
</property>
<property name="text">
<string>No optimisation</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="UpscaleBox">
<property name="font">
<font>
<family>DejaVu Sans</family>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Unchecked - Nothing&lt;br/&gt;&lt;/span&gt;Images smaller than device resolution will not be resized.&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Indeterminate - Stretching&lt;br/&gt;&lt;/span&gt;Images smaller than device resolution will be resized. Aspect ratio will be not preserved.&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Checked - Upscaling&lt;br/&gt;&lt;/span&gt;Images smaller than device resolution will be resized. Aspect ratio will be preserved.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Stretch/Upscale</string>
</property>
<property name="tristate">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="WebtoonBox">
<property name="font">
<font>
<family>DejaVu Sans</family>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable auto-splitting of webtoons like &lt;span style=&quot; font-style:italic;&quot;&gt;Tower of God&lt;/span&gt; or &lt;span style=&quot; font-style:italic;&quot;&gt;Noblesse&lt;/span&gt;.&lt;br/&gt;Pages with a low width, high height and vertical panel flow.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Webtoon mode</string>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QCheckBox" name="NoDitheringBox">
<property name="font">
<font>
<family>DejaVu Sans</family>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Create PNG files instead JPEG.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>PNG output</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="BorderBox">
<property name="font">
<font>
<family>DejaVu Sans</family>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Unchecked - Autodetection&lt;br/&gt;&lt;/span&gt;Color of margins fill will be detected automatically.&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Indeterminate - White&lt;br/&gt;&lt;/span&gt;Margins will be filled with white color.&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Checked - Black&lt;br/&gt;&lt;/span&gt;Margins will be filled with black color.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>W/B margins</string>
</property>
<property name="tristate">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QCheckBox" name="NoRotateBox">
<property name="font">
<font>
<family>DejaVu Sans</family>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Disable splitting and rotation.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>No split/rotate</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QComboBox" name="DeviceBox">
<property name="geometry">
<rect>
<x>10</x>
<y>200</y>
<width>141</width>
<height>31</height>
</rect>
</property>
<property name="font">
<font>
<family>DejaVu Sans</family>
<pointsize>8</pointsize>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Target device.</string>
</property>
</widget>
<widget class="QComboBox" name="FormatBox">
<property name="geometry">
<rect>
<x>260</x>
<y>200</y>
<width>151</width>
<height>31</height>
</rect>
</property>
<property name="font">
<font>
<family>DejaVu Sans</family>
<pointsize>8</pointsize>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Output format.</string>
</property>
</widget>
<widget class="QPushButton" name="ConvertButton">
<property name="geometry">
<rect>
<x>160</x>
<y>200</y>
<width>91</width>
<height>32</height>
</rect>
</property>
<property name="font">
<font>
<family>DejaVu Sans</family>
<pointsize>9</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>Convert</string>
</property>
<property name="icon">
<iconset resource="KCC.qrc">
<normaloff>:/Other/icons/convert.png</normaloff>:/Other/icons/convert.png</iconset>
</property>
</widget>
<widget class="QPushButton" name="DirectoryButton">
<property name="geometry">
<rect>
<x>10</x>
<y>160</y>
<width>141</width>
<height>32</height>
</rect>
</property>
<property name="font">
<font>
<family>DejaVu Sans</family>
<pointsize>8</pointsize>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>Add directory</string>
</property>
<property name="icon">
<iconset resource="KCC.qrc">
<normaloff>:/Other/icons/folder_new.png</normaloff>:/Other/icons/folder_new.png</iconset>
</property>
</widget>
<widget class="QPushButton" name="FileButton">
<property name="geometry">
<rect>
<x>260</x>
<y>160</y>
<width>151</width>
<height>32</height>
</rect>
</property>
<property name="font">
<font>
<family>DejaVu Sans</family>
<pointsize>8</pointsize>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>Add file</string>
</property>
<property name="icon">
<iconset resource="KCC.qrc">
<normaloff>:/Other/icons/document_new.png</normaloff>:/Other/icons/document_new.png</iconset>
</property>
</widget>
<widget class="QPushButton" name="ClearButton">
<property name="geometry">
<rect>
<x>160</x>
<y>160</y>
<width>91</width>
<height>32</height>
</rect>
</property>
<property name="font">
<font>
<family>DejaVu Sans</family>
<pointsize>8</pointsize>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>Clear list</string>
</property>
<property name="icon">
<iconset resource="KCC.qrc">
<normaloff>:/Other/icons/clear.png</normaloff>:/Other/icons/clear.png</iconset>
</property>
</widget>
<widget class="QFrame" name="OptionsBasic">
<property name="geometry">
<rect>
<x>1</x>
<y>230</y>
<width>421</width>
<height>41</height>
</rect>
</property>
<property name="font">
<font>
<family>DejaVu Sans</family>
<pointsize>9</pointsize>
</font>
</property>
<widget class="QCheckBox" name="MangaBox">
<property name="geometry">
<rect>
<x>9</x>
<y>10</y>
<width>130</width>
<height>18</height>
</rect>
</property>
<property name="font">
<font>
<family>DejaVu Sans</family>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Enable right-to-left reading.</string>
</property>
<property name="text">
<string>Manga mode</string>
</property>
</widget>
<widget class="QCheckBox" name="QualityBox">
<property name="geometry">
<rect>
<x>282</x>
<y>10</y>
<width>135</width>
<height>18</height>
</rect>
</property>
<property name="font">
<font>
<family>DejaVu Sans</family>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Sans'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-weight:600; text-decoration: underline;&quot;&gt;Unchecked - Normal quality mode&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-style:italic;&quot;&gt;Use it when Panel View support is not needed.&lt;/span&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-weight:600; text-decoration: underline;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2';&quot;&gt;- Maximum quality when zoom is not enabled.&lt;br /&gt;- Poor quality when zoom is enabled.&lt;br /&gt;- Lowest file size.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-weight:600; text-decoration: underline;&quot;&gt;Indeterminate - High quality mode&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-style:italic;&quot;&gt;Not zoomed image &lt;/span&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-weight:600; font-style:italic;&quot;&gt;might &lt;/span&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-style:italic;&quot;&gt;be a little blurry.&lt;/span&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-weight:600; text-decoration: underline;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2';&quot;&gt;- Medium/High quality when zoom is not enabled.&lt;br /&gt;- Maximum quality when zoom is enabled.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-weight:600; text-decoration: underline;&quot;&gt;Checked - Ultra quality mode&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-style:italic;&quot;&gt;Maximum possible quality.&lt;/span&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-weight:600; text-decoration: underline;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2';&quot;&gt;- Maximum quality when zoom is not enabled.&lt;br /&gt;- Maximum quality when zoom is enabled.&lt;br /&gt;- Very high file size.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>High/Ultra quality</string>
</property>
<property name="tristate">
<bool>true</bool>
</property>
</widget>
<widget class="QCheckBox" name="RotateBox">
<property name="geometry">
<rect>
<x>145</x>
<y>10</y>
<width>130</width>
<height>18</height>
</rect>
</property>
<property name="font">
<font>
<family>DejaVu Sans</family>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Disable page spliting.&lt;br/&gt;They will be rotated instead.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Horizontal mode</string>
</property>
</widget>
<zorder>RotateBox</zorder>
<zorder>MangaBox</zorder>
<zorder>QualityBox</zorder>
</widget>
<widget class="QListWidget" name="JobList">
<property name="geometry">
<rect>
<x>10</x>
<y>50</y>
<width>401</width>
<height>101</height>
</rect>
</property>
<property name="font">
<font>
<family>DejaVu Sans</family>
<pointsize>8</pointsize>
<italic>false</italic>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="showDropIndicator" stdset="0">
<bool>false</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
<property name="iconSize">
<size>
<width>18</width>
<height>18</height>
</size>
</property>
</widget>
<widget class="QPushButton" name="BasicModeButton">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>195</width>
<height>32</height>
</rect>
</property>
<property name="font">
<font>
<family>DejaVu Sans</family>
<pointsize>9</pointsize>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>Basic</string>
</property>
</widget>
<widget class="QPushButton" name="AdvModeButton">
<property name="geometry">
<rect>
<x>217</x>
<y>10</y>
<width>195</width>
<height>32</height>
</rect>
</property>
<property name="font">
<font>
<family>DejaVu Sans</family>
<pointsize>9</pointsize>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string>Advanced</string>
</property>
</widget>
<widget class="QFrame" name="OptionsAdvancedGamma">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>10</x>
<y>305</y>
<width>401</width>
<height>41</height>
</rect>
</property>
<property name="font">
<font>
<family>DejaVu Sans</family>
<pointsize>9</pointsize>
</font>
</property>
<widget class="QLabel" name="GammaLabel">
<property name="geometry">
<rect>
<x>15</x>
<y>0</y>
<width>100</width>
<height>40</height>
</rect>
</property>
<property name="font">
<font>
<family>DejaVu Sans</family>
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;When converting color images setting this option to 1.0 &lt;span style=&quot; font-weight:600;&quot;&gt;might&lt;/span&gt; improve readability.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Gamma: Auto</string>
</property>
</widget>
<widget class="QSlider" name="GammaSlider">
<property name="geometry">
<rect>
<x>110</x>
<y>10</y>
<width>275</width>
<height>22</height>
</rect>
</property>
<property name="font">
<font>
<family>DejaVu Sans</family>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::ClickFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;When converting color images setting this option to 1.0 &lt;span style=&quot; font-weight:600;&quot;&gt;might&lt;/span&gt; improve readability.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="maximum">
<number>500</number>
</property>
<property name="singleStep">
<number>5</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</widget>
<widget class="QProgressBar" name="ProgressBar">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>401</width>
<height>31</height>
</rect>
</property>
<property name="font">
<font>
<family>DejaVu Sans</family>
<pointsize>10</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="value">
<number>0</number>
</property>
<property name="alignment">
<set>Qt::AlignJustify|Qt::AlignVCenter</set>
</property>
<property name="format">
<string/>
</property>
</widget>
<widget class="QFrame" name="OptionsExpert">
<property name="geometry">
<rect>
<x>1</x>
<y>337</y>
<width>421</width>
<height>41</height>
</rect>
</property>
<property name="font">
<font>
<family>DejaVu Sans</family>
<pointsize>9</pointsize>
</font>
</property>
<widget class="QCheckBox" name="ColorBox">
<property name="geometry">
<rect>
<x>9</x>
<y>11</y>
<width>130</width>
<height>18</height>
</rect>
</property>
<property name="font">
<font>
<family>DejaVu Sans</family>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Do not convert images to grayscale.</string>
</property>
<property name="text">
<string>Color mode</string>
</property>
</widget>
<widget class="QFrame" name="OptionsExpertInternal">
<property name="geometry">
<rect>
<x>105</x>
<y>0</y>
<width>295</width>
<height>40</height>
</rect>
</property>
<property name="font">
<font>
<family>DejaVu Sans</family>
</font>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="wLabel">
<property name="font">
<font>
<family>DejaVu Sans</family>
</font>
</property>
<property name="toolTip">
<string>Resolution of target device.</string>
</property>
<property name="text">
<string>Custom width: </string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="customWidth">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>40</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<family>DejaVu Sans</family>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::ClickFocus</enum>
</property>
<property name="acceptDrops">
<bool>false</bool>
</property>
<property name="toolTip">
<string>Resolution of target device.</string>
</property>
<property name="inputMask">
<string>0000; </string>
</property>
<property name="maxLength">
<number>4</number>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="hLabel">
<property name="font">
<font>
<family>DejaVu Sans</family>
</font>
</property>
<property name="toolTip">
<string>Resolution of target device.</string>
</property>
<property name="text">
<string>Custom height: </string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QLineEdit" name="customHeight">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>40</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<family>DejaVu Sans</family>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::ClickFocus</enum>
</property>
<property name="acceptDrops">
<bool>false</bool>
</property>
<property name="toolTip">
<string>Resolution of target device.</string>
</property>
<property name="inputMask">
<string>0000; </string>
</property>
<property name="maxLength">
<number>4</number>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<zorder>OptionsAdvanced</zorder>
<zorder>DeviceBox</zorder>
<zorder>FormatBox</zorder>
<zorder>ConvertButton</zorder>
<zorder>DirectoryButton</zorder>
<zorder>FileButton</zorder>
<zorder>ClearButton</zorder>
<zorder>OptionsBasic</zorder>
<zorder>JobList</zorder>
<zorder>BasicModeButton</zorder>
<zorder>AdvModeButton</zorder>
<zorder>OptionsAdvancedGamma</zorder>
<zorder>OptionsExpert</zorder>
<zorder>ProgressBar</zorder>
</widget>
<action name="ActionBasic">
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<property name="text">
<string>Basic</string>
</property>
<property name="font">
<font/>
</property>
</action>
<action name="ActionAdvanced">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Advanced</string>
</property>
</action>
</widget>
<tabstops>
<tabstop>DirectoryButton</tabstop>
<tabstop>FileButton</tabstop>
<tabstop>ConvertButton</tabstop>
<tabstop>ClearButton</tabstop>
</tabstops>
<resources>
<include location="KCC.qrc"/>
</resources>
<connections/>
</ui>

View File

@@ -47,7 +47,7 @@
</property> </property>
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>9</x> <x>4</x>
<y>253</y> <y>253</y>
<width>421</width> <width>421</width>
<height>61</height> <height>61</height>
@@ -55,6 +55,7 @@
</property> </property>
<property name="font"> <property name="font">
<font> <font>
<family>Lucida Grande</family>
<pointsize>9</pointsize> <pointsize>9</pointsize>
</font> </font>
</property> </property>
@@ -63,7 +64,8 @@
<widget class="QCheckBox" name="ProcessingBox"> <widget class="QCheckBox" name="ProcessingBox">
<property name="font"> <property name="font">
<font> <font>
<pointsize>11</pointsize> <family>Lucida Grande</family>
<pointsize>12</pointsize>
</font> </font>
</property> </property>
<property name="focusPolicy"> <property name="focusPolicy">
@@ -81,35 +83,40 @@
<widget class="QCheckBox" name="UpscaleBox"> <widget class="QCheckBox" name="UpscaleBox">
<property name="font"> <property name="font">
<font> <font>
<pointsize>11</pointsize> <family>Lucida Grande</family>
<pointsize>12</pointsize>
</font> </font>
</property> </property>
<property name="focusPolicy"> <property name="focusPolicy">
<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;Enable image upscaling.&lt;br/&gt;Aspect ratio will be preserved.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt; font-weight:600; text-decoration: underline;&quot;&gt;Unchecked - Nothing&lt;br/&gt;&lt;/span&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Images smaller than device resolution will not be resized.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt; font-weight:600; text-decoration: underline;&quot;&gt;Indeterminate - Stretching&lt;br/&gt;&lt;/span&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Images smaller than device resolution will be resized. Aspect ratio will be not preserved.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt; font-weight:600; text-decoration: underline;&quot;&gt;Checked - Upscaling&lt;br/&gt;&lt;/span&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Images smaller than device resolution will be resized. Aspect ratio will be preserved.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
<property name="text"> <property name="text">
<string>Upscale images</string> <string>Stretch/Upscale</string>
</property>
<property name="tristate">
<bool>true</bool>
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="1"> <item row="3" column="1">
<widget class="QCheckBox" name="StretchBox"> <widget class="QCheckBox" name="WebtoonBox">
<property name="font"> <property name="font">
<font> <font>
<pointsize>11</pointsize> <family>Lucida Grande</family>
<pointsize>12</pointsize>
</font> </font>
</property> </property>
<property name="focusPolicy"> <property name="focusPolicy">
<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;Enable image stretching.&lt;br/&gt;Aspect ratio will be not preserved.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Enable auto-splitting of webtoons like &lt;/span&gt;&lt;span style=&quot; font-size:12pt; font-style:italic;&quot;&gt;Tower of God&lt;/span&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt; or &lt;/span&gt;&lt;span style=&quot; font-size:12pt; font-style:italic;&quot;&gt;Noblesse&lt;/span&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;.&lt;br/&gt;Pages with a low width, high height and vertical panel flow.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
<property name="text"> <property name="text">
<string>Stretch images</string> <string>Webtoon mode</string>
</property> </property>
</widget> </widget>
</item> </item>
@@ -117,14 +124,15 @@
<widget class="QCheckBox" name="NoDitheringBox"> <widget class="QCheckBox" name="NoDitheringBox">
<property name="font"> <property name="font">
<font> <font>
<pointsize>11</pointsize> <family>Lucida Grande</family>
<pointsize>12</pointsize>
</font> </font>
</property> </property>
<property name="focusPolicy"> <property name="focusPolicy">
<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;Create PNG files instead JPEG.&lt;br/&gt;&lt;/span&gt;&lt;span style=&quot; font-size:12pt; font-weight:600;&quot;&gt;Only for non-Kindle devices!&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;Create PNG files instead JPEG.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
<property name="text"> <property name="text">
<string>PNG output</string> <string>PNG output</string>
@@ -135,17 +143,21 @@
<widget class="QCheckBox" name="BorderBox"> <widget class="QCheckBox" name="BorderBox">
<property name="font"> <property name="font">
<font> <font>
<pointsize>11</pointsize> <family>Lucida Grande</family>
<pointsize>12</pointsize>
</font> </font>
</property> </property>
<property name="focusPolicy"> <property name="focusPolicy">
<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;Fill space around images with black color.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt; font-weight:600; text-decoration: underline;&quot;&gt;Unchecked - Autodetection&lt;br/&gt;&lt;/span&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Color of margins fill will be detected automatically.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt; font-weight:600; text-decoration: underline;&quot;&gt;Indeterminate - White&lt;br/&gt;&lt;/span&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Margins will be filled with white color.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt; font-weight:600; text-decoration: underline;&quot;&gt;Checked - Black&lt;br/&gt;&lt;/span&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Margins will be filled with black color.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
<property name="text"> <property name="text">
<string>Black borders</string> <string>W/B margins</string>
</property>
<property name="tristate">
<bool>true</bool>
</property> </property>
</widget> </widget>
</item> </item>
@@ -153,7 +165,8 @@
<widget class="QCheckBox" name="NoRotateBox"> <widget class="QCheckBox" name="NoRotateBox">
<property name="font"> <property name="font">
<font> <font>
<pointsize>11</pointsize> <family>Lucida Grande</family>
<pointsize>12</pointsize>
</font> </font>
</property> </property>
<property name="focusPolicy"> <property name="focusPolicy">
@@ -180,6 +193,7 @@
</property> </property>
<property name="font"> <property name="font">
<font> <font>
<family>Lucida Grande</family>
<pointsize>11</pointsize> <pointsize>11</pointsize>
</font> </font>
</property> </property>
@@ -187,7 +201,7 @@
<enum>Qt::NoFocus</enum> <enum>Qt::NoFocus</enum>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Target device.</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Target device.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
</widget> </widget>
<widget class="QComboBox" name="FormatBox"> <widget class="QComboBox" name="FormatBox">
@@ -201,6 +215,7 @@
</property> </property>
<property name="font"> <property name="font">
<font> <font>
<family>Lucida Grande</family>
<pointsize>11</pointsize> <pointsize>11</pointsize>
</font> </font>
</property> </property>
@@ -208,7 +223,7 @@
<enum>Qt::NoFocus</enum> <enum>Qt::NoFocus</enum>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Output format.</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Output format.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
</widget> </widget>
<widget class="QPushButton" name="ConvertButton"> <widget class="QPushButton" name="ConvertButton">
@@ -222,6 +237,7 @@
</property> </property>
<property name="font"> <property name="font">
<font> <font>
<family>Lucida Grande</family>
<pointsize>11</pointsize> <pointsize>11</pointsize>
<weight>75</weight> <weight>75</weight>
<bold>true</bold> <bold>true</bold>
@@ -249,6 +265,7 @@
</property> </property>
<property name="font"> <property name="font">
<font> <font>
<family>Lucida Grande</family>
<pointsize>11</pointsize> <pointsize>11</pointsize>
</font> </font>
</property> </property>
@@ -274,6 +291,7 @@
</property> </property>
<property name="font"> <property name="font">
<font> <font>
<family>Lucida Grande</family>
<pointsize>11</pointsize> <pointsize>11</pointsize>
</font> </font>
</property> </property>
@@ -299,6 +317,7 @@
</property> </property>
<property name="font"> <property name="font">
<font> <font>
<family>Lucida Grande</family>
<pointsize>11</pointsize> <pointsize>11</pointsize>
</font> </font>
</property> </property>
@@ -316,7 +335,7 @@
<widget class="QFrame" name="OptionsBasic"> <widget class="QFrame" name="OptionsBasic">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>10</x> <x>5</x>
<y>233</y> <y>233</y>
<width>421</width> <width>421</width>
<height>41</height> <height>41</height>
@@ -324,7 +343,8 @@
</property> </property>
<property name="font"> <property name="font">
<font> <font>
<pointsize>9</pointsize> <family>Lucida Grande</family>
<pointsize>12</pointsize>
</font> </font>
</property> </property>
<widget class="QCheckBox" name="MangaBox"> <widget class="QCheckBox" name="MangaBox">
@@ -338,7 +358,8 @@
</property> </property>
<property name="font"> <property name="font">
<font> <font>
<pointsize>11</pointsize> <family>Lucida Grande</family>
<pointsize>12</pointsize>
</font> </font>
</property> </property>
<property name="focusPolicy"> <property name="focusPolicy">
@@ -356,20 +377,21 @@
<rect> <rect>
<x>282</x> <x>282</x>
<y>10</y> <y>10</y>
<width>130</width> <width>135</width>
<height>18</height> <height>18</height>
</rect> </rect>
</property> </property>
<property name="font"> <property name="font">
<font> <font>
<pointsize>11</pointsize> <family>Lucida Grande</family>
<pointsize>12</pointsize>
</font> </font>
</property> </property>
<property name="focusPolicy"> <property name="focusPolicy">
<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-family:'MS Shell Dlg 2'; font-size:14pt; 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-size:14pt; 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-size:14pt; font-weight:600; text-decoration: underline;&quot;&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:14pt;&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-family:'MS Shell Dlg 2'; font-size:14pt; 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-size:14pt; font-style:italic;&quot;&gt;Not zoomed image &lt;/span&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:14pt; font-weight:600; font-style:italic;&quot;&gt;might &lt;/span&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:14pt; font-style:italic;&quot;&gt;be a little blurry.&lt;/span&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:14pt; font-weight:600; text-decoration: underline;&quot;&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:14pt;&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-family:'MS Shell Dlg 2'; font-size:14pt; 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-size:14pt; font-style:italic;&quot;&gt;Maximum possible quality.&lt;/span&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:14pt; font-weight:600; text-decoration: underline;&quot;&gt;&lt;br/&gt;&lt;/span&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:14pt;&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;/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>
@@ -389,7 +411,8 @@
</property> </property>
<property name="font"> <property name="font">
<font> <font>
<pointsize>11</pointsize> <family>Lucida Grande</family>
<pointsize>12</pointsize>
</font> </font>
</property> </property>
<property name="focusPolicy"> <property name="focusPolicy">
@@ -417,6 +440,7 @@
</property> </property>
<property name="font"> <property name="font">
<font> <font>
<family>Lucida Grande</family>
<pointsize>11</pointsize> <pointsize>11</pointsize>
</font> </font>
</property> </property>
@@ -441,6 +465,7 @@
</property> </property>
<property name="font"> <property name="font">
<font> <font>
<family>Lucida Grande</family>
<pointsize>12</pointsize> <pointsize>12</pointsize>
<weight>50</weight> <weight>50</weight>
<bold>false</bold> <bold>false</bold>
@@ -464,6 +489,7 @@
</property> </property>
<property name="font"> <property name="font">
<font> <font>
<family>Lucida Grande</family>
<pointsize>12</pointsize> <pointsize>12</pointsize>
<weight>50</weight> <weight>50</weight>
<bold>false</bold> <bold>false</bold>
@@ -482,7 +508,7 @@
</property> </property>
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>10</x> <x>5</x>
<y>303</y> <y>303</y>
<width>401</width> <width>401</width>
<height>41</height> <height>41</height>
@@ -490,6 +516,7 @@
</property> </property>
<property name="font"> <property name="font">
<font> <font>
<family>Lucida Grande</family>
<pointsize>9</pointsize> <pointsize>9</pointsize>
</font> </font>
</property> </property>
@@ -504,13 +531,14 @@
</property> </property>
<property name="font"> <property name="font">
<font> <font>
<family>Lucida Grande</family>
<pointsize>12</pointsize> <pointsize>12</pointsize>
<weight>50</weight> <weight>50</weight>
<bold>false</bold> <bold>false</bold>
</font> </font>
</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;When converting color images setting this option to 1.0 MIGHT improve readability.&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;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>
<property name="text"> <property name="text">
<string>Gamma: Auto</string> <string>Gamma: Auto</string>
@@ -521,10 +549,15 @@
<rect> <rect>
<x>110</x> <x>110</x>
<y>10</y> <y>10</y>
<width>280</width> <width>290</width>
<height>22</height> <height>22</height>
</rect> </rect>
</property> </property>
<property name="font">
<font>
<family>Lucida Grande</family>
</font>
</property>
<property name="focusPolicy"> <property name="focusPolicy">
<enum>Qt::ClickFocus</enum> <enum>Qt::ClickFocus</enum>
</property> </property>
@@ -553,6 +586,7 @@
</property> </property>
<property name="font"> <property name="font">
<font> <font>
<family>Lucida Grande</family>
<pointsize>10</pointsize> <pointsize>10</pointsize>
<weight>75</weight> <weight>75</weight>
<bold>true</bold> <bold>true</bold>
@@ -574,7 +608,7 @@
<widget class="QFrame" name="OptionsExpert"> <widget class="QFrame" name="OptionsExpert">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>10</x> <x>5</x>
<y>335</y> <y>335</y>
<width>421</width> <width>421</width>
<height>41</height> <height>41</height>
@@ -582,6 +616,7 @@
</property> </property>
<property name="font"> <property name="font">
<font> <font>
<family>Lucida Grande</family>
<pointsize>9</pointsize> <pointsize>9</pointsize>
</font> </font>
</property> </property>
@@ -596,7 +631,8 @@
</property> </property>
<property name="font"> <property name="font">
<font> <font>
<pointsize>11</pointsize> <family>Lucida Grande</family>
<pointsize>12</pointsize>
</font> </font>
</property> </property>
<property name="focusPolicy"> <property name="focusPolicy">
@@ -612,17 +648,23 @@
<widget class="QFrame" name="OptionsExpertInternal"> <widget class="QFrame" name="OptionsExpertInternal">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>90</x> <x>95</x>
<y>0</y> <y>0</y>
<width>315</width> <width>315</width>
<height>40</height> <height>40</height>
</rect> </rect>
</property> </property>
<property name="font">
<font>
<family>Lucida Grande</family>
</font>
</property>
<layout class="QGridLayout" name="gridLayout_2"> <layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="wLabel"> <widget class="QLabel" name="wLabel">
<property name="font"> <property name="font">
<font> <font>
<family>Lucida Grande</family>
<pointsize>12</pointsize> <pointsize>12</pointsize>
<weight>50</weight> <weight>50</weight>
<bold>false</bold> <bold>false</bold>
@@ -652,6 +694,7 @@
</property> </property>
<property name="font"> <property name="font">
<font> <font>
<family>Lucida Grande</family>
<pointsize>12</pointsize> <pointsize>12</pointsize>
</font> </font>
</property> </property>
@@ -676,6 +719,7 @@
<widget class="QLabel" name="hLabel"> <widget class="QLabel" name="hLabel">
<property name="font"> <property name="font">
<font> <font>
<family>Lucida Grande</family>
<pointsize>12</pointsize> <pointsize>12</pointsize>
<weight>50</weight> <weight>50</weight>
<bold>false</bold> <bold>false</bold>
@@ -705,6 +749,7 @@
</property> </property>
<property name="font"> <property name="font">
<font> <font>
<family>Lucida Grande</family>
<pointsize>12</pointsize> <pointsize>12</pointsize>
</font> </font>
</property> </property>

25
KCC.ui
View File

@@ -59,6 +59,9 @@
</font> </font>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>9</number>
</property>
<item row="1" column="0"> <item row="1" column="0">
<widget class="QCheckBox" name="ProcessingBox"> <widget class="QCheckBox" name="ProcessingBox">
<property name="focusPolicy"> <property name="focusPolicy">
@@ -78,23 +81,26 @@
<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;Enable image upscaling.&lt;br/&gt;Aspect ratio will be preserved.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Unchecked - Nothing&lt;br/&gt;&lt;/span&gt;Images smaller than device resolution will not be resized.&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Indeterminate - Stretching&lt;br/&gt;&lt;/span&gt;Images smaller than device resolution will be resized. Aspect ratio will be not preserved.&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Checked - Upscaling&lt;br/&gt;&lt;/span&gt;Images smaller than device resolution will be resized. Aspect ratio will be preserved.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
<property name="text"> <property name="text">
<string>Upscale images</string> <string>Stretch/Upscale</string>
</property>
<property name="tristate">
<bool>true</bool>
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="1"> <item row="3" column="1">
<widget class="QCheckBox" name="StretchBox"> <widget class="QCheckBox" name="WebtoonBox">
<property name="focusPolicy"> <property name="focusPolicy">
<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;Enable image stretching.&lt;br/&gt;Aspect ratio will be not preserved.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable auto-splitting of webtoons like &lt;span style=&quot; font-style:italic;&quot;&gt;Tower of God&lt;/span&gt; or &lt;span style=&quot; font-style:italic;&quot;&gt;Noblesse&lt;/span&gt;.&lt;br/&gt;Pages with a low width, high height and vertical panel flow.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
<property name="text"> <property name="text">
<string>Stretch images</string> <string>Webtoon mode</string>
</property> </property>
</widget> </widget>
</item> </item>
@@ -104,7 +110,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;Create PNG files instead JPEG.&lt;br/&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Only for non-Kindle devices!&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;Create PNG files instead JPEG.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
<property name="text"> <property name="text">
<string>PNG output</string> <string>PNG output</string>
@@ -117,10 +123,13 @@
<enum>Qt::NoFocus</enum> <enum>Qt::NoFocus</enum>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Fill space around images with black color.</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Unchecked - Autodetection&lt;br/&gt;&lt;/span&gt;Color of margins fill will be detected automatically.&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Indeterminate - White&lt;br/&gt;&lt;/span&gt;Margins will be filled with white color.&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline;&quot;&gt;Checked - Black&lt;br/&gt;&lt;/span&gt;Margins will be filled with black color.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
<property name="text"> <property name="text">
<string>Black borders</string> <string>W/B margins</string>
</property>
<property name="tristate">
<bool>true</bool>
</property> </property>
</widget> </widget>
</item> </item>

137
README.md
View File

@@ -24,20 +24,19 @@ You can find the latest released binary at the following links:
- **OS X:** [http://kcc.vulturis.eu/OSX/](http://kcc.vulturis.eu/OSX/) - **OS X:** [http://kcc.vulturis.eu/OSX/](http://kcc.vulturis.eu/OSX/)
- **Linux:** Just download sourcecode and launch: `python kcc.py` - **Linux:** Just download sourcecode and launch: `python kcc.py`
_It has been reported by a couple of users that version 2.10 crashing on OSX at start. We don't know if that issue still exist in version 3.0.
If it happens to you please append your message to [Issue #52](https://github.com/ciromattia/kcc/issues/52)._
## 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 file types:
- PNG, JPG, GIF, TIFF, BMP - PNG, JPG, GIF, TIFF, BMP
- Folders - Folders
- CBZ, ZIP - CBZ, ZIP
- CBR, RAR *(With `unrar` executable)* - CBR, RAR *(With `unrar` 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)*
### 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.
@@ -50,15 +49,16 @@ If it happens to you please append your message to [Issue #52](https://github.co
* Use high quality source files. **This little detail have a major impact on the final result.** * 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. * Read tooltip of _High/Ultra quality_ option. There are many important informations there.
* When converting images smaller than device resolution remember to enable upscaling. * 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. * 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. * The first image found will be set as the comic's cover.
* All files/directories will be added to EPUB in alphabetical order. * All files/directories will be added to EPUB in alphabetical order.
* Output MOBI file should be uploaded via USB. Other methods (e.g. via Calibre) might corrupt it. * Output MOBI file should be uploaded via USB. Other methods might corrupt it.
* If you're converting color images and the end result is not satisfactory, experiment with gamma correction option (check 1.0 setting first).
### GUI ### GUI
Should be pretty self-explanatory. 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).
### Standalone `comic2ebook.py` usage: ### Standalone `comic2ebook.py` usage:
@@ -67,30 +67,60 @@ After completed conversion you should find ready file alongside the original inp
Usage: comic2ebook.py [options] comic_file|comic_folder Usage: comic2ebook.py [options] comic_file|comic_folder
Options: Options:
--version show program's version number and exit MAIN:
-h, --help show this help message and exit -p PROFILE, --profile=PROFILE
-p PROFILE, --profile=PROFILE Device profile (Choose one among K1, K2, K345, KDX, KDXG, KHD, KF, KFHD, KFHD8, KFHDX, KFHDX8, KFA) [Default=KHD]
Device profile (Choose one among K1, K2, K3, K4NT, K4T, KDX, KDXG, KHD, KF, KFHD, KFHD8) [Default=KHD] -q QUALITY, --quality=QUALITY
-t TITLE, --title=TITLE Quality of Panel View. 0 - Normal 1 - High 2 - Ultra [Default=0]
Comic title [Default=filename] -m, --manga-style Manga style (Right-to-left reading and splitting)
-m, --manga-style Manga style (Right-to-left reading and splitting) [Default=False] -w, --webtoon Webtoon processing mode
--quality=QUALITY Output quality. 0 - Normal 1 - High 2 - Ultra [Default=0]
-c, --cbz-output Outputs a CBZ archive and does not generate EPUB OUTPUT SETTINGS:
--noprocessing Do not apply image preprocessing (Page splitting and optimizations) [Default=True] -o OUTPUT, --output=OUTPUT
--forcepng Create PNG files instead JPEG (For non-Kindle devices) [Default=False] Output generated file to specified directory or file
--gamma=GAMMA Apply gamma correction to linearize the image [Default=Auto] -t TITLE, --title=TITLE
--upscale Resize images smaller than device's resolution [Default=False] Comic title [Default=filename or directory name]
--stretch Stretch images to device's resolution [Default=False] --cbz-output Outputs a CBZ archive and does not generate EPUB
--blackborders Use black borders instead of white ones when not stretching and ratio is not like the device's one [Default=False] --batchsplit Split output into multiple files
--rotate Rotate landscape pages instead of splitting them [Default=False]
--nosplitrotate Disable splitting and rotation [Default=False] PROCESSING:
--nocutpagenumbers Do not try to cut page numbering on images [Default=True] --blackborders Disable autodetection and force black borders
-o OUTPUT, --output=OUTPUT --whiteborders Disable autodetection and force white borders
Output generated file (EPUB or CBZ) to specified directory or file --forcecolor Don't convert images to grayscale
--forcecolor Do not convert images to grayscale [Default=False] --forcepng Create PNG files instead JPEG (For non-Kindle devices)
--customwidth=WIDTH Replace screen width provided by device profile [Default=0] --gamma=GAMMA Apply gamma correction to linearize the image [Default=Auto]
--customheight=HEIGHT Replace screen height provided by device profile [Default=0] --nocutpagenumbers Don't try to cut page numbering on images
-v, --verbose Verbose output [Default=False] --noprocessing Don't apply image preprocessing
--nosplitrotate Disable splitting and rotation
--rotate Rotate landscape pages instead of splitting them
--stretch Stretch images to device's resolution
--upscale Resize images smaller than device's resolution
CUSTOM PROFILE:
--customwidth=CUSTOMWIDTH
Replace screen width provided by device profile
--customheight=CUSTOMHEIGHT
Replace screen height provided by device profile
OTHER:
-v, --verbose Verbose output
-h, --help Show this help message and exit
```
### Standalone `comic2panel.py` usage:
```
Usage: comic2panel.py [options] comic_folder
Options:
MANDATORY:
-y HEIGHT, --height=HEIGHT
Height of the target device screen
-i, --in-place Overwrite source directory
OTHER:
-d, --debug Create debug file for every splitted image
-h, --help Show this help message and exit
``` ```
## CREDITS ## CREDITS
@@ -100,22 +130,20 @@ This script born as a cross-platform alternative to `KindleComicParser` by **Dc5
The app relies and includes the following scripts/binaries: The app relies and includes the following scripts/binaries:
- `KindleStrip` script &copy; 2010-2012 by **Paul Durrant** and released in public domain - `KindleUnpack` script by Charles **M. Hannum, P. Durrant, K. Hendricks, S. Siebert, fandrieu, DiapDealer, nickredding**. Released with GPLv3 License.
([forum thread](http://www.mobileread.com/forums/showthread.php?t=96903)) - `rarfile.py` script &copy; 2005-2011 **Marko Kreen** <markokr@gmail.com>. Released with ISC License.
- `rarfile.py` script &copy; 2005-2011 **Marko Kreen** <markokr@gmail.com>, released with ISC License - `image.py` class from **Alex Yatskov**'s [Mangle](http://foosoft.net/mangle/) with subsequent [proDOOMman](https://github.com/proDOOMman/Mangle)'s and [Birua](https://github.com/Birua/Mangle)'s patches.
- `image.py` class from **Alex Yatskov**'s [Mangle](http://foosoft.net/mangle/) with subsequent [proDOOMman](https://github.com/proDOOMman/Mangle)'s and [Birua](https://github.com/Birua/Mangle)'s patches - Icon is by **Nikolay Verin** ([http://ncrow.deviantart.com/](http://ncrow.deviantart.com/)) and released under [CC BY-NC-SA 3.0](http://creativecommons.org/licenses/by-nc-sa/3.0/) License.
- Icon is by **Nikolay Verin** ([http://ncrow.deviantart.com/](http://ncrow.deviantart.com/)) and released under [CC BY-NC-SA 3.0](http://creativecommons.org/licenses/by-nc-sa/3.0/) License
## SAMPLE FILES CREATED BY KCC ## SAMPLE FILES CREATED BY KCC
* [Kindle Keyboard](http://kcc.vulturis.eu/Samples/Ubunchu!-K3.mobi)
* [Kindle DX](http://kcc.vulturis.eu/Samples/Ubunchu!-KDX.mobi)
* [Kindle DXG](http://kcc.vulturis.eu/Samples/Ubunchu!-KDXG.mobi)
* [Kindle Non-Touch](http://kcc.vulturis.eu/Samples/Ubunchu!-K4NT.mobi)
* [Kindle Touch](http://kcc.vulturis.eu/Samples/Ubunchu!-K4T.mobi)
* [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 DX/DXG](http://kcc.vulturis.eu/Samples/Ubunchu!-KDX.mobi)
* [Kindle Fire](http://kcc.vulturis.eu/Samples/Ubunchu!-KF.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 8.9"](http://kcc.vulturis.eu/Samples/Ubunchu!-KFHDX8.mobi)
## CHANGELOG ## CHANGELOG
####1.00 ####1.00
@@ -213,9 +241,32 @@ The app relies and includes the following scripts/binaries:
* Added support for custom width/height * Added support for custom width/height
* Added option to disable color conversion * Added option to disable color conversion
## KNOWN ISSUES ####3.1:
* _Add directory_ dialog allow to select multiple directories but they are not added to job list. [QT bug.](https://bugreports.qt-project.org/browse/QTBUG-21372) * Added profile: Kindle for Android
* Removing SRCS headers sometimes fail in 32bit enviroments. Due to memory limitations. * Add file/directory dialogs now support multiselect
* Many small fixes and tweaks
####3.2:
* Too big EPUB files are now splitted before conversion to MOBI
* Added experimental parser of manga webtoons
* Improved error handling
####3.2.1:
* Hotfixed crash occurring on OS with Russian locale
####3.3:
* Margins are now automatically omitted in Panel View mode
* Margin color fill is now autodetected
* Created MOBI files are not longer marked as _Personal_ on newer Kindle models
* Layout of panels in Panel View mode is now automatically adjusted to content
* Fixed Kindle 2/DX/DXG profiles - no more blank pages
* All Kindle Fire profiles now support hiqh quality Panel View
* Added support of 7z/CB7 files
* Added Kindle Fire HDX profile
* Support for Virtual Panel View was removed
* Profiles for Kindle Keyboard, Touch and Non-Touch are now merged
* Windows release is now bundled with UnRAR and 7za
* Small GUI tweaks
## COPYRIGHT ## COPYRIGHT

13
kcc.py
View File

@@ -1,7 +1,8 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (c) 2012 Ciro Mattia Gonano <ciromattia@gmail.com> # Copyright (c) 2012-2013 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013 Pawel Jastrzebski <pawelj@vulturis.eu>
# #
# Permission to use, copy, modify, and/or distribute this software for # Permission to use, copy, modify, and/or distribute this software for
# any purpose with or without fee is hereby granted, provided that the # any purpose with or without fee is hereby granted, provided that the
@@ -16,8 +17,8 @@
# OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER # OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
# 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.0' __version__ = '3.3'
__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'
@@ -32,10 +33,10 @@ except ImportError:
exit(1) exit(1)
from kcc import KCC_gui from kcc import KCC_gui
from multiprocessing import freeze_support from multiprocessing import freeze_support
if sys.platform.startswith('darwin'):
if sys.platform == 'darwin':
os.environ['PATH'] = '/usr/local/bin:' + os.environ['PATH']
from kcc import KCC_ui_osx as KCC_ui from kcc import KCC_ui_osx as KCC_ui
elif sys.platform.startswith('linux'):
from kcc import KCC_ui_linux as KCC_ui
else: else:
from kcc import KCC_ui from kcc import KCC_ui

View File

@@ -1,7 +1,8 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# Copyright (c) 2013 Ciro Mattia Gonano <ciromattia@gmail.com> # Copyright (c) 2012-2013 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013 Pawel Jastrzebski <pawelj@vulturis.eu>
# #
# Permission to use, copy, modify, and/or distribute this software for # Permission to use, copy, modify, and/or distribute this software for
# any purpose with or without fee is hereby granted, provided that the # any purpose with or without fee is hereby granted, provided that the
@@ -17,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.0' __version__ = '3.3'
__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'
@@ -27,12 +28,14 @@ import sys
import shutil import shutil
import traceback import traceback
import urllib2 import urllib2
import time
import comic2ebook import comic2ebook
import kindlestrip import kindlesplit
from image import ProfileData from image import ProfileData
from subprocess import call, Popen, STDOUT, PIPE from subprocess import call, Popen, STDOUT, PIPE
from PyQt4 import QtGui, QtCore from PyQt4 import QtGui, QtCore
from xml.dom.minidom import parse from xml.dom.minidom import parse
from HTMLParser import HTMLParser
class Icons: class Icons:
@@ -57,6 +60,19 @@ class Icons:
self.error.addPixmap(QtGui.QPixmap(":/Status/icons/error.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.error.addPixmap(QtGui.QPixmap(":/Status/icons/error.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
class HTMLStripper(HTMLParser):
def __init__(self):
HTMLParser.__init__(self)
self.reset()
self.fed = []
def handle_data(self, d):
self.fed.append(d)
def get_data(self):
return ''.join(self.fed)
# noinspection PyBroadException # noinspection PyBroadException
class VersionThread(QtCore.QThread): class VersionThread(QtCore.QThread):
def __init__(self, parent): def __init__(self, parent):
@@ -74,7 +90,8 @@ class VersionThread(QtCore.QThread):
return return
latestVersion = XML.childNodes[0].getElementsByTagName('latest')[0].childNodes[0].toxml() latestVersion = XML.childNodes[0].getElementsByTagName('latest')[0].childNodes[0].toxml()
if tuple(map(int, (latestVersion.split(".")))) > tuple(map(int, (__version__.split(".")))): if tuple(map(int, (latestVersion.split(".")))) > tuple(map(int, (__version__.split(".")))):
self.emit(QtCore.SIGNAL("addMessage"), 'New version is available!', 'warning') self.emit(QtCore.SIGNAL("addMessage"), '<a href="http://kcc.vulturis.eu/">'
'<b>New version is available!</b></a>', 'warning')
# noinspection PyBroadException # noinspection PyBroadException
@@ -82,10 +99,23 @@ class WorkerThread(QtCore.QThread):
def __init__(self, parent): def __init__(self, parent):
QtCore.QThread.__init__(self) QtCore.QThread.__init__(self)
self.parent = parent self.parent = parent
self.conversionAlive = False
self.errors = False
self.kindlegenErrorCode = 0
self.kindlegenError = None
def __del__(self): def __del__(self):
self.wait() self.wait()
def sync(self):
self.conversionAlive = self.parent.conversionAlive
def clean(self):
self.parent.needClean = True
self.emit(QtCore.SIGNAL("hideProgressBar"))
self.emit(QtCore.SIGNAL("addMessage"), '<b>Conversion interrupted.</b>', 'error')
self.emit(QtCore.SIGNAL("modeConvert"), True)
def run(self): def run(self):
self.emit(QtCore.SIGNAL("modeConvert"), False) self.emit(QtCore.SIGNAL("modeConvert"), False)
profile = ProfileData.ProfileLabels[str(GUI.DeviceBox.currentText())] profile = ProfileData.ProfileLabels[str(GUI.DeviceBox.currentText())]
@@ -102,31 +132,42 @@ class WorkerThread(QtCore.QThread):
if self.parent.currentMode > 1: if self.parent.currentMode > 1:
if GUI.ProcessingBox.isChecked(): if GUI.ProcessingBox.isChecked():
argv.append("--noprocessing") argv.append("--noprocessing")
if GUI.UpscaleBox.isChecked() and not GUI.StretchBox.isChecked():
argv.append("--upscale")
if GUI.NoRotateBox.isChecked(): if GUI.NoRotateBox.isChecked():
argv.append("--nosplitrotate") argv.append("--nosplitrotate")
if GUI.BorderBox.isChecked(): if GUI.UpscaleBox.checkState() == 1:
argv.append("--blackborders")
if GUI.StretchBox.isChecked():
argv.append("--stretch") argv.append("--stretch")
elif GUI.UpscaleBox.checkState() == 2:
argv.append("--upscale")
if GUI.BorderBox.checkState() == 1:
argv.append("--whiteborders")
elif GUI.BorderBox.checkState() == 2:
argv.append("--blackborders")
if GUI.NoDitheringBox.isChecked(): if GUI.NoDitheringBox.isChecked():
argv.append("--forcepng") argv.append("--forcepng")
if GUI.WebtoonBox.isChecked():
argv.append("--webtoon")
if float(self.parent.GammaValue) > 0.09: if float(self.parent.GammaValue) > 0.09:
argv.append("--gamma=" + self.parent.GammaValue) argv.append("--gamma=" + self.parent.GammaValue)
if str(GUI.FormatBox.currentText()) == 'CBZ': if str(GUI.FormatBox.currentText()) == 'CBZ':
argv.append("--cbz-output") argv.append("--cbz-output")
if str(GUI.FormatBox.currentText()) == 'MOBI':
argv.append("--batchsplit")
if self.parent.currentMode > 2: if self.parent.currentMode > 2:
argv.append("--customwidth=" + str(GUI.customWidth.text())) argv.append("--customwidth=" + str(GUI.customWidth.text()))
argv.append("--customheight=" + str(GUI.customHeight.text())) argv.append("--customheight=" + str(GUI.customHeight.text()))
if GUI.ColorBox.isChecked(): if GUI.ColorBox.isChecked():
argv.append("--forcecolor") argv.append("--forcecolor")
for i in range(GUI.JobList.count()): for i in range(GUI.JobList.count()):
currentJobs.append(str(GUI.JobList.item(i).text())) if GUI.JobList.item(i).icon().isNull():
currentJobs.append(str(GUI.JobList.item(i).text()))
GUI.JobList.clear() GUI.JobList.clear()
for job in currentJobs: for job in currentJobs:
time.sleep(0.5)
if not self.conversionAlive:
self.clean()
return
self.errors = False self.errors = False
self.emit(QtCore.SIGNAL("addMessage"), 'Source: ' + job, 'info') self.emit(QtCore.SIGNAL("addMessage"), '<b>Source:</b> ' + job, 'info')
if str(GUI.FormatBox.currentText()) == 'CBZ': if str(GUI.FormatBox.currentText()) == 'CBZ':
self.emit(QtCore.SIGNAL("addMessage"), 'Creating CBZ file...', 'info') self.emit(QtCore.SIGNAL("addMessage"), 'Creating CBZ file...', 'info')
else: else:
@@ -136,101 +177,182 @@ class WorkerThread(QtCore.QThread):
try: try:
outputPath = comic2ebook.main(jobargv, self) outputPath = comic2ebook.main(jobargv, self)
self.emit(QtCore.SIGNAL("hideProgressBar")) self.emit(QtCore.SIGNAL("hideProgressBar"))
except UserWarning as warn:
if not self.conversionAlive:
self.clean()
return
else:
self.errors = True
self.emit(QtCore.SIGNAL("addMessage"), str(warn), 'warning')
self.emit(QtCore.SIGNAL("addMessage"), 'KCC failed to create output file!', 'warning')
except Exception as err: except Exception as err:
self.errors = True self.errors = True
type_, value_, traceback_ = sys.exc_info() type_, value_, traceback_ = sys.exc_info()
self.emit(QtCore.SIGNAL("showDialog"), "Error during conversion %s:\n\n%s\n\nTraceback:\n%s" self.emit(QtCore.SIGNAL("showDialog"), "Error during conversion %s:\n\n%s\n\nTraceback:\n%s"
% (jobargv[-1], str(err), traceback.format_tb(traceback_))) % (jobargv[-1], str(err), traceback.format_tb(traceback_)))
self.emit(QtCore.SIGNAL("addMessage"), 'KCC failed to create EPUB!', 'error') self.emit(QtCore.SIGNAL("addMessage"), 'KCC failed to create EPUB!', 'error')
if not self.conversionAlive:
for item in outputPath:
if os.path.exists(item):
os.remove(item)
self.clean()
return
if not self.errors: if not self.errors:
if str(GUI.FormatBox.currentText()) == 'CBZ': if str(GUI.FormatBox.currentText()) == 'CBZ':
self.emit(QtCore.SIGNAL("addMessage"), 'Creating CBZ file... Done!', 'info', True) self.emit(QtCore.SIGNAL("addMessage"), 'Creating CBZ file... Done!', 'info', True)
else: else:
self.emit(QtCore.SIGNAL("addMessage"), 'Creating EPUB file... Done!', 'info', True) self.emit(QtCore.SIGNAL("addMessage"), 'Creating EPUB file... Done!', 'info', True)
if str(GUI.FormatBox.currentText()) == 'MOBI': if str(GUI.FormatBox.currentText()) == 'MOBI':
if not os.path.getsize(outputPath) > 314572800: tomeNumber = 0
self.emit(QtCore.SIGNAL("addMessage"), 'Creating MOBI file...', 'info') for item in outputPath:
tomeNumber += 1
if len(outputPath) > 1:
self.emit(QtCore.SIGNAL("addMessage"), 'Creating MOBI file (' + str(tomeNumber)
+ '/' + str(len(outputPath)) + ')...', 'info')
else:
self.emit(QtCore.SIGNAL("addMessage"), 'Creating MOBI file...', 'info')
self.emit(QtCore.SIGNAL("progressBarTick"), 1) self.emit(QtCore.SIGNAL("progressBarTick"), 1)
try: try:
retcode = call('kindlegen -verbose "' + outputPath + '"', shell=True) self.kindlegenErrorCode = 0
if os.path.getsize(item) < 367001600:
output = Popen('kindlegen -locale en "' + item + '"', stdout=PIPE, stderr=STDOUT,
shell=True)
for line in output.stdout:
# ERROR: Generic error
if "Error(" in line:
self.kindlegenErrorCode = 1
self.kindlegenError = line
# ERROR: EPUB too big
if ":E23026:" in line:
self.kindlegenErrorCode = 23026
if self.kindlegenErrorCode > 0:
break
else:
# ERROR: EPUB too big
self.kindlegenErrorCode = 23026
except: except:
# ERROR: Unknown generic error
self.kindlegenErrorCode = 1
continue continue
if retcode == 0: if not self.conversionAlive:
self.emit(QtCore.SIGNAL("addMessage"), 'Creating MOBI file... Done!', 'info', True) for item in outputPath:
self.emit(QtCore.SIGNAL("addMessage"), 'Removing SRCS header...', 'info') if os.path.exists(item):
os.remove(outputPath) os.remove(item)
mobiPath = outputPath.replace('.epub', '.mobi') if os.path.exists(item.replace('.epub', '.mobi')):
shutil.move(mobiPath, mobiPath + '_tostrip') os.remove(item.replace('.epub', '.mobi'))
self.clean()
return
if self.kindlegenErrorCode == 0:
if len(outputPath) > 1:
self.emit(QtCore.SIGNAL("addMessage"), 'Creating MOBI file (' + str(tomeNumber) + '/'
+ str(len(outputPath)) + ')... Done!', 'info',
True)
else:
self.emit(QtCore.SIGNAL("addMessage"), 'Creating MOBI file... Done!', 'info', True)
self.emit(QtCore.SIGNAL("addMessage"), 'Cleaning MOBI file...', 'info')
os.remove(item)
mobiPath = item.replace('.epub', '.mobi')
shutil.move(mobiPath, mobiPath + '_toclean')
try: try:
kindlestrip.main((mobiPath + '_tostrip', mobiPath)) if profile in ['K345', 'KHD', 'KF', 'KFHD', 'KFHD8', 'KFHDX', 'KFHDX8', 'KFA']:
newKindle = True
else:
newKindle = False
mobisplit = kindlesplit.mobi_split(mobiPath + '_toclean', newKindle)
open(mobiPath, 'wb').write(mobisplit.getResult())
except Exception: except Exception:
self.errors = True self.errors = True
if not self.errors: if not self.errors:
os.remove(mobiPath + '_tostrip') os.remove(mobiPath + '_toclean')
self.emit(QtCore.SIGNAL("addMessage"), 'Removing SRCS header... Done!', 'info', True) self.emit(QtCore.SIGNAL("addMessage"), 'Cleaning MOBI file... Done!', 'info', True)
else: else:
shutil.move(mobiPath + '_tostrip', mobiPath) os.remove(mobiPath + '_toclean')
os.remove(mobiPath)
self.emit(QtCore.SIGNAL("addMessage"), self.emit(QtCore.SIGNAL("addMessage"),
'KindleStrip failed to remove SRCS header!', 'warning') 'KindleUnpack failed to clean MOBI file!', 'error')
self.emit(QtCore.SIGNAL("addMessage"),
'MOBI file will work correctly but it will be highly oversized.', 'warning')
else: else:
os.remove(outputPath) epubSize = (os.path.getsize(item))/1024/1024
if os.path.exists(outputPath.replace('.epub', '.mobi')): os.remove(item)
os.remove(outputPath.replace('.epub', '.mobi')) if os.path.exists(item.replace('.epub', '.mobi')):
os.remove(item.replace('.epub', '.mobi'))
self.emit(QtCore.SIGNAL("addMessage"), 'KindleGen failed to create MOBI!', 'error') self.emit(QtCore.SIGNAL("addMessage"), 'KindleGen failed to create MOBI!', 'error')
self.emit(QtCore.SIGNAL("addMessage"), 'Try converting a smaller batch.', 'error') if self.kindlegenErrorCode == 1 and self.kindlegenError:
else: self.emit(QtCore.SIGNAL("showDialog"), "KindleGen error:\n\n" + self.kindlegenError)
excess = (os.path.getsize(outputPath) - 314572800)/1024/1024 if self.kindlegenErrorCode == 23026:
os.remove(outputPath) self.emit(QtCore.SIGNAL("addMessage"), 'Created EPUB file was too big.',
self.emit(QtCore.SIGNAL("addMessage"), 'Created EPUB file is too big for KindleGen!', 'error') 'error')
self.emit(QtCore.SIGNAL("addMessage"), 'Limit exceeded by ' + str(excess) + self.emit(QtCore.SIGNAL("addMessage"), 'EPUB file: ' + str(epubSize) + 'MB.'
' MB. Try converting a smaller batch.', 'error') ' Supported size: ~300MB.', 'error')
self.emit(QtCore.SIGNAL("hideProgressBar")) self.emit(QtCore.SIGNAL("hideProgressBar"))
self.parent.needClean = True self.parent.needClean = True
self.emit(QtCore.SIGNAL("addMessage"), 'All jobs completed.', 'info') self.emit(QtCore.SIGNAL("addMessage"), '<b>All jobs completed.</b>', 'info')
self.emit(QtCore.SIGNAL("modeConvert"), True) self.emit(QtCore.SIGNAL("modeConvert"), True)
# noinspection PyBroadException # noinspection PyBroadException
class Ui_KCC(object): class Ui_KCC(object):
def selectDir(self): def selectDir(self):
# Dialog allow to select multiple directories but we can't parse that. QT Bug.
if self.needClean: if self.needClean:
self.needClean = False self.needClean = False
GUI.JobList.clear() GUI.JobList.clear()
dname = QtGui.QFileDialog.getExistingDirectory(MainWindow, 'Select directory', self.lastPath) # Dirty, dirty way but OS native QFileDialogs don't support directory multiselect
dirDialog = QtGui.QFileDialog(MainWindow, 'Select directory', self.lastPath)
dirDialog.setFileMode(dirDialog.Directory)
dirDialog.setOption(dirDialog.ShowDirsOnly, True)
dirDialog.setOption(dirDialog.DontUseNativeDialog, True)
l = dirDialog.findChild(QtGui.QListView, "listView")
t = dirDialog.findChild(QtGui.QTreeView)
if l:
l.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
if t:
t.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
if dirDialog.exec_() == 1:
dnames = dirDialog.selectedFiles()
else:
dnames = ""
# Lame UTF-8 security measure # Lame UTF-8 security measure
try: for dname in dnames:
str(dname) try:
except Exception: str(dname)
QtGui.QMessageBox.critical(MainWindow, 'KCC Error', "Path cannot contain non-ASCII characters.", except Exception:
QtGui.QMessageBox.Ok) QtGui.QMessageBox.critical(MainWindow, 'KCC Error', "Path cannot contain non-ASCII characters.",
return QtGui.QMessageBox.Ok)
if str(dname) != "": return
self.lastPath = os.path.abspath(os.path.join(str(dname), os.pardir)) if str(dname) != "":
GUI.JobList.addItem(dname) if sys.platform == 'win32':
dname = dname.replace('/', '\\')
self.lastPath = os.path.abspath(os.path.join(str(dname), os.pardir))
GUI.JobList.addItem(dname)
def selectFile(self): def selectFile(self):
if self.needClean: if self.needClean:
self.needClean = False self.needClean = False
GUI.JobList.clear() GUI.JobList.clear()
if self.UnRAR: if self.UnRAR:
fname = QtGui.QFileDialog.getOpenFileName(MainWindow, 'Select file', self.lastPath, if self.sevenza:
'*.cbz *.cbr *.zip *.rar *.pdf') fnames = QtGui.QFileDialog.getOpenFileNames(MainWindow, 'Select file', self.lastPath,
'*.cbz *.cbr *.cb7 *.zip *.rar *.7z *.pdf')
else:
fnames = QtGui.QFileDialog.getOpenFileNames(MainWindow, 'Select file', self.lastPath,
'*.cbz *.cbr *.zip *.rar *.pdf')
else: else:
fname = QtGui.QFileDialog.getOpenFileName(MainWindow, 'Select file', self.lastPath, if self.sevenza:
'*.cbz *.zip *.pdf') fnames = QtGui.QFileDialog.getOpenFileNames(MainWindow, 'Select file', self.lastPath,
'*.cbz *.cb7 *.zip *.7z *.pdf')
else:
fnames = QtGui.QFileDialog.getOpenFileNames(MainWindow, 'Select file', self.lastPath,
'*.cbz *.zip *.pdf')
# Lame UTF-8 security measure # Lame UTF-8 security measure
try: for fname in fnames:
str(fname) try:
except Exception: str(fname)
QtGui.QMessageBox.critical(MainWindow, 'KCC Error', "Path cannot contain non-ASCII characters.", except Exception:
QtGui.QMessageBox.Ok) QtGui.QMessageBox.critical(MainWindow, 'KCC Error', "Path cannot contain non-ASCII characters.",
return QtGui.QMessageBox.Ok)
if str(fname) != "": return
self.lastPath = os.path.abspath(os.path.join(str(fname), os.pardir)) if str(fname) != "":
GUI.JobList.addItem(fname) self.lastPath = os.path.abspath(os.path.join(str(fname), os.pardir))
GUI.JobList.addItem(fname)
def clearJobs(self): def clearJobs(self):
GUI.JobList.clear() GUI.JobList.clear()
@@ -268,15 +390,21 @@ class Ui_KCC(object):
GUI.OptionsExpert.setEnabled(False) GUI.OptionsExpert.setEnabled(False)
GUI.MangaBox.setEnabled(True) GUI.MangaBox.setEnabled(True)
def modeExpert(self): def modeExpert(self, KFA=False):
self.modeAdvanced() self.modeAdvanced()
self.currentMode = 3 self.currentMode = 3
MainWindow.setMinimumSize(QtCore.QSize(420, 380)) MainWindow.setMinimumSize(QtCore.QSize(420, 380))
MainWindow.setMaximumSize(QtCore.QSize(420, 380)) MainWindow.setMaximumSize(QtCore.QSize(420, 380))
MainWindow.resize(420, 380) MainWindow.resize(420, 380)
GUI.OptionsExpert.setEnabled(True) GUI.OptionsExpert.setEnabled(True)
GUI.MangaBox.setCheckState(0) if KFA:
GUI.MangaBox.setEnabled(False) GUI.ColorBox.setCheckState(2)
GUI.FormatBox.setCurrentIndex(0)
GUI.FormatBox.setEnabled(False)
else:
GUI.FormatBox.setEnabled(True)
GUI.MangaBox.setCheckState(0)
GUI.MangaBox.setEnabled(False)
def modeConvert(self, enable): def modeConvert(self, enable):
if self.currentMode != 3: if self.currentMode != 3:
@@ -286,19 +414,33 @@ class Ui_KCC(object):
GUI.ClearButton.setEnabled(enable) GUI.ClearButton.setEnabled(enable)
GUI.FileButton.setEnabled(enable) GUI.FileButton.setEnabled(enable)
GUI.DeviceBox.setEnabled(enable) GUI.DeviceBox.setEnabled(enable)
GUI.ConvertButton.setEnabled(enable)
GUI.FormatBox.setEnabled(enable) GUI.FormatBox.setEnabled(enable)
GUI.OptionsBasic.setEnabled(enable) GUI.OptionsBasic.setEnabled(enable)
GUI.OptionsAdvanced.setEnabled(enable) GUI.OptionsAdvanced.setEnabled(enable)
GUI.OptionsAdvancedGamma.setEnabled(enable) GUI.OptionsAdvancedGamma.setEnabled(enable)
GUI.OptionsExpert.setEnabled(enable) GUI.OptionsExpert.setEnabled(enable)
if enable: if enable:
self.conversionAlive = False
self.worker.sync()
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(":/Other/icons/convert.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
GUI.ConvertButton.setIcon(icon)
GUI.ConvertButton.setText('Convert')
GUI.ConvertButton.setEnabled(True)
if self.currentMode == 1: if self.currentMode == 1:
self.modeBasic() self.modeBasic()
elif self.currentMode == 2: elif self.currentMode == 2:
self.modeAdvanced() self.modeAdvanced()
elif self.currentMode == 3: elif self.currentMode == 3:
self.modeExpert() self.modeExpert()
else:
self.conversionAlive = True
self.worker.sync()
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(":/Other/icons/clear.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
GUI.ConvertButton.setIcon(icon)
GUI.ConvertButton.setText('Abort')
GUI.ConvertButton.setEnabled(True)
def changeGamma(self, value): def changeGamma(self, value):
value = float(value) value = float(value)
@@ -309,30 +451,76 @@ class Ui_KCC(object):
GUI.GammaLabel.setText('Gamma: ' + str(value)) GUI.GammaLabel.setText('Gamma: ' + str(value))
self.GammaValue = value self.GammaValue = value
def changeDevice(self, value, start=False): def toggleWebtoonBox(self, value):
if value == 11 and (start or self.currentMode != 3): if value:
GUI.NoRotateBox.setEnabled(False)
GUI.NoRotateBox.setChecked(True)
GUI.QualityBox.setEnabled(False)
GUI.QualityBox.setChecked(False)
GUI.MangaBox.setEnabled(False)
GUI.MangaBox.setChecked(False)
self.addMessage('If images are color setting <i>Gamma</i> to 1.0 is recommended.', 'info')
else:
GUI.NoRotateBox.setEnabled(True)
GUI.QualityBox.setEnabled(True)
GUI.MangaBox.setEnabled(True)
def toggleNoSplitRotate(self, value):
if value:
GUI.RotateBox.setEnabled(False)
GUI.RotateBox.setChecked(False)
else:
GUI.RotateBox.setEnabled(True)
def changeDevice(self, value):
if value == 9:
GUI.BasicModeButton.setEnabled(False) GUI.BasicModeButton.setEnabled(False)
GUI.AdvModeButton.setEnabled(False) GUI.AdvModeButton.setEnabled(False)
self.addMessage('<a href="https://github.com/ciromattia/kcc/wiki/NonKindle-devices">'
'List of supported Non-Kindle devices</a>', 'info')
self.modeExpert() self.modeExpert()
elif value == 8:
GUI.BasicModeButton.setEnabled(False)
GUI.AdvModeButton.setEnabled(False)
self.modeExpert(True)
elif self.currentMode == 3: elif self.currentMode == 3:
GUI.BasicModeButton.setEnabled(True) GUI.BasicModeButton.setEnabled(True)
GUI.AdvModeButton.setEnabled(True) GUI.AdvModeButton.setEnabled(True)
self.modeBasic() self.modeBasic()
if value in [0, 1, 5, 6, 7, 8, 9, 11]: if value in [9, 11, 12, 13, 14]:
GUI.QualityBox.setCheckState(0) GUI.QualityBox.setCheckState(0)
GUI.QualityBox.setEnabled(False) GUI.QualityBox.setEnabled(False)
else: else:
GUI.QualityBox.setEnabled(True) if not GUI.WebtoonBox.isChecked():
GUI.QualityBox.setEnabled(True)
if value in [3, 4, 5, 6, 8, 15]:
GUI.NoDitheringBox.setCheckState(0)
GUI.NoDitheringBox.setEnabled(False)
else:
GUI.NoDitheringBox.setEnabled(True)
def stripTags(self, html):
s = HTMLStripper()
s.feed(html)
return s.get_data()
def addMessage(self, message, icon=None, replace=False): def addMessage(self, message, icon=None, replace=False):
if icon: if icon:
icon = eval('self.icons.' + icon) icon = eval('self.icons.' + icon)
item = QtGui.QListWidgetItem(icon, message) item = QtGui.QListWidgetItem(icon, ' ' + self.stripTags(message))
else: else:
item = QtGui.QListWidgetItem(message) item = QtGui.QListWidgetItem(' ' + self.stripTags(message))
if replace: if replace:
GUI.JobList.takeItem(GUI.JobList.count()-1) GUI.JobList.takeItem(GUI.JobList.count()-1)
label = QtGui.QLabel(message)
label.setOpenExternalLinks(True)
if sys.platform == 'darwin':
font = QtGui.QFont()
font.setPointSize(11)
label.setFont(font)
item.setTextColor(QtGui.QColor("white"))
GUI.JobList.addItem(item) GUI.JobList.addItem(item)
GUI.JobList.setItemWidget(item, label)
GUI.JobList.scrollToBottom() GUI.JobList.scrollToBottom()
def showDialog(self, message): def showDialog(self, message):
@@ -340,7 +528,6 @@ class Ui_KCC(object):
def updateProgressbar(self, new=False, status=False): def updateProgressbar(self, new=False, status=False):
if new == "status": if new == "status":
pass
GUI.ProgressBar.setFormat(status) GUI.ProgressBar.setFormat(status)
elif new: elif new:
GUI.ProgressBar.setMaximum(new - 1) GUI.ProgressBar.setMaximum(new - 1)
@@ -350,29 +537,44 @@ class Ui_KCC(object):
GUI.ProgressBar.setValue(GUI.ProgressBar.value() + 1) GUI.ProgressBar.setValue(GUI.ProgressBar.value() + 1)
def convertStart(self): def convertStart(self):
if self.needClean: if self.conversionAlive:
self.needClean = False GUI.ConvertButton.setEnabled(False)
GUI.JobList.clear() self.addMessage('Process will be interrupted. Please wait.', 'warning')
if GUI.JobList.count() == 0: self.conversionAlive = False
self.addMessage('No files selected! Please choose files to convert.', 'error') self.worker.sync()
self.needClean = True else:
return if self.needClean:
if self.currentMode > 2 and (str(GUI.customWidth.text()) == '' or str(GUI.customHeight.text()) == ''): self.needClean = False
GUI.JobList.clear() GUI.JobList.clear()
self.addMessage('Target resolution is not set!', 'error') if GUI.JobList.count() == 0:
self.needClean = True self.addMessage('No files selected! Please choose files to convert.', 'error')
return self.needClean = True
self.worker.start() return
if self.currentMode > 2 and (str(GUI.customWidth.text()) == '' or str(GUI.customHeight.text()) == ''):
GUI.JobList.clear()
self.addMessage('Target resolution is not set!', 'error')
self.needClean = True
return
self.worker.start()
def hideProgressBar(self): def hideProgressBar(self):
GUI.ProgressBar.hide() GUI.ProgressBar.hide()
# noinspection PyUnusedLocal
def saveSettings(self, event): def saveSettings(self, event):
if self.conversionAlive:
GUI.ConvertButton.setEnabled(False)
self.addMessage('Process will be interrupted. Please wait.', 'warning')
self.conversionAlive = False
self.worker.sync()
event.ignore()
if not GUI.ConvertButton.isEnabled():
event.ignore()
self.settings.setValue('settingsVersion', __version__)
self.settings.setValue('lastPath', self.lastPath) self.settings.setValue('lastPath', self.lastPath)
self.settings.setValue('lastDevice', GUI.DeviceBox.currentIndex()) self.settings.setValue('lastDevice', GUI.DeviceBox.currentIndex())
self.settings.setValue('currentFormat', GUI.FormatBox.currentIndex()) self.settings.setValue('currentFormat', GUI.FormatBox.currentIndex())
self.settings.setValue('currentMode', self.currentMode) self.settings.setValue('currentMode', self.currentMode)
self.settings.setValue('firstStart', False)
self.settings.setValue('options', QtCore.QVariant({'MangaBox': GUI.MangaBox.checkState(), self.settings.setValue('options', QtCore.QVariant({'MangaBox': GUI.MangaBox.checkState(),
'RotateBox': GUI.RotateBox.checkState(), 'RotateBox': GUI.RotateBox.checkState(),
'QualityBox': GUI.QualityBox.checkState(), 'QualityBox': GUI.QualityBox.checkState(),
@@ -380,7 +582,7 @@ class Ui_KCC(object):
'UpscaleBox': GUI.UpscaleBox.checkState(), 'UpscaleBox': GUI.UpscaleBox.checkState(),
'NoRotateBox': GUI.NoRotateBox.checkState(), 'NoRotateBox': GUI.NoRotateBox.checkState(),
'BorderBox': GUI.BorderBox.checkState(), 'BorderBox': GUI.BorderBox.checkState(),
'StretchBox': GUI.StretchBox.checkState(), 'WebtoonBox': GUI.WebtoonBox.checkState(),
'NoDitheringBox': GUI.NoDitheringBox.checkState(), 'NoDitheringBox': GUI.NoDitheringBox.checkState(),
'ColorBox': GUI.ColorBox.checkState(), 'ColorBox': GUI.ColorBox.checkState(),
'customWidth': GUI.customWidth.text(), 'customWidth': GUI.customWidth.text(),
@@ -392,41 +594,65 @@ class Ui_KCC(object):
global GUI, MainWindow global GUI, MainWindow
GUI = UI GUI = UI
MainWindow = KCC MainWindow = KCC
profiles = sorted(ProfileData.ProfileLabels.iterkeys()) # User settings will be reverted to default ones if were created in one of the following versions
# Empty string cover all versions before this system was implemented
purgeSettingsVersions = ['']
self.icons = Icons() self.icons = Icons()
self.settings = QtCore.QSettings('KindleComicConverter', 'KindleComicConverter') self.settings = QtCore.QSettings('KindleComicConverter', 'KindleComicConverter')
self.settingsVersion = self.settings.value('settingsVersion', '', type=str)
if self.settingsVersion in purgeSettingsVersions:
QtCore.QSettings.clear(self.settings)
self.settingsVersion = self.settings.value('settingsVersion', '', type=str)
self.lastPath = self.settings.value('lastPath', '', type=str) self.lastPath = self.settings.value('lastPath', '', type=str)
self.lastDevice = self.settings.value('lastDevice', 10, type=int) self.lastDevice = self.settings.value('lastDevice', 0, type=int)
self.currentMode = self.settings.value('currentMode', 1, type=int) self.currentMode = self.settings.value('currentMode', 1, type=int)
self.currentFormat = self.settings.value('currentFormat', 0, type=int) self.currentFormat = self.settings.value('currentFormat', 0, type=int)
self.firstStart = self.settings.value('firstStart', True, type=bool)
self.options = self.settings.value('options', QtCore.QVariant({'GammaSlider': 0})) self.options = self.settings.value('options', QtCore.QVariant({'GammaSlider': 0}))
self.options = self.options.toPyObject() self.options = self.options.toPyObject()
self.worker = WorkerThread(self) self.worker = WorkerThread(self)
self.versionCheck = VersionThread(self) self.versionCheck = VersionThread(self)
self.conversionAlive = False
self.needClean = True self.needClean = True
self.GammaValue = 1.0
self.addMessage('Welcome!', 'info') self.addMessage('<b>Welcome!</b>', 'info')
self.addMessage('Remember: all options have additional informations in tooltips.', 'info') self.addMessage('<b>Remember:</b> All options have additional informations in tooltips.', 'info')
if call('kindlegen', stdout=PIPE, stderr=STDOUT, shell=True) == 0: if self.firstStart:
self.addMessage('Since you are using <b>KCC</b> for first time please see few '
'<a href="https://github.com/ciromattia/kcc#important-tips">important tips</a>.', 'info')
if call('kindlegen -locale en', stdout=PIPE, stderr=STDOUT, shell=True) == 0:
self.KindleGen = True self.KindleGen = True
formats = ['MOBI', 'EPUB', 'CBZ'] formats = ['MOBI', 'EPUB', 'CBZ']
versionCheck = Popen('kindlegen', stdout=PIPE, stderr=STDOUT, shell=True) versionCheck = Popen('kindlegen -locale en', stdout=PIPE, stderr=STDOUT, shell=True)
for line in versionCheck.stdout: for line in versionCheck.stdout:
if "Amazon kindlegen" in line: if "Amazon kindlegen" in line:
versionCheck = line.split('V')[1].split(' ')[0] versionCheck = line.split('V')[1].split(' ')[0]
if tuple(map(int, (versionCheck.split(".")))) < tuple(map(int, ('2.9'.split(".")))): if tuple(map(int, (versionCheck.split(".")))) < tuple(map(int, ('2.9'.split(".")))):
self.addMessage('Your kindlegen is outdated! Creating MOBI might fail.' self.addMessage('Your <a href="http://www.amazon.com/gp/feature.html?ie=UTF8&docId='
' Please update kindlegen from Amazon\'s website.', 'warning') '1000765211">kindlegen</a> is outdated! Creating MOBI might fail.'
' Please update <a href="http://www.amazon.com/gp/feature.html?ie=UTF8&docId='
'1000765211">kindlegen</a> from Amazon\'s website.', 'warning')
break break
else: else:
self.KindleGen = False self.KindleGen = False
formats = ['EPUB', 'CBZ'] formats = ['EPUB', 'CBZ']
self.addMessage('Cannot find kindlegen in PATH! MOBI creation will be disabled.', 'warning') self.addMessage('Cannot find <a href="http://www.amazon.com/gp/feature.html?ie=UTF8&docId='
if call('unrar', stdout=PIPE, stderr=STDOUT, shell=True) == 0: '1000765211">kindlegen</a> in PATH! MOBI creation will be disabled.', 'warning')
rarExitCode = call('unrar', stdout=PIPE, stderr=STDOUT, shell=True)
if rarExitCode == 0 or rarExitCode == 7:
self.UnRAR = True self.UnRAR = True
else: else:
self.UnRAR = False self.UnRAR = False
self.addMessage('Cannot find UnRAR! Processing of CBR/RAR files will be disabled.', 'warning') self.addMessage('Cannot find <a href="http://www.rarlab.com/rar_add.htm">UnRAR</a>!'
' Processing of CBR/RAR files will be disabled.', 'warning')
sevenzaExitCode = call('7za', stdout=PIPE, stderr=STDOUT, shell=True)
if sevenzaExitCode == 0 or sevenzaExitCode == 7:
self.sevenza = True
else:
self.sevenza = False
self.addMessage('Cannot find <a href="http://www.7-zip.org/download.html">7za</a>!'
' Processing of CB7/7Z files will be disabled.', 'warning')
GUI.BasicModeButton.clicked.connect(self.modeBasic) GUI.BasicModeButton.clicked.connect(self.modeBasic)
GUI.AdvModeButton.clicked.connect(self.modeAdvanced) GUI.AdvModeButton.clicked.connect(self.modeAdvanced)
@@ -435,6 +661,8 @@ class Ui_KCC(object):
GUI.FileButton.clicked.connect(self.selectFile) GUI.FileButton.clicked.connect(self.selectFile)
GUI.ConvertButton.clicked.connect(self.convertStart) GUI.ConvertButton.clicked.connect(self.convertStart)
GUI.GammaSlider.valueChanged.connect(self.changeGamma) GUI.GammaSlider.valueChanged.connect(self.changeGamma)
GUI.NoRotateBox.stateChanged.connect(self.toggleNoSplitRotate)
GUI.WebtoonBox.stateChanged.connect(self.toggleWebtoonBox)
GUI.DeviceBox.activated.connect(self.changeDevice) GUI.DeviceBox.activated.connect(self.changeDevice)
KCC.connect(self.worker, QtCore.SIGNAL("progressBarTick"), self.updateProgressbar) KCC.connect(self.worker, QtCore.SIGNAL("progressBarTick"), self.updateProgressbar)
KCC.connect(self.worker, QtCore.SIGNAL("modeConvert"), self.modeConvert) KCC.connect(self.worker, QtCore.SIGNAL("modeConvert"), self.modeConvert)
@@ -444,12 +672,18 @@ class Ui_KCC(object):
KCC.connect(self.versionCheck, QtCore.SIGNAL("addMessage"), self.addMessage) KCC.connect(self.versionCheck, QtCore.SIGNAL("addMessage"), self.addMessage)
KCC.closeEvent = self.saveSettings KCC.closeEvent = self.saveSettings
for profile in profiles: for profile in ProfileData.ProfileLabelsGUI:
if profile != "Other": if profile == "Other":
GUI.DeviceBox.addItem(self.icons.deviceKindle, profile)
else:
GUI.DeviceBox.addItem(self.icons.deviceOther, profile) GUI.DeviceBox.addItem(self.icons.deviceOther, profile)
GUI.DeviceBox.setCurrentIndex(self.lastDevice) elif profile == "Separator":
GUI.DeviceBox.insertSeparator(GUI.DeviceBox.count()+1)
else:
GUI.DeviceBox.addItem(self.icons.deviceKindle, profile)
if self.lastDevice > GUI.DeviceBox.count():
GUI.DeviceBox.setCurrentIndex(0)
self.lastDevice = 0
else:
GUI.DeviceBox.setCurrentIndex(self.lastDevice)
for f in formats: for f in formats:
GUI.FormatBox.addItem(eval('self.icons.' + f + 'Format'), f) GUI.FormatBox.addItem(eval('self.icons.' + f + 'Format'), f)
@@ -477,4 +711,5 @@ class Ui_KCC(object):
self.modeExpert() self.modeExpert()
self.versionCheck.start() self.versionCheck.start()
self.hideProgressBar() self.hideProgressBar()
self.changeDevice(self.lastDevice, True) self.changeDevice(self.lastDevice)
self.worker.sync()

View File

@@ -2,8 +2,8 @@
# Form implementation generated from reading ui file 'KCC.ui' # Form implementation generated from reading ui file 'KCC.ui'
# #
# Created: Fri Jun 21 18:23:19 2013 # Created: Wed Sep 18 12:12:45 2013
# by: PyQt4 UI code generator 4.10.1 # 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!
@@ -47,6 +47,7 @@ class Ui_KCC(object):
self.OptionsAdvanced.setFont(font) self.OptionsAdvanced.setFont(font)
self.OptionsAdvanced.setObjectName(_fromUtf8("OptionsAdvanced")) self.OptionsAdvanced.setObjectName(_fromUtf8("OptionsAdvanced"))
self.gridLayout = QtGui.QGridLayout(self.OptionsAdvanced) self.gridLayout = QtGui.QGridLayout(self.OptionsAdvanced)
self.gridLayout.setContentsMargins(9, -1, -1, -1)
self.gridLayout.setObjectName(_fromUtf8("gridLayout")) self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
self.ProcessingBox = QtGui.QCheckBox(self.OptionsAdvanced) self.ProcessingBox = QtGui.QCheckBox(self.OptionsAdvanced)
self.ProcessingBox.setFocusPolicy(QtCore.Qt.NoFocus) self.ProcessingBox.setFocusPolicy(QtCore.Qt.NoFocus)
@@ -54,18 +55,20 @@ class Ui_KCC(object):
self.gridLayout.addWidget(self.ProcessingBox, 1, 0, 1, 1) self.gridLayout.addWidget(self.ProcessingBox, 1, 0, 1, 1)
self.UpscaleBox = QtGui.QCheckBox(self.OptionsAdvanced) self.UpscaleBox = QtGui.QCheckBox(self.OptionsAdvanced)
self.UpscaleBox.setFocusPolicy(QtCore.Qt.NoFocus) self.UpscaleBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.UpscaleBox.setTristate(True)
self.UpscaleBox.setObjectName(_fromUtf8("UpscaleBox")) self.UpscaleBox.setObjectName(_fromUtf8("UpscaleBox"))
self.gridLayout.addWidget(self.UpscaleBox, 1, 1, 1, 1) self.gridLayout.addWidget(self.UpscaleBox, 1, 1, 1, 1)
self.StretchBox = QtGui.QCheckBox(self.OptionsAdvanced) self.WebtoonBox = QtGui.QCheckBox(self.OptionsAdvanced)
self.StretchBox.setFocusPolicy(QtCore.Qt.NoFocus) self.WebtoonBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.StretchBox.setObjectName(_fromUtf8("StretchBox")) self.WebtoonBox.setObjectName(_fromUtf8("WebtoonBox"))
self.gridLayout.addWidget(self.StretchBox, 3, 1, 1, 1) self.gridLayout.addWidget(self.WebtoonBox, 3, 1, 1, 1)
self.NoDitheringBox = QtGui.QCheckBox(self.OptionsAdvanced) self.NoDitheringBox = QtGui.QCheckBox(self.OptionsAdvanced)
self.NoDitheringBox.setFocusPolicy(QtCore.Qt.NoFocus) self.NoDitheringBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.NoDitheringBox.setObjectName(_fromUtf8("NoDitheringBox")) self.NoDitheringBox.setObjectName(_fromUtf8("NoDitheringBox"))
self.gridLayout.addWidget(self.NoDitheringBox, 3, 2, 1, 1) self.gridLayout.addWidget(self.NoDitheringBox, 3, 2, 1, 1)
self.BorderBox = QtGui.QCheckBox(self.OptionsAdvanced) self.BorderBox = QtGui.QCheckBox(self.OptionsAdvanced)
self.BorderBox.setFocusPolicy(QtCore.Qt.NoFocus) self.BorderBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.BorderBox.setTristate(True)
self.BorderBox.setObjectName(_fromUtf8("BorderBox")) self.BorderBox.setObjectName(_fromUtf8("BorderBox"))
self.gridLayout.addWidget(self.BorderBox, 3, 0, 1, 1) self.gridLayout.addWidget(self.BorderBox, 3, 0, 1, 1)
self.NoRotateBox = QtGui.QCheckBox(self.OptionsAdvanced) self.NoRotateBox = QtGui.QCheckBox(self.OptionsAdvanced)
@@ -262,14 +265,14 @@ class Ui_KCC(object):
KCC.setWindowTitle(_translate("KCC", "Kindle Comic Converter", None)) KCC.setWindowTitle(_translate("KCC", "Kindle Comic Converter", None))
self.ProcessingBox.setToolTip(_translate("KCC", "Disable image optimizations.", None)) self.ProcessingBox.setToolTip(_translate("KCC", "Disable image optimizations.", None))
self.ProcessingBox.setText(_translate("KCC", "No optimisation", None)) self.ProcessingBox.setText(_translate("KCC", "No optimisation", None))
self.UpscaleBox.setToolTip(_translate("KCC", "<html><head/><body><p>Enable image upscaling.<br/>Aspect ratio will be preserved.</p></body></html>", None)) self.UpscaleBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Nothing<br/></span>Images smaller than device resolution will not be resized.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Stretching<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be not preserved.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Upscaling<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be preserved.</p></body></html>", None))
self.UpscaleBox.setText(_translate("KCC", "Upscale images", None)) self.UpscaleBox.setText(_translate("KCC", "Stretch/Upscale", None))
self.StretchBox.setToolTip(_translate("KCC", "<html><head/><body><p>Enable image stretching.<br/>Aspect ratio will be not preserved.</p></body></html>", None)) self.WebtoonBox.setToolTip(_translate("KCC", "<html><head/><body><p>Enable auto-splitting of webtoons like <span style=\" font-style:italic;\">Tower of God</span> or <span style=\" font-style:italic;\">Noblesse</span>.<br/>Pages with a low width, high height and vertical panel flow.</p></body></html>", None))
self.StretchBox.setText(_translate("KCC", "Stretch images", None)) self.WebtoonBox.setText(_translate("KCC", "Webtoon mode", None))
self.NoDitheringBox.setToolTip(_translate("KCC", "<html><head/><body><p>Create PNG files instead JPEG.<br/><span style=\" font-weight:600;\">Only for non-Kindle devices!</span></p></body></html>", None)) self.NoDitheringBox.setToolTip(_translate("KCC", "<html><head/><body><p>Create PNG files instead JPEG.</p></body></html>", None))
self.NoDitheringBox.setText(_translate("KCC", "PNG output", None)) self.NoDitheringBox.setText(_translate("KCC", "PNG output", None))
self.BorderBox.setToolTip(_translate("KCC", "Fill space around images with black color.", None)) self.BorderBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Autodetection<br/></span>Color of margins fill will be detected automatically.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - White<br/></span>Margins will be filled with white color.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Black<br/></span>Margins will be filled with black color.</p></body></html>", None))
self.BorderBox.setText(_translate("KCC", "Black borders", None)) self.BorderBox.setText(_translate("KCC", "W/B margins", None))
self.NoRotateBox.setToolTip(_translate("KCC", "<html><head/><body><p>Disable splitting and rotation.</p></body></html>", None)) self.NoRotateBox.setToolTip(_translate("KCC", "<html><head/><body><p>Disable splitting and rotation.</p></body></html>", None))
self.NoRotateBox.setText(_translate("KCC", "No split/rotate", None)) self.NoRotateBox.setText(_translate("KCC", "No split/rotate", None))
self.DeviceBox.setToolTip(_translate("KCC", "Target device.", None)) self.DeviceBox.setToolTip(_translate("KCC", "Target device.", None))

383
kcc/KCC_ui_linux.py Normal file
View File

@@ -0,0 +1,383 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'KCC-Linux.ui'
#
# Created: Fri Sep 20 10:25:30 2013
# by: PyQt4 UI code generator 4.10
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s
try:
_encoding = QtGui.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)
class Ui_KCC(object):
def setupUi(self, KCC):
KCC.setObjectName(_fromUtf8("KCC"))
KCC.resize(420, 380)
KCC.setMinimumSize(QtCore.QSize(420, 380))
KCC.setMaximumSize(QtCore.QSize(420, 380))
font = QtGui.QFont()
font.setPointSize(9)
KCC.setFont(font)
KCC.setFocusPolicy(QtCore.Qt.NoFocus)
icon = QtGui.QIcon()
icon.addPixmap(QtGui.QPixmap(_fromUtf8(":/Icon/icons/comic2ebook.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
KCC.setWindowIcon(icon)
KCC.setLocale(QtCore.QLocale(QtCore.QLocale.C, QtCore.QLocale.AnyCountry))
self.Form = QtGui.QWidget(KCC)
self.Form.setObjectName(_fromUtf8("Form"))
self.OptionsAdvanced = QtGui.QFrame(self.Form)
self.OptionsAdvanced.setEnabled(True)
self.OptionsAdvanced.setGeometry(QtCore.QRect(1, 254, 421, 61))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setPointSize(9)
self.OptionsAdvanced.setFont(font)
self.OptionsAdvanced.setObjectName(_fromUtf8("OptionsAdvanced"))
self.gridLayout = QtGui.QGridLayout(self.OptionsAdvanced)
self.gridLayout.setContentsMargins(9, -1, -1, -1)
self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
self.ProcessingBox = QtGui.QCheckBox(self.OptionsAdvanced)
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
self.ProcessingBox.setFont(font)
self.ProcessingBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.ProcessingBox.setObjectName(_fromUtf8("ProcessingBox"))
self.gridLayout.addWidget(self.ProcessingBox, 1, 0, 1, 1)
self.UpscaleBox = QtGui.QCheckBox(self.OptionsAdvanced)
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
self.UpscaleBox.setFont(font)
self.UpscaleBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.UpscaleBox.setTristate(True)
self.UpscaleBox.setObjectName(_fromUtf8("UpscaleBox"))
self.gridLayout.addWidget(self.UpscaleBox, 1, 1, 1, 1)
self.WebtoonBox = QtGui.QCheckBox(self.OptionsAdvanced)
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
self.WebtoonBox.setFont(font)
self.WebtoonBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.WebtoonBox.setObjectName(_fromUtf8("WebtoonBox"))
self.gridLayout.addWidget(self.WebtoonBox, 3, 1, 1, 1)
self.NoDitheringBox = QtGui.QCheckBox(self.OptionsAdvanced)
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
self.NoDitheringBox.setFont(font)
self.NoDitheringBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.NoDitheringBox.setObjectName(_fromUtf8("NoDitheringBox"))
self.gridLayout.addWidget(self.NoDitheringBox, 3, 2, 1, 1)
self.BorderBox = QtGui.QCheckBox(self.OptionsAdvanced)
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
self.BorderBox.setFont(font)
self.BorderBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.BorderBox.setTristate(True)
self.BorderBox.setObjectName(_fromUtf8("BorderBox"))
self.gridLayout.addWidget(self.BorderBox, 3, 0, 1, 1)
self.NoRotateBox = QtGui.QCheckBox(self.OptionsAdvanced)
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
self.NoRotateBox.setFont(font)
self.NoRotateBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.NoRotateBox.setObjectName(_fromUtf8("NoRotateBox"))
self.gridLayout.addWidget(self.NoRotateBox, 1, 2, 1, 1)
self.DeviceBox = QtGui.QComboBox(self.Form)
self.DeviceBox.setGeometry(QtCore.QRect(10, 200, 141, 31))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setPointSize(8)
self.DeviceBox.setFont(font)
self.DeviceBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.DeviceBox.setObjectName(_fromUtf8("DeviceBox"))
self.FormatBox = QtGui.QComboBox(self.Form)
self.FormatBox.setGeometry(QtCore.QRect(260, 200, 151, 31))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setPointSize(8)
self.FormatBox.setFont(font)
self.FormatBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.FormatBox.setObjectName(_fromUtf8("FormatBox"))
self.ConvertButton = QtGui.QPushButton(self.Form)
self.ConvertButton.setGeometry(QtCore.QRect(160, 200, 91, 32))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setPointSize(9)
font.setBold(True)
font.setWeight(75)
self.ConvertButton.setFont(font)
self.ConvertButton.setFocusPolicy(QtCore.Qt.NoFocus)
icon1 = QtGui.QIcon()
icon1.addPixmap(QtGui.QPixmap(_fromUtf8(":/Other/icons/convert.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.ConvertButton.setIcon(icon1)
self.ConvertButton.setObjectName(_fromUtf8("ConvertButton"))
self.DirectoryButton = QtGui.QPushButton(self.Form)
self.DirectoryButton.setGeometry(QtCore.QRect(10, 160, 141, 32))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setPointSize(8)
self.DirectoryButton.setFont(font)
self.DirectoryButton.setFocusPolicy(QtCore.Qt.NoFocus)
icon2 = QtGui.QIcon()
icon2.addPixmap(QtGui.QPixmap(_fromUtf8(":/Other/icons/folder_new.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.DirectoryButton.setIcon(icon2)
self.DirectoryButton.setObjectName(_fromUtf8("DirectoryButton"))
self.FileButton = QtGui.QPushButton(self.Form)
self.FileButton.setGeometry(QtCore.QRect(260, 160, 151, 32))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setPointSize(8)
self.FileButton.setFont(font)
self.FileButton.setFocusPolicy(QtCore.Qt.NoFocus)
icon3 = QtGui.QIcon()
icon3.addPixmap(QtGui.QPixmap(_fromUtf8(":/Other/icons/document_new.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.FileButton.setIcon(icon3)
self.FileButton.setObjectName(_fromUtf8("FileButton"))
self.ClearButton = QtGui.QPushButton(self.Form)
self.ClearButton.setGeometry(QtCore.QRect(160, 160, 91, 32))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setPointSize(8)
self.ClearButton.setFont(font)
self.ClearButton.setFocusPolicy(QtCore.Qt.NoFocus)
icon4 = QtGui.QIcon()
icon4.addPixmap(QtGui.QPixmap(_fromUtf8(":/Other/icons/clear.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.ClearButton.setIcon(icon4)
self.ClearButton.setObjectName(_fromUtf8("ClearButton"))
self.OptionsBasic = QtGui.QFrame(self.Form)
self.OptionsBasic.setGeometry(QtCore.QRect(1, 230, 421, 41))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setPointSize(9)
self.OptionsBasic.setFont(font)
self.OptionsBasic.setObjectName(_fromUtf8("OptionsBasic"))
self.MangaBox = QtGui.QCheckBox(self.OptionsBasic)
self.MangaBox.setGeometry(QtCore.QRect(9, 10, 130, 18))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
self.MangaBox.setFont(font)
self.MangaBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.MangaBox.setObjectName(_fromUtf8("MangaBox"))
self.QualityBox = QtGui.QCheckBox(self.OptionsBasic)
self.QualityBox.setGeometry(QtCore.QRect(282, 10, 135, 18))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
self.QualityBox.setFont(font)
self.QualityBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.QualityBox.setTristate(True)
self.QualityBox.setObjectName(_fromUtf8("QualityBox"))
self.RotateBox = QtGui.QCheckBox(self.OptionsBasic)
self.RotateBox.setGeometry(QtCore.QRect(145, 10, 130, 18))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
self.RotateBox.setFont(font)
self.RotateBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.RotateBox.setObjectName(_fromUtf8("RotateBox"))
self.JobList = QtGui.QListWidget(self.Form)
self.JobList.setGeometry(QtCore.QRect(10, 50, 401, 101))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setPointSize(8)
font.setItalic(False)
self.JobList.setFont(font)
self.JobList.setFocusPolicy(QtCore.Qt.NoFocus)
self.JobList.setProperty("showDropIndicator", False)
self.JobList.setSelectionMode(QtGui.QAbstractItemView.NoSelection)
self.JobList.setIconSize(QtCore.QSize(18, 18))
self.JobList.setObjectName(_fromUtf8("JobList"))
self.BasicModeButton = QtGui.QPushButton(self.Form)
self.BasicModeButton.setGeometry(QtCore.QRect(10, 10, 195, 32))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setPointSize(9)
self.BasicModeButton.setFont(font)
self.BasicModeButton.setFocusPolicy(QtCore.Qt.NoFocus)
self.BasicModeButton.setObjectName(_fromUtf8("BasicModeButton"))
self.AdvModeButton = QtGui.QPushButton(self.Form)
self.AdvModeButton.setGeometry(QtCore.QRect(217, 10, 195, 32))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setPointSize(9)
self.AdvModeButton.setFont(font)
self.AdvModeButton.setFocusPolicy(QtCore.Qt.NoFocus)
self.AdvModeButton.setObjectName(_fromUtf8("AdvModeButton"))
self.OptionsAdvancedGamma = QtGui.QFrame(self.Form)
self.OptionsAdvancedGamma.setEnabled(True)
self.OptionsAdvancedGamma.setGeometry(QtCore.QRect(10, 305, 401, 41))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setPointSize(9)
self.OptionsAdvancedGamma.setFont(font)
self.OptionsAdvancedGamma.setObjectName(_fromUtf8("OptionsAdvancedGamma"))
self.GammaLabel = QtGui.QLabel(self.OptionsAdvancedGamma)
self.GammaLabel.setGeometry(QtCore.QRect(15, 0, 100, 40))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
self.GammaLabel.setFont(font)
self.GammaLabel.setObjectName(_fromUtf8("GammaLabel"))
self.GammaSlider = QtGui.QSlider(self.OptionsAdvancedGamma)
self.GammaSlider.setGeometry(QtCore.QRect(110, 10, 275, 22))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
self.GammaSlider.setFont(font)
self.GammaSlider.setFocusPolicy(QtCore.Qt.ClickFocus)
self.GammaSlider.setMaximum(500)
self.GammaSlider.setSingleStep(5)
self.GammaSlider.setOrientation(QtCore.Qt.Horizontal)
self.GammaSlider.setObjectName(_fromUtf8("GammaSlider"))
self.ProgressBar = QtGui.QProgressBar(self.Form)
self.ProgressBar.setGeometry(QtCore.QRect(10, 10, 401, 31))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setPointSize(10)
font.setBold(True)
font.setWeight(75)
self.ProgressBar.setFont(font)
self.ProgressBar.setProperty("value", 0)
self.ProgressBar.setAlignment(QtCore.Qt.AlignJustify|QtCore.Qt.AlignVCenter)
self.ProgressBar.setFormat(_fromUtf8(""))
self.ProgressBar.setObjectName(_fromUtf8("ProgressBar"))
self.OptionsExpert = QtGui.QFrame(self.Form)
self.OptionsExpert.setGeometry(QtCore.QRect(1, 337, 421, 41))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
font.setPointSize(9)
self.OptionsExpert.setFont(font)
self.OptionsExpert.setObjectName(_fromUtf8("OptionsExpert"))
self.ColorBox = QtGui.QCheckBox(self.OptionsExpert)
self.ColorBox.setGeometry(QtCore.QRect(9, 11, 130, 18))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
self.ColorBox.setFont(font)
self.ColorBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.ColorBox.setObjectName(_fromUtf8("ColorBox"))
self.OptionsExpertInternal = QtGui.QFrame(self.OptionsExpert)
self.OptionsExpertInternal.setGeometry(QtCore.QRect(105, 0, 295, 40))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
self.OptionsExpertInternal.setFont(font)
self.OptionsExpertInternal.setObjectName(_fromUtf8("OptionsExpertInternal"))
self.gridLayout_2 = QtGui.QGridLayout(self.OptionsExpertInternal)
self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2"))
self.wLabel = QtGui.QLabel(self.OptionsExpertInternal)
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
self.wLabel.setFont(font)
self.wLabel.setObjectName(_fromUtf8("wLabel"))
self.gridLayout_2.addWidget(self.wLabel, 0, 0, 1, 1)
self.customWidth = QtGui.QLineEdit(self.OptionsExpertInternal)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.customWidth.sizePolicy().hasHeightForWidth())
self.customWidth.setSizePolicy(sizePolicy)
self.customWidth.setMaximumSize(QtCore.QSize(40, 16777215))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
self.customWidth.setFont(font)
self.customWidth.setFocusPolicy(QtCore.Qt.ClickFocus)
self.customWidth.setAcceptDrops(False)
self.customWidth.setMaxLength(4)
self.customWidth.setObjectName(_fromUtf8("customWidth"))
self.gridLayout_2.addWidget(self.customWidth, 0, 1, 1, 1)
self.hLabel = QtGui.QLabel(self.OptionsExpertInternal)
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
self.hLabel.setFont(font)
self.hLabel.setObjectName(_fromUtf8("hLabel"))
self.gridLayout_2.addWidget(self.hLabel, 0, 2, 1, 1)
self.customHeight = QtGui.QLineEdit(self.OptionsExpertInternal)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.customHeight.sizePolicy().hasHeightForWidth())
self.customHeight.setSizePolicy(sizePolicy)
self.customHeight.setMaximumSize(QtCore.QSize(40, 16777215))
font = QtGui.QFont()
font.setFamily(_fromUtf8("DejaVu Sans"))
self.customHeight.setFont(font)
self.customHeight.setFocusPolicy(QtCore.Qt.ClickFocus)
self.customHeight.setAcceptDrops(False)
self.customHeight.setMaxLength(4)
self.customHeight.setObjectName(_fromUtf8("customHeight"))
self.gridLayout_2.addWidget(self.customHeight, 0, 3, 1, 1)
KCC.setCentralWidget(self.Form)
self.ActionBasic = QtGui.QAction(KCC)
self.ActionBasic.setCheckable(True)
self.ActionBasic.setChecked(False)
font = QtGui.QFont()
self.ActionBasic.setFont(font)
self.ActionBasic.setObjectName(_fromUtf8("ActionBasic"))
self.ActionAdvanced = QtGui.QAction(KCC)
self.ActionAdvanced.setCheckable(True)
self.ActionAdvanced.setObjectName(_fromUtf8("ActionAdvanced"))
self.retranslateUi(KCC)
QtCore.QMetaObject.connectSlotsByName(KCC)
KCC.setTabOrder(self.DirectoryButton, self.FileButton)
KCC.setTabOrder(self.FileButton, self.ConvertButton)
KCC.setTabOrder(self.ConvertButton, self.ClearButton)
def retranslateUi(self, KCC):
KCC.setWindowTitle(_translate("KCC", "Kindle Comic Converter", None))
self.ProcessingBox.setToolTip(_translate("KCC", "Disable image optimizations.", None))
self.ProcessingBox.setText(_translate("KCC", "No optimisation", None))
self.UpscaleBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Nothing<br/></span>Images smaller than device resolution will not be resized.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - Stretching<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be not preserved.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Upscaling<br/></span>Images smaller than device resolution will be resized. Aspect ratio will be preserved.</p></body></html>", None))
self.UpscaleBox.setText(_translate("KCC", "Stretch/Upscale", None))
self.WebtoonBox.setToolTip(_translate("KCC", "<html><head/><body><p>Enable auto-splitting of webtoons like <span style=\" font-style:italic;\">Tower of God</span> or <span style=\" font-style:italic;\">Noblesse</span>.<br/>Pages with a low width, high height and vertical panel flow.</p></body></html>", None))
self.WebtoonBox.setText(_translate("KCC", "Webtoon mode", None))
self.NoDitheringBox.setToolTip(_translate("KCC", "<html><head/><body><p>Create PNG files instead JPEG.</p></body></html>", None))
self.NoDitheringBox.setText(_translate("KCC", "PNG output", None))
self.BorderBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-weight:600; text-decoration: underline;\">Unchecked - Autodetection<br/></span>Color of margins fill will be detected automatically.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Indeterminate - White<br/></span>Margins will be filled with white color.</p><p><span style=\" font-weight:600; text-decoration: underline;\">Checked - Black<br/></span>Margins will be filled with black color.</p></body></html>", None))
self.BorderBox.setText(_translate("KCC", "W/B margins", None))
self.NoRotateBox.setToolTip(_translate("KCC", "<html><head/><body><p>Disable splitting and rotation.</p></body></html>", None))
self.NoRotateBox.setText(_translate("KCC", "No split/rotate", None))
self.DeviceBox.setToolTip(_translate("KCC", "Target device.", None))
self.FormatBox.setToolTip(_translate("KCC", "Output format.", None))
self.ConvertButton.setText(_translate("KCC", "Convert", None))
self.DirectoryButton.setText(_translate("KCC", "Add directory", None))
self.FileButton.setText(_translate("KCC", "Add file", None))
self.ClearButton.setText(_translate("KCC", "Clear list", None))
self.MangaBox.setToolTip(_translate("KCC", "Enable right-to-left reading.", None))
self.MangaBox.setText(_translate("KCC", "Manga mode", None))
self.QualityBox.setToolTip(_translate("KCC", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n"
"</style></head><body style=\" font-family:\'Sans\'; font-size:9pt; font-weight:400; font-style:normal;\">\n"
"<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-weight:600; text-decoration: underline;\">Unchecked - Normal quality mode<br /></span><span style=\" font-family:\'MS Shell Dlg 2\'; font-style:italic;\">Use it when Panel View support is not needed.</span><span style=\" font-family:\'MS Shell Dlg 2\'; font-weight:600; text-decoration: underline;\"><br /></span><span style=\" font-family:\'MS Shell Dlg 2\';\">- Maximum quality when zoom is not enabled.<br />- Poor quality when zoom is enabled.<br />- Lowest file size.</span></p>\n"
"<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-weight:600; text-decoration: underline;\">Indeterminate - High quality mode<br /></span><span style=\" font-family:\'MS Shell Dlg 2\'; font-style:italic;\">Not zoomed image </span><span style=\" font-family:\'MS Shell Dlg 2\'; font-weight:600; font-style:italic;\">might </span><span style=\" font-family:\'MS Shell Dlg 2\'; font-style:italic;\">be a little blurry.</span><span style=\" font-family:\'MS Shell Dlg 2\'; font-weight:600; text-decoration: underline;\"><br /></span><span style=\" font-family:\'MS Shell Dlg 2\';\">- Medium/High quality when zoom is not enabled.<br />- Maximum quality when zoom is enabled.</span></p>\n"
"<p style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-weight:600; text-decoration: underline;\">Checked - Ultra quality mode<br /></span><span style=\" font-family:\'MS Shell Dlg 2\'; font-style:italic;\">Maximum possible quality.</span><span style=\" font-family:\'MS Shell Dlg 2\'; font-weight:600; text-decoration: underline;\"><br /></span><span style=\" font-family:\'MS Shell Dlg 2\';\">- Maximum quality when zoom is not enabled.<br />- Maximum quality when zoom is enabled.<br />- Very high file size.</span></p></body></html>", None))
self.QualityBox.setText(_translate("KCC", "High/Ultra quality", None))
self.RotateBox.setToolTip(_translate("KCC", "<html><head/><body><p>Disable page spliting.<br/>They will be rotated instead.</p></body></html>", None))
self.RotateBox.setText(_translate("KCC", "Horizontal mode", None))
self.BasicModeButton.setText(_translate("KCC", "Basic", None))
self.AdvModeButton.setText(_translate("KCC", "Advanced", None))
self.GammaLabel.setToolTip(_translate("KCC", "<html><head/><body><p>When converting color images setting this option to 1.0 <span style=\" font-weight:600;\">might</span> improve readability.</p></body></html>", None))
self.GammaLabel.setText(_translate("KCC", "Gamma: Auto", None))
self.GammaSlider.setToolTip(_translate("KCC", "<html><head/><body><p>When converting color images setting this option to 1.0 <span style=\" font-weight:600;\">might</span> improve readability.</p></body></html>", None))
self.ColorBox.setToolTip(_translate("KCC", "Do not convert images to grayscale.", None))
self.ColorBox.setText(_translate("KCC", "Color mode", None))
self.wLabel.setToolTip(_translate("KCC", "Resolution of target device.", None))
self.wLabel.setText(_translate("KCC", "Custom width: ", None))
self.customWidth.setToolTip(_translate("KCC", "Resolution of target device.", None))
self.customWidth.setInputMask(_translate("KCC", "0000; ", None))
self.hLabel.setToolTip(_translate("KCC", "Resolution of target device.", None))
self.hLabel.setText(_translate("KCC", "Custom height: ", None))
self.customHeight.setToolTip(_translate("KCC", "Resolution of target device.", None))
self.customHeight.setInputMask(_translate("KCC", "0000; ", None))
self.ActionBasic.setText(_translate("KCC", "Basic", None))
self.ActionAdvanced.setText(_translate("KCC", "Advanced", None))
import KCC_rc

View File

@@ -2,8 +2,8 @@
# Form implementation generated from reading ui file 'KCC-OSX.ui' # Form implementation generated from reading ui file 'KCC-OSX.ui'
# #
# Created: Fri Jun 21 18:23:35 2013 # Created: Fri Sep 20 10:57:31 2013
# by: PyQt4 UI code generator 4.10.1 # by: PyQt4 UI code generator 4.10.2
# #
# WARNING! All changes made in this file will be lost! # WARNING! All changes made in this file will be lost!
@@ -41,8 +41,9 @@ class Ui_KCC(object):
self.Form.setObjectName(_fromUtf8("Form")) self.Form.setObjectName(_fromUtf8("Form"))
self.OptionsAdvanced = QtGui.QFrame(self.Form) self.OptionsAdvanced = QtGui.QFrame(self.Form)
self.OptionsAdvanced.setEnabled(True) self.OptionsAdvanced.setEnabled(True)
self.OptionsAdvanced.setGeometry(QtCore.QRect(9, 253, 421, 61)) self.OptionsAdvanced.setGeometry(QtCore.QRect(4, 253, 421, 61))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(9) font.setPointSize(9)
self.OptionsAdvanced.setFont(font) self.OptionsAdvanced.setFont(font)
self.OptionsAdvanced.setObjectName(_fromUtf8("OptionsAdvanced")) self.OptionsAdvanced.setObjectName(_fromUtf8("OptionsAdvanced"))
@@ -50,42 +51,50 @@ class Ui_KCC(object):
self.gridLayout.setObjectName(_fromUtf8("gridLayout")) self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
self.ProcessingBox = QtGui.QCheckBox(self.OptionsAdvanced) self.ProcessingBox = QtGui.QCheckBox(self.OptionsAdvanced)
font = QtGui.QFont() font = QtGui.QFont()
font.setPointSize(11) font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(12)
self.ProcessingBox.setFont(font) self.ProcessingBox.setFont(font)
self.ProcessingBox.setFocusPolicy(QtCore.Qt.NoFocus) self.ProcessingBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.ProcessingBox.setObjectName(_fromUtf8("ProcessingBox")) self.ProcessingBox.setObjectName(_fromUtf8("ProcessingBox"))
self.gridLayout.addWidget(self.ProcessingBox, 1, 0, 1, 1) self.gridLayout.addWidget(self.ProcessingBox, 1, 0, 1, 1)
self.UpscaleBox = QtGui.QCheckBox(self.OptionsAdvanced) self.UpscaleBox = QtGui.QCheckBox(self.OptionsAdvanced)
font = QtGui.QFont() font = QtGui.QFont()
font.setPointSize(11) font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(12)
self.UpscaleBox.setFont(font) self.UpscaleBox.setFont(font)
self.UpscaleBox.setFocusPolicy(QtCore.Qt.NoFocus) self.UpscaleBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.UpscaleBox.setTristate(True)
self.UpscaleBox.setObjectName(_fromUtf8("UpscaleBox")) self.UpscaleBox.setObjectName(_fromUtf8("UpscaleBox"))
self.gridLayout.addWidget(self.UpscaleBox, 1, 1, 1, 1) self.gridLayout.addWidget(self.UpscaleBox, 1, 1, 1, 1)
self.StretchBox = QtGui.QCheckBox(self.OptionsAdvanced) self.WebtoonBox = QtGui.QCheckBox(self.OptionsAdvanced)
font = QtGui.QFont() font = QtGui.QFont()
font.setPointSize(11) font.setFamily(_fromUtf8("Lucida Grande"))
self.StretchBox.setFont(font) font.setPointSize(12)
self.StretchBox.setFocusPolicy(QtCore.Qt.NoFocus) self.WebtoonBox.setFont(font)
self.StretchBox.setObjectName(_fromUtf8("StretchBox")) self.WebtoonBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.gridLayout.addWidget(self.StretchBox, 3, 1, 1, 1) self.WebtoonBox.setObjectName(_fromUtf8("WebtoonBox"))
self.gridLayout.addWidget(self.WebtoonBox, 3, 1, 1, 1)
self.NoDitheringBox = QtGui.QCheckBox(self.OptionsAdvanced) self.NoDitheringBox = QtGui.QCheckBox(self.OptionsAdvanced)
font = QtGui.QFont() font = QtGui.QFont()
font.setPointSize(11) font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(12)
self.NoDitheringBox.setFont(font) self.NoDitheringBox.setFont(font)
self.NoDitheringBox.setFocusPolicy(QtCore.Qt.NoFocus) self.NoDitheringBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.NoDitheringBox.setObjectName(_fromUtf8("NoDitheringBox")) self.NoDitheringBox.setObjectName(_fromUtf8("NoDitheringBox"))
self.gridLayout.addWidget(self.NoDitheringBox, 3, 2, 1, 1) self.gridLayout.addWidget(self.NoDitheringBox, 3, 2, 1, 1)
self.BorderBox = QtGui.QCheckBox(self.OptionsAdvanced) self.BorderBox = QtGui.QCheckBox(self.OptionsAdvanced)
font = QtGui.QFont() font = QtGui.QFont()
font.setPointSize(11) font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(12)
self.BorderBox.setFont(font) self.BorderBox.setFont(font)
self.BorderBox.setFocusPolicy(QtCore.Qt.NoFocus) self.BorderBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.BorderBox.setTristate(True)
self.BorderBox.setObjectName(_fromUtf8("BorderBox")) self.BorderBox.setObjectName(_fromUtf8("BorderBox"))
self.gridLayout.addWidget(self.BorderBox, 3, 0, 1, 1) self.gridLayout.addWidget(self.BorderBox, 3, 0, 1, 1)
self.NoRotateBox = QtGui.QCheckBox(self.OptionsAdvanced) self.NoRotateBox = QtGui.QCheckBox(self.OptionsAdvanced)
font = QtGui.QFont() font = QtGui.QFont()
font.setPointSize(11) font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(12)
self.NoRotateBox.setFont(font) self.NoRotateBox.setFont(font)
self.NoRotateBox.setFocusPolicy(QtCore.Qt.NoFocus) self.NoRotateBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.NoRotateBox.setObjectName(_fromUtf8("NoRotateBox")) self.NoRotateBox.setObjectName(_fromUtf8("NoRotateBox"))
@@ -93,6 +102,7 @@ class Ui_KCC(object):
self.DeviceBox = QtGui.QComboBox(self.Form) self.DeviceBox = QtGui.QComboBox(self.Form)
self.DeviceBox.setGeometry(QtCore.QRect(8, 200, 151, 34)) self.DeviceBox.setGeometry(QtCore.QRect(8, 200, 151, 34))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(11) font.setPointSize(11)
self.DeviceBox.setFont(font) self.DeviceBox.setFont(font)
self.DeviceBox.setFocusPolicy(QtCore.Qt.NoFocus) self.DeviceBox.setFocusPolicy(QtCore.Qt.NoFocus)
@@ -100,6 +110,7 @@ class Ui_KCC(object):
self.FormatBox = QtGui.QComboBox(self.Form) self.FormatBox = QtGui.QComboBox(self.Form)
self.FormatBox.setGeometry(QtCore.QRect(262, 200, 152, 34)) self.FormatBox.setGeometry(QtCore.QRect(262, 200, 152, 34))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(11) font.setPointSize(11)
self.FormatBox.setFont(font) self.FormatBox.setFont(font)
self.FormatBox.setFocusPolicy(QtCore.Qt.NoFocus) self.FormatBox.setFocusPolicy(QtCore.Qt.NoFocus)
@@ -107,6 +118,7 @@ class Ui_KCC(object):
self.ConvertButton = QtGui.QPushButton(self.Form) self.ConvertButton = QtGui.QPushButton(self.Form)
self.ConvertButton.setGeometry(QtCore.QRect(160, 200, 101, 41)) self.ConvertButton.setGeometry(QtCore.QRect(160, 200, 101, 41))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(11) font.setPointSize(11)
font.setBold(True) font.setBold(True)
font.setWeight(75) font.setWeight(75)
@@ -119,6 +131,7 @@ class Ui_KCC(object):
self.DirectoryButton = QtGui.QPushButton(self.Form) self.DirectoryButton = QtGui.QPushButton(self.Form)
self.DirectoryButton.setGeometry(QtCore.QRect(5, 160, 156, 41)) self.DirectoryButton.setGeometry(QtCore.QRect(5, 160, 156, 41))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(11) font.setPointSize(11)
self.DirectoryButton.setFont(font) self.DirectoryButton.setFont(font)
self.DirectoryButton.setFocusPolicy(QtCore.Qt.NoFocus) self.DirectoryButton.setFocusPolicy(QtCore.Qt.NoFocus)
@@ -129,6 +142,7 @@ class Ui_KCC(object):
self.FileButton = QtGui.QPushButton(self.Form) self.FileButton = QtGui.QPushButton(self.Form)
self.FileButton.setGeometry(QtCore.QRect(260, 160, 157, 41)) self.FileButton.setGeometry(QtCore.QRect(260, 160, 157, 41))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(11) font.setPointSize(11)
self.FileButton.setFont(font) self.FileButton.setFont(font)
self.FileButton.setFocusPolicy(QtCore.Qt.NoFocus) self.FileButton.setFocusPolicy(QtCore.Qt.NoFocus)
@@ -139,6 +153,7 @@ class Ui_KCC(object):
self.ClearButton = QtGui.QPushButton(self.Form) self.ClearButton = QtGui.QPushButton(self.Form)
self.ClearButton.setGeometry(QtCore.QRect(160, 160, 101, 41)) self.ClearButton.setGeometry(QtCore.QRect(160, 160, 101, 41))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(11) font.setPointSize(11)
self.ClearButton.setFont(font) self.ClearButton.setFont(font)
self.ClearButton.setFocusPolicy(QtCore.Qt.NoFocus) self.ClearButton.setFocusPolicy(QtCore.Qt.NoFocus)
@@ -147,22 +162,25 @@ class Ui_KCC(object):
self.ClearButton.setIcon(icon4) self.ClearButton.setIcon(icon4)
self.ClearButton.setObjectName(_fromUtf8("ClearButton")) self.ClearButton.setObjectName(_fromUtf8("ClearButton"))
self.OptionsBasic = QtGui.QFrame(self.Form) self.OptionsBasic = QtGui.QFrame(self.Form)
self.OptionsBasic.setGeometry(QtCore.QRect(10, 233, 421, 41)) self.OptionsBasic.setGeometry(QtCore.QRect(5, 233, 421, 41))
font = QtGui.QFont() font = QtGui.QFont()
font.setPointSize(9) font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(12)
self.OptionsBasic.setFont(font) self.OptionsBasic.setFont(font)
self.OptionsBasic.setObjectName(_fromUtf8("OptionsBasic")) self.OptionsBasic.setObjectName(_fromUtf8("OptionsBasic"))
self.MangaBox = QtGui.QCheckBox(self.OptionsBasic) self.MangaBox = QtGui.QCheckBox(self.OptionsBasic)
self.MangaBox.setGeometry(QtCore.QRect(9, 10, 130, 18)) self.MangaBox.setGeometry(QtCore.QRect(9, 10, 130, 18))
font = QtGui.QFont() font = QtGui.QFont()
font.setPointSize(11) font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(12)
self.MangaBox.setFont(font) self.MangaBox.setFont(font)
self.MangaBox.setFocusPolicy(QtCore.Qt.NoFocus) self.MangaBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.MangaBox.setObjectName(_fromUtf8("MangaBox")) self.MangaBox.setObjectName(_fromUtf8("MangaBox"))
self.QualityBox = QtGui.QCheckBox(self.OptionsBasic) self.QualityBox = QtGui.QCheckBox(self.OptionsBasic)
self.QualityBox.setGeometry(QtCore.QRect(282, 10, 130, 18)) self.QualityBox.setGeometry(QtCore.QRect(282, 10, 135, 18))
font = QtGui.QFont() font = QtGui.QFont()
font.setPointSize(11) font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(12)
self.QualityBox.setFont(font) self.QualityBox.setFont(font)
self.QualityBox.setFocusPolicy(QtCore.Qt.NoFocus) self.QualityBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.QualityBox.setTristate(True) self.QualityBox.setTristate(True)
@@ -170,13 +188,15 @@ class Ui_KCC(object):
self.RotateBox = QtGui.QCheckBox(self.OptionsBasic) self.RotateBox = QtGui.QCheckBox(self.OptionsBasic)
self.RotateBox.setGeometry(QtCore.QRect(145, 10, 130, 18)) self.RotateBox.setGeometry(QtCore.QRect(145, 10, 130, 18))
font = QtGui.QFont() font = QtGui.QFont()
font.setPointSize(11) font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(12)
self.RotateBox.setFont(font) self.RotateBox.setFont(font)
self.RotateBox.setFocusPolicy(QtCore.Qt.NoFocus) self.RotateBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.RotateBox.setObjectName(_fromUtf8("RotateBox")) self.RotateBox.setObjectName(_fromUtf8("RotateBox"))
self.JobList = QtGui.QListWidget(self.Form) self.JobList = QtGui.QListWidget(self.Form)
self.JobList.setGeometry(QtCore.QRect(10, 50, 401, 101)) self.JobList.setGeometry(QtCore.QRect(10, 50, 401, 101))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(11) font.setPointSize(11)
self.JobList.setFont(font) self.JobList.setFont(font)
self.JobList.setFocusPolicy(QtCore.Qt.NoFocus) self.JobList.setFocusPolicy(QtCore.Qt.NoFocus)
@@ -186,6 +206,7 @@ class Ui_KCC(object):
self.BasicModeButton = QtGui.QPushButton(self.Form) self.BasicModeButton = QtGui.QPushButton(self.Form)
self.BasicModeButton.setGeometry(QtCore.QRect(5, 10, 210, 41)) self.BasicModeButton.setGeometry(QtCore.QRect(5, 10, 210, 41))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(12) font.setPointSize(12)
font.setBold(False) font.setBold(False)
font.setWeight(50) font.setWeight(50)
@@ -195,6 +216,7 @@ class Ui_KCC(object):
self.AdvModeButton = QtGui.QPushButton(self.Form) self.AdvModeButton = QtGui.QPushButton(self.Form)
self.AdvModeButton.setGeometry(QtCore.QRect(207, 10, 210, 41)) self.AdvModeButton.setGeometry(QtCore.QRect(207, 10, 210, 41))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(12) font.setPointSize(12)
font.setBold(False) font.setBold(False)
font.setWeight(50) font.setWeight(50)
@@ -203,21 +225,26 @@ class Ui_KCC(object):
self.AdvModeButton.setObjectName(_fromUtf8("AdvModeButton")) self.AdvModeButton.setObjectName(_fromUtf8("AdvModeButton"))
self.OptionsAdvancedGamma = QtGui.QFrame(self.Form) self.OptionsAdvancedGamma = QtGui.QFrame(self.Form)
self.OptionsAdvancedGamma.setEnabled(True) self.OptionsAdvancedGamma.setEnabled(True)
self.OptionsAdvancedGamma.setGeometry(QtCore.QRect(10, 303, 401, 41)) self.OptionsAdvancedGamma.setGeometry(QtCore.QRect(5, 303, 401, 41))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(9) font.setPointSize(9)
self.OptionsAdvancedGamma.setFont(font) self.OptionsAdvancedGamma.setFont(font)
self.OptionsAdvancedGamma.setObjectName(_fromUtf8("OptionsAdvancedGamma")) self.OptionsAdvancedGamma.setObjectName(_fromUtf8("OptionsAdvancedGamma"))
self.GammaLabel = QtGui.QLabel(self.OptionsAdvancedGamma) self.GammaLabel = QtGui.QLabel(self.OptionsAdvancedGamma)
self.GammaLabel.setGeometry(QtCore.QRect(20, 0, 100, 40)) self.GammaLabel.setGeometry(QtCore.QRect(20, 0, 100, 40))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(12) font.setPointSize(12)
font.setBold(False) font.setBold(False)
font.setWeight(50) font.setWeight(50)
self.GammaLabel.setFont(font) self.GammaLabel.setFont(font)
self.GammaLabel.setObjectName(_fromUtf8("GammaLabel")) self.GammaLabel.setObjectName(_fromUtf8("GammaLabel"))
self.GammaSlider = QtGui.QSlider(self.OptionsAdvancedGamma) self.GammaSlider = QtGui.QSlider(self.OptionsAdvancedGamma)
self.GammaSlider.setGeometry(QtCore.QRect(110, 10, 280, 22)) self.GammaSlider.setGeometry(QtCore.QRect(110, 10, 290, 22))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
self.GammaSlider.setFont(font)
self.GammaSlider.setFocusPolicy(QtCore.Qt.ClickFocus) self.GammaSlider.setFocusPolicy(QtCore.Qt.ClickFocus)
self.GammaSlider.setMaximum(500) self.GammaSlider.setMaximum(500)
self.GammaSlider.setSingleStep(5) self.GammaSlider.setSingleStep(5)
@@ -226,6 +253,7 @@ class Ui_KCC(object):
self.ProgressBar = QtGui.QProgressBar(self.Form) self.ProgressBar = QtGui.QProgressBar(self.Form)
self.ProgressBar.setGeometry(QtCore.QRect(10, 10, 401, 35)) self.ProgressBar.setGeometry(QtCore.QRect(10, 10, 401, 35))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(10) font.setPointSize(10)
font.setBold(True) font.setBold(True)
font.setWeight(75) font.setWeight(75)
@@ -236,25 +264,31 @@ class Ui_KCC(object):
self.ProgressBar.setFormat(_fromUtf8("")) self.ProgressBar.setFormat(_fromUtf8(""))
self.ProgressBar.setObjectName(_fromUtf8("ProgressBar")) self.ProgressBar.setObjectName(_fromUtf8("ProgressBar"))
self.OptionsExpert = QtGui.QFrame(self.Form) self.OptionsExpert = QtGui.QFrame(self.Form)
self.OptionsExpert.setGeometry(QtCore.QRect(10, 335, 421, 41)) self.OptionsExpert.setGeometry(QtCore.QRect(5, 335, 421, 41))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(9) font.setPointSize(9)
self.OptionsExpert.setFont(font) self.OptionsExpert.setFont(font)
self.OptionsExpert.setObjectName(_fromUtf8("OptionsExpert")) self.OptionsExpert.setObjectName(_fromUtf8("OptionsExpert"))
self.ColorBox = QtGui.QCheckBox(self.OptionsExpert) self.ColorBox = QtGui.QCheckBox(self.OptionsExpert)
self.ColorBox.setGeometry(QtCore.QRect(9, 11, 130, 18)) self.ColorBox.setGeometry(QtCore.QRect(9, 11, 130, 18))
font = QtGui.QFont() font = QtGui.QFont()
font.setPointSize(11) font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(12)
self.ColorBox.setFont(font) self.ColorBox.setFont(font)
self.ColorBox.setFocusPolicy(QtCore.Qt.NoFocus) self.ColorBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.ColorBox.setObjectName(_fromUtf8("ColorBox")) self.ColorBox.setObjectName(_fromUtf8("ColorBox"))
self.OptionsExpertInternal = QtGui.QFrame(self.OptionsExpert) self.OptionsExpertInternal = QtGui.QFrame(self.OptionsExpert)
self.OptionsExpertInternal.setGeometry(QtCore.QRect(90, 0, 315, 40)) self.OptionsExpertInternal.setGeometry(QtCore.QRect(95, 0, 315, 40))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
self.OptionsExpertInternal.setFont(font)
self.OptionsExpertInternal.setObjectName(_fromUtf8("OptionsExpertInternal")) self.OptionsExpertInternal.setObjectName(_fromUtf8("OptionsExpertInternal"))
self.gridLayout_2 = QtGui.QGridLayout(self.OptionsExpertInternal) self.gridLayout_2 = QtGui.QGridLayout(self.OptionsExpertInternal)
self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2")) self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2"))
self.wLabel = QtGui.QLabel(self.OptionsExpertInternal) self.wLabel = QtGui.QLabel(self.OptionsExpertInternal)
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(12) font.setPointSize(12)
font.setBold(False) font.setBold(False)
font.setWeight(50) font.setWeight(50)
@@ -269,6 +303,7 @@ class Ui_KCC(object):
self.customWidth.setSizePolicy(sizePolicy) self.customWidth.setSizePolicy(sizePolicy)
self.customWidth.setMaximumSize(QtCore.QSize(45, 16777215)) self.customWidth.setMaximumSize(QtCore.QSize(45, 16777215))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(12) font.setPointSize(12)
self.customWidth.setFont(font) self.customWidth.setFont(font)
self.customWidth.setFocusPolicy(QtCore.Qt.ClickFocus) self.customWidth.setFocusPolicy(QtCore.Qt.ClickFocus)
@@ -278,6 +313,7 @@ class Ui_KCC(object):
self.gridLayout_2.addWidget(self.customWidth, 0, 1, 1, 1) self.gridLayout_2.addWidget(self.customWidth, 0, 1, 1, 1)
self.hLabel = QtGui.QLabel(self.OptionsExpertInternal) self.hLabel = QtGui.QLabel(self.OptionsExpertInternal)
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(12) font.setPointSize(12)
font.setBold(False) font.setBold(False)
font.setWeight(50) font.setWeight(50)
@@ -292,6 +328,7 @@ class Ui_KCC(object):
self.customHeight.setSizePolicy(sizePolicy) self.customHeight.setSizePolicy(sizePolicy)
self.customHeight.setMaximumSize(QtCore.QSize(45, 16777215)) self.customHeight.setMaximumSize(QtCore.QSize(45, 16777215))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(12) font.setPointSize(12)
self.customHeight.setFont(font) self.customHeight.setFont(font)
self.customHeight.setFocusPolicy(QtCore.Qt.ClickFocus) self.customHeight.setFocusPolicy(QtCore.Qt.ClickFocus)
@@ -321,31 +358,31 @@ class Ui_KCC(object):
KCC.setWindowTitle(_translate("KCC", "Kindle Comic Converter", None)) KCC.setWindowTitle(_translate("KCC", "Kindle Comic Converter", None))
self.ProcessingBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Disable image optimizations.</span></p></body></html>", None)) self.ProcessingBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Disable image optimizations.</span></p></body></html>", None))
self.ProcessingBox.setText(_translate("KCC", "No optimisation", None)) self.ProcessingBox.setText(_translate("KCC", "No optimisation", None))
self.UpscaleBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Enable image upscaling.<br/>Aspect ratio will be preserved.</span></p></body></html>", None)) self.UpscaleBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt; font-weight:600; text-decoration: underline;\">Unchecked - Nothing<br/></span><span style=\" font-size:12pt;\">Images smaller than device resolution will not be resized.</span></p><p><span style=\" font-size:12pt; font-weight:600; text-decoration: underline;\">Indeterminate - Stretching<br/></span><span style=\" font-size:12pt;\">Images smaller than device resolution will be resized. Aspect ratio will be not preserved.</span></p><p><span style=\" font-size:12pt; font-weight:600; text-decoration: underline;\">Checked - Upscaling<br/></span><span style=\" font-size:12pt;\">Images smaller than device resolution will be resized. Aspect ratio will be preserved.</span></p></body></html>", None))
self.UpscaleBox.setText(_translate("KCC", "Upscale images", None)) self.UpscaleBox.setText(_translate("KCC", "Stretch/Upscale", None))
self.StretchBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Enable image stretching.<br/>Aspect ratio will be not preserved.</span></p></body></html>", None)) self.WebtoonBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Enable auto-splitting of webtoons like </span><span style=\" font-size:12pt; font-style:italic;\">Tower of God</span><span style=\" font-size:12pt;\"> or </span><span style=\" font-size:12pt; font-style:italic;\">Noblesse</span><span style=\" font-size:12pt;\">.<br/>Pages with a low width, high height and vertical panel flow.</span></p></body></html>", None))
self.StretchBox.setText(_translate("KCC", "Stretch images", None)) self.WebtoonBox.setText(_translate("KCC", "Webtoon mode", None))
self.NoDitheringBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Create PNG files instead JPEG.<br/></span><span style=\" font-size:12pt; font-weight:600;\">Only for non-Kindle devices!</span></p></body></html>", None)) self.NoDitheringBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Create PNG files instead JPEG.</span></p></body></html>", None))
self.NoDitheringBox.setText(_translate("KCC", "PNG output", None)) self.NoDitheringBox.setText(_translate("KCC", "PNG output", None))
self.BorderBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Fill space around images with black color.</span></p></body></html>", None)) self.BorderBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt; font-weight:600; text-decoration: underline;\">Unchecked - Autodetection<br/></span><span style=\" font-size:12pt;\">Color of margins fill will be detected automatically.</span></p><p><span style=\" font-size:12pt; font-weight:600; text-decoration: underline;\">Indeterminate - White<br/></span><span style=\" font-size:12pt;\">Margins will be filled with white color.</span></p><p><span style=\" font-size:12pt; font-weight:600; text-decoration: underline;\">Checked - Black<br/></span><span style=\" font-size:12pt;\">Margins will be filled with black color.</span></p></body></html>", None))
self.BorderBox.setText(_translate("KCC", "Black borders", None)) self.BorderBox.setText(_translate("KCC", "W/B margins", None))
self.NoRotateBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Disable splitting and rotation.</span></p></body></html>", None)) self.NoRotateBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Disable splitting and rotation.</span></p></body></html>", None))
self.NoRotateBox.setText(_translate("KCC", "No split/rotate", None)) self.NoRotateBox.setText(_translate("KCC", "No split/rotate", None))
self.DeviceBox.setToolTip(_translate("KCC", "Target device.", None)) self.DeviceBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Target device.</span></p></body></html>", None))
self.FormatBox.setToolTip(_translate("KCC", "Output format.", None)) self.FormatBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Output format.</span></p></body></html>", None))
self.ConvertButton.setText(_translate("KCC", "Convert", None)) self.ConvertButton.setText(_translate("KCC", "Convert", None))
self.DirectoryButton.setText(_translate("KCC", "Add directory", None)) self.DirectoryButton.setText(_translate("KCC", "Add directory", None))
self.FileButton.setText(_translate("KCC", "Add file", None)) self.FileButton.setText(_translate("KCC", "Add file", None))
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-family:\'MS Shell Dlg 2\'; font-size:14pt; font-weight:600; text-decoration: underline;\">Unchecked - Normal quality mode<br/></span><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:14pt; font-style:italic;\">Use it when Panel View support is not needed.</span><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:14pt; font-weight:600; text-decoration: underline;\"><br/></span><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:14pt;\">- Maximum quality when zoom is not enabled.<br/>- Poor quality when zoom is enabled.<br/>- Lowest file size.</span></p><p><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:14pt; font-weight:600; text-decoration: underline;\">Indeterminate - High quality mode<br/></span><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:14pt; font-style:italic;\">Not zoomed image </span><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:14pt; font-weight:600; font-style:italic;\">might </span><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:14pt; font-style:italic;\">be a little blurry.</span><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:14pt; font-weight:600; text-decoration: underline;\"><br/></span><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:14pt;\">- Medium/High quality when zoom is not enabled.<br/>- Maximum quality when zoom is enabled.</span></p><p><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:14pt; font-weight:600; text-decoration: underline;\">Checked - Ultra quality mode<br/></span><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:14pt; font-style:italic;\">Maximum possible quality.</span><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:14pt; font-weight:600; text-decoration: underline;\"><br/></span><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:14pt;\">- 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.</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 page spliting.<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 MIGHT improve readability.</span></p></body></html>", 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.GammaSlider.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">When converting color images setting this option to 1.0 </span><span style=\" font-size:12pt; font-weight:600;\">might</span><span style=\" font-size:12pt;\"> improve readability.</span></p></body></html>", None))
self.ColorBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Do not convert images to grayscale.</span></p></body></html>", None)) self.ColorBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Do not convert images to grayscale.</span></p></body></html>", None))

View File

@@ -1,4 +1,4 @@
__version__ = '3.0' __version__ = '3.3'
__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

@@ -1,4 +1,5 @@
# Copyright (c) 2012 Ciro Mattia Gonano <ciromattia@gmail.com> # Copyright (c) 2012-2013 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013 Pawel Jastrzebski <pawelj@vulturis.eu>
# #
# Permission to use, copy, modify, and/or distribute this software for # Permission to use, copy, modify, and/or distribute this software for
# any purpose with or without fee is hereby granted, provided that the # any purpose with or without fee is hereby granted, provided that the
@@ -21,6 +22,7 @@ __docformat__ = 'restructuredtext en'
import os import os
import zipfile import zipfile
import rarfile import rarfile
from subprocess import Popen, STDOUT, PIPE
# noinspection PyBroadException # noinspection PyBroadException
@@ -31,6 +33,8 @@ class CBxArchive:
self.compressor = 'zip' self.compressor = 'zip'
elif rarfile.is_rarfile(origFileName): elif rarfile.is_rarfile(origFileName):
self.compressor = 'rar' self.compressor = 'rar'
elif origFileName.endswith('.7z') or origFileName.endswith('.cb7'):
self.compressor = '7z'
else: else:
self.compressor = None self.compressor = None
@@ -67,12 +71,24 @@ class CBxArchive:
filelist.append(f) filelist.append(f)
cbrFile.extractall(targetdir, filelist) cbrFile.extractall(targetdir, filelist)
def extractCB7(self, targetdir):
output = Popen('7za x "' + self.origFileName + '" -xr!__MACOSX -xr!.DS_Store -xr!thumbs.db -o"' + targetdir +
'"', stdout=PIPE, stderr=STDOUT, shell=True)
extracted = False
for line in output.stdout:
if "Everything is Ok" in line:
extracted = True
if not extracted:
raise OSError
def extract(self, targetdir): def extract(self, targetdir):
print "\n" + targetdir + "\n" print "\n" + targetdir + "\n"
if self.compressor == 'rar': if self.compressor == 'rar':
self.extractCBR(targetdir) self.extractCBR(targetdir)
elif self.compressor == 'zip': elif self.compressor == 'zip':
self.extractCBZ(targetdir) self.extractCBZ(targetdir)
elif self.compressor == '7z':
self.extractCB7(targetdir)
adir = os.listdir(targetdir) adir = os.listdir(targetdir)
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 import shutil

File diff suppressed because it is too large Load Diff

277
kcc/comic2panel.py Normal file
View File

@@ -0,0 +1,277 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2012-2013 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013 Pawel Jastrzebski <pawelj@vulturis.eu>
#
# Permission to use, copy, modify, and/or distribute this software for
# any purpose with or without fee is hereby granted, provided that the
# above copyright notice and this permission notice appear in all
# copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
# AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
# DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
# OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
#
__version__ = '3.3'
__license__ = 'ISC'
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
__docformat__ = 'restructuredtext en'
import os
import sys
from shutil import rmtree, copytree, move
from optparse import OptionParser, OptionGroup
from multiprocessing import Pool, Queue, freeze_support
try:
# noinspection PyUnresolvedReferences
from PIL import Image, ImageStat
except ImportError:
print "ERROR: Pillow is not installed!"
exit(1)
try:
from PyQt4 import QtCore
except ImportError:
QtCore = None
def getImageFileName(imgfile):
filename = os.path.splitext(imgfile)
if filename[0].startswith('.') or\
(filename[1].lower() != '.png' and
filename[1].lower() != '.jpg' and
filename[1].lower() != '.gif' and
filename[1].lower() != '.tif' and
filename[1].lower() != '.tiff' and
filename[1].lower() != '.bmp' and
filename[1].lower() != '.jpeg'):
return None
return filename
def sanitizePanelSize(panel, opt):
newPanels = []
if panel[2] > 8 * opt.height:
diff = (panel[2] / 8)
newPanels.append([panel[0], panel[1] - diff*7, diff])
newPanels.append([panel[1] - diff*7, panel[1] - diff*6, diff])
newPanels.append([panel[1] - diff*6, panel[1] - diff*5, diff])
newPanels.append([panel[1] - diff*5, panel[1] - diff*4, diff])
newPanels.append([panel[1] - diff*4, panel[1] - diff*3, diff])
newPanels.append([panel[1] - diff*3, panel[1] - diff*2, diff])
newPanels.append([panel[1] - diff*2, panel[1] - diff, diff])
newPanels.append([panel[1] - diff, panel[1], diff])
elif panel[2] > 4 * opt.height:
diff = (panel[2] / 4)
newPanels.append([panel[0], panel[1] - diff*3, diff])
newPanels.append([panel[1] - diff*3, panel[1] - diff*2, diff])
newPanels.append([panel[1] - diff*2, panel[1] - diff, diff])
newPanels.append([panel[1] - diff, panel[1], diff])
elif panel[2] > 2 * opt.height:
newPanels.append([panel[0], panel[1] - (panel[2] / 2), (panel[2] / 2)])
newPanels.append([panel[1] - (panel[2] / 2), panel[1], (panel[2] / 2)])
else:
newPanels = [panel]
return newPanels
def splitImage_init(queue, opt):
splitImage.queue = queue
splitImage.options = opt
# noinspection PyUnresolvedReferences
def splitImage(work):
path = work[0]
name = work[1]
opt = splitImage.options
# Harcoded opttions
threshold = 1.0
delta = 15
print ".",
splitImage.queue.put(".")
fileExpanded = os.path.splitext(name)
filePath = os.path.join(path, name)
# Detect corrupted files
try:
Image.open(filePath)
except IOError:
raise RuntimeError('Cannot read image file %s' % filePath)
try:
image = Image.open(filePath)
image.verify()
except:
raise RuntimeError('Image file %s is corrupted' % filePath)
try:
image = Image.open(filePath)
image.load()
except:
raise RuntimeError('Image file %s is corrupted' % filePath)
image = Image.open(filePath)
image = image.convert('RGB')
widthImg, heightImg = image.size
if heightImg > opt.height:
if opt.debug:
from PIL import ImageDraw
debugImage = Image.open(filePath)
draw = ImageDraw.Draw(debugImage)
# Find panels
y1 = 0
y2 = 15
panels = []
while y2 < heightImg:
while ImageStat.Stat(image.crop([0, y1, widthImg, y2])).var[0] < threshold and y2 < heightImg:
y2 += delta
y2 -= delta
y1Temp = y2
y1 = y2 + delta
y2 = y1 + delta
while ImageStat.Stat(image.crop([0, y1, widthImg, y2])).var[0] >= threshold and y2 < heightImg:
y1 += delta
y2 += delta
if y1 + delta >= heightImg:
y1 = heightImg - 1
y2Temp = y1
if opt.debug:
draw.line([(0, y1Temp), (widthImg, y1Temp)], fill=(0, 255, 0))
draw.line([(0, y2Temp), (widthImg, y2Temp)], fill=(255, 0, 0))
panelHeight = y2Temp - y1Temp
if panelHeight > delta:
# Panels that can't be cut nicely will be forcefully splitted
panelsCleaned = sanitizePanelSize([y1Temp, y2Temp, panelHeight], opt)
for panel in panelsCleaned:
panels.append(panel)
if opt.debug:
# noinspection PyUnboundLocalVariable
debugImage.save(os.path.join(path, fileExpanded[0] + '-debug.png'), 'PNG')
# Create virtual pages
pages = []
currentPage = []
pageLeft = opt.height
panelNumber = 0
for panel in panels:
if pageLeft - panel[2] > 0:
pageLeft -= panel[2]
currentPage.append(panelNumber)
panelNumber += 1
else:
if len(currentPage) > 0:
pages.append(currentPage)
pageLeft = opt.height - panel[2]
currentPage = [panelNumber]
panelNumber += 1
if len(currentPage) > 0:
pages.append(currentPage)
# Create pages
pageNumber = 1
for page in pages:
pageHeight = 0
targetHeight = 0
for panel in page:
pageHeight += panels[panel][2]
if pageHeight > delta:
newPage = Image.new('RGB', (widthImg, pageHeight))
for panel in page:
panelImg = image.crop([0, panels[panel][0], widthImg, panels[panel][1]])
newPage.paste(panelImg, (0, targetHeight))
targetHeight += panels[panel][2]
newPage.save(os.path.join(path, fileExpanded[0] + '-' +
str(pageNumber) + '.png'), 'PNG')
pageNumber += 1
os.remove(filePath)
def Copyright():
print ('comic2panel v%(__version__)s. '
'Written 2013 by Ciro Mattia Gonano and Pawel Jastrzebski.' % globals())
# noinspection PyBroadException
def main(argv=None, qtGUI=None):
global options
parser = OptionParser(usage="Usage: %prog [options] comic_folder", add_help_option=False)
mainOptions = OptionGroup(parser, "MANDATORY")
otherOptions = OptionGroup(parser, "OTHER")
mainOptions.add_option("-y", "--height", type="int", dest="height", default=0,
help="Height of the target device screen")
mainOptions.add_option("-i", "--in-place", action="store_true", dest="inPlace", default=False,
help="Overwrite source directory")
otherOptions.add_option("-d", "--debug", action="store_true", dest="debug", default=False,
help="Create debug file for every splitted image")
otherOptions.add_option("-h", "--help", action="help",
help="Show this help message and exit")
parser.add_option_group(mainOptions)
parser.add_option_group(otherOptions)
options, args = parser.parse_args(argv)
if qtGUI:
GUI = qtGUI
else:
GUI = None
if len(args) != 1:
parser.print_help()
return
if options.height > 0:
options.sourceDir = args[0]
options.targetDir = args[0] + "-Splitted"
print "\nSplitting images..."
if os.path.isdir(options.sourceDir):
rmtree(options.targetDir, True)
copytree(options.sourceDir, options.targetDir)
work = []
pagenumber = 0
queue = Queue()
pool = Pool(None, splitImage_init, [queue, options])
for root, dirs, files in os.walk(options.targetDir, False):
for name in files:
if getImageFileName(name) is not None:
pagenumber += 1
work.append([root, name])
else:
os.remove(os.path.join(root, name))
if GUI:
GUI.emit(QtCore.SIGNAL("progressBarTick"), pagenumber)
if len(work) > 0:
workers = pool.map_async(func=splitImage, iterable=work)
pool.close()
if GUI:
while not workers.ready():
# noinspection PyBroadException
try:
queue.get(True, 5)
except:
pass
GUI.emit(QtCore.SIGNAL("progressBarTick"))
pool.join()
queue.close()
try:
workers.get()
except:
rmtree(options.targetDir, True)
raise RuntimeError("One of workers crashed. Cause: " + str(sys.exc_info()[1]))
if GUI:
GUI.emit(QtCore.SIGNAL("progressBarTick"), 1)
if options.inPlace:
rmtree(options.sourceDir, True)
move(options.targetDir, options.sourceDir)
else:
rmtree(options.targetDir)
raise UserWarning("Source directory is empty.")
else:
raise UserWarning("Provided path is not a directory.")
else:
raise UserWarning("Target height is not set.")
if __name__ == "__main__":
freeze_support()
Copyright()
main(sys.argv[1:])
sys.exit(0)

View File

@@ -1,6 +1,7 @@
# Copyright (C) 2010 Alex Yatskov # Copyright (C) 2010 Alex Yatskov
# Copyright (C) 2011 Stanislav (proDOOMman) Kosolapov <prodoomman@gmail.com> # Copyright (C) 2011 Stanislav (proDOOMman) Kosolapov <prodoomman@gmail.com>
# Copyright (C) 2012-2013 Ciro Mattia Gonano <ciromattia@gmail.com> # Copyright (C) 2012-2013 Ciro Mattia Gonano <ciromattia@gmail.com>
# 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
@@ -29,6 +30,9 @@ except ImportError:
class ProfileData: class ProfileData:
def __init__(self):
pass
Palette4 = [ Palette4 = [
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
@@ -73,36 +77,60 @@ class ProfileData:
0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
] ]
PalleteNull = [
]
Profiles = { Profiles = {
'K1': ("Kindle 1", (600, 800), Palette4, 1.8, (900, 1200)), 'K1': ("Kindle 1", (600, 670), Palette4, 1.8, (900, 1005)),
'K2': ("Kindle 2", (600, 800), Palette15, 1.8, (900, 1200)), 'K2': ("Kindle 2", (600, 670), Palette15, 1.8, (900, 1005)),
'K3': ("Kindle Keyboard", (600, 800), Palette16, 1.8, (900, 1200)), 'K345': ("Kindle", (600, 800), Palette16, 1.8, (900, 1200)),
'K4NT': ("Kindle Non-Touch", (600, 800), Palette16, 1.8, (900, 1200)),
'K4T': ("Kindle Touch", (600, 800), Palette16, 1.8, (900, 1200)),
'KHD': ("Kindle Paperwhite", (758, 1024), Palette16, 1.8, (1137, 1536)), 'KHD': ("Kindle Paperwhite", (758, 1024), Palette16, 1.8, (1137, 1536)),
'KDX': ("Kindle DX", (824, 1200), Palette15, 1.8, (1236, 1800)), 'KDX': ("Kindle DX", (824, 1000), Palette15, 1.8, (1236, 1500)),
'KDXG': ("Kindle DXG", (824, 1200), Palette16, 1.8, (1236, 1800)), 'KDXG': ("Kindle DXG", (824, 1000), Palette16, 1.8, (1236, 1500)),
'KF': ("Kindle Fire", (600, 1024), Palette16, 1.0, (900, 1536)), 'KF': ("Kindle Fire", (600, 1024), PalleteNull, 1.0, (900, 1536)),
'KFHD': ("Kindle Fire HD 7\"", (800, 1280), Palette16, 1.0, (1200, 1920)), 'KFHD': ("K. Fire HD 7\"", (800, 1280), PalleteNull, 1.0, (1200, 1920)),
'KFHD8': ("Kindle Fire HD 8.9\"", (1200, 1920), Palette16, 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)),
'KFHDX8': ("K. Fire HDX 8.9\"", (1600, 2560), PalleteNull, 1.0, (2400, 3840)),
'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 = { ProfileLabels = {
"Kindle 1": 'K1', "Kindle 1": 'K1',
"Kindle 2": 'K2', "Kindle 2": 'K2',
"Kindle 3/Keyboard": 'K3', "Kindle": 'K345',
"Kindle 4/Non-Touch": 'K4NT',
"Kindle 4/Touch": 'K4T',
"Kindle Paperwhite": 'KHD', "Kindle Paperwhite": 'KHD',
"Kindle DX": 'KDX', "Kindle DX": 'KDX',
"Kindle DXG": 'KDXG', "Kindle DXG": 'KDXG',
"Kindle Fire": 'KF', "Kindle Fire": 'KF',
"Kindle Fire HD 7\"": 'KFHD', "K. Fire HD 7\"": 'KFHD',
"Kindle Fire HD 8.9\"": 'KFHD8', "K. Fire HD 8.9\"": 'KFHD8',
"K. Fire HDX 7\"": 'KFHDX',
"K. Fire HDX 8.9\"": 'KFHDX8',
"Kindle for Android": 'KFA',
"Other": 'OTHER' "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",
"Kindle DXG",
"Kindle Fire"
]
class ComicPage: class ComicPage:
def __init__(self, source, device): def __init__(self, source, device):
@@ -113,34 +141,51 @@ class ComicPage:
# Detect corrupted files - Phase 2 # Detect corrupted files - Phase 2
try: try:
self.origFileName = source self.origFileName = source
self.filename = os.path.basename(self.origFileName)
self.image = Image.open(source) self.image = Image.open(source)
except IOError: except IOError:
raise RuntimeError('Cannot read image file %s' % source) raise RuntimeError('Cannot read image file %s' % source)
# Detect corrupted files - Phase 3 # Detect corrupted files - Phase 3
try: try:
self.image = Image.open(source)
self.image.verify() self.image.verify()
except: except:
raise RuntimeError('Image file %s is corrupted' % source) 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.border = None
self.noHPV = None
self.noVPV = None
self.fill = None
def saveToDir(self, targetdir, forcepng, color, wipe, suffix=None): def saveToDir(self, targetdir, forcepng, color, wipe):
filename = os.path.basename(self.origFileName)
try: try:
suffix = ""
if not color: if not color:
self.image = self.image.convert('L') # convert to grayscale self.image = self.image.convert('L') # convert to grayscale
if suffix == "R": if self.rotated:
suffix = "_kccrotated" suffix += "_kccrot"
else:
suffix = ""
if wipe: if wipe:
os.remove(os.path.join(targetdir, filename)) os.remove(os.path.join(targetdir, self.filename))
else: else:
suffix += "_kcchq" suffix += "_kcchq"
if self.noHPV:
suffix += "_kccnh"
if self.noVPV:
suffix += "_kccnv"
if self.border:
suffix += "_kccx" + str(self.border[0]) + "_kccy" + str(self.border[1])
if forcepng: if forcepng:
self.image.save(os.path.join(targetdir, os.path.splitext(filename)[0] + suffix + ".png"), "PNG") self.image.save(os.path.join(targetdir, os.path.splitext(self.filename)[0] + suffix + ".png"), "PNG")
else: else:
self.image.save(os.path.join(targetdir, os.path.splitext(filename)[0] + suffix + ".jpg"), "JPEG") self.image.save(os.path.join(targetdir, os.path.splitext(self.filename)[0] + suffix + ".jpg"), "JPEG")
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))
@@ -162,70 +207,101 @@ class ComicPage:
palImg.putpalette(self.palette) palImg.putpalette(self.palette)
self.image = self.image.quantize(palette=palImg) self.image = self.image.quantize(palette=palImg)
def resizeImage(self, upscale=False, stretch=False, black_borders=False, isSplit=False, toRight=False, def resizeImage(self, upscale=False, stretch=False, bordersColor=None, qualityMode=0):
landscapeMode=False, qualityMode=0):
method = Image.ANTIALIAS method = Image.ANTIALIAS
if black_borders: if bordersColor:
fill = 'black' fill = bordersColor
else: else:
fill = 'white' fill = self.fill
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])
# Kindle Paperwhite/Touch - Force upscale of splited pages to increase readability generateBorder = False
if isSplit and landscapeMode:
upscale = True
if self.image.size[0] <= self.size[0] and self.image.size[1] <= self.size[1]: if self.image.size[0] <= self.size[0] and self.image.size[1] <= self.size[1]:
if not upscale: if not upscale:
borderw = (self.size[0] - self.image.size[0]) / 2 borderw = (self.size[0] - self.image.size[0]) / 2
borderh = (self.size[1] - self.image.size[1]) / 2 borderh = (self.size[1] - self.image.size[1]) / 2
self.image = ImageOps.expand(self.image, border=(borderw, borderh), fill=fill) 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 return self.image
else: else:
method = Image.BILINEAR method = Image.BILINEAR
if stretch: # if stretching call directly resize() without other considerations. if stretch: # If stretching call directly resize() without other considerations.
self.image = self.image.resize(size, method) self.image = self.image.resize(size, method)
if generateBorder:
if fill == 'white':
border = ImageOps.invert(self.image).getbbox()
else:
border = self.image.getbbox()
if border is not None:
if (border[2]-border[0])*1.5 < self.size[0]:
self.noHPV = True
if (border[3]-border[1])*1.5 < self.size[1]:
self.noVPV = True
self.border = [int(round(float(border[0])/float(self.image.size[0])*100, 2)*100*1.5),
int(round(float(border[1])/float(self.image.size[1])*100, 2)*100*1.5)]
else:
self.border = [0, 0]
self.noHPV = True
self.noVPV = True
return self.image return self.image
ratioDev = float(self.size[0]) / float(self.size[1]) ratioDev = float(self.size[0]) / float(self.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:
if isSplit and landscapeMode: 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)
tempImg = Image.new(self.image.mode, (self.image.size[0] + diff, self.image.size[1]), fill)
if toRight:
tempImg.paste(self.image, (diff, 0))
else:
tempImg.paste(self.image, (0, 0))
self.image = tempImg
else:
diff = int(self.image.size[1] * ratioDev) - self.image.size[0]
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)
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):
width, height = self.image.size width, height = self.image.size
dstwidth, dstheight = self.size dstwidth, dstheight = self.size
#print "Image is %d x %d" % (width,height) # Only split if origin is not oriented the same as target
# only split if origin is not oriented the same as target
if (width > height) != (dstwidth > dstheight): if (width > height) != (dstwidth > dstheight):
if rotate: if rotate:
self.image = self.image.rotate(90) self.image = self.image.rotate(90)
return "R" self.rotated = True
return None
else: else:
self.rotated = False
if width > height: if width > height:
# source is landscape, so split by the width # Source is landscape, so split by the width
leftbox = (0, 0, width / 2, height) leftbox = (0, 0, width / 2, height)
rightbox = (width / 2, 0, width, height) rightbox = (width / 2, 0, width, height)
else: else:
# source is portrait and target is landscape, so split by the height # Source is portrait and target is landscape, so split by the height
leftbox = (0, 0, width, height / 2) leftbox = (0, 0, width, height / 2)
rightbox = (0, height / 2, width, height) rightbox = (0, height / 2, width, height)
filename = os.path.splitext(os.path.basename(self.origFileName)) filename = os.path.splitext(self.filename)
fileone = targetdir + '/' + filename[0] + '_kcca' + filename[1] fileone = targetdir + '/' + filename[0] + '_kcca' + filename[1]
filetwo = targetdir + '/' + filename[0] + '_kccb' + filename[1] filetwo = targetdir + '/' + filename[0] + '_kccb' + filename[1]
try: try:
@@ -242,6 +318,7 @@ class ComicPage:
raise RuntimeError('Cannot write image in directory %s: %s' % (targetdir, e)) raise RuntimeError('Cannot write image in directory %s: %s' % (targetdir, e))
return fileone, filetwo return fileone, filetwo
else: else:
self.rotated = False
return None return None
def cutPageNumber(self): def cutPageNumber(self):
@@ -337,4 +414,48 @@ class ComicPage:
# print "Right crop: %s"%diff # print "Right crop: %s"%diff
self.image = self.image.crop((0, 0, widthImg - diff, heightImg)) self.image = self.image.crop((0, 0, widthImg - diff, heightImg))
# print "New size: %sx%s"%(self.image.size[0],self.image.size[1]) # print "New size: %sx%s"%(self.image.size[0],self.image.size[1])
return self.image return self.image
def getImageHistogram(self, image):
histogram = image.histogram()
RBGW = []
pixelCount = 0
for i in range(256):
pixelCount += histogram[i] + histogram[256 + i] + histogram[512 + i]
RBGW.append(histogram[i] + histogram[256 + i] + histogram[512 + i])
white = 0
black = 0
for i in range(245, 256):
white += RBGW[i]
for i in range(11):
black += RBGW[i]
if black > white and black > pixelCount*0.5:
return True
else:
return False
def getImageFill(self, isWebToon):
fill = 0
if isWebToon or self.rotated:
fill += self.getImageHistogram(self.image.crop((0, 0, self.image.size[0], 5)))
fill += self.getImageHistogram(self.image.crop((0, self.image.size[1]-5, self.image.size[0],
self.image.size[1])))
else:
fill += self.getImageHistogram(self.image.crop((0, 0, 5, self.image.size[1])))
fill += self.getImageHistogram(self.image.crop((self.image.size[0]-5, 0, self.image.size[0],
self.image.size[1])))
if fill == 2:
self.fill = 'black'
elif fill == 0:
self.fill = 'white'
else:
fill = 0
fill += self.getImageHistogram(self.image.crop((0, 0, 5, 5)))
fill += self.getImageHistogram(self.image.crop((self.image.size[0]-5, 0, self.image.size[0], 5)))
fill += self.getImageHistogram(self.image.crop((0, self.image.size[1]-5, 5, self.image.size[1])))
fill += self.getImageHistogram(self.image.crop((self.image.size[0]-5, self.image.size[1]-5,
self.image.size[0], self.image.size[1])))
if fill > 1:
self.fill = 'black'
else:
self.fill = 'white'

384
kcc/kindlesplit.py Normal file
View File

@@ -0,0 +1,384 @@
# Based on initial version of KindleUnpack. Copyright (C) 2009 Charles M. Hannum <root@ihack.net>
# Improvements Copyright (C) 2009-2012 P. Durrant, K. Hendricks, S. Siebert, fandrieu, DiapDealer, nickredding
# Copyright (C) 2013 Pawel Jastrzebski <pawelj@vulturis.eu>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
__license__ = 'ISC'
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
__docformat__ = 'restructuredtext en'
import struct
# from uuid import uuid4
# important pdb header offsets
unique_id_seed = 68
number_of_pdb_records = 76
# important palmdoc header offsets
book_length = 4
book_record_count = 8
first_pdb_record = 78
# important rec0 offsets
length_of_book = 4
mobi_header_base = 16
mobi_header_length = 20
mobi_type = 24
mobi_version = 36
first_non_text = 80
title_offset = 84
first_image_record = 108
first_content_index = 192
last_content_index = 194
kf8_last_content_index = 192 # for KF8 mobi headers
fcis_index = 200
flis_index = 208
srcs_index = 224
srcs_count = 228
primary_index = 244
datp_index = 256
huffoff = 112
hufftbloff = 120
def getint(datain, ofs, sz='L'):
i, = struct.unpack_from('>'+sz, datain, ofs)
return i
def writeint(datain, ofs, n, length='L'):
if length == 'L':
return datain[:ofs]+struct.pack('>L', n)+datain[ofs+4:]
else:
return datain[:ofs]+struct.pack('>H', n)+datain[ofs+2:]
def getsecaddr(datain, secno):
nsec = getint(datain, number_of_pdb_records, 'H')
assert secno >= 0 & secno < nsec, 'secno %d out of range (nsec=%d)' % (secno, nsec)
secstart = getint(datain, first_pdb_record+secno*8)
if secno == nsec-1:
secend = len(datain)
else:
secend = getint(datain, first_pdb_record+(secno+1)*8)
return secstart, secend
def readsection(datain, secno):
secstart, secend = getsecaddr(datain, secno)
return datain[secstart:secend]
def writesection(datain, secno, secdata): # overwrite, accounting for different length
dataout = deletesectionrange(datain, secno, secno)
return insertsection(dataout, secno, secdata)
def nullsection(datain, secno): # make it zero-length without deleting it
datalst = []
nsec = getint(datain, number_of_pdb_records, 'H')
secstart, secend = getsecaddr(datain, secno)
zerosecstart, zerosecend = getsecaddr(datain, 0)
dif = secend-secstart
datalst.append(datain[:first_pdb_record])
for i in range(0, secno+1):
ofs, flgval = struct.unpack_from('>2L', datain, first_pdb_record+i*8)
datalst.append(struct.pack('>L', ofs) + struct.pack('>L', flgval))
for i in range(secno+1, nsec):
ofs, flgval = struct.unpack_from('>2L', datain, first_pdb_record+i*8)
ofs -= dif
datalst.append(struct.pack('>L', ofs) + struct.pack('>L', flgval))
lpad = zerosecstart - (first_pdb_record + 8*nsec)
if lpad > 0:
datalst.append('\0' * lpad)
datalst.append(datain[zerosecstart: secstart])
datalst.append(datain[secend:])
dataout = "".join(datalst)
return dataout
def deletesectionrange(datain, firstsec, lastsec): # delete a range of sections
datalst = []
firstsecstart, firstsecend = getsecaddr(datain, firstsec)
lastsecstart, lastsecend = getsecaddr(datain, lastsec)
zerosecstart, zerosecend = getsecaddr(datain, 0)
dif = lastsecend - firstsecstart + 8*(lastsec-firstsec+1)
nsec = getint(datain, number_of_pdb_records, 'H')
datalst.append(datain[:unique_id_seed])
datalst.append(struct.pack('>L', 2*(nsec-(lastsec-firstsec+1))+1))
datalst.append(datain[unique_id_seed+4:number_of_pdb_records])
datalst.append(struct.pack('>H', nsec-(lastsec-firstsec+1)))
newstart = zerosecstart - 8*(lastsec-firstsec+1)
for i in range(0, firstsec):
ofs, flgval = struct.unpack_from('>2L', datain, first_pdb_record+i*8)
ofs -= 8 * (lastsec - firstsec + 1)
datalst.append(struct.pack('>L', ofs) + struct.pack('>L', flgval))
for i in range(lastsec+1, nsec):
ofs, flgval = struct.unpack_from('>2L', datain, first_pdb_record+i*8)
ofs -= dif
flgval = 2*(i-(lastsec-firstsec+1))
datalst.append(struct.pack('>L', ofs) + struct.pack('>L', flgval))
lpad = newstart - (first_pdb_record + 8*(nsec - (lastsec - firstsec + 1)))
if lpad > 0:
datalst.append('\0' * lpad)
datalst.append(datain[zerosecstart:firstsecstart])
datalst.append(datain[lastsecend:])
dataout = "".join(datalst)
return dataout
def insertsection(datain, secno, secdata): # insert a new section
datalst = []
nsec = getint(datain, number_of_pdb_records, 'H')
secstart, secend = getsecaddr(datain, secno)
zerosecstart, zerosecend = getsecaddr(datain, 0)
dif = len(secdata)
datalst.append(datain[:unique_id_seed])
datalst.append(struct.pack('>L', 2*(nsec+1)+1))
datalst.append(datain[unique_id_seed+4:number_of_pdb_records])
datalst.append(struct.pack('>H', nsec+1))
newstart = zerosecstart + 8
for i in range(0, secno):
ofs, flgval = struct.unpack_from('>2L', datain, first_pdb_record+i*8)
ofs += 8
datalst.append(struct.pack('>L', ofs) + struct.pack('>L', flgval))
datalst.append(struct.pack('>L', secstart + 8) + struct.pack('>L', (2*secno)))
for i in range(secno, nsec):
ofs, flgval = struct.unpack_from('>2L', datain, first_pdb_record+i*8)
ofs = ofs + dif + 8
flgval = 2*(i+1)
datalst.append(struct.pack('>L', ofs) + struct.pack('>L', flgval))
lpad = newstart - (first_pdb_record + 8*(nsec + 1))
if lpad > 0:
datalst.append('\0' * lpad)
datalst.append(datain[zerosecstart:secstart])
datalst.append(secdata)
datalst.append(datain[secstart:])
dataout = "".join(datalst)
return dataout
def insertsectionrange(sectionsource, firstsec, lastsec, sectiontarget, targetsec): # insert a range of sections
dataout = sectiontarget
for idx in range(lastsec, firstsec-1, -1):
dataout = insertsection(dataout, targetsec, readsection(sectionsource, idx))
return dataout
def get_exth_params(rec0):
ebase = mobi_header_base + getint(rec0, mobi_header_length)
elen = getint(rec0, ebase+4)
enum = getint(rec0, ebase+8)
return ebase, elen, enum
def add_exth(rec0, exth_num, exth_bytes):
ebase, elen, enum = get_exth_params(rec0)
newrecsize = 8+len(exth_bytes)
newrec0 = rec0[0:ebase+4]+struct.pack('>L', elen+newrecsize)+struct.pack('>L', enum+1) +\
struct.pack('>L', exth_num) + struct.pack('>L', newrecsize)+exth_bytes+rec0[ebase+12:]
newrec0 = writeint(newrec0, title_offset, getint(newrec0, title_offset)+newrecsize)
return newrec0
def read_exth(rec0, exth_num):
exth_values = []
ebase, elen, enum = get_exth_params(rec0)
ebase += 12
while enum > 0:
exth_id = getint(rec0, ebase)
if exth_id == exth_num:
# We might have multiple exths, so build a list.
exth_values.append(rec0[ebase+8:ebase+getint(rec0, ebase+4)])
enum -= 1
ebase = ebase+getint(rec0, ebase+4)
return exth_values
def write_exth(rec0, exth_num, exth_bytes):
ebase, elen, enum = get_exth_params(rec0)
ebase_idx = ebase+12
enum_idx = enum
while enum_idx > 0:
exth_id = getint(rec0, ebase_idx)
if exth_id == exth_num:
dif = len(exth_bytes)+8-getint(rec0, ebase_idx+4)
newrec0 = rec0
if dif != 0:
newrec0 = writeint(newrec0, title_offset, getint(newrec0, title_offset)+dif)
return newrec0[:ebase+4]+struct.pack('>L', elen+len(exth_bytes)+8-getint(rec0, ebase_idx+4)) +\
struct.pack('>L', enum)+rec0[ebase+12:ebase_idx+4] +\
struct.pack('>L', len(exth_bytes)+8)+exth_bytes +\
rec0[ebase_idx+getint(rec0, ebase_idx+4):]
enum_idx -= 1
ebase_idx = ebase_idx+getint(rec0, ebase_idx+4)
return rec0
def del_exth(rec0, exth_num):
ebase, elen, enum = get_exth_params(rec0)
ebase_idx = ebase+12
enum_idx = 0
while enum_idx < enum:
exth_id = getint(rec0, ebase_idx)
exth_size = getint(rec0, ebase_idx+4)
if exth_id == exth_num:
newrec0 = rec0
newrec0 = writeint(newrec0, title_offset, getint(newrec0, title_offset)-exth_size)
newrec0 = newrec0[:ebase_idx]+newrec0[ebase_idx+exth_size:]
newrec0 = newrec0[0:ebase+4]+struct.pack('>L', elen-exth_size)+struct.pack('>L', enum-1)+newrec0[ebase+12:]
return newrec0
enum_idx += 1
ebase_idx = ebase_idx+exth_size
return rec0
class mobi_split:
def __init__(self, infile, newKindle):
try:
datain = open(infile, 'rb').read()
datain_rec0 = readsection(datain, 0)
ver = getint(datain_rec0, mobi_version)
# fake_asin = str(uuid4())
self.combo = (ver != 8)
if not self.combo:
return
exth121 = read_exth(datain_rec0, 121)
if len(exth121) == 0:
self.combo = False
return
else:
# only pay attention to first exth121
# (there should only be one)
datain_kf8, = struct.unpack_from('>L', exth121[0], 0)
if datain_kf8 == 0xffffffff:
self.combo = False
return
datain_kfrec0 = readsection(datain, datain_kf8)
firstimage = getint(datain_rec0, first_image_record)
lastimage = getint(datain_rec0, last_content_index, 'H')
if not newKindle:
# create the standalone mobi7
num_sec = getint(datain, number_of_pdb_records, 'H')
# remove BOUNDARY up to but not including ELF record
self.result_file = deletesectionrange(datain, datain_kf8-1, num_sec-2)
# check if there are SRCS records and delete them
srcs = getint(datain_rec0, srcs_index)
num_srcs = getint(datain_rec0, srcs_count)
if srcs != 0xffffffff and num_srcs > 0:
self.result_file = deletesectionrange(self.result_file, srcs, srcs+num_srcs-1)
datain_rec0 = writeint(datain_rec0, srcs_index, 0xffffffff)
datain_rec0 = writeint(datain_rec0, srcs_count, 0)
# reset the EXTH 121 KF8 Boundary meta data to 0xffffffff
datain_rec0 = write_exth(datain_rec0, 121, struct.pack('>L', 0xffffffff))
# datain_rec0 = del_exth(datain_rec0,121)
# datain_rec0 = del_exth(datain_rec0,534)
# don't remove the EXTH 125 KF8 Count of Resources, seems to be present in mobi6 files as well
# set the EXTH 129 KF8 Masthead / Cover Image string to the null string
datain_rec0 = write_exth(datain_rec0, 129, '')
# don't remove the EXTH 131 KF8 Unidentified Count, seems to be present in mobi6 files as well
# Make sure we have an ASIN & cdeType set...
# if len(read_exth(datain_rec0, 113)) == 0:
# datain_rec0 = add_exth(datain_rec0, 113, fake_asin)
# if len(read_exth(datain_rec0, 504)) == 0:
# datain_rec0 = add_exth(datain_rec0, 504, fake_asin)
if len(read_exth(datain_rec0, 501)) == 0:
datain_rec0 = add_exth(datain_rec0, 501, b'EBOK')
# need to reset flags stored in 0x80-0x83
# old mobi with exth: 0x50, mobi7 part with exth: 0x1850, mobi8 part with exth: 0x1050
# Bit Flags
# 0x1000 = Bit 12 indicates if embedded fonts are used or not
# 0x0800 = means this Header points to *shared* images/resource/fonts ??
# 0x0080 = unknown new flag, why is this now being set by Kindlegen 2.8?
# 0x0040 = exth exists
# 0x0010 = Not sure but this is always set so far
fval, = struct.unpack_from('>L', datain_rec0, 0x80)
# need to remove flag 0x0800 for KindlePreviewer 2.8 and unset Bit 12 for embedded fonts
fval &= 0x07FF
datain_rec0 = datain_rec0[:0x80] + struct.pack('>L', fval) + datain_rec0[0x84:]
self.result_file = writesection(self.result_file, 0, datain_rec0)
if lastimage == 0xffff:
# find the lowest of the next sections and copy up to that.
ofs_list = [(kf8_last_content_index, 'L'), (fcis_index, 'L'), (flis_index, 'L'), (datp_index, 'L'),
(hufftbloff, 'L')]
for ofs, sz in ofs_list:
n = getint(datain_kfrec0, ofs, sz)
if 0 < n < lastimage:
lastimage = n-1
# Try to null out FONT and RES, but leave the (empty) PDB record so image refs remain valid
for i in range(firstimage, lastimage):
imgsec = readsection(self.result_file, i)
if imgsec[0:4] in ['RESC', 'FONT']:
self.result_file = nullsection(self.result_file, i)
# mobi7 finished
else:
# create standalone mobi8
self.result_file = deletesectionrange(datain, 0, datain_kf8-1)
target = getint(datain_kfrec0, first_image_record)
self.result_file = insertsectionrange(datain, firstimage, lastimage, self.result_file, target)
datain_kfrec0 = readsection(self.result_file, 0)
# Only keep the correct EXTH 116 StartOffset, KG 2.5 carries over the one from the mobi7 part,
# which then points at garbage in the mobi8 part, and confuses FW 3.4
kf8starts = read_exth(datain_kfrec0, 116)
# If we have multiple StartOffset, keep only the last one
kf8start_count = len(kf8starts)
while kf8start_count > 1:
kf8start_count -= 1
datain_kfrec0 = del_exth(datain_kfrec0, 116)
# update the EXTH 125 KF8 Count of Images/Fonts/Resources
datain_kfrec0 = write_exth(datain_kfrec0, 125, struct.pack('>L', lastimage-firstimage+1))
# Same dance for the KF8, we want an ASIN & cdeType :)
# if len(read_exth(datain_kfrec0, 113)) == 0:
# datain_kfrec0 = add_exth(datain_kfrec0, 113, fake_asin)
# if len(read_exth(datain_kfrec0, 504)) == 0:
# datain_kfrec0 = add_exth(datain_kfrec0, 504, fake_asin)
if len(read_exth(datain_kfrec0, 501)) == 0:
datain_kfrec0 = add_exth(datain_kfrec0, 501, b'EBOK')
# need to reset flags stored in 0x80-0x83
# old mobi with exth: 0x50, mobi7 part with exth: 0x1850, mobi8 part with exth: 0x1050
# standalone mobi8 with exth: 0x0050
# Bit Flags
# 0x1000 = Bit 12 indicates if embedded fonts are used or not
# 0x0800 = means this Header points to *shared* images/resource/fonts ??
# 0x0080 = unknown new flag, why is this now being set by Kindlegen 2.8?
# 0x0040 = exth exists
# 0x0010 = Not sure but this is always set so far
fval, = struct.unpack_from('>L', datain_kfrec0, 0x80)
fval &= 0x1FFF
fval |= 0x0800
datain_kfrec0 = datain_kfrec0[:0x80] + struct.pack('>L', fval) + datain_kfrec0[0x84:]
# properly update other index pointers that have been shifted by the insertion of images
ofs_list = [(kf8_last_content_index, 'L'), (fcis_index, 'L'), (flis_index, 'L'), (datp_index, 'L'),
(hufftbloff, 'L')]
for ofs, sz in ofs_list:
n = getint(datain_kfrec0, ofs, sz)
if n != 0xffffffff:
datain_kfrec0 = writeint(datain_kfrec0, ofs, n+lastimage-firstimage+1, sz)
self.result_file = writesection(self.result_file, 0, datain_kfrec0)
# mobi8 finished
except Exception:
raise
def getResult(self):
return self.result_file

View File

@@ -1,236 +0,0 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
#
# This is a python script. You need a Python interpreter to run it.
# For example, ActiveState Python, which exists for windows.
#
# This script strips the penultimate record from a Mobipocket file.
# This is useful because the current KindleGen add a compressed copy
# of the source files used in this record, making the ebook produced
# about twice as big as it needs to be.
#
#
# This is free and unencumbered software released into the public domain.
#
# Anyone is free to copy, modify, publish, use, compile, sell, or
# distribute this software, either in source code form or as a compiled
# binary, for any purpose, commercial or non-commercial, and by any
# means.
#
# In jurisdictions that recognize copyright laws, the author or authors
# of this software dedicate any and all copyright interest in the
# software to the public domain. We make this dedication for the benefit
# of the public at large and to the detriment of our heirs and
# successors. We intend this dedication to be an overt act of
# relinquishment in perpetuity of all present and future rights to this
# software under copyright law.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
#
# For more information, please refer to <http://unlicense.org/>
#
# Written by Paul Durrant, 2010-2011, paul@durrant.co.uk, pdurrant on mobileread.com
# With enhancements by Kevin Hendricks, KevinH on mobileread.com
#
# Changelog
# 1.00 - Initial version
# 1.10 - Added an option to output the stripped data
# 1.20 - Added check for source files section (thanks Piquan)
# 1.30 - Added prelim Support for K8 style mobis
# 1.31 - removed the SRCS section but kept a 0 size entry for it
# 1.32 - removes the SRCS section and its entry, now updates metadata 121 if needed
# 1.33 - now uses and modifies mobiheader SRCS and CNT
# 1.34 - added credit for Kevin Hendricks
# 1.35 - fixed bug when more than one compilation (SRCS/CMET) records
__version__ = '1.35'
import sys
import struct
import binascii
class Unbuffered:
def __init__(self, stream):
self.stream = stream
def write(self, data):
self.stream.write(data)
self.stream.flush()
def __getattr__(self, attr):
return getattr(self.stream, attr)
class StripException(Exception):
pass
class SectionStripper:
def loadSection(self, section):
if (section + 1 == self.num_sections):
endoff = len(self.data_file)
else:
endoff = self.sections[section + 1][0]
off = self.sections[section][0]
return self.data_file[off:endoff]
def patch(self, off, new):
self.data_file = self.data_file[:off] + new + self.data_file[off+len(new):]
def strip(self, off, len):
self.data_file = self.data_file[:off] + self.data_file[off+len:]
def patchSection(self, section, new, in_off = 0):
if (section + 1 == self.num_sections):
endoff = len(self.data_file)
else:
endoff = self.sections[section + 1][0]
off = self.sections[section][0]
assert off + in_off + len(new) <= endoff
self.patch(off + in_off, new)
def updateEXTH121(self, srcs_secnum, srcs_cnt, mobiheader):
mobi_length, = struct.unpack('>L',mobiheader[0x14:0x18])
exth_flag, = struct.unpack('>L', mobiheader[0x80:0x84])
exth = 'NONE'
try:
if exth_flag & 0x40:
exth = mobiheader[16 + mobi_length:]
if (len(exth) >= 4) and (exth[:4] == 'EXTH'):
nitems, = struct.unpack('>I', exth[8:12])
pos = 12
for i in xrange(nitems):
type, size = struct.unpack('>II', exth[pos: pos + 8])
# print type, size
if type == 121:
boundaryptr, =struct.unpack('>L',exth[pos+8: pos + size])
if srcs_secnum <= boundaryptr:
boundaryptr -= srcs_cnt
prefix = mobiheader[0:16 + mobi_length + pos + 8]
suffix = mobiheader[16 + mobi_length + pos + 8 + 4:]
nval = struct.pack('>L',boundaryptr)
mobiheader = prefix + nval + suffix
pos += size
except:
pass
return mobiheader
def __init__(self, datain):
if datain[0x3C:0x3C+8] != 'BOOKMOBI':
raise StripException("invalid file format")
self.num_sections, = struct.unpack('>H', datain[76:78])
# get mobiheader and check SRCS section number and count
offset0, = struct.unpack_from('>L', datain, 78)
offset1, = struct.unpack_from('>L', datain, 86)
mobiheader = datain[offset0:offset1]
srcs_secnum, srcs_cnt = struct.unpack_from('>2L', mobiheader, 0xe0)
if srcs_secnum == 0xffffffff or srcs_cnt == 0:
raise StripException("File doesn't contain the sources section.")
print "Found SRCS section number %d, and count %d" % (srcs_secnum, srcs_cnt)
# find its offset and length
next = srcs_secnum + srcs_cnt
srcs_offset, flgval = struct.unpack_from('>2L', datain, 78+(srcs_secnum*8))
next_offset, flgval = struct.unpack_from('>2L', datain, 78+(next*8))
srcs_length = next_offset - srcs_offset
if datain[srcs_offset:srcs_offset+4] != 'SRCS':
raise StripException("SRCS section num does not point to SRCS.")
print " beginning at offset %0x and ending at offset %0x" % (srcs_offset, srcs_length)
# it appears bytes 68-71 always contain (2*num_sections) + 1
# this is not documented anyplace at all but it appears to be some sort of next
# available unique_id used to identify specific sections in the palm db
self.data_file = datain[:68] + struct.pack('>L',((self.num_sections-srcs_cnt)*2+1))
self.data_file += datain[72:76]
# write out the number of sections reduced by srtcs_cnt
self.data_file = self.data_file + struct.pack('>H',self.num_sections-srcs_cnt)
# we are going to remove srcs_cnt SRCS sections so the offset of every entry in the table
# up to the srcs secnum must begin 8 bytes earlier per section removed (each table entry is 8 )
delta = -8 * srcs_cnt
for i in xrange(srcs_secnum):
offset, flgval = struct.unpack_from('>2L', datain, 78+(i*8))
offset += delta
self.data_file += struct.pack('>L',offset) + struct.pack('>L',flgval)
# for every record after the srcs_cnt SRCS records we must start it
# earlier by 8*srcs_cnt + the length of the srcs sections themselves)
delta = delta - srcs_length
for i in xrange(srcs_secnum+srcs_cnt,self.num_sections):
offset, flgval = struct.unpack_from('>2L', datain, 78+(i*8))
offset += delta
flgval = 2 * (i - srcs_cnt)
self.data_file += struct.pack('>L',offset) + struct.pack('>L',flgval)
# now pad it out to begin right at the first offset
# typically this is 2 bytes of nulls
first_offset, flgval = struct.unpack_from('>2L', self.data_file, 78)
self.data_file += '\0' * (first_offset - len(self.data_file))
# now finally add on every thing up to the original src_offset
self.data_file += datain[offset0: srcs_offset]
# and everything afterwards
self.data_file += datain[srcs_offset+srcs_length:]
#store away the SRCS section in case the user wants it output
self.stripped_data_header = datain[srcs_offset:srcs_offset+16]
self.stripped_data = datain[srcs_offset+16:srcs_offset+srcs_length]
# update the number of sections count
self.num_section = self.num_sections - srcs_cnt
# update the srcs_secnum and srcs_cnt in the mobiheader
offset0, flgval0 = struct.unpack_from('>2L', self.data_file, 78)
offset1, flgval1 = struct.unpack_from('>2L', self.data_file, 86)
mobiheader = self.data_file[offset0:offset1]
mobiheader = mobiheader[:0xe0]+ struct.pack('>L', 0xffffffff) + struct.pack('>L', 0) + mobiheader[0xe8:]
# if K8 mobi, handle metadata 121 in old mobiheader
mobiheader = self.updateEXTH121(srcs_secnum, srcs_cnt, mobiheader)
self.data_file = self.data_file[0:offset0] + mobiheader + self.data_file[offset1:]
print "done"
def getResult(self):
return self.data_file
def getStrippedData(self):
return self.stripped_data
def getHeader(self):
return self.stripped_data_header
def main(argv=None):
infile = argv[0]
outfile = argv[1]
data_file = file(infile, 'rb').read()
try:
strippedFile = SectionStripper(data_file)
file(outfile, 'wb').write(strippedFile.getResult())
print "Header Bytes: " + binascii.b2a_hex(strippedFile.getHeader())
if len(argv)==3:
file(argv[2], 'wb').write(strippedFile.getStrippedData())
except StripException, e:
print "Error: %s" % e
sys.exit(1)
if __name__ == "__main__":
sys.stdout=Unbuffered(sys.stdout)
print ('KindleStrip v%(__version__)s. '
'Written 2010-2012 by Paul Durrant and Kevin Hendricks.' % globals())
if len(sys.argv)<3 or len(sys.argv)>4:
print "Strips the Sources record from Mobipocket ebooks"
print "For ebooks generated using KindleGen 1.1 and later that add the source"
print "Usage:"
print " %s <infile> <outfile> <strippeddatafile>" % sys.argv[0]
print "<strippeddatafile> is optional."
sys.exit(1)
else:
main(sys.argv[1:])
sys.exit(0)

View File

@@ -1,4 +1,5 @@
# Copyright (c) 2012 Ciro Mattia Gonano <ciromattia@gmail.com> # Copyright (c) 2012-2013 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (c) 2013 Pawel Jastrzebski <pawelj@vulturis.eu>
# #
# Based upon the code snippet by Ned Batchelder # Based upon the code snippet by Ned Batchelder
# (http://nedbatchelder.com/blog/200712/extracting_jpgs_from_pdfs.html) # (http://nedbatchelder.com/blog/200712/extracting_jpgs_from_pdfs.html)
@@ -29,7 +30,7 @@ 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] self.path = self.filename[0] + "-KCC-TMP"
def getPath(self): def getPath(self):
return self.path return self.path
@@ -70,4 +71,4 @@ class PdfJpgExtract:
njpg += 1 njpg += 1
i = iend i = iend
return self.path return self.path, njpg

View File

@@ -0,0 +1,91 @@
****** ***** ****** UnRAR - free utility for RAR archives
** ** ** ** ** ** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
****** ******* ****** License for use and distribution of
** ** ** ** ** ** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
** ** ** ** ** ** FREEWARE version
~~~~~~~~~~~~~~~~
The UnRAR utility is freeware. This means:
1. All copyrights to RAR and the utility UnRAR are exclusively
owned by the author - Alexander Roshal.
2. The UnRAR utility may be freely distributed. It is allowed
to distribute UnRAR inside of other software packages.
3. THE RAR ARCHIVER AND THE UnRAR UTILITY ARE DISTRIBUTED "AS IS".
NO WARRANTY OF ANY KIND IS EXPRESSED OR IMPLIED. YOU USE AT
YOUR OWN RISK. THE AUTHOR WILL NOT BE LIABLE FOR DATA LOSS,
DAMAGES, LOSS OF PROFITS OR ANY OTHER KIND OF LOSS WHILE USING
OR MISUSING THIS SOFTWARE.
4. Neither RAR binary code, WinRAR binary code, UnRAR source or UnRAR
binary code may be used or reverse engineered to re-create the RAR
compression algorithm, which is proprietary, without written
permission of the author.
5. If you don't agree with terms of the license you must remove
UnRAR files from your storage devices and cease to use the
utility.
Thank you for your interest in RAR and UnRAR.
Alexander L. Roshal
7-Zip
~~~~~
License for use and distribution
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7-Zip Copyright (C) 1999-2012 Igor Pavlov.
Licenses for files are:
1) 7z.dll: GNU LGPL + unRAR restriction
2) All other files: GNU LGPL
The GNU LGPL + unRAR restriction means that you must follow both
GNU LGPL rules and unRAR restriction rules.
Note:
You can use 7-Zip on any computer, including a computer in a commercial
organization. You don't need to register or pay for 7-Zip.
GNU LGPL information
--------------------
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You can receive a copy of the GNU Lesser General Public License from
http://www.gnu.org/
unRAR restriction
-----------------
The decompression engine for RAR archives was developed using source
code of unRAR program.
All copyrights to original unRAR code are owned by Alexander Roshal.
The license for original unRAR code has the following restriction:
The unRAR sources cannot be used to re-create the RAR compression algorithm,
which is proprietary. Distribution of modified unRAR sources in separate form
or as a part of other software is permitted, provided that it is clearly
stated in the documentation and source comments that the code may
not be used to develop a RAR (WinRAR) compatible archiver.
--
Igor Pavlov

View File

@@ -10,7 +10,7 @@ Usage (Windows):
from sys import platform from sys import platform
NAME = "KindleComicConverter" NAME = "KindleComicConverter"
VERSION = "3.0" VERSION = "3.3"
MAIN = "kcc.py" MAIN = "kcc.py"
if platform == "darwin": if platform == "darwin":
@@ -41,7 +41,11 @@ elif platform == "win32":
from cx_Freeze import setup, Executable from cx_Freeze import setup, Executable
base = "Win32GUI" base = "Win32GUI"
extra_options = dict( extra_options = dict(
options={"build_exe": {"include_files": ['LICENSE.txt'], "compressed": True}}, options={"build_exe": {"include_files": ['LICENSE.txt',
['other/UnRAR.exe', 'UnRAR.exe'],
['other/7za.exe', '7za.exe'],
['other/Additional-LICENSE.txt', 'Additional-LICENSE.txt']
], "compressed": True}},
executables=[Executable(MAIN, executables=[Executable(MAIN,
base=base, base=base,
targetName="KCC.exe", targetName="KCC.exe",