1
0
mirror of https://github.com/ciromattia/kcc synced 2025-12-13 09:46:25 +00:00

Merge branch 'v3.3'

This commit is contained in:
Paweł Jastrzębski
2013-09-29 10:35:20 +02:00
20 changed files with 2340 additions and 745 deletions

3
.gitignore vendored
View File

@@ -7,4 +7,5 @@ dist
kindlegen*
.DS_Store
Thumbs.db
UnRAR.exe
/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 name="geometry">
<rect>
<x>9</x>
<x>4</x>
<y>253</y>
<width>421</width>
<height>61</height>
@@ -55,6 +55,7 @@
</property>
<property name="font">
<font>
<family>Lucida Grande</family>
<pointsize>9</pointsize>
</font>
</property>
@@ -63,7 +64,8 @@
<widget class="QCheckBox" name="ProcessingBox">
<property name="font">
<font>
<pointsize>11</pointsize>
<family>Lucida Grande</family>
<pointsize>12</pointsize>
</font>
</property>
<property name="focusPolicy">
@@ -81,14 +83,15 @@
<widget class="QCheckBox" name="UpscaleBox">
<property name="font">
<font>
<pointsize>11</pointsize>
<family>Lucida Grande</family>
<pointsize>12</pointsize>
</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>
<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 name="text">
<string>Stretch/Upscale</string>
@@ -102,14 +105,15 @@
<widget class="QCheckBox" name="WebtoonBox">
<property name="font">
<font>
<pointsize>11</pointsize>
<family>Lucida Grande</family>
<pointsize>12</pointsize>
</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;&quot;&gt;EXPERIMENTAL!&lt;br/&gt;&lt;/span&gt;Enable auto-splitting of webtoons like &lt;span style=&quot; font-style:italic;&quot;&gt;Tower of God&lt;/span&gt; or &lt;span style=&quot; font-style:italic;&quot;&gt;Noblesse&lt;/span&gt;.&lt;br/&gt;Pages with a low width, high height and vertical panel flow.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&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 name="text">
<string>Webtoon mode</string>
@@ -120,14 +124,15 @@
<widget class="QCheckBox" name="NoDitheringBox">
<property name="font">
<font>
<pointsize>11</pointsize>
<family>Lucida Grande</family>
<pointsize>12</pointsize>
</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-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 name="text">
<string>PNG output</string>
@@ -138,17 +143,21 @@
<widget class="QCheckBox" name="BorderBox">
<property name="font">
<font>
<pointsize>11</pointsize>
<family>Lucida Grande</family>
<pointsize>12</pointsize>
</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-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 name="text">
<string>Black borders</string>
<string>W/B margins</string>
</property>
<property name="tristate">
<bool>true</bool>
</property>
</widget>
</item>
@@ -156,7 +165,8 @@
<widget class="QCheckBox" name="NoRotateBox">
<property name="font">
<font>
<pointsize>11</pointsize>
<family>Lucida Grande</family>
<pointsize>12</pointsize>
</font>
</property>
<property name="focusPolicy">
@@ -183,6 +193,7 @@
</property>
<property name="font">
<font>
<family>Lucida Grande</family>
<pointsize>11</pointsize>
</font>
</property>
@@ -190,7 +201,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Target device.</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&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>
</widget>
<widget class="QComboBox" name="FormatBox">
@@ -204,6 +215,7 @@
</property>
<property name="font">
<font>
<family>Lucida Grande</family>
<pointsize>11</pointsize>
</font>
</property>
@@ -211,7 +223,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>Output format.</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&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>
</widget>
<widget class="QPushButton" name="ConvertButton">
@@ -225,6 +237,7 @@
</property>
<property name="font">
<font>
<family>Lucida Grande</family>
<pointsize>11</pointsize>
<weight>75</weight>
<bold>true</bold>
@@ -252,6 +265,7 @@
</property>
<property name="font">
<font>
<family>Lucida Grande</family>
<pointsize>11</pointsize>
</font>
</property>
@@ -277,6 +291,7 @@
</property>
<property name="font">
<font>
<family>Lucida Grande</family>
<pointsize>11</pointsize>
</font>
</property>
@@ -302,6 +317,7 @@
</property>
<property name="font">
<font>
<family>Lucida Grande</family>
<pointsize>11</pointsize>
</font>
</property>
@@ -319,7 +335,7 @@
<widget class="QFrame" name="OptionsBasic">
<property name="geometry">
<rect>
<x>10</x>
<x>5</x>
<y>233</y>
<width>421</width>
<height>41</height>
@@ -327,7 +343,8 @@
</property>
<property name="font">
<font>
<pointsize>9</pointsize>
<family>Lucida Grande</family>
<pointsize>12</pointsize>
</font>
</property>
<widget class="QCheckBox" name="MangaBox">
@@ -341,7 +358,8 @@
</property>
<property name="font">
<font>
<pointsize>11</pointsize>
<family>Lucida Grande</family>
<pointsize>12</pointsize>
</font>
</property>
<property name="focusPolicy">
@@ -359,20 +377,21 @@
<rect>
<x>282</x>
<y>10</y>
<width>130</width>
<width>135</width>
<height>18</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>11</pointsize>
<family>Lucida Grande</family>
<pointsize>12</pointsize>
</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-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 name="text">
<string>High/Ultra quality</string>
@@ -392,7 +411,8 @@
</property>
<property name="font">
<font>
<pointsize>11</pointsize>
<family>Lucida Grande</family>
<pointsize>12</pointsize>
</font>
</property>
<property name="focusPolicy">
@@ -420,6 +440,7 @@
</property>
<property name="font">
<font>
<family>Lucida Grande</family>
<pointsize>11</pointsize>
</font>
</property>
@@ -444,6 +465,7 @@
</property>
<property name="font">
<font>
<family>Lucida Grande</family>
<pointsize>12</pointsize>
<weight>50</weight>
<bold>false</bold>
@@ -467,6 +489,7 @@
</property>
<property name="font">
<font>
<family>Lucida Grande</family>
<pointsize>12</pointsize>
<weight>50</weight>
<bold>false</bold>
@@ -485,7 +508,7 @@
</property>
<property name="geometry">
<rect>
<x>10</x>
<x>5</x>
<y>303</y>
<width>401</width>
<height>41</height>
@@ -493,6 +516,7 @@
</property>
<property name="font">
<font>
<family>Lucida Grande</family>
<pointsize>9</pointsize>
</font>
</property>
@@ -507,13 +531,14 @@
</property>
<property name="font">
<font>
<family>Lucida Grande</family>
<pointsize>12</pointsize>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;When converting color images setting this option to 1.0 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 name="text">
<string>Gamma: Auto</string>
@@ -524,10 +549,15 @@
<rect>
<x>110</x>
<y>10</y>
<width>280</width>
<width>290</width>
<height>22</height>
</rect>
</property>
<property name="font">
<font>
<family>Lucida Grande</family>
</font>
</property>
<property name="focusPolicy">
<enum>Qt::ClickFocus</enum>
</property>
@@ -556,6 +586,7 @@
</property>
<property name="font">
<font>
<family>Lucida Grande</family>
<pointsize>10</pointsize>
<weight>75</weight>
<bold>true</bold>
@@ -577,7 +608,7 @@
<widget class="QFrame" name="OptionsExpert">
<property name="geometry">
<rect>
<x>10</x>
<x>5</x>
<y>335</y>
<width>421</width>
<height>41</height>
@@ -585,6 +616,7 @@
</property>
<property name="font">
<font>
<family>Lucida Grande</family>
<pointsize>9</pointsize>
</font>
</property>
@@ -599,7 +631,8 @@
</property>
<property name="font">
<font>
<pointsize>11</pointsize>
<family>Lucida Grande</family>
<pointsize>12</pointsize>
</font>
</property>
<property name="focusPolicy">
@@ -615,17 +648,23 @@
<widget class="QFrame" name="OptionsExpertInternal">
<property name="geometry">
<rect>
<x>90</x>
<x>95</x>
<y>0</y>
<width>315</width>
<height>40</height>
</rect>
</property>
<property name="font">
<font>
<family>Lucida Grande</family>
</font>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="wLabel">
<property name="font">
<font>
<family>Lucida Grande</family>
<pointsize>12</pointsize>
<weight>50</weight>
<bold>false</bold>
@@ -655,6 +694,7 @@
</property>
<property name="font">
<font>
<family>Lucida Grande</family>
<pointsize>12</pointsize>
</font>
</property>
@@ -679,6 +719,7 @@
<widget class="QLabel" name="hLabel">
<property name="font">
<font>
<family>Lucida Grande</family>
<pointsize>12</pointsize>
<weight>50</weight>
<bold>false</bold>
@@ -708,6 +749,7 @@
</property>
<property name="font">
<font>
<family>Lucida Grande</family>
<pointsize>12</pointsize>
</font>
</property>

11
KCC.ui
View File

@@ -97,7 +97,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;EXPERIMENTAL!&lt;br/&gt;&lt;/span&gt;Enable auto-splitting of webtoons like &lt;span style=&quot; font-style:italic;&quot;&gt;Tower of God&lt;/span&gt; or &lt;span style=&quot; font-style:italic;&quot;&gt;Noblesse&lt;/span&gt;.&lt;br/&gt;Pages with a low width, high height and vertical panel flow.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable auto-splitting of webtoons like &lt;span style=&quot; font-style:italic;&quot;&gt;Tower of God&lt;/span&gt; or &lt;span style=&quot; font-style:italic;&quot;&gt;Noblesse&lt;/span&gt;.&lt;br/&gt;Pages with a low width, high height and vertical panel flow.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Webtoon mode</string>
@@ -110,7 +110,7 @@
<enum>Qt::NoFocus</enum>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Create PNG files instead JPEG.&lt;br/&gt;&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 name="text">
<string>PNG output</string>
@@ -123,10 +123,13 @@
<enum>Qt::NoFocus</enum>
</property>
<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 name="text">
<string>Black borders</string>
<string>W/B margins</string>
</property>
<property name="tristate">
<bool>true</bool>
</property>
</widget>
</item>

View File

@@ -30,11 +30,13 @@ You can find the latest released binary at the following links:
- Folders
- CBZ, ZIP
- CBR, RAR *(With `unrar` executable)*
- CB7, 7Z *(With `7za` executable)*
- PDF *(Extracting only contained JPG images)*
## OPTIONAL REQUIREMENTS
- [KindleGen](http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000765211) v2.9+ in a directory reachable by your _PATH_ or in _KCC_ directory *(For .mobi generation)*
- [UnRAR](http://www.rarlab.com/download.htm) *(For CBR/RAR support)*
- [7za](http://www.7-zip.org/download.html) *(For 7z/CB7 support)*
### For compiling/running from source:
- Python 2.7 - Included in MacOS and Linux, follow the [official documentation](http://www.python.org/getit/windows/) to install on Windows.
@@ -52,7 +54,7 @@ You can find the latest released binary at the following links:
* Check our [wiki](https://github.com/ciromattia/kcc/wiki/Other-devices) for a list of tested Non-Kindle E-Readers.
* The first image found will be set as the comic's cover.
* All files/directories will be added to EPUB in alphabetical order.
* Output MOBI file should be uploaded via USB. Other methods (e.g. via Calibre) might corrupt it.
* Output MOBI file should be uploaded via USB. Other methods might corrupt it.
### GUI
@@ -67,12 +69,10 @@ Usage: comic2ebook.py [options] comic_file|comic_folder
Options:
MAIN:
-p PROFILE, --profile=PROFILE
Device profile (Choose one among K1, K2, K3, K4NT, K4T, KDX, KDXG, KHD, KF, KFHD, KFHD8, KFA) [Default=KHD]
Device profile (Choose one among K1, K2, K345, KDX, KDXG, KHD, KF, KFHD, KFHD8, KFHDX, KFHDX8, KFA) [Default=KHD]
-q QUALITY, --quality=QUALITY
Quality of Panel View. 0 - Normal 1 - High 2 - Ultra [Default=0]
-m, --manga-style Manga style (Right-to-left reading and splitting)
EXPERIMENTAL:
-w, --webtoon Webtoon processing mode
OUTPUT SETTINGS:
@@ -84,7 +84,8 @@ Options:
--batchsplit Split output into multiple files
PROCESSING:
--blackborders Use black borders instead of white ones
--blackborders Disable autodetection and force black borders
--whiteborders Disable autodetection and force white borders
--forcecolor Don't convert images to grayscale
--forcepng Create PNG files instead JPEG (For non-Kindle devices)
--gamma=GAMMA Apply gamma correction to linearize the image [Default=Auto]
@@ -129,22 +130,20 @@ This script born as a cross-platform alternative to `KindleComicParser` by **Dc5
The app relies and includes the following scripts/binaries:
- `KindleStrip` script &copy; 2010-2012 by **Paul Durrant** and released in public domain
([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
- `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
- `KindleUnpack` script by Charles **M. Hannum, P. Durrant, K. Hendricks, S. Siebert, fandrieu, DiapDealer, nickredding**. Released with GPLv3 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.
- Icon is by **Nikolay Verin** ([http://ncrow.deviantart.com/](http://ncrow.deviantart.com/)) and released under [CC BY-NC-SA 3.0](http://creativecommons.org/licenses/by-nc-sa/3.0/) License.
## SAMPLE FILES CREATED BY KCC
* [Kindle 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](http://kcc.vulturis.eu/Samples/Ubunchu!-K345.mobi)
* [Kindle DX/DXG](http://kcc.vulturis.eu/Samples/Ubunchu!-KDX.mobi)
* [Kindle Fire](http://kcc.vulturis.eu/Samples/Ubunchu!-KF.mobi)
* [Kindle Fire HD](http://kcc.vulturis.eu/Samples/Ubunchu!-KFHD.mobi)
* [Kindle Fire HD 8.9"](http://kcc.vulturis.eu/Samples/Ubunchu!-KFHD8.mobi)
* [Kindle Fire HDX](http://kcc.vulturis.eu/Samples/Ubunchu!-KFHDX.mobi)
* [Kindle Fire HDX 8.9"](http://kcc.vulturis.eu/Samples/Ubunchu!-KFHDX8.mobi)
## CHANGELOG
####1.00
@@ -255,8 +254,19 @@ The app relies and includes the following scripts/binaries:
####3.2.1:
* Hotfixed crash occurring on OS with Russian locale
## KNOWN ISSUES
* Removing SRCS headers sometimes fail in 32bit enviroments. Due to memory limitations.
####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

10
kcc.py
View File

@@ -1,7 +1,8 @@
#!/usr/bin/env python
# -*- 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
# 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
# PERFORMANCE OF THIS SOFTWARE.
__version__ = '3.2.1'
__version__ = '3.3'
__license__ = 'ISC'
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
__docformat__ = 'restructuredtext en'
@@ -32,9 +33,10 @@ except ImportError:
exit(1)
from kcc import KCC_gui
from multiprocessing import freeze_support
if sys.platform == 'darwin':
if sys.platform.startswith('darwin'):
from kcc import KCC_ui_osx as KCC_ui
elif sys.platform.startswith('linux'):
from kcc import KCC_ui_linux as KCC_ui
else:
from kcc import KCC_ui

View File

@@ -1,7 +1,8 @@
#!/usr/bin/env python
# -*- 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
# 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
# PERFORMANCE OF THIS SOFTWARE.
__version__ = '3.2.1'
__version__ = '3.3'
__license__ = 'ISC'
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
__docformat__ = 'restructuredtext en'
@@ -29,7 +30,7 @@ import traceback
import urllib2
import time
import comic2ebook
import kindlestrip
import kindlesplit
from image import ProfileData
from subprocess import call, Popen, STDOUT, PIPE
from PyQt4 import QtGui, QtCore
@@ -98,6 +99,10 @@ class WorkerThread(QtCore.QThread):
def __init__(self, parent):
QtCore.QThread.__init__(self)
self.parent = parent
self.conversionAlive = False
self.errors = False
self.kindlegenErrorCode = 0
self.kindlegenError = None
def __del__(self):
self.wait()
@@ -111,7 +116,6 @@ class WorkerThread(QtCore.QThread):
self.emit(QtCore.SIGNAL("addMessage"), '<b>Conversion interrupted.</b>', 'error')
self.emit(QtCore.SIGNAL("modeConvert"), True)
# noinspection PyUnboundLocalVariable
def run(self):
self.emit(QtCore.SIGNAL("modeConvert"), False)
profile = ProfileData.ProfileLabels[str(GUI.DeviceBox.currentText())]
@@ -130,12 +134,14 @@ class WorkerThread(QtCore.QThread):
argv.append("--noprocessing")
if GUI.NoRotateBox.isChecked():
argv.append("--nosplitrotate")
if GUI.BorderBox.isChecked():
argv.append("--blackborders")
if GUI.UpscaleBox.checkState() == 1:
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():
argv.append("--forcepng")
if GUI.WebtoonBox.isChecked():
@@ -209,7 +215,8 @@ class WorkerThread(QtCore.QThread):
try:
self.kindlegenErrorCode = 0
if os.path.getsize(item) < 367001600:
output = Popen('kindlegen -locale en "' + item + '"', stdout=PIPE, stderr=STDOUT, shell=True)
output = Popen('kindlegen -locale en "' + item + '"', stdout=PIPE, stderr=STDOUT,
shell=True)
for line in output.stdout:
# ERROR: Generic error
if "Error(" in line:
@@ -242,23 +249,27 @@ class WorkerThread(QtCore.QThread):
True)
else:
self.emit(QtCore.SIGNAL("addMessage"), 'Creating MOBI file... Done!', 'info', True)
self.emit(QtCore.SIGNAL("addMessage"), 'Removing SRCS header...', 'info')
self.emit(QtCore.SIGNAL("addMessage"), 'Cleaning MOBI file...', 'info')
os.remove(item)
mobiPath = item.replace('.epub', '.mobi')
shutil.move(mobiPath, mobiPath + '_tostrip')
shutil.move(mobiPath, mobiPath + '_toclean')
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:
self.errors = True
if not self.errors:
os.remove(mobiPath + '_tostrip')
self.emit(QtCore.SIGNAL("addMessage"), 'Removing SRCS header... Done!', 'info', True)
os.remove(mobiPath + '_toclean')
self.emit(QtCore.SIGNAL("addMessage"), 'Cleaning MOBI file... Done!', 'info', True)
else:
shutil.move(mobiPath + '_tostrip', mobiPath)
os.remove(mobiPath + '_toclean')
os.remove(mobiPath)
self.emit(QtCore.SIGNAL("addMessage"),
'KindleStrip failed to remove SRCS header!', 'warning')
self.emit(QtCore.SIGNAL("addMessage"),
'MOBI file will work correctly but it will be highly oversized.', 'warning')
'KindleUnpack failed to clean MOBI file!', 'error')
else:
epubSize = (os.path.getsize(item))/1024/1024
os.remove(item)
@@ -318,11 +329,19 @@ class Ui_KCC(object):
self.needClean = False
GUI.JobList.clear()
if self.UnRAR:
fnames = QtGui.QFileDialog.getOpenFileNames(MainWindow, 'Select file', self.lastPath,
'*.cbz *.cbr *.zip *.rar *.pdf')
if self.sevenza:
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:
fnames = QtGui.QFileDialog.getOpenFileNames(MainWindow, 'Select file', self.lastPath,
'*.cbz *.zip *.pdf')
if self.sevenza:
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
for fname in fnames:
try:
@@ -438,13 +457,13 @@ class Ui_KCC(object):
GUI.NoRotateBox.setChecked(True)
GUI.QualityBox.setEnabled(False)
GUI.QualityBox.setChecked(False)
GUI.BorderBox.setEnabled(False)
GUI.BorderBox.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.BorderBox.setEnabled(True)
GUI.MangaBox.setEnabled(True)
def toggleNoSplitRotate(self, value):
if value:
@@ -454,13 +473,13 @@ class Ui_KCC(object):
GUI.RotateBox.setEnabled(True)
def changeDevice(self, value):
if value == 12:
if value == 9:
GUI.BasicModeButton.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()
elif value == 11:
elif value == 8:
GUI.BasicModeButton.setEnabled(False)
GUI.AdvModeButton.setEnabled(False)
self.modeExpert(True)
@@ -468,11 +487,17 @@ class Ui_KCC(object):
GUI.BasicModeButton.setEnabled(True)
GUI.AdvModeButton.setEnabled(True)
self.modeBasic()
if value in [0, 1, 5, 6, 7, 8, 9, 12]:
if value in [9, 11, 12, 13, 14]:
GUI.QualityBox.setCheckState(0)
GUI.QualityBox.setEnabled(False)
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()
@@ -544,10 +569,12 @@ class Ui_KCC(object):
event.ignore()
if not GUI.ConvertButton.isEnabled():
event.ignore()
self.settings.setValue('settingsVersion', __version__)
self.settings.setValue('lastPath', self.lastPath)
self.settings.setValue('lastDevice', GUI.DeviceBox.currentIndex())
self.settings.setValue('currentFormat', GUI.FormatBox.currentIndex())
self.settings.setValue('currentMode', self.currentMode)
self.settings.setValue('firstStart', False)
self.settings.setValue('options', QtCore.QVariant({'MangaBox': GUI.MangaBox.checkState(),
'RotateBox': GUI.RotateBox.checkState(),
'QualityBox': GUI.QualityBox.checkState(),
@@ -567,22 +594,33 @@ class Ui_KCC(object):
global GUI, MainWindow
GUI = UI
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.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.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.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.options.toPyObject()
self.worker = WorkerThread(self)
self.versionCheck = VersionThread(self)
self.conversionAlive = False
self.needClean = True
self.GammaValue = 1.0
self.addMessage('<b>Welcome!</b>', 'info')
self.addMessage('<b>Remember:</b> All options have additional informations in tooltips.', 'info')
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
formats = ['MOBI', 'EPUB', 'CBZ']
@@ -608,6 +646,13 @@ class Ui_KCC(object):
self.UnRAR = False
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.AdvModeButton.clicked.connect(self.modeAdvanced)
@@ -627,12 +672,18 @@ class Ui_KCC(object):
KCC.connect(self.versionCheck, QtCore.SIGNAL("addMessage"), self.addMessage)
KCC.closeEvent = self.saveSettings
for profile in profiles:
if profile != "Other":
GUI.DeviceBox.addItem(self.icons.deviceKindle, profile)
else:
for profile in ProfileData.ProfileLabelsGUI:
if profile == "Other":
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:
GUI.FormatBox.addItem(eval('self.icons.' + f + 'Format'), f)
@@ -650,8 +701,6 @@ class Ui_KCC(object):
elif str(option) == "GammaSlider":
GUI.GammaSlider.setValue(int(self.options[option]))
self.changeGamma(int(self.options[option]))
elif str(option) == "StretchBox" or str(option) == "WebstripBox":
pass
else:
eval('GUI.' + str(option)).setCheckState(self.options[option])
if self.currentMode == 1:

View File

@@ -2,8 +2,8 @@
# Form implementation generated from reading ui file 'KCC.ui'
#
# Created: Wed Aug 14 08:39:46 2013
# by: PyQt4 UI code generator 4.10.2
# Created: Wed Sep 18 12:12:45 2013
# by: PyQt4 UI code generator 4.10.3
#
# WARNING! All changes made in this file will be lost!
@@ -68,6 +68,7 @@ class Ui_KCC(object):
self.gridLayout.addWidget(self.NoDitheringBox, 3, 2, 1, 1)
self.BorderBox = QtGui.QCheckBox(self.OptionsAdvanced)
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)
@@ -266,12 +267,12 @@ class Ui_KCC(object):
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><span style=\" font-weight:600;\">EXPERIMENTAL!<br/></span>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.setToolTip(_translate("KCC", "<html><head/><body><p>Enable auto-splitting of webtoons like <span style=\" font-style:italic;\">Tower of God</span> or <span style=\" font-style:italic;\">Noblesse</span>.<br/>Pages with a low width, high height and vertical panel flow.</p></body></html>", None))
self.WebtoonBox.setText(_translate("KCC", "Webtoon mode", None))
self.NoDitheringBox.setToolTip(_translate("KCC", "<html><head/><body><p>Create PNG files instead JPEG.<br/><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.BorderBox.setToolTip(_translate("KCC", "Fill space around images with black color.", None))
self.BorderBox.setText(_translate("KCC", "Black borders", 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))

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,7 +2,7 @@
# Form implementation generated from reading ui file 'KCC-OSX.ui'
#
# Created: Wed Aug 14 08:39:45 2013
# Created: Fri Sep 20 10:57:31 2013
# by: PyQt4 UI code generator 4.10.2
#
# WARNING! All changes made in this file will be lost!
@@ -41,8 +41,9 @@ class Ui_KCC(object):
self.Form.setObjectName(_fromUtf8("Form"))
self.OptionsAdvanced = QtGui.QFrame(self.Form)
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.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(9)
self.OptionsAdvanced.setFont(font)
self.OptionsAdvanced.setObjectName(_fromUtf8("OptionsAdvanced"))
@@ -50,14 +51,16 @@ class Ui_KCC(object):
self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
self.ProcessingBox = QtGui.QCheckBox(self.OptionsAdvanced)
font = QtGui.QFont()
font.setPointSize(11)
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(12)
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.setPointSize(11)
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(12)
self.UpscaleBox.setFont(font)
self.UpscaleBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.UpscaleBox.setTristate(True)
@@ -65,28 +68,33 @@ class Ui_KCC(object):
self.gridLayout.addWidget(self.UpscaleBox, 1, 1, 1, 1)
self.WebtoonBox = QtGui.QCheckBox(self.OptionsAdvanced)
font = QtGui.QFont()
font.setPointSize(11)
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(12)
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.setPointSize(11)
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(12)
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.setPointSize(11)
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(12)
self.BorderBox.setFont(font)
self.BorderBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.BorderBox.setTristate(True)
self.BorderBox.setObjectName(_fromUtf8("BorderBox"))
self.gridLayout.addWidget(self.BorderBox, 3, 0, 1, 1)
self.NoRotateBox = QtGui.QCheckBox(self.OptionsAdvanced)
font = QtGui.QFont()
font.setPointSize(11)
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(12)
self.NoRotateBox.setFont(font)
self.NoRotateBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.NoRotateBox.setObjectName(_fromUtf8("NoRotateBox"))
@@ -94,6 +102,7 @@ class Ui_KCC(object):
self.DeviceBox = QtGui.QComboBox(self.Form)
self.DeviceBox.setGeometry(QtCore.QRect(8, 200, 151, 34))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(11)
self.DeviceBox.setFont(font)
self.DeviceBox.setFocusPolicy(QtCore.Qt.NoFocus)
@@ -101,6 +110,7 @@ class Ui_KCC(object):
self.FormatBox = QtGui.QComboBox(self.Form)
self.FormatBox.setGeometry(QtCore.QRect(262, 200, 152, 34))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(11)
self.FormatBox.setFont(font)
self.FormatBox.setFocusPolicy(QtCore.Qt.NoFocus)
@@ -108,6 +118,7 @@ class Ui_KCC(object):
self.ConvertButton = QtGui.QPushButton(self.Form)
self.ConvertButton.setGeometry(QtCore.QRect(160, 200, 101, 41))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(11)
font.setBold(True)
font.setWeight(75)
@@ -120,6 +131,7 @@ class Ui_KCC(object):
self.DirectoryButton = QtGui.QPushButton(self.Form)
self.DirectoryButton.setGeometry(QtCore.QRect(5, 160, 156, 41))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(11)
self.DirectoryButton.setFont(font)
self.DirectoryButton.setFocusPolicy(QtCore.Qt.NoFocus)
@@ -130,6 +142,7 @@ class Ui_KCC(object):
self.FileButton = QtGui.QPushButton(self.Form)
self.FileButton.setGeometry(QtCore.QRect(260, 160, 157, 41))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(11)
self.FileButton.setFont(font)
self.FileButton.setFocusPolicy(QtCore.Qt.NoFocus)
@@ -140,6 +153,7 @@ class Ui_KCC(object):
self.ClearButton = QtGui.QPushButton(self.Form)
self.ClearButton.setGeometry(QtCore.QRect(160, 160, 101, 41))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(11)
self.ClearButton.setFont(font)
self.ClearButton.setFocusPolicy(QtCore.Qt.NoFocus)
@@ -148,22 +162,25 @@ class Ui_KCC(object):
self.ClearButton.setIcon(icon4)
self.ClearButton.setObjectName(_fromUtf8("ClearButton"))
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.setPointSize(9)
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(12)
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.setPointSize(11)
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(12)
self.MangaBox.setFont(font)
self.MangaBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.MangaBox.setObjectName(_fromUtf8("MangaBox"))
self.QualityBox = QtGui.QCheckBox(self.OptionsBasic)
self.QualityBox.setGeometry(QtCore.QRect(282, 10, 130, 18))
self.QualityBox.setGeometry(QtCore.QRect(282, 10, 135, 18))
font = QtGui.QFont()
font.setPointSize(11)
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(12)
self.QualityBox.setFont(font)
self.QualityBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.QualityBox.setTristate(True)
@@ -171,13 +188,15 @@ class Ui_KCC(object):
self.RotateBox = QtGui.QCheckBox(self.OptionsBasic)
self.RotateBox.setGeometry(QtCore.QRect(145, 10, 130, 18))
font = QtGui.QFont()
font.setPointSize(11)
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(12)
self.RotateBox.setFont(font)
self.RotateBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.RotateBox.setObjectName(_fromUtf8("RotateBox"))
self.JobList = QtGui.QListWidget(self.Form)
self.JobList.setGeometry(QtCore.QRect(10, 50, 401, 101))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(11)
self.JobList.setFont(font)
self.JobList.setFocusPolicy(QtCore.Qt.NoFocus)
@@ -187,6 +206,7 @@ class Ui_KCC(object):
self.BasicModeButton = QtGui.QPushButton(self.Form)
self.BasicModeButton.setGeometry(QtCore.QRect(5, 10, 210, 41))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(12)
font.setBold(False)
font.setWeight(50)
@@ -196,6 +216,7 @@ class Ui_KCC(object):
self.AdvModeButton = QtGui.QPushButton(self.Form)
self.AdvModeButton.setGeometry(QtCore.QRect(207, 10, 210, 41))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(12)
font.setBold(False)
font.setWeight(50)
@@ -204,21 +225,26 @@ class Ui_KCC(object):
self.AdvModeButton.setObjectName(_fromUtf8("AdvModeButton"))
self.OptionsAdvancedGamma = QtGui.QFrame(self.Form)
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.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(9)
self.OptionsAdvancedGamma.setFont(font)
self.OptionsAdvancedGamma.setObjectName(_fromUtf8("OptionsAdvancedGamma"))
self.GammaLabel = QtGui.QLabel(self.OptionsAdvancedGamma)
self.GammaLabel.setGeometry(QtCore.QRect(20, 0, 100, 40))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(12)
font.setBold(False)
font.setWeight(50)
self.GammaLabel.setFont(font)
self.GammaLabel.setObjectName(_fromUtf8("GammaLabel"))
self.GammaSlider = QtGui.QSlider(self.OptionsAdvancedGamma)
self.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.setMaximum(500)
self.GammaSlider.setSingleStep(5)
@@ -227,6 +253,7 @@ class Ui_KCC(object):
self.ProgressBar = QtGui.QProgressBar(self.Form)
self.ProgressBar.setGeometry(QtCore.QRect(10, 10, 401, 35))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(10)
font.setBold(True)
font.setWeight(75)
@@ -237,25 +264,31 @@ class Ui_KCC(object):
self.ProgressBar.setFormat(_fromUtf8(""))
self.ProgressBar.setObjectName(_fromUtf8("ProgressBar"))
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.setFamily(_fromUtf8("Lucida Grande"))
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.setPointSize(11)
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(12)
self.ColorBox.setFont(font)
self.ColorBox.setFocusPolicy(QtCore.Qt.NoFocus)
self.ColorBox.setObjectName(_fromUtf8("ColorBox"))
self.OptionsExpertInternal = QtGui.QFrame(self.OptionsExpert)
self.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.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("Lucida Grande"))
font.setPointSize(12)
font.setBold(False)
font.setWeight(50)
@@ -270,6 +303,7 @@ class Ui_KCC(object):
self.customWidth.setSizePolicy(sizePolicy)
self.customWidth.setMaximumSize(QtCore.QSize(45, 16777215))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(12)
self.customWidth.setFont(font)
self.customWidth.setFocusPolicy(QtCore.Qt.ClickFocus)
@@ -279,6 +313,7 @@ class Ui_KCC(object):
self.gridLayout_2.addWidget(self.customWidth, 0, 1, 1, 1)
self.hLabel = QtGui.QLabel(self.OptionsExpertInternal)
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(12)
font.setBold(False)
font.setWeight(50)
@@ -293,6 +328,7 @@ class Ui_KCC(object):
self.customHeight.setSizePolicy(sizePolicy)
self.customHeight.setMaximumSize(QtCore.QSize(45, 16777215))
font = QtGui.QFont()
font.setFamily(_fromUtf8("Lucida Grande"))
font.setPointSize(12)
self.customHeight.setFont(font)
self.customHeight.setFocusPolicy(QtCore.Qt.ClickFocus)
@@ -322,31 +358,31 @@ class Ui_KCC(object):
KCC.setWindowTitle(_translate("KCC", "Kindle Comic Converter", None))
self.ProcessingBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Disable image optimizations.</span></p></body></html>", None))
self.ProcessingBox.setText(_translate("KCC", "No optimisation", None))
self.UpscaleBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-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.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt; font-weight:600; text-decoration: underline;\">Unchecked - Nothing<br/></span><span style=\" font-size:12pt;\">Images smaller than device resolution will not be resized.</span></p><p><span style=\" font-size:12pt; font-weight:600; text-decoration: underline;\">Indeterminate - Stretching<br/></span><span style=\" font-size:12pt;\">Images smaller than device resolution will be resized. Aspect ratio will be not preserved.</span></p><p><span style=\" font-size:12pt; font-weight:600; text-decoration: underline;\">Checked - Upscaling<br/></span><span style=\" font-size:12pt;\">Images smaller than device resolution will be resized. Aspect ratio will be preserved.</span></p></body></html>", None))
self.UpscaleBox.setText(_translate("KCC", "Stretch/Upscale", None))
self.WebtoonBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-weight:600;\">EXPERIMENTAL!<br/></span>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.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Enable auto-splitting of webtoons like </span><span style=\" font-size:12pt; font-style:italic;\">Tower of God</span><span style=\" font-size:12pt;\"> or </span><span style=\" font-size:12pt; font-style:italic;\">Noblesse</span><span style=\" font-size:12pt;\">.<br/>Pages with a low width, high height and vertical panel flow.</span></p></body></html>", None))
self.WebtoonBox.setText(_translate("KCC", "Webtoon mode", None))
self.NoDitheringBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Create PNG files instead JPEG.<br/></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.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.setText(_translate("KCC", "Black borders", None))
self.BorderBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt; font-weight:600; text-decoration: underline;\">Unchecked - Autodetection<br/></span><span style=\" font-size:12pt;\">Color of margins fill will be detected automatically.</span></p><p><span style=\" font-size:12pt; font-weight:600; text-decoration: underline;\">Indeterminate - White<br/></span><span style=\" font-size:12pt;\">Margins will be filled with white color.</span></p><p><span style=\" font-size:12pt; font-weight:600; text-decoration: underline;\">Checked - Black<br/></span><span style=\" font-size:12pt;\">Margins will be filled with black color.</span></p></body></html>", None))
self.BorderBox.setText(_translate("KCC", "W/B margins", None))
self.NoRotateBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Disable splitting and rotation.</span></p></body></html>", None))
self.NoRotateBox.setText(_translate("KCC", "No split/rotate", None))
self.DeviceBox.setToolTip(_translate("KCC", "Target device.", None))
self.FormatBox.setToolTip(_translate("KCC", "Output format.", None))
self.DeviceBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Target device.</span></p></body></html>", None))
self.FormatBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Output format.</span></p></body></html>", None))
self.ConvertButton.setText(_translate("KCC", "Convert", None))
self.DirectoryButton.setText(_translate("KCC", "Add directory", None))
self.FileButton.setText(_translate("KCC", "Add file", None))
self.ClearButton.setText(_translate("KCC", "Clear list", None))
self.MangaBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Enable right-to-left reading.</span></p></body></html>", None))
self.MangaBox.setText(_translate("KCC", "Manga mode", None))
self.QualityBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-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.RotateBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Disable page spliting.<br/>They will be rotated instead.</span></p></body></html>", None))
self.RotateBox.setText(_translate("KCC", "Horizontal mode", None))
self.BasicModeButton.setText(_translate("KCC", "Basic", None))
self.AdvModeButton.setText(_translate("KCC", "Advanced", None))
self.GammaLabel.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">When converting color images setting this option to 1.0 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.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))

View File

@@ -1,4 +1,4 @@
__version__ = '3.2.1'
__version__ = '3.3'
__license__ = 'ISC'
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
__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
# any purpose with or without fee is hereby granted, provided that the
@@ -21,6 +22,7 @@ __docformat__ = 'restructuredtext en'
import os
import zipfile
import rarfile
from subprocess import Popen, STDOUT, PIPE
# noinspection PyBroadException
@@ -31,6 +33,8 @@ class CBxArchive:
self.compressor = 'zip'
elif rarfile.is_rarfile(origFileName):
self.compressor = 'rar'
elif origFileName.endswith('.7z') or origFileName.endswith('.cb7'):
self.compressor = '7z'
else:
self.compressor = None
@@ -67,12 +71,24 @@ class CBxArchive:
filelist.append(f)
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):
print "\n" + targetdir + "\n"
if self.compressor == 'rar':
self.extractCBR(targetdir)
elif self.compressor == 'zip':
self.extractCBZ(targetdir)
elif self.compressor == '7z':
self.extractCB7(targetdir)
adir = os.listdir(targetdir)
if len(adir) == 1 and os.path.isdir(os.path.join(targetdir, adir[0])):
import shutil

View File

@@ -1,7 +1,8 @@
#!/usr/bin/env python
# -*- 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
# 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
# PERFORMANCE OF THIS SOFTWARE.
#
__version__ = '3.2.1'
__version__ = '3.3'
__license__ = 'ISC'
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
__docformat__ = 'restructuredtext en'
@@ -44,11 +45,18 @@ import pdfjpgextract
def buildHTML(path, imgfile):
filename = getImageFileName(imgfile)
if filename is not None:
# All files marked with this sufix need horizontal Panel View.
if "_kccrotated" in str(filename):
rotate = True
if "_kccrot" in str(filename):
rotatedPage = True
else:
rotate = False
rotatedPage = False
if "_kccnh" in str(filename):
noHorizontalPV = True
else:
noHorizontalPV = False
if "_kccnv" in str(filename):
noVerticalPV = True
else:
noVerticalPV = False
htmlpath = ''
postfix = ''
backref = 1
@@ -79,88 +87,82 @@ def buildHTML(path, imgfile):
imgfile, "\" class=\"singlePage\"/></div>\n"
])
if options.panelview:
if rotate:
if options.righttoleft:
f.writelines(["<div id=\"BoxTL\"><a class=\"app-amzn-magnify\" data-app-amzn-magnify=",
"'{\"targetId\":\"BoxTL-Panel-Parent\", \"ordinal\":1}'></a></div>\n",
"<div id=\"BoxTR\"><a class=\"app-amzn-magnify\" data-app-amzn-magnify=",
"'{\"targetId\":\"BoxTR-Panel-Parent\", \"ordinal\":3}'></a></div>\n",
"<div id=\"BoxBL\"><a class=\"app-amzn-magnify\" data-app-amzn-magnify=",
"'{\"targetId\":\"BoxBL-Panel-Parent\", \"ordinal\":2}'></a></div>\n",
"<div id=\"BoxBR\"><a class=\"app-amzn-magnify\" data-app-amzn-magnify="
"'{\"targetId\":\"BoxBR-Panel-Parent\", \"ordinal\":4}'></a></div>\n"
])
if not noHorizontalPV and not noVerticalPV:
if rotatedPage:
if options.righttoleft:
order = [1, 3, 2, 4]
else:
order = [2, 4, 1, 3]
else:
f.writelines(["<div id=\"BoxTL\"><a class=\"app-amzn-magnify\" data-app-amzn-magnify=",
"'{\"targetId\":\"BoxTL-Panel-Parent\", \"ordinal\":2}'></a></div>\n",
"<div id=\"BoxTR\"><a class=\"app-amzn-magnify\" data-app-amzn-magnify=",
"'{\"targetId\":\"BoxTR-Panel-Parent\", \"ordinal\":4}'></a></div>\n",
"<div id=\"BoxBL\"><a class=\"app-amzn-magnify\" data-app-amzn-magnify=",
"'{\"targetId\":\"BoxBL-Panel-Parent\", \"ordinal\":1}'></a></div>\n",
"<div id=\"BoxBR\"><a class=\"app-amzn-magnify\" data-app-amzn-magnify="
"'{\"targetId\":\"BoxBR-Panel-Parent\", \"ordinal\":3}'></a></div>\n"
])
if options.righttoleft:
order = [2, 1, 4, 3]
else:
order = [1, 2, 3, 4]
boxes = ["BoxTL", "BoxTR", "BoxBL", "BoxBR"]
elif noHorizontalPV and not noVerticalPV:
if rotatedPage:
if options.righttoleft:
order = [2, 1]
else:
order = [1, 2]
else:
order = [1, 2]
boxes = ["BoxT", "BoxB"]
elif not noHorizontalPV and noVerticalPV:
if rotatedPage:
order = [1, 2]
else:
if options.righttoleft:
order = [2, 1]
else:
order = [1, 2]
boxes = ["BoxL", "BoxR"]
else:
if options.righttoleft:
f.writelines(["<div id=\"BoxTL\"><a class=\"app-amzn-magnify\" data-app-amzn-magnify=",
"'{\"targetId\":\"BoxTL-Panel-Parent\", \"ordinal\":2}'></a></div>\n",
"<div id=\"BoxTR\"><a class=\"app-amzn-magnify\" data-app-amzn-magnify=",
"'{\"targetId\":\"BoxTR-Panel-Parent\", \"ordinal\":1}'></a></div>\n",
"<div id=\"BoxBL\"><a class=\"app-amzn-magnify\" data-app-amzn-magnify=",
"'{\"targetId\":\"BoxBL-Panel-Parent\", \"ordinal\":4}'></a></div>\n",
"<div id=\"BoxBR\"><a class=\"app-amzn-magnify\" data-app-amzn-magnify="
"'{\"targetId\":\"BoxBR-Panel-Parent\", \"ordinal\":3}'></a></div>\n"
])
else:
f.writelines(["<div id=\"BoxTL\"><a class=\"app-amzn-magnify\" data-app-amzn-magnify=",
"'{\"targetId\":\"BoxTL-Panel-Parent\", \"ordinal\":1}'></a></div>\n",
"<div id=\"BoxTR\"><a class=\"app-amzn-magnify\" data-app-amzn-magnify=",
"'{\"targetId\":\"BoxTR-Panel-Parent\", \"ordinal\":2}'></a></div>\n",
"<div id=\"BoxBL\"><a class=\"app-amzn-magnify\" data-app-amzn-magnify=",
"'{\"targetId\":\"BoxBL-Panel-Parent\", \"ordinal\":3}'></a></div>\n",
"<div id=\"BoxBR\"><a class=\"app-amzn-magnify\" data-app-amzn-magnify="
"'{\"targetId\":\"BoxBR-Panel-Parent\", \"ordinal\":4}'></a></div>\n"
])
order = [1]
boxes = ["BoxC"]
for i in range(0, len(boxes)):
f.writelines(["<div id=\"" + boxes[i] + "\"><a class=\"app-amzn-magnify\" data-app-amzn-magnify=",
"'{\"targetId\":\"" + boxes[i] + "-Panel-Parent\", \"ordinal\":" + str(order[i]),
"}'></a></div>\n"])
if options.quality == 2:
imgfilepv = string.split(imgfile, ".")
imgfilepv[0] = imgfilepv[0].split("_kccx")[0].replace("_kccnh", "").replace("_kccnv", "")
imgfilepv[0] += "_kcchq"
imgfilepv = string.join(imgfilepv, ".")
else:
imgfilepv = imgfile
f.writelines(["<div id=\"BoxTL-Panel-Parent\" class=\"target-mag-parent\"><div id=\"BoxTL-Panel\" class=\"",
"target-mag\"><img src=\"", "../" * backref, "Images/", postfix, imgfilepv, "\" alt=\"",
imgfilepv, "\"/></div></div>\n",
"<div id=\"BoxTR-Panel-Parent\" class=\"target-mag-parent\"><div id=\"BoxTR-Panel\" class=\"",
"target-mag\"><img src=\"", "../" * backref, "Images/", postfix, imgfilepv, "\" alt=\"",
imgfilepv, "\"/></div></div>\n",
"<div id=\"BoxBL-Panel-Parent\" class=\"target-mag-parent\"><div id=\"BoxBL-Panel\" class=\"",
"target-mag\"><img src=\"", "../" * backref, "Images/", postfix, imgfilepv, "\" alt=\"",
imgfilepv, "\"/></div></div>\n",
"<div id=\"BoxBR-Panel-Parent\" class=\"target-mag-parent\"><div id=\"BoxBR-Panel\" class=\"",
"target-mag\"><img src=\"", "../" * backref, "Images/", postfix, imgfilepv, "\" alt=\"",
imgfilepv, "\"/></div></div>\n"
])
xy = string.split(filename[0], "_kccx")[1]
x = string.split(xy, "_kccy")[0].lstrip("0")
y = string.split(xy, "_kccy")[1].lstrip("0")
if x != "":
x = "-" + str(float(x)/100) + "%"
else:
x = "0%"
if y != "":
y = "-" + str(float(y)/100) + "%"
else:
y = "0%"
boxStyles = {"BoxTL": "left:" + x + ";top:" + y + ";",
"BoxTR": "right:" + x + ";top:" + y + ";",
"BoxBL": "left:" + x + ";bottom:" + y + ";",
"BoxBR": "right:" + x + ";bottom:" + y + ";",
"BoxT": "left:-25%;top:" + y + ";",
"BoxB": "left:-25%;bottom:" + y + ";",
"BoxL": "left:" + x + ";top:-25%;",
"BoxR": "right:" + x + ";top:-25%;",
"BoxC": "right:-25%;top:-25%;"
}
for box in boxes:
f.writelines(["<div id=\"" + box + "-Panel-Parent\" class=\"target-mag-parent\"><div id=\"",
"Generic-Panel\" class=\"target-mag\"><img style=\"" + boxStyles[box] + "\" src=\"",
"../" * backref, "Images/", postfix, imgfilepv, "\" alt=\"" + imgfilepv,
"\"/></div></div>\n",
])
f.writelines(["</div>\n</body>\n</html>"])
f.close()
return path, imgfile
def buildBlankHTML(path):
f = open(os.path.join(path, 'blank.html'), "w")
f.writelines(["<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" ",
"\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n",
"<html xmlns=\"http://www.w3.org/1999/xhtml\">\n",
"<head>\n",
"<title></title>\n",
"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>\n",
"</head>\n",
"<body>\n",
"</body>\n",
"</html>"])
f.close()
return path
def buildNCX(dstdir, title, chapters):
from uuid import uuid4
options.uuid = str(uuid4())
@@ -173,16 +175,18 @@ def buildNCX(dstdir, title, chapters):
"<ncx version=\"2005-1\" xml:lang=\"en-US\" xmlns=\"http://www.daisy.org/z3986/2005/ncx/\">\n",
"<head>\n",
"<meta name=\"dtb:uid\" content=\"", options.uuid, "\"/>\n",
"<meta name=\"dtb:depth\" content=\"2\"/>\n",
"<meta name=\"dtb:depth\" content=\"1\"/>\n",
"<meta name=\"dtb:totalPageCount\" content=\"0\"/>\n",
"<meta name=\"dtb:maxPageNumber\" content=\"0\"/>\n",
"<meta name=\"generated\" content=\"true\"/>\n",
"</head>\n",
"<docTitle><text>", title, "</text></docTitle>\n",
"<navMap>"
])
for chapter in chapters:
folder = chapter[0].replace(os.path.join(dstdir, 'OEBPS'), '').lstrip('/').lstrip('\\\\')
title = os.path.basename(folder)
if os.path.basename(folder) != "Text":
title = os.path.basename(folder)
filename = getImageFileName(os.path.join(folder, chapter[1]))
f.write("<navPoint id=\"" + folder.replace('/', '_').replace('\\', '_') + "\"><navLabel><text>" + title
+ "</text></navLabel><content src=\"" + filename[0].replace("\\", "/") + ".html\"/></navPoint>\n")
@@ -197,38 +201,33 @@ def buildOPF(dstdir, title, filelist, cover=None):
imgres = str(deviceres[0]) + "x" + str(deviceres[1])
if options.righttoleft:
writingmode = "horizontal-rl"
facing = "right"
facing1 = "right"
facing2 = "left"
else:
writingmode = "horizontal-lr"
facing = "left"
facing1 = "left"
facing2 = "right"
f = open(opffile, "w")
f.writelines(["<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
"<package version=\"2.0\" unique-identifier=\"BookID\" xmlns=\"http://www.idpf.org/2007/opf\">\n",
"<metadata xmlns:dc=\"http://purl.org/dc/elements/1.1/\" ",
"xmlns:opf=\"http://www.idpf.org/2007/opf\">\n",
"<package version=\"2.0\" unique-identifier=\"BookID\" ",
"xmlns=\"http://www.idpf.org/2007/opf\">\n",
"<metadata xmlns:opf=\"http://www.idpf.org/2007/opf\" ",
"xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n",
"<dc:title>", title, "</dc:title>\n",
"<dc:language>en-US</dc:language>\n",
"<dc:identifier id=\"BookID\" opf:scheme=\"UUID\">", options.uuid, "</dc:identifier>\n",
"<dc:Creator>KCC</dc:Creator>\n",
"<meta name=\"generator\" content=\"KindleComicConverter-" + __version__ + "\"/>\n",
"<meta name=\"RegionMagnification\" content=\"true\"/>\n",
"<meta name=\"region-mag\" content=\"true\"/>\n",
"<meta name=\"cover\" content=\"cover\"/>\n",
"<meta name=\"book-type\" content=\"comic\"/>\n",
"<meta name=\"rendition:layout\" content=\"pre-paginated\"/>\n",
"<meta name=\"zero-gutter\" content=\"true\"/>\n",
"<meta name=\"zero-margin\" content=\"true\"/>\n",
"<meta name=\"fixed-layout\" content=\"true\"/>\n"
])
if options.landscapemode:
f.writelines(["<meta name=\"rendition:orientation\" content=\"auto\"/>\n",
"<meta name=\"orientation-lock\" content=\"none\"/>\n"])
else:
f.writelines(["<meta name=\"rendition:orientation\" content=\"portrait\"/>\n",
"<meta name=\"orientation-lock\" content=\"portrait\"/>\n"])
f.writelines(["<meta name=\"original-resolution\" content=\"", imgres, "\"/>\n",
"<meta name=\"rendition:orientation\" content=\"portrait\"/>\n",
"<meta name=\"orientation-lock\" content=\"portrait\"/>\n",
"<meta name=\"original-resolution\" content=\"", imgres, "\"/>\n",
"<meta name=\"primary-writing-mode\" content=\"", writingmode, "\"/>\n",
"<meta name=\"rendition:layout\" content=\"pre-paginated\"/>\n",
"<meta name=\"ke-border-color\" content=\"#ffffff\"/>\n",
"<meta name=\"ke-border-width\" content=\"0\"/>\n",
"</metadata>\n<manifest>\n<item id=\"ncx\" href=\"toc.ncx\" ",
"media-type=\"application/x-dtbncx+xml\"/>\n"])
if cover is not None:
@@ -253,44 +252,10 @@ def buildOPF(dstdir, title, filelist, cover=None):
mt = 'image/jpeg'
f.write("<item id=\"img_" + uniqueid + "\" href=\"" + folder + "/" + path[1] + "\" media-type=\""
+ mt + "\"/>\n")
if options.landscapemode and splitCount > 0:
splitCountUsed = 1
while splitCountUsed <= splitCount:
f.write("<item id=\"blank-page" + str(splitCountUsed) +
"\" href=\"Text/blank.html\" media-type=\"application/xhtml+xml\"/>\n")
splitCountUsed += 1
f.write("<item id=\"css\" href=\"Text/style.css\" media-type=\"text/css\"/>\n")
f.write("</manifest>\n<spine toc=\"ncx\">\n")
splitCountUsed = 1
for entry in reflist:
if "_kcca" in str(entry):
# noinspection PyRedundantParentheses
if ((options.righttoleft and facing == 'left') or (not options.righttoleft and facing == 'right')) and\
options.landscapemode:
f.write("<itemref idref=\"blank-page" + str(splitCountUsed) + "\" properties=\"layout-blank\"/>\n")
splitCountUsed += 1
if options.landscapemode:
f.write("<itemref idref=\"page_" + entry + "\" properties=\"page-spread-" + facing1 + "\"/>\n")
else:
f.write("<itemref idref=\"page_" + entry + "\"/>\n")
elif "_kccb" in str(entry):
if options.landscapemode:
f.write("<itemref idref=\"page_" + entry + "\" properties=\"page-spread-" + facing2 + "\"/>\n")
else:
f.write("<itemref idref=\"page_" + entry + "\"/>\n")
if options.righttoleft:
facing = "right"
else:
facing = "left"
else:
if options.landscapemode:
f.write("<itemref idref=\"page_" + entry + "\" properties=\"page-spread-" + facing + "\"/>\n")
else:
f.write("<itemref idref=\"page_" + entry + "\"/>\n")
if facing == 'right':
facing = 'left'
else:
facing = 'right'
f.write("<itemref idref=\"page_" + entry + "\"/>\n")
f.write("</spine>\n<guide>\n</guide>\n</package>\n")
f.close()
os.mkdir(os.path.join(dstdir, 'META-INF'))
@@ -322,24 +287,22 @@ def getImageFileName(imgfile):
return filename
def applyImgOptimization(img, isSplit, toRight, options, overrideQuality=5):
if not options.webtoon:
def applyImgOptimization(img, opt, overrideQuality=5):
img.getImageFill(opt.webtoon)
if not opt.webtoon:
img.cropWhiteSpace(10.0)
if options.cutpagenumbers and not options.webtoon:
if opt.cutpagenumbers and not opt.webtoon:
img.cutPageNumber()
img.optimizeImage(options.gamma)
img.optimizeImage(opt.gamma)
if overrideQuality != 5:
img.resizeImage(options.upscale, options.stretch, options.black_borders, isSplit, toRight,
options.landscapemode, overrideQuality)
img.resizeImage(opt.upscale, opt.stretch, opt.bordersColor, overrideQuality)
else:
img.resizeImage(options.upscale, options.stretch, options.black_borders, isSplit, toRight,
options.landscapemode, options.quality)
if options.forcepng and not options.forcecolor:
img.resizeImage(opt.upscale, opt.stretch, opt.bordersColor, opt.quality)
if opt.forcepng and not opt.forcecolor:
img.quantizeImage()
def dirImgProcess(path):
global options, splitCount
work = []
pagenumber = 0
pagenumbermodifier = 0
@@ -378,7 +341,6 @@ def dirImgProcess(path):
splitpages.sort()
for page in splitpages:
if (page + pagenumbermodifier) % 2 == 0:
splitCount += 1
pagenumbermodifier += 1
pagenumbermodifier += 1
else:
@@ -386,9 +348,9 @@ def dirImgProcess(path):
raise UserWarning("Source directory is empty.")
def fileImgProcess_init(queue, options):
def fileImgProcess_init(queue, opt):
fileImgProcess.queue = queue
fileImgProcess.options = options
fileImgProcess.options = opt
# noinspection PyUnresolvedReferences
@@ -396,59 +358,53 @@ def fileImgProcess(work):
afile = work[0]
dirpath = work[1]
pagenumber = work[2]
options = fileImgProcess.options
opt = fileImgProcess.options
output = None
if options.verbose:
print "Optimizing " + afile + " for " + options.profile
if opt.verbose:
print "Optimizing " + afile + " for " + opt.profile
else:
print ".",
fileImgProcess.queue.put(".")
img = image.ComicPage(os.path.join(dirpath, afile), options.profileData)
if options.quality == 2:
img = image.ComicPage(os.path.join(dirpath, afile), opt.profileData)
if opt.quality == 2:
wipe = False
else:
wipe = True
if options.nosplitrotate:
if opt.nosplitrotate:
split = None
else:
split = img.splitPage(dirpath, options.righttoleft, options.rotate)
if split is not None and split is not "R":
if options.verbose:
split = img.splitPage(dirpath, opt.righttoleft, opt.rotate)
if split is not None:
if opt.verbose:
print "Splitted " + afile
if options.righttoleft:
toRight1 = False
toRight2 = True
else:
toRight1 = True
toRight2 = False
output = pagenumber
img0 = image.ComicPage(split[0], options.profileData)
applyImgOptimization(img0, True, toRight1, options)
img0.saveToDir(dirpath, options.forcepng, options.forcecolor, wipe)
img1 = image.ComicPage(split[1], options.profileData)
applyImgOptimization(img1, True, toRight2, options)
img1.saveToDir(dirpath, options.forcepng, options.forcecolor, wipe)
if options.quality == 2:
img3 = image.ComicPage(split[0], options.profileData)
applyImgOptimization(img3, True, toRight1, options, 0)
img3.saveToDir(dirpath, options.forcepng, options.forcecolor, True)
img4 = image.ComicPage(split[1], options.profileData)
applyImgOptimization(img4, True, toRight2, options, 0)
img4.saveToDir(dirpath, options.forcepng, options.forcecolor, True)
img0 = image.ComicPage(split[0], opt.profileData)
applyImgOptimization(img0, opt)
img0.saveToDir(dirpath, opt.forcepng, opt.forcecolor, wipe)
img1 = image.ComicPage(split[1], opt.profileData)
applyImgOptimization(img1, opt)
img1.saveToDir(dirpath, opt.forcepng, opt.forcecolor, wipe)
if opt.quality == 2:
img3 = image.ComicPage(split[0], opt.profileData)
applyImgOptimization(img3, opt, 0)
img3.saveToDir(dirpath, opt.forcepng, opt.forcecolor, True)
img4 = image.ComicPage(split[1], opt.profileData)
applyImgOptimization(img4, opt, 0)
img4.saveToDir(dirpath, opt.forcepng, opt.forcecolor, True)
else:
applyImgOptimization(img, False, False, options)
img.saveToDir(dirpath, options.forcepng, options.forcecolor, wipe, split)
if options.quality == 2:
img2 = image.ComicPage(os.path.join(dirpath, afile), options.profileData)
if split == "R":
applyImgOptimization(img, opt)
img.saveToDir(dirpath, opt.forcepng, opt.forcecolor, wipe)
if opt.quality == 2:
img2 = image.ComicPage(os.path.join(dirpath, afile), opt.profileData)
if img.rotated:
img2.image = img2.image.rotate(90)
applyImgOptimization(img2, False, False, options, 0)
img2.saveToDir(dirpath, options.forcepng, options.forcecolor, True, split)
img2.rotated = True
applyImgOptimization(img2, opt, 0)
img2.saveToDir(dirpath, opt.forcepng, opt.forcecolor, True)
return output
def genEpubStruct(path):
global options
filelist = []
chapterlist = []
cover = None
@@ -508,6 +464,36 @@ def genEpubStruct(path):
"height: ", str(panelviewsize[1]), "px;\n",
"width: ", str(panelviewsize[0]), "px;\n",
"}\n",
"#Generic-Panel {\n",
"top: 0;\n",
"height: 100%;\n",
"width: 100%;\n",
"}\n",
"#BoxC {\n",
"top: 0;\n",
"height: 100%;\n",
"width: 100%;\n",
"}\n",
"#BoxT {\n",
"top: 0;\n",
"height: 50%;\n",
"width: 100%;\n",
"}\n",
"#BoxB {\n",
"bottom: 0;\n",
"height: 50%;\n",
"width: 100%;\n",
"}\n",
"#BoxL {\n",
"left: 0;\n",
"height: 100%;\n",
"width: 50%;\n",
"}\n",
"#BoxR {\n",
"right: 0;\n",
"height: 100%;\n",
"width: 50%;\n",
"}\n",
"#BoxTL {\n",
"top: 0;\n",
"left: 0;\n",
@@ -531,47 +517,7 @@ def genEpubStruct(path):
"right: 0;\n",
"height: 50%;\n",
"width: 50%;\n",
"}\n",
"#BoxTL-Panel {\n",
"top: 0;\n",
"left: 0;\n",
"height: 100%;\n",
"width: 100%;\n",
"}\n",
"#BoxTL-Panel img {\n",
"top: 0%;\n",
"left: 0%;\n",
"}\n",
"#BoxTR-Panel {\n",
"top: 0;\n",
"right: 0;\n",
"height: 100%;\n",
"width: 100%;\n",
"}\n",
"#BoxTR-Panel img {\n",
"top: 0%;\n",
"right: 0%;\n",
"}\n",
"#BoxBL-Panel {\n",
"bottom: 0;\n",
"left: 0;\n",
"height: 100%;\n",
"width: 100%;\n",
"}\n",
"#BoxBL-Panel img {\n",
"bottom: 0%;\n",
"left: 0%;\n",
"}\n",
"#BoxBR-Panel {\n",
"bottom: 0;\n",
"right: 0;\n",
"height: 100%;\n",
"width: 100%;\n",
"}\n",
"#BoxBR-Panel img {\n",
"bottom: 0%;\n",
"right: 0%;\n",
"}"
"}",
])
f.close()
for (dirpath, dirnames, filenames) in os.walk(os.path.join(path, 'OEBPS', 'Images')):
@@ -588,13 +534,11 @@ def genEpubStruct(path):
'cover' + getImageFileName(filelist[-1][1])[1])
copyfile(os.path.join(filelist[-1][0], filelist[-1][1]), cover)
buildNCX(path, options.title, chapterlist)
# ensure we're sorting files alphabetically
# Ensure we're sorting files alphabetically
convert = lambda text: int(text) if text.isdigit() else text
alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)', key)]
filelist.sort(key=lambda name: (alphanum_key(name[0].lower()), alphanum_key(name[1].lower())))
buildOPF(path, options.title, filelist, cover)
if options.landscapemode and splitCount > 0:
filelist.append(buildBlankHTML(os.path.join(path, 'OEBPS', 'Text')))
def getWorkFolder(afile):
@@ -625,8 +569,7 @@ def getWorkFolder(afile):
path = cbx.extract(workdir)
except OSError:
rmtree(workdir)
print 'Unrar not found, please download from ' + \
'http://www.rarlab.com/download.htm and put into your PATH.'
print 'UnRAR/7za not found or file failed to extract!'
sys.exit(21)
else:
rmtree(workdir)
@@ -637,9 +580,9 @@ def getWorkFolder(afile):
def slugify(value):
# Normalizes string, converts to lowercase, removes non-alpha characters,
# and converts spaces to hyphens.
# Normalizes string, converts to lowercase, removes non-alpha characters and converts spaces to hyphens.
import unicodedata
#noinspection PyArgumentList
value = unicodedata.normalize('NFKD', unicode(value, 'latin1')).encode('ascii', 'ignore')
value = re.sub('[^\w\s\.-]', '', value).strip().lower()
value = re.sub('[-\.\s]+', '-', value)
@@ -689,6 +632,7 @@ def getDirectorySize(start_path='.'):
return total_size
# noinspection PyUnusedLocal
def createNewTome(parentPath):
tomePathRoot = tempfile.mkdtemp('', 'KCC-TMP-')
#tomePathRoot = tempfile.mkdtemp('', 'KCC-TMP-', parentPath)
@@ -843,21 +787,22 @@ def Usage():
def main(argv=None, qtGUI=None):
global parser, options, epub_path, splitCount, GUI
global parser, options, GUI
parser = OptionParser(usage="Usage: %prog [options] comic_file|comic_folder", add_help_option=False)
mainOptions = OptionGroup(parser, "MAIN")
experimentalOptions = OptionGroup(parser, "EXPERIMENTAL")
processingOptions = OptionGroup(parser, "PROCESSING")
outputOptions = OptionGroup(parser, "OUTPUT SETTINGS")
customProfileOptions = OptionGroup(parser, "CUSTOM PROFILE")
otherOptions = OptionGroup(parser, "OTHER")
mainOptions.add_option("-p", "--profile", action="store", dest="profile", default="KHD",
help="Device profile (Choose one among K1, K2, K3, K4NT, K4T, KDX, KDXG, KHD, KF, KFHD,"
" KFHD8, KFA) [Default=KHD]")
help="Device profile (Choose one among K1, K2, K345, KDX, KDXG, KHD, KF, KFHD, KFHD8, KFHDX,"
" KFHDX8, KFA) [Default=KHD]")
mainOptions.add_option("-q", "--quality", type="int", dest="quality", default="0",
help="Quality of Panel View. 0 - Normal 1 - High 2 - Ultra [Default=0]")
mainOptions.add_option("-m", "--manga-style", action="store_true", dest="righttoleft", default=False,
help="Manga style (Right-to-left reading and splitting)")
mainOptions.add_option("-w", "--webtoon", action="store_true", dest="webtoon", default=False,
help="Webtoon processing mode"),
outputOptions.add_option("-o", "--output", action="store", dest="output", default=None,
help="Output generated file to specified directory or file")
outputOptions.add_option("-t", "--title", action="store", dest="title", default="defaulttitle",
@@ -866,10 +811,10 @@ def main(argv=None, qtGUI=None):
help="Outputs a CBZ archive and does not generate EPUB")
outputOptions.add_option("--batchsplit", action="store_true", dest="batchsplit", default=False,
help="Split output into multiple files"),
experimentalOptions.add_option("-w", "--webtoon", action="store_true", dest="webtoon", default=False,
help="Webtoon processing mode"),
processingOptions.add_option("--blackborders", action="store_true", dest="black_borders", default=False,
help="Use black borders instead of white ones")
help="Disable autodetection and force black borders")
processingOptions.add_option("--whiteborders", action="store_true", dest="white_borders", default=False,
help="Disable autodetection and force white borders")
processingOptions.add_option("--forcecolor", action="store_true", dest="forcecolor", default=False,
help="Don't convert images to grayscale")
processingOptions.add_option("--forcepng", action="store_true", dest="forcepng", default=False,
@@ -897,7 +842,6 @@ def main(argv=None, qtGUI=None):
otherOptions.add_option("-h", "--help", action="help",
help="Show this help message and exit")
parser.add_option_group(mainOptions)
parser.add_option_group(experimentalOptions)
parser.add_option_group(outputOptions)
parser.add_option_group(processingOptions)
parser.add_option_group(customProfileOptions)
@@ -920,7 +864,6 @@ def main(argv=None, qtGUI=None):
comic2panel.main(['-y ' + str(options.customheight), '-i', path], qtGUI)
else:
comic2panel.main(['-y ' + str(image.ProfileData.Profiles[options.profile][1][1]), '-i', path], qtGUI)
splitCount = 0
if options.imgproc:
print "\nProcessing images..."
if GUI:
@@ -984,45 +927,29 @@ def getOutputFilename(srcpath, wantedname, ext, tomeNumber):
def checkOptions():
global options
# Webtoon mode mandatory options
if options.webtoon:
options.nosplitrotate = True
options.black_borders = False
options.quality = 0
# Landscape mode is only supported by Kindle Touch and Paperwhite.
if options.profile == 'K4T' or options.profile == 'KHD':
options.landscapemode = True
else:
options.landscapemode = False
# Older Kindle don't support Virtual Panel View. We providing them configuration that will fake that feature.
# Ultra quality mode require Real Panel View. Landscape mode don't work correcly without Virtual Panel View.
if options.profile == 'K3' or options.profile == 'K4NT' or options.quality == 2:
# Real Panel View
options.panelview = True
options.landscapemode = False
else:
# Virtual Panel View
options.panelview = False
options.panelview = True
options.bordersColor = None
if options.white_borders:
options.bordersColor = "white"
if options.black_borders:
options.bordersColor = "black"
# Disabling grayscale conversion for Kindle Fire family.
if options.profile == 'KF' or options.profile == 'KFHD' or options.profile == 'KFHD8' or options.forcecolor:
if options.profile == 'KF' or options.profile == 'KFHD' or options.profile == 'KFHD8' or options.profile == 'KFHDX'\
or options.profile == 'KFHDX8' or options.forcecolor:
options.forcecolor = True
else:
options.forcecolor = False
# Mixing vertical and horizontal pages require real Panel View.
# Landscape mode don't work correcly without Virtual Panel View.
if options.rotate:
options.panelview = True
options.landscapemode = False
# Older Kindle don't need higher resolution files due lack of Panel View.
# Kindle Fire family have very high resolution. Bigger images are not needed.
if options.profile == 'K1' or options.profile == 'K2' or options.profile == 'KDX' or options.profile == 'KDXG'\
or options.profile == 'KF' or options.profile == 'KFHD' or options.profile == 'KFHD8':
if options.profile == 'K1' or options.profile == 'K2' or options.profile == 'KDX' or options.profile == 'KDXG':
options.quality = 0
if options.profile == 'K1' or options.profile == 'K2' or options.profile == 'KDX' or options.profile == 'KDXG':
options.panelview = False
# Disable all Kindle features
options.panelview = False
# Webtoon mode mandatory options
if options.webtoon:
options.nosplitrotate = True
options.quality = 0
options.panelview = False
# Disable all Kindle features for other e-readers
if options.profile == 'OTHER':
options.landscapemode = False
options.panelview = False
options.quality = 0
# Kindle for Android profile require target resolution.

View File

@@ -1,7 +1,8 @@
#!/usr/bin/env python
# -*- 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
# 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
# PERFORMANCE OF THIS SOFTWARE.
#
__version__ = '3.2.1'
__version__ = '3.3'
__license__ = 'ISC'
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
__docformat__ = 'restructuredtext en'
@@ -28,7 +29,7 @@ from shutil import rmtree, copytree, move
from optparse import OptionParser, OptionGroup
from multiprocessing import Pool, Queue, freeze_support
try:
# noinspection PyUnresolvedReferences,PyPackageRequirements
# noinspection PyUnresolvedReferences
from PIL import Image, ImageStat
except ImportError:
print "ERROR: Pillow is not installed!"
@@ -53,48 +54,9 @@ def getImageFileName(imgfile):
return filename
def getImageHistogram(image):
histogram = image.histogram()
RBGW = []
for i in range(256):
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 white > black:
return False
else:
return True
def getImageFill(image):
imageSize = image.size
imageT = image.crop((0, 0, imageSize[0], 1))
imageB = image.crop((0, imageSize[1]-1, imageSize[0], imageSize[1]))
fill = 0
fill += getImageHistogram(imageT)
fill += getImageHistogram(imageB)
if fill == 2:
return 'KCCFB'
elif fill == 0:
return 'KCCFW'
else:
imageL = image.crop((0, 0, 1, imageSize[1]))
imageR = image.crop((imageSize[0]-1, 0, imageSize[0], imageSize[1]))
fill += getImageHistogram(imageL)
fill += getImageHistogram(imageR)
if fill >= 2:
return 'KCCFB'
else:
return 'KCCFW'
def sanitizePanelSize(panel, options):
def sanitizePanelSize(panel, opt):
newPanels = []
if panel[2] > 8 * options.height:
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])
@@ -104,13 +66,13 @@ def sanitizePanelSize(panel, options):
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 * options.height:
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 * options.height:
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:
@@ -118,17 +80,17 @@ def sanitizePanelSize(panel, options):
return newPanels
def splitImage_init(queue, options):
def splitImage_init(queue, opt):
splitImage.queue = queue
splitImage.options = options
splitImage.options = opt
# noinspection PyUnresolvedReferences
def splitImage(work):
path = work[0]
name = work[1]
options = splitImage.options
# Harcoded options
opt = splitImage.options
# Harcoded opttions
threshold = 1.0
delta = 15
print ".",
@@ -137,7 +99,7 @@ def splitImage(work):
filePath = os.path.join(path, name)
# Detect corrupted files
try:
image = Image.open(filePath)
Image.open(filePath)
except IOError:
raise RuntimeError('Cannot read image file %s' % filePath)
try:
@@ -153,8 +115,8 @@ def splitImage(work):
image = Image.open(filePath)
image = image.convert('RGB')
widthImg, heightImg = image.size
if heightImg > options.height:
if options.debug:
if heightImg > opt.height:
if opt.debug:
from PIL import ImageDraw
debugImage = Image.open(filePath)
draw = ImageDraw.Draw(debugImage)
@@ -176,23 +138,23 @@ def splitImage(work):
if y1 + delta >= heightImg:
y1 = heightImg - 1
y2Temp = y1
if options.debug:
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], options)
panelsCleaned = sanitizePanelSize([y1Temp, y2Temp, panelHeight], opt)
for panel in panelsCleaned:
panels.append(panel)
if options.debug:
if opt.debug:
# noinspection PyUnboundLocalVariable
debugImage.save(os.path.join(path, fileExpanded[0] + '-debug.png'), 'PNG')
# Create virtual pages
pages = []
currentPage = []
pageLeft = options.height
pageLeft = opt.height
panelNumber = 0
for panel in panels:
if pageLeft - panel[2] > 0:
@@ -202,7 +164,7 @@ def splitImage(work):
else:
if len(currentPage) > 0:
pages.append(currentPage)
pageLeft = options.height - panel[2]
pageLeft = opt.height - panel[2]
currentPage = [panelNumber]
panelNumber += 1
if len(currentPage) > 0:
@@ -222,7 +184,7 @@ def splitImage(work):
newPage.paste(panelImg, (0, targetHeight))
targetHeight += panels[panel][2]
newPage.save(os.path.join(path, fileExpanded[0] + '-' +
str(pageNumber) + '-' + getImageFill(newPage) + '.png'), 'PNG')
str(pageNumber) + '.png'), 'PNG')
pageNumber += 1
os.remove(filePath)

View File

@@ -1,6 +1,7 @@
# Copyright (C) 2010 Alex Yatskov
# Copyright (C) 2011 Stanislav (proDOOMman) Kosolapov <prodoomman@gmail.com>
# Copyright (C) 2012-2013 Ciro Mattia Gonano <ciromattia@gmail.com>
# Copyright (C) 2013 Pawel Jastrzebski <pawelj@vulturis.eu>
#
# 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
@@ -21,7 +22,7 @@ __docformat__ = 'restructuredtext en'
import os
try:
# noinspection PyUnresolvedReferences,PyPackageRequirements
# noinspection PyUnresolvedReferences
from PIL import Image, ImageOps, ImageStat, ImageChops
except ImportError:
print "ERROR: Pillow is not installed!"
@@ -29,6 +30,9 @@ except ImportError:
class ProfileData:
def __init__(self):
pass
Palette4 = [
0x00, 0x00, 0x00,
0x55, 0x55, 0x55,
@@ -73,38 +77,60 @@ class ProfileData:
0xff, 0xff, 0xff,
]
PalleteNull = [
]
Profiles = {
'K1': ("Kindle 1", (600, 800), Palette4, 1.8, (900, 1200)),
'K2': ("Kindle 2", (600, 800), Palette15, 1.8, (900, 1200)),
'K3': ("Kindle Keyboard", (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)),
'K1': ("Kindle 1", (600, 670), Palette4, 1.8, (900, 1005)),
'K2': ("Kindle 2", (600, 670), Palette15, 1.8, (900, 1005)),
'K345': ("Kindle", (600, 800), Palette16, 1.8, (900, 1200)),
'KHD': ("Kindle Paperwhite", (758, 1024), Palette16, 1.8, (1137, 1536)),
'KDX': ("Kindle DX", (824, 1200), Palette15, 1.8, (1236, 1800)),
'KDXG': ("Kindle DXG", (824, 1200), Palette16, 1.8, (1236, 1800)),
'KF': ("Kindle Fire", (600, 1024), Palette16, 1.0, (900, 1536)),
'KFHD': ("Kindle Fire HD 7\"", (800, 1280), Palette16, 1.0, (1200, 1920)),
'KFHD8': ("Kindle Fire HD 8.9\"", (1200, 1920), Palette16, 1.0, (1800, 2880)),
'KFA': ("Kindle for Android", (0, 0), Palette16, 1.0, (0, 0)),
'KDX': ("Kindle DX", (824, 1000), Palette15, 1.8, (1236, 1500)),
'KDXG': ("Kindle DXG", (824, 1000), Palette16, 1.8, (1236, 1500)),
'KF': ("Kindle Fire", (600, 1024), PalleteNull, 1.0, (900, 1536)),
'KFHD': ("K. Fire HD 7\"", (800, 1280), PalleteNull, 1.0, (1200, 1920)),
'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)),
}
ProfileLabels = {
"Kindle 1": 'K1',
"Kindle 2": 'K2',
"Kindle 3/Keyboard": 'K3',
"Kindle 4/Non-Touch": 'K4NT',
"Kindle 4/Touch": 'K4T',
"Kindle": 'K345',
"Kindle Paperwhite": 'KHD',
"Kindle DX": 'KDX',
"Kindle DXG": 'KDXG',
"Kindle Fire": 'KF',
"Kindle Fire HD 7\"": 'KFHD',
"Kindle Fire HD 8.9\"": 'KFHD8',
"K. Fire HD 7\"": 'KFHD',
"K. Fire HD 8.9\"": 'KFHD8',
"K. Fire HDX 7\"": 'KFHDX',
"K. Fire HDX 8.9\"": 'KFHDX8',
"Kindle for Android": 'KFA',
"Other": 'OTHER'
}
ProfileLabelsGUI = [
"Kindle Paperwhite",
"Kindle",
"Separator",
"K. Fire HD 7\"",
"K. Fire HD 8.9\"",
"K. Fire HDX 7\"",
"K. Fire HDX 8.9\"",
"Separator",
"Kindle for Android",
"Other",
"Separator",
"Kindle 1",
"Kindle 2",
"Kindle DX",
"Kindle DXG",
"Kindle Fire"
]
class ComicPage:
def __init__(self, source, device):
@@ -133,19 +159,29 @@ class ComicPage:
raise RuntimeError('Image file %s is corrupted' % source)
self.image = Image.open(source)
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):
try:
suffix = ""
if not color:
self.image = self.image.convert('L') # convert to grayscale
if suffix == "R":
suffix = "_kccrotated"
else:
suffix = ""
if self.rotated:
suffix += "_kccrot"
if wipe:
os.remove(os.path.join(targetdir, self.filename))
else:
suffix += "_kcchq"
if self.noHPV:
suffix += "_kccnh"
if self.noVPV:
suffix += "_kccnv"
if self.border:
suffix += "_kccx" + str(self.border[0]) + "_kccy" + str(self.border[1])
if forcepng:
self.image.save(os.path.join(targetdir, os.path.splitext(self.filename)[0] + suffix + ".png"), "PNG")
else:
@@ -171,72 +207,98 @@ class ComicPage:
palImg.putpalette(self.palette)
self.image = self.image.quantize(palette=palImg)
def resizeImage(self, upscale=False, stretch=False, black_borders=False, isSplit=False, toRight=False,
landscapeMode=False, qualityMode=0):
def resizeImage(self, upscale=False, stretch=False, bordersColor=None, qualityMode=0):
method = Image.ANTIALIAS
if '-KCCFW' in str(self.filename):
fill = 'white'
elif '-KCCFB' in str(self.filename):
fill = 'black'
if bordersColor:
fill = bordersColor
else:
if black_borders:
fill = 'black'
else:
fill = 'white'
fill = self.fill
if qualityMode == 0:
size = (self.size[0], self.size[1])
generateBorder = True
elif qualityMode == 1:
size = (self.panelviewsize[0], self.panelviewsize[1])
generateBorder = True
else:
size = (self.panelviewsize[0], self.panelviewsize[1])
# Kindle Paperwhite/Touch - Force upscale of splited pages to increase readability
if isSplit and landscapeMode:
upscale = True
generateBorder = False
if self.image.size[0] <= self.size[0] and self.image.size[1] <= self.size[1]:
if not upscale:
borderw = (self.size[0] - self.image.size[0]) / 2
borderh = (self.size[1] - self.image.size[1]) / 2
self.image = ImageOps.expand(self.image, border=(borderw, borderh), fill=fill)
if generateBorder:
if (self.image.size[0]-(2*borderw))*1.5 < self.size[0]:
self.noHPV = True
if (self.image.size[1]-(2*borderh))*1.5 < self.size[1]:
self.noVPV = True
self.border = [int(round(float(borderw)/float(self.image.size[0])*100, 2)*100*1.5),
int(round(float(borderh)/float(self.image.size[1])*100, 2)*100*1.5)]
return self.image
else:
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)
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
ratioDev = float(self.size[0]) / float(self.size[1])
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]
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)
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:
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.fit(self.image, size, method=method, centering=(0.5, 0.5))
if generateBorder:
if fill == 'white':
border = ImageOps.invert(self.image).getbbox()
else:
border = self.image.getbbox()
if border is not None:
if (border[2]-border[0])*1.5 < self.size[0]:
self.noHPV = True
if (border[3]-border[1])*1.5 < self.size[1]:
self.noVPV = True
self.border = [int(round(float(border[0])/float(self.image.size[0])*100, 2)*100*1.5),
int(round(float(border[1])/float(self.image.size[1])*100, 2)*100*1.5)]
else:
self.border = [0, 0]
self.noHPV = True
self.noVPV = True
return self.image
def splitPage(self, targetdir, righttoleft=False, rotate=False):
width, height = self.image.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 rotate:
self.image = self.image.rotate(90)
return "R"
self.rotated = True
return None
else:
self.rotated = False
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)
rightbox = (width / 2, 0, width, height)
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)
rightbox = (0, height / 2, width, height)
filename = os.path.splitext(self.filename)
@@ -256,6 +318,7 @@ class ComicPage:
raise RuntimeError('Cannot write image in directory %s: %s' % (targetdir, e))
return fileone, filetwo
else:
self.rotated = False
return None
def cutPageNumber(self):
@@ -351,4 +414,48 @@ class ComicPage:
# print "Right crop: %s"%diff
self.image = self.image.crop((0, 0, widthImg - diff, heightImg))
# 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
# (http://nedbatchelder.com/blog/200712/extracting_jpgs_from_pdfs.html)

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
NAME = "KindleComicConverter"
VERSION = "3.2.1"
VERSION = "3.3"
MAIN = "kcc.py"
if platform == "darwin":
@@ -41,7 +41,11 @@ elif platform == "win32":
from cx_Freeze import setup, Executable
base = "Win32GUI"
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,
base=base,
targetName="KCC.exe",