mirror of
https://github.com/ciromattia/kcc
synced 2026-04-16 22:18:51 +00:00
Compare commits
62 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0cf92fc48f | ||
|
|
953942ca00 | ||
|
|
c46ca8b507 | ||
|
|
48d3bee225 | ||
|
|
3b0e5cc309 | ||
|
|
e5be31f9d5 | ||
|
|
17ea85c31f | ||
|
|
572e1422bf | ||
|
|
af263073b5 | ||
|
|
7facf2d620 | ||
|
|
eef3ff434b | ||
|
|
c680cfd5c5 | ||
|
|
3e8469611d | ||
|
|
39ab475156 | ||
|
|
636de67a17 | ||
|
|
d80c18f652 | ||
|
|
557bd2bbbf | ||
|
|
ddd223c2ec | ||
|
|
50f5b600b1 | ||
|
|
d94df8390a | ||
|
|
8b33331929 | ||
|
|
86a9dde1eb | ||
|
|
33dec77063 | ||
|
|
fe06e2fa19 | ||
|
|
7b5e3eaafd | ||
|
|
0a30f1ffb9 | ||
|
|
8687604d26 | ||
|
|
0a9fd6c439 | ||
|
|
c95a9395de | ||
|
|
77066d7a9f | ||
|
|
c8e5b7de9a | ||
|
|
3e11a88a7c | ||
|
|
a7e4968836 | ||
|
|
6d9e2d3c03 | ||
|
|
0789e7a353 | ||
|
|
ff97a85552 | ||
|
|
33cfd92cef | ||
|
|
58513ef59f | ||
|
|
6056e3e767 | ||
|
|
1b1ed7c4ab | ||
|
|
5b44e4bddd | ||
|
|
54592969a4 | ||
|
|
38007ab3d5 | ||
|
|
bdd10c7617 | ||
|
|
c0f4bc021a | ||
|
|
34d6af93a6 | ||
|
|
0df481dabb | ||
|
|
55c5b91411 | ||
|
|
be745f4602 | ||
|
|
8bf5ad0f12 | ||
|
|
1b723b2fee | ||
|
|
6095eb98c4 | ||
|
|
95bb070a6b | ||
|
|
75a338304a | ||
|
|
1c28305b83 | ||
|
|
1f1abb80be | ||
|
|
3addc4563a | ||
|
|
e37e7566e2 | ||
|
|
eedf537902 | ||
|
|
5e8bd52433 | ||
|
|
910e8a6cf9 | ||
|
|
edfc2467a3 |
11
.gitignore
vendored
11
.gitignore
vendored
@@ -2,10 +2,11 @@
|
||||
*.cbz
|
||||
*.cbr
|
||||
.idea
|
||||
build
|
||||
dist
|
||||
kindlegen*
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
/UnRAR.exe
|
||||
/7za.exe
|
||||
build
|
||||
dist
|
||||
Output
|
||||
test
|
||||
solaio
|
||||
kindlegen*
|
||||
|
||||
26
KCC-Linux.ui
26
KCC-Linux.ui
@@ -7,19 +7,19 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>420</width>
|
||||
<height>380</height>
|
||||
<height>397</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>420</width>
|
||||
<height>380</height>
|
||||
<height>397</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>420</width>
|
||||
<height>380</height>
|
||||
<height>397</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
@@ -27,9 +27,6 @@
|
||||
<pointsize>9</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Kindle Comic Converter</string>
|
||||
</property>
|
||||
@@ -546,9 +543,6 @@ p, li { white-space: pre-wrap; }
|
||||
<family>DejaVu Sans</family>
|
||||
</font>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><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></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Gamma: Auto</string>
|
||||
</property>
|
||||
@@ -570,9 +564,6 @@ p, li { white-space: pre-wrap; }
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::ClickFocus</enum>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><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></string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>500</number>
|
||||
</property>
|
||||
@@ -785,6 +776,17 @@ p, li { white-space: pre-wrap; }
|
||||
<zorder>OptionsExpert</zorder>
|
||||
<zorder>ProgressBar</zorder>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusBar">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>DejaVu Sans</family>
|
||||
<pointsize>8</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="sizeGripEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
<action name="ActionBasic">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
|
||||
26
KCC-OSX.ui
26
KCC-OSX.ui
@@ -7,19 +7,19 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>420</width>
|
||||
<height>380</height>
|
||||
<height>397</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>420</width>
|
||||
<height>380</height>
|
||||
<height>397</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>420</width>
|
||||
<height>380</height>
|
||||
<height>397</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
@@ -27,9 +27,6 @@
|
||||
<pointsize>9</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Kindle Comic Converter</string>
|
||||
</property>
|
||||
@@ -546,9 +543,6 @@
|
||||
<bold>false</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><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></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Gamma: Auto</string>
|
||||
</property>
|
||||
@@ -570,9 +564,6 @@
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::ClickFocus</enum>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><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></string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>500</number>
|
||||
</property>
|
||||
@@ -797,6 +788,17 @@
|
||||
<zorder>OptionsAdvancedGamma</zorder>
|
||||
<zorder>OptionsExpert</zorder>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusBar">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>Aharoni</family>
|
||||
<pointsize>8</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="sizeGripEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
<action name="ActionBasic">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
|
||||
26
KCC.ui
26
KCC.ui
@@ -7,19 +7,19 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>420</width>
|
||||
<height>380</height>
|
||||
<height>397</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>420</width>
|
||||
<height>380</height>
|
||||
<height>397</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>420</width>
|
||||
<height>380</height>
|
||||
<height>397</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
@@ -27,9 +27,6 @@
|
||||
<pointsize>9</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Kindle Comic Converter</string>
|
||||
</property>
|
||||
@@ -472,9 +469,6 @@ p, li { white-space: pre-wrap; }
|
||||
<height>40</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>When converting color images setting this option to 1.0 MIGHT improve readability.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Gamma: Auto</string>
|
||||
</property>
|
||||
@@ -491,9 +485,6 @@ p, li { white-space: pre-wrap; }
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::ClickFocus</enum>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><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></string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>500</number>
|
||||
</property>
|
||||
@@ -674,6 +665,17 @@ p, li { white-space: pre-wrap; }
|
||||
<zorder>OptionsExpert</zorder>
|
||||
<zorder>ProgressBar</zorder>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusBar">
|
||||
<property name="font">
|
||||
<font>
|
||||
<family>MS Shell Dlg 2</family>
|
||||
<pointsize>8</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="sizeGripEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
<action name="ActionBasic">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
ISC LICENSE
|
||||
ISC LICENSE
|
||||
|
||||
Copyright (c) 2013 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||
Copyright (c) 2013 Paweł Jastrzębski <pawelj@vulturis.eu>
|
||||
|
||||
76
README.md
76
README.md
@@ -1,6 +1,6 @@
|
||||
# KCC
|
||||
|
||||
**KindleComicConverter** is a Python app to convert comic files or folders to ePub or Panel View MOBI.
|
||||
**Kindle Comic Converter** is a Python app to convert comic files or folders to ePub or Panel View MOBI.
|
||||
It was initally developed for Kindle but since v2.2 it outputs valid ePub 2.0 so _**despite its name, KCC is
|
||||
actually a comic to EPUB converter that every e-reader owner can happily use**_.
|
||||
It can also optionally optimize images by applying a number of transformations.
|
||||
@@ -8,21 +8,23 @@ It can also optionally optimize images by applying a number of transformations.
|
||||
### A word of warning
|
||||
**KCC** _is not_ [Amazon's Kindle Comic Creator](http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1001103761) nor is in any way endorsed by Amazon.
|
||||
Amazon's tool is for comic publishers and involves a lot of manual effort, while **KCC** is for comic readers.
|
||||
If you want to read some comments over *Amazon's KC2* you can take a look at [this](http://www.mobileread.com/forums/showthread.php?t=207461&page=7#96) and [that](http://www.mobileread.com/forums/showthread.php?t=211047) threads on Mobileread.
|
||||
_KC2_ in no way is a replacement for **KCC** so you can be quite confident we'll going to carry on developing our little monster ;)
|
||||
_KC2_ in no way is a replacement for **KCC** so you can be quite confident we'll going to carry on developing our little monster ;-)
|
||||
|
||||
### Issues / new features / donations
|
||||
If you have some problems using KCC please [file an issue here](https://github.com/ciromattia/kcc/issues/new).
|
||||
If you can fix an open issue, fork & make a pull request.
|
||||
If you want more chances an issue is fixes or your wanted feature added, consider [placing a bounty](https://www.bountysource.com/trackers/65571-ciromattia-kcc)!
|
||||
|
||||
### Donations
|
||||
If you find **KCC** valuable you can consider donating to the authors:
|
||||
|
||||
* Ciro Mattia Gonano [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=D8WNYNPBGDAS2)
|
||||
* Paweł Jastrzębski [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=YTTJ4LK2JDHPS)
|
||||
* Ciro Mattia Gonano: [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=D8WNYNPBGDAS2) [](http://flattr.com/thing/2260449/ciromattiakcc-on-GitHub)
|
||||
* Paweł Jastrzębski: [](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=YTTJ4LK2JDHPS) [](bitcoin:1W15wwqsfd7wbaZ6wvSJf1LW1bz6q5L8b?label=KCC) [1W15wwqsfd7wbaZ6wvSJf1LW1bz6q5L8b](bitcoin:1W15wwqsfd7wbaZ6wvSJf1LW1bz6q5L8b?label=KCC)
|
||||
|
||||
## BINARY RELEASES
|
||||
You can find the latest released binary at the following links:
|
||||
- **Win64:** [http://kcc.vulturis.eu/Win64/](http://kcc.vulturis.eu/Win64/)
|
||||
- **Win32:** [http://kcc.vulturis.eu/Win32/](http://kcc.vulturis.eu/Win32/)
|
||||
- **OS X:** [http://kcc.vulturis.eu/OSX/](http://kcc.vulturis.eu/OSX/)
|
||||
- **Linux:** Just download sourcecode and launch: `python kcc.py`
|
||||
- **Windows:** [http://kcc.vulturis.eu/Windows/](http://kcc.vulturis.eu/Windows/)
|
||||
- **Linux:** [http://kcc.vulturis.eu/Linux/](http://kcc.vulturis.eu/Linux/)
|
||||
- **OS X (10.8 or later):** [http://kcc.vulturis.eu/OSX/](http://kcc.vulturis.eu/OSX/)
|
||||
- **OS X (10.7 or earlier):** Soon™
|
||||
|
||||
## INPUT FORMATS
|
||||
**KCC** can understand and convert, at the moment, the following file types:
|
||||
@@ -40,9 +42,10 @@ You can find the latest released binary at the following links:
|
||||
|
||||
### For compiling/running from source:
|
||||
- Python 2.7 - Included in MacOS and Linux, follow the [official documentation](http://www.python.org/getit/windows/) to install on Windows.
|
||||
- PyQt4 - Please refer to official documentation for installing into your system.
|
||||
- [PyQt4](http://www.riverbankcomputing.co.uk/software/pyqt/download) - Please refer to official documentation for installing into your system.
|
||||
- [Pillow](http://pypi.python.org/pypi/Pillow/) 2.2.1+ - For comic optimizations. Please refer to official documentation for installing into your system.
|
||||
- **To build OS X release a modified QT is required:** [Patch](https://github.com/ciromattia/kcc/blob/master/other/QT-4.8.5-QListWidget.patch)
|
||||
- [Psutil](https://code.google.com/p/psutil/) - Please refer to official documentation for installing into your system.
|
||||
- **To build OS X release you need a modified QT:** [patch](https://github.com/ciromattia/kcc/blob/master/other/QT-4.8.5-QListWidget.patch)
|
||||
|
||||
## USAGE
|
||||
|
||||
@@ -51,11 +54,17 @@ You can find the latest released binary at the following links:
|
||||
* Read tooltip of _High/Ultra quality_ option. There are many important informations there.
|
||||
* When converting images smaller than device resolution remember to enable upscaling.
|
||||
* Panel View (auto zooming every part of page) can be disabled directly on Kindle. There is no KCC option to do that.
|
||||
* If you're converting color images and the end result is not satisfactory, experiment with gamma correction option (check 1.0 setting first).
|
||||
* Check our [wiki](https://github.com/ciromattia/kcc/wiki/Other-devices) for a list of tested Non-Kindle E-Readers.
|
||||
* The first image found will be set as the comic's cover.
|
||||
* All files/directories will be added to EPUB in alphabetical order.
|
||||
* Output MOBI file should be uploaded via USB. Other methods might corrupt it.
|
||||
* Using high/ultra quality output option with Kindle Fire HD/HDX in most cases is just waste of space.
|
||||
* ComicRack metadata will be parsed only if they are saved in *ComicInfo.xml* file.
|
||||
|
||||
### Calibre:
|
||||
* Calibre can be used to upload files created by KCC.
|
||||
* Uploading KCC output with Calibre will remove *Personal* tag from cover.
|
||||
* **Don't convert files created by KCC with Calibre!** Any conversion process will corrupt the file!
|
||||
* Don't use Calibre reader to preview files created by KCC. It can't parse them correctly.
|
||||
|
||||
### GUI
|
||||
|
||||
@@ -147,30 +156,30 @@ The app relies and includes the following scripts/binaries:
|
||||
* [Kindle Fire HDX 8.9"](http://kcc.vulturis.eu/Samples/Ubunchu!-KFHDX8.mobi)
|
||||
|
||||
## CHANGELOG
|
||||
####1.00
|
||||
####1.0
|
||||
* Initial version
|
||||
|
||||
####1.10
|
||||
####1.1
|
||||
* Added support for CBZ/CBR files in comic2ebook.py
|
||||
|
||||
####1.11
|
||||
* Added support for CBZ/CBR files in KindleComicConverter
|
||||
####1.1.1
|
||||
* Added support for CBZ/CBR files in Kindle Comic Converter
|
||||
|
||||
####1.20
|
||||
####1.2
|
||||
* Comic optimizations! Split pages not target-oriented (landscape with portrait target or portrait with landscape target), add palette and other image optimizations from Mangle. WARNING: PIL is required for all image mangling!
|
||||
|
||||
####1.30
|
||||
####1.3
|
||||
* Fixed an issue in OPF generation for device resolution
|
||||
* Reworked options system (call with -h option to get the inline help)
|
||||
|
||||
####1.40
|
||||
####1.4
|
||||
* Added some options for controlling image optimization
|
||||
* Further optimization (ImageOps, page numbering cut, autocontrast)
|
||||
|
||||
####1.41
|
||||
####1.4.1
|
||||
* Fixed a serious bug on resizing when img ratio was bigger than device one
|
||||
|
||||
####1.50
|
||||
####1.5
|
||||
* Added subfolder support for multiple chapters.
|
||||
|
||||
####2.0
|
||||
@@ -179,7 +188,7 @@ The app relies and includes the following scripts/binaries:
|
||||
####2.1
|
||||
* Added basic error reporting
|
||||
|
||||
#### 2.2:
|
||||
####2.2:
|
||||
* Added (valid!) ePub 2.0 output
|
||||
* Rename .zip files to .cbz to avoid overwriting
|
||||
|
||||
@@ -278,6 +287,23 @@ The app relies and includes the following scripts/binaries:
|
||||
* Merged DX and DXG profiles
|
||||
* Many other minor bug fixes and GUI tweaks
|
||||
|
||||
####3.5:
|
||||
* Added simple content server - Converted files can be now delivered wireless
|
||||
* Added proper Windows installer
|
||||
* Improved multiprocessing speed
|
||||
* GUI tweaks and minor bug fixes
|
||||
|
||||
####3.6:
|
||||
* Increased quality of Panel View zoom
|
||||
* Creation of multipart MOBI output is now faster on machines with 4GB+ RAM
|
||||
* Automatic gamma correction now distinguishes color and grayscale images
|
||||
* Added ComicRack metadata parser
|
||||
* Implemented new method to detect border color in non-webtoon comics
|
||||
* Upscaling is now enabled by default for Kindle Fire HD/HDX
|
||||
* Windows nad Linux releases now have tray icon
|
||||
* Fixed Kindle Fire HDX 7" output
|
||||
* Increased target resolution for Kindle DX/DXG CBZ output
|
||||
|
||||
## COPYRIGHT
|
||||
|
||||
Copyright (c) 2012-2013 Ciro Mattia Gonano and Paweł Jastrzębski.
|
||||
|
||||
BIN
icons/Wizard-Small.bmp
Normal file
BIN
icons/Wizard-Small.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
BIN
icons/Wizard.bmp
Normal file
BIN
icons/Wizard.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 201 KiB |
124
kcc.iss
Normal file
124
kcc.iss
Normal file
@@ -0,0 +1,124 @@
|
||||
#define MyAppName "Kindle Comic Converter"
|
||||
#define MyAppVersion "3.6"
|
||||
#define MyAppPublisher "Ciro Mattia Gonano, Paweł Jastrzębski"
|
||||
#define MyAppURL "http://kcc.vulturis.eu/"
|
||||
#define MyAppExeName "KCC.exe"
|
||||
|
||||
[Setup]
|
||||
AppId={{7D279A59-C65E-4DA7-B165-56DD06596216}
|
||||
AppName={#MyAppName}
|
||||
AppVersion={#MyAppVersion}
|
||||
AppPublisher={#MyAppPublisher}
|
||||
AppPublisherURL={#MyAppURL}
|
||||
AppSupportURL={#MyAppURL}
|
||||
AppUpdatesURL={#MyAppURL}
|
||||
AppCopyright=Copyright (C) 2012-2013 Ciro Mattia Gonano and Paweł Jastrzębski
|
||||
DefaultDirName={pf}\{#MyAppName}
|
||||
DefaultGroupName={#MyAppName}
|
||||
AllowNoIcons=yes
|
||||
LicenseFile=LICENSE.txt
|
||||
OutputBaseFilename=KindleComicConverter_win_{#MyAppVersion}
|
||||
SetupIconFile=icons\comic2ebook.ico
|
||||
SolidCompression=yes
|
||||
ArchitecturesInstallIn64BitMode=x64
|
||||
ShowLanguageDialog=no
|
||||
LanguageDetectionMethod=none
|
||||
WizardImageFile=icons\Wizard.bmp
|
||||
WizardSmallImageFile=icons\Wizard-Small.bmp
|
||||
UninstallDisplayName={#MyAppName}
|
||||
UninstallDisplayIcon={app}\{#MyAppExeName}
|
||||
ChangesAssociations=True
|
||||
InfoAfterFile=other\InstallWarning.rtf
|
||||
SignTool=SignTool /d $q{#MyAppName}$q /du $q{#MyAppURL}$q $f
|
||||
|
||||
[Languages]
|
||||
Name: "english"; MessagesFile: "compiler:Default.isl"
|
||||
|
||||
[Tasks]
|
||||
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
|
||||
Name: "CBZassociation"; Description: "CBZ"; GroupDescription: "File associations:"
|
||||
Name: "CBRassociation"; Description: "CBR"; GroupDescription: "File associations:"
|
||||
Name: "CB7association"; Description: "CB7"; GroupDescription: "File associations:"
|
||||
|
||||
[Files]
|
||||
; x64 files
|
||||
Source: "build\exe.win-amd64-2.7\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
|
||||
Source: "build\exe.win-amd64-2.7\_ctypes.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
|
||||
Source: "build\exe.win-amd64-2.7\_hashlib.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
|
||||
Source: "build\exe.win-amd64-2.7\_multiprocessing.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
|
||||
Source: "build\exe.win-amd64-2.7\_socket.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
|
||||
Source: "build\exe.win-amd64-2.7\_ssl.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
|
||||
Source: "build\exe.win-amd64-2.7\bz2.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
|
||||
Source: "build\exe.win-amd64-2.7\LIBEAY32.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
|
||||
Source: "build\exe.win-amd64-2.7\library.zip"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
|
||||
Source: "build\exe.win-amd64-2.7\PIL._imaging.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
|
||||
Source: "build\exe.win-amd64-2.7\PIL._imagingft.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
|
||||
Source: "build\exe.win-amd64-2.7\pyexpat.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
|
||||
Source: "build\exe.win-amd64-2.7\PyQt4.QtCore.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
|
||||
Source: "build\exe.win-amd64-2.7\PyQt4.QtGui.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
|
||||
Source: "build\exe.win-amd64-2.7\PyQt4.QtNetwork.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
|
||||
Source: "build\exe.win-amd64-2.7\python27.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
|
||||
Source: "build\exe.win-amd64-2.7\QtCore4.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
|
||||
Source: "build\exe.win-amd64-2.7\QtGui4.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
|
||||
Source: "build\exe.win-amd64-2.7\QtNetwork4.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
|
||||
Source: "build\exe.win-amd64-2.7\select.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
|
||||
Source: "build\exe.win-amd64-2.7\sip.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
|
||||
Source: "build\exe.win-amd64-2.7\SSLEAY32.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
|
||||
Source: "build\exe.win-amd64-2.7\unicodedata.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
|
||||
Source: "build\exe.win-amd64-2.7\_psutil_mswindows.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: Is64BitInstallMode
|
||||
; x86 files
|
||||
Source: "build\exe.win32-2.7\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion solidbreak; Check: not Is64BitInstallMode
|
||||
Source: "build\exe.win32-2.7\_ctypes.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
||||
Source: "build\exe.win32-2.7\_hashlib.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
||||
Source: "build\exe.win32-2.7\_multiprocessing.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
||||
Source: "build\exe.win32-2.7\_socket.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
||||
Source: "build\exe.win32-2.7\_ssl.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
||||
Source: "build\exe.win32-2.7\bz2.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
||||
Source: "build\exe.win32-2.7\LIBEAY32.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
||||
Source: "build\exe.win32-2.7\library.zip"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
||||
Source: "build\exe.win32-2.7\PIL._imaging.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
||||
Source: "build\exe.win32-2.7\PIL._imagingft.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
||||
Source: "build\exe.win32-2.7\pyexpat.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
||||
Source: "build\exe.win32-2.7\PyQt4.QtCore.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
||||
Source: "build\exe.win32-2.7\PyQt4.QtGui.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
||||
Source: "build\exe.win32-2.7\PyQt4.QtNetwork.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
||||
Source: "build\exe.win32-2.7\python27.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
||||
Source: "build\exe.win32-2.7\QtCore4.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
||||
Source: "build\exe.win32-2.7\QtGui4.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
||||
Source: "build\exe.win32-2.7\QtNetwork4.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
||||
Source: "build\exe.win32-2.7\select.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
||||
Source: "build\exe.win32-2.7\sip.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
||||
Source: "build\exe.win32-2.7\SSLEAY32.dll"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
||||
Source: "build\exe.win32-2.7\unicodedata.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
||||
Source: "build\exe.win32-2.7\_psutil_mswindows.pyd"; DestDir: "{app}"; Flags: ignoreversion; Check: not Is64BitInstallMode
|
||||
; Common files
|
||||
Source: "LICENSE.txt"; DestDir: "{app}"; Flags: ignoreversion solidbreak
|
||||
Source: "other\Additional-LICENSE.txt"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "other\UnRAR.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "other\7za.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||
|
||||
[Icons]
|
||||
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
|
||||
Name: "{group}\Readme"; Filename: "https://github.com/ciromattia/kcc#kcc"
|
||||
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
|
||||
|
||||
[Run]
|
||||
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
|
||||
|
||||
[Messages]
|
||||
WelcomeLabel1=Welcome to the KCC Setup Wizard
|
||||
FinishedHeadingLabel=Completing the KCC Setup Wizard
|
||||
|
||||
[Registry]
|
||||
Root: HKCR; SubKey: ".cbz"; ValueType: string; ValueData: "KCCZIP"; Flags: uninsdeletekey; Tasks: CBZassociation
|
||||
Root: HKCR; SubKey: "KCCZIP"; ValueType: string; ValueData: "KCC ZIP Archive"; Flags: uninsdeletekey; Tasks: CBZassociation
|
||||
Root: HKCR; SubKey: "KCCZIP\Shell\Open\Command"; ValueType: string; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey; Tasks: CBZassociation
|
||||
Root: HKCR; Subkey: "KCCZIP\DefaultIcon"; ValueType: string; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletevalue; Tasks: CBZassociation
|
||||
Root: HKCR; SubKey: ".cbr"; ValueType: string; ValueData: "KCCRAR"; Flags: uninsdeletekey; Tasks: CBRassociation
|
||||
Root: HKCR; SubKey: "KCCRAR"; ValueType: string; ValueData: "KCC RAR Archive"; Flags: uninsdeletekey; Tasks: CBRassociation
|
||||
Root: HKCR; SubKey: "KCCRAR\Shell\Open\Command"; ValueType: string; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey; Tasks: CBRassociation
|
||||
Root: HKCR; Subkey: "KCCRAR\DefaultIcon"; ValueType: string; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletevalue; Tasks: CBRassociation
|
||||
Root: HKCR; SubKey: ".cb7"; ValueType: string; ValueData: "KCCCB7"; Flags: uninsdeletekey; Tasks: CB7association
|
||||
Root: HKCR; SubKey: "KCCCB7"; ValueType: string; ValueData: "KCC 7z Archive"; Flags: uninsdeletekey; Tasks: CB7association
|
||||
Root: HKCR; SubKey: "KCCCB7\Shell\Open\Command"; ValueType: string; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey; Tasks: CB7association
|
||||
Root: HKCR; Subkey: "KCCCB7\DefaultIcon"; ValueType: string; ValueData: "{app}\{#MyAppExeName},0"; Flags: uninsdeletevalue; Tasks: CB7association
|
||||
47
kcc.py
47
kcc.py
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python2
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2012-2013 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||
@@ -18,7 +18,7 @@
|
||||
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
# PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
__version__ = '3.4'
|
||||
__version__ = '3.6'
|
||||
__license__ = 'ISC'
|
||||
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
@@ -26,26 +26,32 @@ __docformat__ = 'restructuredtext en'
|
||||
import sys
|
||||
import os
|
||||
try:
|
||||
# noinspection PyUnresolvedReferences
|
||||
#noinspection PyUnresolvedReferences
|
||||
from PyQt4 import QtCore, QtGui, QtNetwork
|
||||
except ImportError:
|
||||
print "ERROR: PyQT4 is not installed!"
|
||||
if sys.platform.startswith('linux'):
|
||||
import Tkinter
|
||||
import tkMessageBox
|
||||
importRoot = Tkinter.Tk()
|
||||
importRoot.withdraw()
|
||||
tkMessageBox.showerror("KCC - Error", "PyQT4 is not installed!")
|
||||
exit(1)
|
||||
from kcc import KCC_gui
|
||||
from multiprocessing import freeze_support
|
||||
|
||||
# OS specific PATH variable workarounds
|
||||
if sys.platform.startswith('darwin'):
|
||||
# Workaround Finder-launched app PATH evaluation
|
||||
os.environ['PATH'] = '/usr/local/bin:' + os.environ['PATH']
|
||||
from kcc import KCC_ui_osx as KCC_ui
|
||||
elif sys.platform.startswith('linux'):
|
||||
from kcc import KCC_ui_linux as KCC_ui
|
||||
else:
|
||||
# Workaround for Windows file association mechanism
|
||||
if 'RESOURCEPATH' in os.environ:
|
||||
os.environ['PATH'] = os.environ['RESOURCEPATH'] + ':' + os.environ['PATH']
|
||||
else:
|
||||
os.environ['PATH'] = os.path.dirname(os.path.abspath(__file__)) + '/other/:' + os.environ['PATH']
|
||||
elif sys.platform.startswith('win'):
|
||||
if getattr(sys, 'frozen', False):
|
||||
os.chdir(os.path.dirname(os.path.abspath(sys.executable)))
|
||||
else:
|
||||
os.environ['PATH'] = os.path.dirname(os.path.abspath(__file__)) + '/other/;' + os.environ['PATH']
|
||||
os.chdir(os.path.dirname(os.path.abspath(__file__)))
|
||||
from kcc import KCC_ui
|
||||
|
||||
|
||||
# Implementing detection of already running KCC instance and forwarding argv to it
|
||||
@@ -89,10 +95,10 @@ class QApplicationMessaging(QtGui.QApplication):
|
||||
return False
|
||||
|
||||
freeze_support()
|
||||
APP = QApplicationMessaging(sys.argv)
|
||||
if APP.isRunning():
|
||||
KCCAplication = QApplicationMessaging(sys.argv)
|
||||
if KCCAplication.isRunning():
|
||||
if len(sys.argv) > 1:
|
||||
APP.sendMessage(sys.argv[1].decode(sys.getfilesystemencoding()))
|
||||
KCCAplication.sendMessage(sys.argv[1].decode(sys.getfilesystemencoding()))
|
||||
sys.exit(0)
|
||||
else:
|
||||
messageBox = QtGui.QMessageBox()
|
||||
@@ -101,13 +107,8 @@ if APP.isRunning():
|
||||
messageBox.setWindowIcon(icon)
|
||||
QtGui.QMessageBox.critical(messageBox, 'KCC - Error', 'KCC is already running!', QtGui.QMessageBox.Ok)
|
||||
sys.exit(1)
|
||||
KCC = QtGui.QMainWindow()
|
||||
UI = KCC_ui.Ui_KCC()
|
||||
UI.setupUi(KCC)
|
||||
GUI = KCC_gui.Ui_KCC(UI, KCC, APP)
|
||||
KCC.setWindowTitle("Kindle Comic Converter " + __version__)
|
||||
KCC.show()
|
||||
KCC.raise_()
|
||||
KCCWindow = QtGui.QMainWindow()
|
||||
KCCUI = KCC_gui.KCCGUI(KCCAplication, KCCWindow)
|
||||
if len(sys.argv) > 1:
|
||||
GUI.handleMessage(sys.argv[1].decode(sys.getfilesystemencoding()))
|
||||
sys.exit(APP.exec_())
|
||||
KCCUI.handleMessage(sys.argv[1].decode(sys.getfilesystemencoding()))
|
||||
sys.exit(KCCAplication.exec_())
|
||||
|
||||
604
kcc/KCC_gui.py
604
kcc/KCC_gui.py
@@ -1,4 +1,3 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2012-2013 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||
@@ -18,24 +17,47 @@
|
||||
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
# PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
__version__ = '3.4'
|
||||
__version__ = '3.6'
|
||||
__license__ = 'ISC'
|
||||
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import os
|
||||
import sys
|
||||
import shutil
|
||||
import traceback
|
||||
import urllib2
|
||||
import time
|
||||
import socket
|
||||
import comic2ebook
|
||||
import kindlesplit
|
||||
from string import split
|
||||
from time import sleep
|
||||
from shutil import move
|
||||
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
|
||||
from SocketServer import ThreadingMixIn
|
||||
from image import ProfileData
|
||||
from subprocess import call, Popen, STDOUT, PIPE
|
||||
from subprocess import STDOUT, PIPE
|
||||
from PyQt4 import QtGui, QtCore
|
||||
from xml.dom.minidom import parse
|
||||
from HTMLParser import HTMLParser
|
||||
from KCC_rc_web import WebContent
|
||||
try:
|
||||
#noinspection PyUnresolvedReferences
|
||||
from psutil import TOTAL_PHYMEM, Popen
|
||||
except ImportError:
|
||||
print "ERROR: Psutil is not installed!"
|
||||
if sys.platform.startswith('linux'):
|
||||
import Tkinter
|
||||
import tkMessageBox
|
||||
importRoot = Tkinter.Tk()
|
||||
importRoot.withdraw()
|
||||
tkMessageBox.showerror("KCC - Error", "Psutil is not installed!")
|
||||
exit(1)
|
||||
if sys.platform.startswith('darwin'):
|
||||
import KCC_ui_osx as KCC_ui
|
||||
elif sys.platform.startswith('linux'):
|
||||
import KCC_ui_linux as KCC_ui
|
||||
else:
|
||||
import KCC_ui
|
||||
|
||||
|
||||
class Icons:
|
||||
@@ -59,6 +81,9 @@ class Icons:
|
||||
self.error = QtGui.QIcon()
|
||||
self.error.addPixmap(QtGui.QPixmap(":/Status/icons/error.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
|
||||
self.programIcon = QtGui.QIcon()
|
||||
self.programIcon.addPixmap(QtGui.QPixmap(":/Icon/icons/comic2ebook.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
|
||||
|
||||
class HTMLStripper(HTMLParser):
|
||||
def __init__(self):
|
||||
@@ -73,11 +98,104 @@ class HTMLStripper(HTMLParser):
|
||||
return ''.join(self.fed)
|
||||
|
||||
|
||||
# noinspection PyBroadException
|
||||
class VersionThread(QtCore.QThread):
|
||||
def __init__(self, parent):
|
||||
class WebServerHandler(BaseHTTPRequestHandler):
|
||||
#noinspection PyAttributeOutsideInit
|
||||
def do_GET(self):
|
||||
if self.path == '/':
|
||||
self.path = '/index.html'
|
||||
try:
|
||||
sendReply = False
|
||||
mimetype = None
|
||||
if self.path.endswith('.mobi'):
|
||||
mimetype = 'application/x-mobipocket-ebook'
|
||||
sendReply = True
|
||||
if self.path.endswith('.epub'):
|
||||
mimetype = 'application/epub+zip'
|
||||
sendReply = True
|
||||
if self.path.endswith('.cbz'):
|
||||
mimetype = 'application/x-cbz'
|
||||
sendReply = True
|
||||
if self.path == '/index.html':
|
||||
self.send_response(200)
|
||||
self.send_header('Content-type', 'text/html')
|
||||
self.end_headers()
|
||||
self.wfile.write('<!DOCTYPE html>\n'
|
||||
'<html lang="en">\n'
|
||||
'<head><meta charset="utf-8">\n'
|
||||
'<link href="' + GUI.webContent.favicon + '" rel="icon" type="image/x-icon" />\n'
|
||||
'<title>Kindle Comic Converter</title>\n'
|
||||
'</head>\n'
|
||||
'<body>\n'
|
||||
'<div style="text-align: center; font-size:25px">\n'
|
||||
'<p style="font-size:50px">- <img style="vertical-align: middle" '
|
||||
'alt="KCC Logo" src="' + GUI.webContent.logo + '" /> -</p>\n')
|
||||
if len(GUI.completedWork) > 0 and not GUI.conversionAlive:
|
||||
for key in sorted(GUI.completedWork.iterkeys()):
|
||||
self.wfile.write('<p><a href="' + key + '">' + split(key, '.')[0] + '</a></p>\n')
|
||||
else:
|
||||
self.wfile.write('<p style="font-weight: bold">No downloads are available.<br/>'
|
||||
'Convert some files and refresh this page.</p>\n')
|
||||
self.wfile.write('</div>\n'
|
||||
'</body>\n'
|
||||
'</html>\n')
|
||||
elif sendReply:
|
||||
outputFile = GUI.completedWork[urllib2.unquote(self.path[1:])].decode('utf-8')
|
||||
fp = open(outputFile, 'rb')
|
||||
self.send_response(200)
|
||||
self.send_header('Content-type', mimetype)
|
||||
self.send_header('Content-Length', os.path.getsize(outputFile))
|
||||
self.end_headers()
|
||||
while True:
|
||||
chunk = fp.read(8192)
|
||||
if not chunk:
|
||||
fp.close()
|
||||
break
|
||||
self.wfile.write(chunk)
|
||||
return
|
||||
except (IOError, LookupError):
|
||||
self.send_error(404, 'File Not Found: %s' % self.path)
|
||||
|
||||
|
||||
class WebServerThreaded(ThreadingMixIn, HTTPServer):
|
||||
"""Handle requests in a separate thread."""
|
||||
|
||||
|
||||
class WebServerThread(QtCore.QThread):
|
||||
def __init__(self):
|
||||
QtCore.QThread.__init__(self)
|
||||
self.server = None
|
||||
self.running = False
|
||||
|
||||
def __del__(self):
|
||||
self.wait()
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
# Sweet cross-platform one-liner to get LAN ip address
|
||||
lIP = [ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if not ip.startswith("127.")][:1][0]
|
||||
except StandardError:
|
||||
# Sadly it can fail on some Linux configurations
|
||||
lIP = None
|
||||
try:
|
||||
self.server = WebServerThreaded(('', 4242), WebServerHandler)
|
||||
self.running = True
|
||||
if lIP:
|
||||
self.emit(QtCore.SIGNAL("addMessage"), '<b><a href="http://' + lIP +
|
||||
':4242/">Content server</a></b> started.', 'info')
|
||||
else:
|
||||
self.emit(QtCore.SIGNAL("addMessage"), '<b>Content server</b> started on port 4242.', 'info')
|
||||
while self.running:
|
||||
self.server.handle_request()
|
||||
except StandardError:
|
||||
self.emit(QtCore.SIGNAL("addMessage"), '<b>Content server</b> failed to start!', 'error')
|
||||
|
||||
def stop(self):
|
||||
self.running = False
|
||||
|
||||
|
||||
class VersionThread(QtCore.QThread):
|
||||
def __init__(self):
|
||||
QtCore.QThread.__init__(self)
|
||||
self.parent = parent
|
||||
|
||||
def __del__(self):
|
||||
self.wait()
|
||||
@@ -86,36 +204,143 @@ class VersionThread(QtCore.QThread):
|
||||
try:
|
||||
XML = urllib2.urlopen('http://kcc.vulturis.eu/Version.php')
|
||||
XML = parse(XML)
|
||||
except Exception:
|
||||
except StandardError:
|
||||
return
|
||||
latestVersion = XML.childNodes[0].getElementsByTagName('latest')[0].childNodes[0].toxml()
|
||||
if tuple(map(int, (latestVersion.split(".")))) > tuple(map(int, (__version__.split(".")))):
|
||||
self.emit(QtCore.SIGNAL("addMessage"), '<a href="http://kcc.vulturis.eu/">'
|
||||
'<b>New version is available!</b></a>', 'warning')
|
||||
'<b>New version is available!</b></a> '
|
||||
'(<a href="https://github.com/ciromattia/kcc/releases/">'
|
||||
'Changelog</a>)', 'warning')
|
||||
|
||||
|
||||
# noinspection PyBroadException
|
||||
class WorkerThread(QtCore.QThread):
|
||||
def __init__(self, parent):
|
||||
class ProgressThread(QtCore.QThread):
|
||||
def __init__(self):
|
||||
QtCore.QThread.__init__(self)
|
||||
self.parent = parent
|
||||
self.running = False
|
||||
self.content = None
|
||||
self.progress = 0
|
||||
|
||||
def __del__(self):
|
||||
self.wait()
|
||||
|
||||
def run(self):
|
||||
self.running = True
|
||||
while self.running:
|
||||
sleep(1)
|
||||
if self.content:
|
||||
self.emit(QtCore.SIGNAL("addMessage"), self.content + self.progress * '.', 'info', True)
|
||||
self.progress += 1
|
||||
if self.progress == 4:
|
||||
self.progress = 0
|
||||
|
||||
def stop(self):
|
||||
self.running = False
|
||||
|
||||
|
||||
class WorkerSignals(QtCore.QObject):
|
||||
result = QtCore.pyqtSignal(list)
|
||||
|
||||
|
||||
class KindleGenThread(QtCore.QRunnable):
|
||||
def __init__(self, batch):
|
||||
super(KindleGenThread, self).__init__()
|
||||
self.signals = WorkerSignals()
|
||||
self.work = batch
|
||||
|
||||
def run(self):
|
||||
kindlegenErrorCode = 0
|
||||
kindlegenError = ''
|
||||
try:
|
||||
if os.path.getsize(self.work) < 367001600:
|
||||
output = Popen('kindlegen -locale en "' + self.work.encode(sys.getfilesystemencoding()) + '"',
|
||||
stdout=PIPE, stderr=STDOUT, shell=True)
|
||||
for line in output.stdout:
|
||||
# ERROR: Generic error
|
||||
if "Error(" in line:
|
||||
kindlegenErrorCode = 1
|
||||
kindlegenError = line
|
||||
# ERROR: EPUB too big
|
||||
if ":E23026:" in line:
|
||||
kindlegenErrorCode = 23026
|
||||
if kindlegenErrorCode > 0:
|
||||
break
|
||||
else:
|
||||
# ERROR: EPUB too big
|
||||
kindlegenErrorCode = 23026
|
||||
self.signals.result.emit([kindlegenErrorCode, kindlegenError, self.work])
|
||||
except StandardError:
|
||||
# ERROR: Unknown generic error
|
||||
kindlegenErrorCode = 1
|
||||
self.signals.result.emit([kindlegenErrorCode, kindlegenError, self.work])
|
||||
|
||||
|
||||
class KindleUnpackThread(QtCore.QRunnable):
|
||||
def __init__(self, batch):
|
||||
super(KindleUnpackThread, self).__init__()
|
||||
self.signals = WorkerSignals()
|
||||
self.work = batch
|
||||
|
||||
def run(self):
|
||||
item = self.work[0]
|
||||
profile = self.work[1]
|
||||
os.remove(item)
|
||||
mobiPath = item.replace('.epub', '.mobi')
|
||||
move(mobiPath, mobiPath + '_toclean')
|
||||
try:
|
||||
# MOBI file produced by KindleGen is hybrid. KF8 + M7 + Source header
|
||||
# KindleSplit is removing redundant data as we need only KF8 part for new Kindle models
|
||||
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())
|
||||
self.signals.result.emit([True])
|
||||
except StandardError:
|
||||
self.signals.result.emit([False])
|
||||
|
||||
|
||||
class WorkerThread(QtCore.QThread):
|
||||
#noinspection PyArgumentList
|
||||
def __init__(self):
|
||||
QtCore.QThread.__init__(self)
|
||||
self.pool = QtCore.QThreadPool()
|
||||
self.conversionAlive = False
|
||||
self.errors = False
|
||||
self.kindlegenErrorCode = 0
|
||||
self.kindlegenError = None
|
||||
self.kindlegenErrorCode = [0]
|
||||
self.workerOutput = []
|
||||
# Let's make sure that we don't fill the memory
|
||||
availableMemory = TOTAL_PHYMEM/1000000000
|
||||
if availableMemory <= 2:
|
||||
self.threadNumber = 1
|
||||
elif 2 < availableMemory <= 4:
|
||||
self.threadNumber = 2
|
||||
else:
|
||||
self.threadNumber = 4
|
||||
# Let's make sure that we don't use too many threads
|
||||
if self.threadNumber > QtCore.QThread.idealThreadCount():
|
||||
self.threadNumber = QtCore.QThread.idealThreadCount()
|
||||
|
||||
def __del__(self):
|
||||
self.wait()
|
||||
|
||||
def sync(self):
|
||||
self.conversionAlive = self.parent.conversionAlive
|
||||
self.conversionAlive = GUI.conversionAlive
|
||||
|
||||
def clean(self):
|
||||
self.parent.needClean = True
|
||||
GUI.progress.content = ''
|
||||
GUI.progress.stop()
|
||||
GUI.needClean = True
|
||||
self.emit(QtCore.SIGNAL("hideProgressBar"))
|
||||
self.emit(QtCore.SIGNAL("addMessage"), '<b>Conversion interrupted.</b>', 'error')
|
||||
self.emit(QtCore.SIGNAL("addTrayMessage"), 'Conversion interrupted.', 'Critical')
|
||||
self.emit(QtCore.SIGNAL("modeConvert"), True)
|
||||
|
||||
def addResult(self, output):
|
||||
self.emit(QtCore.SIGNAL("progressBarTick"))
|
||||
self.workerOutput.append(output)
|
||||
|
||||
def run(self):
|
||||
self.emit(QtCore.SIGNAL("modeConvert"), False)
|
||||
profile = ProfileData.ProfileLabels[str(GUI.DeviceBox.currentText())]
|
||||
@@ -129,7 +354,10 @@ class WorkerThread(QtCore.QThread):
|
||||
argv.append("--quality=1")
|
||||
elif GUI.QualityBox.checkState() == 2:
|
||||
argv.append("--quality=2")
|
||||
if self.parent.currentMode > 1:
|
||||
if GUI.currentMode == 1:
|
||||
if profile in ['KFHD', 'KFHD8', 'KFHDX', 'KFHDX8']:
|
||||
argv.append("--upscale")
|
||||
if GUI.currentMode > 1:
|
||||
if GUI.ProcessingBox.isChecked():
|
||||
argv.append("--noprocessing")
|
||||
if GUI.NoRotateBox.isChecked():
|
||||
@@ -146,13 +374,14 @@ class WorkerThread(QtCore.QThread):
|
||||
argv.append("--forcepng")
|
||||
if GUI.WebtoonBox.isChecked():
|
||||
argv.append("--webtoon")
|
||||
if float(self.parent.GammaValue) > 0.09:
|
||||
argv.append("--gamma=" + self.parent.GammaValue)
|
||||
if float(GUI.GammaValue) > 0.09:
|
||||
# noinspection PyTypeChecker
|
||||
argv.append("--gamma=" + GUI.GammaValue)
|
||||
if str(GUI.FormatBox.currentText()) == 'CBZ':
|
||||
argv.append("--cbz-output")
|
||||
if str(GUI.FormatBox.currentText()) == 'MOBI':
|
||||
argv.append("--batchsplit")
|
||||
if self.parent.currentMode > 2:
|
||||
if GUI.currentMode > 2:
|
||||
argv.append("--customwidth=" + str(GUI.customWidth.text()))
|
||||
argv.append("--customheight=" + str(GUI.customHeight.text()))
|
||||
if GUI.ColorBox.isChecked():
|
||||
@@ -163,16 +392,18 @@ class WorkerThread(QtCore.QThread):
|
||||
currentJobs.append(unicode(GUI.JobList.item(i).text()))
|
||||
GUI.JobList.clear()
|
||||
for job in currentJobs:
|
||||
time.sleep(0.5)
|
||||
sleep(0.5)
|
||||
if not self.conversionAlive:
|
||||
self.clean()
|
||||
return
|
||||
self.errors = False
|
||||
self.emit(QtCore.SIGNAL("addMessage"), '<b>Source:</b> ' + job, 'info')
|
||||
if str(GUI.FormatBox.currentText()) == 'CBZ':
|
||||
self.emit(QtCore.SIGNAL("addMessage"), 'Creating CBZ file...', 'info')
|
||||
self.emit(QtCore.SIGNAL("addMessage"), 'Creating CBZ files', 'info')
|
||||
GUI.progress.content = 'Creating CBZ files'
|
||||
else:
|
||||
self.emit(QtCore.SIGNAL("addMessage"), 'Creating EPUB file...', 'info')
|
||||
self.emit(QtCore.SIGNAL("addMessage"), 'Creating EPUB files', 'info')
|
||||
GUI.progress.content = 'Creating EPUB files'
|
||||
jobargv = list(argv)
|
||||
jobargv.append(job)
|
||||
try:
|
||||
@@ -183,15 +414,19 @@ class WorkerThread(QtCore.QThread):
|
||||
self.clean()
|
||||
return
|
||||
else:
|
||||
GUI.progress.content = ''
|
||||
self.errors = True
|
||||
self.emit(QtCore.SIGNAL("addMessage"), str(warn), 'warning')
|
||||
self.emit(QtCore.SIGNAL("addMessage"), 'KCC failed to create output file!', 'warning')
|
||||
self.emit(QtCore.SIGNAL("addMessage"), 'Failed to create output file!', 'warning')
|
||||
self.emit(QtCore.SIGNAL("addTrayMessage"), 'Failed to create output file!', 'Critical')
|
||||
except Exception as err:
|
||||
GUI.progress.content = ''
|
||||
self.errors = True
|
||||
type_, value_, traceback_ = sys.exc_info()
|
||||
self.emit(QtCore.SIGNAL("showDialog"), "Error during conversion %s:\n\n%s\n\nTraceback:\n%s"
|
||||
% (jobargv[-1], str(err), traceback.format_tb(traceback_)))
|
||||
self.emit(QtCore.SIGNAL("addMessage"), 'KCC failed to create EPUB!', 'error')
|
||||
self.emit(QtCore.SIGNAL("addMessage"), 'Failed to create EPUB!', 'error')
|
||||
self.emit(QtCore.SIGNAL("addTrayMessage"), 'Failed to create EPUB!', 'Critical')
|
||||
if not self.conversionAlive:
|
||||
for item in outputPath:
|
||||
if os.path.exists(item):
|
||||
@@ -199,109 +434,133 @@ class WorkerThread(QtCore.QThread):
|
||||
self.clean()
|
||||
return
|
||||
if not self.errors:
|
||||
GUI.progress.content = ''
|
||||
if str(GUI.FormatBox.currentText()) == 'CBZ':
|
||||
self.emit(QtCore.SIGNAL("addMessage"), 'Creating CBZ file... <b>Done!</b>', 'info', True)
|
||||
self.emit(QtCore.SIGNAL("addMessage"), 'Creating CBZ files... <b>Done!</b>', 'info', True)
|
||||
else:
|
||||
self.emit(QtCore.SIGNAL("addMessage"), 'Creating EPUB file... <b>Done!</b>', 'info', True)
|
||||
self.emit(QtCore.SIGNAL("addMessage"), 'Creating EPUB files... <b>Done!</b>', 'info', True)
|
||||
if str(GUI.FormatBox.currentText()) == 'MOBI':
|
||||
tomeNumber = 0
|
||||
self.emit(QtCore.SIGNAL("progressBarTick"), 'status', 'Creating MOBI files')
|
||||
self.emit(QtCore.SIGNAL("progressBarTick"), len(outputPath)*2+1)
|
||||
self.emit(QtCore.SIGNAL("progressBarTick"))
|
||||
self.emit(QtCore.SIGNAL("addMessage"), 'Creating MOBI files', 'info')
|
||||
GUI.progress.content = 'Creating MOBI files'
|
||||
self.workerOutput = []
|
||||
# Number of KindleGen threads depends on the size of RAM
|
||||
self.pool.setMaxThreadCount(self.threadNumber)
|
||||
for item in outputPath:
|
||||
tomeNumber += 1
|
||||
if len(outputPath) > 1:
|
||||
self.emit(QtCore.SIGNAL("addMessage"), 'Creating MOBI file (' + str(tomeNumber)
|
||||
+ '/' + str(len(outputPath)) + ')...', 'info')
|
||||
else:
|
||||
self.emit(QtCore.SIGNAL("addMessage"), 'Creating MOBI file...', 'info')
|
||||
self.emit(QtCore.SIGNAL("progressBarTick"), 1)
|
||||
try:
|
||||
self.kindlegenErrorCode = 0
|
||||
if os.path.getsize(item) < 367001600:
|
||||
output = Popen('kindlegen -locale en "' + item.encode(sys.getfilesystemencoding()) +
|
||||
'"', stdout=PIPE, stderr=STDOUT, shell=True)
|
||||
for line in output.stdout:
|
||||
# ERROR: Generic error
|
||||
if "Error(" in line:
|
||||
self.kindlegenErrorCode = 1
|
||||
self.kindlegenError = line
|
||||
# ERROR: EPUB too big
|
||||
if ":E23026:" in line:
|
||||
self.kindlegenErrorCode = 23026
|
||||
if self.kindlegenErrorCode > 0:
|
||||
break
|
||||
else:
|
||||
# ERROR: EPUB too big
|
||||
self.kindlegenErrorCode = 23026
|
||||
except:
|
||||
# ERROR: Unknown generic error
|
||||
self.kindlegenErrorCode = 1
|
||||
continue
|
||||
if not self.conversionAlive:
|
||||
for item in outputPath:
|
||||
if os.path.exists(item):
|
||||
os.remove(item)
|
||||
if os.path.exists(item.replace('.epub', '.mobi')):
|
||||
os.remove(item.replace('.epub', '.mobi'))
|
||||
self.clean()
|
||||
return
|
||||
if self.kindlegenErrorCode == 0:
|
||||
if len(outputPath) > 1:
|
||||
self.emit(QtCore.SIGNAL("addMessage"), 'Creating MOBI file (' + str(tomeNumber) + '/'
|
||||
+ str(len(outputPath)) + ')... <b>Done!</b>',
|
||||
'info', True)
|
||||
else:
|
||||
self.emit(QtCore.SIGNAL("addMessage"), 'Creating MOBI file... <b>Done!</b>', 'info',
|
||||
True)
|
||||
self.emit(QtCore.SIGNAL("addMessage"), 'Cleaning MOBI file...', 'info')
|
||||
os.remove(item)
|
||||
mobiPath = item.replace('.epub', '.mobi')
|
||||
shutil.move(mobiPath, mobiPath + '_toclean')
|
||||
try:
|
||||
# MOBI file produced by KindleGen is hybrid. KF8 + M7 + Source header
|
||||
# KindleSplit is removing redundant data as we need only KF8 part for new Kindle models
|
||||
if profile in ['K345', 'KHD', 'KF', 'KFHD', 'KFHD8', '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 + '_toclean')
|
||||
self.emit(QtCore.SIGNAL("addMessage"), 'Cleaning MOBI file... <b>Done!</b>', 'info',
|
||||
True)
|
||||
else:
|
||||
os.remove(mobiPath + '_toclean')
|
||||
os.remove(mobiPath)
|
||||
self.emit(QtCore.SIGNAL("addMessage"),
|
||||
'KindleUnpack failed to clean MOBI file!', 'error')
|
||||
else:
|
||||
epubSize = (os.path.getsize(item))/1024/1024
|
||||
os.remove(item)
|
||||
worker = KindleGenThread(item)
|
||||
worker.signals.result.connect(self.addResult)
|
||||
self.pool.start(worker)
|
||||
self.pool.waitForDone()
|
||||
sleep(0.5)
|
||||
self.kindlegenErrorCode = [0]
|
||||
for errors in self.workerOutput:
|
||||
if errors[0] != 0:
|
||||
self.kindlegenErrorCode = errors
|
||||
break
|
||||
if not self.conversionAlive:
|
||||
for item in outputPath:
|
||||
if os.path.exists(item):
|
||||
os.remove(item)
|
||||
if os.path.exists(item.replace('.epub', '.mobi')):
|
||||
os.remove(item.replace('.epub', '.mobi'))
|
||||
self.emit(QtCore.SIGNAL("addMessage"), 'KindleGen failed to create MOBI!', 'error')
|
||||
if self.kindlegenErrorCode == 1 and self.kindlegenError:
|
||||
self.emit(QtCore.SIGNAL("showDialog"), "KindleGen error:\n\n" + self.kindlegenError)
|
||||
if self.kindlegenErrorCode == 23026:
|
||||
self.emit(QtCore.SIGNAL("addMessage"), 'Created EPUB file was too big.',
|
||||
'error')
|
||||
self.emit(QtCore.SIGNAL("addMessage"), 'EPUB file: ' + str(epubSize) + 'MB.'
|
||||
' Supported size: ~300MB.', 'error')
|
||||
self.clean()
|
||||
return
|
||||
if self.kindlegenErrorCode[0] == 0:
|
||||
GUI.progress.content = ''
|
||||
self.emit(QtCore.SIGNAL("addMessage"), 'Creating MOBI files... <b>Done!</b>', 'info', True)
|
||||
self.emit(QtCore.SIGNAL("addMessage"), 'Cleaning MOBI files', 'info')
|
||||
GUI.progress.content = 'Cleaning MOBI files'
|
||||
self.workerOutput = []
|
||||
# Multithreading KindleUnpack in current form is a waste of resources.
|
||||
# Unless we higly optimise KindleUnpack or drop 32bit support this will not change.
|
||||
self.pool.setMaxThreadCount(1)
|
||||
for item in outputPath:
|
||||
worker = KindleUnpackThread([item, profile])
|
||||
worker.signals.result.connect(self.addResult)
|
||||
self.pool.start(worker)
|
||||
self.pool.waitForDone()
|
||||
sleep(0.5)
|
||||
for success in self.workerOutput:
|
||||
if not success:
|
||||
self.errors = True
|
||||
break
|
||||
if not self.errors:
|
||||
for item in outputPath:
|
||||
GUI.progress.content = ''
|
||||
mobiPath = item.replace('.epub', '.mobi')
|
||||
os.remove(mobiPath + '_toclean')
|
||||
GUI.completedWork[os.path.basename(mobiPath).encode('utf-8')] = \
|
||||
mobiPath.encode('utf-8')
|
||||
self.emit(QtCore.SIGNAL("addMessage"), 'Cleaning MOBI files... <b>Done!</b>', 'info',
|
||||
True)
|
||||
else:
|
||||
GUI.progress.content = ''
|
||||
for item in outputPath:
|
||||
mobiPath = item.replace('.epub', '.mobi')
|
||||
if os.path.exists(mobiPath):
|
||||
os.remove(mobiPath)
|
||||
if os.path.exists(mobiPath + '_toclean'):
|
||||
os.remove(mobiPath + '_toclean')
|
||||
self.emit(QtCore.SIGNAL("addMessage"), 'KindleUnpack failed to clean MOBI file!', 'error')
|
||||
self.emit(QtCore.SIGNAL("addTrayMessage"), 'KindleUnpack failed to clean MOBI file!',
|
||||
'Critical')
|
||||
else:
|
||||
GUI.progress.content = ''
|
||||
epubSize = (os.path.getsize(self.kindlegenErrorCode[2]))/1024/1024
|
||||
for item in outputPath:
|
||||
if os.path.exists(item):
|
||||
os.remove(item)
|
||||
if os.path.exists(item.replace('.epub', '.mobi')):
|
||||
os.remove(item.replace('.epub', '.mobi'))
|
||||
self.emit(QtCore.SIGNAL("addMessage"), 'KindleGen failed to create MOBI!', 'error')
|
||||
self.emit(QtCore.SIGNAL("addTrayMessage"), 'KindleGen failed to create MOBI!', 'Critical')
|
||||
if self.kindlegenErrorCode[0] == 1 and self.kindlegenErrorCode[1] != '':
|
||||
self.emit(QtCore.SIGNAL("showDialog"), "KindleGen error:\n\n" +
|
||||
self.self.kindlegenErrorCode[1])
|
||||
if self.kindlegenErrorCode[0] == 23026:
|
||||
self.emit(QtCore.SIGNAL("addMessage"), 'Created EPUB file was too big.',
|
||||
'error')
|
||||
self.emit(QtCore.SIGNAL("addMessage"), 'EPUB file: ' + str(epubSize) + 'MB.'
|
||||
' Supported size: ~300MB.', 'error')
|
||||
else:
|
||||
for item in outputPath:
|
||||
GUI.completedWork[os.path.basename(item).encode('utf-8')] = item.encode('utf-8')
|
||||
GUI.progress.content = ''
|
||||
GUI.progress.stop()
|
||||
self.emit(QtCore.SIGNAL("hideProgressBar"))
|
||||
self.parent.needClean = True
|
||||
GUI.needClean = True
|
||||
self.emit(QtCore.SIGNAL("addMessage"), '<b>All jobs completed.</b>', 'info')
|
||||
self.emit(QtCore.SIGNAL("addTrayMessage"), 'All jobs completed.', 'Information')
|
||||
self.emit(QtCore.SIGNAL("modeConvert"), True)
|
||||
|
||||
|
||||
# noinspection PyBroadException
|
||||
class Ui_KCC(object):
|
||||
class SystemTrayIcon(QtGui.QSystemTrayIcon):
|
||||
def __init__(self):
|
||||
if not sys.platform.startswith('darwin') and self.isSystemTrayAvailable():
|
||||
QtGui.QSystemTrayIcon.__init__(self, GUI.icons.programIcon, MW)
|
||||
self.activated.connect(self.catchClicks)
|
||||
|
||||
def catchClicks(self):
|
||||
MW.showNormal()
|
||||
MW.raise_()
|
||||
MW.activateWindow()
|
||||
|
||||
def addTrayMessage(self, message, icon):
|
||||
if not sys.platform.startswith('darwin'):
|
||||
icon = eval('QtGui.QSystemTrayIcon.' + icon)
|
||||
if self.supportsMessages() and not MW.isActiveWindow():
|
||||
self.showMessage('Kindle Comic Converter', message, icon)
|
||||
|
||||
|
||||
class KCCGUI(KCC_ui.Ui_KCC):
|
||||
def selectDir(self):
|
||||
if self.needClean:
|
||||
self.needClean = False
|
||||
GUI.JobList.clear()
|
||||
# Dirty, dirty way but OS native QFileDialogs don't support directory multiselect
|
||||
dirDialog = QtGui.QFileDialog(MainWindow, 'Select directory', self.lastPath)
|
||||
dirDialog = QtGui.QFileDialog(MW, 'Select directory', self.lastPath)
|
||||
dirDialog.setFileMode(dirDialog.Directory)
|
||||
dirDialog.setOption(dirDialog.ShowDirsOnly, True)
|
||||
dirDialog.setOption(dirDialog.DontUseNativeDialog, True)
|
||||
@@ -321,6 +580,7 @@ class Ui_KCC(object):
|
||||
dname = dname.replace('/', '\\')
|
||||
self.lastPath = os.path.abspath(os.path.join(unicode(dname), os.pardir))
|
||||
GUI.JobList.addItem(dname)
|
||||
MW.setFocus()
|
||||
|
||||
def selectFile(self):
|
||||
if self.needClean:
|
||||
@@ -328,17 +588,17 @@ class Ui_KCC(object):
|
||||
GUI.JobList.clear()
|
||||
if self.UnRAR:
|
||||
if self.sevenza:
|
||||
fnames = QtGui.QFileDialog.getOpenFileNames(MainWindow, 'Select file', self.lastPath,
|
||||
fnames = QtGui.QFileDialog.getOpenFileNames(MW, 'Select file', self.lastPath,
|
||||
'*.cbz *.cbr *.cb7 *.zip *.rar *.7z *.pdf')
|
||||
else:
|
||||
fnames = QtGui.QFileDialog.getOpenFileNames(MainWindow, 'Select file', self.lastPath,
|
||||
fnames = QtGui.QFileDialog.getOpenFileNames(MW, 'Select file', self.lastPath,
|
||||
'*.cbz *.cbr *.zip *.rar *.pdf')
|
||||
else:
|
||||
if self.sevenza:
|
||||
fnames = QtGui.QFileDialog.getOpenFileNames(MainWindow, 'Select file', self.lastPath,
|
||||
fnames = QtGui.QFileDialog.getOpenFileNames(MW, 'Select file', self.lastPath,
|
||||
'*.cbz *.cb7 *.zip *.7z *.pdf')
|
||||
else:
|
||||
fnames = QtGui.QFileDialog.getOpenFileNames(MainWindow, 'Select file', self.lastPath,
|
||||
fnames = QtGui.QFileDialog.getOpenFileNames(MW, 'Select file', self.lastPath,
|
||||
'*.cbz *.zip *.pdf')
|
||||
for fname in fnames:
|
||||
if unicode(fname) != "":
|
||||
@@ -350,9 +610,14 @@ class Ui_KCC(object):
|
||||
|
||||
def modeBasic(self):
|
||||
self.currentMode = 1
|
||||
MainWindow.setMinimumSize(QtCore.QSize(420, 270))
|
||||
MainWindow.setMaximumSize(QtCore.QSize(420, 270))
|
||||
MainWindow.resize(420, 270)
|
||||
if sys.platform.startswith('darwin'):
|
||||
MW.setMinimumSize(QtCore.QSize(420, 291))
|
||||
MW.setMaximumSize(QtCore.QSize(420, 291))
|
||||
MW.resize(420, 291)
|
||||
else:
|
||||
MW.setMinimumSize(QtCore.QSize(420, 287))
|
||||
MW.setMaximumSize(QtCore.QSize(420, 287))
|
||||
MW.resize(420, 287)
|
||||
GUI.BasicModeButton.setStyleSheet('font-weight:Bold;')
|
||||
GUI.AdvModeButton.setStyleSheet('font-weight:Normal;')
|
||||
GUI.FormatBox.setCurrentIndex(0)
|
||||
@@ -371,9 +636,9 @@ class Ui_KCC(object):
|
||||
|
||||
def modeAdvanced(self):
|
||||
self.currentMode = 2
|
||||
MainWindow.setMinimumSize(QtCore.QSize(420, 345))
|
||||
MainWindow.setMaximumSize(QtCore.QSize(420, 345))
|
||||
MainWindow.resize(420, 345)
|
||||
MW.setMinimumSize(QtCore.QSize(420, 365))
|
||||
MW.setMaximumSize(QtCore.QSize(420, 365))
|
||||
MW.resize(420, 365)
|
||||
GUI.BasicModeButton.setStyleSheet('font-weight:Normal;')
|
||||
GUI.AdvModeButton.setStyleSheet('font-weight:Bold;')
|
||||
GUI.FormatBox.setEnabled(True)
|
||||
@@ -388,9 +653,9 @@ class Ui_KCC(object):
|
||||
def modeExpert(self, KFA=False):
|
||||
self.modeAdvanced()
|
||||
self.currentMode = 3
|
||||
MainWindow.setMinimumSize(QtCore.QSize(420, 380))
|
||||
MainWindow.setMaximumSize(QtCore.QSize(420, 380))
|
||||
MainWindow.resize(420, 380)
|
||||
MW.setMinimumSize(QtCore.QSize(420, 397))
|
||||
MW.setMaximumSize(QtCore.QSize(420, 397))
|
||||
MW.resize(420, 397)
|
||||
GUI.OptionsExpert.setEnabled(True)
|
||||
if KFA:
|
||||
GUI.ColorBox.setChecked(True)
|
||||
@@ -454,7 +719,6 @@ class Ui_KCC(object):
|
||||
GUI.QualityBox.setChecked(False)
|
||||
GUI.MangaBox.setEnabled(False)
|
||||
GUI.MangaBox.setChecked(False)
|
||||
self.addMessage('If images will be too dark after conversion: Set <i>Gamma</i> to 1.0.', 'info')
|
||||
else:
|
||||
if not GUI.ProcessingBox.isChecked():
|
||||
GUI.NoRotateBox.setEnabled(True)
|
||||
@@ -527,9 +791,12 @@ class Ui_KCC(object):
|
||||
GUI.QualityBox.setChecked(False)
|
||||
GUI.QualityBox.setEnabled(False)
|
||||
self.QualityBoxDisabled = True
|
||||
if value in [4, 5, 6, 7]:
|
||||
if GUI.UpscaleBox.isEnabled():
|
||||
GUI.UpscaleBox.setChecked(True)
|
||||
else:
|
||||
if not GUI.WebtoonBox.isChecked() and not GUI.ProcessingBox.isChecked() \
|
||||
and str(GUI.FormatBox.currentText()) != 'CBZ':
|
||||
and str(GUI.FormatBox.currentText()) != 'CBZ' and value not in [9, 11, 12, 13]:
|
||||
GUI.QualityBox.setEnabled(True)
|
||||
self.QualityBoxDisabled = False
|
||||
|
||||
@@ -568,7 +835,7 @@ class Ui_KCC(object):
|
||||
GUI.JobList.scrollToBottom()
|
||||
|
||||
def showDialog(self, message):
|
||||
QtGui.QMessageBox.critical(MainWindow, 'KCC - Error', message, QtGui.QMessageBox.Ok)
|
||||
QtGui.QMessageBox.critical(MW, 'KCC - Error', message, QtGui.QMessageBox.Ok)
|
||||
|
||||
def updateProgressbar(self, new=False, status=False):
|
||||
if new == "status":
|
||||
@@ -587,6 +854,7 @@ class Ui_KCC(object):
|
||||
self.conversionAlive = False
|
||||
self.worker.sync()
|
||||
else:
|
||||
self.progress.start()
|
||||
if self.needClean:
|
||||
self.needClean = False
|
||||
GUI.JobList.clear()
|
||||
@@ -613,6 +881,7 @@ class Ui_KCC(object):
|
||||
event.ignore()
|
||||
if not GUI.ConvertButton.isEnabled():
|
||||
event.ignore()
|
||||
self.contentServer.stop()
|
||||
self.settings.setValue('settingsVersion', __version__)
|
||||
self.settings.setValue('lastPath', self.lastPath)
|
||||
self.settings.setValue('lastDevice', GUI.DeviceBox.currentIndex())
|
||||
@@ -635,8 +904,8 @@ class Ui_KCC(object):
|
||||
self.settings.sync()
|
||||
|
||||
def handleMessage(self, message):
|
||||
MainWindow.raise_()
|
||||
MainWindow.activateWindow()
|
||||
MW.raise_()
|
||||
MW.activateWindow()
|
||||
if not self.conversionAlive:
|
||||
if self.needClean:
|
||||
self.needClean = False
|
||||
@@ -660,14 +929,18 @@ class Ui_KCC(object):
|
||||
else:
|
||||
self.addMessage('This file type is unsupported!', 'error')
|
||||
|
||||
def __init__(self, UI, KCC, APP):
|
||||
global GUI, MainWindow
|
||||
GUI = UI
|
||||
MainWindow = KCC
|
||||
def __init__(self, KCCAplication, KCCWindow):
|
||||
global APP, MW, GUI
|
||||
APP = KCCAplication
|
||||
MW = KCCWindow
|
||||
GUI = self
|
||||
self.setupUi(MW)
|
||||
# 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.webContent = WebContent()
|
||||
self.tray = SystemTrayIcon()
|
||||
self.settings = QtCore.QSettings('KindleComicConverter', 'KindleComicConverter')
|
||||
self.settingsVersion = self.settings.value('settingsVersion', '', type=str)
|
||||
if self.settingsVersion in purgeSettingsVersions:
|
||||
@@ -680,25 +953,49 @@ class Ui_KCC(object):
|
||||
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.worker = WorkerThread()
|
||||
self.versionCheck = VersionThread()
|
||||
self.contentServer = WebServerThread()
|
||||
self.progress = ProgressThread()
|
||||
self.conversionAlive = False
|
||||
self.needClean = True
|
||||
self.QualityBoxDisabled = False
|
||||
self.GammaValue = 1.0
|
||||
self.completedWork = {}
|
||||
if sys.platform.startswith('darwin'):
|
||||
self.listFontSize = 11
|
||||
self.statusBarFontSize = 10
|
||||
self.statusBarStyle = 'QLabel{padding-top:5px;padding-bottom:5px;border-top:2px solid #C2C7CB}'
|
||||
elif sys.platform.startswith('linux'):
|
||||
self.listFontSize = 8
|
||||
self.statusBarFontSize = 8
|
||||
self.statusBarStyle = 'QLabel{padding-top:5px;padding-bottom:3px;border-top:2px solid #C2C7CB}'
|
||||
self.tray.show()
|
||||
else:
|
||||
self.listFontSize = 9
|
||||
self.statusBarFontSize = 8
|
||||
self.statusBarStyle = 'QLabel{padding-top:3px;padding-bottom:3px;border-top:2px solid #C2C7CB}'
|
||||
self.tray.show()
|
||||
|
||||
statusBarLabel = QtGui.QLabel('<b><a href="http://kcc.vulturis.eu/">HOMEPAGE</a> - <a href="https://github.com/'
|
||||
'ciromattia/kcc/blob/master/README.md#issues--new-features--donations">DONATE</a>'
|
||||
' - <a href="https://github.com/ciromattia/kcc/blob/master/README.md#kcc">README<'
|
||||
'/a> - <a href="https://github.com/ciromattia/kcc/wiki">WIKI</a></b>')
|
||||
statusBarLabel.setAlignment(QtCore.Qt.AlignCenter)
|
||||
statusBarLabel.setStyleSheet(self.statusBarStyle)
|
||||
statusBarLabel.setOpenExternalLinks(True)
|
||||
statusBarLabelFont = QtGui.QFont()
|
||||
statusBarLabelFont.setPointSize(self.statusBarFontSize)
|
||||
statusBarLabel.setFont(statusBarLabelFont)
|
||||
GUI.statusBar.addPermanentWidget(statusBarLabel, 1)
|
||||
|
||||
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:
|
||||
kindleGenExitCode = Popen('kindlegen -locale en', stdout=PIPE, stderr=STDOUT, shell=True)
|
||||
if kindleGenExitCode.wait() == 0:
|
||||
self.KindleGen = True
|
||||
formats = ['MOBI', 'EPUB', 'CBZ']
|
||||
versionCheck = Popen('kindlegen -locale en', stdout=PIPE, stderr=STDOUT, shell=True)
|
||||
@@ -716,14 +1013,16 @@ class Ui_KCC(object):
|
||||
formats = ['EPUB', 'CBZ']
|
||||
self.addMessage('Cannot find <a href="http://www.amazon.com/gp/feature.html?ie=UTF8&docId='
|
||||
'1000765211">kindlegen</a> in PATH! MOBI creation will be disabled.', 'warning')
|
||||
rarExitCode = call('unrar', stdout=PIPE, stderr=STDOUT, shell=True)
|
||||
rarExitCode = Popen('unrar', stdout=PIPE, stderr=STDOUT, shell=True)
|
||||
rarExitCode = rarExitCode.wait()
|
||||
if rarExitCode == 0 or rarExitCode == 7:
|
||||
self.UnRAR = True
|
||||
else:
|
||||
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)
|
||||
sevenzaExitCode = Popen('7za', stdout=PIPE, stderr=STDOUT, shell=True)
|
||||
sevenzaExitCode = sevenzaExitCode.wait()
|
||||
if sevenzaExitCode == 0 or sevenzaExitCode == 7:
|
||||
self.sevenza = True
|
||||
else:
|
||||
@@ -744,13 +1043,16 @@ class Ui_KCC(object):
|
||||
GUI.ProcessingBox.stateChanged.connect(self.toggleProcessingBox)
|
||||
GUI.DeviceBox.activated.connect(self.changeDevice)
|
||||
GUI.FormatBox.activated.connect(self.changeFormat)
|
||||
KCC.connect(self.worker, QtCore.SIGNAL("progressBarTick"), self.updateProgressbar)
|
||||
KCC.connect(self.worker, QtCore.SIGNAL("modeConvert"), self.modeConvert)
|
||||
KCC.connect(self.worker, QtCore.SIGNAL("addMessage"), self.addMessage)
|
||||
KCC.connect(self.worker, QtCore.SIGNAL("showDialog"), self.showDialog)
|
||||
KCC.connect(self.worker, QtCore.SIGNAL("hideProgressBar"), self.hideProgressBar)
|
||||
KCC.connect(self.versionCheck, QtCore.SIGNAL("addMessage"), self.addMessage)
|
||||
KCC.closeEvent = self.saveSettings
|
||||
MW.connect(self.worker, QtCore.SIGNAL("progressBarTick"), self.updateProgressbar)
|
||||
MW.connect(self.worker, QtCore.SIGNAL("modeConvert"), self.modeConvert)
|
||||
MW.connect(self.worker, QtCore.SIGNAL("addMessage"), self.addMessage)
|
||||
MW.connect(self.worker, QtCore.SIGNAL("addTrayMessage"), self.tray.addTrayMessage)
|
||||
MW.connect(self.worker, QtCore.SIGNAL("showDialog"), self.showDialog)
|
||||
MW.connect(self.worker, QtCore.SIGNAL("hideProgressBar"), self.hideProgressBar)
|
||||
MW.connect(self.versionCheck, QtCore.SIGNAL("addMessage"), self.addMessage)
|
||||
MW.connect(self.contentServer, QtCore.SIGNAL("addMessage"), self.addMessage)
|
||||
MW.connect(self.progress, QtCore.SIGNAL("addMessage"), self.addMessage)
|
||||
MW.closeEvent = self.saveSettings
|
||||
|
||||
for f in formats:
|
||||
GUI.FormatBox.addItem(eval('self.icons.' + f + 'Format'), f)
|
||||
@@ -791,5 +1093,9 @@ class Ui_KCC(object):
|
||||
self.changeDevice(self.lastDevice)
|
||||
self.changeFormat()
|
||||
self.versionCheck.start()
|
||||
self.contentServer.start()
|
||||
self.hideProgressBar()
|
||||
self.worker.sync()
|
||||
MW.setWindowTitle("Kindle Comic Converter " + __version__)
|
||||
MW.show()
|
||||
MW.raise_()
|
||||
|
||||
225
kcc/KCC_rc_web.py
Normal file
225
kcc/KCC_rc_web.py
Normal file
@@ -0,0 +1,225 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Resources used by content server
|
||||
|
||||
|
||||
class WebContent:
|
||||
def __init__(self):
|
||||
self.favicon = 'data:image/x-icon;base64,AAABAAEAEBAAAAAAAABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAA' \
|
||||
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACalpVpycW64O7q20wAAAAAAAAAAAA' \
|
||||
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVlNNSJiWj//i39b11dHDKAAAAAAAAAAAAAA' \
|
||||
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEpGP0eKh4L/19fU/9DLvo4AAAAAAAAAAAAAAAAAAAA' \
|
||||
'AAAAAAJCOdiqRkIprr6yhfrSxpom4tauRu7mvl8C+s52opJvFvLu3/6nq7v/P087i0c7AVtLPwi4AAAAAAAAAALm1hTK' \
|
||||
'NinTvv723/9rZ0P/g3NH/39rT/+Db1//e3Nr/497b/8Tb3/8s4/z/yObp/9zRy//R0MnnAAAAAAAAAAC4tImElJGF/9v' \
|
||||
'b0/+8udn/bpnl/2ax+v9Rru//OMTi/zXc9v8i5///AOD//1Tf9P/W5ez/2dXS8AAAAAAAAAAAubSOprayqf/p5tv/dI3' \
|
||||
'g/wNh2/8Rd+f/Dn7d/waO2/8AxOj/AKvW/wC+4P8Akdb/oMzt/+fg2e0AAAAAAAAAAKymhr3Bvrf/6Ojj/z5F0P8DH8H' \
|
||||
'/GG/a/yKQ//8RleT/FInf/xuD6f8QfMf/EpL//4Kx5P/m4NftAAAAAAAAAACinIPK0c/F/9jX6f8ZIuz/BinM/xFQ2/8' \
|
||||
'il///IIz4/yKP//8fivf/IIr7/xN+8P9ff7D/49/Y7QAAAAAAAAAAnJaB1OLh1P+6uuf/AQLt/wEH+v8bffv/G3jf/w5' \
|
||||
'Gxv8eifP/CSzL/xp35P8HReH/TVKz/+Ti1+0AAAAAAAAAAJeRgdzw7+D/nJ3f/wAA+f8FGuT/Ci/F/wAD3P8FGtj/CS7' \
|
||||
'd/wAA8P8NQMX/AA7//01Lxv/o6NftAAAAAAAAAACTjYHj+/rm/3t89/8AAO7/AAC8/wAA9P8AAP//AADz/wAA/f8AAP/' \
|
||||
'/AAPi/wAA9v9aWrz/7e3e7QAAAAAAAAAAk42D5/v68f+op9b/NTVx/w8PkP8AAPz/AADU/wAA8v8AAP//AADn/wAA//8' \
|
||||
'AAJb/cnKP//X07e0AAAAAAAAAAJmUi+/5+Pj//f72//f37v/b2/T/t7bw/5GRv/9ycvT/Xl7v/1NTu/9QUPX/VlaJ/8D' \
|
||||
'Avv/z8vDuAAAAAAAAAAB7dGrWqKSe/83Kx//l5OL/9/fx////+P/////////7////+v////v////3/////f/9/fz/8/L' \
|
||||
'x9gAAAAAAAAAAbGVaGmhhVWBsZVqTd3FmtYmDesublo7YrKih4rq3sebFwr3nzMnE5M7MyN7PzMjUxsO/xNzb2IEAAAA' \
|
||||
'A/98AAP/PAAD/xwAA+AcAAMABAACAAQAAgAEAAIABAACAAQAAgAEAAIABAACAAQAAgAEAAIABAACAAQAA4AEAAA%3D%3D'
|
||||
self.logo = 'data:image/jpeg;base64,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' \
|
||||
'ruooAoSOUAUAUAUAUAUB/9k%3D'
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'KCC.ui'
|
||||
#
|
||||
# Created: Sat Oct 12 11:28:00 2013
|
||||
# Created: Wed Dec 04 18:28:13 2013
|
||||
# by: PyQt4 UI code generator 4.10.3
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
@@ -26,13 +26,12 @@ except AttributeError:
|
||||
class Ui_KCC(object):
|
||||
def setupUi(self, KCC):
|
||||
KCC.setObjectName(_fromUtf8("KCC"))
|
||||
KCC.resize(420, 380)
|
||||
KCC.setMinimumSize(QtCore.QSize(420, 380))
|
||||
KCC.setMaximumSize(QtCore.QSize(420, 380))
|
||||
KCC.resize(420, 397)
|
||||
KCC.setMinimumSize(QtCore.QSize(420, 397))
|
||||
KCC.setMaximumSize(QtCore.QSize(420, 397))
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(9)
|
||||
KCC.setFont(font)
|
||||
KCC.setFocusPolicy(QtCore.Qt.NoFocus)
|
||||
icon = QtGui.QIcon()
|
||||
icon.addPixmap(QtGui.QPixmap(_fromUtf8(":/Icon/icons/comic2ebook.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
KCC.setWindowIcon(icon)
|
||||
@@ -247,6 +246,14 @@ class Ui_KCC(object):
|
||||
self.customHeight.setObjectName(_fromUtf8("customHeight"))
|
||||
self.gridLayout_2.addWidget(self.customHeight, 0, 3, 1, 1)
|
||||
KCC.setCentralWidget(self.Form)
|
||||
self.statusBar = QtGui.QStatusBar(KCC)
|
||||
font = QtGui.QFont()
|
||||
font.setFamily(_fromUtf8("MS Shell Dlg 2"))
|
||||
font.setPointSize(8)
|
||||
self.statusBar.setFont(font)
|
||||
self.statusBar.setSizeGripEnabled(False)
|
||||
self.statusBar.setObjectName(_fromUtf8("statusBar"))
|
||||
KCC.setStatusBar(self.statusBar)
|
||||
self.ActionBasic = QtGui.QAction(KCC)
|
||||
self.ActionBasic.setCheckable(True)
|
||||
self.ActionBasic.setChecked(False)
|
||||
@@ -298,9 +305,7 @@ class Ui_KCC(object):
|
||||
self.RotateBox.setText(_translate("KCC", "Horizontal mode", None))
|
||||
self.BasicModeButton.setText(_translate("KCC", "Basic", None))
|
||||
self.AdvModeButton.setText(_translate("KCC", "Advanced", None))
|
||||
self.GammaLabel.setToolTip(_translate("KCC", "When converting color images setting this option to 1.0 MIGHT improve readability.", None))
|
||||
self.GammaLabel.setText(_translate("KCC", "Gamma: Auto", None))
|
||||
self.GammaSlider.setToolTip(_translate("KCC", "<html><head/><body><p>When converting color images setting this option to 1.0 <span style=\" font-weight:600;\">might</span> improve readability.</p></body></html>", None))
|
||||
self.ColorBox.setToolTip(_translate("KCC", "Do not convert images to grayscale.", None))
|
||||
self.ColorBox.setText(_translate("KCC", "Color mode", None))
|
||||
self.wLabel.setToolTip(_translate("KCC", "Resolution of target device.", None))
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'KCC-Linux.ui'
|
||||
#
|
||||
# Created: Sat Oct 12 11:28:11 2013
|
||||
# Created: Wed Dec 04 18:27:52 2013
|
||||
# by: PyQt4 UI code generator 4.10.3
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
@@ -26,13 +26,12 @@ except AttributeError:
|
||||
class Ui_KCC(object):
|
||||
def setupUi(self, KCC):
|
||||
KCC.setObjectName(_fromUtf8("KCC"))
|
||||
KCC.resize(420, 380)
|
||||
KCC.setMinimumSize(QtCore.QSize(420, 380))
|
||||
KCC.setMaximumSize(QtCore.QSize(420, 380))
|
||||
KCC.resize(420, 397)
|
||||
KCC.setMinimumSize(QtCore.QSize(420, 397))
|
||||
KCC.setMaximumSize(QtCore.QSize(420, 397))
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(9)
|
||||
KCC.setFont(font)
|
||||
KCC.setFocusPolicy(QtCore.Qt.NoFocus)
|
||||
icon = QtGui.QIcon()
|
||||
icon.addPixmap(QtGui.QPixmap(_fromUtf8(":/Icon/icons/comic2ebook.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
KCC.setWindowIcon(icon)
|
||||
@@ -317,6 +316,14 @@ class Ui_KCC(object):
|
||||
self.customHeight.setObjectName(_fromUtf8("customHeight"))
|
||||
self.gridLayout_2.addWidget(self.customHeight, 0, 3, 1, 1)
|
||||
KCC.setCentralWidget(self.Form)
|
||||
self.statusBar = QtGui.QStatusBar(KCC)
|
||||
font = QtGui.QFont()
|
||||
font.setFamily(_fromUtf8("DejaVu Sans"))
|
||||
font.setPointSize(8)
|
||||
self.statusBar.setFont(font)
|
||||
self.statusBar.setSizeGripEnabled(False)
|
||||
self.statusBar.setObjectName(_fromUtf8("statusBar"))
|
||||
KCC.setStatusBar(self.statusBar)
|
||||
self.ActionBasic = QtGui.QAction(KCC)
|
||||
self.ActionBasic.setCheckable(True)
|
||||
self.ActionBasic.setChecked(False)
|
||||
@@ -367,9 +374,7 @@ class Ui_KCC(object):
|
||||
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))
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Form implementation generated from reading ui file 'KCC-OSX.ui'
|
||||
#
|
||||
# Created: Sat Oct 12 11:28:19 2013
|
||||
# Created: Wed Dec 04 18:28:04 2013
|
||||
# by: PyQt4 UI code generator 4.10.3
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
@@ -26,13 +26,12 @@ except AttributeError:
|
||||
class Ui_KCC(object):
|
||||
def setupUi(self, KCC):
|
||||
KCC.setObjectName(_fromUtf8("KCC"))
|
||||
KCC.resize(420, 380)
|
||||
KCC.setMinimumSize(QtCore.QSize(420, 380))
|
||||
KCC.setMaximumSize(QtCore.QSize(420, 380))
|
||||
KCC.resize(420, 397)
|
||||
KCC.setMinimumSize(QtCore.QSize(420, 397))
|
||||
KCC.setMaximumSize(QtCore.QSize(420, 397))
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(9)
|
||||
KCC.setFont(font)
|
||||
KCC.setFocusPolicy(QtCore.Qt.NoFocus)
|
||||
icon = QtGui.QIcon()
|
||||
icon.addPixmap(QtGui.QPixmap(_fromUtf8(":/Icon/icons/comic2ebook.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
|
||||
KCC.setWindowIcon(icon)
|
||||
@@ -340,6 +339,14 @@ class Ui_KCC(object):
|
||||
self.customHeight.setObjectName(_fromUtf8("customHeight"))
|
||||
self.gridLayout_2.addWidget(self.customHeight, 0, 3, 1, 1)
|
||||
KCC.setCentralWidget(self.Form)
|
||||
self.statusBar = QtGui.QStatusBar(KCC)
|
||||
font = QtGui.QFont()
|
||||
font.setFamily(_fromUtf8("Aharoni"))
|
||||
font.setPointSize(8)
|
||||
self.statusBar.setFont(font)
|
||||
self.statusBar.setSizeGripEnabled(False)
|
||||
self.statusBar.setObjectName(_fromUtf8("statusBar"))
|
||||
KCC.setStatusBar(self.statusBar)
|
||||
self.ActionBasic = QtGui.QAction(KCC)
|
||||
self.ActionBasic.setCheckable(True)
|
||||
self.ActionBasic.setChecked(False)
|
||||
@@ -385,9 +392,7 @@ class Ui_KCC(object):
|
||||
self.RotateBox.setText(_translate("KCC", "Horizontal mode", None))
|
||||
self.BasicModeButton.setText(_translate("KCC", "Basic", None))
|
||||
self.AdvModeButton.setText(_translate("KCC", "Advanced", None))
|
||||
self.GammaLabel.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">When converting color images setting this option to 1.0 </span><span style=\" font-size:12pt; font-weight:600;\">might</span><span style=\" font-size:12pt;\"> improve readability.</span></p></body></html>", None))
|
||||
self.GammaLabel.setText(_translate("KCC", "Gamma: Auto", None))
|
||||
self.GammaSlider.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">When converting color images setting this option to 1.0 </span><span style=\" font-size:12pt; font-weight:600;\">might</span><span style=\" font-size:12pt;\"> improve readability.</span></p></body></html>", None))
|
||||
self.ColorBox.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Do not convert images to grayscale.</span></p></body></html>", None))
|
||||
self.ColorBox.setText(_translate("KCC", "Color mode", None))
|
||||
self.wLabel.setToolTip(_translate("KCC", "<html><head/><body><p><span style=\" font-size:12pt;\">Resolution of target device.</span></p></body></html>", None))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
__version__ = '3.4'
|
||||
__version__ = '3.6'
|
||||
__license__ = 'ISC'
|
||||
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
@@ -23,10 +23,23 @@ import os
|
||||
import zipfile
|
||||
import rarfile
|
||||
import locale
|
||||
from subprocess import Popen, STDOUT, PIPE
|
||||
from sys import platform
|
||||
from subprocess import STDOUT, PIPE
|
||||
try:
|
||||
#noinspection PyUnresolvedReferences
|
||||
from psutil import Popen
|
||||
except ImportError:
|
||||
print "ERROR: Psutil is not installed!"
|
||||
if platform.startswith('linux'):
|
||||
import Tkinter
|
||||
import tkMessageBox
|
||||
importRoot = Tkinter.Tk()
|
||||
importRoot.withdraw()
|
||||
tkMessageBox.showerror("KCC - Error", "Psutil is not installed!")
|
||||
exit(1)
|
||||
from shutil import move
|
||||
|
||||
|
||||
# noinspection PyBroadException
|
||||
class CBxArchive:
|
||||
def __init__(self, origFileName):
|
||||
self.origFileName = origFileName
|
||||
@@ -51,7 +64,7 @@ class CBxArchive:
|
||||
elif f.endswith('/'):
|
||||
try:
|
||||
os.makedirs(os.path.join(targetdir, f))
|
||||
except:
|
||||
except StandardError:
|
||||
pass # the dir exists so we are going to extract the images only.
|
||||
else:
|
||||
filelist.append(f)
|
||||
@@ -66,7 +79,7 @@ class CBxArchive:
|
||||
elif f.endswith('/'):
|
||||
try:
|
||||
os.makedirs(os.path.join(targetdir, f))
|
||||
except:
|
||||
except StandardError:
|
||||
pass # the dir exists so we are going to extract the images only.
|
||||
else:
|
||||
filelist.append(f.encode(locale.getpreferredencoding()))
|
||||
@@ -92,9 +105,10 @@ class CBxArchive:
|
||||
elif self.compressor == '7z':
|
||||
self.extractCB7(targetdir)
|
||||
adir = os.listdir(targetdir)
|
||||
if 'ComicInfo.xml' in adir:
|
||||
adir.remove('ComicInfo.xml')
|
||||
if len(adir) == 1 and os.path.isdir(os.path.join(targetdir, adir[0])):
|
||||
import shutil
|
||||
for f in os.listdir(os.path.join(targetdir, adir[0])):
|
||||
shutil.move(os.path.join(targetdir, adir[0], f), targetdir)
|
||||
move(os.path.join(targetdir, adir[0], f), targetdir)
|
||||
os.rmdir(os.path.join(targetdir, adir[0]))
|
||||
return targetdir
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python2
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2012-2013 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||
@@ -18,20 +18,23 @@
|
||||
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
# PERFORMANCE OF THIS SOFTWARE.
|
||||
#
|
||||
__version__ = '3.4'
|
||||
__version__ = '3.6'
|
||||
__license__ = 'ISC'
|
||||
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
import re
|
||||
import stat
|
||||
import string
|
||||
import unicodedata
|
||||
from tempfile import mkdtemp
|
||||
from shutil import move, copyfile, copytree, rmtree, make_archive
|
||||
from optparse import OptionParser, OptionGroup
|
||||
from multiprocessing import Pool, Queue, freeze_support
|
||||
from multiprocessing import Pool, freeze_support
|
||||
from xml.dom.minidom import parse
|
||||
from uuid import uuid4
|
||||
try:
|
||||
from PyQt4 import QtCore
|
||||
except ImportError:
|
||||
@@ -126,35 +129,48 @@ def buildHTML(path, imgfile):
|
||||
"}'></a></div>\n"])
|
||||
if options.quality == 2:
|
||||
imgfilepv = string.split(imgfile, ".")
|
||||
imgfilepv[0] = imgfilepv[0].split("_kccx")[0].replace("_kccnh", "").replace("_kccnv", "")
|
||||
imgfilepv[0] = imgfilepv[0].split("_kccxl")[0].replace("_kccnh", "").replace("_kccnv", "")
|
||||
imgfilepv[0] += "_kcchq"
|
||||
imgfilepv = string.join(imgfilepv, ".")
|
||||
else:
|
||||
imgfilepv = imgfile
|
||||
if "_kccx" in filename[0]:
|
||||
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) + "%"
|
||||
if "_kccxl" in filename[0]:
|
||||
borders = filename[0].split('_kccxl')[1]
|
||||
borders = re.findall('[0-9]{1,6}', borders)
|
||||
xl = borders[0].lstrip("0")
|
||||
yu = borders[1].lstrip("0")
|
||||
xr = borders[2].lstrip("0")
|
||||
yd = borders[3].lstrip("0")
|
||||
if xl != "":
|
||||
xl = "-" + str(float(xl)/100) + "%"
|
||||
else:
|
||||
x = "0%"
|
||||
if y != "":
|
||||
y = "-" + str(float(y)/100) + "%"
|
||||
xl = "0%"
|
||||
if xr != "":
|
||||
xr = "-" + str(float(xr)/100) + "%"
|
||||
else:
|
||||
y = "0%"
|
||||
xr = "0%"
|
||||
if yu != "":
|
||||
yu = "-" + str(float(yu)/100) + "%"
|
||||
else:
|
||||
yu = "0%"
|
||||
if yd != "":
|
||||
yd = "-" + str(float(yd)/100) + "%"
|
||||
else:
|
||||
yd = "0%"
|
||||
else:
|
||||
x = "0%"
|
||||
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%;"
|
||||
xl = "0%"
|
||||
yu = "0%"
|
||||
xr = "0%"
|
||||
yd = "0%"
|
||||
boxStyles = {"BoxTL": "left:" + xl + ";top:" + yu + ";",
|
||||
"BoxTR": "right:" + xr + ";top:" + yu + ";",
|
||||
"BoxBL": "left:" + xl + ";bottom:" + yd + ";",
|
||||
"BoxBR": "right:" + xr + ";bottom:" + yd + ";",
|
||||
"BoxT": "left:" + xl + ";top:" + yu + ";",
|
||||
"BoxB": "left:" + xl + ";bottom:" + yd + ";",
|
||||
"BoxL": "left:" + xl + ";top:" + yu + ";",
|
||||
"BoxR": "right:" + xr + ";top:" + yu + ";",
|
||||
"BoxC": "left:" + xl + ";top:" + yu + ";"
|
||||
}
|
||||
for box in boxes:
|
||||
f.writelines(["<div id=\"" + box + "-Panel-Parent\" class=\"target-mag-parent\"><div id=\"",
|
||||
@@ -168,7 +184,6 @@ def buildHTML(path, imgfile):
|
||||
|
||||
|
||||
def buildNCX(dstdir, title, chapters):
|
||||
from uuid import uuid4
|
||||
options.uuid = str(uuid4())
|
||||
options.uuid = options.uuid.encode('utf-8')
|
||||
ncxfile = os.path.join(dstdir, 'OEBPS', 'toc.ncx')
|
||||
@@ -216,9 +231,10 @@ def buildOPF(dstdir, title, filelist, cover=None):
|
||||
"xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n",
|
||||
"<dc:title>", title.encode('utf-8'), "</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",
|
||||
"<dc:identifier id=\"BookID\" opf:scheme=\"UUID\">", options.uuid, "</dc:identifier>\n"])
|
||||
for author in options.authors:
|
||||
f.writelines(["<dc:Creator>", author.encode('utf-8'), "</dc:Creator>\n"])
|
||||
f.writelines(["<meta name=\"generator\" content=\"KindleComicConverter-" + __version__ + "\"/>\n",
|
||||
"<meta name=\"RegionMagnification\" content=\"true\"/>\n",
|
||||
"<meta name=\"region-mag\" content=\"true\"/>\n",
|
||||
"<meta name=\"cover\" content=\"cover\"/>\n",
|
||||
@@ -292,121 +308,110 @@ def getImageFileName(imgfile):
|
||||
return filename
|
||||
|
||||
|
||||
def applyImgOptimization(img, opt, overrideQuality=5):
|
||||
img.getImageFill(opt.webtoon)
|
||||
def applyImgOptimization(img, opt, hqImage=None):
|
||||
if not img.fill:
|
||||
img.getImageFill(opt.webtoon)
|
||||
if not opt.webtoon:
|
||||
img.cropWhiteSpace(10.0)
|
||||
if opt.cutpagenumbers and not opt.webtoon:
|
||||
img.cutPageNumber()
|
||||
img.optimizeImage(opt.gamma)
|
||||
if overrideQuality != 5:
|
||||
img.resizeImage(opt.upscale, opt.stretch, opt.bordersColor, overrideQuality)
|
||||
if hqImage:
|
||||
img.resizeImage(opt.upscale, opt.stretch, opt.bordersColor, 0)
|
||||
img.calculateBorder(hqImage)
|
||||
else:
|
||||
img.resizeImage(opt.upscale, opt.stretch, opt.bordersColor, opt.quality)
|
||||
if opt.panelview and opt.quality != 2:
|
||||
img.calculateBorder(img)
|
||||
if opt.forcepng and not opt.forcecolor:
|
||||
img.quantizeImage()
|
||||
|
||||
|
||||
def dirImgProcess(path):
|
||||
global workerPool, workerOutput
|
||||
workerPool = Pool()
|
||||
workerOutput = []
|
||||
work = []
|
||||
pagenumber = 0
|
||||
pagenumbermodifier = 0
|
||||
queue = Queue()
|
||||
pool = Pool(None, fileImgProcess_init, [queue, options])
|
||||
for (dirpath, dirnames, filenames) in os.walk(path):
|
||||
for afile in filenames:
|
||||
if getImageFileName(afile) is not None:
|
||||
pagenumber += 1
|
||||
work.append([afile, dirpath, pagenumber])
|
||||
work.append([afile, dirpath, options])
|
||||
if GUI:
|
||||
GUI.emit(QtCore.SIGNAL("progressBarTick"), pagenumber)
|
||||
if len(work) > 0:
|
||||
splitpages = pool.map_async(func=fileImgProcess, iterable=work)
|
||||
pool.close()
|
||||
if GUI:
|
||||
while not splitpages.ready():
|
||||
# noinspection PyBroadException
|
||||
try:
|
||||
queue.get(True, 5)
|
||||
except:
|
||||
pass
|
||||
if not GUI.conversionAlive:
|
||||
pool.terminate()
|
||||
rmtree(os.path.join(path, '..', '..'), True)
|
||||
raise UserWarning("Conversion interrupted.")
|
||||
GUI.emit(QtCore.SIGNAL("progressBarTick"))
|
||||
pool.join()
|
||||
queue.close()
|
||||
try:
|
||||
splitpages = splitpages.get()
|
||||
except:
|
||||
for i in work:
|
||||
workerPool.apply_async(func=fileImgProcess, args=(i, ), callback=fileImgProcess_tick)
|
||||
workerPool.close()
|
||||
workerPool.join()
|
||||
if GUI and not GUI.conversionAlive:
|
||||
rmtree(os.path.join(path, '..', '..'), True)
|
||||
raise RuntimeError("One of workers crashed. Cause: " + str(sys.exc_info()[1]))
|
||||
splitpages = filter(None, splitpages)
|
||||
splitpages.sort()
|
||||
for page in splitpages:
|
||||
if (page + pagenumbermodifier) % 2 == 0:
|
||||
pagenumbermodifier += 1
|
||||
pagenumbermodifier += 1
|
||||
raise UserWarning("Conversion interrupted.")
|
||||
if len(workerOutput) > 0:
|
||||
rmtree(os.path.join(path, '..', '..'), True)
|
||||
raise RuntimeError("One of workers crashed. Cause: " + workerOutput[0])
|
||||
else:
|
||||
rmtree(os.path.join(path, '..', '..'), True)
|
||||
raise UserWarning("Source directory is empty.")
|
||||
|
||||
|
||||
def fileImgProcess_init(queue, opt):
|
||||
fileImgProcess.queue = queue
|
||||
fileImgProcess.options = opt
|
||||
def fileImgProcess_tick(output):
|
||||
if output:
|
||||
workerOutput.append(output)
|
||||
workerPool.terminate()
|
||||
if GUI:
|
||||
GUI.emit(QtCore.SIGNAL("progressBarTick"))
|
||||
if not GUI.conversionAlive:
|
||||
workerPool.terminate()
|
||||
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
def fileImgProcess(work):
|
||||
afile = work[0]
|
||||
dirpath = work[1]
|
||||
pagenumber = work[2]
|
||||
opt = fileImgProcess.options
|
||||
output = None
|
||||
if opt.verbose:
|
||||
print "Optimizing " + afile + " for " + opt.profile
|
||||
else:
|
||||
print ".",
|
||||
fileImgProcess.queue.put(".")
|
||||
img = image.ComicPage(os.path.join(dirpath, afile), opt.profileData)
|
||||
if opt.quality == 2:
|
||||
wipe = False
|
||||
else:
|
||||
wipe = True
|
||||
if opt.nosplitrotate:
|
||||
split = None
|
||||
else:
|
||||
split = img.splitPage(dirpath, opt.righttoleft, opt.rotate)
|
||||
if split is not None:
|
||||
try:
|
||||
afile = work[0]
|
||||
dirpath = work[1]
|
||||
opt = work[2]
|
||||
if opt.verbose:
|
||||
print "Splitted " + afile
|
||||
output = pagenumber
|
||||
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)
|
||||
print "Optimizing " + afile + " for " + opt.profile
|
||||
else:
|
||||
print ".",
|
||||
img = image.ComicPage(os.path.join(dirpath, afile), opt.profileData)
|
||||
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, 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)
|
||||
img2.rotated = True
|
||||
applyImgOptimization(img2, opt, 0)
|
||||
img2.saveToDir(dirpath, opt.forcepng, opt.forcecolor, True)
|
||||
return output
|
||||
wipe = False
|
||||
else:
|
||||
wipe = True
|
||||
if opt.nosplitrotate:
|
||||
split = None
|
||||
else:
|
||||
split = img.splitPage(dirpath, opt.righttoleft, opt.rotate)
|
||||
if split is not None:
|
||||
if opt.verbose:
|
||||
print "Splitted " + afile
|
||||
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:
|
||||
img0b = image.ComicPage(split[0], opt.profileData, img0.fill)
|
||||
applyImgOptimization(img0b, opt, img0)
|
||||
img0b.saveToDir(dirpath, opt.forcepng, opt.forcecolor, True)
|
||||
img1b = image.ComicPage(split[1], opt.profileData, img1.fill)
|
||||
applyImgOptimization(img1b, opt, img1)
|
||||
img1b.saveToDir(dirpath, opt.forcepng, opt.forcecolor, True)
|
||||
else:
|
||||
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, img.fill)
|
||||
if img.rotated:
|
||||
img2.image = img2.image.rotate(90)
|
||||
img2.rotated = True
|
||||
applyImgOptimization(img2, opt, img)
|
||||
img2.saveToDir(dirpath, opt.forcepng, opt.forcecolor, True)
|
||||
except StandardError:
|
||||
return str(sys.exc_info()[1])
|
||||
|
||||
|
||||
def genEpubStruct(path):
|
||||
@@ -547,12 +552,15 @@ def genEpubStruct(path):
|
||||
|
||||
|
||||
def getWorkFolder(afile):
|
||||
if len(afile) > 240:
|
||||
raise UserWarning("Path is too long.")
|
||||
if os.path.isdir(afile):
|
||||
workdir = tempfile.mkdtemp('', 'KCC-TMP-')
|
||||
#workdir = tempfile.mkdtemp('', 'KCC-TMP-', os.path.join(os.path.splitext(afile)[0], '..'))
|
||||
workdir = mkdtemp('', 'KCC-TMP-')
|
||||
try:
|
||||
os.rmdir(workdir) # needed for copytree() fails if dst already exists
|
||||
fullPath = os.path.join(workdir, 'OEBPS', 'Images')
|
||||
if len(fullPath) > 240:
|
||||
raise UserWarning("Path is too long.")
|
||||
copytree(afile, fullPath)
|
||||
sanitizeTreeBeforeConversion(fullPath)
|
||||
return workdir
|
||||
@@ -566,8 +574,7 @@ def getWorkFolder(afile):
|
||||
rmtree(path, True)
|
||||
raise UserWarning("Failed to extract images.")
|
||||
else:
|
||||
workdir = tempfile.mkdtemp('', 'KCC-TMP-')
|
||||
#workdir = tempfile.mkdtemp('', 'KCC-TMP-', os.path.dirname(afile))
|
||||
workdir = mkdtemp('', 'KCC-TMP-')
|
||||
cbx = cbxarchive.CBxArchive(afile)
|
||||
if cbx.isCbxFile():
|
||||
try:
|
||||
@@ -579,14 +586,66 @@ def getWorkFolder(afile):
|
||||
else:
|
||||
rmtree(workdir, True)
|
||||
raise TypeError
|
||||
if len(os.path.join(path, 'OEBPS', 'Images')) > 240:
|
||||
raise UserWarning("Path is too long.")
|
||||
move(path, path + "_temp")
|
||||
move(path + "_temp", os.path.join(path, 'OEBPS', 'Images'))
|
||||
return path
|
||||
|
||||
|
||||
def checkComicInfo(path, originalPath):
|
||||
xmlPath = os.path.join(path, 'ComicInfo.xml')
|
||||
options.authors = ['KCC']
|
||||
titleSuffix = ''
|
||||
if options.title == 'defaulttitle':
|
||||
defaultTitle = True
|
||||
if os.path.isdir(originalPath):
|
||||
options.title = os.path.basename(originalPath)
|
||||
else:
|
||||
options.title = os.path.splitext(os.path.basename(originalPath))[0]
|
||||
else:
|
||||
defaultTitle = False
|
||||
if os.path.exists(xmlPath):
|
||||
try:
|
||||
xml = parse(xmlPath)
|
||||
except StandardError:
|
||||
os.remove(xmlPath)
|
||||
return
|
||||
options.authors = []
|
||||
if defaultTitle:
|
||||
if len(xml.getElementsByTagName('Series')) != 0:
|
||||
options.title = xml.getElementsByTagName('Series')[0].firstChild.nodeValue
|
||||
if len(xml.getElementsByTagName('Volume')) != 0:
|
||||
titleSuffix += ' V' + xml.getElementsByTagName('Volume')[0].firstChild.nodeValue
|
||||
if len(xml.getElementsByTagName('Number')) != 0:
|
||||
titleSuffix += ' #' + xml.getElementsByTagName('Number')[0].firstChild.nodeValue
|
||||
options.title += titleSuffix
|
||||
if len(xml.getElementsByTagName('Writer')) != 0:
|
||||
authorsTemp = string.split(xml.getElementsByTagName('Writer')[0].firstChild.nodeValue, ', ')
|
||||
for author in authorsTemp:
|
||||
options.authors.append(author)
|
||||
if len(xml.getElementsByTagName('Penciller')) != 0:
|
||||
authorsTemp = string.split(xml.getElementsByTagName('Penciller')[0].firstChild.nodeValue, ', ')
|
||||
for author in authorsTemp:
|
||||
options.authors.append(author)
|
||||
if len(xml.getElementsByTagName('Inker')) != 0:
|
||||
authorsTemp = string.split(xml.getElementsByTagName('Inker')[0].firstChild.nodeValue, ', ')
|
||||
for author in authorsTemp:
|
||||
options.authors.append(author)
|
||||
if len(xml.getElementsByTagName('Colorist')) != 0:
|
||||
authorsTemp = string.split(xml.getElementsByTagName('Colorist')[0].firstChild.nodeValue, ', ')
|
||||
for author in authorsTemp:
|
||||
options.authors.append(author)
|
||||
if len(options.authors) > 0:
|
||||
options.authors = list(set(options.authors))
|
||||
options.authors.sort()
|
||||
else:
|
||||
options.authors = ['KCC']
|
||||
os.remove(xmlPath)
|
||||
|
||||
|
||||
def slugify(value):
|
||||
# Normalizes string, converts to lowercase, removes non-alpha characters and converts spaces to hyphens.
|
||||
import unicodedata
|
||||
if isinstance(value, str):
|
||||
#noinspection PyArgumentList
|
||||
value = unicodedata.normalize('NFKD', unicode(value, 'latin1')).encode('ascii', 'ignore')
|
||||
@@ -641,10 +700,8 @@ def getDirectorySize(start_path='.'):
|
||||
return total_size
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal
|
||||
def createNewTome(parentPath):
|
||||
tomePathRoot = tempfile.mkdtemp('', 'KCC-TMP-')
|
||||
#tomePathRoot = tempfile.mkdtemp('', 'KCC-TMP-', parentPath)
|
||||
def createNewTome():
|
||||
tomePathRoot = mkdtemp('', 'KCC-TMP-')
|
||||
tomePath = os.path.join(tomePathRoot, 'OEBPS', 'Images')
|
||||
os.makedirs(tomePath)
|
||||
return tomePath, tomePathRoot
|
||||
@@ -661,7 +718,7 @@ def walkLevel(some_dir, level=1):
|
||||
del dirs[:]
|
||||
|
||||
|
||||
def splitDirectory(path, mode, parentPath):
|
||||
def splitDirectory(path, mode):
|
||||
output = []
|
||||
currentSize = 0
|
||||
currentTarget = path
|
||||
@@ -670,7 +727,7 @@ def splitDirectory(path, mode, parentPath):
|
||||
for name in files:
|
||||
size = os.path.getsize(os.path.join(root, name))
|
||||
if currentSize + size > 262144000:
|
||||
currentTarget, pathRoot = createNewTome(parentPath)
|
||||
currentTarget, pathRoot = createNewTome()
|
||||
output.append(pathRoot)
|
||||
currentSize = size
|
||||
else:
|
||||
@@ -682,7 +739,7 @@ def splitDirectory(path, mode, parentPath):
|
||||
for name in dirs:
|
||||
size = getDirectorySize(os.path.join(root, name))
|
||||
if currentSize + size > 262144000:
|
||||
currentTarget, pathRoot = createNewTome(parentPath)
|
||||
currentTarget, pathRoot = createNewTome()
|
||||
output.append(pathRoot)
|
||||
currentSize = size
|
||||
else:
|
||||
@@ -697,7 +754,7 @@ def splitDirectory(path, mode, parentPath):
|
||||
currentSize = 0
|
||||
if size > 262144000:
|
||||
if not firstTome:
|
||||
currentTarget, pathRoot = createNewTome(parentPath)
|
||||
currentTarget, pathRoot = createNewTome()
|
||||
output.append(pathRoot)
|
||||
else:
|
||||
firstTome = False
|
||||
@@ -705,7 +762,7 @@ def splitDirectory(path, mode, parentPath):
|
||||
for nameInside in dirsInside:
|
||||
size = getDirectorySize(os.path.join(rootInside, nameInside))
|
||||
if currentSize + size > 262144000:
|
||||
currentTarget, pathRoot = createNewTome(parentPath)
|
||||
currentTarget, pathRoot = createNewTome()
|
||||
output.append(pathRoot)
|
||||
currentSize = size
|
||||
else:
|
||||
@@ -714,7 +771,7 @@ def splitDirectory(path, mode, parentPath):
|
||||
move(os.path.join(rootInside, nameInside), os.path.join(currentTarget, nameInside))
|
||||
else:
|
||||
if not firstTome:
|
||||
currentTarget, pathRoot = createNewTome(parentPath)
|
||||
currentTarget, pathRoot = createNewTome()
|
||||
output.append(pathRoot)
|
||||
move(os.path.join(root, name), os.path.join(currentTarget, name))
|
||||
else:
|
||||
@@ -722,7 +779,7 @@ def splitDirectory(path, mode, parentPath):
|
||||
return output
|
||||
|
||||
|
||||
# noinspection PyUnboundLocalVariable
|
||||
#noinspection PyUnboundLocalVariable
|
||||
def preSplitDirectory(path):
|
||||
if getDirectorySize(os.path.join(path, 'OEBPS', 'Images')) > 262144000:
|
||||
# Detect directory stucture
|
||||
@@ -775,7 +832,7 @@ def preSplitDirectory(path):
|
||||
GUI.emit(QtCore.SIGNAL("addMessage"), '')
|
||||
return [path]
|
||||
# Split directories
|
||||
split = splitDirectory(os.path.join(path, 'OEBPS', 'Images'), mode, os.path.join(path, '..'))
|
||||
split = splitDirectory(os.path.join(path, 'OEBPS', 'Images'), mode)
|
||||
path = [path]
|
||||
for tome in split:
|
||||
path.append(tome)
|
||||
@@ -866,6 +923,7 @@ def main(argv=None, qtGUI=None):
|
||||
parser.print_help()
|
||||
return
|
||||
path = getWorkFolder(args[0])
|
||||
checkComicInfo(path + "/OEBPS/Images/", args[0])
|
||||
if options.webtoon:
|
||||
if GUI:
|
||||
GUI.emit(QtCore.SIGNAL("progressBarTick"), 'status', 'Splitting images')
|
||||
@@ -887,12 +945,18 @@ def main(argv=None, qtGUI=None):
|
||||
tomes = [path]
|
||||
filepath = []
|
||||
tomeNumber = 0
|
||||
if GUI:
|
||||
if options.cbzoutput:
|
||||
GUI.emit(QtCore.SIGNAL("progressBarTick"), 'status', 'Compressing CBZ files')
|
||||
else:
|
||||
GUI.emit(QtCore.SIGNAL("progressBarTick"), 'status', 'Compressing EPUB files')
|
||||
GUI.emit(QtCore.SIGNAL("progressBarTick"), len(tomes) + 1)
|
||||
GUI.emit(QtCore.SIGNAL("progressBarTick"))
|
||||
options.baseTitle = options.title
|
||||
for tome in tomes:
|
||||
if len(tomes) > 1:
|
||||
tomeNumber += 1
|
||||
options.title = os.path.splitext(os.path.basename(args[0]))[0] + ' ' + str(tomeNumber)
|
||||
elif options.title == 'defaulttitle':
|
||||
options.title = os.path.splitext(os.path.basename(args[0]))[0]
|
||||
options.title = options.baseTitle + ' [' + str(tomeNumber) + '/' + str(len(tomes)) + ']'
|
||||
if options.cbzoutput:
|
||||
# if CBZ output wanted, compress all images and return filepath
|
||||
print "\nCreating CBZ file..."
|
||||
@@ -912,6 +976,8 @@ def main(argv=None, qtGUI=None):
|
||||
make_archive(tome + '_comic', 'zip', tome)
|
||||
move(tome + '_comic.zip', filepath[-1])
|
||||
rmtree(tome, True)
|
||||
if GUI:
|
||||
GUI.emit(QtCore.SIGNAL("progressBarTick"))
|
||||
return filepath
|
||||
|
||||
|
||||
@@ -969,6 +1035,9 @@ def checkOptions():
|
||||
if options.profile == 'KFA' and (options.customwidth == 0 or options.customheight == 0):
|
||||
print "ERROR: Kindle for Android profile require --customwidth and --customheight options!"
|
||||
sys.exit(1)
|
||||
# CBZ files on Kindle DX/DXG support higher resolution
|
||||
if options.profile == 'KDX' and options.cbzoutput:
|
||||
options.customheight = 1200
|
||||
# Override profile data
|
||||
if options.customwidth != 0 or options.customheight != 0:
|
||||
X = image.ProfileData.Profiles[options.profile][1][0]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python2
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c) 2012-2013 Ciro Mattia Gonano <ciromattia@gmail.com>
|
||||
@@ -18,7 +18,7 @@
|
||||
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
# PERFORMANCE OF THIS SOFTWARE.
|
||||
#
|
||||
__version__ = '3.4'
|
||||
__version__ = '3.6'
|
||||
__license__ = 'ISC'
|
||||
__copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jastrzebski <pawelj@vulturis.eu>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
@@ -27,15 +27,31 @@ import os
|
||||
import sys
|
||||
from shutil import rmtree, copytree, move
|
||||
from optparse import OptionParser, OptionGroup
|
||||
from multiprocessing import Pool, Queue, freeze_support
|
||||
from multiprocessing import Pool, freeze_support
|
||||
try:
|
||||
# noinspection PyUnresolvedReferences
|
||||
#noinspection PyUnresolvedReferences
|
||||
from PIL import Image, ImageStat
|
||||
if tuple(map(int, ('2.2.1'.split(".")))) > tuple(map(int, (Image.PILLOW_VERSION.split(".")))):
|
||||
print "ERROR: Pillow 2.2.1 or newer is required!"
|
||||
if sys.platform.startswith('linux'):
|
||||
#noinspection PyUnresolvedReferences
|
||||
import Tkinter
|
||||
#noinspection PyUnresolvedReferences
|
||||
import tkMessageBox
|
||||
importRoot = Tkinter.Tk()
|
||||
importRoot.withdraw()
|
||||
tkMessageBox.showerror("KCC - Error", "Pillow 2.2.1 or newer is required!")
|
||||
exit(1)
|
||||
except ImportError:
|
||||
print "ERROR: Pillow is not installed!"
|
||||
if sys.platform.startswith('linux'):
|
||||
#noinspection PyUnresolvedReferences
|
||||
import Tkinter
|
||||
#noinspection PyUnresolvedReferences
|
||||
import tkMessageBox
|
||||
importRoot = Tkinter.Tk()
|
||||
importRoot.withdraw()
|
||||
tkMessageBox.showerror("KCC - Error", "Pillow 2.2.1 or newer is required!")
|
||||
exit(1)
|
||||
try:
|
||||
from PyQt4 import QtCore
|
||||
@@ -83,113 +99,119 @@ def sanitizePanelSize(panel, opt):
|
||||
return newPanels
|
||||
|
||||
|
||||
def splitImage_init(queue, opt):
|
||||
splitImage.queue = queue
|
||||
splitImage.options = opt
|
||||
def splitImage_tick(output):
|
||||
if output:
|
||||
splitWorkerOutput.append(output)
|
||||
splitWorkerPool.terminate()
|
||||
if GUI:
|
||||
GUI.emit(QtCore.SIGNAL("progressBarTick"))
|
||||
if not GUI.conversionAlive:
|
||||
splitWorkerPool.terminate()
|
||||
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
#noinspection PyUnboundLocalVariable
|
||||
def splitImage(work):
|
||||
path = work[0]
|
||||
name = work[1]
|
||||
opt = splitImage.options
|
||||
# Harcoded opttions
|
||||
threshold = 1.0
|
||||
delta = 15
|
||||
print ".",
|
||||
splitImage.queue.put(".")
|
||||
fileExpanded = os.path.splitext(name)
|
||||
filePath = os.path.join(path, name)
|
||||
# Detect corrupted files
|
||||
try:
|
||||
Image.open(filePath)
|
||||
except IOError:
|
||||
raise RuntimeError('Cannot read image file %s' % filePath)
|
||||
try:
|
||||
path = work[0]
|
||||
name = work[1]
|
||||
opt = work[2]
|
||||
# Harcoded opttions
|
||||
threshold = 1.0
|
||||
delta = 15
|
||||
print ".",
|
||||
fileExpanded = os.path.splitext(name)
|
||||
filePath = os.path.join(path, name)
|
||||
# Detect corrupted files
|
||||
try:
|
||||
Image.open(filePath)
|
||||
except IOError:
|
||||
raise RuntimeError('Cannot read image file %s' % filePath)
|
||||
try:
|
||||
image = Image.open(filePath)
|
||||
image.verify()
|
||||
except:
|
||||
raise RuntimeError('Image file %s is corrupted' % filePath)
|
||||
try:
|
||||
image = Image.open(filePath)
|
||||
image.load()
|
||||
except:
|
||||
raise RuntimeError('Image file %s is corrupted' % filePath)
|
||||
image = Image.open(filePath)
|
||||
image.verify()
|
||||
except:
|
||||
raise RuntimeError('Image file %s is corrupted' % filePath)
|
||||
try:
|
||||
image = Image.open(filePath)
|
||||
image.load()
|
||||
except:
|
||||
raise RuntimeError('Image file %s is corrupted' % filePath)
|
||||
image = Image.open(filePath)
|
||||
image = image.convert('RGB')
|
||||
widthImg, heightImg = image.size
|
||||
if heightImg > opt.height:
|
||||
if opt.debug:
|
||||
from PIL import ImageDraw
|
||||
debugImage = Image.open(filePath)
|
||||
draw = ImageDraw.Draw(debugImage)
|
||||
|
||||
# Find panels
|
||||
y1 = 0
|
||||
y2 = 15
|
||||
panels = []
|
||||
while y2 < heightImg:
|
||||
while ImageStat.Stat(image.crop([0, y1, widthImg, y2])).var[0] < threshold and y2 < heightImg:
|
||||
y2 += delta
|
||||
y2 -= delta
|
||||
y1Temp = y2
|
||||
y1 = y2 + delta
|
||||
y2 = y1 + delta
|
||||
while ImageStat.Stat(image.crop([0, y1, widthImg, y2])).var[0] >= threshold and y2 < heightImg:
|
||||
y1 += delta
|
||||
y2 += delta
|
||||
if y1 + delta >= heightImg:
|
||||
y1 = heightImg - 1
|
||||
y2Temp = y1
|
||||
image = image.convert('RGB')
|
||||
widthImg, heightImg = image.size
|
||||
if heightImg > opt.height:
|
||||
if opt.debug:
|
||||
draw.line([(0, y1Temp), (widthImg, y1Temp)], fill=(0, 255, 0))
|
||||
draw.line([(0, y2Temp), (widthImg, y2Temp)], fill=(255, 0, 0))
|
||||
panelHeight = y2Temp - y1Temp
|
||||
if panelHeight > delta:
|
||||
# Panels that can't be cut nicely will be forcefully splitted
|
||||
panelsCleaned = sanitizePanelSize([y1Temp, y2Temp, panelHeight], opt)
|
||||
for panel in panelsCleaned:
|
||||
panels.append(panel)
|
||||
if opt.debug:
|
||||
# noinspection PyUnboundLocalVariable
|
||||
debugImage.save(os.path.join(path, fileExpanded[0] + '-debug.png'), 'PNG')
|
||||
from PIL import ImageDraw
|
||||
debugImage = Image.open(filePath)
|
||||
draw = ImageDraw.Draw(debugImage)
|
||||
|
||||
# Create virtual pages
|
||||
pages = []
|
||||
currentPage = []
|
||||
pageLeft = opt.height
|
||||
panelNumber = 0
|
||||
for panel in panels:
|
||||
if pageLeft - panel[2] > 0:
|
||||
pageLeft -= panel[2]
|
||||
currentPage.append(panelNumber)
|
||||
panelNumber += 1
|
||||
else:
|
||||
if len(currentPage) > 0:
|
||||
pages.append(currentPage)
|
||||
pageLeft = opt.height - panel[2]
|
||||
currentPage = [panelNumber]
|
||||
panelNumber += 1
|
||||
if len(currentPage) > 0:
|
||||
pages.append(currentPage)
|
||||
# Find panels
|
||||
y1 = 0
|
||||
y2 = 15
|
||||
panels = []
|
||||
while y2 < heightImg:
|
||||
while ImageStat.Stat(image.crop([0, y1, widthImg, y2])).var[0] < threshold and y2 < heightImg:
|
||||
y2 += delta
|
||||
y2 -= delta
|
||||
y1Temp = y2
|
||||
y1 = y2 + delta
|
||||
y2 = y1 + delta
|
||||
while ImageStat.Stat(image.crop([0, y1, widthImg, y2])).var[0] >= threshold and y2 < heightImg:
|
||||
y1 += delta
|
||||
y2 += delta
|
||||
if y1 + delta >= heightImg:
|
||||
y1 = heightImg - 1
|
||||
y2Temp = y1
|
||||
if opt.debug:
|
||||
draw.line([(0, y1Temp), (widthImg, y1Temp)], fill=(0, 255, 0))
|
||||
draw.line([(0, y2Temp), (widthImg, y2Temp)], fill=(255, 0, 0))
|
||||
panelHeight = y2Temp - y1Temp
|
||||
if panelHeight > delta:
|
||||
# Panels that can't be cut nicely will be forcefully splitted
|
||||
panelsCleaned = sanitizePanelSize([y1Temp, y2Temp, panelHeight], opt)
|
||||
for panel in panelsCleaned:
|
||||
panels.append(panel)
|
||||
if opt.debug:
|
||||
debugImage.save(os.path.join(path, fileExpanded[0] + '-debug.png'), 'PNG')
|
||||
|
||||
# Create pages
|
||||
pageNumber = 1
|
||||
for page in pages:
|
||||
pageHeight = 0
|
||||
targetHeight = 0
|
||||
for panel in page:
|
||||
pageHeight += panels[panel][2]
|
||||
if pageHeight > delta:
|
||||
newPage = Image.new('RGB', (widthImg, pageHeight))
|
||||
# Create virtual pages
|
||||
pages = []
|
||||
currentPage = []
|
||||
pageLeft = opt.height
|
||||
panelNumber = 0
|
||||
for panel in panels:
|
||||
if pageLeft - panel[2] > 0:
|
||||
pageLeft -= panel[2]
|
||||
currentPage.append(panelNumber)
|
||||
panelNumber += 1
|
||||
else:
|
||||
if len(currentPage) > 0:
|
||||
pages.append(currentPage)
|
||||
pageLeft = opt.height - panel[2]
|
||||
currentPage = [panelNumber]
|
||||
panelNumber += 1
|
||||
if len(currentPage) > 0:
|
||||
pages.append(currentPage)
|
||||
|
||||
# Create pages
|
||||
pageNumber = 1
|
||||
for page in pages:
|
||||
pageHeight = 0
|
||||
targetHeight = 0
|
||||
for panel in page:
|
||||
panelImg = image.crop([0, panels[panel][0], widthImg, panels[panel][1]])
|
||||
newPage.paste(panelImg, (0, targetHeight))
|
||||
targetHeight += panels[panel][2]
|
||||
newPage.save(os.path.join(path, fileExpanded[0] + '-' +
|
||||
str(pageNumber) + '.png'), 'PNG')
|
||||
pageNumber += 1
|
||||
os.remove(filePath)
|
||||
pageHeight += panels[panel][2]
|
||||
if pageHeight > delta:
|
||||
newPage = Image.new('RGB', (widthImg, pageHeight))
|
||||
for panel in page:
|
||||
panelImg = image.crop([0, panels[panel][0], widthImg, panels[panel][1]])
|
||||
newPage.paste(panelImg, (0, targetHeight))
|
||||
targetHeight += panels[panel][2]
|
||||
newPage.save(os.path.join(path, fileExpanded[0] + '-' +
|
||||
str(pageNumber) + '.png'), 'PNG')
|
||||
pageNumber += 1
|
||||
os.remove(filePath)
|
||||
except StandardError:
|
||||
return str(sys.exc_info()[1])
|
||||
|
||||
|
||||
def Copyright():
|
||||
@@ -197,9 +219,8 @@ def Copyright():
|
||||
'Written 2013 by Ciro Mattia Gonano and Pawel Jastrzebski.' % globals())
|
||||
|
||||
|
||||
# noinspection PyBroadException
|
||||
def main(argv=None, qtGUI=None):
|
||||
global options
|
||||
global options, GUI, splitWorkerPool, splitWorkerOutput
|
||||
parser = OptionParser(usage="Usage: %prog [options] comic_folder", add_help_option=False)
|
||||
mainOptions = OptionGroup(parser, "MANDATORY")
|
||||
otherOptions = OptionGroup(parser, "OTHER")
|
||||
@@ -230,37 +251,28 @@ def main(argv=None, qtGUI=None):
|
||||
copytree(options.sourceDir, options.targetDir)
|
||||
work = []
|
||||
pagenumber = 0
|
||||
queue = Queue()
|
||||
pool = Pool(None, splitImage_init, [queue, options])
|
||||
splitWorkerOutput = []
|
||||
splitWorkerPool = Pool()
|
||||
for root, dirs, files in os.walk(options.targetDir, False):
|
||||
for name in files:
|
||||
if getImageFileName(name) is not None:
|
||||
pagenumber += 1
|
||||
work.append([root, name])
|
||||
work.append([root, name, options])
|
||||
else:
|
||||
os.remove(os.path.join(root, name))
|
||||
if GUI:
|
||||
GUI.emit(QtCore.SIGNAL("progressBarTick"), pagenumber)
|
||||
if len(work) > 0:
|
||||
workers = pool.map_async(func=splitImage, iterable=work)
|
||||
pool.close()
|
||||
if GUI:
|
||||
while not workers.ready():
|
||||
# noinspection PyBroadException
|
||||
try:
|
||||
queue.get(True, 5)
|
||||
except:
|
||||
pass
|
||||
GUI.emit(QtCore.SIGNAL("progressBarTick"))
|
||||
pool.join()
|
||||
queue.close()
|
||||
try:
|
||||
workers.get()
|
||||
except:
|
||||
for i in work:
|
||||
splitWorkerPool.apply_async(func=splitImage, args=(i, ), callback=splitImage_tick)
|
||||
splitWorkerPool.close()
|
||||
splitWorkerPool.join()
|
||||
if GUI and not GUI.conversionAlive:
|
||||
rmtree(options.targetDir, True)
|
||||
raise RuntimeError("One of workers crashed. Cause: " + str(sys.exc_info()[1]))
|
||||
if GUI:
|
||||
GUI.emit(QtCore.SIGNAL("progressBarTick"), 1)
|
||||
raise UserWarning("Conversion interrupted.")
|
||||
if len(splitWorkerOutput) > 0:
|
||||
rmtree(options.targetDir, True)
|
||||
raise RuntimeError("One of workers crashed. Cause: " + splitWorkerOutput[0])
|
||||
if options.inPlace:
|
||||
rmtree(options.sourceDir)
|
||||
move(options.targetDir, options.sourceDir)
|
||||
|
||||
245
kcc/image.py
245
kcc/image.py
@@ -21,14 +21,31 @@ __copyright__ = '2012-2013, Ciro Mattia Gonano <ciromattia@gmail.com>, Pawel Jas
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import os
|
||||
from sys import platform
|
||||
try:
|
||||
# noinspection PyUnresolvedReferences
|
||||
from PIL import Image, ImageOps, ImageStat, ImageChops
|
||||
if tuple(map(int, ('2.2.1'.split(".")))) > tuple(map(int, (Image.PILLOW_VERSION.split(".")))):
|
||||
print "ERROR: Pillow 2.2.1 or newer is required!"
|
||||
if platform.startswith('linux'):
|
||||
#noinspection PyUnresolvedReferences
|
||||
import Tkinter
|
||||
#noinspection PyUnresolvedReferences
|
||||
import tkMessageBox
|
||||
importRoot = Tkinter.Tk()
|
||||
importRoot.withdraw()
|
||||
tkMessageBox.showerror("KCC - Error", "Pillow 2.2.1 or newer is required!")
|
||||
exit(1)
|
||||
except ImportError:
|
||||
print "ERROR: Pillow is not installed!"
|
||||
if platform.startswith('linux'):
|
||||
#noinspection PyUnresolvedReferences
|
||||
import Tkinter
|
||||
#noinspection PyUnresolvedReferences
|
||||
import tkMessageBox
|
||||
importRoot = Tkinter.Tk()
|
||||
importRoot.withdraw()
|
||||
tkMessageBox.showerror("KCC - Error", "Pillow 2.2.1 or newer is required!")
|
||||
exit(1)
|
||||
|
||||
|
||||
@@ -133,7 +150,7 @@ class ProfileData:
|
||||
|
||||
|
||||
class ComicPage:
|
||||
def __init__(self, source, device):
|
||||
def __init__(self, source, device, fill=None):
|
||||
try:
|
||||
self.profile_label, self.size, self.palette, self.gamma, self.panelviewsize = device
|
||||
except KeyError:
|
||||
@@ -163,7 +180,10 @@ class ComicPage:
|
||||
self.border = None
|
||||
self.noHPV = None
|
||||
self.noVPV = None
|
||||
self.fill = None
|
||||
if fill:
|
||||
self.fill = fill
|
||||
else:
|
||||
self.fill = None
|
||||
|
||||
def saveToDir(self, targetdir, forcepng, color, wipe):
|
||||
try:
|
||||
@@ -181,7 +201,8 @@ class ComicPage:
|
||||
if self.noVPV:
|
||||
suffix += "_kccnv"
|
||||
if self.border:
|
||||
suffix += "_kccx" + str(self.border[0]) + "_kccy" + str(self.border[1])
|
||||
suffix += "_kccxl" + str(self.border[0]) + "_kccyu" + str(self.border[1]) + "_kccxr" +\
|
||||
str(self.border[2]) + "_kccyd" + str(self.border[3])
|
||||
if forcepng:
|
||||
self.image.save(os.path.join(targetdir, os.path.splitext(self.filename)[0] + suffix + ".png"), "PNG",
|
||||
optimize=1)
|
||||
@@ -194,6 +215,8 @@ class ComicPage:
|
||||
def optimizeImage(self, gamma):
|
||||
if gamma < 0.1:
|
||||
gamma = self.gamma
|
||||
if self.gamma != 1.0 and self.isImageColor(self.image):
|
||||
gamma = 1.0
|
||||
if gamma == 1.0:
|
||||
self.image = ImageOps.autocontrast(self.image)
|
||||
else:
|
||||
@@ -210,58 +233,56 @@ class ComicPage:
|
||||
# Quantize is deprecated but new function call it internally anyway...
|
||||
self.image = self.image.quantize(palette=palImg)
|
||||
|
||||
def calculateBorderPercent(self, x, img, isWidth):
|
||||
if isWidth:
|
||||
return int(round(float(x)/float(img.image.size[0]), 4) * 10000 * 1.5)
|
||||
else:
|
||||
return int(round(float(x)/float(img.image.size[1]), 4) * 10000 * 1.5)
|
||||
|
||||
def calculateBorder(self, sourceImage):
|
||||
if self.fill == 'white':
|
||||
border = ImageOps.invert(sourceImage.image).getbbox()
|
||||
else:
|
||||
border = sourceImage.image.getbbox()
|
||||
if border is not None:
|
||||
self.border = [self.calculateBorderPercent(border[0], sourceImage, True),
|
||||
self.calculateBorderPercent(border[1], sourceImage, False),
|
||||
self.calculateBorderPercent((sourceImage.image.size[0] - border[2]), sourceImage, True),
|
||||
self.calculateBorderPercent((sourceImage.image.size[1] - border[3]), sourceImage, False)]
|
||||
if int((border[2] - border[0]) * 1.5) < self.size[0]:
|
||||
self.noHPV = True
|
||||
self.border[0] /= 2
|
||||
if int((border[3] - border[1]) * 1.5) < self.size[1]:
|
||||
self.noVPV = True
|
||||
self.border[1] /= 2
|
||||
else:
|
||||
self.border = [0, 0, 0, 0]
|
||||
self.noHPV = True
|
||||
self.noVPV = True
|
||||
|
||||
def resizeImage(self, upscale=False, stretch=False, bordersColor=None, qualityMode=0):
|
||||
# High-quality downscaling filter
|
||||
method = Image.ANTIALIAS
|
||||
if bordersColor:
|
||||
fill = bordersColor
|
||||
else:
|
||||
fill = self.fill
|
||||
# Set target size
|
||||
if qualityMode == 0:
|
||||
size = (self.size[0], self.size[1])
|
||||
generateBorder = True
|
||||
elif qualityMode == 1:
|
||||
size = (self.panelviewsize[0], self.panelviewsize[1])
|
||||
generateBorder = True
|
||||
else:
|
||||
size = (self.panelviewsize[0], self.panelviewsize[1])
|
||||
generateBorder = False
|
||||
# If image is smaller than screen and upscale is off - Just expand it
|
||||
if self.image.size[0] <= self.size[0] and self.image.size[1] <= self.size[1]:
|
||||
if not upscale:
|
||||
borderw = (self.size[0] - self.image.size[0]) / 2
|
||||
borderh = (self.size[1] - self.image.size[1]) / 2
|
||||
self.image = ImageOps.expand(self.image, border=(borderw, borderh), fill=fill)
|
||||
if generateBorder:
|
||||
if (self.image.size[0]-(2*borderw))*1.5 < self.size[0]:
|
||||
self.noHPV = True
|
||||
if (self.image.size[1]-(2*borderh))*1.5 < self.size[1]:
|
||||
self.noVPV = True
|
||||
self.border = [int(round(float(borderw)/float(self.image.size[0])*100, 2)*100*1.5),
|
||||
int(round(float(borderh)/float(self.image.size[1])*100, 2)*100*1.5)]
|
||||
return self.image
|
||||
else:
|
||||
# Cubic spline interpolation in a 4x4 environment
|
||||
method = Image.BICUBIC
|
||||
# If image is smaller than device resolution and upscale is off - Just expand it by adding margins
|
||||
if self.image.size[0] <= self.size[0] and self.image.size[1] <= self.size[1] and 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)
|
||||
return self.image
|
||||
# If stretching is on - Resize without other considerations
|
||||
if stretch:
|
||||
if self.image.size[0] <= size[0] and self.image.size[1] <= size[1]:
|
||||
method = Image.BICUBIC
|
||||
else:
|
||||
method = Image.ANTIALIAS
|
||||
self.image = self.image.resize(size, method)
|
||||
if generateBorder:
|
||||
if fill == 'white':
|
||||
border = ImageOps.invert(self.image).getbbox()
|
||||
else:
|
||||
border = self.image.getbbox()
|
||||
if border is not None:
|
||||
if (border[2]-border[0])*1.5 < self.size[0]:
|
||||
self.noHPV = True
|
||||
if (border[3]-border[1])*1.5 < self.size[1]:
|
||||
self.noVPV = True
|
||||
self.border = [int(round(float(border[0])/float(self.image.size[0])*100, 2)*100*1.5),
|
||||
int(round(float(border[1])/float(self.image.size[1])*100, 2)*100*1.5)]
|
||||
else:
|
||||
self.border = [0, 0]
|
||||
self.noHPV = True
|
||||
self.noVPV = True
|
||||
return self.image
|
||||
# Otherwise - Upscale/Downscale
|
||||
ratioDev = float(self.size[0]) / float(self.size[1])
|
||||
@@ -271,23 +292,11 @@ class ComicPage:
|
||||
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)
|
||||
if self.image.size[0] <= size[0] and self.image.size[1] <= size[1]:
|
||||
method = Image.BICUBIC
|
||||
else:
|
||||
method = Image.ANTIALIAS
|
||||
self.image = ImageOps.fit(self.image, size, method=method, centering=(0.5, 0.5))
|
||||
if generateBorder:
|
||||
if fill == 'white':
|
||||
border = ImageOps.invert(self.image).getbbox()
|
||||
else:
|
||||
border = self.image.getbbox()
|
||||
if border is not None:
|
||||
if (border[2]-border[0])*1.5 < self.size[0]:
|
||||
self.noHPV = True
|
||||
if (border[3]-border[1])*1.5 < self.size[1]:
|
||||
self.noVPV = True
|
||||
self.border = [int(round(float(border[0])/float(self.image.size[0])*100, 2)*100*1.5),
|
||||
int(round(float(border[1])/float(self.image.size[1])*100, 2)*100*1.5)]
|
||||
else:
|
||||
self.border = [0, 0]
|
||||
self.noHPV = True
|
||||
self.noVPV = True
|
||||
return self.image
|
||||
|
||||
def splitPage(self, targetdir, righttoleft=False, rotate=False):
|
||||
@@ -393,7 +402,6 @@ class ComicPage:
|
||||
while ImageStat.Stat(self.image.crop((0, 0, widthImg, diff))).var[0] < threshold and diff < heightImg:
|
||||
diff += delta
|
||||
diff -= delta
|
||||
# print "Top crop: %s"%diff
|
||||
self.image = self.image.crop((0, diff, widthImg, heightImg))
|
||||
widthImg, heightImg = self.image.size
|
||||
diff = delta
|
||||
@@ -401,7 +409,6 @@ class ComicPage:
|
||||
while ImageStat.Stat(self.image.crop((0, 0, diff, heightImg))).var[0] < threshold and diff < widthImg:
|
||||
diff += delta
|
||||
diff -= delta
|
||||
# print "Left crop: %s"%diff
|
||||
self.image = self.image.crop((diff, 0, widthImg, heightImg))
|
||||
widthImg, heightImg = self.image.size
|
||||
diff = delta
|
||||
@@ -410,7 +417,6 @@ class ComicPage:
|
||||
and diff < heightImg:
|
||||
diff += delta
|
||||
diff -= delta
|
||||
# print "Down crop: %s"%diff
|
||||
self.image = self.image.crop((0, 0, widthImg, heightImg - diff))
|
||||
widthImg, heightImg = self.image.size
|
||||
diff = delta
|
||||
@@ -419,12 +425,10 @@ class ComicPage:
|
||||
and diff < widthImg:
|
||||
diff += delta
|
||||
diff -= delta
|
||||
# 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
|
||||
|
||||
def getImageHistogram(self, image):
|
||||
def getImageHistogram(self, image, new=True):
|
||||
histogram = image.histogram()
|
||||
RBGW = []
|
||||
pixelCount = 0
|
||||
@@ -433,37 +437,100 @@ class ComicPage:
|
||||
RBGW.append(histogram[i] + histogram[256 + i] + histogram[512 + i])
|
||||
white = 0
|
||||
black = 0
|
||||
for i in range(245, 256):
|
||||
for i in range(251, 256):
|
||||
white += RBGW[i]
|
||||
for i in range(11):
|
||||
for i in range(5):
|
||||
black += RBGW[i]
|
||||
if black > white and black > pixelCount*0.5:
|
||||
return True
|
||||
if new:
|
||||
if black > 0 and white == 0:
|
||||
return 1
|
||||
elif white > 0 and black == 0:
|
||||
return -1
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
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)))
|
||||
if isWebToon:
|
||||
fill = 0
|
||||
fill += self.getImageHistogram(self.image.crop((0, 0, self.image.size[0], 5)), False)
|
||||
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'
|
||||
self.image.size[1])), False)
|
||||
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)), False)
|
||||
fill += self.getImageHistogram(self.image.crop((self.image.size[0]-5, 0, self.image.size[0], 5)), False)
|
||||
fill += self.getImageHistogram(self.image.crop((0, self.image.size[1]-5, 5, self.image.size[1])), False)
|
||||
fill += self.getImageHistogram(self.image.crop((self.image.size[0]-5, self.image.size[1]-5,
|
||||
self.image.size[0], self.image.size[1])), False)
|
||||
if fill > 1:
|
||||
self.fill = 'black'
|
||||
else:
|
||||
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:
|
||||
# Search fom horizontal solid lines
|
||||
startY = 0
|
||||
stopY = 3
|
||||
searching = True
|
||||
while stopY <= self.image.size[1]:
|
||||
checkSolid = self.getImageHistogram(self.image.crop((0, startY, self.image.size[0], stopY)))
|
||||
if checkSolid:
|
||||
fill += checkSolid
|
||||
startY = stopY + 1
|
||||
stopY = startY + 3
|
||||
if stopY > self.image.size[1] and searching:
|
||||
startY = self.image.size[1] - 3
|
||||
stopY = self.image.size[1]
|
||||
searching = False
|
||||
# Search fom vertical solid lines
|
||||
startX = 0
|
||||
stopX = 3
|
||||
searching = True
|
||||
while stopX <= self.image.size[0]:
|
||||
checkSolid = self.getImageHistogram(self.image.crop((startX, 0, stopX, self.image.size[1])))
|
||||
if checkSolid:
|
||||
fill += checkSolid
|
||||
startX = stopX + 1
|
||||
stopX = startX + 3
|
||||
if stopX > self.image.size[0] and searching:
|
||||
startX = self.image.size[0] - 3
|
||||
stopX = self.image.size[0]
|
||||
searching = False
|
||||
if fill > 0:
|
||||
self.fill = 'black'
|
||||
else:
|
||||
self.fill = 'white'
|
||||
self.fill = 'white'
|
||||
|
||||
def isImageColor(self, image):
|
||||
v = ImageStat.Stat(image).var
|
||||
isMonochromatic = reduce(lambda x, y: x and y < 0.005, v, True)
|
||||
if isMonochromatic:
|
||||
# Monochromatic
|
||||
return False
|
||||
else:
|
||||
if len(v) == 3:
|
||||
maxmin = abs(max(v) - min(v))
|
||||
if maxmin > 1000:
|
||||
# Color
|
||||
return True
|
||||
elif maxmin > 100:
|
||||
# Probably color
|
||||
return True
|
||||
else:
|
||||
# Grayscale
|
||||
return False
|
||||
elif len(v) == 1:
|
||||
# Black and white
|
||||
return False
|
||||
else:
|
||||
# Detection failed
|
||||
return False
|
||||
|
||||
229
other/InstallWarning.rtf
Normal file
229
other/InstallWarning.rtf
Normal file
@@ -0,0 +1,229 @@
|
||||
{\rtf1\adeflang1025\ansi\ansicpg1250\uc1\adeff0\deff0\stshfdbch0\stshfloch31506\stshfhich31506\stshfbi31506\deflang1045\deflangfe1045\themelang1045\themelangfe0\themelangcs0{\fonttbl{\f0\fbidi \froman\fcharset238\fprq2{\*\panose 02020603050405020304}Times New Roman;}
|
||||
{\f0\fbidi \froman\fcharset238\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f37\fbidi \fswiss\fcharset238\fprq2{\*\panose 020f0502020204030204}Calibri;}
|
||||
{\flomajor\f31500\fbidi \froman\fcharset238\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fdbmajor\f31501\fbidi \froman\fcharset238\fprq2{\*\panose 02020603050405020304}Times New Roman;}
|
||||
{\fhimajor\f31502\fbidi \fswiss\fcharset238\fprq2{\*\panose 020f0302020204030204}Calibri Light;}{\fbimajor\f31503\fbidi \froman\fcharset238\fprq2{\*\panose 02020603050405020304}Times New Roman;}
|
||||
{\flominor\f31504\fbidi \froman\fcharset238\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fdbminor\f31505\fbidi \froman\fcharset238\fprq2{\*\panose 02020603050405020304}Times New Roman;}
|
||||
{\fhiminor\f31506\fbidi \fswiss\fcharset238\fprq2{\*\panose 020f0502020204030204}Calibri;}{\fbiminor\f31507\fbidi \froman\fcharset238\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f41\fbidi \froman\fcharset0\fprq2 Times New Roman;}
|
||||
{\f40\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\f42\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f43\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\f44\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}
|
||||
{\f45\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\f46\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\f47\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f41\fbidi \froman\fcharset0\fprq2 Times New Roman;}
|
||||
{\f40\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\f42\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f43\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\f44\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}
|
||||
{\f45\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\f46\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\f47\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f411\fbidi \fswiss\fcharset0\fprq2 Calibri;}
|
||||
{\f410\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;}{\f412\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;}{\f413\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;}{\f416\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;}
|
||||
{\f417\fbidi \fswiss\fcharset163\fprq2 Calibri (Vietnamese);}{\flomajor\f31510\fbidi \froman\fcharset0\fprq2 Times New Roman;}{\flomajor\f31509\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}
|
||||
{\flomajor\f31511\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\flomajor\f31512\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\flomajor\f31513\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}
|
||||
{\flomajor\f31514\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\flomajor\f31515\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\flomajor\f31516\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}
|
||||
{\fdbmajor\f31520\fbidi \froman\fcharset0\fprq2 Times New Roman;}{\fdbmajor\f31519\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fdbmajor\f31521\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}
|
||||
{\fdbmajor\f31522\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fdbmajor\f31523\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fdbmajor\f31524\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
|
||||
{\fdbmajor\f31525\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fdbmajor\f31526\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fhimajor\f31530\fbidi \fswiss\fcharset0\fprq2 Calibri Light;}
|
||||
{\fhimajor\f31529\fbidi \fswiss\fcharset204\fprq2 Calibri Light Cyr;}{\fhimajor\f31531\fbidi \fswiss\fcharset161\fprq2 Calibri Light Greek;}{\fhimajor\f31532\fbidi \fswiss\fcharset162\fprq2 Calibri Light Tur;}
|
||||
{\fhimajor\f31535\fbidi \fswiss\fcharset186\fprq2 Calibri Light Baltic;}{\fhimajor\f31536\fbidi \fswiss\fcharset163\fprq2 Calibri Light (Vietnamese);}{\fbimajor\f31540\fbidi \froman\fcharset0\fprq2 Times New Roman;}
|
||||
{\fbimajor\f31539\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fbimajor\f31541\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fbimajor\f31542\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}
|
||||
{\fbimajor\f31543\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fbimajor\f31544\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fbimajor\f31545\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}
|
||||
{\fbimajor\f31546\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\flominor\f31550\fbidi \froman\fcharset0\fprq2 Times New Roman;}{\flominor\f31549\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}
|
||||
{\flominor\f31551\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\flominor\f31552\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\flominor\f31553\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}
|
||||
{\flominor\f31554\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\flominor\f31555\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\flominor\f31556\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}
|
||||
{\fdbminor\f31560\fbidi \froman\fcharset0\fprq2 Times New Roman;}{\fdbminor\f31559\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fdbminor\f31561\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}
|
||||
{\fdbminor\f31562\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fdbminor\f31563\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fdbminor\f31564\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}
|
||||
{\fdbminor\f31565\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fdbminor\f31566\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fhiminor\f31570\fbidi \fswiss\fcharset0\fprq2 Calibri;}
|
||||
{\fhiminor\f31569\fbidi \fswiss\fcharset204\fprq2 Calibri Cyr;}{\fhiminor\f31571\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;}{\fhiminor\f31572\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;}
|
||||
{\fhiminor\f31575\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;}{\fhiminor\f31576\fbidi \fswiss\fcharset163\fprq2 Calibri (Vietnamese);}{\fbiminor\f31580\fbidi \froman\fcharset0\fprq2 Times New Roman;}
|
||||
{\fbiminor\f31579\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fbiminor\f31581\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fbiminor\f31582\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}
|
||||
{\fbiminor\f31583\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fbiminor\f31584\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fbiminor\f31585\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}
|
||||
{\fbiminor\f31586\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;
|
||||
\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;
|
||||
\chyperlink\ctint255\cshade255\red5\green99\blue193;\cfollowedhyperlink\ctint255\cshade255\red149\green79\blue114;}{\*\defchp \f31506\fs22\lang1045\langfe1033\langfenp1033 }{\*\defpap \ql \li0\ri0\sa160\sl259\slmult1
|
||||
\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 }\noqfpromote {\stylesheet{\ql \li0\ri0\sa160\sl259\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs22\alang1025 \ltrch\fcs0
|
||||
\f31506\fs22\lang1045\langfe1033\cgrid\langnp1045\langfenp1033 \snext0 \sqformat \spriority0 Normal;}{\*\cs10 \additive \ssemihidden \sunhideused \spriority1 Default Paragraph Font;}{\*
|
||||
\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\trcbpat1\trcfpat1\tblind0\tblindtype3\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv \ql \li0\ri0\sa160\sl259\slmult1
|
||||
\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31506\afs22\alang1025 \ltrch\fcs0 \f31506\fs22\lang1045\langfe1033\cgrid\langnp1045\langfenp1033 \snext11 \ssemihidden \sunhideused Normal Table;}{\*\cs15 \additive
|
||||
\rtlch\fcs1 \af0 \ltrch\fcs0 \ul\cf17 \sbasedon10 \sunhideused \styrsid3562894 Hyperlink;}{\*\cs16 \additive \rtlch\fcs1 \af0 \ltrch\fcs0 \ul\cf18 \sbasedon10 \ssemihidden \sunhideused \styrsid7678248 FollowedHyperlink;}}{\*\rsidtbl \rsid1081196
|
||||
\rsid3146412\rsid3562894\rsid5731975\rsid7678248\rsid9265883\rsid11107340\rsid12600926\rsid13187577}{\mmathPr\mmathFont34\mbrkBin0\mbrkBinSub0\msmallFrac0\mdispDef1\mlMargin0\mrMargin0\mdefJc1\mwrapIndent1440\mintLim0\mnaryLim1}{\info
|
||||
{\author Pawe\'b3 Jastrz\'eabski}{\operator Pawe\'b3 Jastrz\'eabski}{\creatim\yr2013\mo10\dy29\hr15\min17}{\revtim\yr2013\mo10\dy29\hr15\min28}{\version8}{\edmins8}{\nofpages1}{\nofwords33}{\nofchars200}{\nofcharsws232}{\vern57435}}{\*\xmlnstbl {\xmlns1 h
|
||||
ttp://schemas.microsoft.com/office/word/2003/wordml}}\paperw11906\paperh16838\margl1417\margr1417\margt1417\margb1417\gutter0\ltrsect
|
||||
\deftab708\widowctrl\ftnbj\aenddoc\hyphhotz425\trackmoves0\trackformatting1\donotembedsysfont1\relyonvml0\donotembedlingdata0\grfdocevents0\validatexml1\showplaceholdtext0\ignoremixedcontent0\saveinvalidxml0
|
||||
\showxmlerrors1\noxlattoyen\expshrtn\noultrlspc\dntblnsbdb\nospaceforul\formshade\horzdoc\dgmargin\dghspace180\dgvspace180\dghorigin1417\dgvorigin1417\dghshow1\dgvshow1
|
||||
\jexpand\viewkind1\viewscale100\pgbrdrhead\pgbrdrfoot\splytwnine\ftnlytwnine\htmautsp\nolnhtadjtbl\useltbaln\alntblind\lytcalctblwd\lyttblrtgr\lnbrkrule\nobrkwrptbl\snaptogridincell\allowfieldendsel\wrppunct
|
||||
\asianbrkrule\rsidroot11107340\newtblstyruls\nogrowautofit\usenormstyforlist\noindnmbrts\felnbrelev\nocxsptable\indrlsweleven\noafcnsttbl\afelev\utinl\hwelev\spltpgpar\notcvasp\notbrkcnstfrctbl\notvatxbx\krnprsnet\cachedcolbal \nouicompat \fet0
|
||||
{\*\wgrffmtfilter 2450}\nofeaturethrottle1\ilfomacatclnup0\ltrpar \sectd \ltrsect\linex0\headery708\footery708\colsx708\endnhere\sectlinegrid360\sectdefaultcl\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl2
|
||||
\pnucltr\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl6
|
||||
\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang
|
||||
{\pntxtb (}{\pntxta )}}\pard\plain \ltrpar\ql \li0\ri0\sa160\sl259\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs22\alang1025 \ltrch\fcs0
|
||||
\f31506\fs22\lang1045\langfe1033\cgrid\langnp1045\langfenp1033 {\rtlch\fcs1 \af0 \ltrch\fcs0 \b\fs52\cf6\lang2057\langfe1033\langnp2057\insrsid3562894\charrsid3562894 Warning!}{\rtlch\fcs1 \af0 \ltrch\fcs0
|
||||
\b\fs52\cf6\lang2057\langfe1033\langnp2057\insrsid13187577\charrsid3562894
|
||||
\par }{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \fs28\lang2057\langfe1033\langnp2057\insrsid1081196 Creation of}{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \fs28\lang2057\langfe1033\langnp2057\insrsid3562894\charrsid12600926 }{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0
|
||||
\b\fs28\lang2057\langfe1033\langnp2057\insrsid3562894\charrsid12600926 MOBI}{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \fs28\lang2057\langfe1033\langnp2057\insrsid3562894\charrsid12600926 files }{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0
|
||||
\fs28\lang2057\langfe1033\langnp2057\insrsid5731975\charrsid12600926 require additional software.}{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \fs28\lang2057\langfe1033\langnp2057\insrsid3562894\charrsid12600926
|
||||
\par }{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \b\fs28\lang2057\langfe1033\langnp2057\insrsid3562894\charrsid12600926 Please download: }{\field\flddirty{\*\fldinst {\rtlch\fcs1 \af0\afs24 \ltrch\fcs0
|
||||
\b\fs28\lang2057\langfe1033\langnp2057\insrsid3562894\charrsid12600926 HYPERLINK "http://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000765211" }{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \b\fs28\lang2057\langfe1033\langnp2057\insrsid3562894\charrsid12600926
|
||||
{\*\datafield
|
||||
00d0c9ea79f9bace118c8200aa004ba90b0200000003000000e0c9ea79f9bace118c8200aa004ba90b9600000068007400740070003a002f002f007700770077002e0061006d0061007a006f006e002e0063006f006d002f00670070002f0066006500610074007500720065002e00680074006d006c003f00690065003d00
|
||||
5500540046003800260064006f006300490064003d0031003000300030003700360035003200310031000000795881f43b1d7f48af2c825dc485276300000000a5ab000000}}}{\fldrslt {\rtlch\fcs1 \af0\afs24 \ltrch\fcs0
|
||||
\cs15\b\fs28\ul\cf17\lang2057\langfe1033\langnp2057\insrsid3562894\charrsid12600926 KindleGen}}}\sectd \ltrsect\linex0\headery708\footery708\colsx708\endnhere\sectlinegrid360\sectdefaultcl\sftnbj {\rtlch\fcs1 \af0\afs24 \ltrch\fcs0
|
||||
\b\fs28\lang2057\langfe1033\langnp2057\insrsid3562894\charrsid12600926
|
||||
\par }{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \fs28\lang2057\langfe1033\langnp2057\insrsid3562894\charrsid12600926 And place }{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \i\fs28\lang2057\langfe1033\langnp2057\insrsid5731975\charrsid12600926 kindlegen.exe}{\rtlch\fcs1
|
||||
\af0\afs24 \ltrch\fcs0 \fs28\lang2057\langfe1033\langnp2057\insrsid5731975\charrsid12600926 }{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \fs28\lang2057\langfe1033\langnp2057\insrsid3562894\charrsid12600926 inside }{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0
|
||||
\b\fs28\lang2057\langfe1033\langnp2057\insrsid3146412\charrsid3146412 Kindle}{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \b\fs28\lang2057\langfe1033\langnp2057\insrsid3146412 }{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0
|
||||
\b\fs28\lang2057\langfe1033\langnp2057\insrsid3146412\charrsid3146412 Comic}{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \b\fs28\lang2057\langfe1033\langnp2057\insrsid3146412 }{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0
|
||||
\b\fs28\lang2057\langfe1033\langnp2057\insrsid3146412\charrsid3146412 Converter}{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0 \b\fs28\lang2057\langfe1033\langnp2057\insrsid3146412 }{\rtlch\fcs1 \af0\afs24 \ltrch\fcs0
|
||||
\fs28\lang2057\langfe1033\langnp2057\insrsid3562894\charrsid12600926 directory.
|
||||
\par }{\*\themedata 504b030414000600080000002100e9de0fbfff0000001c020000130000005b436f6e74656e745f54797065735d2e786d6cac91cb4ec3301045f748fc83e52d4a
|
||||
9cb2400825e982c78ec7a27cc0c8992416c9d8b2a755fbf74cd25442a820166c2cd933f79e3be372bd1f07b5c3989ca74aaff2422b24eb1b475da5df374fd9ad
|
||||
5689811a183c61a50f98f4babebc2837878049899a52a57be670674cb23d8e90721f90a4d2fa3802cb35762680fd800ecd7551dc18eb899138e3c943d7e503b6
|
||||
b01d583deee5f99824e290b4ba3f364eac4a430883b3c092d4eca8f946c916422ecab927f52ea42b89a1cd59c254f919b0e85e6535d135a8de20f20b8c12c3b0
|
||||
0c895fcf6720192de6bf3b9e89ecdbd6596cbcdd8eb28e7c365ecc4ec1ff1460f53fe813d3cc7f5b7f020000ffff0300504b030414000600080000002100a5d6
|
||||
a7e7c0000000360100000b0000005f72656c732f2e72656c73848fcf6ac3300c87ef85bd83d17d51d2c31825762fa590432fa37d00e1287f68221bdb1bebdb4f
|
||||
c7060abb0884a4eff7a93dfeae8bf9e194e720169aaa06c3e2433fcb68e1763dbf7f82c985a4a725085b787086a37bdbb55fbc50d1a33ccd311ba548b6309512
|
||||
0f88d94fbc52ae4264d1c910d24a45db3462247fa791715fd71f989e19e0364cd3f51652d73760ae8fa8c9ffb3c330cc9e4fc17faf2ce545046e37944c69e462
|
||||
a1a82fe353bd90a865aad41ed0b5b8f9d6fd010000ffff0300504b0304140006000800000021006b799616830000008a0000001c0000007468656d652f746865
|
||||
6d652f7468656d654d616e616765722e786d6c0ccc4d0ac3201040e17da17790d93763bb284562b2cbaebbf600439c1a41c7a0d29fdbd7e5e38337cedf14d59b
|
||||
4b0d592c9c070d8a65cd2e88b7f07c2ca71ba8da481cc52c6ce1c715e6e97818c9b48d13df49c873517d23d59085adb5dd20d6b52bd521ef2cdd5eb9246a3d8b
|
||||
4757e8d3f729e245eb2b260a0238fd010000ffff0300504b030414000600080000002100b7e72e45da060000a81a0000160000007468656d652f7468656d652f
|
||||
7468656d65312e786d6cec595d8b1b37147d2ff43f0cf3eef86bc61f4bbcc11edbd936bbc9123b2979d4dab24759cdc88ce4dd981028c963a1509a963e34d0b7
|
||||
3e94b68104fa92fe9a6d53da14f2177aa5198f255bdb4d96149692352c63f9dcaba37bef9cab195dbe722fa2ce114e386171cb2d5f2ab90e8e476c4ce269cbbd
|
||||
35ec171aaec3058ac788b218b7dc05e6ee95ed0f3fb88cb6448823ec807dccb750cb0d85986d158b7c04c3885f62331cc36f13964448c0d7645a1c27e818fc46
|
||||
b45829956ac50891d875621481db3d2616c7ce0c1d122ce6ce8dc9848cb0bbbd9ca44761a658703930a2c9404e8133cb7d65a39b8c0fcb12c8173ca089738468
|
||||
cb8569c7ec7888ef09d7a1880bf8a1e596d49f5bdcbe5c445b991115a7d86a767df597d96506e3c38a9a33991ee4937a9eefd5dab97f05a06213d7abf76abd5a
|
||||
ee4f01d068040b4eb9e83efd4eb3d3f533ac064a2f2dbebbf56eb56ce035ffd50dce6d5f7e0cbc02a5febd0d7cbf1f40140dbc02a5787f03ef79f54ae0197805
|
||||
4af1b50d7cbdd4ee7a7503af402125f1e106bae4d7aac172b53964c2e88e15def4bd7ebd92395fa1a01af22293534c582cce28b908dd65491f70124f9120b123
|
||||
16333c4123a8ed005172901067974c43a8bf198a1987e152a5d42f55e1bffc78ea4a05066d61a4594b7a40886f0c495a0e1f2564265aeec7e0d5d520af5ffcf8
|
||||
fac533e7e4e1f39387bf9c3c7a74f2f0e7d49161b583e2a96ef5eafb2ffe7ef2a9f3d7b3ef5e3dfeca8ee73afef79f3efbedd72fed4058e92a042fbf7efac7f3
|
||||
a72fbff9fccf1f1e5be0ed041de8f021893077aee363e7268b60612a0426737c90bc9dc5304444b768c7538e622467b1f8ef89d0405f5f208a2cb80e3623783b
|
||||
01a5b101afceef1a8407613217c4e2f15a1819c03dc6688725d6285c937369611ecee3a97df264aee36e2274649b3b40b191dfde7c064a4b6c2e83101b34f729
|
||||
8a059ae2180b47fec60e31b6acee0e21465cf7c828619c4d847387381d44ac21199203a39a56463b2482bc2c6c0421df466cf66e3b1d466dabeee22313097705
|
||||
a216f2434c8d305e457381229bcb218aa81ef05d24421bc9c12219e9b81e1790e929a6cce98d31e7369b1b09ac574bfa3590177bdaf7e8223291892087369fbb
|
||||
88311dd965874188a2990d3b2071a8633fe28750a2c8d967c206df63e61d22bf431e507c6aba6fc31e409fe06c35b805caaa5bac0a44fe324f2cb9bc8a9951bf
|
||||
83059d20aca406f4dfd0f388c4678afb9aacfbffadac8390befcf68965551755d0db09b1de513b6b327e1a6e5dbc03968cc9c5d7ee2e9ac7fb186e97cd06f65e
|
||||
badf4bb7fbbf97eed3eee7772fd82b8d06f9965bc574c7aef6efd159dbf709a174201614ef72b583e7d0a0c67d1894e6ea8116e74f75b3102ee50d0df318b869
|
||||
82948d9330f10911e1204433d8e6975de964ca33d753eecc1887ddbf1ab6fa96783a8ff6d8387d782d97e5836aaa211c89d578c9cfc7e18943a4e85a7df54096
|
||||
bb576ca7eaf9794940dabe0d096d329344d542a2be1c9441524feb10340b09b5b277c2a26961d190ee97a9da6001d4f2acc00eca817d57cbf53d30012378b042
|
||||
148f659ed2542fb3ab92f92e337d5a308d0a80edc4b20256996e4aaea72e4fae2e2db537c8b441422b3793848a8c6a653c44639c55a71c7d131a6f9bebe62aa5
|
||||
063d190a351f94d68a46bdf16f2cce9b6bb05bd7061aeb4a4163e7b8e5d6aa3e94cc08cd5aee049efee1329a41ed70b9f345740a2fd64622496ff8f328cb2ce1
|
||||
a28b7898065c894eaa061111387128895aae5c7e9e061a2b0d51dcca1510840b4bae09b272d1c841d2cd24e3c9048f849e766d44463afd0a0a9f6a85f557657e
|
||||
7eb0b4647348f7201c1f3b07749edc4450627ebd2c0338261c5e0295d3688e09bcdccc856c557f6b8d29935dfdeda2aaa1741cd15988b28ea28b790a57529ed3
|
||||
51dff21868dfb2354340b590648df0602a1bac1e54a39be65d23e5706ad73ddb48464e13cd55cf345445764dbb8a19332cdbc05a2ccfd7e43556cb1083a6e91d
|
||||
3e95ee75c96d2eb56e6d9f90770908781e3f4bd77d8386a0515b4d6650938c3765586a76366af68ee502cfa0f6264d4253fddad2ed5adcf21e619d0e06cfd5f9
|
||||
c16ebd6a6168b2dc5eaa48ab4311fdbc821ddc05f1e8c2bbe039155ca5128e2112041ba281da93a4b201b7c83d91dd1a70e5cc13d272ef97fcb61754fca0506a
|
||||
f8bd8257f54a8586dfae16dabe5f2df7fc72a9dba93c80c622c2a8eca707327d78234517d9b18c1adf389a89962fdd2e8d585464eab0a5a888aba39972c5389a
|
||||
490f639ca13c73711d02a273bf56e937abcd4eadd0acb6fb05afdb69149a41ad53e8d6827ab7df0dfc46b3ffc0758e14d86b5703afd66b146ae5202878b592a4
|
||||
df6816ea5ea5d2f6eaed46cf6b3fc8b631b0f2543eb258407815afed7f000000ffff0300504b0304140006000800000021000dd1909fb60000001b0100002700
|
||||
00007468656d652f7468656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c73848f4d0ac2301484f78277086f6fd3ba109126dd88d0ad
|
||||
d40384e4350d363f2451eced0dae2c082e8761be9969bb979dc9136332de3168aa1a083ae995719ac16db8ec8e4052164e89d93b64b060828e6f37ed1567914b
|
||||
284d262452282e3198720e274a939cd08a54f980ae38a38f56e422a3a641c8bbd048f7757da0f19b017cc524bd62107bd5001996509affb3fd381a89672f1f16
|
||||
5dfe514173d9850528a2c6cce0239baa4c04ca5bbabac4df000000ffff0300504b01022d0014000600080000002100e9de0fbfff0000001c0200001300000000
|
||||
000000000000000000000000005b436f6e74656e745f54797065735d2e786d6c504b01022d0014000600080000002100a5d6a7e7c0000000360100000b000000
|
||||
00000000000000000000300100005f72656c732f2e72656c73504b01022d00140006000800000021006b799616830000008a0000001c00000000000000000000
|
||||
000000190200007468656d652f7468656d652f7468656d654d616e616765722e786d6c504b01022d0014000600080000002100b7e72e45da060000a81a000016
|
||||
00000000000000000000000000d60200007468656d652f7468656d652f7468656d65312e786d6c504b01022d00140006000800000021000dd1909fb60000001b
|
||||
0100002700000000000000000000000000e40900007468656d652f7468656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c73504b050600000000050005005d010000df0a00000000}
|
||||
{\*\colorschememapping 3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d3822207374616e64616c6f6e653d22796573223f3e0d0a3c613a636c724d
|
||||
617020786d6c6e733a613d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f64726177696e676d6c2f323030362f6d6169
|
||||
6e22206267313d226c743122207478313d22646b3122206267323d226c743222207478323d22646b322220616363656e74313d22616363656e74312220616363
|
||||
656e74323d22616363656e74322220616363656e74333d22616363656e74332220616363656e74343d22616363656e74342220616363656e74353d22616363656e74352220616363656e74363d22616363656e74362220686c696e6b3d22686c696e6b2220666f6c486c696e6b3d22666f6c486c696e6b222f3e}
|
||||
{\*\latentstyles\lsdstimax371\lsdlockeddef0\lsdsemihiddendef0\lsdunhideuseddef0\lsdqformatdef0\lsdprioritydef99{\lsdlockedexcept \lsdqformat1 \lsdpriority0 \lsdlocked0 Normal;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 1;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 2;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 3;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 4;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 5;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 6;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 7;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 8;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 9;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 1;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 5;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 6;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 7;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 8;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 9;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 1;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 2;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 3;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 4;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 5;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 6;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 7;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 8;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 9;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Normal Indent;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 footnote text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 annotation text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 header;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 footer;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index heading;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority35 \lsdlocked0 caption;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 table of figures;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 envelope address;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 envelope return;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 footnote reference;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 annotation reference;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 line number;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 page number;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 endnote reference;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 endnote text;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 table of authorities;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 macro;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 toa heading;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 3;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 3;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 3;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 5;\lsdqformat1 \lsdpriority10 \lsdlocked0 Title;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Closing;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Signature;\lsdsemihidden1 \lsdunhideused1 \lsdpriority1 \lsdlocked0 Default Paragraph Font;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text Indent;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 4;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Message Header;\lsdqformat1 \lsdpriority11 \lsdlocked0 Subtitle;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Salutation;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Date;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text First Indent;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text First Indent 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Note Heading;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text Indent 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text Indent 3;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Block Text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Hyperlink;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 FollowedHyperlink;\lsdqformat1 \lsdpriority22 \lsdlocked0 Strong;
|
||||
\lsdqformat1 \lsdpriority20 \lsdlocked0 Emphasis;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Document Map;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Plain Text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 E-mail Signature;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Top of Form;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Bottom of Form;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Normal (Web);\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Acronym;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Address;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Cite;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Code;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Definition;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Keyboard;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Preformatted;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Sample;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Typewriter;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Variable;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 annotation subject;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 No List;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 1;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Balloon Text;\lsdpriority39 \lsdlocked0 Table Grid;
|
||||
\lsdsemihidden1 \lsdlocked0 Placeholder Text;\lsdqformat1 \lsdpriority1 \lsdlocked0 No Spacing;\lsdpriority60 \lsdlocked0 Light Shading;\lsdpriority61 \lsdlocked0 Light List;\lsdpriority62 \lsdlocked0 Light Grid;
|
||||
\lsdpriority63 \lsdlocked0 Medium Shading 1;\lsdpriority64 \lsdlocked0 Medium Shading 2;\lsdpriority65 \lsdlocked0 Medium List 1;\lsdpriority66 \lsdlocked0 Medium List 2;\lsdpriority67 \lsdlocked0 Medium Grid 1;\lsdpriority68 \lsdlocked0 Medium Grid 2;
|
||||
\lsdpriority69 \lsdlocked0 Medium Grid 3;\lsdpriority70 \lsdlocked0 Dark List;\lsdpriority71 \lsdlocked0 Colorful Shading;\lsdpriority72 \lsdlocked0 Colorful List;\lsdpriority73 \lsdlocked0 Colorful Grid;\lsdpriority60 \lsdlocked0 Light Shading Accent 1;
|
||||
\lsdpriority61 \lsdlocked0 Light List Accent 1;\lsdpriority62 \lsdlocked0 Light Grid Accent 1;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 1;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 1;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 1;
|
||||
\lsdsemihidden1 \lsdlocked0 Revision;\lsdqformat1 \lsdpriority34 \lsdlocked0 List Paragraph;\lsdqformat1 \lsdpriority29 \lsdlocked0 Quote;\lsdqformat1 \lsdpriority30 \lsdlocked0 Intense Quote;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 1;
|
||||
\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 1;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 1;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 1;\lsdpriority70 \lsdlocked0 Dark List Accent 1;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 1;
|
||||
\lsdpriority72 \lsdlocked0 Colorful List Accent 1;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 1;\lsdpriority60 \lsdlocked0 Light Shading Accent 2;\lsdpriority61 \lsdlocked0 Light List Accent 2;\lsdpriority62 \lsdlocked0 Light Grid Accent 2;
|
||||
\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 2;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 2;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 2;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 2;
|
||||
\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 2;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 2;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 2;\lsdpriority70 \lsdlocked0 Dark List Accent 2;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 2;
|
||||
\lsdpriority72 \lsdlocked0 Colorful List Accent 2;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 2;\lsdpriority60 \lsdlocked0 Light Shading Accent 3;\lsdpriority61 \lsdlocked0 Light List Accent 3;\lsdpriority62 \lsdlocked0 Light Grid Accent 3;
|
||||
\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 3;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 3;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 3;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 3;
|
||||
\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 3;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 3;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 3;\lsdpriority70 \lsdlocked0 Dark List Accent 3;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 3;
|
||||
\lsdpriority72 \lsdlocked0 Colorful List Accent 3;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 3;\lsdpriority60 \lsdlocked0 Light Shading Accent 4;\lsdpriority61 \lsdlocked0 Light List Accent 4;\lsdpriority62 \lsdlocked0 Light Grid Accent 4;
|
||||
\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 4;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 4;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 4;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 4;
|
||||
\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 4;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 4;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 4;\lsdpriority70 \lsdlocked0 Dark List Accent 4;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 4;
|
||||
\lsdpriority72 \lsdlocked0 Colorful List Accent 4;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 4;\lsdpriority60 \lsdlocked0 Light Shading Accent 5;\lsdpriority61 \lsdlocked0 Light List Accent 5;\lsdpriority62 \lsdlocked0 Light Grid Accent 5;
|
||||
\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 5;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 5;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 5;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 5;
|
||||
\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 5;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 5;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 5;\lsdpriority70 \lsdlocked0 Dark List Accent 5;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 5;
|
||||
\lsdpriority72 \lsdlocked0 Colorful List Accent 5;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 5;\lsdpriority60 \lsdlocked0 Light Shading Accent 6;\lsdpriority61 \lsdlocked0 Light List Accent 6;\lsdpriority62 \lsdlocked0 Light Grid Accent 6;
|
||||
\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 6;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 6;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 6;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 6;
|
||||
\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 6;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 6;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 6;\lsdpriority70 \lsdlocked0 Dark List Accent 6;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 6;
|
||||
\lsdpriority72 \lsdlocked0 Colorful List Accent 6;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 6;\lsdqformat1 \lsdpriority19 \lsdlocked0 Subtle Emphasis;\lsdqformat1 \lsdpriority21 \lsdlocked0 Intense Emphasis;
|
||||
\lsdqformat1 \lsdpriority31 \lsdlocked0 Subtle Reference;\lsdqformat1 \lsdpriority32 \lsdlocked0 Intense Reference;\lsdqformat1 \lsdpriority33 \lsdlocked0 Book Title;\lsdsemihidden1 \lsdunhideused1 \lsdpriority37 \lsdlocked0 Bibliography;
|
||||
\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority39 \lsdlocked0 TOC Heading;\lsdpriority41 \lsdlocked0 Plain Table 1;\lsdpriority42 \lsdlocked0 Plain Table 2;\lsdpriority43 \lsdlocked0 Plain Table 3;\lsdpriority44 \lsdlocked0 Plain Table 4;
|
||||
\lsdpriority45 \lsdlocked0 Plain Table 5;\lsdpriority40 \lsdlocked0 Grid Table Light;\lsdpriority46 \lsdlocked0 Grid Table 1 Light;\lsdpriority47 \lsdlocked0 Grid Table 2;\lsdpriority48 \lsdlocked0 Grid Table 3;\lsdpriority49 \lsdlocked0 Grid Table 4;
|
||||
\lsdpriority50 \lsdlocked0 Grid Table 5 Dark;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 1;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 1;
|
||||
\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 1;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 1;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 1;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 1;
|
||||
\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 1;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 2;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 2;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 2;
|
||||
\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 2;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 2;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 2;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 2;
|
||||
\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 3;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 3;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 3;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 3;
|
||||
\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 3;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 3;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 3;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 4;
|
||||
\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 4;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 4;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 4;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 4;
|
||||
\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 4;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 4;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 5;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 5;
|
||||
\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 5;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 5;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 5;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 5;
|
||||
\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 5;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 6;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 6;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 6;
|
||||
\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 6;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 6;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 6;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 6;
|
||||
\lsdpriority46 \lsdlocked0 List Table 1 Light;\lsdpriority47 \lsdlocked0 List Table 2;\lsdpriority48 \lsdlocked0 List Table 3;\lsdpriority49 \lsdlocked0 List Table 4;\lsdpriority50 \lsdlocked0 List Table 5 Dark;
|
||||
\lsdpriority51 \lsdlocked0 List Table 6 Colorful;\lsdpriority52 \lsdlocked0 List Table 7 Colorful;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 1;\lsdpriority47 \lsdlocked0 List Table 2 Accent 1;\lsdpriority48 \lsdlocked0 List Table 3 Accent 1;
|
||||
\lsdpriority49 \lsdlocked0 List Table 4 Accent 1;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 1;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 1;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 1;
|
||||
\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 2;\lsdpriority47 \lsdlocked0 List Table 2 Accent 2;\lsdpriority48 \lsdlocked0 List Table 3 Accent 2;\lsdpriority49 \lsdlocked0 List Table 4 Accent 2;
|
||||
\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 2;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 2;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 2;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 3;
|
||||
\lsdpriority47 \lsdlocked0 List Table 2 Accent 3;\lsdpriority48 \lsdlocked0 List Table 3 Accent 3;\lsdpriority49 \lsdlocked0 List Table 4 Accent 3;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 3;
|
||||
\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 3;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 3;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 4;\lsdpriority47 \lsdlocked0 List Table 2 Accent 4;
|
||||
\lsdpriority48 \lsdlocked0 List Table 3 Accent 4;\lsdpriority49 \lsdlocked0 List Table 4 Accent 4;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 4;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 4;
|
||||
\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 4;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 5;\lsdpriority47 \lsdlocked0 List Table 2 Accent 5;\lsdpriority48 \lsdlocked0 List Table 3 Accent 5;
|
||||
\lsdpriority49 \lsdlocked0 List Table 4 Accent 5;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 5;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 5;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 5;
|
||||
\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 6;\lsdpriority47 \lsdlocked0 List Table 2 Accent 6;\lsdpriority48 \lsdlocked0 List Table 3 Accent 6;\lsdpriority49 \lsdlocked0 List Table 4 Accent 6;
|
||||
\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 6;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 6;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 6;}}{\*\datastore 010500000200000018000000
|
||||
4d73786d6c322e534158584d4c5265616465722e362e30000000000000000000000e0000
|
||||
d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff0900060000000000000000000000010000000100000000000000001000000200000001000000feffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
fffffffffffffffffdffffff04000000feffffff05000000fefffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffff52006f006f007400200045006e00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500ffffffffffffffff010000000c6ad98892f1d411a65f0040963251e50000000000000000000000006069
|
||||
e214b3d4ce010300000080020000000000004d0073006f004400610074006100530074006f0072006500000000000000000000000000000000000000000000000000000000000000000000000000000000001a000101ffffffffffffffff0200000000000000000000000000000000000000000000006069e214b3d4ce01
|
||||
6069e214b3d4ce010000000000000000000000003500d900ca00dd00ce004400cc00c8005a0045004700c400cd0057004900c500d400c900cb00ce00570051003d003d000000000000000000000000000000000032000101ffffffffffffffff0300000000000000000000000000000000000000000000006069e214b3d4
|
||||
ce016069e214b3d4ce010000000000000000000000004900740065006d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000201ffffffff04000000ffffffff000000000000000000000000000000000000000000000000
|
||||
00000000000000000000000000000000fc00000000000000010000000200000003000000feffffff0500000006000000070000000800000009000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3c623a536f75726365732053656c65637465645374796c653d225c415041536978746845646974696f6e4f66666963654f6e6c696e652e78736c22205374796c654e616d653d22415041222056657273696f6e3d22362220786d6c6e733a
|
||||
623d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f6f6666696365446f63756d656e742f323030362f6269626c696f6772617068792220786d6c6e733d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f6f6666696365446f63756d656e74
|
||||
2f323030362f6269626c696f677261706879223e3c2f623a536f75726365733e000000003c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d3822207374616e64616c6f6e653d226e6f223f3e0d0a3c64733a6461746173746f72654974656d2064733a6974656d49443d227b42384244
|
||||
394137462d323833422d343136342d413442352d3632323544323941454535397d2220786d6c6e733a64733d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f6f6666696365446f63756d656e742f323030362f637573746f6d586d6c223e3c64733a736368656d61526566733e3c
|
||||
64733a736368656d615265662064733a7572693d22687474703a2f2f736368656d61732e6f70656e500072006f007000650072007400690065007300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000200ffffffffffffffffffffffff000000000000
|
||||
0000000000000000000000000000000000000000000000000000000000000400000055010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff00000000
|
||||
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff0000
|
||||
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff
|
||||
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000786d6c666f726d6174732e6f72672f6f6666696365446f63756d656e742f323030362f6269626c696f677261706879222f3e3c2f64733a736368656d61526566733e3c2f64733a6461746173746f
|
||||
72654974656d3e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000105000000000000}}
|
||||
34
setup.py
34
setup.py
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env python2
|
||||
"""
|
||||
cx_Freeze build script for KCC.
|
||||
|
||||
@@ -10,7 +11,7 @@ Usage (Windows):
|
||||
from sys import platform
|
||||
|
||||
NAME = "KindleComicConverter"
|
||||
VERSION = "3.4"
|
||||
VERSION = "3.6"
|
||||
MAIN = "kcc.py"
|
||||
|
||||
if platform == "darwin":
|
||||
@@ -23,10 +24,11 @@ if platform == "darwin":
|
||||
argv_emulation=True,
|
||||
iconfile='icons/comic2ebook.icns',
|
||||
includes=['PIL', 'sip', 'PyQt4', 'PyQt4.QtCore', 'PyQt4.QtGui', 'PyQt4.QtNetwork'],
|
||||
qt_plugins=[],
|
||||
excludes=['PyQt4.QtDeclarative', 'PyQt4.QtDesigner', 'PyQt4.QtHelp', 'PyQt4.QtMultimedia',
|
||||
'PyQt4.QtOpenGL', 'PyQt4.QtScript', 'PyQt4.QtScriptTools', 'PyQt4.QtSql', 'PyQt4.QtSvg',
|
||||
'PyQt4.QtXmlPatterns', 'PyQt4.QtXml', 'PyQt4.QtWebKit', 'PyQt4.QtTest'],
|
||||
resources=['LICENSE.txt', 'other/Additional-LICENSE.txt'],
|
||||
'PyQt4.QtXmlPatterns', 'PyQt4.QtXml', 'PyQt4.QtWebKit', 'PyQt4.QtTest', 'Tkinter'],
|
||||
resources=['LICENSE.txt', 'other/Additional-LICENSE.txt', 'other/unrar', 'other/7za'],
|
||||
plist=dict(
|
||||
CFBundleName=NAME,
|
||||
CFBundleShortVersionString=VERSION,
|
||||
@@ -42,6 +44,10 @@ if platform == "darwin":
|
||||
CFBundleTypeRole='Viewer',
|
||||
)
|
||||
],
|
||||
LSMinimumSystemVersion='10.6.0',
|
||||
LSEnvironment=dict(
|
||||
PATH='/usr/local/bin:/usr/bin:/bin'
|
||||
),
|
||||
NSHumanReadableCopyright='ISC License (ISCL)'
|
||||
)
|
||||
)
|
||||
@@ -55,7 +61,8 @@ elif platform == "win32":
|
||||
['other/UnRAR.exe', 'UnRAR.exe'],
|
||||
['other/7za.exe', '7za.exe'],
|
||||
['other/Additional-LICENSE.txt', 'Additional-LICENSE.txt']
|
||||
], "compressed": True}},
|
||||
], "compressed": True,
|
||||
"excludes": ['Tkinter']}},
|
||||
executables=[Executable(MAIN,
|
||||
base=base,
|
||||
targetName="KCC.exe",
|
||||
@@ -65,18 +72,10 @@ elif platform == "win32":
|
||||
appendScriptToLibrary=False,
|
||||
compress=True)])
|
||||
else:
|
||||
from cx_Freeze import setup, Executable
|
||||
extra_options = dict(
|
||||
options={"build_exe": {"include_files": ['LICENSE.txt',
|
||||
['other/Additional-LICENSE.txt', 'Additional-LICENSE.txt']
|
||||
], "compressed": True}},
|
||||
executables=[Executable(MAIN,
|
||||
icon="icons/comic2ebook.png",
|
||||
copyDependentFiles=True,
|
||||
appendScriptToExe=True,
|
||||
appendScriptToLibrary=False,
|
||||
compress=True)])
|
||||
print 'Please use setup.sh to build Linux package.'
|
||||
exit()
|
||||
|
||||
#noinspection PyUnboundLocalVariable
|
||||
setup(
|
||||
name=NAME,
|
||||
version=VERSION,
|
||||
@@ -89,3 +88,8 @@ setup(
|
||||
packages=['kcc'], requires=['Pillow'],
|
||||
**extra_options
|
||||
)
|
||||
|
||||
if platform == "darwin":
|
||||
from os import chmod
|
||||
chmod('dist/' + NAME + '.app/Contents/Resources/unrar', 0777)
|
||||
chmod('dist/' + NAME + '.app/Contents/Resources/7za', 0777)
|
||||
12
setup.sh
Normal file
12
setup.sh
Normal file
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
# Linux Python package build script
|
||||
|
||||
VERSION="3.6"
|
||||
|
||||
cp kcc.py __main__.py
|
||||
zip kcc.zip __main__.py kcc/*.py
|
||||
echo "#!/usr/bin/env python2" > kcc-bin
|
||||
cat kcc.zip >> kcc-bin
|
||||
chmod +x kcc-bin
|
||||
tar --xform s:^.*/:: --xform s/kcc-bin/kcc/ --xform s/comic2ebook/kcc/ -czf KindleComicConverter_linux_$VERSION.tar.gz kcc-bin LICENSE.txt icons/comic2ebook.png
|
||||
rm __main__.py kcc.zip kcc-bin
|
||||
Reference in New Issue
Block a user